diff options
-rw-r--r-- | ppapi/cpp/paint_manager.cc | 105 | ||||
-rw-r--r-- | ppapi/cpp/paint_manager.h | 21 | ||||
-rw-r--r-- | ppapi/examples/2d/paint_manager_example.cc | 3 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppapi_plugin_instance.cc | 23 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppb_graphics_2d_impl.cc | 37 |
5 files changed, 115 insertions, 74 deletions
diff --git a/ppapi/cpp/paint_manager.cc b/ppapi/cpp/paint_manager.cc index 1508333..bc02016 100644 --- a/ppapi/cpp/paint_manager.cc +++ b/ppapi/cpp/paint_manager.cc @@ -17,7 +17,8 @@ PaintManager::PaintManager() is_always_opaque_(false), callback_factory_(NULL), manual_callback_pending_(false), - flush_pending_(false) { + flush_pending_(false), + has_pending_resize_(false) { // Set the callback object outside of the initializer list to avoid a // compiler warning about using "this" in an initializer list. callback_factory_.Initialize(this); @@ -31,7 +32,8 @@ PaintManager::PaintManager(Instance* instance, is_always_opaque_(is_always_opaque), callback_factory_(NULL), manual_callback_pending_(false), - flush_pending_(false) { + flush_pending_(false), + has_pending_resize_(false) { // Set the callback object outside of the initializer list to avoid a // compiler warning about using "this" in an initializer list. callback_factory_.Initialize(this); @@ -53,35 +55,29 @@ void PaintManager::Initialize(Instance* instance, } void PaintManager::SetSize(const Size& new_size) { - if (new_size == graphics_.size()) + if (GetEffectiveSize() == new_size) return; - graphics_ = Graphics2D(instance_, new_size, is_always_opaque_); - if (graphics_.is_null()) - return; - instance_->BindGraphics(graphics_); - - manual_callback_pending_ = false; - flush_pending_ = false; - callback_factory_.CancelAll(); + has_pending_resize_ = true; + pending_size_ = new_size; Invalidate(); } void PaintManager::Invalidate() { - // You must call SetDevice before using. - PP_DCHECK(!graphics_.is_null()); + // You must call SetSize before using. + PP_DCHECK(!graphics_.is_null() || has_pending_resize_); EnsureCallbackPending(); - aggregator_.InvalidateRect(Rect(graphics_.size())); + aggregator_.InvalidateRect(Rect(GetEffectiveSize())); } void PaintManager::InvalidateRect(const Rect& rect) { - // You must call SetDevice before using. - PP_DCHECK(!graphics_.is_null()); + // You must call SetSize before using. + PP_DCHECK(!graphics_.is_null() || has_pending_resize_); // Clip the rect to the device area. - Rect clipped_rect = rect.Intersect(Rect(graphics_.size())); + Rect clipped_rect = rect.Intersect(Rect(GetEffectiveSize())); if (clipped_rect.IsEmpty()) return; // Nothing to do. @@ -90,13 +86,17 @@ void PaintManager::InvalidateRect(const Rect& rect) { } void PaintManager::ScrollRect(const Rect& clip_rect, const Point& amount) { - // You must call SetDevice before using. - PP_DCHECK(!graphics_.is_null()); + // You must call SetSize before using. + PP_DCHECK(!graphics_.is_null() || has_pending_resize_); EnsureCallbackPending(); aggregator_.ScrollRect(clip_rect, amount); } +Size PaintManager::GetEffectiveSize() const { + return has_pending_resize_ ? pending_size_ : graphics_.size(); +} + void PaintManager::EnsureCallbackPending() { // The best way for us to do the next update is to get a notification that // a previous one has completed. So if we're already waiting for one, we @@ -125,32 +125,56 @@ void PaintManager::DoPaint() { PaintAggregator::PaintUpdate update = aggregator_.GetPendingUpdate(); aggregator_.ClearPendingUpdate(); + // Apply any pending resize. Setting the graphics to this class must happen + // before asking the plugin to paint in case it requests the Graphics2D during + // painting. However, the bind must not happen until afterward since we don't + // want to have an unpainted device bound. The needs_binding flag tells us + // whether to do this later. + bool needs_binding = false; + if (has_pending_resize_) { + graphics_ = Graphics2D(instance_, pending_size_, is_always_opaque_); + needs_binding = true; + + // Since we're binding a new one, all of the callbacks have been canceled. + manual_callback_pending_ = false; + flush_pending_ = false; + callback_factory_.CancelAll(); + + // This must be cleared before calling into the plugin since it may do + // additional invalidation or sizing operations. + has_pending_resize_ = false; + pending_size_ = Size(); + } + // Apply any scroll before asking the client to paint. if (update.has_scroll) graphics_.Scroll(update.scroll_rect, update.scroll_delta); - if (!client_->OnPaint(graphics_, update.paint_rects, update.paint_bounds)) - return; // Nothing was painted, don't schedule a flush. - - int32_t result = graphics_.Flush( - callback_factory_.NewCallback(&PaintManager::OnFlushComplete)); - - // If you trigger this assertion, then your plugin has called Flush() - // manually. When using the PaintManager, you should not call Flush, it will - // handle that for you because it needs to know when it can do the next paint - // by implementing the flush callback. - // - // Another possible cause of this assertion is re-using devices. If you - // use one device, swap it with another, then swap it back, we won't know - // that we've already scheduled a Flush on the first device. It's best to not - // re-use devices in this way. - PP_DCHECK(result != PP_ERROR_INPROGRESS); - - if (result == PP_OK_COMPLETIONPENDING) { - flush_pending_ = true; - } else { - PP_DCHECK(result == PP_OK); // Catch all other errors in debug mode. + if (client_->OnPaint(graphics_, update.paint_rects, update.paint_bounds)) { + // Something was painted, schedule a flush. + int32_t result = graphics_.Flush( + callback_factory_.NewCallback(&PaintManager::OnFlushComplete)); + + // If you trigger this assertion, then your plugin has called Flush() + // manually. When using the PaintManager, you should not call Flush, it + // will handle that for you because it needs to know when it can do the + // next paint by implementing the flush callback. + // + // Another possible cause of this assertion is re-using devices. If you + // use one device, swap it with another, then swap it back, we won't know + // that we've already scheduled a Flush on the first device. It's best to + // not re-use devices in this way. + PP_DCHECK(result != PP_ERROR_INPROGRESS); + + if (result == PP_OK_COMPLETIONPENDING) { + flush_pending_ = true; + } else { + PP_DCHECK(result == PP_OK); // Catch all other errors in debug mode. + } } + + if (needs_binding) + instance_->BindGraphics(graphics_); } void PaintManager::OnFlushComplete(int32_t) { @@ -175,4 +199,5 @@ void PaintManager::OnManualCallbackComplete(int32_t) { DoPaint(); } + } // namespace pp diff --git a/ppapi/cpp/paint_manager.h b/ppapi/cpp/paint_manager.h index d8cba66..5f14862 100644 --- a/ppapi/cpp/paint_manager.h +++ b/ppapi/cpp/paint_manager.h @@ -146,9 +146,12 @@ class PaintManager { // position changed). void SetSize(const Size& new_size); - // Provides access to the underlying device in case you need it. Note: if - // you call Flush on this device the paint manager will get very confused, - // don't do this! + // Provides access to the underlying device in case you need it. If you have + // done a SetSize, note that the graphics context won't be updated until + // right before the next OnPaint call. + // + // Note: if you call Flush on this device the paint manager will get very + // confused, don't do this! const Graphics2D& graphics() const { return graphics_; } Graphics2D& graphics() { return graphics_; } @@ -161,6 +164,12 @@ class PaintManager { // The given rect should be scrolled by the given amounts. void ScrollRect(const Rect& clip_rect, const Point& amount); + // Returns the size of the graphics context for the next paint operation. + // This is the pending size if a resize is pending (the plugin has called + // SetSize but we haven't actually painted it yet), or the current size of + // no resize is pending. + Size GetEffectiveSize() const; + private: // Disallow copy and assign (these are unimplemented). PaintManager(const PaintManager&); @@ -200,6 +209,12 @@ class PaintManager { // See comment for EnsureCallbackPending for more on how these work. bool manual_callback_pending_; bool flush_pending_; + + // When we get a resize, we don't bind right away (see SetSize). The + // has_pending_resize_ tells us that we need to do a resize for the next + // paint operation. When true, the new size is in pending_size_. + bool has_pending_resize_; + Size pending_size_; }; } // namespace pp diff --git a/ppapi/examples/2d/paint_manager_example.cc b/ppapi/examples/2d/paint_manager_example.cc index e9b034e..8a5a2f5 100644 --- a/ppapi/examples/2d/paint_manager_example.cc +++ b/ppapi/examples/2d/paint_manager_example.cc @@ -73,7 +73,7 @@ class MyInstance : public pp::Instance, public pp::PaintManager::Client { } // PaintManager::Client implementation. - virtual bool OnPaint(pp::Graphics2D&, + virtual bool OnPaint(pp::Graphics2D& graphics_2d, const std::vector<pp::Rect>& paint_rects, const pp::Rect& paint_bounds) { // Make an image just large enough to hold all dirty rects. We won't @@ -114,6 +114,7 @@ class MyInstance : public pp::Instance, public pp::PaintManager::Client { square.height(), 0xFF000000); + graphics_2d.PaintImageData(updated_image, paint_bounds.point()); return true; } diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc index 65faa07..9ae9014 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.cc +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc @@ -1400,29 +1400,6 @@ PP_Bool PluginInstance::BindGraphics(PP_Instance instance, if (!graphics_2d->BindToInstance(this)) return PP_FALSE; // Can't bind to more than one instance. - // See http://crbug.com/49403: this can be further optimized by keeping the - // old device around and painting from it. - if (bound_graphics_2d()) { - // Start the new image with the content of the old image until the plugin - // repaints. - // Use ImageDataAutoMapper to ensure the image data is valid. - ImageDataAutoMapper mapper(bound_graphics_2d()->image_data()); - if (!mapper.is_valid()) - return PP_FALSE; - const SkBitmap* old_backing_bitmap = - bound_graphics_2d()->image_data()->GetMappedBitmap(); - SkRect old_size = SkRect::MakeWH( - SkScalar(static_cast<float>(old_backing_bitmap->width())), - SkScalar(static_cast<float>(old_backing_bitmap->height()))); - - SkCanvas canvas(*graphics_2d->image_data()->GetMappedBitmap()); - canvas.drawBitmap(*old_backing_bitmap, 0, 0); - - // Fill in any extra space with white. - canvas.clipRect(old_size, SkRegion::kDifference_Op); - canvas.drawARGB(255, 255, 255, 255); - } - bound_graphics_ = graphics_2d; setBackingTextureId(0); // BindToInstance will have invalidated the plugin if necessary. diff --git a/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc b/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc index caf3821..f6294449 100644 --- a/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc +++ b/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc @@ -495,19 +495,42 @@ void PPB_Graphics2D_Impl::Paint(WebKit::WebCanvas* canvas, CGContextDrawImage(canvas, bitmap_rect, image); CGContextRestoreGState(canvas); #else + SkRect sk_plugin_rect = SkRect::MakeXYWH( + SkIntToScalar(plugin_rect.origin().x()), + SkIntToScalar(plugin_rect.origin().y()), + SkIntToScalar(plugin_rect.width()), + SkIntToScalar(plugin_rect.height())); + canvas->save(); + canvas->clipRect(sk_plugin_rect); + + if (instance()->IsFullPagePlugin()) { + // When we're resizing a window with a full-frame plugin, the plugin may + // not yet have bound a new device, which will leave parts of the + // background exposed if the window is getting larger. We want this to + // show white (typically less jarring) rather than black or uninitialized. + // We don't do this for non-full-frame plugins since we specifically want + // the page background to show through. + canvas->save(); + SkRect image_data_rect = SkRect::MakeXYWH( + SkIntToScalar(plugin_rect.origin().x()), + SkIntToScalar(plugin_rect.origin().y()), + SkIntToScalar(image_data_->width()), + SkIntToScalar(image_data_->height())); + canvas->clipRect(image_data_rect, SkRegion::kDifference_Op); + + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + paint.setColor(SK_ColorWHITE); + canvas->drawRect(sk_plugin_rect, paint); + canvas->restore(); + } + SkPaint paint; if (is_always_opaque_) { // When we know the device is opaque, we can disable blending for slightly // more optimized painting. paint.setXfermodeMode(SkXfermode::kSrc_Mode); } - - canvas->save(); - SkRect clip_rect = SkRect::MakeXYWH(SkIntToScalar(plugin_rect.origin().x()), - SkIntToScalar(plugin_rect.origin().y()), - SkIntToScalar(plugin_rect.width()), - SkIntToScalar(plugin_rect.height())); - canvas->clipRect(clip_rect); canvas->drawBitmap(backing_bitmap, SkIntToScalar(plugin_rect.x()), SkIntToScalar(plugin_rect.y()), |