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. 4 5 #include "content/browser/renderer_host/backing_store_win.h" 6 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" 17 18 namespace content { 19 namespace { 20 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)); 25 26 // These values are shared with gfx::PlatformDevice 27 hdr.bV5Size = sizeof(BITMAPINFOHEADER); 28 hdr.bV5Width = width; 29 hdr.bV5Height = -height; // minus means top-down bitmap 30 hdr.bV5Planes = 1; 31 hdr.bV5BitCount = color_depth; 32 hdr.bV5Compression = BI_RGB; // no compression 33 hdr.bV5SizeImage = 0; 34 hdr.bV5XPelsPerMeter = 1; 35 hdr.bV5YPelsPerMeter = 1; 36 hdr.bV5ClrUsed = 0; 37 hdr.bV5ClrImportant = 0; 38 39 if (BackingStoreWin::ColorManagementEnabled()) { 40 hdr.bV5CSType = LCS_sRGB; 41 hdr.bV5Intent = LCS_GM_IMAGES; 42 } 43 44 void* data = NULL; 45 HANDLE dib = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO*>(&hdr), 46 0, &data, NULL, 0); 47 DCHECK(data); 48 return dib; 49 } 50 51 } // namespace 52 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) 64 color_depth_ = 16; 65 hdc_ = CreateCompatibleDC(screen_dc); 66 ReleaseDC(NULL, screen_dc); 67 } 68 69 BackingStoreWin::~BackingStoreWin() { 70 DCHECK(hdc_); 71 if (original_bitmap_) { 72 SelectObject(hdc_, original_bitmap_); 73 } 74 if (backing_store_dib_) { 75 DeleteObject(backing_store_dib_); 76 backing_store_dib_ = NULL; 77 } 78 DeleteDC(hdc_); 79 } 80 81 // static 82 bool BackingStoreWin::ColorManagementEnabled() { 83 static bool enabled = false; 84 static bool checked = false; 85 if (!checked) { 86 checked = true; 87 const CommandLine& command = *CommandLine::ForCurrentProcess(); 88 enabled = command.HasSwitch(switches::kEnableMonitorProfile); 89 } 90 return enabled; 91 } 92 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); 97 } 98 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, 104 float scale_factor, 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(), 114 color_depth_); 115 if (!backing_store_dib_) { 116 NOTREACHED(); 117 return; 118 } 119 original_bitmap_ = SelectObject(hdc_, backing_store_dib_); 120 } 121 122 TransportDIB* dib = process->GetTransportDIB(bitmap); 123 if (!dib) 124 return; 125 126 gfx::Rect pixel_bitmap_rect = gfx::ToEnclosingRect( 127 gfx::ScaleRect(bitmap_rect, scale_factor)); 128 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()); 136 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_, 143 target_rect.x(), 144 target_rect.y(), 145 target_rect.width(), 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(), 151 dib->memory(), 152 &bitmap_info); 153 } 154 } 155 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)) 160 return false; 161 162 HDC temp_dc = output->GetSurface(); 163 BitBlt(temp_dc, 0, 0, rect.width(), rect.height(), 164 hdc(), rect.x(), rect.y(), SRCCOPY); 165 return true; 166 } 167 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); 173 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); 181 } 182 183 } // namespace content 184