Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / renderer / pepper / pepper_compositor_host.cc
blobe372b1b01c7f6d5448a91cd683e9f1c5f9e2086e
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/pepper/pepper_compositor_host.h"
7 #include "base/logging.h"
8 #include "base/memory/shared_memory.h"
9 #include "cc/layers/layer.h"
10 #include "cc/layers/solid_color_layer.h"
11 #include "cc/layers/texture_layer.h"
12 #include "cc/resources/texture_mailbox.h"
13 #include "cc/trees/layer_tree_host.h"
14 #include "content/public/renderer/renderer_ppapi_host.h"
15 #include "content/renderer/pepper/gfx_conversion.h"
16 #include "content/renderer/pepper/host_globals.h"
17 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
18 #include "content/renderer/pepper/ppb_image_data_impl.h"
19 #include "ppapi/c/pp_errors.h"
20 #include "ppapi/host/dispatch_host_message.h"
21 #include "ppapi/host/ppapi_host.h"
22 #include "ppapi/proxy/ppapi_messages.h"
23 #include "ppapi/thunk/enter.h"
24 #include "ppapi/thunk/ppb_image_data_api.h"
25 #include "third_party/khronos/GLES2/gl2.h"
26 #include "ui/gfx/transform.h"
28 using ppapi::host::HostMessageContext;
29 using ppapi::thunk::EnterResourceNoLock;
30 using ppapi::thunk::PPB_ImageData_API;
32 namespace content {
34 namespace {
36 int32_t VerifyCommittedLayer(
37 const ppapi::CompositorLayerData* old_layer,
38 const ppapi::CompositorLayerData* new_layer,
39 scoped_ptr<base::SharedMemory>* image_shm) {
40 if (!new_layer->is_valid())
41 return PP_ERROR_BADARGUMENT;
43 if (new_layer->color) {
44 // Make sure the old layer is a color layer too.
45 if (old_layer && !old_layer->color)
46 return PP_ERROR_BADARGUMENT;
47 return PP_OK;
50 if (new_layer->texture) {
51 if (old_layer) {
52 // Make sure the old layer is a texture layer too.
53 if (!new_layer->texture)
54 return PP_ERROR_BADARGUMENT;
55 // The mailbox should be same, if the resource_id is not changed.
56 if (new_layer->common.resource_id == old_layer->common.resource_id) {
57 if (new_layer->texture->mailbox != old_layer->texture->mailbox)
58 return PP_ERROR_BADARGUMENT;
59 return PP_OK;
62 if (!new_layer->texture->mailbox.Verify())
63 return PP_ERROR_BADARGUMENT;
64 return PP_OK;
67 if (new_layer->image) {
68 if (old_layer) {
69 // Make sure the old layer is an image layer too.
70 if (!new_layer->image)
71 return PP_ERROR_BADARGUMENT;
72 // The image data resource should be same, if the resource_id is not
73 // changed.
74 if (new_layer->common.resource_id == old_layer->common.resource_id) {
75 if (new_layer->image->resource != old_layer->image->resource)
76 return PP_ERROR_BADARGUMENT;
77 return PP_OK;
80 EnterResourceNoLock<PPB_ImageData_API> enter(new_layer->image->resource,
81 true);
82 if (enter.failed())
83 return PP_ERROR_BADRESOURCE;
85 // TODO(penghuang): support all kinds of image.
86 PP_ImageDataDesc desc;
87 if (enter.object()->Describe(&desc) != PP_TRUE ||
88 desc.stride != desc.size.width * 4 ||
89 desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL) {
90 return PP_ERROR_BADARGUMENT;
93 int handle;
94 uint32_t byte_count;
95 if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK)
96 return PP_ERROR_FAILED;
98 #if defined(OS_WIN)
99 base::SharedMemoryHandle shm_handle;
100 if (!::DuplicateHandle(::GetCurrentProcess(),
101 reinterpret_cast<base::SharedMemoryHandle>(handle),
102 ::GetCurrentProcess(),
103 &shm_handle,
105 FALSE,
106 DUPLICATE_SAME_ACCESS)) {
107 return PP_ERROR_FAILED;
109 #else
110 base::SharedMemoryHandle shm_handle(dup(handle), false);
111 #endif
112 image_shm->reset(new base::SharedMemory(shm_handle, true));
113 if (!(*image_shm)->Map(desc.stride * desc.size.height)) {
114 image_shm->reset();
115 return PP_ERROR_NOMEMORY;
117 return PP_OK;
120 return PP_ERROR_BADARGUMENT;
123 } // namespace
125 PepperCompositorHost::LayerData::LayerData(
126 const scoped_refptr<cc::Layer>& cc,
127 const ppapi::CompositorLayerData& pp) : cc_layer(cc), pp_layer(pp) {}
129 PepperCompositorHost::LayerData::~LayerData() {}
131 PepperCompositorHost::PepperCompositorHost(
132 RendererPpapiHost* host,
133 PP_Instance instance,
134 PP_Resource resource)
135 : ResourceHost(host->GetPpapiHost(), instance, resource),
136 bound_instance_(NULL),
137 weak_factory_(this) {
138 layer_ = cc::Layer::Create();
139 // TODO(penghuang): SetMasksToBounds() can be expensive if the layer is
140 // transformed. Possibly better could be to explicitly clip the child layers
141 // (by modifying their bounds).
142 layer_->SetMasksToBounds(true);
143 layer_->SetIsDrawable(true);
146 PepperCompositorHost::~PepperCompositorHost() {
147 // Unbind from the instance when destroyed if we're still bound.
148 if (bound_instance_)
149 bound_instance_->BindGraphics(bound_instance_->pp_instance(), 0);
152 bool PepperCompositorHost::BindToInstance(
153 PepperPluginInstanceImpl* new_instance) {
154 if (new_instance && new_instance->pp_instance() != pp_instance())
155 return false; // Can't bind other instance's contexts.
156 if (bound_instance_ == new_instance)
157 return true; // Rebinding the same device, nothing to do.
158 if (bound_instance_ && new_instance)
159 return false; // Can't change a bound device.
160 bound_instance_ = new_instance;
161 if (!bound_instance_)
162 SendCommitLayersReplyIfNecessary();
164 return true;
167 void PepperCompositorHost::ViewInitiatedPaint() {
168 SendCommitLayersReplyIfNecessary();
171 void PepperCompositorHost::ViewFlushedPaint() {}
173 void PepperCompositorHost::ImageReleased(
174 int32_t id,
175 const scoped_ptr<base::SharedMemory>& shared_memory,
176 uint32_t sync_point,
177 bool is_lost) {
178 ResourceReleased(id, sync_point, is_lost);
181 void PepperCompositorHost::ResourceReleased(int32_t id,
182 uint32_t sync_point,
183 bool is_lost) {
184 host()->SendUnsolicitedReply(
185 pp_resource(),
186 PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost));
189 void PepperCompositorHost::SendCommitLayersReplyIfNecessary() {
190 if (!commit_layers_reply_context_.is_valid())
191 return;
192 host()->SendReply(commit_layers_reply_context_,
193 PpapiPluginMsg_Compositor_CommitLayersReply());
194 commit_layers_reply_context_ = ppapi::host::ReplyMessageContext();
197 void PepperCompositorHost::UpdateLayer(
198 const scoped_refptr<cc::Layer>& layer,
199 const ppapi::CompositorLayerData* old_layer,
200 const ppapi::CompositorLayerData* new_layer,
201 scoped_ptr<base::SharedMemory> image_shm) {
202 // Always update properties on cc::Layer, because cc::Layer
203 // will ignore any setting with unchanged value.
204 layer->SetIsDrawable(true);
205 layer->SetBlendMode(SkXfermode::kSrcOver_Mode);
206 layer->SetOpacity(new_layer->common.opacity);
207 layer->SetBounds(PP_ToGfxSize(new_layer->common.size));
208 layer->SetTransformOrigin(gfx::Point3F(new_layer->common.size.width / 2,
209 new_layer->common.size.height / 2,
210 0.0f));
212 gfx::Transform transform(gfx::Transform::kSkipInitialization);
213 transform.matrix().setColMajorf(new_layer->common.transform.matrix);
214 layer->SetTransform(transform);
216 // Consider a (0,0,0,0) rect as no clip rect.
217 if (new_layer->common.clip_rect.point.x != 0 ||
218 new_layer->common.clip_rect.point.y != 0 ||
219 new_layer->common.clip_rect.size.width != 0 ||
220 new_layer->common.clip_rect.size.height != 0) {
221 scoped_refptr<cc::Layer> clip_parent = layer->parent();
222 if (clip_parent.get() == layer_.get()) {
223 // Create a clip parent layer, if it does not exist.
224 clip_parent = cc::Layer::Create();
225 clip_parent->SetMasksToBounds(true);
226 clip_parent->SetIsDrawable(true);
227 layer_->ReplaceChild(layer.get(), clip_parent);
228 clip_parent->AddChild(layer);
230 gfx::Point position = PP_ToGfxPoint(new_layer->common.clip_rect.point);
231 clip_parent->SetPosition(position);
232 clip_parent->SetBounds(PP_ToGfxSize(new_layer->common.clip_rect.size));
233 layer->SetPosition(gfx::Point(-position.x(), -position.y()));
234 } else if (layer->parent() != layer_.get()) {
235 // Remove the clip parent layer.
236 layer_->ReplaceChild(layer->parent(), layer);
237 layer->SetPosition(gfx::Point());
240 if (new_layer->color) {
241 layer->SetBackgroundColor(SkColorSetARGBMacro(
242 new_layer->color->alpha * 255,
243 new_layer->color->red * 255,
244 new_layer->color->green * 255,
245 new_layer->color->blue * 255));
246 return;
249 if (new_layer->texture) {
250 scoped_refptr<cc::TextureLayer> texture_layer(
251 static_cast<cc::TextureLayer*>(layer.get()));
252 if (!old_layer ||
253 new_layer->common.resource_id != old_layer->common.resource_id) {
254 cc::TextureMailbox mailbox(new_layer->texture->mailbox,
255 new_layer->texture->target,
256 new_layer->texture->sync_point);
257 texture_layer->SetTextureMailbox(mailbox,
258 cc::SingleReleaseCallback::Create(
259 base::Bind(&PepperCompositorHost::ResourceReleased,
260 weak_factory_.GetWeakPtr(),
261 new_layer->common.resource_id)));;
263 texture_layer->SetPremultipliedAlpha(new_layer->texture->premult_alpha);
264 gfx::RectF rect = PP_ToGfxRectF(new_layer->texture->source_rect);
265 texture_layer->SetUV(rect.origin(), rect.bottom_right());
266 return;
269 if (new_layer->image) {
270 if (!old_layer ||
271 new_layer->common.resource_id != old_layer->common.resource_id) {
272 scoped_refptr<cc::TextureLayer> image_layer(
273 static_cast<cc::TextureLayer*>(layer.get()));
274 EnterResourceNoLock<PPB_ImageData_API> enter(new_layer->image->resource,
275 true);
276 DCHECK(enter.succeeded());
278 // TODO(penghuang): support all kinds of image.
279 PP_ImageDataDesc desc;
280 PP_Bool rv = enter.object()->Describe(&desc);
281 DCHECK_EQ(rv, PP_TRUE);
282 DCHECK_EQ(desc.stride, desc.size.width * 4);
283 DCHECK_EQ(desc.format, PP_IMAGEDATAFORMAT_RGBA_PREMUL);
285 cc::TextureMailbox mailbox(image_shm.get(),
286 PP_ToGfxSize(desc.size));
287 image_layer->SetTextureMailbox(mailbox,
288 cc::SingleReleaseCallback::Create(
289 base::Bind(&PepperCompositorHost::ImageReleased,
290 weak_factory_.GetWeakPtr(),
291 new_layer->common.resource_id,
292 base::Passed(&image_shm))));
294 // ImageData is always premultiplied alpha.
295 image_layer->SetPremultipliedAlpha(true);
297 return;
299 // Should not be reached.
300 NOTREACHED();
303 int32_t PepperCompositorHost::OnResourceMessageReceived(
304 const IPC::Message& msg,
305 HostMessageContext* context) {
306 PPAPI_BEGIN_MESSAGE_MAP(PepperCompositorHost, msg)
307 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
308 PpapiHostMsg_Compositor_CommitLayers, OnHostMsgCommitLayers)
309 PPAPI_END_MESSAGE_MAP()
310 return ppapi::host::ResourceHost::OnResourceMessageReceived(msg, context);
313 bool PepperCompositorHost::IsCompositorHost() {
314 return true;
317 int32_t PepperCompositorHost::OnHostMsgCommitLayers(
318 HostMessageContext* context,
319 const std::vector<ppapi::CompositorLayerData>& layers,
320 bool reset) {
321 if (commit_layers_reply_context_.is_valid())
322 return PP_ERROR_INPROGRESS;
324 scoped_ptr<scoped_ptr<base::SharedMemory>[]> image_shms;
325 if (layers.size() > 0) {
326 image_shms.reset(new scoped_ptr<base::SharedMemory>[layers.size()]);
327 if (!image_shms)
328 return PP_ERROR_NOMEMORY;
329 // Verfiy the layers first, if an error happens, we will return the error to
330 // plugin and keep current layers set by the previous CommitLayers()
331 // unchanged.
332 for (size_t i = 0; i < layers.size(); ++i) {
333 const ppapi::CompositorLayerData* old_layer = NULL;
334 if (!reset && i < layers_.size())
335 old_layer = &layers_[i].pp_layer;
336 int32_t rv = VerifyCommittedLayer(old_layer, &layers[i], &image_shms[i]);
337 if (rv != PP_OK)
338 return rv;
342 // ResetLayers() has been called, we need rebuild layer stack.
343 if (reset) {
344 layer_->RemoveAllChildren();
345 layers_.clear();
348 for (size_t i = 0; i < layers.size(); ++i) {
349 const ppapi::CompositorLayerData* pp_layer = &layers[i];
350 LayerData* data = i >= layers_.size() ? NULL : &layers_[i];
351 DCHECK(!data || data->cc_layer.get());
352 scoped_refptr<cc::Layer> cc_layer = data ? data->cc_layer : NULL;
353 ppapi::CompositorLayerData* old_layer = data ? &data->pp_layer : NULL;
355 if (!cc_layer.get()) {
356 if (pp_layer->color)
357 cc_layer = cc::SolidColorLayer::Create();
358 else if (pp_layer->texture || pp_layer->image)
359 cc_layer = cc::TextureLayer::CreateForMailbox(NULL);
360 layer_->AddChild(cc_layer);
363 UpdateLayer(cc_layer, old_layer, pp_layer, image_shms[i].Pass());
365 if (old_layer)
366 *old_layer = *pp_layer;
367 else
368 layers_.push_back(LayerData(cc_layer, *pp_layer));
371 // We need to force a commit for each CommitLayers() call, even if no layers
372 // changed since the last call to CommitLayers(). This is so
373 // WiewInitiatedPaint() will always be called.
374 if (layer_->layer_tree_host())
375 layer_->layer_tree_host()->SetNeedsCommit();
377 // If the host is not bound to the instance, return PP_OK immediately.
378 if (!bound_instance_)
379 return PP_OK;
381 commit_layers_reply_context_ = context->MakeReplyMessageContext();
382 return PP_OK_COMPLETIONPENDING;
385 } // namespace content