Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / compositor / software_output_device_win.cc
blob098da8279c7f94a915d31f7c106a7cccc0557da6
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"
16 namespace content {
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_)
28 return;
29 for (SoftwareOutputDeviceWin* device : devices_) {
30 device->ReleaseContents();
32 backing_.reset();
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());
45 devices_.erase(it);
46 Resized();
49 base::SharedMemory* OutputDeviceBacking::GetSharedMemory() {
50 if (backing_)
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.
61 size_t max_size = 1;
62 for (const SoftwareOutputDeviceWin* device : devices_) {
63 max_size = std::max(
64 max_size,
65 static_cast<size_t>(device->viewport_pixel_size().GetArea() * 4));
67 return max_size;
70 SoftwareOutputDeviceWin::SoftwareOutputDeviceWin(OutputDeviceBacking* backing,
71 ui::Compositor* compositor)
72 : hwnd_(compositor->widget()),
73 is_hwnd_composited_(false),
74 backing_(backing),
75 in_paint_(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_)
83 backing_ = nullptr;
84 if (backing_)
85 backing_->RegisterOutputDevice(this);
88 SoftwareOutputDeviceWin::~SoftwareOutputDeviceWin() {
89 DCHECK_CURRENTLY_ON(BrowserThread::UI);
90 DCHECK(!in_paint_);
91 if (backing_)
92 backing_->UnregisterOutputDevice(this);
95 void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size,
96 float scale_factor) {
97 DCHECK_CURRENTLY_ON(BrowserThread::UI);
98 DCHECK(!in_paint_);
100 scale_factor_ = scale_factor;
102 if (viewport_pixel_size_ == viewport_pixel_size)
103 return;
105 viewport_pixel_size_ = viewport_pixel_size;
106 if (backing_)
107 backing_->Resized();
108 contents_.clear();
111 SkCanvas* SoftwareOutputDeviceWin::BeginPaint(const gfx::Rect& damage_rect) {
112 DCHECK_CURRENTLY_ON(BrowserThread::UI);
113 DCHECK(!in_paint_);
114 if (!contents_) {
115 HANDLE shared_section = NULL;
116 if (backing_)
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;
124 in_paint_ = true;
125 return contents_.get();
128 void SoftwareOutputDeviceWin::EndPaint() {
129 DCHECK_CURRENTLY_ON(BrowserThread::UI);
130 DCHECK(contents_);
131 DCHECK(in_paint_);
133 in_paint_ = false;
134 SoftwareOutputDevice::EndPaint();
136 gfx::Rect rect = damage_rect_;
137 rect.Intersect(gfx::Rect(viewport_pixel_size_));
138 if (rect.IsEmpty())
139 return;
141 if (is_hwnd_composited_) {
142 RECT wr;
143 GetWindowRect(hwnd_, &wr);
144 SIZE size = {wr.right - wr.left, wr.bottom - wr.top};
145 POINT position = {wr.left, wr.top};
146 POINT zero = {0, 0};
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());
158 } else {
159 HDC hdc = ::GetDC(hwnd_);
160 RECT src_rect = rect.ToRECT();
161 skia::DrawToNativeContext(contents_.get(), hdc, rect.x(), rect.y(),
162 &src_rect);
163 ::ReleaseDC(hwnd_, hdc);
167 void SoftwareOutputDeviceWin::ReleaseContents() {
168 DCHECK(!contents_ || contents_->unique());
169 DCHECK(!in_paint_);
170 contents_.clear();
173 } // namespace content