diff options
Diffstat (limited to 'chrome/gpu/gpu_backing_store_win.cc')
-rw-r--r-- | chrome/gpu/gpu_backing_store_win.cc | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/chrome/gpu/gpu_backing_store_win.cc b/chrome/gpu/gpu_backing_store_win.cc new file mode 100644 index 0000000..1b4dcd5 --- /dev/null +++ b/chrome/gpu/gpu_backing_store_win.cc @@ -0,0 +1,185 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/gpu/gpu_backing_store_win.h" + +#include "app/gfx/gdi_util.h" +#include "app/win_util.h" +#include "base/logging.h" +#include "chrome/common/gpu_messages.h" +#include "chrome/gpu/gpu_view_win.h" +#include "chrome/gpu/gpu_thread.h" + +namespace { + +// Creates a dib conforming to the height/width/section parameters passed in. +HANDLE CreateDIB(HDC dc, int width, int height, int color_depth) { + BITMAPV5HEADER hdr = {0}; + ZeroMemory(&hdr, sizeof(BITMAPV5HEADER)); + + // These values are shared with gfx::PlatformDevice + hdr.bV5Size = sizeof(BITMAPINFOHEADER); + hdr.bV5Width = width; + hdr.bV5Height = -height; // minus means top-down bitmap + hdr.bV5Planes = 1; + hdr.bV5BitCount = color_depth; + hdr.bV5Compression = BI_RGB; // no compression + hdr.bV5SizeImage = 0; + hdr.bV5XPelsPerMeter = 1; + hdr.bV5YPelsPerMeter = 1; + hdr.bV5ClrUsed = 0; + hdr.bV5ClrImportant = 0; + + + void* data = NULL; + HANDLE dib = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO*>(&hdr), + 0, &data, NULL, 0); + DCHECK(data); + return dib; +} + +void CallStretchDIBits(HDC hdc, int dest_x, int dest_y, int dest_w, int dest_h, + int src_x, int src_y, int src_w, int src_h, void* pixels, + const BITMAPINFO* bitmap_info) { + // When blitting a rectangle that touches the bottom, left corner of the + // bitmap, StretchDIBits looks at it top-down! For more details, see + // http://wiki.allegro.cc/index.php?title=StretchDIBits. + int rv; + int bitmap_h = -bitmap_info->bmiHeader.biHeight; + int bottom_up_src_y = bitmap_h - src_y - src_h; + if (bottom_up_src_y == 0 && src_x == 0 && src_h != bitmap_h) { + rv = StretchDIBits(hdc, + dest_x, dest_h + dest_y - 1, dest_w, -dest_h, + src_x, bitmap_h - src_y + 1, src_w, -src_h, + pixels, bitmap_info, DIB_RGB_COLORS, SRCCOPY); + } else { + rv = StretchDIBits(hdc, + dest_x, dest_y, dest_w, dest_h, + src_x, bottom_up_src_y, src_w, src_h, + pixels, bitmap_info, DIB_RGB_COLORS, SRCCOPY); + } + DCHECK(rv != GDI_ERROR); +} + +} // namespace + + +GpuBackingStoreWin::GpuBackingStoreWin(GpuViewWin* view, + GpuThread* gpu_thread, + int32 routing_id, + const gfx::Size& size) + : view_(view), + gpu_thread_(gpu_thread), + routing_id_(routing_id), + size_(size) { + gpu_thread_->AddRoute(routing_id_, this); + + HDC screen_dc = ::GetDC(NULL); + color_depth_ = ::GetDeviceCaps(screen_dc, BITSPIXEL); + // Color depths less than 16 bpp require a palette to be specified. Instead, + // we specify the desired color depth as 16 which lets the OS to come up + // with an approximation. + if (color_depth_ < 16) + color_depth_ = 16; + hdc_ = CreateCompatibleDC(screen_dc); + ReleaseDC(NULL, screen_dc); +} + +GpuBackingStoreWin::~GpuBackingStoreWin() { + gpu_thread_->RemoveRoute(routing_id_); + + DCHECK(hdc_); + if (original_bitmap_) { + SelectObject(hdc_, original_bitmap_); + } + if (backing_store_dib_) { + DeleteObject(backing_store_dib_); + backing_store_dib_ = NULL; + } + DeleteDC(hdc_); +} + +void GpuBackingStoreWin::OnMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(GpuBackingStoreWin, msg) + IPC_MESSAGE_HANDLER(GpuMsg_PaintToBackingStore, OnPaintToBackingStore) + IPC_MESSAGE_HANDLER(GpuMsg_ScrollBackingStore, OnScrollBackingStore) + IPC_END_MESSAGE_MAP_EX() +} + +void GpuBackingStoreWin::OnChannelConnected(int32 peer_pid) { +} + +void GpuBackingStoreWin::OnChannelError() { + // FIXME(brettw) does this mean we aren't getting any more messages and we + // should delete outselves? +} + +void GpuBackingStoreWin::OnPaintToBackingStore( + base::ProcessId source_process_id, + TransportDIB::Id id, + const gfx::Rect& bitmap_rect, + const std::vector<gfx::Rect>& copy_rects) { + HANDLE source_process_handle = OpenProcess(PROCESS_ALL_ACCESS, + FALSE, source_process_id); + CHECK(source_process_handle); + + // On Windows we need to duplicate the handle from the remote process. + // See BrowserRenderProcessHost::MapTransportDIB for how to do this on other + // platforms. + HANDLE section = win_util::GetSectionFromProcess( + id.handle, source_process_handle, false /* read write */); + CHECK(section); + TransportDIB* dib = TransportDIB::Map(section); + CHECK(dib); + + if (!backing_store_dib_) { + backing_store_dib_ = CreateDIB(hdc_, size_.width(), + size_.height(), color_depth_); + if (!backing_store_dib_) { + NOTREACHED(); + + // TODO(brettw): do this in such a way that we can't forget to + // send the ACK. + gpu_thread_->Send(new GpuHostMsg_PaintToBackingStore_ACK(routing_id_)); + return; + } + original_bitmap_ = SelectObject(hdc_, backing_store_dib_); + } + + BITMAPINFOHEADER hdr; + gfx::CreateBitmapHeader(bitmap_rect.width(), bitmap_rect.height(), &hdr); + // Account for a bitmap_rect that exceeds the bounds of our view + gfx::Rect view_rect(0, 0, size_.width(), size_.height()); + + for (size_t i = 0; i < copy_rects.size(); i++) { + gfx::Rect paint_rect = view_rect.Intersect(copy_rects[i]); + CallStretchDIBits(hdc_, + paint_rect.x(), + paint_rect.y(), + paint_rect.width(), + paint_rect.height(), + paint_rect.x() - bitmap_rect.x(), + paint_rect.y() - bitmap_rect.y(), + paint_rect.width(), + paint_rect.height(), + dib->memory(), + reinterpret_cast<BITMAPINFO*>(&hdr)); + view_->InvalidateRect(&paint_rect.ToRECT()); + } + + CloseHandle(source_process_handle); + gpu_thread_->Send(new GpuHostMsg_PaintToBackingStore_ACK(routing_id_)); +} + +void GpuBackingStoreWin::OnScrollBackingStore(int dx, int dy, + const gfx::Rect& clip_rect, + const gfx::Size& view_size) { + RECT damaged_rect, r = clip_rect.ToRECT(); + ScrollDC(hdc_, dx, dy, NULL, &r, NULL, &damaged_rect); + + // TODO(darin): this doesn't work if dx and dy are both non-zero! + DCHECK(dx == 0 || dy == 0); + + view_->DidScrollBackingStoreRect(dx, dy, clip_rect); +} |