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 <iterator> | 7 #include <iterator> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 #include "base/task.h" | 11 #include "base/task.h" |
12 #include "gfx/point.h" | 12 #include "gfx/point.h" |
13 #include "gfx/rect.h" | 13 #include "gfx/rect.h" |
14 #include "skia/ext/platform_canvas.h" | 14 #include "skia/ext/platform_canvas.h" |
| 15 #include "third_party/ppapi/c/pp_errors.h" |
15 #include "third_party/ppapi/c/pp_module.h" | 16 #include "third_party/ppapi/c/pp_module.h" |
16 #include "third_party/ppapi/c/pp_rect.h" | 17 #include "third_party/ppapi/c/pp_rect.h" |
17 #include "third_party/ppapi/c/pp_resource.h" | 18 #include "third_party/ppapi/c/pp_resource.h" |
18 #include "third_party/ppapi/c/ppb_device_context_2d.h" | 19 #include "third_party/ppapi/c/ppb_device_context_2d.h" |
19 #include "third_party/skia/include/core/SkBitmap.h" | 20 #include "third_party/skia/include/core/SkBitmap.h" |
20 #include "webkit/glue/plugins/pepper_image_data.h" | 21 #include "webkit/glue/plugins/pepper_image_data.h" |
21 #include "webkit/glue/plugins/pepper_plugin_instance.h" | 22 #include "webkit/glue/plugins/pepper_plugin_instance.h" |
22 #include "webkit/glue/plugins/pepper_plugin_module.h" | 23 #include "webkit/glue/plugins/pepper_plugin_module.h" |
23 #include "webkit/glue/plugins/pepper_resource_tracker.h" | 24 #include "webkit/glue/plugins/pepper_resource_tracker.h" |
24 | 25 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 } | 113 } |
113 | 114 |
114 bool ReplaceContents(PP_Resource device_context, PP_Resource image) { | 115 bool ReplaceContents(PP_Resource device_context, PP_Resource image) { |
115 scoped_refptr<DeviceContext2D> context( | 116 scoped_refptr<DeviceContext2D> context( |
116 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); | 117 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); |
117 if (!context.get()) | 118 if (!context.get()) |
118 return false; | 119 return false; |
119 return context->ReplaceContents(image); | 120 return context->ReplaceContents(image); |
120 } | 121 } |
121 | 122 |
122 bool Flush(PP_Resource device_context, | 123 int32_t Flush(PP_Resource device_context, |
123 PPB_DeviceContext2D_FlushCallback callback, | 124 PP_CompletionCallback callback) { |
124 void* callback_data) { | |
125 scoped_refptr<DeviceContext2D> context( | 125 scoped_refptr<DeviceContext2D> context( |
126 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); | 126 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); |
127 if (!context.get()) | 127 if (!context.get()) |
128 return false; | 128 return PP_Error_BadResource; |
129 return context->Flush(callback, callback_data); | 129 return context->Flush(callback); |
130 } | 130 } |
131 | 131 |
132 const PPB_DeviceContext2D ppb_devicecontext2d = { | 132 const PPB_DeviceContext2D ppb_devicecontext2d = { |
133 &Create, | 133 &Create, |
134 &IsDeviceContext2D, | 134 &IsDeviceContext2D, |
135 &Describe, | 135 &Describe, |
136 &PaintImageData, | 136 &PaintImageData, |
137 &Scroll, | 137 &Scroll, |
138 &ReplaceContents, | 138 &ReplaceContents, |
139 &Flush | 139 &Flush |
(...skipping 24 matching lines...) Expand all Loading... |
164 gfx::Rect paint_src_rect; | 164 gfx::Rect paint_src_rect; |
165 | 165 |
166 // Valid when type == SCROLL. | 166 // Valid when type == SCROLL. |
167 gfx::Rect scroll_clip_rect; | 167 gfx::Rect scroll_clip_rect; |
168 int scroll_dx, scroll_dy; | 168 int scroll_dx, scroll_dy; |
169 | 169 |
170 // Valid when type == REPLACE. | 170 // Valid when type == REPLACE. |
171 scoped_refptr<ImageData> replace_image; | 171 scoped_refptr<ImageData> replace_image; |
172 }; | 172 }; |
173 | 173 |
174 DeviceContext2D::FlushCallbackData::FlushCallbackData( | |
175 PPB_DeviceContext2D_FlushCallback c, | |
176 void* d) | |
177 : callback_(c), | |
178 callback_data_(d) { | |
179 } | |
180 | |
181 void DeviceContext2D::FlushCallbackData::Execute(PP_Resource device_context) { | |
182 callback_(device_context, callback_data_); | |
183 } | |
184 | |
185 DeviceContext2D::DeviceContext2D(PluginModule* module) | 174 DeviceContext2D::DeviceContext2D(PluginModule* module) |
186 : Resource(module), | 175 : Resource(module), |
187 bound_instance_(NULL), | 176 bound_instance_(NULL), |
188 flushed_any_data_(false), | 177 flushed_any_data_(false), |
189 offscreen_flush_pending_(false) { | 178 offscreen_flush_pending_(false) { |
190 } | 179 } |
191 | 180 |
192 DeviceContext2D::~DeviceContext2D() { | 181 DeviceContext2D::~DeviceContext2D() { |
193 } | 182 } |
194 | 183 |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 image_resource->height() != image_data_->height()) | 273 image_resource->height() != image_data_->height()) |
285 return false; | 274 return false; |
286 | 275 |
287 QueuedOperation operation(QueuedOperation::REPLACE); | 276 QueuedOperation operation(QueuedOperation::REPLACE); |
288 operation.replace_image = image_resource; | 277 operation.replace_image = image_resource; |
289 queued_operations_.push_back(operation); | 278 queued_operations_.push_back(operation); |
290 | 279 |
291 return true; | 280 return true; |
292 } | 281 } |
293 | 282 |
294 bool DeviceContext2D::Flush(PPB_DeviceContext2D_FlushCallback callback, | 283 int32_t DeviceContext2D::Flush(const PP_CompletionCallback& callback) { |
295 void* callback_data) { | |
296 // Don't allow more than one pending flush at a time. | 284 // Don't allow more than one pending flush at a time. |
297 if (HasPendingFlush()) | 285 if (HasPendingFlush()) |
298 return false; | 286 return PP_Error_InProgress; |
299 | 287 |
300 // TODO(brettw) check that the current thread is not the main one and | 288 // TODO(brettw) check that the current thread is not the main one and |
301 // implement blocking flushes in this case. | 289 // implement blocking flushes in this case. |
302 if (!callback) | 290 if (!callback.func) |
303 return false; | 291 return PP_Error_BadArgument; |
304 | 292 |
305 gfx::Rect changed_rect; | 293 gfx::Rect changed_rect; |
306 for (size_t i = 0; i < queued_operations_.size(); i++) { | 294 for (size_t i = 0; i < queued_operations_.size(); i++) { |
307 QueuedOperation& operation = queued_operations_[i]; | 295 QueuedOperation& operation = queued_operations_[i]; |
308 gfx::Rect op_rect; | 296 gfx::Rect op_rect; |
309 switch (operation.type) { | 297 switch (operation.type) { |
310 case QueuedOperation::PAINT: | 298 case QueuedOperation::PAINT: |
311 ExecutePaintImageData(operation.paint_image.get(), | 299 ExecutePaintImageData(operation.paint_image.get(), |
312 operation.paint_x, operation.paint_y, | 300 operation.paint_x, operation.paint_y, |
313 operation.paint_src_rect, | 301 operation.paint_src_rect, |
(...skipping 15 matching lines...) Expand all Loading... |
329 | 317 |
330 // We need the rect to be in terms of the current clip rect of the plugin | 318 // We need the rect to be in terms of the current clip rect of the plugin |
331 // since that's what will actually be painted. If we issue an invalidate | 319 // since that's what will actually be painted. If we issue an invalidate |
332 // for a clipped-out region, WebKit will do nothing and we won't get any | 320 // for a clipped-out region, WebKit will do nothing and we won't get any |
333 // ViewInitiatedPaint/ViewFlushedPaint calls, leaving our callback stranded. | 321 // ViewInitiatedPaint/ViewFlushedPaint calls, leaving our callback stranded. |
334 gfx::Rect visible_changed_rect; | 322 gfx::Rect visible_changed_rect; |
335 if (bound_instance_ && !changed_rect.IsEmpty()) | 323 if (bound_instance_ && !changed_rect.IsEmpty()) |
336 visible_changed_rect = bound_instance_->clip().Intersect(changed_rect); | 324 visible_changed_rect = bound_instance_->clip().Intersect(changed_rect); |
337 | 325 |
338 if (bound_instance_ && !visible_changed_rect.IsEmpty()) { | 326 if (bound_instance_ && !visible_changed_rect.IsEmpty()) { |
339 unpainted_flush_callback_.reset(new FlushCallbackData(callback, | 327 unpainted_flush_callback_.Set(callback); |
340 callback_data)); | |
341 bound_instance_->InvalidateRect(visible_changed_rect); | 328 bound_instance_->InvalidateRect(visible_changed_rect); |
342 } else { | 329 } else { |
343 // There's nothing visible to invalidate so just schedule the callback to | 330 // There's nothing visible to invalidate so just schedule the callback to |
344 // execute in the next round of the message loop. | 331 // execute in the next round of the message loop. |
345 ScheduleOffscreenCallback( | 332 ScheduleOffscreenCallback(FlushCallbackData(callback)); |
346 FlushCallbackData(callback, callback_data)); | |
347 } | 333 } |
348 return true; | 334 return PP_Error_WouldBlock; |
349 } | 335 } |
350 | 336 |
351 bool DeviceContext2D::ReadImageData(PP_Resource image, int32_t x, int32_t y) { | 337 bool DeviceContext2D::ReadImageData(PP_Resource image, int32_t x, int32_t y) { |
352 // Get and validate the image object to paint into. | 338 // Get and validate the image object to paint into. |
353 scoped_refptr<ImageData> image_resource( | 339 scoped_refptr<ImageData> image_resource( |
354 ResourceTracker::Get()->GetAsImageData(image)); | 340 ResourceTracker::Get()->GetAsImageData(image)); |
355 if (!image_resource.get()) | 341 if (!image_resource.get()) |
356 return false; | 342 return false; |
357 if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL) | 343 if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL) |
358 return false; // Must be in the right format. | 344 return false; // Must be in the right format. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 bool DeviceContext2D::BindToInstance(PluginInstance* new_instance) { | 377 bool DeviceContext2D::BindToInstance(PluginInstance* new_instance) { |
392 if (bound_instance_ == new_instance) | 378 if (bound_instance_ == new_instance) |
393 return true; // Rebinding the same device, nothing to do. | 379 return true; // Rebinding the same device, nothing to do. |
394 if (bound_instance_ && new_instance) | 380 if (bound_instance_ && new_instance) |
395 return false; // Can't change a bound device. | 381 return false; // Can't change a bound device. |
396 | 382 |
397 if (!new_instance) { | 383 if (!new_instance) { |
398 // When the device is detached, we'll not get any more paint callbacks so | 384 // When the device is detached, we'll not get any more paint callbacks so |
399 // we need to clear the list, but we still want to issue any pending | 385 // we need to clear the list, but we still want to issue any pending |
400 // callbacks to the plugin. | 386 // callbacks to the plugin. |
401 if (unpainted_flush_callback_.get()) { | 387 if (!unpainted_flush_callback_.is_null()) { |
402 ScheduleOffscreenCallback(*unpainted_flush_callback_.get()); | 388 ScheduleOffscreenCallback(unpainted_flush_callback_); |
403 unpainted_flush_callback_.reset(); | 389 unpainted_flush_callback_.Clear(); |
404 } | 390 } |
405 if (painted_flush_callback_.get()) { | 391 if (!painted_flush_callback_.is_null()) { |
406 ScheduleOffscreenCallback(*painted_flush_callback_.get()); | 392 ScheduleOffscreenCallback(painted_flush_callback_); |
407 painted_flush_callback_.reset(); | 393 painted_flush_callback_.Clear(); |
408 } | 394 } |
409 } else if (flushed_any_data_) { | 395 } else if (flushed_any_data_) { |
410 // Only schedule a paint if this backing store has had any data flushed to | 396 // Only schedule a paint if this backing store has had any data flushed to |
411 // it. This is an optimization. A "normal" plugin will first allocated a | 397 // it. This is an optimization. A "normal" plugin will first allocated a |
412 // backing store, bind it, and then execute their normal painting and | 398 // backing store, bind it, and then execute their normal painting and |
413 // update loop. If binding a device always invalidated, it would mean we | 399 // update loop. If binding a device always invalidated, it would mean we |
414 // would get one paint for the bind, and one for the first time the plugin | 400 // would get one paint for the bind, and one for the first time the plugin |
415 // actually painted something. By not bothering to schedule an invalidate | 401 // actually painted something. By not bothering to schedule an invalidate |
416 // when an empty device is initially bound, we can save an extra paint for | 402 // when an empty device is initially bound, we can save an extra paint for |
417 // many plugins during the critical page initialization phase. | 403 // many plugins during the critical page initialization phase. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y()); | 448 gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y()); |
463 canvas->drawBitmap(backing_bitmap, | 449 canvas->drawBitmap(backing_bitmap, |
464 SkIntToScalar(plugin_rect.origin().x()), | 450 SkIntToScalar(plugin_rect.origin().x()), |
465 SkIntToScalar(plugin_rect.origin().y())); | 451 SkIntToScalar(plugin_rect.origin().y())); |
466 #endif | 452 #endif |
467 } | 453 } |
468 | 454 |
469 void DeviceContext2D::ViewInitiatedPaint() { | 455 void DeviceContext2D::ViewInitiatedPaint() { |
470 // Move any "unpainted" callback to the painted state. See | 456 // Move any "unpainted" callback to the painted state. See |
471 // |unpainted_flush_callback_| in the header for more. | 457 // |unpainted_flush_callback_| in the header for more. |
472 if (unpainted_flush_callback_.get()) { | 458 if (!unpainted_flush_callback_.is_null()) { |
473 DCHECK(!painted_flush_callback_.get()); | 459 DCHECK(painted_flush_callback_.is_null()); |
474 painted_flush_callback_.swap(unpainted_flush_callback_); | 460 std::swap(painted_flush_callback_, unpainted_flush_callback_); |
475 } | 461 } |
476 } | 462 } |
477 | 463 |
478 void DeviceContext2D::ViewFlushedPaint() { | 464 void DeviceContext2D::ViewFlushedPaint() { |
479 // Notify any "painted" callback. See |unpainted_flush_callback_| in the | 465 // Notify any "painted" callback. See |unpainted_flush_callback_| in the |
480 // header for more. | 466 // header for more. |
481 if (painted_flush_callback_.get()) { | 467 if (!painted_flush_callback_.is_null()) { |
482 // We must clear this variable before issuing the callback. It will be | 468 // We must clear this variable before issuing the callback. It will be |
483 // common for the plugin to issue another invalidate in response to a flush | 469 // common for the plugin to issue another invalidate in response to a flush |
484 // callback, and we don't want to think that a callback is already pending. | 470 // callback, and we don't want to think that a callback is already pending. |
485 scoped_ptr<FlushCallbackData> callback; | 471 FlushCallbackData callback; |
486 callback.swap(painted_flush_callback_); | 472 std::swap(callback, painted_flush_callback_); |
487 callback->Execute(GetResource()); | 473 callback.Execute(PP_OK); |
488 } | 474 } |
489 } | 475 } |
490 | 476 |
491 void DeviceContext2D::ExecutePaintImageData(ImageData* image, | 477 void DeviceContext2D::ExecutePaintImageData(ImageData* image, |
492 int x, int y, | 478 int x, int y, |
493 const gfx::Rect& src_rect, | 479 const gfx::Rect& src_rect, |
494 gfx::Rect* invalidated_rect) { | 480 gfx::Rect* invalidated_rect) { |
495 // Ensure the source image is mapped to read from it. | 481 // Ensure the source image is mapped to read from it. |
496 ImageDataAutoMapper auto_mapper(image); | 482 ImageDataAutoMapper auto_mapper(image); |
497 if (!auto_mapper.is_valid()) | 483 if (!auto_mapper.is_valid()) |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 callback)); | 528 callback)); |
543 } | 529 } |
544 | 530 |
545 void DeviceContext2D::ExecuteOffscreenCallback(FlushCallbackData data) { | 531 void DeviceContext2D::ExecuteOffscreenCallback(FlushCallbackData data) { |
546 DCHECK(offscreen_flush_pending_); | 532 DCHECK(offscreen_flush_pending_); |
547 | 533 |
548 // We must clear this flag before issuing the callback. It will be | 534 // We must clear this flag before issuing the callback. It will be |
549 // common for the plugin to issue another invalidate in response to a flush | 535 // common for the plugin to issue another invalidate in response to a flush |
550 // callback, and we don't want to think that a callback is already pending. | 536 // callback, and we don't want to think that a callback is already pending. |
551 offscreen_flush_pending_ = false; | 537 offscreen_flush_pending_ = false; |
552 data.Execute(GetResource()); | 538 data.Execute(PP_OK); |
553 } | 539 } |
554 | 540 |
555 bool DeviceContext2D::HasPendingFlush() const { | 541 bool DeviceContext2D::HasPendingFlush() const { |
556 return unpainted_flush_callback_.get() || painted_flush_callback_.get() || | 542 return !unpainted_flush_callback_.is_null() || |
| 543 !painted_flush_callback_.is_null() || |
557 offscreen_flush_pending_; | 544 offscreen_flush_pending_; |
558 } | 545 } |
559 | 546 |
560 } // namespace pepper | 547 } // namespace pepper |
OLD | NEW |