Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: webkit/glue/plugins/pepper_device_context_2d.cc

Issue 2712002: First pass at implementing real Flush callbacks. This does not currently... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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>
8
7 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop.h"
11 #include "base/task.h"
8 #include "gfx/point.h" 12 #include "gfx/point.h"
9 #include "gfx/rect.h" 13 #include "gfx/rect.h"
10 #include "skia/ext/platform_canvas.h" 14 #include "skia/ext/platform_canvas.h"
11 #include "third_party/ppapi/c/pp_module.h" 15 #include "third_party/ppapi/c/pp_module.h"
12 #include "third_party/ppapi/c/pp_rect.h" 16 #include "third_party/ppapi/c/pp_rect.h"
13 #include "third_party/ppapi/c/pp_resource.h" 17 #include "third_party/ppapi/c/pp_resource.h"
14 #include "third_party/ppapi/c/ppb_device_context_2d.h" 18 #include "third_party/ppapi/c/ppb_device_context_2d.h"
15 #include "third_party/skia/include/core/SkBitmap.h" 19 #include "third_party/skia/include/core/SkBitmap.h"
16 #include "webkit/glue/plugins/pepper_image_data.h" 20 #include "webkit/glue/plugins/pepper_image_data.h"
21 #include "webkit/glue/plugins/pepper_plugin_instance.h"
17 #include "webkit/glue/plugins/pepper_plugin_module.h" 22 #include "webkit/glue/plugins/pepper_plugin_module.h"
18 #include "webkit/glue/plugins/pepper_resource_tracker.h" 23 #include "webkit/glue/plugins/pepper_resource_tracker.h"
19 24
20 #if defined(OS_MACOSX) 25 #if defined(OS_MACOSX)
21 #include "base/mac_util.h" 26 #include "base/mac_util.h"
22 #include "base/scoped_cftyperef.h" 27 #include "base/scoped_cftyperef.h"
23 #endif 28 #endif
24 29
25 namespace pepper { 30 namespace pepper {
26 31
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 if (!module) 68 if (!module)
64 return NULL; 69 return NULL;
65 70
66 scoped_refptr<DeviceContext2D> context(new DeviceContext2D(module)); 71 scoped_refptr<DeviceContext2D> context(new DeviceContext2D(module));
67 if (!context->Init(width, height, is_always_opaque)) 72 if (!context->Init(width, height, is_always_opaque))
68 return NULL; 73 return NULL;
69 context->AddRef(); // AddRef for the caller. 74 context->AddRef(); // AddRef for the caller.
70 return context->GetResource(); 75 return context->GetResource();
71 } 76 }
72 77
78 bool IsDeviceContext2D(PP_Resource resource) {
79 scoped_refptr<DeviceContext2D> context(
80 ResourceTracker::Get()->GetAsDeviceContext2D(resource));
81 return !!context.get();
82 }
83
73 bool Describe(PP_Resource device_context, 84 bool Describe(PP_Resource device_context,
74 int32_t* width, int32_t* height, bool* is_always_opaque) { 85 int32_t* width, int32_t* height, bool* is_always_opaque) {
75 scoped_refptr<DeviceContext2D> context( 86 scoped_refptr<DeviceContext2D> context(
76 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); 87 ResourceTracker::Get()->GetAsDeviceContext2D(device_context));
77 if (!context.get()) 88 if (!context.get())
78 return false; 89 return false;
79 return context->Describe(width, height, is_always_opaque); 90 return context->Describe(width, height, is_always_opaque);
80 } 91 }
81 92
82 bool PaintImageData(PP_Resource device_context, 93 bool PaintImageData(PP_Resource device_context,
(...skipping 30 matching lines...) Expand all
113 void* callback_data) { 124 void* callback_data) {
114 scoped_refptr<DeviceContext2D> context( 125 scoped_refptr<DeviceContext2D> context(
115 ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); 126 ResourceTracker::Get()->GetAsDeviceContext2D(device_context));
116 if (!context.get()) 127 if (!context.get())
117 return false; 128 return false;
118 return context->Flush(callback, callback_data); 129 return context->Flush(callback, callback_data);
119 } 130 }
120 131
121 const PPB_DeviceContext2D ppb_devicecontext2d = { 132 const PPB_DeviceContext2D ppb_devicecontext2d = {
122 &Create, 133 &Create,
134 &IsDeviceContext2D,
123 &Describe, 135 &Describe,
124 &PaintImageData, 136 &PaintImageData,
125 &Scroll, 137 &Scroll,
126 &ReplaceContents, 138 &ReplaceContents,
127 &Flush 139 &Flush
128 }; 140 };
129 141
130 } // namespace 142 } // namespace
131 143
132 struct DeviceContext2D::QueuedOperation { 144 struct DeviceContext2D::QueuedOperation {
(...skipping 19 matching lines...) Expand all
152 gfx::Rect paint_src_rect; 164 gfx::Rect paint_src_rect;
153 165
154 // Valid when type == SCROLL. 166 // Valid when type == SCROLL.
155 gfx::Rect scroll_clip_rect; 167 gfx::Rect scroll_clip_rect;
156 int scroll_dx, scroll_dy; 168 int scroll_dx, scroll_dy;
157 169
158 // Valid when type == REPLACE. 170 // Valid when type == REPLACE.
159 scoped_refptr<ImageData> replace_image; 171 scoped_refptr<ImageData> replace_image;
160 }; 172 };
161 173
162 DeviceContext2D::DeviceContext2D(PluginModule* module) : Resource(module) { 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)
186 : Resource(module),
187 bound_instance_(NULL),
188 flushed_any_data_(false) {
163 } 189 }
164 190
165 DeviceContext2D::~DeviceContext2D() { 191 DeviceContext2D::~DeviceContext2D() {
166 } 192 }
167 193
168 // static 194 // static
169 const PPB_DeviceContext2D* DeviceContext2D::GetInterface() { 195 const PPB_DeviceContext2D* DeviceContext2D::GetInterface() {
170 return &ppb_devicecontext2d; 196 return &ppb_devicecontext2d;
171 } 197 }
172 198
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 285
260 QueuedOperation operation(QueuedOperation::REPLACE); 286 QueuedOperation operation(QueuedOperation::REPLACE);
261 operation.replace_image = image_resource; 287 operation.replace_image = image_resource;
262 queued_operations_.push_back(operation); 288 queued_operations_.push_back(operation);
263 289
264 return true; 290 return true;
265 } 291 }
266 292
267 bool DeviceContext2D::Flush(PPB_DeviceContext2D_FlushCallback callback, 293 bool DeviceContext2D::Flush(PPB_DeviceContext2D_FlushCallback callback,
268 void* callback_data) { 294 void* callback_data) {
295 // TODO(brettw) check that the current thread is not the main one and
296 // implement blocking flushes in this case.
297 if (!callback)
298 return false;
299
300 if (queued_operations_.empty())
301 return true; // Nothing to do.
302
303 gfx::Rect changed_rect;
269 for (size_t i = 0; i < queued_operations_.size(); i++) { 304 for (size_t i = 0; i < queued_operations_.size(); i++) {
270 QueuedOperation& operation = queued_operations_[i]; 305 QueuedOperation& operation = queued_operations_[i];
306 gfx::Rect op_rect;
271 switch (operation.type) { 307 switch (operation.type) {
272 case QueuedOperation::PAINT: 308 case QueuedOperation::PAINT:
273 ExecutePaintImageData(operation.paint_image.get(), 309 ExecutePaintImageData(operation.paint_image.get(),
274 operation.paint_x, operation.paint_y, 310 operation.paint_x, operation.paint_y,
275 operation.paint_src_rect); 311 operation.paint_src_rect,
312 &op_rect);
276 break; 313 break;
277 case QueuedOperation::SCROLL: 314 case QueuedOperation::SCROLL:
278 ExecuteScroll(operation.scroll_clip_rect, 315 ExecuteScroll(operation.scroll_clip_rect,
279 operation.scroll_dx, operation.scroll_dy); 316 operation.scroll_dx, operation.scroll_dy,
317 &op_rect);
280 break; 318 break;
281 case QueuedOperation::REPLACE: 319 case QueuedOperation::REPLACE:
282 ExecuteReplaceContents(operation.replace_image.get()); 320 ExecuteReplaceContents(operation.replace_image.get(), &op_rect);
283 break; 321 break;
284 } 322 }
323 changed_rect = changed_rect.Union(op_rect);
285 } 324 }
286 queued_operations_.clear(); 325 queued_operations_.clear();
287 // TODO(brettw) implement invalidate and callbacks! 326 flushed_any_data_ = true;
288 327
289 // Cause the updated part of the screen to be repainted. This will happen 328 // We need the rect to be in terms of the current clip rect of the plugin
290 // asynchronously. 329 // since that's what will actually be painted. If we issue an invalidate
291 /* 330 // for a clipped-out region, WebKit will do nothing and we won't get any
292 gfx::Rect dest_gfx_rect(src_rect->left, src_rect->top, 331 // ViewInitiatedPaint/ViewFlushedPaint calls, leaving our callback stranded.
293 src_rect->right - src_rect->left, 332 gfx::Rect visible_changed_rect;
294 src_rect->bottom - src_rect->top); 333 if (bound_instance_ && !changed_rect.IsEmpty())
334 visible_changed_rect = bound_instance_->clip().Intersect(changed_rect);
295 335
296 plugin_delegate_->instance()->webplugin()->InvalidateRect(dest_gfx_rect); 336 if (bound_instance_ && !visible_changed_rect.IsEmpty()) {
297 337 unpainted_flush_callbacks_.push_back(FlushCallbackData(callback,
298 // Save the callback to execute later. See |unpainted_flush_callbacks_| in 338 callback_data));
299 // the header file. 339 bound_instance_->InvalidateRect(visible_changed_rect);
300 if (callback) { 340 } else {
301 unpainted_flush_callbacks_.push_back( 341 // There's nothing visible to invalidate so just schedule the callback to
302 FlushCallbackData(callback, id, context, user_data)); 342 // execute in the next round of the message loop.
343 ScheduleOffscreenCallback(
344 FlushCallbackData(callback, callback_data));
303 } 345 }
304 */
305 return true; 346 return true;
306 } 347 }
307 348
308 bool DeviceContext2D::ReadImageData(PP_Resource image, int32_t x, int32_t y) { 349 bool DeviceContext2D::ReadImageData(PP_Resource image, int32_t x, int32_t y) {
309 // Get and validate the image object to paint into. 350 // Get and validate the image object to paint into.
310 scoped_refptr<ImageData> image_resource( 351 scoped_refptr<ImageData> image_resource(
311 ResourceTracker::Get()->GetAsImageData(image)); 352 ResourceTracker::Get()->GetAsImageData(image));
312 if (!image_resource.get()) 353 if (!image_resource.get())
313 return false; 354 return false;
314 if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL) 355 if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL)
(...skipping 23 matching lines...) Expand all
338 SkIntToScalar(image_resource->height()) }; 379 SkIntToScalar(image_resource->height()) };
339 380
340 // We want to replace the contents of the bitmap rather than blend. 381 // We want to replace the contents of the bitmap rather than blend.
341 SkPaint paint; 382 SkPaint paint;
342 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 383 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
343 dest_canvas->drawBitmapRect(*image_data_->GetMappedBitmap(), 384 dest_canvas->drawBitmapRect(*image_data_->GetMappedBitmap(),
344 &src_irect, dest_rect, &paint); 385 &src_irect, dest_rect, &paint);
345 return true; 386 return true;
346 } 387 }
347 388
389 bool DeviceContext2D::BindToInstance(PluginInstance* new_instance) {
390 if (bound_instance_ == new_instance)
391 return true; // Rebinding the same device, nothing to do.
392 if (bound_instance_ && new_instance)
393 return false; // Can't change a bound device.
394
395 if (!new_instance) {
396 // When the device is detached, we'll not get any more paint callbacks so
397 // we need to clear the list, but we still want to issue any pending
398 // callbacks to the plugin.
399 for (size_t i = 0; i < unpainted_flush_callbacks_.size(); i++)
400 ScheduleOffscreenCallback(unpainted_flush_callbacks_[i]);
401 for (size_t i = 0; i < painted_flush_callbacks_.size(); i++)
402 ScheduleOffscreenCallback(painted_flush_callbacks_[i]);
403 unpainted_flush_callbacks_.clear();
404 painted_flush_callbacks_.clear();
405 } else if (flushed_any_data_) {
406 // Only schedule a paint if this backing store has had any data flushed to
407 // it. This is an optimization. A "normal" plugin will first allocated a
408 // backing store, bind it, and then execute their normal painting and
409 // update loop. If binding a device always invalidated, it would mean we
410 // would get one paint for the bind, and one for the first time the plugin
411 // actually painted something. By not bothering to schedule an invalidate
412 // when an empty device is initially bound, we can save an extra paint for
413 // many plugins during the critical page initialization phase.
414 new_instance->InvalidateRect(gfx::Rect());
415 }
416
417 bound_instance_ = new_instance;
418 return true;
419 }
420
348 void DeviceContext2D::Paint(WebKit::WebCanvas* canvas, 421 void DeviceContext2D::Paint(WebKit::WebCanvas* canvas,
349 const gfx::Rect& plugin_rect, 422 const gfx::Rect& plugin_rect,
350 const gfx::Rect& paint_rect) { 423 const gfx::Rect& paint_rect) {
351 // We're guaranteed to have a mapped canvas since we mapped it in Init(). 424 // We're guaranteed to have a mapped canvas since we mapped it in Init().
352 const SkBitmap& backing_bitmap = *image_data_->GetMappedBitmap(); 425 const SkBitmap& backing_bitmap = *image_data_->GetMappedBitmap();
353 426
354 #if defined(OS_MACOSX) 427 #if defined(OS_MACOSX)
355 SkAutoLockPixels lock(backing_bitmap); 428 SkAutoLockPixels lock(backing_bitmap);
356 429
357 scoped_cftyperef<CGDataProviderRef> data_provider( 430 scoped_cftyperef<CGDataProviderRef> data_provider(
(...skipping 24 matching lines...) Expand all
382 CGContextDrawImage(canvas, bounds, image); 455 CGContextDrawImage(canvas, bounds, image);
383 CGContextRestoreGState(canvas); 456 CGContextRestoreGState(canvas);
384 #else 457 #else
385 gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y()); 458 gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y());
386 canvas->drawBitmap(backing_bitmap, 459 canvas->drawBitmap(backing_bitmap,
387 SkIntToScalar(plugin_rect.origin().x()), 460 SkIntToScalar(plugin_rect.origin().x()),
388 SkIntToScalar(plugin_rect.origin().y())); 461 SkIntToScalar(plugin_rect.origin().y()));
389 #endif 462 #endif
390 } 463 }
391 464
465 void DeviceContext2D::ViewInitiatedPaint() {
466 // Move all "unpainted" callbacks to the painted state. See
467 // |unpainted_flush_callbacks_| in the header for more.
468 std::copy(unpainted_flush_callbacks_.begin(),
469 unpainted_flush_callbacks_.end(),
470 std::back_inserter(painted_flush_callbacks_));
471 unpainted_flush_callbacks_.clear();
472 }
473
474 void DeviceContext2D::ViewFlushedPaint() {
475 // Notify all "painted" callbacks. See |unpainted_flush_callbacks_| in the
476 // header for more.
477 for (size_t i = 0; i < painted_flush_callbacks_.size(); i++)
478 painted_flush_callbacks_[i].Execute(GetResource());
479 painted_flush_callbacks_.clear();
480 }
481
392 void DeviceContext2D::ExecutePaintImageData(ImageData* image, 482 void DeviceContext2D::ExecutePaintImageData(ImageData* image,
393 int x, int y, 483 int x, int y,
394 const gfx::Rect& src_rect) { 484 const gfx::Rect& src_rect,
485 gfx::Rect* invalidated_rect) {
486 // Ensure the source image is mapped to read from it.
487 ImageDataAutoMapper auto_mapper(image);
488 if (!auto_mapper.is_valid())
489 return;
490
395 // Portion within the source image to cut out. 491 // Portion within the source image to cut out.
396 SkIRect src_irect = { src_rect.x(), src_rect.y(), 492 SkIRect src_irect = { src_rect.x(), src_rect.y(),
397 src_rect.right(), src_rect.bottom() }; 493 src_rect.right(), src_rect.bottom() };
398 494
399 // Location within the backing store to copy to. 495 // Location within the backing store to copy to.
400 SkRect dest_rect = { SkIntToScalar(x + src_rect.x()), 496 *invalidated_rect = src_rect;
401 SkIntToScalar(y + src_rect.y()), 497 invalidated_rect->Offset(x, y);
402 SkIntToScalar(x + src_rect.right()), 498 SkRect dest_rect = { SkIntToScalar(invalidated_rect->x()),
403 SkIntToScalar(y + src_rect.bottom()) }; 499 SkIntToScalar(invalidated_rect->y()),
500 SkIntToScalar(invalidated_rect->right()),
501 SkIntToScalar(invalidated_rect->bottom()) };
404 502
405 // We're guaranteed to have a mapped canvas since we mapped it in Init(). 503 // We're guaranteed to have a mapped canvas since we mapped it in Init().
406 skia::PlatformCanvas* backing_canvas = image_data_->mapped_canvas(); 504 skia::PlatformCanvas* backing_canvas = image_data_->mapped_canvas();
407 505
408 // Ensure the source image is mapped to read from it.
409 ImageDataAutoMapper auto_mapper(image);
410 if (!auto_mapper.is_valid())
411 return;
412
413 // We want to replace the contents of the bitmap rather than blend. 506 // We want to replace the contents of the bitmap rather than blend.
414 SkPaint paint; 507 SkPaint paint;
415 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 508 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
416 backing_canvas->drawBitmapRect(*image->GetMappedBitmap(), 509 backing_canvas->drawBitmapRect(*image->GetMappedBitmap(),
417 &src_irect, dest_rect, &paint); 510 &src_irect, dest_rect, &paint);
418 } 511 }
419 512
420 void DeviceContext2D::ExecuteScroll(const gfx::Rect& clip, int dx, int dy) { 513 void DeviceContext2D::ExecuteScroll(const gfx::Rect& clip, int dx, int dy,
514 gfx::Rect* invalidated_rect) {
421 // FIXME(brettw) 515 // FIXME(brettw)
422 } 516 }
423 517
424 void DeviceContext2D::ExecuteReplaceContents(ImageData* image) { 518 void DeviceContext2D::ExecuteReplaceContents(ImageData* image,
519 gfx::Rect* invalidated_rect) {
425 image_data_->Swap(image); 520 image_data_->Swap(image);
521 *invalidated_rect = gfx::Rect(0, 0,
522 image_data_->width(), image_data_->height());
523 }
524
525 void DeviceContext2D::ScheduleOffscreenCallback(
526 const FlushCallbackData& callback) {
527 MessageLoop::current()->PostTask(
528 FROM_HERE,
529 NewRunnableMethod(this,
530 &DeviceContext2D::ExecuteOffscreenCallback,
531 callback));
532 }
533
534 void DeviceContext2D::ExecuteOffscreenCallback(FlushCallbackData data) {
535 data.Execute(GetResource());
426 } 536 }
427 537
428 } // namespace pepper 538 } // namespace pepper
OLDNEW
« no previous file with comments | « webkit/glue/plugins/pepper_device_context_2d.h ('k') | webkit/glue/plugins/pepper_plugin_instance.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698