Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / pepper_graphics_2d_host.cc
index c13931d..5bed73c 100644 (file)
 #include "ppapi/host/host_message_context.h"
 #include "ppapi/host/ppapi_host.h"
 #include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/ppb_view_shared.h"
 #include "ppapi/thunk/enter.h"
 #include "skia/ext/platform_canvas.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"
@@ -136,7 +136,8 @@ struct PepperGraphics2DHost::QueuedOperation {
   enum Type {
     PAINT,
     SCROLL,
-    REPLACE
+    REPLACE,
+    SET_OFFSET
   };
 
   QueuedOperation(Type t)
@@ -160,18 +161,24 @@ struct PepperGraphics2DHost::QueuedOperation {
 
   // Valid when type == REPLACE.
   scoped_refptr<PPB_ImageData_Impl> replace_image;
+
+  // Valid when type == SET_OFFSET.
+  gfx::Point offset;
 };
 
 // static
-PepperGraphics2DHost* PepperGraphics2DHost::Create(RendererPpapiHost* host,
-                                                   PP_Instance instance,
-                                                   PP_Resource resource,
-                                                   const PP_Size& size,
-                                                   PP_Bool is_always_opaque) {
+PepperGraphics2DHost* PepperGraphics2DHost::Create(
+    RendererPpapiHost* host,
+    PP_Instance instance,
+    PP_Resource resource,
+    const PP_Size& size,
+    PP_Bool is_always_opaque,
+    scoped_refptr<PPB_ImageData_Impl> backing_store) {
   PepperGraphics2DHost* resource_host =
       new PepperGraphics2DHost(host, instance, resource);
   if (!resource_host->Init(size.width, size.height,
-                           PP_ToBool(is_always_opaque))) {
+                           PP_ToBool(is_always_opaque),
+                           backing_store)) {
     delete resource_host;
     return NULL;
   }
@@ -189,7 +196,8 @@ PepperGraphics2DHost::PepperGraphics2DHost(RendererPpapiHost* host,
       is_always_opaque_(false),
       scale_(1.0f),
       is_running_in_process_(host->IsRunningInProcess()),
-      texture_mailbox_modified_(true) {}
+      texture_mailbox_modified_(true),
+      resize_mode_(PP_GRAPHICS2D_DEV_RESIZEMODE_DEFAULT) {}
 
 PepperGraphics2DHost::~PepperGraphics2DHost() {
   // Unbind from the instance when destroyed if we're still bound.
@@ -197,10 +205,13 @@ PepperGraphics2DHost::~PepperGraphics2DHost() {
     bound_instance_->BindGraphics(bound_instance_->pp_instance(), 0);
 }
 
-bool PepperGraphics2DHost::Init(int width, int height, bool is_always_opaque) {
+bool PepperGraphics2DHost::Init(
+    int width,
+    int height,
+    bool is_always_opaque,
+    scoped_refptr<PPB_ImageData_Impl> backing_store) {
   // The underlying PPB_ImageData_Impl will validate the dimensions.
-  image_data_ = new PPB_ImageData_Impl(pp_instance(),
-                                       PPB_ImageData_Impl::PLATFORM);
+  image_data_ = backing_store;
   if (!image_data_->Init(PPB_ImageData_Impl::GetNativeImageDataFormat(),
                          width, height, true) ||
       !image_data_->Map()) {
@@ -225,13 +236,19 @@ int32_t PepperGraphics2DHost::OnResourceMessageReceived(
     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
         PpapiHostMsg_Graphics2D_ReplaceContents,
         OnHostMsgReplaceContents)
-    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
+    PPAPI_DISPATCH_HOST_RESOURCE_CALL(
         PpapiHostMsg_Graphics2D_Flush,
         OnHostMsgFlush)
     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
         PpapiHostMsg_Graphics2D_Dev_SetScale,
         OnHostMsgSetScale)
     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
+        PpapiHostMsg_Graphics2D_SetOffset,
+        OnHostMsgSetOffset)
+    PPAPI_DISPATCH_HOST_RESOURCE_CALL(
+        PpapiHostMsg_Graphics2D_SetResizeMode,
+        OnHostMsgSetResizeMode)
+    PPAPI_DISPATCH_HOST_RESOURCE_CALL(
         PpapiHostMsg_Graphics2D_ReadImageData,
         OnHostMsgReadImageData)
   IPC_END_MESSAGE_MAP()
@@ -322,7 +339,7 @@ bool PepperGraphics2DHost::BindToInstance(
 // 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 PepperGraphics2DHost::Paint(WebKit::WebCanvas* canvas,
+void PepperGraphics2DHost::Paint(blink::WebCanvas* canvas,
                                  const gfx::Rect& plugin_rect,
                                  const gfx::Rect& paint_rect) {
   TRACE_EVENT0("pepper", "PepperGraphics2DHost::Paint");
@@ -379,11 +396,17 @@ void PepperGraphics2DHost::Paint(WebKit::WebCanvas* canvas,
   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_);
+
+  gfx::PointF resize_scale(GetResizeScale());
+  gfx::PointF scale(ScalePoint(resize_scale, scale_));
+  if ((scale.x() != 1.0f || scale.y() != 1.0f) &&
+      scale.x() > 0.0f && scale.y() > 0.0f) {
+    canvas->scale(scale.x(), scale.y());
+    pixel_origin.set(pixel_origin.x() * (1.0f / scale.x()),
+                     pixel_origin.y() * (1.0f / scale.y()));
   }
+  pixel_origin.offset(SkIntToScalar(plugin_offset_.x()),
+                      SkIntToScalar(plugin_offset_.y()));
   canvas->drawBitmap(image, pixel_origin.x(), pixel_origin.y(), &paint);
 }
 
@@ -398,6 +421,13 @@ void PepperGraphics2DHost::ViewFlushedPaint() {
   }
 }
 
+void PepperGraphics2DHost::DidChangeView(const ppapi::ViewData& view_data) {
+  gfx::Size old_plugin_size = current_plugin_size_;
+  current_plugin_size_ = PP_ToGfxSize(view_data.rect.size);
+  if (bound_instance_)
+    bound_instance_->UpdateLayerTransform();
+}
+
 void PepperGraphics2DHost::SetScale(float scale) {
   scale_ = scale;
 }
@@ -414,6 +444,27 @@ PPB_ImageData_Impl* PepperGraphics2DHost::ImageData() {
   return image_data_.get();
 }
 
+gfx::Size PepperGraphics2DHost::Size() const {
+  if (!image_data_)
+    return gfx::Size();
+  return gfx::Size(image_data_->width(), image_data_->height());
+}
+
+gfx::PointF PepperGraphics2DHost::GetResizeScale() const {
+  switch (resize_mode_) {
+    case PP_GRAPHICS2D_DEV_RESIZEMODE_DEFAULT:
+      return gfx::PointF(1.0f, 1.0f);
+    case PP_GRAPHICS2D_DEV_RESIZEMODE_STRETCH:
+      if (flushed_plugin_size_.IsEmpty())
+        return gfx::PointF(1.0f, 1.0f);
+      return gfx::PointF(
+          1.0f * current_plugin_size_.width() / flushed_plugin_size_.width(),
+          1.0f * current_plugin_size_.height() / flushed_plugin_size_.height());
+  }
+  NOTREACHED();
+  return gfx::PointF(1.0f, 1.0f);
+}
+
 int32_t PepperGraphics2DHost::OnHostMsgPaintImageData(
     ppapi::host::HostMessageContext* context,
     const ppapi::HostResource& image_data,
@@ -506,7 +557,8 @@ int32_t PepperGraphics2DHost::OnHostMsgReplaceContents(
 }
 
 int32_t PepperGraphics2DHost::OnHostMsgFlush(
-    ppapi::host::HostMessageContext* context) {
+    ppapi::host::HostMessageContext* context,
+    const ppapi::ViewData& view_data) {
   // Don't allow more than one pending flush at a time.
   if (HasPendingFlush())
     return PP_ERROR_INPROGRESS;
@@ -514,10 +566,10 @@ int32_t PepperGraphics2DHost::OnHostMsgFlush(
   PP_Resource old_image_data = 0;
   flush_reply_context_ = context->MakeReplyMessageContext();
   if (is_running_in_process_)
-    return Flush(NULL);
+    return Flush(NULL, PP_ToGfxSize(view_data.rect.size));
 
   // Reuse image data when running out of process.
-  int32_t result = Flush(&old_image_data);
+  int32_t result = Flush(&old_image_data, PP_ToGfxSize(view_data.rect.size));
 
   if (old_image_data) {
     // If the Graphics2D has an old image data it's not using any more, send
@@ -543,6 +595,22 @@ int32_t PepperGraphics2DHost::OnHostMsgSetScale(
   return PP_ERROR_BADARGUMENT;
 }
 
+int32_t PepperGraphics2DHost::OnHostMsgSetOffset(
+    ppapi::host::HostMessageContext* context,
+    const PP_Point& offset) {
+  QueuedOperation operation(QueuedOperation::SET_OFFSET);
+  operation.offset = PP_ToGfxPoint(offset);
+  queued_operations_.push_back(operation);
+  return PP_OK;
+}
+
+int32_t PepperGraphics2DHost::OnHostMsgSetResizeMode(
+    ppapi::host::HostMessageContext* context,
+    PP_Graphics2D_Dev_ResizeMode resize_mode) {
+  resize_mode_ = resize_mode;
+  return PP_OK;
+}
+
 int32_t PepperGraphics2DHost::OnHostMsgReadImageData(
     ppapi::host::HostMessageContext* context,
     PP_Resource image,
@@ -552,7 +620,7 @@ int32_t PepperGraphics2DHost::OnHostMsgReadImageData(
 }
 
 void ReleaseCallback(scoped_ptr<base::SharedMemory> memory,
-                     unsigned sync_point,
+                     uint32 sync_point,
                      bool lost_resource) {}
 
 bool PepperGraphics2DHost::PrepareTextureMailbox(
@@ -582,13 +650,15 @@ void PepperGraphics2DHost::AttachedToNewLayer() {
   texture_mailbox_modified_ = true;
 }
 
-int32_t PepperGraphics2DHost::Flush(PP_Resource* old_image_data) {
+int32_t PepperGraphics2DHost::Flush(PP_Resource* old_image_data,
+                                    const gfx::Size& flushed_plugin_size) {
   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;
+    gfx::Rect old_op_rect;
     switch (operation.type) {
       case QueuedOperation::PAINT:
         ExecutePaintImageData(operation.paint_image.get(),
@@ -612,16 +682,28 @@ int32_t PepperGraphics2DHost::Flush(PP_Resource* old_image_data) {
                                done_replace_contents ? NULL : old_image_data);
         done_replace_contents = true;
         break;
+      case QueuedOperation::SET_OFFSET:
+        old_op_rect = gfx::Rect(plugin_offset_.x(), plugin_offset_.y(),
+            image_data_->width(), image_data_->height());
+        plugin_offset_ = operation.offset;
+        // The offset is applied below for |op_rect|.
+        op_rect = gfx::Rect(image_data_->width(), image_data_->height());
+        break;
     }
 
+    op_rect.Offset(plugin_offset_.x(), plugin_offset_.y());
+
     // 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 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()) {
+    if (bound_instance_ && (!op_rect.IsEmpty() || !old_op_rect.IsEmpty())) {
       gfx::Point scroll_delta(operation.scroll_dx, operation.scroll_dy);
+      if (!ConvertToLogicalPixels(scale_, &old_op_rect, NULL)) {
+        NOTREACHED();
+      }
       if (!ConvertToLogicalPixels(scale_,
                                   &op_rect,
                                   operation.type == QueuedOperation::SCROLL ?
@@ -635,23 +717,32 @@ int32_t PepperGraphics2DHost::Flush(PP_Resource* old_image_data) {
 
       // 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())
+      if (!gfx::IntersectRects(clip, op_rect).IsEmpty() ||
+          !gfx::IntersectRects(clip, old_op_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);
+        DCHECK(old_op_rect.IsEmpty());
       } else {
-        bound_instance_->InvalidateRect(op_rect);
+        if (!op_rect.IsEmpty())
+          bound_instance_->InvalidateRect(op_rect);
+        if (!old_op_rect.IsEmpty())
+          bound_instance_->InvalidateRect(old_op_rect);
       }
       texture_mailbox_modified_ = true;
     }
   }
   queued_operations_.clear();
 
+  flushed_plugin_size_ = flushed_plugin_size;
+  if (bound_instance_)
+    bound_instance_->UpdateLayerTransform();
+
   if (!bound_instance_) {
     // As promised in the API, we always schedule callback when unbound.
     ScheduleOffscreenFlushAck();