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/gpu/gpu_backing_store_win.h" | |
6 | |
7 #include "app/win_util.h" | |
8 #include "base/logging.h" | |
9 #include "chrome/common/gpu_messages.h" | |
10 #include "chrome/gpu/gpu_view_win.h" | |
11 #include "chrome/gpu/gpu_thread.h" | |
12 #include "gfx/gdi_util.h" | |
13 | |
14 namespace { | |
15 | |
16 // Creates a dib conforming to the height/width/section parameters passed in. | |
17 HANDLE CreateDIB(HDC dc, int width, int height, int color_depth) { | |
18 BITMAPV5HEADER hdr = {0}; | |
19 ZeroMemory(&hdr, sizeof(BITMAPV5HEADER)); | |
20 | |
21 // These values are shared with gfx::PlatformDevice | |
22 hdr.bV5Size = sizeof(BITMAPINFOHEADER); | |
23 hdr.bV5Width = width; | |
24 hdr.bV5Height = -height; // minus means top-down bitmap | |
25 hdr.bV5Planes = 1; | |
26 hdr.bV5BitCount = color_depth; | |
27 hdr.bV5Compression = BI_RGB; // no compression | |
28 hdr.bV5SizeImage = 0; | |
29 hdr.bV5XPelsPerMeter = 1; | |
30 hdr.bV5YPelsPerMeter = 1; | |
31 hdr.bV5ClrUsed = 0; | |
32 hdr.bV5ClrImportant = 0; | |
33 | |
34 | |
35 void* data = NULL; | |
36 HANDLE dib = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO*>(&hdr), | |
37 0, &data, NULL, 0); | |
38 DCHECK(data); | |
39 return dib; | |
40 } | |
41 | |
42 void CallStretchDIBits(HDC hdc, int dest_x, int dest_y, int dest_w, int dest_h, | |
43 int src_x, int src_y, int src_w, int src_h, void* pixels, | |
44 const BITMAPINFO* bitmap_info) { | |
45 // When blitting a rectangle that touches the bottom, left corner of the | |
46 // bitmap, StretchDIBits looks at it top-down! For more details, see | |
47 // http://wiki.allegro.cc/index.php?title=StretchDIBits. | |
48 int rv; | |
49 int bitmap_h = -bitmap_info->bmiHeader.biHeight; | |
50 int bottom_up_src_y = bitmap_h - src_y - src_h; | |
51 if (bottom_up_src_y == 0 && src_x == 0 && src_h != bitmap_h) { | |
52 rv = StretchDIBits(hdc, | |
53 dest_x, dest_h + dest_y - 1, dest_w, -dest_h, | |
54 src_x, bitmap_h - src_y + 1, src_w, -src_h, | |
55 pixels, bitmap_info, DIB_RGB_COLORS, SRCCOPY); | |
56 } else { | |
57 rv = StretchDIBits(hdc, | |
58 dest_x, dest_y, dest_w, dest_h, | |
59 src_x, bottom_up_src_y, src_w, src_h, | |
60 pixels, bitmap_info, DIB_RGB_COLORS, SRCCOPY); | |
61 } | |
62 DCHECK(rv != GDI_ERROR); | |
63 } | |
64 | |
65 } // namespace | |
66 | |
67 | |
68 GpuBackingStoreWin::GpuBackingStoreWin(GpuViewWin* view, | |
69 GpuThread* gpu_thread, | |
70 int32 routing_id, | |
71 const gfx::Size& size) | |
72 : view_(view), | |
73 gpu_thread_(gpu_thread), | |
74 routing_id_(routing_id), | |
75 size_(size) { | |
76 gpu_thread_->AddRoute(routing_id_, this); | |
77 | |
78 HDC screen_dc = ::GetDC(NULL); | |
79 color_depth_ = ::GetDeviceCaps(screen_dc, BITSPIXEL); | |
80 // Color depths less than 16 bpp require a palette to be specified. Instead, | |
81 // we specify the desired color depth as 16 which lets the OS to come up | |
82 // with an approximation. | |
83 if (color_depth_ < 16) | |
84 color_depth_ = 16; | |
85 hdc_ = CreateCompatibleDC(screen_dc); | |
86 ReleaseDC(NULL, screen_dc); | |
87 } | |
88 | |
89 GpuBackingStoreWin::~GpuBackingStoreWin() { | |
90 gpu_thread_->RemoveRoute(routing_id_); | |
91 | |
92 DCHECK(hdc_); | |
93 if (original_bitmap_) { | |
94 SelectObject(hdc_, original_bitmap_); | |
95 } | |
96 if (backing_store_dib_) { | |
97 DeleteObject(backing_store_dib_); | |
98 backing_store_dib_ = NULL; | |
99 } | |
100 DeleteDC(hdc_); | |
101 } | |
102 | |
103 void GpuBackingStoreWin::OnMessageReceived(const IPC::Message& msg) { | |
104 IPC_BEGIN_MESSAGE_MAP(GpuBackingStoreWin, msg) | |
105 IPC_MESSAGE_HANDLER(GpuMsg_PaintToBackingStore, OnPaintToBackingStore) | |
106 IPC_MESSAGE_HANDLER(GpuMsg_ScrollBackingStore, OnScrollBackingStore) | |
107 IPC_END_MESSAGE_MAP_EX() | |
108 } | |
109 | |
110 void GpuBackingStoreWin::OnChannelConnected(int32 peer_pid) { | |
111 } | |
112 | |
113 void GpuBackingStoreWin::OnChannelError() { | |
114 // FIXME(brettw) does this mean we aren't getting any more messages and we | |
115 // should delete outselves? | |
116 } | |
117 | |
118 void GpuBackingStoreWin::OnPaintToBackingStore( | |
119 base::ProcessId source_process_id, | |
120 TransportDIB::Id id, | |
121 const gfx::Rect& bitmap_rect, | |
122 const std::vector<gfx::Rect>& copy_rects) { | |
123 HANDLE source_process_handle = OpenProcess(PROCESS_ALL_ACCESS, | |
124 FALSE, source_process_id); | |
125 CHECK(source_process_handle); | |
126 | |
127 // On Windows we need to duplicate the handle from the remote process. | |
128 // See BrowserRenderProcessHost::MapTransportDIB for how to do this on other | |
129 // platforms. | |
130 HANDLE section = win_util::GetSectionFromProcess( | |
131 id.handle, source_process_handle, false /* read write */); | |
132 CHECK(section); | |
133 scoped_ptr<TransportDIB> dib(TransportDIB::Map(section)); | |
134 CHECK(dib.get()); | |
135 | |
136 if (!backing_store_dib_) { | |
137 backing_store_dib_ = CreateDIB(hdc_, size_.width(), | |
138 size_.height(), color_depth_); | |
139 if (!backing_store_dib_) { | |
140 NOTREACHED(); | |
141 | |
142 // TODO(brettw): do this in such a way that we can't forget to | |
143 // send the ACK. | |
144 gpu_thread_->Send(new GpuHostMsg_PaintToBackingStore_ACK(routing_id_)); | |
145 return; | |
146 } | |
147 original_bitmap_ = SelectObject(hdc_, backing_store_dib_); | |
148 } | |
149 | |
150 BITMAPINFOHEADER hdr; | |
151 gfx::CreateBitmapHeader(bitmap_rect.width(), bitmap_rect.height(), &hdr); | |
152 // Account for a bitmap_rect that exceeds the bounds of our view | |
153 gfx::Rect view_rect(0, 0, size_.width(), size_.height()); | |
154 | |
155 for (size_t i = 0; i < copy_rects.size(); i++) { | |
156 gfx::Rect paint_rect = view_rect.Intersect(copy_rects[i]); | |
157 CallStretchDIBits(hdc_, | |
158 paint_rect.x(), | |
159 paint_rect.y(), | |
160 paint_rect.width(), | |
161 paint_rect.height(), | |
162 paint_rect.x() - bitmap_rect.x(), | |
163 paint_rect.y() - bitmap_rect.y(), | |
164 paint_rect.width(), | |
165 paint_rect.height(), | |
166 dib->memory(), | |
167 reinterpret_cast<BITMAPINFO*>(&hdr)); | |
168 view_->InvalidateRect(&paint_rect.ToRECT()); | |
169 } | |
170 | |
171 CloseHandle(source_process_handle); | |
172 gpu_thread_->Send(new GpuHostMsg_PaintToBackingStore_ACK(routing_id_)); | |
173 } | |
174 | |
175 void GpuBackingStoreWin::OnScrollBackingStore(int dx, int dy, | |
176 const gfx::Rect& clip_rect, | |
177 const gfx::Size& view_size) { | |
178 RECT damaged_rect, r = clip_rect.ToRECT(); | |
179 ScrollDC(hdc_, dx, dy, NULL, &r, NULL, &damaged_rect); | |
180 | |
181 // TODO(darin): this doesn't work if dx and dy are both non-zero! | |
182 DCHECK(dx == 0 || dy == 0); | |
183 | |
184 view_->DidScrollBackingStoreRect(dx, dy, clip_rect); | |
185 } | |
OLD | NEW |