Chromium Code Reviews| 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..1d2b2aaa577fe5ca53833c220ed4f46f830795c7 |
| --- /dev/null |
| +++ b/content/renderer/pepper/pepper_compositor_host.cc |
| @@ -0,0 +1,293 @@ |
| +// 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/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 { |
| + |
| +PepperCompositorHost::PepperCompositorHost( |
| + RendererPpapiHost* host, |
| + PP_Instance instance, |
| + PP_Resource resource) |
| + : ResourceHost(host->GetPpapiHost(), instance, resource), |
| + bound_instance_(NULL), |
| + weak_factory_(this) { |
| + layer_ = cc::SolidColorLayer::Create(); |
|
piman
2014/06/04 13:19:42
You're only using this for grouping, maybe just ma
Peng
2014/06/05 00:50:38
Done.
|
| + layer_->SetMasksToBounds(true); |
|
piman
2014/06/04 13:19:43
Note: this can be expensive if the layer is transf
Peng
2014/06/05 00:50:38
Done.
|
| + 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. |
|
piman
2014/06/04 13:19:42
This can only happen for bound_instance_ == new_in
Peng
2014/06/05 00:50:38
Seems it is not necessary to check this case.
|
| + if (bound_instance_ && new_instance) |
| + return false; // Can't change a bound device. |
|
piman
2014/06/04 13:19:42
You can replace this by a DCHECK, since we call Bi
Peng
2014/06/05 00:50:38
Done.
|
| + 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::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; |
| +} |
| + |
| +void PepperCompositorHost::UpdateLayer( |
| + const scoped_refptr<cc::Layer>& layer, |
| + const ppapi::CompositorLayerData* old_layer, |
| + const ppapi::CompositorLayerData* new_layer) { |
| + CHECK(!old_layer || new_layer->type == old_layer->type); |
|
piman
2014/06/04 13:19:42
no CHECK. Use DCHECK.
Peng
2014/06/05 00:50:38
Done.
|
| + |
| + // Always update properties on cc::Layer, because cc::Layer |
| + // will ignore any setting with unchanged value. |
| + layer->SetBounds(PP_ToGfxSize((new_layer)->size)); |
|
piman
2014/06/04 13:19:42
no need for extra () around new_layer
Peng
2014/06/05 00:50:38
Done.
|
| + layer->SetBlendMode(SkXfermode::kSrcOver_Mode); |
| + layer->SetOpacity(new_layer->opacity / 255.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) { |
| + if (!layer->mask_layer()) |
| + layer->SetMaskLayer(cc::Layer::Create()); |
|
piman
2014/06/04 13:19:43
Masks are *very* expensive. It's most likely not w
Peng
2014/06/05 00:50:38
Done.
|
| + layer->mask_layer()->SetPosition(PP_ToGfxPoint(new_layer->clip_rect.point)); |
| + layer->mask_layer()->SetBounds(PP_ToGfxSize(new_layer->clip_rect.size)); |
| + } else { |
| + layer->SetMaskLayer(NULL); |
| + } |
| + |
| + if (new_layer->type == ppapi::CompositorLayerData::TYPE_COLOR) { |
| + layer->SetBackgroundColor(SkColorSetARGBMacro(new_layer->color.alpha, |
| + new_layer->color.red, |
| + new_layer->color.green, |
| + new_layer->color.blue)); |
| + } 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); |
| + 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); |
| + PP_ImageDataDesc desc; |
| + enter.object()->Describe(&desc); |
| + int handle; |
| + uint32_t byte_count; |
| + enter.object()->GetSharedMemory(&handle, &byte_count); |
| +#if defined(OS_WIN) |
| + base::SharedMemoryHandle shm_handle = |
| + static_cast<base::SharedMemoryHandle>(_dup(handle)); |
| +#else |
| + base::SharedMemoryHandle shm_handle(dup(handle), false); |
| +#endif |
|
piman
2014/06/04 13:19:43
rather than duping the handle, can we just keep a
Peng
2014/06/05 00:50:38
I found SharedMemory will closed the handle in dto
|
| + // 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)); |
| + CHECK(shared_memory->Map(desc.stride * desc.size.height)); |
|
piman
2014/06/04 13:19:43
no CHECK.
Peng
2014/06/05 00:50:38
If the Map() failed. cc will crash anyway. So what
piman
2014/06/09 18:27:24
Return failure and not crash?
Peng
2014/06/10 16:20:28
Done
|
| + 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); |
| + } |
| + } |
| +} |
| + |
| +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()) { |
| + NOTREACHED(); |
|
piman
2014/06/04 13:19:42
Not NOTREACHED(), it can be reached by untrusted p
Peng
2014/06/05 00:50:38
Sorry. I don't understand. In plugin process, we w
danakj
2014/06/06 14:54:31
NOTREACHED() means "it's impossible to get here".
Peng
2014/06/06 19:29:43
Remove NOTREACHED(). Done
|
| + return PP_ERROR_INPROGRESS; |
| + } |
| + |
| + commit_layers_reply_context_ = context->MakeReplyMessageContext(); |
| + |
| + // Verfiy layers first, if an error happens, we will return the error to |
|
raymes
2014/06/04 01:11:38
nit: Verify the layers first
Peng
2014/06/05 00:50:38
Done.
|
| + // plugin and keep current layers set by previous CommitLayers() unchanged. |
|
raymes
2014/06/04 01:11:38
nit: by the previous CommitLayers()
Peng
2014/06/05 00:50:38
Done.
|
| + for (size_t i = 0; i < layers.size(); ++i) { |
| + const ppapi::CompositorLayerData& pp_layer = layers[i]; |
| + // Make sure the layer type is not changed. |
| + if (!reset) { |
| + ppapi::CompositorLayerData* old_layer = |
| + i >= pp_layers_.size() ? NULL : &pp_layers_[i]; |
| + if (old_layer && old_layer->type != pp_layer.type) { |
| + NOTREACHED(); |
|
piman
2014/06/04 13:19:42
Same here, not NOTREACHED
Peng
2014/06/05 00:50:38
Same. It should only crash in debug build. And jus
|
| + return PP_ERROR_BADARGUMENT; |
| + } |
| + } |
| + |
| + if (pp_layer.type == ppapi::CompositorLayerData::TYPE_COLOR || |
| + pp_layer.type == ppapi::CompositorLayerData::TYPE_TEXTURE) { |
| + continue; |
| + } |
| + |
| + // Check image layer. |
| + if (pp_layer.type == ppapi::CompositorLayerData::TYPE_IMAGE) { |
| + EnterResourceNoLock<PPB_ImageData_API> enter( |
| + pp_layer.image.host_resource, true); |
| + if (enter.failed()) { |
| + NOTREACHED(); |
|
piman
2014/06/04 13:19:42
same here
Peng
2014/06/10 16:20:28
Done.
|
| + return PP_ERROR_BADRESOURCE; |
| + } |
| + |
| + // TODO(penghuang): support all kinds of image. |
| + PP_ImageDataDesc desc; |
| + if (!enter.object()->Describe(&desc) || |
| + desc.stride != desc.size.width * 4 || |
| + desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL) { |
| + NOTREACHED(); |
|
piman
2014/06/04 13:19:43
same here
Peng
2014/06/10 16:20:28
Done.
|
| + return PP_ERROR_BADARGUMENT; |
| + } |
| + |
| + int handle; |
| + uint32_t byte_count; |
| + if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK) |
| + return PP_ERROR_FAILED; |
| + continue; |
| + } |
| + return PP_ERROR_BADARGUMENT; |
|
raymes
2014/06/04 01:11:38
nit: Could we pull the body of this loop out into
Peng
2014/06/05 00:50:38
Done.
|
| + } |
| + |
| + // ResetLayers() has been called, we need rebuild layer stack. |
| + if (reset) { |
| + layer_->RemoveAllChildren(); |
| + cc_layers_.clear(); |
| + pp_layers_.clear(); |
| + } |
| + |
| + for (size_t i = 0; i < layers.size(); ++i) { |
| + const ppapi::CompositorLayerData& pp_layer = layers[i]; |
| + ppapi::CompositorLayerData* old_layer = |
| + i >= pp_layers_.size() ? NULL : &pp_layers_[i]; |
| + scoped_refptr<cc::Layer> cc_layer = |
| + i >= cc_layers_.size() ? NULL : cc_layers_[i]; |
| + |
| + CHECK((old_layer && cc_layer) || (!old_layer && !cc_layer)); |
|
piman
2014/06/04 13:19:43
no CHECK. use DCHECK.
can also be written as DCHE
Peng
2014/06/05 00:50:38
After adding struct LayerData { cc_layer, pp_layer
|
| + |
| + 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); |
| + } |
| + cc_layer->SetIsDrawable(true); |
| + cc_layer->SetAnchorPoint(gfx::PointF()); |
|
raymes
2014/06/04 01:11:38
Would it make sense to shift these into UpdateLaye
Peng
2014/06/05 00:50:38
Done.
|
| + } |
| + |
| + UpdateLayer(cc_layer, old_layer, &pp_layer); |
| + |
| + if (old_layer) { |
| + *old_layer = pp_layer; |
| + } else { |
| + layer_->AddChild(cc_layer); |
| + cc_layers_.push_back(cc_layer); |
| + pp_layers_.push_back(pp_layer); |
| + } |
| + } |
| + |
| + return PP_OK_COMPLETIONPENDING; |
| +} |
| + |
| +} // namespace content |