Home | History | Annotate | Download | only in renderer_host
      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