Index: webkit/plugins/ppapi/ppb_graphics_2d_impl.cc |
diff --git a/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc b/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc |
deleted file mode 100644 |
index 590a61d2d943a020a37aa64c9831649a845ab4b4..0000000000000000000000000000000000000000 |
--- a/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc |
+++ /dev/null |
@@ -1,716 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "webkit/plugins/ppapi/ppb_graphics_2d_impl.h" |
- |
-#include <iterator> |
- |
-#include "base/bind.h" |
-#include "base/debug/trace_event.h" |
-#include "base/logging.h" |
-#include "base/message_loop.h" |
-#include "base/time.h" |
-#include "skia/ext/platform_canvas.h" |
-#include "ppapi/c/pp_errors.h" |
-#include "ppapi/c/pp_rect.h" |
-#include "ppapi/c/pp_resource.h" |
-#include "ppapi/c/ppb_graphics_2d.h" |
-#include "ppapi/thunk/enter.h" |
-#include "ppapi/thunk/thunk.h" |
-#include "third_party/skia/include/core/SkBitmap.h" |
-#include "ui/gfx/blit.h" |
-#include "ui/gfx/point.h" |
-#include "ui/gfx/point_conversions.h" |
-#include "ui/gfx/rect.h" |
-#include "ui/gfx/rect_conversions.h" |
-#include "ui/gfx/size_conversions.h" |
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" |
-#include "ui/gfx/skia_util.h" |
-#include "webkit/plugins/ppapi/common.h" |
-#include "webkit/plugins/ppapi/gfx_conversion.h" |
-#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" |
-#include "webkit/plugins/ppapi/ppb_image_data_impl.h" |
-#include "webkit/plugins/ppapi/resource_helper.h" |
- |
-#if defined(OS_MACOSX) |
-#include "base/mac/mac_util.h" |
-#include "base/mac/scoped_cftyperef.h" |
-#endif |
- |
-using ppapi::thunk::EnterResourceNoLock; |
-using ppapi::thunk::PPB_ImageData_API; |
-using ppapi::TrackedCallback; |
- |
-namespace webkit { |
-namespace ppapi { |
- |
-namespace { |
- |
-const int64 kOffscreenCallbackDelayMs = 1000 / 30; // 30 fps |
- |
-// Converts a rect inside an image of the given dimensions. The rect may be |
-// NULL to indicate it should be the entire image. If the rect is outside of |
-// the image, this will do nothing and return false. |
-bool ValidateAndConvertRect(const PP_Rect* rect, |
- int image_width, int image_height, |
- gfx::Rect* dest) { |
- if (!rect) { |
- // Use the entire image area. |
- *dest = gfx::Rect(0, 0, image_width, image_height); |
- } else { |
- // Validate the passed-in area. |
- if (rect->point.x < 0 || rect->point.y < 0 || |
- rect->size.width <= 0 || rect->size.height <= 0) |
- return false; |
- |
- // Check the max bounds, being careful of overflow. |
- if (static_cast<int64>(rect->point.x) + |
- static_cast<int64>(rect->size.width) > |
- static_cast<int64>(image_width)) |
- return false; |
- if (static_cast<int64>(rect->point.y) + |
- static_cast<int64>(rect->size.height) > |
- static_cast<int64>(image_height)) |
- return false; |
- |
- *dest = gfx::Rect(rect->point.x, rect->point.y, |
- rect->size.width, rect->size.height); |
- } |
- return true; |
-} |
- |
-// Converts BGRA <-> RGBA. |
-void ConvertBetweenBGRAandRGBA(const uint32_t* input, |
- int pixel_length, |
- uint32_t* output) { |
- for (int i = 0; i < pixel_length; i++) { |
- const unsigned char* pixel_in = |
- reinterpret_cast<const unsigned char*>(&input[i]); |
- unsigned char* pixel_out = reinterpret_cast<unsigned char*>(&output[i]); |
- pixel_out[0] = pixel_in[2]; |
- pixel_out[1] = pixel_in[1]; |
- pixel_out[2] = pixel_in[0]; |
- pixel_out[3] = pixel_in[3]; |
- } |
-} |
- |
-// Converts ImageData from PP_IMAGEDATAFORMAT_BGRA_PREMUL to |
-// PP_IMAGEDATAFORMAT_RGBA_PREMUL, or reverse. It's assumed that the |
-// destination image is always mapped (so will have non-NULL data). |
-void ConvertImageData(PPB_ImageData_Impl* src_image, const SkIRect& src_rect, |
- PPB_ImageData_Impl* dest_image, const SkRect& dest_rect) { |
- ImageDataAutoMapper auto_mapper(src_image); |
- |
- DCHECK(src_image->format() != dest_image->format()); |
- DCHECK(PPB_ImageData_Impl::IsImageDataFormatSupported(src_image->format())); |
- DCHECK(PPB_ImageData_Impl::IsImageDataFormatSupported(dest_image->format())); |
- |
- const SkBitmap* src_bitmap = src_image->GetMappedBitmap(); |
- const SkBitmap* dest_bitmap = dest_image->GetMappedBitmap(); |
- if (src_rect.width() == src_image->width() && |
- dest_rect.width() == dest_image->width()) { |
- // Fast path if the full line needs to be converted. |
- ConvertBetweenBGRAandRGBA( |
- src_bitmap->getAddr32(static_cast<int>(src_rect.fLeft), |
- static_cast<int>(src_rect.fTop)), |
- src_rect.width() * src_rect.height(), |
- dest_bitmap->getAddr32(static_cast<int>(dest_rect.fLeft), |
- static_cast<int>(dest_rect.fTop))); |
- } else { |
- // Slow path where we convert line by line. |
- for (int y = 0; y < src_rect.height(); y++) { |
- ConvertBetweenBGRAandRGBA( |
- src_bitmap->getAddr32(static_cast<int>(src_rect.fLeft), |
- static_cast<int>(src_rect.fTop + y)), |
- src_rect.width(), |
- dest_bitmap->getAddr32(static_cast<int>(dest_rect.fLeft), |
- static_cast<int>(dest_rect.fTop + y))); |
- } |
- } |
-} |
- |
-} // namespace |
- |
-struct PPB_Graphics2D_Impl::QueuedOperation { |
- enum Type { |
- PAINT, |
- SCROLL, |
- REPLACE |
- }; |
- |
- QueuedOperation(Type t) |
- : type(t), |
- paint_x(0), |
- paint_y(0), |
- scroll_dx(0), |
- scroll_dy(0) { |
- } |
- |
- Type type; |
- |
- // Valid when type == PAINT. |
- scoped_refptr<PPB_ImageData_Impl> paint_image; |
- int paint_x, paint_y; |
- gfx::Rect paint_src_rect; |
- |
- // Valid when type == SCROLL. |
- gfx::Rect scroll_clip_rect; |
- int scroll_dx, scroll_dy; |
- |
- // Valid when type == REPLACE. |
- scoped_refptr<PPB_ImageData_Impl> replace_image; |
-}; |
- |
-PPB_Graphics2D_Impl::PPB_Graphics2D_Impl(PP_Instance instance) |
- : Resource(::ppapi::OBJECT_IS_IMPL, instance), |
- bound_instance_(NULL), |
- offscreen_flush_pending_(false), |
- is_always_opaque_(false), |
- scale_(1.0f), |
- weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
-} |
- |
-PPB_Graphics2D_Impl::~PPB_Graphics2D_Impl() { |
- // LastPluginRefWasDeleted should have aborted all pending callbacks. |
- DCHECK(painted_flush_callback_.is_null()); |
- DCHECK(unpainted_flush_callback_.is_null()); |
-} |
- |
-// static |
-PP_Resource PPB_Graphics2D_Impl::Create(PP_Instance instance, |
- const PP_Size& size, |
- PP_Bool is_always_opaque) { |
- scoped_refptr<PPB_Graphics2D_Impl> graphics_2d( |
- new PPB_Graphics2D_Impl(instance)); |
- if (!graphics_2d->Init(size.width, size.height, |
- PPBoolToBool(is_always_opaque))) { |
- return 0; |
- } |
- return graphics_2d->GetReference(); |
-} |
- |
-bool PPB_Graphics2D_Impl::Init(int width, int height, bool is_always_opaque) { |
- // The underlying PPB_ImageData_Impl will validate the dimensions. |
- image_data_ = new PPB_ImageData_Impl(pp_instance(), |
- PPB_ImageData_Impl::PLATFORM); |
- if (!image_data_->Init(PPB_ImageData_Impl::GetNativeImageDataFormat(), |
- width, height, true) || |
- !image_data_->Map()) { |
- image_data_ = NULL; |
- return false; |
- } |
- is_always_opaque_ = is_always_opaque; |
- scale_ = 1.0f; |
- return true; |
-} |
- |
-::ppapi::thunk::PPB_Graphics2D_API* |
-PPB_Graphics2D_Impl::AsPPB_Graphics2D_API() { |
- return this; |
-} |
- |
-void PPB_Graphics2D_Impl::LastPluginRefWasDeleted() { |
- // Abort any pending callbacks. |
- unpainted_flush_callback_.PostAbort(); |
- painted_flush_callback_.PostAbort(); |
-} |
- |
-PP_Bool PPB_Graphics2D_Impl::Describe(PP_Size* size, |
- PP_Bool* is_always_opaque) { |
- size->width = image_data_->width(); |
- size->height = image_data_->height(); |
- *is_always_opaque = PP_FromBool(is_always_opaque_); |
- return PP_TRUE; |
-} |
- |
-void PPB_Graphics2D_Impl::PaintImageData(PP_Resource image_data, |
- const PP_Point* top_left, |
- const PP_Rect* src_rect) { |
- if (!top_left) |
- return; |
- |
- EnterResourceNoLock<PPB_ImageData_API> enter(image_data, true); |
- if (enter.failed()) { |
- Log(PP_LOGLEVEL_ERROR, |
- "PPB_Graphics2D.PaintImageData: Bad image resource."); |
- return; |
- } |
- PPB_ImageData_Impl* image_resource = |
- static_cast<PPB_ImageData_Impl*>(enter.object()); |
- |
- QueuedOperation operation(QueuedOperation::PAINT); |
- operation.paint_image = image_resource; |
- if (!ValidateAndConvertRect(src_rect, image_resource->width(), |
- image_resource->height(), |
- &operation.paint_src_rect)) |
- return; |
- |
- // Validate the bitmap position using the previously-validated rect, there |
- // should be no painted area outside of the image. |
- int64 x64 = static_cast<int64>(top_left->x); |
- int64 y64 = static_cast<int64>(top_left->y); |
- if (x64 + static_cast<int64>(operation.paint_src_rect.x()) < 0 || |
- x64 + static_cast<int64>(operation.paint_src_rect.right()) > |
- image_data_->width()) |
- return; |
- if (y64 + static_cast<int64>(operation.paint_src_rect.y()) < 0 || |
- y64 + static_cast<int64>(operation.paint_src_rect.bottom()) > |
- image_data_->height()) |
- return; |
- operation.paint_x = top_left->x; |
- operation.paint_y = top_left->y; |
- |
- queued_operations_.push_back(operation); |
-} |
- |
-void PPB_Graphics2D_Impl::Scroll(const PP_Rect* clip_rect, |
- const PP_Point* amount) { |
- QueuedOperation operation(QueuedOperation::SCROLL); |
- if (!ValidateAndConvertRect(clip_rect, |
- image_data_->width(), |
- image_data_->height(), |
- &operation.scroll_clip_rect)) |
- return; |
- |
- // If we're being asked to scroll by more than the clip rect size, just |
- // ignore this scroll command and say it worked. |
- int32 dx = amount->x; |
- int32 dy = amount->y; |
- if (dx <= -image_data_->width() || dx >= image_data_->width() || |
- dy <= -image_data_->height() || dy >= image_data_->height()) { |
- Log(PP_LOGLEVEL_ERROR, |
- "PPB_Graphics2D.Scroll: Scroll amount is larger than image size."); |
- return; |
- } |
- |
- operation.scroll_dx = dx; |
- operation.scroll_dy = dy; |
- |
- queued_operations_.push_back(operation); |
-} |
- |
-void PPB_Graphics2D_Impl::ReplaceContents(PP_Resource image_data) { |
- EnterResourceNoLock<PPB_ImageData_API> enter(image_data, true); |
- if (enter.failed()) |
- return; |
- PPB_ImageData_Impl* image_resource = |
- static_cast<PPB_ImageData_Impl*>(enter.object()); |
- |
- if (!PPB_ImageData_Impl::IsImageDataFormatSupported( |
- image_resource->format())) { |
- Log(PP_LOGLEVEL_ERROR, |
- "PPB_Graphics2D.ReplaceContents: Image data format is not supported."); |
- return; |
- } |
- |
- if (image_resource->width() != image_data_->width() || |
- image_resource->height() != image_data_->height()) { |
- Log(PP_LOGLEVEL_ERROR, |
- "PPB_Graphics2D.ReplaceContents: Image size doesn't match " |
- "Graphics2D size."); |
- return; |
- } |
- |
- QueuedOperation operation(QueuedOperation::REPLACE); |
- operation.replace_image = image_resource; |
- queued_operations_.push_back(operation); |
-} |
- |
-int32_t PPB_Graphics2D_Impl::Flush(scoped_refptr<TrackedCallback> callback, |
- PP_Resource* old_image_data) { |
- TRACE_EVENT0("pepper", "PPB_Graphics2D_Impl::Flush"); |
- // Don't allow more than one pending flush at a time. |
- if (HasPendingFlush()) |
- return PP_ERROR_INPROGRESS; |
- |
- bool done_replace_contents = false; |
- bool no_update_visible = true; |
- bool is_plugin_visible = true; |
- for (size_t i = 0; i < queued_operations_.size(); i++) { |
- QueuedOperation& operation = queued_operations_[i]; |
- gfx::Rect op_rect; |
- switch (operation.type) { |
- case QueuedOperation::PAINT: |
- ExecutePaintImageData(operation.paint_image, |
- operation.paint_x, operation.paint_y, |
- operation.paint_src_rect, |
- &op_rect); |
- break; |
- case QueuedOperation::SCROLL: |
- ExecuteScroll(operation.scroll_clip_rect, |
- operation.scroll_dx, operation.scroll_dy, |
- &op_rect); |
- break; |
- case QueuedOperation::REPLACE: |
- // Since the out parameter |old_image_data| takes ownership of the |
- // reference, if there are more than one ReplaceContents calls queued |
- // the first |old_image_data| will get overwritten and leaked. So we |
- // only supply this for the first call. |
- ExecuteReplaceContents(operation.replace_image, &op_rect, |
- done_replace_contents ? NULL : old_image_data); |
- done_replace_contents = true; |
- break; |
- } |
- |
- // For correctness with accelerated compositing, we must issue an invalidate |
- // on the full op_rect even if it is partially or completely off-screen. |
- // However, if we issue an invalidate for a clipped-out region, WebKit will |
- // do nothing and we won't get any ViewWillInitiatePaint/ViewFlushedPaint |
- // calls, leaving our callback stranded. So we still need to check whether |
- // the repainted area is visible to determine how to deal with the callback. |
- if (bound_instance_ && !op_rect.IsEmpty()) { |
- gfx::Point scroll_delta(operation.scroll_dx, operation.scroll_dy); |
- if (!ConvertToLogicalPixels(scale_, |
- &op_rect, |
- operation.type == QueuedOperation::SCROLL ? |
- &scroll_delta : NULL)) { |
- // Conversion requires falling back to InvalidateRect. |
- operation.type = QueuedOperation::PAINT; |
- } |
- |
- gfx::Rect clip = PP_ToGfxRect(bound_instance_->view_data().clip_rect); |
- is_plugin_visible = !clip.IsEmpty(); |
- |
- // Set |no_update_visible| to false if the change overlaps the visible |
- // area. |
- gfx::Rect visible_changed_rect = gfx::IntersectRects(clip, op_rect); |
- if (!visible_changed_rect.IsEmpty()) |
- no_update_visible = false; |
- |
- // Notify the plugin of the entire change (op_rect), even if it is |
- // partially or completely off-screen. |
- if (operation.type == QueuedOperation::SCROLL) { |
- bound_instance_->ScrollRect(scroll_delta.x(), scroll_delta.y(), |
- op_rect); |
- } else { |
- bound_instance_->InvalidateRect(op_rect); |
- } |
- } |
- } |
- queued_operations_.clear(); |
- |
- if (!bound_instance_) { |
- // As promised in the API, we always schedule callback when unbound. |
- ScheduleOffscreenCallback(FlushCallbackData(callback)); |
- } else if (no_update_visible && is_plugin_visible && |
- bound_instance_->view_data().is_page_visible) { |
- // There's nothing visible to invalidate so just schedule the callback to |
- // execute in the next round of the message loop. |
- ScheduleOffscreenCallback(FlushCallbackData(callback)); |
- } else { |
- unpainted_flush_callback_.Set(callback); |
- } |
- |
- return PP_OK_COMPLETIONPENDING; |
-} |
- |
-bool PPB_Graphics2D_Impl::SetScale(float scale) { |
- if (scale > 0.0f) { |
- scale_ = scale; |
- return true; |
- } |
- |
- return false; |
-} |
- |
-float PPB_Graphics2D_Impl::GetScale() { |
- return scale_; |
-} |
- |
-bool PPB_Graphics2D_Impl::ReadImageData(PP_Resource image, |
- const PP_Point* top_left) { |
- // Get and validate the image object to paint into. |
- EnterResourceNoLock<PPB_ImageData_API> enter(image, true); |
- if (enter.failed()) |
- return false; |
- PPB_ImageData_Impl* image_resource = |
- static_cast<PPB_ImageData_Impl*>(enter.object()); |
- if (!PPB_ImageData_Impl::IsImageDataFormatSupported( |
- image_resource->format())) |
- return false; // Must be in the right format. |
- |
- // Validate the bitmap position. |
- int x = top_left->x; |
- if (x < 0 || |
- static_cast<int64>(x) + static_cast<int64>(image_resource->width()) > |
- image_data_->width()) |
- return false; |
- int y = top_left->y; |
- if (y < 0 || |
- static_cast<int64>(y) + static_cast<int64>(image_resource->height()) > |
- image_data_->height()) |
- return false; |
- |
- ImageDataAutoMapper auto_mapper(image_resource); |
- if (!auto_mapper.is_valid()) |
- return false; |
- |
- SkIRect src_irect = { x, y, |
- x + image_resource->width(), |
- y + image_resource->height() }; |
- SkRect dest_rect = { SkIntToScalar(0), |
- SkIntToScalar(0), |
- SkIntToScalar(image_resource->width()), |
- SkIntToScalar(image_resource->height()) }; |
- |
- if (image_resource->format() != image_data_->format()) { |
- // Convert the image data if the format does not match. |
- ConvertImageData(image_data_, src_irect, image_resource, dest_rect); |
- } else { |
- SkCanvas* dest_canvas = image_resource->GetCanvas(); |
- |
- // We want to replace the contents of the bitmap rather than blend. |
- SkPaint paint; |
- paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
- dest_canvas->drawBitmapRect(*image_data_->GetMappedBitmap(), |
- &src_irect, dest_rect, &paint); |
- } |
- return true; |
-} |
- |
-bool PPB_Graphics2D_Impl::BindToInstance(PluginInstance* new_instance) { |
- if (bound_instance_ == new_instance) |
- return true; // Rebinding the same device, nothing to do. |
- if (bound_instance_ && new_instance) |
- return false; // Can't change a bound device. |
- |
- if (!new_instance) { |
- // When the device is detached, we'll not get any more paint callbacks so |
- // we need to clear the list, but we still want to issue any pending |
- // callbacks to the plugin. |
- if (!unpainted_flush_callback_.is_null()) { |
- FlushCallbackData callback; |
- std::swap(callback, unpainted_flush_callback_); |
- ScheduleOffscreenCallback(callback); |
- } |
- if (!painted_flush_callback_.is_null()) { |
- FlushCallbackData callback; |
- std::swap(callback, painted_flush_callback_); |
- ScheduleOffscreenCallback(callback); |
- } |
- } else { |
- // Devices being replaced, redraw the plugin. |
- new_instance->InvalidateRect(gfx::Rect()); |
- } |
- |
- bound_instance_ = new_instance; |
- return true; |
-} |
- |
-// The |backing_bitmap| must be clipped to the |plugin_rect| to avoid painting |
-// outside the plugin area. This can happen if the plugin has been resized since |
-// PaintImageData verified the image is within the plugin size. |
-void PPB_Graphics2D_Impl::Paint(WebKit::WebCanvas* canvas, |
- const gfx::Rect& plugin_rect, |
- const gfx::Rect& paint_rect) { |
- TRACE_EVENT0("pepper", "PPB_Graphics2D_Impl::Paint"); |
- ImageDataAutoMapper auto_mapper(image_data_); |
- const SkBitmap& backing_bitmap = *image_data_->GetMappedBitmap(); |
- |
- gfx::Rect invalidate_rect = gfx::IntersectRects(plugin_rect, paint_rect); |
- SkRect sk_invalidate_rect = gfx::RectToSkRect(invalidate_rect); |
- SkAutoCanvasRestore auto_restore(canvas, true); |
- canvas->clipRect(sk_invalidate_rect); |
- gfx::Size pixel_image_size(image_data_->width(), image_data_->height()); |
- gfx::Size image_size = gfx::ToFlooredSize( |
- gfx::ScaleSize(pixel_image_size, scale_)); |
- |
- PluginInstance* plugin_instance = ResourceHelper::GetPluginInstance(this); |
- if (!plugin_instance) |
- return; |
- if (plugin_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. |
- SkAutoCanvasRestore auto_restore(canvas, true); |
- SkRect image_data_rect = |
- gfx::RectToSkRect(gfx::Rect(plugin_rect.origin(), image_size)); |
- canvas->clipRect(image_data_rect, SkRegion::kDifference_Op); |
- |
- SkPaint paint; |
- paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
- paint.setColor(SK_ColorWHITE); |
- canvas->drawRect(sk_invalidate_rect, paint); |
- } |
- |
- SkBitmap image; |
- // Copy to device independent bitmap when target canvas doesn't support |
- // platform paint. |
- if (!skia::SupportsPlatformPaint(canvas)) |
- backing_bitmap.copyTo(&image, SkBitmap::kARGB_8888_Config); |
- else |
- image = backing_bitmap; |
- |
- 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); |
- } |
- |
- SkPoint origin; |
- origin.set(SkIntToScalar(plugin_rect.x()), SkIntToScalar(plugin_rect.y())); |
- |
- SkPoint pixel_origin = origin; |
- if (scale_ != 1.0f && scale_ > 0.0f) { |
- float inverse_scale = 1.0f / scale_; |
- pixel_origin.scale(inverse_scale); |
- canvas->scale(scale_, scale_); |
- } |
- canvas->drawBitmap(image, pixel_origin.x(), pixel_origin.y(), &paint); |
-} |
- |
-void PPB_Graphics2D_Impl::ViewWillInitiatePaint() { |
- // Move any "unpainted" callback to the painted state. See |
- // |unpainted_flush_callback_| in the header for more. |
- if (!unpainted_flush_callback_.is_null()) { |
- DCHECK(painted_flush_callback_.is_null()); |
- std::swap(painted_flush_callback_, unpainted_flush_callback_); |
- } |
-} |
- |
-void PPB_Graphics2D_Impl::ViewInitiatedPaint() { |
-} |
- |
-void PPB_Graphics2D_Impl::ViewFlushedPaint() { |
- TRACE_EVENT0("pepper", "PPB_Graphics2D_Impl::ViewFlushedPaint"); |
- // Notify any "painted" callback. See |unpainted_flush_callback_| in the |
- // header for more. |
- if (!painted_flush_callback_.is_null()) |
- painted_flush_callback_.Execute(PP_OK); |
-} |
- |
-// static |
-bool PPB_Graphics2D_Impl::ConvertToLogicalPixels(float scale, |
- gfx::Rect* op_rect, |
- gfx::Point* delta) { |
- if (scale == 1.0f || scale <= 0.0f) |
- return true; |
- |
- gfx::Rect original_rect = *op_rect; |
- // Take the enclosing rectangle after scaling so a rectangle scaled down then |
- // scaled back up by the inverse scale would fully contain the entire area |
- // affected by the original rectangle. |
- *op_rect = gfx::ToEnclosingRect(gfx::ScaleRect(*op_rect, scale)); |
- if (delta) { |
- gfx::Point original_delta = *delta; |
- float inverse_scale = 1.0f / scale; |
- *delta = gfx::ToFlooredPoint(gfx::ScalePoint(*delta, scale)); |
- |
- gfx::Rect inverse_scaled_rect = |
- gfx::ToEnclosingRect(gfx::ScaleRect(*op_rect, inverse_scale)); |
- if (original_rect != inverse_scaled_rect) |
- return false; |
- gfx::Point inverse_scaled_point = |
- gfx::ToFlooredPoint(gfx::ScalePoint(*delta, inverse_scale)); |
- if (original_delta != inverse_scaled_point) |
- return false; |
- } |
- |
- return true; |
-} |
- |
-void PPB_Graphics2D_Impl::ExecutePaintImageData(PPB_ImageData_Impl* image, |
- int x, int y, |
- const gfx::Rect& src_rect, |
- gfx::Rect* invalidated_rect) { |
- // Ensure the source image is mapped to read from it. |
- ImageDataAutoMapper auto_mapper(image); |
- if (!auto_mapper.is_valid()) |
- return; |
- |
- // Portion within the source image to cut out. |
- SkIRect src_irect = { src_rect.x(), src_rect.y(), |
- src_rect.right(), src_rect.bottom() }; |
- |
- // Location within the backing store to copy to. |
- *invalidated_rect = src_rect; |
- invalidated_rect->Offset(x, y); |
- SkRect dest_rect = { SkIntToScalar(invalidated_rect->x()), |
- SkIntToScalar(invalidated_rect->y()), |
- SkIntToScalar(invalidated_rect->right()), |
- SkIntToScalar(invalidated_rect->bottom()) }; |
- |
- if (image->format() != image_data_->format()) { |
- // Convert the image data if the format does not match. |
- ConvertImageData(image, src_irect, image_data_, dest_rect); |
- } else { |
- // We're guaranteed to have a mapped canvas since we mapped it in Init(). |
- SkCanvas* backing_canvas = image_data_->GetCanvas(); |
- |
- // We want to replace the contents of the bitmap rather than blend. |
- SkPaint paint; |
- paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
- backing_canvas->drawBitmapRect(*image->GetMappedBitmap(), |
- &src_irect, dest_rect, &paint); |
- } |
-} |
- |
-void PPB_Graphics2D_Impl::ExecuteScroll(const gfx::Rect& clip, |
- int dx, int dy, |
- gfx::Rect* invalidated_rect) { |
- gfx::ScrollCanvas(image_data_->GetCanvas(), clip, gfx::Vector2d(dx, dy)); |
- *invalidated_rect = clip; |
-} |
- |
-void PPB_Graphics2D_Impl::ExecuteReplaceContents(PPB_ImageData_Impl* image, |
- gfx::Rect* invalidated_rect, |
- PP_Resource* old_image_data) { |
- if (image->format() != image_data_->format()) { |
- DCHECK(image->width() == image_data_->width() && |
- image->height() == image_data_->height()); |
- // Convert the image data if the format does not match. |
- SkIRect src_irect = { 0, 0, image->width(), image->height() }; |
- SkRect dest_rect = { SkIntToScalar(0), |
- SkIntToScalar(0), |
- SkIntToScalar(image_data_->width()), |
- SkIntToScalar(image_data_->height()) }; |
- ConvertImageData(image, src_irect, image_data_, dest_rect); |
- } else { |
- // The passed-in image may not be mapped in our process, and we need to |
- // guarantee that the current backing store is always mapped. |
- if (!image->Map()) |
- return; |
- |
- if (old_image_data) |
- *old_image_data = image_data_->GetReference(); |
- image_data_ = image; |
- } |
- *invalidated_rect = gfx::Rect(0, 0, |
- image_data_->width(), image_data_->height()); |
-} |
- |
-void PPB_Graphics2D_Impl::ScheduleOffscreenCallback( |
- const FlushCallbackData& callback) { |
- DCHECK(!HasPendingFlush()); |
- offscreen_flush_pending_ = true; |
- MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&PPB_Graphics2D_Impl::ExecuteOffscreenCallback, |
- weak_ptr_factory_.GetWeakPtr(), |
- callback), |
- base::TimeDelta::FromMilliseconds(kOffscreenCallbackDelayMs)); |
-} |
- |
-void PPB_Graphics2D_Impl::ExecuteOffscreenCallback(FlushCallbackData data) { |
- DCHECK(offscreen_flush_pending_); |
- |
- // We must clear this flag before issuing the callback. It will be |
- // common for the plugin to issue another invalidate in response to a flush |
- // callback, and we don't want to think that a callback is already pending. |
- offscreen_flush_pending_ = false; |
- data.Execute(PP_OK); |
-} |
- |
-bool PPB_Graphics2D_Impl::HasPendingFlush() const { |
- return !unpainted_flush_callback_.is_null() || |
- !painted_flush_callback_.is_null() || |
- offscreen_flush_pending_; |
-} |
- |
-} // namespace ppapi |
-} // namespace webkit |