[ServiceWorker] Implement WebServiceWorkerContextClient::openWindow().
[chromium-blink-merge.git] / content / renderer / pepper / pepper_compositor_host.cc
blobeec292af60622cbda3b35fefaca8908ff26babd7
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/child/child_shared_bitmap_manager.h"
15 #include "content/child/child_thread_impl.h"
16 #include "content/public/renderer/renderer_ppapi_host.h"
17 #include "content/renderer/pepper/gfx_conversion.h"
18 #include "content/renderer/pepper/host_globals.h"
19 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
20 #include "content/renderer/pepper/ppb_image_data_impl.h"
21 #include "ppapi/c/pp_errors.h"
22 #include "ppapi/host/dispatch_host_message.h"
23 #include "ppapi/host/ppapi_host.h"
24 #include "ppapi/proxy/ppapi_messages.h"
25 #include "ppapi/thunk/enter.h"
26 #include "ppapi/thunk/ppb_image_data_api.h"
27 #include "third_party/khronos/GLES2/gl2.h"
28 #include "ui/gfx/transform.h"
30 using ppapi::host::HostMessageContext;
31 using ppapi::thunk::EnterResourceNoLock;
32 using ppapi::thunk::PPB_ImageData_API;
34 namespace content {
36 namespace {
38 int32_t VerifyCommittedLayer(
39 const ppapi::CompositorLayerData* old_layer,
40 const ppapi::CompositorLayerData* new_layer,
41 scoped_ptr<base::SharedMemory>* image_shm) {
42 if (!new_layer->is_valid())
43 return PP_ERROR_BADARGUMENT;
45 if (new_layer->color) {
46 // Make sure the old layer is a color layer too.
47 if (old_layer && !old_layer->color)
48 return PP_ERROR_BADARGUMENT;
49 return PP_OK;
52 if (new_layer->texture) {
53 if (old_layer) {
54 // Make sure the old layer is a texture layer too.
55 if (!new_layer->texture)
56 return PP_ERROR_BADARGUMENT;
57 // The mailbox should be same, if the resource_id is not changed.
58 if (new_layer->common.resource_id == old_layer->common.resource_id) {
59 if (new_layer->texture->mailbox != old_layer->texture->mailbox)
60 return PP_ERROR_BADARGUMENT;
61 return PP_OK;
64 if (!new_layer->texture->mailbox.Verify())
65 return PP_ERROR_BADARGUMENT;
66 return PP_OK;
69 if (new_layer->image) {
70 if (old_layer) {
71 // Make sure the old layer is an image layer too.
72 if (!new_layer->image)
73 return PP_ERROR_BADARGUMENT;
74 // The image data resource should be same, if the resource_id is not
75 // changed.
76 if (new_layer->common.resource_id == old_layer->common.resource_id) {
77 if (new_layer->image->resource != old_layer->image->resource)
78 return PP_ERROR_BADARGUMENT;
79 return PP_OK;
82 EnterResourceNoLock<PPB_ImageData_API> enter(new_layer->image->resource,
83 true);
84 if (enter.failed())
85 return PP_ERROR_BADRESOURCE;
87 // TODO(penghuang): support all kinds of image.
88 PP_ImageDataDesc desc;
89 if (enter.object()->Describe(&desc) != PP_TRUE ||
90 desc.stride != desc.size.width * 4 ||
91 desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL) {
92 return PP_ERROR_BADARGUMENT;
95 int handle;
96 uint32_t byte_count;
97 if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK)
98 return PP_ERROR_FAILED;
100 #if defined(OS_WIN)
101 base::SharedMemoryHandle shm_handle;
102 if (!::DuplicateHandle(::GetCurrentProcess(),
103 reinterpret_cast<base::SharedMemoryHandle>(handle),
104 ::GetCurrentProcess(),
105 &shm_handle,
107 FALSE,
108 DUPLICATE_SAME_ACCESS)) {
109 return PP_ERROR_FAILED;
111 #else
112 base::SharedMemoryHandle shm_handle(dup(handle), false);
113 #endif
114 image_shm->reset(new base::SharedMemory(shm_handle, true));
115 if (!(*image_shm)->Map(desc.stride * desc.size.height)) {
116 image_shm->reset();
117 return PP_ERROR_NOMEMORY;
119 return PP_OK;
122 return PP_ERROR_BADARGUMENT;
125 } // namespace
127 PepperCompositorHost::LayerData::LayerData(
128 const scoped_refptr<cc::Layer>& cc,
129 const ppapi::CompositorLayerData& pp) : cc_layer(cc), pp_layer(pp) {}
131 PepperCompositorHost::LayerData::~LayerData() {}
133 PepperCompositorHost::PepperCompositorHost(
134 RendererPpapiHost* host,
135 PP_Instance instance,
136 PP_Resource resource)
137 : ResourceHost(host->GetPpapiHost(), instance, resource),
138 bound_instance_(NULL),
139 weak_factory_(this) {
140 layer_ = cc::Layer::Create();
141 // TODO(penghuang): SetMasksToBounds() can be expensive if the layer is
142 // transformed. Possibly better could be to explicitly clip the child layers
143 // (by modifying their bounds).
144 layer_->SetMasksToBounds(true);
145 layer_->SetIsDrawable(true);
148 PepperCompositorHost::~PepperCompositorHost() {
149 // Unbind from the instance when destroyed if we're still bound.
150 if (bound_instance_)
151 bound_instance_->BindGraphics(bound_instance_->pp_instance(), 0);
154 bool PepperCompositorHost::BindToInstance(
155 PepperPluginInstanceImpl* new_instance) {
156 if (new_instance && new_instance->pp_instance() != pp_instance())
157 return false; // Can't bind other instance's contexts.
158 if (bound_instance_ == new_instance)
159 return true; // Rebinding the same device, nothing to do.
160 if (bound_instance_ && new_instance)
161 return false; // Can't change a bound device.
162 bound_instance_ = new_instance;
163 if (!bound_instance_)
164 SendCommitLayersReplyIfNecessary();
166 return true;
169 void PepperCompositorHost::ViewInitiatedPaint() {
170 SendCommitLayersReplyIfNecessary();
173 void PepperCompositorHost::ImageReleased(
174 int32_t id,
175 scoped_ptr<base::SharedMemory> shared_memory,
176 scoped_ptr<cc::SharedBitmap> bitmap,
177 uint32_t sync_point,
178 bool is_lost) {
179 bitmap.reset();
180 shared_memory.reset();
181 ResourceReleased(id, sync_point, is_lost);
184 void PepperCompositorHost::ResourceReleased(int32_t id,
185 uint32_t sync_point,
186 bool is_lost) {
187 host()->SendUnsolicitedReply(
188 pp_resource(),
189 PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost));
192 void PepperCompositorHost::SendCommitLayersReplyIfNecessary() {
193 if (!commit_layers_reply_context_.is_valid())
194 return;
195 host()->SendReply(commit_layers_reply_context_,
196 PpapiPluginMsg_Compositor_CommitLayersReply());
197 commit_layers_reply_context_ = ppapi::host::ReplyMessageContext();
200 void PepperCompositorHost::UpdateLayer(
201 const scoped_refptr<cc::Layer>& layer,
202 const ppapi::CompositorLayerData* old_layer,
203 const ppapi::CompositorLayerData* new_layer,
204 scoped_ptr<base::SharedMemory> image_shm) {
205 // Always update properties on cc::Layer, because cc::Layer
206 // will ignore any setting with unchanged value.
207 layer->SetIsDrawable(true);
208 layer->SetBlendMode(SkXfermode::kSrcOver_Mode);
209 layer->SetOpacity(new_layer->common.opacity);
210 layer->SetBounds(PP_ToGfxSize(new_layer->common.size));
211 layer->SetTransformOrigin(gfx::Point3F(new_layer->common.size.width / 2,
212 new_layer->common.size.height / 2,
213 0.0f));
215 gfx::Transform transform(gfx::Transform::kSkipInitialization);
216 transform.matrix().setColMajorf(new_layer->common.transform.matrix);
217 layer->SetTransform(transform);
219 // Consider a (0,0,0,0) rect as no clip rect.
220 if (new_layer->common.clip_rect.point.x != 0 ||
221 new_layer->common.clip_rect.point.y != 0 ||
222 new_layer->common.clip_rect.size.width != 0 ||
223 new_layer->common.clip_rect.size.height != 0) {
224 scoped_refptr<cc::Layer> clip_parent = layer->parent();
225 if (clip_parent.get() == layer_.get()) {
226 // Create a clip parent layer, if it does not exist.
227 clip_parent = cc::Layer::Create();
228 clip_parent->SetMasksToBounds(true);
229 clip_parent->SetIsDrawable(true);
230 layer_->ReplaceChild(layer.get(), clip_parent);
231 clip_parent->AddChild(layer);
233 gfx::Point position = PP_ToGfxPoint(new_layer->common.clip_rect.point);
234 clip_parent->SetPosition(position);
235 clip_parent->SetBounds(PP_ToGfxSize(new_layer->common.clip_rect.size));
236 layer->SetPosition(gfx::Point(-position.x(), -position.y()));
237 } else if (layer->parent() != layer_.get()) {
238 // Remove the clip parent layer.
239 layer_->ReplaceChild(layer->parent(), layer);
240 layer->SetPosition(gfx::Point());
243 if (new_layer->color) {
244 layer->SetBackgroundColor(SkColorSetARGBMacro(
245 new_layer->color->alpha * 255,
246 new_layer->color->red * 255,
247 new_layer->color->green * 255,
248 new_layer->color->blue * 255));
249 return;
252 if (new_layer->texture) {
253 scoped_refptr<cc::TextureLayer> texture_layer(
254 static_cast<cc::TextureLayer*>(layer.get()));
255 if (!old_layer ||
256 new_layer->common.resource_id != old_layer->common.resource_id) {
257 cc::TextureMailbox mailbox(new_layer->texture->mailbox,
258 new_layer->texture->target,
259 new_layer->texture->sync_point);
260 texture_layer->SetTextureMailbox(mailbox,
261 cc::SingleReleaseCallback::Create(
262 base::Bind(&PepperCompositorHost::ResourceReleased,
263 weak_factory_.GetWeakPtr(),
264 new_layer->common.resource_id)));
265 // TODO(penghuang): get a damage region from the application and
266 // pass it to SetNeedsDisplayRect().
267 texture_layer->SetNeedsDisplay();
269 texture_layer->SetPremultipliedAlpha(new_layer->texture->premult_alpha);
270 gfx::RectF rect = PP_ToGfxRectF(new_layer->texture->source_rect);
271 texture_layer->SetUV(rect.origin(), rect.bottom_right());
272 return;
275 if (new_layer->image) {
276 if (!old_layer ||
277 new_layer->common.resource_id != old_layer->common.resource_id) {
278 scoped_refptr<cc::TextureLayer> image_layer(
279 static_cast<cc::TextureLayer*>(layer.get()));
280 EnterResourceNoLock<PPB_ImageData_API> enter(new_layer->image->resource,
281 true);
282 DCHECK(enter.succeeded());
284 // TODO(penghuang): support all kinds of image.
285 PP_ImageDataDesc desc;
286 PP_Bool rv = enter.object()->Describe(&desc);
287 DCHECK_EQ(rv, PP_TRUE);
288 DCHECK_EQ(desc.stride, desc.size.width * 4);
289 DCHECK_EQ(desc.format, PP_IMAGEDATAFORMAT_RGBA_PREMUL);
290 scoped_ptr<cc::SharedBitmap> bitmap =
291 ChildThreadImpl::current()
292 ->shared_bitmap_manager()
293 ->GetBitmapForSharedMemory(image_shm.get());
295 cc::TextureMailbox mailbox(bitmap.get(), PP_ToGfxSize(desc.size));
296 image_layer->SetTextureMailbox(
297 mailbox,
298 cc::SingleReleaseCallback::Create(base::Bind(
299 &PepperCompositorHost::ImageReleased, weak_factory_.GetWeakPtr(),
300 new_layer->common.resource_id, base::Passed(&image_shm),
301 base::Passed(&bitmap))));
302 // TODO(penghuang): get a damage region from the application and
303 // pass it to SetNeedsDisplayRect().
304 image_layer->SetNeedsDisplay();
306 // ImageData is always premultiplied alpha.
307 image_layer->SetPremultipliedAlpha(true);
309 return;
311 // Should not be reached.
312 NOTREACHED();
315 int32_t PepperCompositorHost::OnResourceMessageReceived(
316 const IPC::Message& msg,
317 HostMessageContext* context) {
318 PPAPI_BEGIN_MESSAGE_MAP(PepperCompositorHost, msg)
319 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
320 PpapiHostMsg_Compositor_CommitLayers, OnHostMsgCommitLayers)
321 PPAPI_END_MESSAGE_MAP()
322 return ppapi::host::ResourceHost::OnResourceMessageReceived(msg, context);
325 bool PepperCompositorHost::IsCompositorHost() {
326 return true;
329 int32_t PepperCompositorHost::OnHostMsgCommitLayers(
330 HostMessageContext* context,
331 const std::vector<ppapi::CompositorLayerData>& layers,
332 bool reset) {
333 if (commit_layers_reply_context_.is_valid())
334 return PP_ERROR_INPROGRESS;
336 scoped_ptr<scoped_ptr<base::SharedMemory>[]> image_shms;
337 if (layers.size() > 0) {
338 image_shms.reset(new scoped_ptr<base::SharedMemory>[layers.size()]);
339 if (!image_shms)
340 return PP_ERROR_NOMEMORY;
341 // Verfiy the layers first, if an error happens, we will return the error to
342 // plugin and keep current layers set by the previous CommitLayers()
343 // unchanged.
344 for (size_t i = 0; i < layers.size(); ++i) {
345 const ppapi::CompositorLayerData* old_layer = NULL;
346 if (!reset && i < layers_.size())
347 old_layer = &layers_[i].pp_layer;
348 int32_t rv = VerifyCommittedLayer(old_layer, &layers[i], &image_shms[i]);
349 if (rv != PP_OK)
350 return rv;
354 // ResetLayers() has been called, we need rebuild layer stack.
355 if (reset) {
356 layer_->RemoveAllChildren();
357 layers_.clear();
360 for (size_t i = 0; i < layers.size(); ++i) {
361 const ppapi::CompositorLayerData* pp_layer = &layers[i];
362 LayerData* data = i >= layers_.size() ? NULL : &layers_[i];
363 DCHECK(!data || data->cc_layer.get());
364 scoped_refptr<cc::Layer> cc_layer = data ? data->cc_layer : NULL;
365 ppapi::CompositorLayerData* old_layer = data ? &data->pp_layer : NULL;
367 if (!cc_layer.get()) {
368 if (pp_layer->color)
369 cc_layer = cc::SolidColorLayer::Create();
370 else if (pp_layer->texture || pp_layer->image)
371 cc_layer = cc::TextureLayer::CreateForMailbox(NULL);
372 layer_->AddChild(cc_layer);
375 UpdateLayer(cc_layer, old_layer, pp_layer, image_shms[i].Pass());
377 if (old_layer)
378 *old_layer = *pp_layer;
379 else
380 layers_.push_back(LayerData(cc_layer, *pp_layer));
383 // We need to force a commit for each CommitLayers() call, even if no layers
384 // changed since the last call to CommitLayers(). This is so
385 // WiewInitiatedPaint() will always be called.
386 if (layer_->layer_tree_host())
387 layer_->layer_tree_host()->SetNeedsCommit();
389 // If the host is not bound to the instance, return PP_OK immediately.
390 if (!bound_instance_)
391 return PP_OK;
393 commit_layers_reply_context_ = context->MakeReplyMessageContext();
394 return PP_OK_COMPLETIONPENDING;
397 } // namespace content