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