OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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. | |
4 | |
5 #include "chrome/browser/renderer_host/backing_store_win.h" | |
6 | |
7 #include "app/surface/transport_dib.h" | |
8 #include "base/command_line.h" | |
9 #include "chrome/browser/renderer_host/render_process_host.h" | |
10 #include "chrome/browser/renderer_host/render_widget_host.h" | |
11 #include "chrome/common/chrome_switches.h" | |
12 #include "skia/ext/platform_canvas.h" | |
13 #include "ui/gfx/gdi_util.h" | |
14 | |
15 namespace { | |
16 | |
17 // Creates a dib conforming to the height/width/section parameters passed in. | |
18 HANDLE CreateDIB(HDC dc, int width, int height, int color_depth) { | |
19 BITMAPV5HEADER hdr = {0}; | |
20 ZeroMemory(&hdr, sizeof(BITMAPV5HEADER)); | |
21 | |
22 // These values are shared with gfx::PlatformDevice | |
23 hdr.bV5Size = sizeof(BITMAPINFOHEADER); | |
24 hdr.bV5Width = width; | |
25 hdr.bV5Height = -height; // minus means top-down bitmap | |
26 hdr.bV5Planes = 1; | |
27 hdr.bV5BitCount = color_depth; | |
28 hdr.bV5Compression = BI_RGB; // no compression | |
29 hdr.bV5SizeImage = 0; | |
30 hdr.bV5XPelsPerMeter = 1; | |
31 hdr.bV5YPelsPerMeter = 1; | |
32 hdr.bV5ClrUsed = 0; | |
33 hdr.bV5ClrImportant = 0; | |
34 | |
35 if (BackingStoreWin::ColorManagementEnabled()) { | |
36 hdr.bV5CSType = LCS_sRGB; | |
37 hdr.bV5Intent = LCS_GM_IMAGES; | |
38 } | |
39 | |
40 void* data = NULL; | |
41 HANDLE dib = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO*>(&hdr), | |
42 0, &data, NULL, 0); | |
43 DCHECK(data); | |
44 return dib; | |
45 } | |
46 | |
47 void CallStretchDIBits(HDC hdc, int dest_x, int dest_y, int dest_w, int dest_h, | |
48 int src_x, int src_y, int src_w, int src_h, void* pixels, | |
49 const BITMAPINFO* bitmap_info) { | |
50 // When blitting a rectangle that touches the bottom, left corner of the | |
51 // bitmap, StretchDIBits looks at it top-down! For more details, see | |
52 // http://wiki.allegro.cc/index.php?title=StretchDIBits. | |
53 int rv; | |
54 int bitmap_h = -bitmap_info->bmiHeader.biHeight; | |
55 int bottom_up_src_y = bitmap_h - src_y - src_h; | |
56 if (bottom_up_src_y == 0 && src_x == 0 && src_h != bitmap_h) { | |
57 rv = StretchDIBits(hdc, | |
58 dest_x, dest_h + dest_y - 1, dest_w, -dest_h, | |
59 src_x, bitmap_h - src_y + 1, src_w, -src_h, | |
60 pixels, bitmap_info, DIB_RGB_COLORS, SRCCOPY); | |
61 } else { | |
62 rv = StretchDIBits(hdc, | |
63 dest_x, dest_y, dest_w, dest_h, | |
64 src_x, bottom_up_src_y, src_w, src_h, | |
65 pixels, bitmap_info, DIB_RGB_COLORS, SRCCOPY); | |
66 } | |
67 DCHECK(rv != GDI_ERROR); | |
68 } | |
69 | |
70 } // namespace | |
71 | |
72 BackingStoreWin::BackingStoreWin(RenderWidgetHost* widget, const gfx::Size& size
) | |
73 : BackingStore(widget, size), | |
74 backing_store_dib_(NULL), | |
75 original_bitmap_(NULL) { | |
76 HDC screen_dc = ::GetDC(NULL); | |
77 color_depth_ = ::GetDeviceCaps(screen_dc, BITSPIXEL); | |
78 // Color depths less than 16 bpp require a palette to be specified. Instead, | |
79 // we specify the desired color depth as 16 which lets the OS to come up | |
80 // with an approximation. | |
81 if (color_depth_ < 16) | |
82 color_depth_ = 16; | |
83 hdc_ = CreateCompatibleDC(screen_dc); | |
84 ReleaseDC(NULL, screen_dc); | |
85 } | |
86 | |
87 BackingStoreWin::~BackingStoreWin() { | |
88 DCHECK(hdc_); | |
89 if (original_bitmap_) { | |
90 SelectObject(hdc_, original_bitmap_); | |
91 } | |
92 if (backing_store_dib_) { | |
93 DeleteObject(backing_store_dib_); | |
94 backing_store_dib_ = NULL; | |
95 } | |
96 DeleteDC(hdc_); | |
97 } | |
98 | |
99 // static | |
100 bool BackingStoreWin::ColorManagementEnabled() { | |
101 static bool enabled = false; | |
102 static bool checked = false; | |
103 if (!checked) { | |
104 checked = true; | |
105 const CommandLine& command = *CommandLine::ForCurrentProcess(); | |
106 enabled = command.HasSwitch(switches::kEnableMonitorProfile); | |
107 } | |
108 return enabled; | |
109 } | |
110 | |
111 size_t BackingStoreWin::MemorySize() { | |
112 return size().GetArea() * (color_depth_ / 8); | |
113 } | |
114 | |
115 void BackingStoreWin::PaintToBackingStore( | |
116 RenderProcessHost* process, | |
117 TransportDIB::Id bitmap, | |
118 const gfx::Rect& bitmap_rect, | |
119 const std::vector<gfx::Rect>& copy_rects) { | |
120 if (!backing_store_dib_) { | |
121 backing_store_dib_ = CreateDIB(hdc_, size().width(), | |
122 size().height(), color_depth_); | |
123 if (!backing_store_dib_) { | |
124 NOTREACHED(); | |
125 return; | |
126 } | |
127 original_bitmap_ = SelectObject(hdc_, backing_store_dib_); | |
128 } | |
129 | |
130 TransportDIB* dib = process->GetTransportDIB(bitmap); | |
131 if (!dib) | |
132 return; | |
133 | |
134 BITMAPINFOHEADER hdr; | |
135 gfx::CreateBitmapHeader(bitmap_rect.width(), bitmap_rect.height(), &hdr); | |
136 // Account for a bitmap_rect that exceeds the bounds of our view | |
137 gfx::Rect view_rect(size()); | |
138 | |
139 for (size_t i = 0; i < copy_rects.size(); i++) { | |
140 gfx::Rect paint_rect = view_rect.Intersect(copy_rects[i]); | |
141 CallStretchDIBits(hdc_, | |
142 paint_rect.x(), | |
143 paint_rect.y(), | |
144 paint_rect.width(), | |
145 paint_rect.height(), | |
146 paint_rect.x() - bitmap_rect.x(), | |
147 paint_rect.y() - bitmap_rect.y(), | |
148 paint_rect.width(), | |
149 paint_rect.height(), | |
150 dib->memory(), | |
151 reinterpret_cast<BITMAPINFO*>(&hdr)); | |
152 } | |
153 } | |
154 | |
155 bool BackingStoreWin::CopyFromBackingStore(const gfx::Rect& rect, | |
156 skia::PlatformCanvas* output) { | |
157 if (!output->initialize(rect.width(), rect.height(), true)) | |
158 return false; | |
159 | |
160 HDC temp_dc = output->beginPlatformPaint(); | |
161 BitBlt(temp_dc, 0, 0, rect.width(), rect.height(), | |
162 hdc(), rect.x(), rect.y(), SRCCOPY); | |
163 output->endPlatformPaint(); | |
164 return true; | |
165 } | |
166 | |
167 void BackingStoreWin::ScrollBackingStore(int dx, int dy, | |
168 const gfx::Rect& clip_rect, | |
169 const gfx::Size& view_size) { | |
170 RECT damaged_rect, r = clip_rect.ToRECT(); | |
171 ScrollDC(hdc_, dx, dy, NULL, &r, NULL, &damaged_rect); | |
172 | |
173 // TODO(darin): this doesn't work if dx and dy are both non-zero! | |
174 DCHECK(dx == 0 || dy == 0); | |
175 } | |
OLD | NEW |