third_party/re2: Remove remove-static-initializers.patch.
[chromium-blink-merge.git] / content / renderer / pepper / pepper_compositor_host.cc
blobd366db4bff7d7f4a63870a1253f93e6c35633d7c
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 <limits>
9 #include "base/logging.h"
10 #include "base/memory/shared_memory.h"
11 #include "cc/layers/layer.h"
12 #include "cc/layers/solid_color_layer.h"
13 #include "cc/layers/texture_layer.h"
14 #include "cc/resources/texture_mailbox.h"
15 #include "cc/trees/layer_tree_host.h"
16 #include "content/child/child_shared_bitmap_manager.h"
17 #include "content/child/child_thread_impl.h"
18 #include "content/public/renderer/renderer_ppapi_host.h"
19 #include "content/renderer/pepper/gfx_conversion.h"
20 #include "content/renderer/pepper/host_globals.h"
21 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
22 #include "content/renderer/pepper/ppb_image_data_impl.h"
23 #include "ppapi/c/pp_errors.h"
24 #include "ppapi/host/dispatch_host_message.h"
25 #include "ppapi/host/ppapi_host.h"
26 #include "ppapi/proxy/ppapi_messages.h"
27 #include "ppapi/thunk/enter.h"
28 #include "ppapi/thunk/ppb_image_data_api.h"
29 #include "third_party/khronos/GLES2/gl2.h"
30 #include "ui/gfx/transform.h"
32 using ppapi::host::HostMessageContext;
33 using ppapi::thunk::EnterResourceNoLock;
34 using ppapi::thunk::PPB_ImageData_API;
36 namespace content {
38 namespace {
40 bool CheckPPFloatRect(const PP_FloatRect& rect, float width, float height) {
41 const float kEpsilon = std::numeric_limits<float>::epsilon();
42 return (rect.point.x >= -kEpsilon &&
43 rect.point.y >= -kEpsilon &&
44 rect.point.x + rect.size.width <= width + kEpsilon &&
45 rect.point.y + rect.size.height <= height + kEpsilon);
48 int32_t VerifyCommittedLayer(
49 const ppapi::CompositorLayerData* old_layer,
50 const ppapi::CompositorLayerData* new_layer,
51 scoped_ptr<base::SharedMemory>* image_shm) {
52 if (!new_layer->is_valid())
53 return PP_ERROR_BADARGUMENT;
55 if (new_layer->color) {
56 // Make sure the old layer is a color layer too.
57 if (old_layer && !old_layer->color)
58 return PP_ERROR_BADARGUMENT;
59 return PP_OK;
62 if (new_layer->texture) {
63 if (old_layer) {
64 // Make sure the old layer is a texture layer too.
65 if (!new_layer->texture)
66 return PP_ERROR_BADARGUMENT;
67 // The mailbox should be same, if the resource_id is not changed.
68 if (new_layer->common.resource_id == old_layer->common.resource_id) {
69 if (new_layer->texture->mailbox != old_layer->texture->mailbox)
70 return PP_ERROR_BADARGUMENT;
71 return PP_OK;
74 if (!new_layer->texture->mailbox.Verify())
75 return PP_ERROR_BADARGUMENT;
77 // Make sure the source rect is not beyond the dimensions of the
78 // texture.
79 if (!CheckPPFloatRect(new_layer->texture->source_rect, 1.0f, 1.0f))
80 return PP_ERROR_BADARGUMENT;
81 return PP_OK;
84 if (new_layer->image) {
85 if (old_layer) {
86 // Make sure the old layer is an image layer too.
87 if (!new_layer->image)
88 return PP_ERROR_BADARGUMENT;
89 // The image data resource should be same, if the resource_id is not
90 // changed.
91 if (new_layer->common.resource_id == old_layer->common.resource_id) {
92 if (new_layer->image->resource != old_layer->image->resource)
93 return PP_ERROR_BADARGUMENT;
94 return PP_OK;
98 EnterResourceNoLock<PPB_ImageData_API> enter(new_layer->image->resource,
99 true);
100 if (enter.failed())
101 return PP_ERROR_BADRESOURCE;
103 // TODO(penghuang): support all kinds of image.
104 PP_ImageDataDesc desc;
105 if (enter.object()->Describe(&desc) != PP_TRUE ||
106 desc.stride != desc.size.width * 4 ||
107 desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL) {
108 return PP_ERROR_BADARGUMENT;
111 // Make sure the source rect is not beyond the dimensions of the
112 // image.
113 if (!CheckPPFloatRect(new_layer->image->source_rect,
114 desc.size.width, desc.size.height)) {
115 return PP_ERROR_BADARGUMENT;
118 int handle;
119 uint32_t byte_count;
120 if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK)
121 return PP_ERROR_FAILED;
123 #if defined(OS_WIN)
124 base::SharedMemoryHandle shm_handle;
125 if (!::DuplicateHandle(::GetCurrentProcess(),
126 reinterpret_cast<base::SharedMemoryHandle>(handle),
127 ::GetCurrentProcess(),
128 &shm_handle,
130 FALSE,
131 DUPLICATE_SAME_ACCESS)) {
132 return PP_ERROR_FAILED;
134 #else
135 base::SharedMemoryHandle shm_handle(dup(handle), false);
136 #endif
137 image_shm->reset(new base::SharedMemory(shm_handle, true));
138 if (!(*image_shm)->Map(desc.stride * desc.size.height)) {
139 image_shm->reset();
140 return PP_ERROR_NOMEMORY;
142 return PP_OK;
145 return PP_ERROR_BADARGUMENT;
148 } // namespace
150 PepperCompositorHost::LayerData::LayerData(
151 const scoped_refptr<cc::Layer>& cc,
152 const ppapi::CompositorLayerData& pp) : cc_layer(cc), pp_layer(pp) {}
154 PepperCompositorHost::LayerData::~LayerData() {}
156 PepperCompositorHost::PepperCompositorHost(
157 RendererPpapiHost* host,
158 PP_Instance instance,
159 PP_Resource resource)
160 : ResourceHost(host->GetPpapiHost(), instance, resource),
161 bound_instance_(NULL),
162 weak_factory_(this) {
163 layer_ = cc::Layer::Create();
164 // TODO(penghuang): SetMasksToBounds() can be expensive if the layer is
165 // transformed. Possibly better could be to explicitly clip the child layers
166 // (by modifying their bounds).
167 layer_->SetMasksToBounds(true);
168 layer_->SetIsDrawable(true);
171 PepperCompositorHost::~PepperCompositorHost() {
172 // Unbind from the instance when destroyed if we're still bound.
173 if (bound_instance_)
174 bound_instance_->BindGraphics(bound_instance_->pp_instance(), 0);
177 bool PepperCompositorHost::BindToInstance(
178 PepperPluginInstanceImpl* new_instance) {
179 if (new_instance && new_instance->pp_instance() != pp_instance())
180 return false; // Can't bind other instance's contexts.
181 if (bound_instance_ == new_instance)
182 return true; // Rebinding the same device, nothing to do.
183 if (bound_instance_ && new_instance)
184 return false; // Can't change a bound device.
185 bound_instance_ = new_instance;
186 if (!bound_instance_)
187 SendCommitLayersReplyIfNecessary();
189 return true;
192 void PepperCompositorHost::ViewInitiatedPaint() {
193 SendCommitLayersReplyIfNecessary();
196 void PepperCompositorHost::ImageReleased(
197 int32_t id,
198 scoped_ptr<base::SharedMemory> shared_memory,
199 scoped_ptr<cc::SharedBitmap> bitmap,
200 uint32_t sync_point,
201 bool is_lost) {
202 bitmap.reset();
203 shared_memory.reset();
204 ResourceReleased(id, sync_point, is_lost);
207 void PepperCompositorHost::ResourceReleased(int32_t id,
208 uint32_t sync_point,
209 bool is_lost) {
210 host()->SendUnsolicitedReply(
211 pp_resource(),
212 PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost));
215 void PepperCompositorHost::SendCommitLayersReplyIfNecessary() {
216 if (!commit_layers_reply_context_.is_valid())
217 return;
218 host()->SendReply(commit_layers_reply_context_,
219 PpapiPluginMsg_Compositor_CommitLayersReply());
220 commit_layers_reply_context_ = ppapi::host::ReplyMessageContext();
223 void PepperCompositorHost::UpdateLayer(
224 const scoped_refptr<cc::Layer>& layer,
225 const ppapi::CompositorLayerData* old_layer,
226 const ppapi::CompositorLayerData* new_layer,
227 scoped_ptr<base::SharedMemory> image_shm) {
228 // Always update properties on cc::Layer, because cc::Layer
229 // will ignore any setting with unchanged value.
230 layer->SetIsDrawable(true);
231 layer->SetBlendMode(SkXfermode::kSrcOver_Mode);
232 layer->SetOpacity(new_layer->common.opacity);
233 layer->SetBounds(PP_ToGfxSize(new_layer->common.size));
234 layer->SetTransformOrigin(gfx::Point3F(new_layer->common.size.width / 2,
235 new_layer->common.size.height / 2,
236 0.0f));
238 gfx::Transform transform(gfx::Transform::kSkipInitialization);
239 transform.matrix().setColMajorf(new_layer->common.transform.matrix);
240 layer->SetTransform(transform);
242 // Consider a (0,0,0,0) rect as no clip rect.
243 if (new_layer->common.clip_rect.point.x != 0 ||
244 new_layer->common.clip_rect.point.y != 0 ||
245 new_layer->common.clip_rect.size.width != 0 ||
246 new_layer->common.clip_rect.size.height != 0) {
247 scoped_refptr<cc::Layer> clip_parent = layer->parent();
248 if (clip_parent.get() == layer_.get()) {
249 // Create a clip parent layer, if it does not exist.
250 clip_parent = cc::Layer::Create();
251 clip_parent->SetMasksToBounds(true);
252 clip_parent->SetIsDrawable(true);
253 layer_->ReplaceChild(layer.get(), clip_parent);
254 clip_parent->AddChild(layer);
256 gfx::Point position = PP_ToGfxPoint(new_layer->common.clip_rect.point);
257 clip_parent->SetPosition(position);
258 clip_parent->SetBounds(PP_ToGfxSize(new_layer->common.clip_rect.size));
259 layer->SetPosition(gfx::Point(-position.x(), -position.y()));
260 } else if (layer->parent() != layer_.get()) {
261 // Remove the clip parent layer.
262 layer_->ReplaceChild(layer->parent(), layer);
263 layer->SetPosition(gfx::Point());
266 if (new_layer->color) {
267 layer->SetBackgroundColor(SkColorSetARGBMacro(
268 new_layer->color->alpha * 255,
269 new_layer->color->red * 255,
270 new_layer->color->green * 255,
271 new_layer->color->blue * 255));
272 return;
275 if (new_layer->texture) {
276 scoped_refptr<cc::TextureLayer> texture_layer(
277 static_cast<cc::TextureLayer*>(layer.get()));
278 if (!old_layer ||
279 new_layer->common.resource_id != old_layer->common.resource_id) {
280 cc::TextureMailbox mailbox(new_layer->texture->mailbox,
281 new_layer->texture->target,
282 new_layer->texture->sync_point);
283 texture_layer->SetTextureMailbox(mailbox,
284 cc::SingleReleaseCallback::Create(
285 base::Bind(&PepperCompositorHost::ResourceReleased,
286 weak_factory_.GetWeakPtr(),
287 new_layer->common.resource_id)));
288 // TODO(penghuang): get a damage region from the application and
289 // pass it to SetNeedsDisplayRect().
290 texture_layer->SetNeedsDisplay();
292 texture_layer->SetPremultipliedAlpha(new_layer->texture->premult_alpha);
293 gfx::RectF rect = PP_ToGfxRectF(new_layer->texture->source_rect);
294 texture_layer->SetUV(rect.origin(), rect.bottom_right());
295 return;
298 if (new_layer->image) {
299 if (!old_layer ||
300 new_layer->common.resource_id != old_layer->common.resource_id) {
301 scoped_refptr<cc::TextureLayer> image_layer(
302 static_cast<cc::TextureLayer*>(layer.get()));
303 EnterResourceNoLock<PPB_ImageData_API> enter(new_layer->image->resource,
304 true);
305 DCHECK(enter.succeeded());
307 // TODO(penghuang): support all kinds of image.
308 PP_ImageDataDesc desc;
309 PP_Bool rv = enter.object()->Describe(&desc);
310 DCHECK_EQ(rv, PP_TRUE);
311 DCHECK_EQ(desc.stride, desc.size.width * 4);
312 DCHECK_EQ(desc.format, PP_IMAGEDATAFORMAT_RGBA_PREMUL);
313 scoped_ptr<cc::SharedBitmap> bitmap =
314 ChildThreadImpl::current()
315 ->shared_bitmap_manager()
316 ->GetBitmapForSharedMemory(image_shm.get());
318 cc::TextureMailbox mailbox(bitmap.get(), PP_ToGfxSize(desc.size));
319 image_layer->SetTextureMailbox(
320 mailbox,
321 cc::SingleReleaseCallback::Create(base::Bind(
322 &PepperCompositorHost::ImageReleased, weak_factory_.GetWeakPtr(),
323 new_layer->common.resource_id, base::Passed(&image_shm),
324 base::Passed(&bitmap))));
325 // TODO(penghuang): get a damage region from the application and
326 // pass it to SetNeedsDisplayRect().
327 image_layer->SetNeedsDisplay();
329 // ImageData is always premultiplied alpha.
330 image_layer->SetPremultipliedAlpha(true);
332 return;
334 // Should not be reached.
335 NOTREACHED();
338 int32_t PepperCompositorHost::OnResourceMessageReceived(
339 const IPC::Message& msg,
340 HostMessageContext* context) {
341 PPAPI_BEGIN_MESSAGE_MAP(PepperCompositorHost, msg)
342 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
343 PpapiHostMsg_Compositor_CommitLayers, OnHostMsgCommitLayers)
344 PPAPI_END_MESSAGE_MAP()
345 return ppapi::host::ResourceHost::OnResourceMessageReceived(msg, context);
348 bool PepperCompositorHost::IsCompositorHost() {
349 return true;
352 int32_t PepperCompositorHost::OnHostMsgCommitLayers(
353 HostMessageContext* context,
354 const std::vector<ppapi::CompositorLayerData>& layers,
355 bool reset) {
356 if (commit_layers_reply_context_.is_valid())
357 return PP_ERROR_INPROGRESS;
359 scoped_ptr<scoped_ptr<base::SharedMemory>[]> image_shms;
360 if (layers.size() > 0) {
361 image_shms.reset(new scoped_ptr<base::SharedMemory>[layers.size()]);
362 if (!image_shms)
363 return PP_ERROR_NOMEMORY;
364 // Verfiy the layers first, if an error happens, we will return the error to
365 // plugin and keep current layers set by the previous CommitLayers()
366 // unchanged.
367 for (size_t i = 0; i < layers.size(); ++i) {
368 const ppapi::CompositorLayerData* old_layer = NULL;
369 if (!reset && i < layers_.size())
370 old_layer = &layers_[i].pp_layer;
371 int32_t rv = VerifyCommittedLayer(old_layer, &layers[i], &image_shms[i]);
372 if (rv != PP_OK)
373 return rv;
377 // ResetLayers() has been called, we need rebuild layer stack.
378 if (reset) {
379 layer_->RemoveAllChildren();
380 layers_.clear();
383 for (size_t i = 0; i < layers.size(); ++i) {
384 const ppapi::CompositorLayerData* pp_layer = &layers[i];
385 LayerData* data = i >= layers_.size() ? NULL : &layers_[i];
386 DCHECK(!data || data->cc_layer.get());
387 scoped_refptr<cc::Layer> cc_layer = data ? data->cc_layer : NULL;
388 ppapi::CompositorLayerData* old_layer = data ? &data->pp_layer : NULL;
390 if (!cc_layer.get()) {
391 if (pp_layer->color)
392 cc_layer = cc::SolidColorLayer::Create();
393 else if (pp_layer->texture || pp_layer->image)
394 cc_layer = cc::TextureLayer::CreateForMailbox(NULL);
395 layer_->AddChild(cc_layer);
398 UpdateLayer(cc_layer, old_layer, pp_layer, image_shms[i].Pass());
400 if (old_layer)
401 *old_layer = *pp_layer;
402 else
403 layers_.push_back(LayerData(cc_layer, *pp_layer));
406 // We need to force a commit for each CommitLayers() call, even if no layers
407 // changed since the last call to CommitLayers(). This is so
408 // WiewInitiatedPaint() will always be called.
409 if (layer_->layer_tree_host())
410 layer_->layer_tree_host()->SetNeedsCommit();
412 // If the host is not bound to the instance, return PP_OK immediately.
413 if (!bound_instance_)
414 return PP_OK;
416 commit_layers_reply_context_ = context->MakeReplyMessageContext();
417 return PP_OK_COMPLETIONPENDING;
420 } // namespace content