Chromium Code Reviews

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

Issue 2862002: Implement more of Flush properly. This adds support for waiting on the messag... (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.
Jump to:
View unified diff | | 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> 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"
(...skipping 167 matching lines...)
178 callback_data_(d) { 178 callback_data_(d) {
179 } 179 }
180 180
181 void DeviceContext2D::FlushCallbackData::Execute(PP_Resource device_context) { 181 void DeviceContext2D::FlushCallbackData::Execute(PP_Resource device_context) {
182 callback_(device_context, callback_data_); 182 callback_(device_context, callback_data_);
183 } 183 }
184 184
185 DeviceContext2D::DeviceContext2D(PluginModule* module) 185 DeviceContext2D::DeviceContext2D(PluginModule* module)
186 : Resource(module), 186 : Resource(module),
187 bound_instance_(NULL), 187 bound_instance_(NULL),
188 flushed_any_data_(false) { 188 flushed_any_data_(false),
189 offscreen_flush_pending_(false) {
189 } 190 }
190 191
191 DeviceContext2D::~DeviceContext2D() { 192 DeviceContext2D::~DeviceContext2D() {
192 } 193 }
193 194
194 // static 195 // static
195 const PPB_DeviceContext2D* DeviceContext2D::GetInterface() { 196 const PPB_DeviceContext2D* DeviceContext2D::GetInterface() {
196 return &ppb_devicecontext2d; 197 return &ppb_devicecontext2d;
197 } 198 }
198 199
(...skipping 86 matching lines...)
285 286
286 QueuedOperation operation(QueuedOperation::REPLACE); 287 QueuedOperation operation(QueuedOperation::REPLACE);
287 operation.replace_image = image_resource; 288 operation.replace_image = image_resource;
288 queued_operations_.push_back(operation); 289 queued_operations_.push_back(operation);
289 290
290 return true; 291 return true;
291 } 292 }
292 293
293 bool DeviceContext2D::Flush(PPB_DeviceContext2D_FlushCallback callback, 294 bool DeviceContext2D::Flush(PPB_DeviceContext2D_FlushCallback callback,
294 void* callback_data) { 295 void* callback_data) {
296 // Don't allow more than one pending flush at a time.
297 if (HasPendingFlush())
298 return false;
299
295 // TODO(brettw) check that the current thread is not the main one and 300 // TODO(brettw) check that the current thread is not the main one and
296 // implement blocking flushes in this case. 301 // implement blocking flushes in this case.
297 if (!callback) 302 if (!callback)
298 return false; 303 return false;
299 304
300 if (queued_operations_.empty())
301 return true; // Nothing to do.
302
303 gfx::Rect changed_rect; 305 gfx::Rect changed_rect;
304 for (size_t i = 0; i < queued_operations_.size(); i++) { 306 for (size_t i = 0; i < queued_operations_.size(); i++) {
305 QueuedOperation& operation = queued_operations_[i]; 307 QueuedOperation& operation = queued_operations_[i];
306 gfx::Rect op_rect; 308 gfx::Rect op_rect;
307 switch (operation.type) { 309 switch (operation.type) {
308 case QueuedOperation::PAINT: 310 case QueuedOperation::PAINT:
309 ExecutePaintImageData(operation.paint_image.get(), 311 ExecutePaintImageData(operation.paint_image.get(),
310 operation.paint_x, operation.paint_y, 312 operation.paint_x, operation.paint_y,
311 operation.paint_src_rect, 313 operation.paint_src_rect,
312 &op_rect); 314 &op_rect);
(...skipping 14 matching lines...)
327 329
328 // We need the rect to be in terms of the current clip rect of the plugin 330 // We need the rect to be in terms of the current clip rect of the plugin
329 // since that's what will actually be painted. If we issue an invalidate 331 // since that's what will actually be painted. If we issue an invalidate
330 // for a clipped-out region, WebKit will do nothing and we won't get any 332 // for a clipped-out region, WebKit will do nothing and we won't get any
331 // ViewInitiatedPaint/ViewFlushedPaint calls, leaving our callback stranded. 333 // ViewInitiatedPaint/ViewFlushedPaint calls, leaving our callback stranded.
332 gfx::Rect visible_changed_rect; 334 gfx::Rect visible_changed_rect;
333 if (bound_instance_ && !changed_rect.IsEmpty()) 335 if (bound_instance_ && !changed_rect.IsEmpty())
334 visible_changed_rect = bound_instance_->clip().Intersect(changed_rect); 336 visible_changed_rect = bound_instance_->clip().Intersect(changed_rect);
335 337
336 if (bound_instance_ && !visible_changed_rect.IsEmpty()) { 338 if (bound_instance_ && !visible_changed_rect.IsEmpty()) {
337 unpainted_flush_callbacks_.push_back(FlushCallbackData(callback, 339 unpainted_flush_callback_.reset(new FlushCallbackData(callback,
338 callback_data)); 340 callback_data));
339 bound_instance_->InvalidateRect(visible_changed_rect); 341 bound_instance_->InvalidateRect(visible_changed_rect);
340 } else { 342 } else {
341 // There's nothing visible to invalidate so just schedule the callback to 343 // There's nothing visible to invalidate so just schedule the callback to
342 // execute in the next round of the message loop. 344 // execute in the next round of the message loop.
343 ScheduleOffscreenCallback( 345 ScheduleOffscreenCallback(
344 FlushCallbackData(callback, callback_data)); 346 FlushCallbackData(callback, callback_data));
345 } 347 }
346 return true; 348 return true;
347 } 349 }
348 350
(...skipping 40 matching lines...)
389 bool DeviceContext2D::BindToInstance(PluginInstance* new_instance) { 391 bool DeviceContext2D::BindToInstance(PluginInstance* new_instance) {
390 if (bound_instance_ == new_instance) 392 if (bound_instance_ == new_instance)
391 return true; // Rebinding the same device, nothing to do. 393 return true; // Rebinding the same device, nothing to do.
392 if (bound_instance_ && new_instance) 394 if (bound_instance_ && new_instance)
393 return false; // Can't change a bound device. 395 return false; // Can't change a bound device.
394 396
395 if (!new_instance) { 397 if (!new_instance) {
396 // When the device is detached, we'll not get any more paint callbacks so 398 // 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 399 // we need to clear the list, but we still want to issue any pending
398 // callbacks to the plugin. 400 // callbacks to the plugin.
399 for (size_t i = 0; i < unpainted_flush_callbacks_.size(); i++) 401 if (unpainted_flush_callback_.get()) {
400 ScheduleOffscreenCallback(unpainted_flush_callbacks_[i]); 402 ScheduleOffscreenCallback(*unpainted_flush_callback_.get());
401 for (size_t i = 0; i < painted_flush_callbacks_.size(); i++) 403 unpainted_flush_callback_.reset();
402 ScheduleOffscreenCallback(painted_flush_callbacks_[i]); 404 }
403 unpainted_flush_callbacks_.clear(); 405 if (painted_flush_callback_.get()) {
404 painted_flush_callbacks_.clear(); 406 ScheduleOffscreenCallback(*painted_flush_callback_.get());
407 painted_flush_callback_.reset();
408 }
405 } else if (flushed_any_data_) { 409 } else if (flushed_any_data_) {
406 // Only schedule a paint if this backing store has had any data flushed to 410 // 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 411 // it. This is an optimization. A "normal" plugin will first allocated a
408 // backing store, bind it, and then execute their normal painting and 412 // backing store, bind it, and then execute their normal painting and
409 // update loop. If binding a device always invalidated, it would mean we 413 // 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 414 // 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 415 // 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 416 // when an empty device is initially bound, we can save an extra paint for
413 // many plugins during the critical page initialization phase. 417 // many plugins during the critical page initialization phase.
414 new_instance->InvalidateRect(gfx::Rect()); 418 new_instance->InvalidateRect(gfx::Rect());
(...skipping 41 matching lines...)
456 CGContextRestoreGState(canvas); 460 CGContextRestoreGState(canvas);
457 #else 461 #else
458 gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y()); 462 gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y());
459 canvas->drawBitmap(backing_bitmap, 463 canvas->drawBitmap(backing_bitmap,
460 SkIntToScalar(plugin_rect.origin().x()), 464 SkIntToScalar(plugin_rect.origin().x()),
461 SkIntToScalar(plugin_rect.origin().y())); 465 SkIntToScalar(plugin_rect.origin().y()));
462 #endif 466 #endif
463 } 467 }
464 468
465 void DeviceContext2D::ViewInitiatedPaint() { 469 void DeviceContext2D::ViewInitiatedPaint() {
466 // Move all "unpainted" callbacks to the painted state. See 470 // Move any "unpainted" callback to the painted state. See
467 // |unpainted_flush_callbacks_| in the header for more. 471 // |unpainted_flush_callback_| in the header for more.
468 std::copy(unpainted_flush_callbacks_.begin(), 472 if (unpainted_flush_callback_.get()) {
469 unpainted_flush_callbacks_.end(), 473 DCHECK(!painted_flush_callback_.get());
470 std::back_inserter(painted_flush_callbacks_)); 474 painted_flush_callback_.swap(unpainted_flush_callback_);
471 unpainted_flush_callbacks_.clear(); 475 }
472 } 476 }
473 477
474 void DeviceContext2D::ViewFlushedPaint() { 478 void DeviceContext2D::ViewFlushedPaint() {
475 // Notify all "painted" callbacks. See |unpainted_flush_callbacks_| in the 479 // Notify any "painted" callback. See |unpainted_flush_callback_| in the
476 // header for more. 480 // header for more.
477 for (size_t i = 0; i < painted_flush_callbacks_.size(); i++) 481 if (painted_flush_callback_.get()) {
478 painted_flush_callbacks_[i].Execute(GetResource()); 482 // We must clear this variable before issuing the callback. It will be
479 painted_flush_callbacks_.clear(); 483 // 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.
485 scoped_ptr<FlushCallbackData> callback;
486 callback.swap(painted_flush_callback_);
487 callback->Execute(GetResource());
488 }
480 } 489 }
481 490
482 void DeviceContext2D::ExecutePaintImageData(ImageData* image, 491 void DeviceContext2D::ExecutePaintImageData(ImageData* image,
483 int x, int y, 492 int x, int y,
484 const gfx::Rect& src_rect, 493 const gfx::Rect& src_rect,
485 gfx::Rect* invalidated_rect) { 494 gfx::Rect* invalidated_rect) {
486 // Ensure the source image is mapped to read from it. 495 // Ensure the source image is mapped to read from it.
487 ImageDataAutoMapper auto_mapper(image); 496 ImageDataAutoMapper auto_mapper(image);
488 if (!auto_mapper.is_valid()) 497 if (!auto_mapper.is_valid())
489 return; 498 return;
(...skipping 15 matching lines...)
505 514
506 // We want to replace the contents of the bitmap rather than blend. 515 // We want to replace the contents of the bitmap rather than blend.
507 SkPaint paint; 516 SkPaint paint;
508 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 517 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
509 backing_canvas->drawBitmapRect(*image->GetMappedBitmap(), 518 backing_canvas->drawBitmapRect(*image->GetMappedBitmap(),
510 &src_irect, dest_rect, &paint); 519 &src_irect, dest_rect, &paint);
511 } 520 }
512 521
513 void DeviceContext2D::ExecuteScroll(const gfx::Rect& clip, int dx, int dy, 522 void DeviceContext2D::ExecuteScroll(const gfx::Rect& clip, int dx, int dy,
514 gfx::Rect* invalidated_rect) { 523 gfx::Rect* invalidated_rect) {
515 // FIXME(brettw) 524 // TODO(brettw): implement this.
516 } 525 }
517 526
518 void DeviceContext2D::ExecuteReplaceContents(ImageData* image, 527 void DeviceContext2D::ExecuteReplaceContents(ImageData* image,
519 gfx::Rect* invalidated_rect) { 528 gfx::Rect* invalidated_rect) {
520 image_data_->Swap(image); 529 image_data_->Swap(image);
521 *invalidated_rect = gfx::Rect(0, 0, 530 *invalidated_rect = gfx::Rect(0, 0,
522 image_data_->width(), image_data_->height()); 531 image_data_->width(), image_data_->height());
523 } 532 }
524 533
525 void DeviceContext2D::ScheduleOffscreenCallback( 534 void DeviceContext2D::ScheduleOffscreenCallback(
526 const FlushCallbackData& callback) { 535 const FlushCallbackData& callback) {
536 DCHECK(!HasPendingFlush());
537 offscreen_flush_pending_ = true;
527 MessageLoop::current()->PostTask( 538 MessageLoop::current()->PostTask(
528 FROM_HERE, 539 FROM_HERE,
529 NewRunnableMethod(this, 540 NewRunnableMethod(this,
530 &DeviceContext2D::ExecuteOffscreenCallback, 541 &DeviceContext2D::ExecuteOffscreenCallback,
531 callback)); 542 callback));
532 } 543 }
533 544
534 void DeviceContext2D::ExecuteOffscreenCallback(FlushCallbackData data) { 545 void DeviceContext2D::ExecuteOffscreenCallback(FlushCallbackData data) {
546 DCHECK(offscreen_flush_pending_);
547
548 // 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
550 // callback, and we don't want to think that a callback is already pending.
551 offscreen_flush_pending_ = false;
535 data.Execute(GetResource()); 552 data.Execute(GetResource());
536 } 553 }
537 554
555 bool DeviceContext2D::HasPendingFlush() const {
556 return unpainted_flush_callback_.get() || painted_flush_callback_.get() ||
557 offscreen_flush_pending_;
558 }
559
538 } // namespace pepper 560 } // namespace pepper
OLDNEW
« no previous file with comments | « webkit/glue/plugins/pepper_device_context_2d.h ('k') | webkit/glue/plugins/pepper_plugin_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine