1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/compositor/software_output_device_win.h"
7 #include "base/memory/shared_memory.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "skia/ext/platform_canvas.h"
10 #include "third_party/skia/include/core/SkBitmap.h"
11 #include "third_party/skia/include/core/SkDevice.h"
12 #include "ui/compositor/compositor.h"
13 #include "ui/gfx/gdi_util.h"
14 #include "ui/gfx/skia_util.h"
18 OutputDeviceBacking::OutputDeviceBacking() : created_byte_size_(0) {
21 OutputDeviceBacking::~OutputDeviceBacking() {
22 DCHECK(devices_
.empty());
25 void OutputDeviceBacking::Resized() {
26 size_t new_size
= GetMaxByteSize();
27 if (new_size
== created_byte_size_
)
29 for (SoftwareOutputDeviceWin
* device
: devices_
) {
30 device
->ReleaseContents();
33 created_byte_size_
= 0;
36 void OutputDeviceBacking::RegisterOutputDevice(
37 SoftwareOutputDeviceWin
* device
) {
38 devices_
.push_back(device
);
41 void OutputDeviceBacking::UnregisterOutputDevice(
42 SoftwareOutputDeviceWin
* device
) {
43 auto it
= std::find(devices_
.begin(), devices_
.end(), device
);
44 DCHECK(it
!= devices_
.end());
49 base::SharedMemory
* OutputDeviceBacking::GetSharedMemory() {
51 return backing_
.get();
52 created_byte_size_
= GetMaxByteSize();
54 backing_
.reset(new base::SharedMemory
);
55 CHECK(backing_
->CreateAnonymous(created_byte_size_
));
56 return backing_
.get();
59 size_t OutputDeviceBacking::GetMaxByteSize() {
60 // Minimum byte size is 1 because creating a 0-byte-long SharedMemory fails.
62 for (const SoftwareOutputDeviceWin
* device
: devices_
) {
65 static_cast<size_t>(device
->viewport_pixel_size().GetArea() * 4));
70 SoftwareOutputDeviceWin::SoftwareOutputDeviceWin(OutputDeviceBacking
* backing
,
71 ui::Compositor
* compositor
)
72 : hwnd_(compositor
->widget()),
73 is_hwnd_composited_(false),
76 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
78 LONG style
= GetWindowLong(hwnd_
, GWL_EXSTYLE
);
79 is_hwnd_composited_
= !!(style
& WS_EX_COMPOSITED
);
80 // Layered windows must be completely updated every time, so they can't
81 // share contents with other windows.
82 if (is_hwnd_composited_
)
85 backing_
->RegisterOutputDevice(this);
88 SoftwareOutputDeviceWin::~SoftwareOutputDeviceWin() {
89 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
92 backing_
->UnregisterOutputDevice(this);
95 void SoftwareOutputDeviceWin::Resize(const gfx::Size
& viewport_pixel_size
,
97 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
100 scale_factor_
= scale_factor
;
102 if (viewport_pixel_size_
== viewport_pixel_size
)
105 viewport_pixel_size_
= viewport_pixel_size
;
111 SkCanvas
* SoftwareOutputDeviceWin::BeginPaint(const gfx::Rect
& damage_rect
) {
112 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
115 HANDLE shared_section
= NULL
;
117 shared_section
= backing_
->GetSharedMemory()->handle();
118 contents_
= skia::AdoptRef(skia::CreatePlatformCanvas(
119 viewport_pixel_size_
.width(), viewport_pixel_size_
.height(), true,
120 shared_section
, skia::CRASH_ON_FAILURE
));
123 damage_rect_
= damage_rect
;
125 return contents_
.get();
128 void SoftwareOutputDeviceWin::EndPaint() {
129 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
134 SoftwareOutputDevice::EndPaint();
136 gfx::Rect rect
= damage_rect_
;
137 rect
.Intersect(gfx::Rect(viewport_pixel_size_
));
141 if (is_hwnd_composited_
) {
143 GetWindowRect(hwnd_
, &wr
);
144 SIZE size
= {wr
.right
- wr
.left
, wr
.bottom
- wr
.top
};
145 POINT position
= {wr
.left
, wr
.top
};
147 BLENDFUNCTION blend
= {AC_SRC_OVER
, 0x00, 0xFF, AC_SRC_ALPHA
};
149 DWORD style
= GetWindowLong(hwnd_
, GWL_EXSTYLE
);
150 style
&= ~WS_EX_COMPOSITED
;
151 style
|= WS_EX_LAYERED
;
152 SetWindowLong(hwnd_
, GWL_EXSTYLE
, style
);
154 HDC dib_dc
= skia::BeginPlatformPaint(contents_
.get());
155 ::UpdateLayeredWindow(hwnd_
, NULL
, &position
, &size
, dib_dc
, &zero
,
156 RGB(0xFF, 0xFF, 0xFF), &blend
, ULW_ALPHA
);
157 skia::EndPlatformPaint(contents_
.get());
159 HDC hdc
= ::GetDC(hwnd_
);
160 RECT src_rect
= rect
.ToRECT();
161 skia::DrawToNativeContext(contents_
.get(), hdc
, rect
.x(), rect
.y(),
163 ::ReleaseDC(hwnd_
, hdc
);
167 void SoftwareOutputDeviceWin::ReleaseContents() {
168 DCHECK(!contents_
|| contents_
->unique());
173 } // namespace content