OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webkit/glue/plugins/pepper_device_context_2d.h" | 5 #include "webkit/glue/plugins/pepper_device_context_2d.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "gfx/point.h" | 8 #include "gfx/point.h" |
9 #include "gfx/rect.h" | 9 #include "gfx/rect.h" |
10 #include "skia/ext/platform_canvas.h" | 10 #include "skia/ext/platform_canvas.h" |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 if (!module) | 63 if (!module) |
64 return NULL; | 64 return NULL; |
65 | 65 |
66 scoped_refptr<DeviceContext2D> context(new DeviceContext2D(module)); | 66 scoped_refptr<DeviceContext2D> context(new DeviceContext2D(module)); |
67 if (!context->Init(width, height, is_always_opaque)) | 67 if (!context->Init(width, height, is_always_opaque)) |
68 return NULL; | 68 return NULL; |
69 context->AddRef(); // AddRef for the caller. | 69 context->AddRef(); // AddRef for the caller. |
70 return context->GetResource(); | 70 return context->GetResource(); |
71 } | 71 } |
72 | 72 |
| 73 bool Describe(PP_Resource device_context, |
| 74 int32_t* width, int32_t* height, bool* is_always_opaque) { |
| 75 scoped_refptr<DeviceContext2D> context( |
| 76 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); |
| 77 if (!context.get()) |
| 78 return false; |
| 79 return context->Describe(width, height, is_always_opaque); |
| 80 } |
| 81 |
73 bool PaintImageData(PP_Resource device_context, | 82 bool PaintImageData(PP_Resource device_context, |
74 PP_Resource image, | 83 PP_Resource image, |
75 int32_t x, int32_t y, | 84 int32_t x, int32_t y, |
76 const PP_Rect* src_rect) { | 85 const PP_Rect* src_rect) { |
77 scoped_refptr<DeviceContext2D> context( | 86 scoped_refptr<DeviceContext2D> context( |
78 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); | 87 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); |
79 if (!context.get()) | 88 if (!context.get()) |
80 return false; | 89 return false; |
81 return context->PaintImageData(image, x, y, src_rect); | 90 return context->PaintImageData(image, x, y, src_rect); |
82 } | 91 } |
(...skipping 19 matching lines...) Expand all Loading... |
102 bool Flush(PP_Resource device_context, | 111 bool Flush(PP_Resource device_context, |
103 PPB_DeviceContext2D_FlushCallback callback, | 112 PPB_DeviceContext2D_FlushCallback callback, |
104 void* callback_data) { | 113 void* callback_data) { |
105 scoped_refptr<DeviceContext2D> context( | 114 scoped_refptr<DeviceContext2D> context( |
106 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); | 115 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); |
107 if (!context.get()) | 116 if (!context.get()) |
108 return false; | 117 return false; |
109 return context->Flush(callback, callback_data); | 118 return context->Flush(callback, callback_data); |
110 } | 119 } |
111 | 120 |
| 121 bool ReadImageData(PP_Resource device_context, |
| 122 PP_Resource image, |
| 123 int32_t x, int32_t y) { |
| 124 scoped_refptr<DeviceContext2D> context( |
| 125 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); |
| 126 if (!context.get()) |
| 127 return false; |
| 128 return context->ReadImageData(image, x, y); |
| 129 } |
| 130 |
112 const PPB_DeviceContext2D ppb_devicecontext2d = { | 131 const PPB_DeviceContext2D ppb_devicecontext2d = { |
113 &Create, | 132 &Create, |
| 133 &Describe, |
114 &PaintImageData, | 134 &PaintImageData, |
115 &Scroll, | 135 &Scroll, |
116 &ReplaceContents, | 136 &ReplaceContents, |
117 &Flush | 137 &Flush, |
| 138 &ReadImageData |
118 }; | 139 }; |
119 | 140 |
120 } // namespace | 141 } // namespace |
121 | 142 |
122 struct DeviceContext2D::QueuedOperation { | 143 struct DeviceContext2D::QueuedOperation { |
123 enum Type { | 144 enum Type { |
124 PAINT, | 145 PAINT, |
125 SCROLL, | 146 SCROLL, |
126 REPLACE | 147 REPLACE |
127 }; | 148 }; |
(...skipping 26 matching lines...) Expand all Loading... |
154 | 175 |
155 DeviceContext2D::~DeviceContext2D() { | 176 DeviceContext2D::~DeviceContext2D() { |
156 } | 177 } |
157 | 178 |
158 // static | 179 // static |
159 const PPB_DeviceContext2D* DeviceContext2D::GetInterface() { | 180 const PPB_DeviceContext2D* DeviceContext2D::GetInterface() { |
160 return &ppb_devicecontext2d; | 181 return &ppb_devicecontext2d; |
161 } | 182 } |
162 | 183 |
163 bool DeviceContext2D::Init(int width, int height, bool is_always_opaque) { | 184 bool DeviceContext2D::Init(int width, int height, bool is_always_opaque) { |
| 185 // The underlying ImageData will validate the dimensions. |
164 image_data_ = new ImageData(module()); | 186 image_data_ = new ImageData(module()); |
165 if (!image_data_->Init(PP_IMAGEDATAFORMAT_BGRA_PREMUL, width, height, true) || | 187 if (!image_data_->Init(PP_IMAGEDATAFORMAT_BGRA_PREMUL, width, height, true) || |
166 !image_data_->Map()) { | 188 !image_data_->Map()) { |
167 image_data_ = NULL; | 189 image_data_ = NULL; |
168 return false; | 190 return false; |
169 } | 191 } |
170 | 192 |
171 return true; | 193 return true; |
172 } | 194 } |
173 | 195 |
| 196 bool DeviceContext2D::Describe(int32_t* width, int32_t* height, |
| 197 bool* is_always_opaque) { |
| 198 *width = image_data_->width(); |
| 199 *height = image_data_->height(); |
| 200 *is_always_opaque = false; // TODO(brettw) implement this. |
| 201 return true; |
| 202 } |
| 203 |
174 bool DeviceContext2D::PaintImageData(PP_Resource image, | 204 bool DeviceContext2D::PaintImageData(PP_Resource image, |
175 int32_t x, int32_t y, | 205 int32_t x, int32_t y, |
176 const PP_Rect* src_rect) { | 206 const PP_Rect* src_rect) { |
177 scoped_refptr<ImageData> image_resource( | 207 scoped_refptr<ImageData> image_resource( |
178 ResourceTracker::Get()->GetAsImageData(image)); | 208 ResourceTracker::Get()->GetAsImageData(image)); |
179 if (!image_resource.get() || !image_resource->is_valid()) | 209 if (!image_resource.get()) |
180 return false; | 210 return false; |
181 | 211 |
182 const SkBitmap& new_image_bitmap = image_resource->GetMappedBitmap(); | |
183 | |
184 QueuedOperation operation(QueuedOperation::PAINT); | 212 QueuedOperation operation(QueuedOperation::PAINT); |
185 operation.paint_image = image_resource; | 213 operation.paint_image = image_resource; |
186 if (!ValidateAndConvertRect(src_rect, new_image_bitmap.width(), | 214 if (!ValidateAndConvertRect(src_rect, image_resource->width(), |
187 new_image_bitmap.height(), | 215 image_resource->height(), |
188 &operation.paint_src_rect)) | 216 &operation.paint_src_rect)) |
189 return false; | 217 return false; |
190 | 218 |
191 // Validate the bitmap position using the previously-validated rect. | 219 // Validate the bitmap position using the previously-validated rect, there |
192 if (x < 0 || | 220 // should be no painted area outside of the image. |
193 static_cast<int64>(x) + | 221 int64 x64 = static_cast<int64>(x), y64 = static_cast<int64>(y); |
194 static_cast<int64>(operation.paint_src_rect.right()) > | 222 if (x64 + static_cast<int64>(operation.paint_src_rect.x()) < 0 || |
| 223 x64 + static_cast<int64>(operation.paint_src_rect.right()) > |
195 image_data_->width()) | 224 image_data_->width()) |
196 return false; | 225 return false; |
197 if (y < 0 || | 226 if (y64 + static_cast<int64>(operation.paint_src_rect.y()) < 0 || |
198 static_cast<int64>(y) + | 227 y64 + static_cast<int64>(operation.paint_src_rect.bottom()) > |
199 static_cast<int64>(operation.paint_src_rect.bottom()) > | |
200 image_data_->height()) | 228 image_data_->height()) |
201 return false; | 229 return false; |
202 operation.paint_x = x; | 230 operation.paint_x = x; |
203 operation.paint_y = y; | 231 operation.paint_y = y; |
204 | 232 |
205 queued_operations_.push_back(operation); | 233 queued_operations_.push_back(operation); |
206 return true; | 234 return true; |
207 } | 235 } |
208 | 236 |
209 bool DeviceContext2D::Scroll(const PP_Rect* clip_rect, | 237 bool DeviceContext2D::Scroll(const PP_Rect* clip_rect, |
(...skipping 14 matching lines...) Expand all Loading... |
224 operation.scroll_dx = dx; | 252 operation.scroll_dx = dx; |
225 operation.scroll_dy = dy; | 253 operation.scroll_dy = dy; |
226 | 254 |
227 queued_operations_.push_back(operation); | 255 queued_operations_.push_back(operation); |
228 return false; | 256 return false; |
229 } | 257 } |
230 | 258 |
231 bool DeviceContext2D::ReplaceContents(PP_Resource image) { | 259 bool DeviceContext2D::ReplaceContents(PP_Resource image) { |
232 scoped_refptr<ImageData> image_resource( | 260 scoped_refptr<ImageData> image_resource( |
233 ResourceTracker::Get()->GetAsImageData(image)); | 261 ResourceTracker::Get()->GetAsImageData(image)); |
234 if (!image_resource.get() || !image_resource->is_valid()) | 262 if (!image_resource.get()) |
| 263 return false; |
| 264 if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL) |
235 return false; | 265 return false; |
236 | 266 |
237 if (image_resource->width() != image_data_->width() || | 267 if (image_resource->width() != image_data_->width() || |
238 image_resource->height() != image_data_->height()) | 268 image_resource->height() != image_data_->height()) |
239 return false; | 269 return false; |
240 | 270 |
241 QueuedOperation operation(QueuedOperation::REPLACE); | 271 QueuedOperation operation(QueuedOperation::REPLACE); |
242 operation.replace_image = new ImageData(image_resource->module()); | 272 operation.replace_image = image_resource; |
243 queued_operations_.push_back(operation); | 273 queued_operations_.push_back(operation); |
244 | 274 |
245 // Swap the input image data with the new one we just made in the | 275 return true; |
246 // QueuedOperation. This way the plugin still gets to manage the reference | |
247 // count of the old object without having memory released out from under it. | |
248 // But it ensures that after this, if the plugin does try to use the image | |
249 // it gave us, those operations will fail. | |
250 operation.replace_image->Swap(image_resource.get()); | |
251 | |
252 return false; | |
253 } | 276 } |
254 | 277 |
255 bool DeviceContext2D::Flush(PPB_DeviceContext2D_FlushCallback callback, | 278 bool DeviceContext2D::Flush(PPB_DeviceContext2D_FlushCallback callback, |
256 void* callback_data) { | 279 void* callback_data) { |
257 for (size_t i = 0; i < queued_operations_.size(); i++) { | 280 for (size_t i = 0; i < queued_operations_.size(); i++) { |
258 QueuedOperation& operation = queued_operations_[i]; | 281 QueuedOperation& operation = queued_operations_[i]; |
259 switch (operation.type) { | 282 switch (operation.type) { |
260 case QueuedOperation::PAINT: | 283 case QueuedOperation::PAINT: |
261 ExecutePaintImageData(operation.paint_image.get(), | 284 ExecutePaintImageData(operation.paint_image.get(), |
262 operation.paint_x, operation.paint_y, | 285 operation.paint_x, operation.paint_y, |
(...skipping 23 matching lines...) Expand all Loading... |
286 // Save the callback to execute later. See |unpainted_flush_callbacks_| in | 309 // Save the callback to execute later. See |unpainted_flush_callbacks_| in |
287 // the header file. | 310 // the header file. |
288 if (callback) { | 311 if (callback) { |
289 unpainted_flush_callbacks_.push_back( | 312 unpainted_flush_callbacks_.push_back( |
290 FlushCallbackData(callback, id, context, user_data)); | 313 FlushCallbackData(callback, id, context, user_data)); |
291 } | 314 } |
292 */ | 315 */ |
293 return true; | 316 return true; |
294 } | 317 } |
295 | 318 |
| 319 bool DeviceContext2D::ReadImageData(PP_Resource image, int32_t x, int32_t y) { |
| 320 // Get and validate the image object to paint into. |
| 321 scoped_refptr<ImageData> image_resource( |
| 322 ResourceTracker::Get()->GetAsImageData(image)); |
| 323 if (!image_resource.get()) |
| 324 return false; |
| 325 if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL) |
| 326 return false; // Must be in the right format. |
| 327 |
| 328 // Validate the bitmap position. |
| 329 if (x < 0 || |
| 330 static_cast<int64>(x) + static_cast<int64>(image_resource->width()) > |
| 331 image_data_->width()) |
| 332 return false; |
| 333 if (y < 0 || |
| 334 static_cast<int64>(y) + static_cast<int64>(image_resource->height()) > |
| 335 image_data_->height()) |
| 336 return false; |
| 337 |
| 338 ImageDataAutoMapper auto_mapper(image_resource.get()); |
| 339 if (!auto_mapper.is_valid()) |
| 340 return false; |
| 341 skia::PlatformCanvas* dest_canvas = image_resource->mapped_canvas(); |
| 342 |
| 343 SkIRect src_irect = { x, y, |
| 344 x + image_resource->width(), |
| 345 y + image_resource->height() }; |
| 346 SkRect dest_rect = { SkIntToScalar(0), |
| 347 SkIntToScalar(0), |
| 348 SkIntToScalar(image_resource->width()), |
| 349 SkIntToScalar(image_resource->height()) }; |
| 350 |
| 351 // We want to replace the contents of the bitmap rather than blend. |
| 352 SkPaint paint; |
| 353 paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
| 354 dest_canvas->drawBitmapRect(*image_data_->GetMappedBitmap(), |
| 355 &src_irect, dest_rect, &paint); |
| 356 return true; |
| 357 } |
| 358 |
296 void DeviceContext2D::Paint(WebKit::WebCanvas* canvas, | 359 void DeviceContext2D::Paint(WebKit::WebCanvas* canvas, |
297 const gfx::Rect& plugin_rect, | 360 const gfx::Rect& plugin_rect, |
298 const gfx::Rect& paint_rect) { | 361 const gfx::Rect& paint_rect) { |
299 // We're guaranteed to have a mapped canvas since we mapped it in Init(). | 362 // We're guaranteed to have a mapped canvas since we mapped it in Init(). |
300 const SkBitmap& backing_bitmap = image_data_->GetMappedBitmap(); | 363 const SkBitmap& backing_bitmap = *image_data_->GetMappedBitmap(); |
301 | 364 |
302 #if defined(OS_MACOSX) | 365 #if defined(OS_MACOSX) |
303 SkAutoLockPixels lock(backing_bitmap); | 366 SkAutoLockPixels lock(backing_bitmap); |
304 | 367 |
305 scoped_cftyperef<CGDataProviderRef> data_provider( | 368 scoped_cftyperef<CGDataProviderRef> data_provider( |
306 CGDataProviderCreateWithData( | 369 CGDataProviderCreateWithData( |
307 NULL, backing_bitmap.getAddr32(0, 0), | 370 NULL, backing_bitmap.getAddr32(0, 0), |
308 backing_bitmap.rowBytes() * backing_bitmap.height(), NULL)); | 371 backing_bitmap.rowBytes() * backing_bitmap.height(), NULL)); |
309 scoped_cftyperef<CGImageRef> image( | 372 scoped_cftyperef<CGImageRef> image( |
310 CGImageCreate( | 373 CGImageCreate( |
(...skipping 19 matching lines...) Expand all Loading... |
330 CGContextDrawImage(canvas, bounds, image); | 393 CGContextDrawImage(canvas, bounds, image); |
331 CGContextRestoreGState(canvas); | 394 CGContextRestoreGState(canvas); |
332 #else | 395 #else |
333 gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y()); | 396 gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y()); |
334 canvas->drawBitmap(backing_bitmap, | 397 canvas->drawBitmap(backing_bitmap, |
335 SkIntToScalar(plugin_rect.origin().x()), | 398 SkIntToScalar(plugin_rect.origin().x()), |
336 SkIntToScalar(plugin_rect.origin().y())); | 399 SkIntToScalar(plugin_rect.origin().y())); |
337 #endif | 400 #endif |
338 } | 401 } |
339 | 402 |
340 | 403 void DeviceContext2D::ExecutePaintImageData(ImageData* image, |
341 void DeviceContext2D::ExecutePaintImageData(const ImageData* image, | |
342 int x, int y, | 404 int x, int y, |
343 const gfx::Rect& src_rect) { | 405 const gfx::Rect& src_rect) { |
344 // Portion within the source image to cut out. | 406 // Portion within the source image to cut out. |
345 SkIRect src_irect = { src_rect.x(), src_rect.y(), | 407 SkIRect src_irect = { src_rect.x(), src_rect.y(), |
346 src_rect.right(), src_rect.bottom() }; | 408 src_rect.right(), src_rect.bottom() }; |
347 | 409 |
348 // Location within the backing store to copy to. | 410 // Location within the backing store to copy to. |
349 SkRect dest_rect = { SkIntToScalar(x + src_rect.x()), | 411 SkRect dest_rect = { SkIntToScalar(x + src_rect.x()), |
350 SkIntToScalar(y + src_rect.y()), | 412 SkIntToScalar(y + src_rect.y()), |
351 SkIntToScalar(x + src_rect.right()), | 413 SkIntToScalar(x + src_rect.right()), |
352 SkIntToScalar(y + src_rect.bottom()) }; | 414 SkIntToScalar(y + src_rect.bottom()) }; |
353 | 415 |
354 // We're guaranteed to have a mapped canvas since we mapped it in Init(). | 416 // We're guaranteed to have a mapped canvas since we mapped it in Init(). |
355 skia::PlatformCanvas* backing_canvas = image_data_->mapped_canvas(); | 417 skia::PlatformCanvas* backing_canvas = image_data_->mapped_canvas(); |
356 | 418 |
| 419 // Ensure the source image is mapped to read from it. |
| 420 ImageDataAutoMapper auto_mapper(image); |
| 421 if (!auto_mapper.is_valid()) |
| 422 return; |
| 423 |
357 // We want to replace the contents of the bitmap rather than blend. | 424 // We want to replace the contents of the bitmap rather than blend. |
358 SkPaint paint; | 425 SkPaint paint; |
359 paint.setXfermodeMode(SkXfermode::kSrc_Mode); | 426 paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
360 backing_canvas->drawBitmapRect(image->GetMappedBitmap(), | 427 backing_canvas->drawBitmapRect(*image->GetMappedBitmap(), |
361 &src_irect, dest_rect, &paint); | 428 &src_irect, dest_rect, &paint); |
362 } | 429 } |
363 | 430 |
364 void DeviceContext2D::ExecuteScroll(const gfx::Rect& clip, int dx, int dy) { | 431 void DeviceContext2D::ExecuteScroll(const gfx::Rect& clip, int dx, int dy) { |
365 // FIXME(brettw) | 432 // FIXME(brettw) |
366 } | 433 } |
367 | 434 |
368 void DeviceContext2D::ExecuteReplaceContents(ImageData* image) { | 435 void DeviceContext2D::ExecuteReplaceContents(ImageData* image) { |
369 image_data_->Swap(image); | 436 image_data_->Swap(image); |
370 } | 437 } |
371 | 438 |
372 } // namespace pepper | 439 } // namespace pepper |
OLD | NEW |