OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 "webkit/glue/plugins/pepper_device_context_2d.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "gfx/point.h" |
| 9 #include "gfx/rect.h" |
| 10 #include "skia/ext/platform_canvas.h" |
| 11 #include "third_party/ppapi/c/pp_module.h" |
| 12 #include "third_party/ppapi/c/pp_rect.h" |
| 13 #include "third_party/ppapi/c/pp_resource.h" |
| 14 #include "third_party/ppapi/c/ppb_device_context_2d.h" |
| 15 #include "third_party/skia/include/core/SkBitmap.h" |
| 16 #include "webkit/glue/plugins/pepper_image_data.h" |
| 17 #include "webkit/glue/plugins/pepper_plugin_module.h" |
| 18 #include "webkit/glue/plugins/pepper_resource_tracker.h" |
| 19 |
| 20 #if defined(OS_MACOSX) |
| 21 #include "base/mac_util.h" |
| 22 #include "base/scoped_cftyperef.h" |
| 23 #endif |
| 24 |
| 25 namespace pepper { |
| 26 |
| 27 namespace { |
| 28 |
| 29 PP_Resource Create(PP_Module module_id, int32_t width, int32_t height) { |
| 30 PluginModule* module = PluginModule::FromPPModule(module_id); |
| 31 if (!module) |
| 32 return NullPPResource(); |
| 33 |
| 34 scoped_refptr<DeviceContext2D> context(new DeviceContext2D(module)); |
| 35 if (!context->Init(width, height)) |
| 36 return NullPPResource(); |
| 37 context->AddRef(); // AddRef for the caller. |
| 38 return context->GetResource(); |
| 39 } |
| 40 |
| 41 void PaintImageData(PP_Resource device_context, |
| 42 PP_Resource image, |
| 43 int32_t x, int32_t y, |
| 44 const PP_Rect* dirty, |
| 45 uint32_t dirty_rect_count, |
| 46 PPB_DeviceContext2D_PaintCallback callback, |
| 47 void* callback_data) { |
| 48 scoped_refptr<Resource> device_resource = |
| 49 ResourceTracker::Get()->GetResource(device_context); |
| 50 if (!device_resource.get()) |
| 51 return; |
| 52 DeviceContext2D* context = device_resource->AsDeviceContext2D(); |
| 53 if (!context) |
| 54 return; |
| 55 context->PaintImageData(image, x, y, dirty, dirty_rect_count, |
| 56 callback, callback_data); |
| 57 } |
| 58 |
| 59 const PPB_DeviceContext2D ppb_devicecontext2d = { |
| 60 &Create, |
| 61 &PaintImageData, |
| 62 }; |
| 63 |
| 64 } // namespace |
| 65 |
| 66 DeviceContext2D::DeviceContext2D(PluginModule* module) : Resource(module) { |
| 67 } |
| 68 |
| 69 DeviceContext2D::~DeviceContext2D() { |
| 70 } |
| 71 |
| 72 // static |
| 73 const PPB_DeviceContext2D* DeviceContext2D::GetInterface() { |
| 74 return &ppb_devicecontext2d; |
| 75 } |
| 76 |
| 77 bool DeviceContext2D::Init(int width, int height) { |
| 78 image_data_.reset(new ImageData(module())); |
| 79 if (!image_data_->Init(PP_IMAGEDATAFORMAT_BGRA_PREMUL, width, height) || |
| 80 !image_data_->Map()) { |
| 81 image_data_.reset(); |
| 82 return false; |
| 83 } |
| 84 |
| 85 return true; |
| 86 } |
| 87 |
| 88 void DeviceContext2D::PaintImageData(PP_Resource image, |
| 89 int32_t x, int32_t y, |
| 90 const PP_Rect* dirty, |
| 91 uint32_t dirty_rect_count, |
| 92 PPB_DeviceContext2D_PaintCallback callback, |
| 93 void* callback_data) { |
| 94 scoped_refptr<Resource> image_resource = |
| 95 ResourceTracker::Get()->GetResource(image); |
| 96 if (!image_resource.get()) |
| 97 return; |
| 98 ImageData* new_image_data = image_resource->AsImageData(); |
| 99 if (!new_image_data) |
| 100 return; |
| 101 |
| 102 const SkBitmap& new_image_bitmap = new_image_data->GetMappedBitmap(); |
| 103 |
| 104 // TODO(brettw) handle multiple dirty rects. |
| 105 DCHECK(dirty_rect_count == 1); |
| 106 |
| 107 // Draw the bitmap to the backing store. |
| 108 SkIRect src_rect; |
| 109 if (dirty->left == 0 && dirty->top == 0 && |
| 110 dirty->right == 0 && dirty->bottom == 0) { |
| 111 // Default to the entire bitmap. |
| 112 src_rect.fLeft = 0; |
| 113 src_rect.fTop = 0; |
| 114 src_rect.fRight = new_image_bitmap.width(); |
| 115 src_rect.fBottom = new_image_bitmap.height(); |
| 116 } else { |
| 117 src_rect.fLeft = dirty->left; |
| 118 src_rect.fTop = dirty->top; |
| 119 src_rect.fRight = dirty->right; |
| 120 src_rect.fBottom = dirty->bottom; |
| 121 } |
| 122 SkRect dest_rect = { SkIntToScalar(src_rect.fLeft), |
| 123 SkIntToScalar(src_rect.fTop), |
| 124 SkIntToScalar(src_rect.fRight), |
| 125 SkIntToScalar(src_rect.fBottom) }; |
| 126 |
| 127 // We're guaranteed to have a mapped canvas since we mapped it in Init(). |
| 128 skia::PlatformCanvas* backing_canvas = image_data_->mapped_canvas(); |
| 129 |
| 130 // We want to replace the contents of the bitmap rather than blend. |
| 131 SkPaint paint; |
| 132 paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
| 133 backing_canvas->drawBitmapRect(new_image_bitmap, |
| 134 &src_rect, dest_rect, &paint); |
| 135 |
| 136 // TODO(brettw) implement invalidate and callbacks! |
| 137 |
| 138 // Cause the updated part of the screen to be repainted. This will happen |
| 139 // asynchronously. |
| 140 /* |
| 141 gfx::Rect dest_gfx_rect(dirty->left, dirty->top, |
| 142 dirty->right - dirty->left, |
| 143 dirty->bottom - dirty->top); |
| 144 |
| 145 plugin_delegate_->instance()->webplugin()->InvalidateRect(dest_gfx_rect); |
| 146 |
| 147 // Save the callback to execute later. See |unpainted_flush_callbacks_| in |
| 148 // the header file. |
| 149 if (callback) { |
| 150 unpainted_flush_callbacks_.push_back( |
| 151 FlushCallbackData(callback, id, context, user_data)); |
| 152 } |
| 153 */ |
| 154 } |
| 155 |
| 156 void DeviceContext2D::Paint(WebKit::WebCanvas* canvas, |
| 157 const gfx::Rect& plugin_rect, |
| 158 const gfx::Rect& paint_rect) { |
| 159 // We're guaranteed to have a mapped canvas since we mapped it in Init(). |
| 160 const SkBitmap& backing_bitmap = image_data_->GetMappedBitmap(); |
| 161 |
| 162 #if defined(OS_MACOSX) |
| 163 SkAutoLockPixels lock(backing_bitmap); |
| 164 |
| 165 scoped_cftyperef<CGDataProviderRef> data_provider( |
| 166 CGDataProviderCreateWithData( |
| 167 NULL, backing_bitmap.getAddr32(0, 0), |
| 168 backing_bitmap.rowBytes() * backing_bitmap.height(), NULL)); |
| 169 scoped_cftyperef<CGImageRef> image( |
| 170 CGImageCreate( |
| 171 backing_bitmap.width(), backing_bitmap.height(), |
| 172 8, 32, backing_bitmap.rowBytes(), |
| 173 mac_util::GetSystemColorSpace(), |
| 174 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, |
| 175 data_provider, NULL, false, kCGRenderingIntentDefault)); |
| 176 |
| 177 // Flip the transform |
| 178 CGContextSaveGState(canvas); |
| 179 float window_height = static_cast<float>(CGBitmapContextGetHeight(canvas)); |
| 180 CGContextTranslateCTM(canvas, 0, window_height); |
| 181 CGContextScaleCTM(canvas, 1.0, -1.0); |
| 182 |
| 183 CGRect bounds; |
| 184 bounds.origin.x = plugin_rect.origin().x(); |
| 185 bounds.origin.y = window_height - plugin_rect.origin().y() - |
| 186 backing_bitmap.height(); |
| 187 bounds.size.width = backing_bitmap.width(); |
| 188 bounds.size.height = backing_bitmap.height(); |
| 189 |
| 190 CGContextDrawImage(canvas, bounds, image); |
| 191 CGContextRestoreGState(canvas); |
| 192 #else |
| 193 gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y()); |
| 194 canvas->drawBitmap(backing_bitmap, |
| 195 SkIntToScalar(plugin_rect.origin().x()), |
| 196 SkIntToScalar(plugin_rect.origin().y())); |
| 197 #endif |
| 198 } |
| 199 |
| 200 } // namespace pepper |
OLD | NEW |