#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"
enum Type {
PAINT,
SCROLL,
- REPLACE
+ REPLACE,
+ SET_OFFSET
};
QueuedOperation(Type t)
// 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;
}
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.
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()) {
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()
// 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");
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);
}
}
}
+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;
}
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,
}
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;
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
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,
}
void ReleaseCallback(scoped_ptr<base::SharedMemory> memory,
- unsigned sync_point,
+ uint32 sync_point,
bool lost_resource) {}
bool PepperGraphics2DHost::PrepareTextureMailbox(
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(),
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 ?
// 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();