| Index: content/renderer/pepper/pepper_compositor_host.cc
|
| diff --git a/content/renderer/pepper/pepper_compositor_host.cc b/content/renderer/pepper/pepper_compositor_host.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..258ee9d9337e6b43eec92de9187cb06a3c61bcc6
|
| --- /dev/null
|
| +++ b/content/renderer/pepper/pepper_compositor_host.cc
|
| @@ -0,0 +1,336 @@
|
| +// Copyright 2014 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 "content/renderer/pepper/pepper_compositor_host.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/memory/shared_memory.h"
|
| +#include "cc/layers/layer.h"
|
| +#include "cc/layers/solid_color_layer.h"
|
| +#include "cc/layers/texture_layer.h"
|
| +#include "cc/resources/texture_mailbox.h"
|
| +#include "content/public/renderer/renderer_ppapi_host.h"
|
| +#include "content/renderer/pepper/gfx_conversion.h"
|
| +#include "content/renderer/pepper/host_globals.h"
|
| +#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
|
| +#include "content/renderer/pepper/ppb_image_data_impl.h"
|
| +#include "ppapi/c/pp_errors.h"
|
| +#include "ppapi/host/dispatch_host_message.h"
|
| +#include "ppapi/host/ppapi_host.h"
|
| +#include "ppapi/proxy/ppapi_messages.h"
|
| +#include "ppapi/thunk/enter.h"
|
| +#include "ppapi/thunk/ppb_image_data_api.h"
|
| +#include "third_party/khronos/GLES2/gl2.h"
|
| +#include "ui/gfx/transform.h"
|
| +
|
| +using ppapi::host::HostMessageContext;
|
| +using ppapi::thunk::EnterResourceNoLock;
|
| +using ppapi::thunk::PPB_ImageData_API;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +int32_t VerifyCommittedLayer(
|
| + const ppapi::CompositorLayerData* old_layer,
|
| + const ppapi::CompositorLayerData* new_layer) {
|
| + if (old_layer && old_layer->type != new_layer->type)
|
| + return PP_ERROR_BADARGUMENT;
|
| +
|
| + if (new_layer->type == ppapi::CompositorLayerData::TYPE_COLOR)
|
| + return PP_OK;
|
| +
|
| + // Check texture layer.
|
| + if (new_layer->type == ppapi::CompositorLayerData::TYPE_TEXTURE) {
|
| + if (old_layer && new_layer->resource_id == old_layer->resource_id) {
|
| + if (memcmp(new_layer->texture.mailbox,
|
| + old_layer->texture.mailbox,
|
| + sizeof(ppapi::CompositorLayerData::Mailbox)) != 0) {
|
| + return PP_ERROR_BADARGUMENT;
|
| + }
|
| + } else {
|
| + gpu::Mailbox gpu_mailbox;
|
| + gpu_mailbox.SetName(new_layer->texture.mailbox);
|
| + if (!gpu_mailbox.Verify())
|
| + return PP_ERROR_BADARGUMENT;
|
| + }
|
| + return PP_OK;
|
| + }
|
| +
|
| + // Check image layer.
|
| + if (new_layer->type == ppapi::CompositorLayerData::TYPE_IMAGE) {
|
| + if (old_layer && new_layer->resource_id == old_layer->resource_id) {
|
| + if (new_layer->image.host_resource != old_layer->image.host_resource)
|
| + return PP_ERROR_BADARGUMENT;
|
| + } else {
|
| + EnterResourceNoLock<PPB_ImageData_API> enter(
|
| + new_layer->image.host_resource, true);
|
| + if (enter.failed())
|
| + return PP_ERROR_BADRESOURCE;
|
| +
|
| + // TODO(penghuang): support all kinds of image.
|
| + PP_ImageDataDesc desc;
|
| + if (enter.object()->Describe(&desc) != PP_TRUE ||
|
| + desc.stride != desc.size.width * 4 ||
|
| + desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL) {
|
| + return PP_ERROR_BADARGUMENT;
|
| + }
|
| +
|
| + int handle;
|
| + uint32_t byte_count;
|
| + if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK)
|
| + return PP_ERROR_FAILED;
|
| + }
|
| + return PP_OK;
|
| + }
|
| + return PP_ERROR_BADARGUMENT;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +PepperCompositorHost::PepperCompositorHost(
|
| + RendererPpapiHost* host,
|
| + PP_Instance instance,
|
| + PP_Resource resource)
|
| + : ResourceHost(host->GetPpapiHost(), instance, resource),
|
| + bound_instance_(NULL),
|
| + weak_factory_(this) {
|
| + layer_ = cc::Layer::Create();
|
| + // TODO(penghuang): SetMasksToBounds() can be expensive if the layer is
|
| + // transformed. Possibly better could be to explicitly clip the child layers
|
| + // (by modifying their bounds).
|
| + layer_->SetMasksToBounds(true);
|
| + layer_->SetIsDrawable(true);
|
| +}
|
| +
|
| +PepperCompositorHost::~PepperCompositorHost() {
|
| + // Unbind from the instance when destroyed if we're still bound.
|
| + if (bound_instance_)
|
| + bound_instance_->BindGraphics(bound_instance_->pp_instance(), 0);
|
| +}
|
| +
|
| +bool PepperCompositorHost::BindToInstance(
|
| + PepperPluginInstanceImpl* new_instance) {
|
| + if (new_instance && new_instance->pp_instance() != pp_instance())
|
| + return false; // Can't bind other instance's contexts.
|
| + 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.
|
| + bound_instance_ = new_instance;
|
| + return true;
|
| +}
|
| +
|
| +void PepperCompositorHost::ViewInitiatedPaint() {
|
| + if (!commit_layers_reply_context_.is_valid())
|
| + return;
|
| + host()->SendReply(commit_layers_reply_context_,
|
| + PpapiPluginMsg_Compositor_CommitLayersReply());
|
| + commit_layers_reply_context_ = ppapi::host::ReplyMessageContext();
|
| +}
|
| +
|
| +void PepperCompositorHost::ViewFlushedPaint() {}
|
| +
|
| +void PepperCompositorHost::UpdateLayer(
|
| + const scoped_refptr<cc::Layer>& layer,
|
| + const ppapi::CompositorLayerData* old_layer,
|
| + const ppapi::CompositorLayerData* new_layer) {
|
| + DCHECK(!old_layer || new_layer->type == old_layer->type);
|
| +
|
| + // Always update properties on cc::Layer, because cc::Layer
|
| + // will ignore any setting with unchanged value.
|
| + layer->SetIsDrawable(true);
|
| + layer->SetBlendMode(SkXfermode::kSrcOver_Mode);
|
| + layer->SetOpacity(new_layer->opacity);
|
| + layer->SetBounds(PP_ToGfxSize(new_layer->size));
|
| + layer->SetTransformOrigin(gfx::Point3F(
|
| + new_layer->size.width / 2, new_layer->size.height / 2, 0.0f));
|
| +
|
| + gfx::Transform transform(gfx::Transform::kSkipInitialization);
|
| + transform.matrix().setColMajorf(new_layer->transform);
|
| + layer->SetTransform(transform);
|
| +
|
| + // Consider a (0,0,0,0) rect as no clip rect.
|
| + if (new_layer->clip_rect.point.x != 0 ||
|
| + new_layer->clip_rect.point.y != 0 ||
|
| + new_layer->clip_rect.size.width != 0 ||
|
| + new_layer->clip_rect.size.height != 0) {
|
| + scoped_refptr<cc::Layer> clip_parent = layer->parent();
|
| + if (clip_parent == layer_) {
|
| + // Create a clip parent layer, if it does not exist.
|
| + clip_parent = cc::Layer::Create();
|
| + clip_parent->SetMasksToBounds(true);
|
| + clip_parent->SetIsDrawable(true);
|
| + layer_->ReplaceChild(layer, clip_parent);
|
| + clip_parent->AddChild(layer);
|
| + }
|
| + gfx::Point position = PP_ToGfxPoint(new_layer->clip_rect.point);
|
| + clip_parent->SetPosition(position);
|
| + clip_parent->SetBounds(PP_ToGfxSize(new_layer->clip_rect.size));
|
| + layer->SetPosition(gfx::Point(-position.x(), -position.y()));
|
| + } else if (layer->parent() != layer_) {
|
| + // Remove the clip parent layer.
|
| + layer_->ReplaceChild(layer->parent(), layer);
|
| + layer->SetPosition(gfx::Point());
|
| + }
|
| +
|
| + if (new_layer->type == ppapi::CompositorLayerData::TYPE_COLOR) {
|
| + layer->SetBackgroundColor(SkColorSetARGBMacro(new_layer->color.alpha * 255,
|
| + new_layer->color.red * 255,
|
| + new_layer->color.green * 255,
|
| + new_layer->color.blue * 255));
|
| + } else if (new_layer->type == ppapi::CompositorLayerData::TYPE_TEXTURE) {
|
| + scoped_refptr<cc::TextureLayer> texture_layer(
|
| + static_cast<cc::TextureLayer*>(layer.get()));
|
| + if (!old_layer || new_layer->resource_id != old_layer->resource_id) {
|
| + gpu::Mailbox gpu_mailbox;
|
| + gpu_mailbox.SetName(new_layer->texture.mailbox);
|
| + DCHECK(gpu_mailbox.Verify());
|
| + cc::TextureMailbox mailbox(gpu_mailbox,
|
| + GL_TEXTURE_2D,
|
| + new_layer->texture.sync_point);
|
| + texture_layer->SetTextureMailbox(mailbox,
|
| + cc::SingleReleaseCallback::Create(
|
| + base::Bind(&PepperCompositorHost::ResourceReleased,
|
| + weak_factory_.GetWeakPtr(),
|
| + new_layer->resource_id)));;
|
| + }
|
| + texture_layer->SetPremultipliedAlpha(new_layer->texture.premult_alpha);
|
| + gfx::RectF rect = PP_ToGfxRectF(new_layer->texture.source_rect);
|
| + texture_layer->SetUV(rect.origin(), rect.bottom_right());
|
| + } else if (new_layer->type == ppapi::CompositorLayerData::TYPE_IMAGE) {
|
| + if (!old_layer || new_layer->resource_id != old_layer->resource_id) {
|
| + scoped_refptr<cc::TextureLayer> image_layer(
|
| + static_cast<cc::TextureLayer*>(layer.get()));
|
| + EnterResourceNoLock<PPB_ImageData_API> enter(
|
| + new_layer->image.host_resource, true);
|
| + DCHECK(enter.succeeded());
|
| + PP_ImageDataDesc desc;
|
| + {
|
| + PP_Bool rv = enter.object()->Describe(&desc);
|
| + DCHECK_EQ(rv, PP_TRUE);
|
| + }
|
| + int handle;
|
| + uint32_t byte_count;
|
| + {
|
| + int32_t rv = enter.object()->GetSharedMemory(&handle, &byte_count);
|
| + DCHECK_EQ(rv, PP_OK);
|
| + }
|
| +#if defined(OS_WIN)
|
| + base::SharedMemoryHandle shm_handle =
|
| + static_cast<base::SharedMemoryHandle>(_dup(handle));
|
| +#else
|
| + base::SharedMemoryHandle shm_handle(dup(handle), false);
|
| +#endif
|
| + // Use a scoped_ptr to keep shared_memory alive until
|
| + // PepperCompositorHost::ImageReleased is called.
|
| + scoped_ptr<base::SharedMemory> shared_memory(
|
| + new base::SharedMemory(shm_handle, true));
|
| + shared_memory->Map(desc.stride * desc.size.height);
|
| + cc::TextureMailbox mailbox(shared_memory.get(),
|
| + PP_ToGfxSize(desc.size));
|
| + image_layer->SetTextureMailbox(mailbox,
|
| + cc::SingleReleaseCallback::Create(
|
| + base::Bind(&PepperCompositorHost::ImageReleased,
|
| + weak_factory_.GetWeakPtr(),
|
| + new_layer->resource_id,
|
| + base::Passed(&shared_memory))));
|
| +
|
| + // ImageData is always premultiplied alpha.
|
| + image_layer->SetPremultipliedAlpha(true);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void PepperCompositorHost::ResourceReleased(int32_t id,
|
| + uint32_t sync_point,
|
| + bool is_lost) {
|
| + host()->SendUnsolicitedReply(
|
| + pp_resource(),
|
| + PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost));
|
| +}
|
| +
|
| +void PepperCompositorHost::ImageReleased(
|
| + int32_t id,
|
| + const scoped_ptr<base::SharedMemory>& shared_memory,
|
| + uint32_t sync_point,
|
| + bool is_lost) {
|
| + ResourceReleased(id, sync_point, is_lost);
|
| +}
|
| +
|
| +int32_t PepperCompositorHost::OnResourceMessageReceived(
|
| + const IPC::Message& msg,
|
| + HostMessageContext* context) {
|
| + PPAPI_BEGIN_MESSAGE_MAP(PepperCompositorHost, msg)
|
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL(
|
| + PpapiHostMsg_Compositor_CommitLayers, OnHostMsgCommitLayers)
|
| + PPAPI_END_MESSAGE_MAP()
|
| + return ppapi::host::ResourceHost::OnResourceMessageReceived(msg, context);
|
| +}
|
| +
|
| +bool PepperCompositorHost::IsCompositorHost() {
|
| + return true;
|
| +}
|
| +
|
| +int32_t PepperCompositorHost::OnHostMsgCommitLayers(
|
| + HostMessageContext* context,
|
| + const std::vector<ppapi::CompositorLayerData>& layers,
|
| + bool reset) {
|
| + // Do not support CommitLayers() on an unbounded compositor.
|
| + if (!bound_instance_)
|
| + return PP_ERROR_FAILED;
|
| +
|
| + if (commit_layers_reply_context_.is_valid())
|
| + return PP_ERROR_INPROGRESS;
|
| +
|
| + commit_layers_reply_context_ = context->MakeReplyMessageContext();
|
| +
|
| + // Verfiy the layers first, if an error happens, we will return the error to
|
| + // plugin and keep current layers set by the previous CommitLayers()
|
| + // unchanged.
|
| + for (size_t i = 0; i < layers.size(); ++i) {
|
| + const ppapi::CompositorLayerData* old_layer = NULL;
|
| + if (!reset && i < layers_.size())
|
| + old_layer = &layers_[i].pp_layer;
|
| + int32_t rv = VerifyCommittedLayer(old_layer, &layers[i]);
|
| + if (rv != PP_OK)
|
| + return rv;
|
| + }
|
| +
|
| + // ResetLayers() has been called, we need rebuild layer stack.
|
| + if (reset) {
|
| + layer_->RemoveAllChildren();
|
| + layers_.clear();
|
| + }
|
| +
|
| + for (size_t i = 0; i < layers.size(); ++i) {
|
| + const ppapi::CompositorLayerData* pp_layer = &layers[i];
|
| + LayerData* data = i >= layers_.size() ? NULL : &layers_[i];
|
| + DCHECK(!data || data->cc_layer);
|
| + scoped_refptr<cc::Layer> cc_layer = data ? data->cc_layer : NULL;
|
| + ppapi::CompositorLayerData* old_layer = data ? &data->pp_layer : NULL;
|
| +
|
| + if (!cc_layer) {
|
| + if (pp_layer->type == ppapi::CompositorLayerData::TYPE_COLOR) {
|
| + cc_layer = cc::SolidColorLayer::Create();
|
| + } else if (pp_layer->type == ppapi::CompositorLayerData::TYPE_TEXTURE ||
|
| + pp_layer->type == ppapi::CompositorLayerData::TYPE_IMAGE) {
|
| + cc_layer = cc::TextureLayer::CreateForMailbox(NULL);
|
| + }
|
| + layer_->AddChild(cc_layer);
|
| + }
|
| +
|
| + UpdateLayer(cc_layer, old_layer, pp_layer);
|
| +
|
| + if (old_layer) {
|
| + *old_layer = *pp_layer;
|
| + } else {
|
| + layers_.push_back(LayerData(cc_layer, *pp_layer));
|
| + }
|
| + }
|
| +
|
| + return PP_OK_COMPLETIONPENDING;
|
| +}
|
| +
|
| +} // namespace content
|
|
|