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"
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
);
29 hdr
.bV5Height
= -height
; // minus means top-down bitmap
31 hdr
.bV5BitCount
= color_depth
;
32 hdr
.bV5Compression
= BI_RGB
; // no compression
34 hdr
.bV5XPelsPerMeter
= 1;
35 hdr
.bV5YPelsPerMeter
= 1;
37 hdr
.bV5ClrImportant
= 0;
39 if (BackingStoreWin::ColorManagementEnabled()) {
40 hdr
.bV5CSType
= LCS_sRGB
;
41 hdr
.bV5Intent
= LCS_GM_IMAGES
;
45 HANDLE dib
= CreateDIBSection(dc
, reinterpret_cast<BITMAPINFO
*>(&hdr
),
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)
65 hdc_
= CreateCompatibleDC(screen_dc
);
66 ReleaseDC(NULL
, screen_dc
);
69 BackingStoreWin::~BackingStoreWin() {
71 if (original_bitmap_
) {
72 SelectObject(hdc_
, original_bitmap_
);
74 if (backing_store_dib_
) {
75 DeleteObject(backing_store_dib_
);
76 backing_store_dib_
= NULL
;
82 bool BackingStoreWin::ColorManagementEnabled() {
83 static bool enabled
= false;
84 static bool checked
= false;
87 const CommandLine
& command
= *CommandLine::ForCurrentProcess();
88 enabled
= command
.HasSwitch(switches::kEnableMonitorProfile
);
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
,
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(),
115 if (!backing_store_dib_
) {
119 original_bitmap_
= SelectObject(hdc_
, backing_store_dib_
);
122 TransportDIB
* dib
= process
->GetTransportDIB(bitmap
);
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_
,
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(),
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))
162 HDC temp_dc
= output
->GetSurface();
163 BitBlt(temp_dc
, 0, 0, rect
.width(), rect
.height(),
164 hdc(), rect
.x(), rect
.y(), SRCCOPY
);
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