Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / backing_store_win.cc
blob5ccafbb062b366a60c7129f127f90dc47dc22830
1 // Copyright (c) 2012 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/renderer_host/backing_store_win.h"
7 #include "base/command_line.h"
8 #include "content/browser/renderer_host/render_process_host_impl.h"
9 #include "content/browser/renderer_host/render_widget_host_impl.h"
10 #include "content/public/common/content_switches.h"
11 #include "skia/ext/platform_canvas.h"
12 #include "ui/base/win/dpi.h"
13 #include "ui/gfx/gdi_util.h"
14 #include "ui/gfx/rect_conversions.h"
15 #include "ui/gfx/size_conversions.h"
16 #include "ui/surface/transport_dib.h"
18 namespace content {
19 namespace {
21 // Creates a dib conforming to the height/width/section parameters passed in.
22 HANDLE CreateDIB(HDC dc, int width, int height, int color_depth) {
23 BITMAPV5HEADER hdr = {0};
24 ZeroMemory(&hdr, sizeof(BITMAPV5HEADER));
26 // These values are shared with gfx::PlatformDevice
27 hdr.bV5Size = sizeof(BITMAPINFOHEADER);
28 hdr.bV5Width = width;
29 hdr.bV5Height = -height; // minus means top-down bitmap
30 hdr.bV5Planes = 1;
31 hdr.bV5BitCount = color_depth;
32 hdr.bV5Compression = BI_RGB; // no compression
33 hdr.bV5SizeImage = 0;
34 hdr.bV5XPelsPerMeter = 1;
35 hdr.bV5YPelsPerMeter = 1;
36 hdr.bV5ClrUsed = 0;
37 hdr.bV5ClrImportant = 0;
39 if (BackingStoreWin::ColorManagementEnabled()) {
40 hdr.bV5CSType = LCS_sRGB;
41 hdr.bV5Intent = LCS_GM_IMAGES;
44 void* data = NULL;
45 HANDLE dib = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO*>(&hdr),
46 0, &data, NULL, 0);
47 DCHECK(data);
48 return dib;
51 } // namespace
53 BackingStoreWin::BackingStoreWin(RenderWidgetHost* widget,
54 const gfx::Size& size)
55 : BackingStore(widget, size),
56 backing_store_dib_(NULL),
57 original_bitmap_(NULL) {
58 HDC screen_dc = ::GetDC(NULL);
59 color_depth_ = ::GetDeviceCaps(screen_dc, BITSPIXEL);
60 // Color depths less than 16 bpp require a palette to be specified. Instead,
61 // we specify the desired color depth as 16 which lets the OS to come up
62 // with an approximation.
63 if (color_depth_ < 16)
64 color_depth_ = 16;
65 hdc_ = CreateCompatibleDC(screen_dc);
66 ReleaseDC(NULL, screen_dc);
69 BackingStoreWin::~BackingStoreWin() {
70 DCHECK(hdc_);
71 if (original_bitmap_) {
72 SelectObject(hdc_, original_bitmap_);
74 if (backing_store_dib_) {
75 DeleteObject(backing_store_dib_);
76 backing_store_dib_ = NULL;
78 DeleteDC(hdc_);
81 // static
82 bool BackingStoreWin::ColorManagementEnabled() {
83 static bool enabled = false;
84 static bool checked = false;
85 if (!checked) {
86 checked = true;
87 const CommandLine& command = *CommandLine::ForCurrentProcess();
88 enabled = command.HasSwitch(switches::kEnableMonitorProfile);
90 return enabled;
93 size_t BackingStoreWin::MemorySize() {
94 gfx::Size size_in_pixels = gfx::ToCeiledSize(gfx::ScaleSize(size(),
95 ui::win::GetDeviceScaleFactor()));
96 return size_in_pixels.GetArea() * (color_depth_ / 8);
99 void BackingStoreWin::PaintToBackingStore(
100 RenderProcessHost* process,
101 TransportDIB::Id bitmap,
102 const gfx::Rect& bitmap_rect,
103 const std::vector<gfx::Rect>& copy_rects,
104 float scale_factor,
105 const base::Closure& completion_callback,
106 bool* scheduled_completion_callback) {
107 *scheduled_completion_callback = false;
108 gfx::Size size_in_pixels = gfx::ToCeiledSize(gfx::ScaleSize(
109 size(), scale_factor));
110 if (!backing_store_dib_) {
111 backing_store_dib_ = CreateDIB(hdc_,
112 size_in_pixels.width(),
113 size_in_pixels.height(),
114 color_depth_);
115 if (!backing_store_dib_) {
116 NOTREACHED();
117 return;
119 original_bitmap_ = SelectObject(hdc_, backing_store_dib_);
122 TransportDIB* dib = process->GetTransportDIB(bitmap);
123 if (!dib)
124 return;
126 gfx::Rect pixel_bitmap_rect = gfx::ToEnclosingRect(
127 gfx::ScaleRect(bitmap_rect, scale_factor));
129 BITMAPINFO bitmap_info;
130 memset(&bitmap_info, 0, sizeof(bitmap_info));
131 gfx::CreateBitmapHeader(pixel_bitmap_rect.width(),
132 pixel_bitmap_rect.height(),
133 &bitmap_info.bmiHeader);
134 // Account for a bitmap_rect that exceeds the bounds of our view.
135 gfx::Rect view_rect(size());
137 for (size_t i = 0; i < copy_rects.size(); i++) {
138 gfx::Rect paint_rect = gfx::IntersectRects(view_rect, copy_rects[i]);
139 gfx::Rect pixel_copy_rect = gfx::ToEnclosingRect(
140 gfx::ScaleRect(paint_rect, scale_factor));
141 gfx::Rect target_rect = pixel_copy_rect;
142 gfx::StretchDIBits(hdc_,
143 target_rect.x(),
144 target_rect.y(),
145 target_rect.width(),
146 target_rect.height(),
147 pixel_copy_rect.x() - pixel_bitmap_rect.x(),
148 pixel_copy_rect.y() - pixel_bitmap_rect.y(),
149 pixel_copy_rect.width(),
150 pixel_copy_rect.height(),
151 dib->memory(),
152 &bitmap_info);
156 bool BackingStoreWin::CopyFromBackingStore(const gfx::Rect& rect,
157 skia::PlatformBitmap* output) {
158 // TODO(kevers): Make sure this works with HiDPI backing stores.
159 if (!output->Allocate(rect.width(), rect.height(), true))
160 return false;
162 HDC temp_dc = output->GetSurface();
163 BitBlt(temp_dc, 0, 0, rect.width(), rect.height(),
164 hdc(), rect.x(), rect.y(), SRCCOPY);
165 return true;
168 void BackingStoreWin::ScrollBackingStore(const gfx::Vector2d& delta,
169 const gfx::Rect& clip_rect,
170 const gfx::Size& view_size) {
171 // TODO(darin): this doesn't work if delta x() and y() are both non-zero!
172 DCHECK(delta.x() == 0 || delta.y() == 0);
174 float scale = ui::win::GetDeviceScaleFactor();
175 gfx::Rect screen_rect = gfx::ToEnclosingRect(
176 gfx::ScaleRect(clip_rect, scale));
177 int dx = static_cast<int>(delta.x() * scale);
178 int dy = static_cast<int>(delta.y() * scale);
179 RECT damaged_rect, r = screen_rect.ToRECT();
180 ScrollDC(hdc_, dx, dy, NULL, &r, NULL, &damaged_rect);
183 } // namespace content