// 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_view_win.h" #include "chrome/common/gpu_messages.h" #include "chrome/gpu/gpu_backing_store_win.h" #include "chrome/gpu/gpu_thread.h" namespace { void DrawBackground(const RECT& dirty_rect, CPaintDC* dc) { HBRUSH white_brush = reinterpret_cast(GetStockObject(WHITE_BRUSH)); dc->FillRect(&dirty_rect, white_brush); } void DrawResizeCorner(const RECT& dirty_rect, HDC dc) { // TODO(brettw): implement this. } } // namespace GpuViewWin::GpuViewWin(GpuThread* gpu_thread, HWND parent, int32 routing_id) : gpu_thread_(gpu_thread), routing_id_(routing_id), parent_(parent) { gpu_thread_->AddRoute(routing_id_, this); Create(parent_); SetWindowText(L"GPU window"); ShowWindow(SW_SHOW); } GpuViewWin::~GpuViewWin() { gpu_thread_->RemoveRoute(routing_id_); // TODO(brettw) may want to delete any dangling backing stores, or perhaps // assert if one still exists. } void GpuViewWin::OnMessageReceived(const IPC::Message& msg) { IPC_BEGIN_MESSAGE_MAP(GpuViewWin, msg) IPC_MESSAGE_HANDLER(GpuMsg_NewBackingStore, OnNewBackingStore) IPC_END_MESSAGE_MAP_EX() } void GpuViewWin::OnChannelConnected(int32 peer_pid) { } void GpuViewWin::OnChannelError() { // TODO(brettw) do we need to delete ourselves now? } void GpuViewWin::DidScrollBackingStoreRect(int dx, int dy, const gfx::Rect& rect) { // We need to pass in SW_INVALIDATE to ScrollWindowEx. The documentation on // MSDN states that it only applies to the HRGN argument, which is wrong. // Not passing in this flag does not invalidate the region which was scrolled // from, thus causing painting issues. RECT clip_rect = rect.ToRECT(); ScrollWindowEx(dx, dy, NULL, &clip_rect, NULL, NULL, SW_INVALIDATE); } void GpuViewWin::OnNewBackingStore(int32 routing_id, const gfx::Size& size) { backing_store_.reset( new GpuBackingStoreWin(this, gpu_thread_, routing_id, size)); MoveWindow(0, 0, size.width(), size.height(), TRUE); } void GpuViewWin::OnPaint(HDC unused_dc) { // Grab the region to paint before creation of paint_dc since it clears the // damage region. ScopedGDIObject damage_region(CreateRectRgn(0, 0, 0, 0)); GetUpdateRgn(damage_region, FALSE); CPaintDC paint_dc(m_hWnd); gfx::Rect damaged_rect(paint_dc.m_ps.rcPaint); if (damaged_rect.IsEmpty()) return; if (backing_store_.get()) { gfx::Rect bitmap_rect(gfx::Point(), backing_store_->size()); // Blit only the damaged regions from the backing store. DWORD data_size = GetRegionData(damage_region, 0, NULL); // TODO(brettw) why is the "+1" necessary here? When I remove it, the // page paints black, but according to the documentation, its not needed. scoped_array region_data_buf(new char[data_size + 1]); RGNDATA* region_data = reinterpret_cast(region_data_buf.get()); GetRegionData(damage_region, data_size, region_data); RECT* region_rects = reinterpret_cast(region_data->Buffer); for (DWORD i = 0; i < region_data->rdh.nCount; ++i) { gfx::Rect paint_rect = bitmap_rect.Intersect(gfx::Rect(region_rects[i])); if (!paint_rect.IsEmpty()) { DrawResizeCorner(paint_rect.ToRECT(), backing_store_->hdc()); BitBlt(paint_dc.m_hDC, paint_rect.x(), paint_rect.y(), paint_rect.width(), paint_rect.height(), backing_store_->hdc(), paint_rect.x(), paint_rect.y(), SRCCOPY); } } // Fill the remaining portion of the damaged_rect with the background if (damaged_rect.right() > bitmap_rect.right()) { RECT r; r.left = std::max(bitmap_rect.right(), damaged_rect.x()); r.right = damaged_rect.right(); r.top = damaged_rect.y(); r.bottom = std::min(bitmap_rect.bottom(), damaged_rect.bottom()); DrawBackground(r, &paint_dc); } if (damaged_rect.bottom() > bitmap_rect.bottom()) { RECT r; r.left = damaged_rect.x(); r.right = damaged_rect.right(); r.top = std::max(bitmap_rect.bottom(), damaged_rect.y()); r.bottom = damaged_rect.bottom(); DrawBackground(r, &paint_dc); } } else { DrawBackground(paint_dc.m_ps.rcPaint, &paint_dc); } }