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_aura.h" 6 7 #include "content/browser/renderer_host/dip_util.h" 8 #include "content/browser/renderer_host/render_process_host_impl.h" 9 #include "content/public/browser/render_widget_host.h" 10 #include "skia/ext/platform_canvas.h" 11 #include "third_party/skia/include/core/SkCanvas.h" 12 #include "ui/gfx/canvas.h" 13 #include "ui/gfx/image/image_skia.h" 14 #include "ui/gfx/rect.h" 15 #include "ui/gfx/rect_conversions.h" 16 #include "ui/gfx/size_conversions.h" 17 #include "ui/gfx/vector2d_conversions.h" 18 19 namespace { 20 21 gfx::Size ToPixelSize(gfx::Size dipSize, float scale) { 22 return gfx::ToCeiledSize(gfx::ScaleSize(dipSize, scale)); 23 } 24 25 } // namespace 26 27 28 namespace content { 29 30 // Assume that somewhere along the line, someone will do width * height * 4 31 // with signed numbers. If the maximum value is 2**31, then 2**31 / 4 = 32 // 2**29 and floor(sqrt(2**29)) = 23170. 33 34 // Max height and width for layers 35 static const int kMaxVideoLayerSize = 23170; 36 37 BackingStoreAura::BackingStoreAura(RenderWidgetHost* widget, 38 const gfx::Size& size) 39 : BackingStore(widget, size) { 40 device_scale_factor_ = 41 ui::GetImageScale(GetScaleFactorForView(widget->GetView())); 42 gfx::Size pixel_size = ToPixelSize(size, device_scale_factor_); 43 bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 44 pixel_size.width(), pixel_size.height()); 45 bitmap_.allocPixels(); 46 canvas_.reset(new SkCanvas(bitmap_)); 47 } 48 49 BackingStoreAura::~BackingStoreAura() { 50 } 51 52 void BackingStoreAura::SkiaShowRect(const gfx::Point& point, 53 gfx::Canvas* canvas) { 54 gfx::ImageSkia image = gfx::ImageSkia(gfx::ImageSkiaRep(bitmap_, 55 device_scale_factor_)); 56 canvas->DrawImageInt(image, point.x(), point.y()); 57 } 58 59 void BackingStoreAura::ScaleFactorChanged(float device_scale_factor) { 60 if (device_scale_factor == device_scale_factor_) 61 return; 62 63 gfx::Size old_pixel_size = ToPixelSize(size(), device_scale_factor_); 64 device_scale_factor_ = device_scale_factor; 65 66 gfx::Size pixel_size = ToPixelSize(size(), device_scale_factor_); 67 SkBitmap new_bitmap; 68 new_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 69 pixel_size.width(), pixel_size.height()); 70 new_bitmap.allocPixels(); 71 scoped_ptr<SkCanvas> new_canvas(new SkCanvas(new_bitmap)); 72 73 // Copy old contents; a low-res flash is better than a black flash. 74 SkPaint copy_paint; 75 copy_paint.setXfermodeMode(SkXfermode::kSrc_Mode); 76 SkIRect src_rect = SkIRect::MakeWH(old_pixel_size.width(), 77 old_pixel_size.height()); 78 SkRect dst_rect = SkRect::MakeWH(pixel_size.width(), pixel_size.height()); 79 new_canvas.get()->drawBitmapRect(bitmap_, &src_rect, dst_rect, ©_paint); 80 81 canvas_.swap(new_canvas); 82 bitmap_ = new_bitmap; 83 } 84 85 size_t BackingStoreAura::MemorySize() { 86 // NOTE: The computation may be different when the canvas is a subrectangle of 87 // a larger bitmap. 88 return ToPixelSize(size(), device_scale_factor_).GetArea() * 4; 89 } 90 91 void BackingStoreAura::PaintToBackingStore( 92 RenderProcessHost* process, 93 TransportDIB::Id bitmap, 94 const gfx::Rect& bitmap_rect, 95 const std::vector<gfx::Rect>& copy_rects, 96 float scale_factor, 97 const base::Closure& completion_callback, 98 bool* scheduled_completion_callback) { 99 *scheduled_completion_callback = false; 100 if (bitmap_rect.IsEmpty()) 101 return; 102 103 gfx::Rect pixel_bitmap_rect = gfx::ToEnclosingRect( 104 gfx::ScaleRect(bitmap_rect, scale_factor)); 105 106 const int width = pixel_bitmap_rect.width(); 107 const int height = pixel_bitmap_rect.height(); 108 109 if (width <= 0 || width > kMaxVideoLayerSize || 110 height <= 0 || height > kMaxVideoLayerSize) 111 return; 112 113 TransportDIB* dib = process->GetTransportDIB(bitmap); 114 if (!dib) 115 return; 116 117 SkPaint copy_paint; 118 copy_paint.setXfermodeMode(SkXfermode::kSrc_Mode); 119 120 SkBitmap sk_bitmap; 121 sk_bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); 122 sk_bitmap.setPixels(dib->memory()); 123 for (size_t i = 0; i < copy_rects.size(); i++) { 124 const gfx::Rect pixel_copy_rect = gfx::ToEnclosingRect( 125 gfx::ScaleRect(copy_rects[i], scale_factor)); 126 int x = pixel_copy_rect.x() - pixel_bitmap_rect.x(); 127 int y = pixel_copy_rect.y() - pixel_bitmap_rect.y(); 128 SkIRect srcrect = SkIRect::MakeXYWH(x, y, 129 pixel_copy_rect.width(), 130 pixel_copy_rect.height()); 131 132 const gfx::Rect pixel_copy_dst_rect = gfx::ToEnclosingRect( 133 gfx::ScaleRect(copy_rects[i], device_scale_factor_)); 134 SkRect dstrect = SkRect::MakeXYWH( 135 SkIntToScalar(pixel_copy_dst_rect.x()), 136 SkIntToScalar(pixel_copy_dst_rect.y()), 137 SkIntToScalar(pixel_copy_dst_rect.width()), 138 SkIntToScalar(pixel_copy_dst_rect.height())); 139 canvas_.get()->drawBitmapRect(sk_bitmap, &srcrect, dstrect, ©_paint); 140 } 141 } 142 143 void BackingStoreAura::ScrollBackingStore(const gfx::Vector2d& delta, 144 const gfx::Rect& clip_rect, 145 const gfx::Size& view_size) { 146 gfx::Rect pixel_rect = gfx::ToEnclosingRect( 147 gfx::ScaleRect(clip_rect, device_scale_factor_)); 148 gfx::Vector2d pixel_delta = gfx::ToFlooredVector2d( 149 gfx::ScaleVector2d(delta, device_scale_factor_)); 150 151 int x = std::min(pixel_rect.x(), pixel_rect.x() - pixel_delta.x()); 152 int y = std::min(pixel_rect.y(), pixel_rect.y() - pixel_delta.y()); 153 int w = pixel_rect.width() + abs(pixel_delta.x()); 154 int h = pixel_rect.height() + abs(pixel_delta.y()); 155 SkIRect rect = SkIRect::MakeXYWH(x, y, w, h); 156 bitmap_.scrollRect(&rect, pixel_delta.x(), pixel_delta.y()); 157 } 158 159 bool BackingStoreAura::CopyFromBackingStore(const gfx::Rect& rect, 160 skia::PlatformBitmap* output) { 161 const int width = 162 std::min(size().width(), rect.width()) * device_scale_factor_; 163 const int height = 164 std::min(size().height(), rect.height()) * device_scale_factor_; 165 if (!output->Allocate(width, height, true)) 166 return false; 167 168 SkIRect skrect = SkIRect::MakeXYWH(rect.x(), rect.y(), width, height); 169 SkBitmap b; 170 if (!canvas_->readPixels(skrect, &b)) 171 return false; 172 SkCanvas(output->GetBitmap()).writePixels(b, rect.x(), rect.y()); 173 return true; 174 } 175 176 } // namespace content 177