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/solid_color_layer.h" | |
10 #include "cc/layers/texture_layer.h" | |
11 #include "cc/resources/texture_mailbox.h" | |
12 #include "content/public/renderer/renderer_ppapi_host.h" | |
13 #include "content/renderer/pepper/gfx_conversion.h" | |
14 #include "content/renderer/pepper/host_globals.h" | |
15 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" | |
16 #include "content/renderer/pepper/ppb_image_data_impl.h" | |
17 #include "ppapi/c/pp_errors.h" | |
18 #include "ppapi/host/dispatch_host_message.h" | |
19 #include "ppapi/host/ppapi_host.h" | |
20 #include "ppapi/proxy/ppapi_messages.h" | |
21 #include "ppapi/thunk/enter.h" | |
22 #include "ppapi/thunk/ppb_image_data_api.h" | |
23 #include "third_party/khronos/GLES2/gl2.h" | |
24 #include "ui/gfx/transform.h" | |
25 | |
26 using ppapi::host::HostMessageContext; | |
27 using ppapi::thunk::EnterResourceNoLock; | |
28 using ppapi::thunk::PPB_ImageData_API; | |
29 | |
30 namespace content { | |
31 | |
32 PepperCompositorHost::PepperCompositorHost( | |
33 RendererPpapiHost* host, | |
34 PP_Instance instance, | |
35 PP_Resource resource) | |
36 : ResourceHost(host->GetPpapiHost(), instance, resource), | |
37 bound_instance_(NULL), | |
38 weak_factory_(this) { | |
39 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.
| |
40 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.
| |
41 layer_->SetIsDrawable(true); | |
42 } | |
43 | |
44 PepperCompositorHost::~PepperCompositorHost() { | |
45 // Unbind from the instance when destroyed if we're still bound. | |
46 if (bound_instance_) | |
47 bound_instance_->BindGraphics(bound_instance_->pp_instance(), 0); | |
48 } | |
49 | |
50 bool PepperCompositorHost::BindToInstance( | |
51 PepperPluginInstanceImpl* new_instance) { | |
52 if (new_instance && new_instance->pp_instance() != pp_instance()) | |
53 return false; // Can't bind other instance's contexts. | |
54 if (bound_instance_ == new_instance) | |
55 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.
| |
56 if (bound_instance_ && new_instance) | |
57 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.
| |
58 bound_instance_ = new_instance; | |
59 return true; | |
60 } | |
61 | |
62 void PepperCompositorHost::ViewInitiatedPaint() { | |
63 if (!commit_layers_reply_context_.is_valid()) | |
64 return; | |
65 host()->SendReply(commit_layers_reply_context_, | |
66 PpapiPluginMsg_Compositor_CommitLayersReply()); | |
67 commit_layers_reply_context_ = ppapi::host::ReplyMessageContext(); | |
68 } | |
69 | |
70 void PepperCompositorHost::ViewFlushedPaint() {} | |
71 | |
72 void PepperCompositorHost::ResourceReleased(int32_t id, | |
73 uint32_t sync_point, | |
74 bool is_lost) { | |
75 host()->SendUnsolicitedReply( | |
76 pp_resource(), | |
77 PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost)); | |
78 } | |
79 | |
80 void PepperCompositorHost::ImageReleased( | |
81 int32_t id, | |
82 const scoped_ptr<base::SharedMemory>& shared_memory, | |
83 uint32_t sync_point, | |
84 bool is_lost) { | |
85 ResourceReleased(id, sync_point, is_lost); | |
86 } | |
87 | |
88 int32_t PepperCompositorHost::OnResourceMessageReceived( | |
89 const IPC::Message& msg, | |
90 HostMessageContext* context) { | |
91 PPAPI_BEGIN_MESSAGE_MAP(PepperCompositorHost, msg) | |
92 PPAPI_DISPATCH_HOST_RESOURCE_CALL( | |
93 PpapiHostMsg_Compositor_CommitLayers, OnHostMsgCommitLayers) | |
94 PPAPI_END_MESSAGE_MAP() | |
95 return ppapi::host::ResourceHost::OnResourceMessageReceived(msg, context); | |
96 } | |
97 | |
98 bool PepperCompositorHost::IsCompositorHost() { | |
99 return true; | |
100 } | |
101 | |
102 void PepperCompositorHost::UpdateLayer( | |
103 const scoped_refptr<cc::Layer>& layer, | |
104 const ppapi::CompositorLayerData* old_layer, | |
105 const ppapi::CompositorLayerData* new_layer) { | |
106 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.
| |
107 | |
108 // Always update properties on cc::Layer, because cc::Layer | |
109 // will ignore any setting with unchanged value. | |
110 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.
| |
111 layer->SetBlendMode(SkXfermode::kSrcOver_Mode); | |
112 layer->SetOpacity(new_layer->opacity / 255.0f); | |
113 | |
114 gfx::Transform transform(gfx::Transform::kSkipInitialization); | |
115 transform.matrix().setColMajorf(new_layer->transform); | |
116 layer->SetTransform(transform); | |
117 | |
118 // Consider a (0,0,0,0) rect as no clip rect. | |
119 if (new_layer->clip_rect.point.x != 0 || | |
120 new_layer->clip_rect.point.y != 0 || | |
121 new_layer->clip_rect.size.width != 0 || | |
122 new_layer->clip_rect.size.height != 0) { | |
123 if (!layer->mask_layer()) | |
124 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.
| |
125 layer->mask_layer()->SetPosition(PP_ToGfxPoint(new_layer->clip_rect.point)); | |
126 layer->mask_layer()->SetBounds(PP_ToGfxSize(new_layer->clip_rect.size)); | |
127 } else { | |
128 layer->SetMaskLayer(NULL); | |
129 } | |
130 | |
131 if (new_layer->type == ppapi::CompositorLayerData::TYPE_COLOR) { | |
132 layer->SetBackgroundColor(SkColorSetARGBMacro(new_layer->color.alpha, | |
133 new_layer->color.red, | |
134 new_layer->color.green, | |
135 new_layer->color.blue)); | |
136 } else if (new_layer->type == ppapi::CompositorLayerData::TYPE_TEXTURE) { | |
137 scoped_refptr<cc::TextureLayer> texture_layer( | |
138 static_cast<cc::TextureLayer*>(layer.get())); | |
139 if (!old_layer || new_layer->resource_id != old_layer->resource_id) { | |
140 gpu::Mailbox gpu_mailbox; | |
141 gpu_mailbox.SetName(new_layer->texture.mailbox); | |
142 cc::TextureMailbox mailbox(gpu_mailbox, | |
143 GL_TEXTURE_2D, | |
144 new_layer->texture.sync_point); | |
145 texture_layer->SetTextureMailbox(mailbox, | |
146 cc::SingleReleaseCallback::Create( | |
147 base::Bind(&PepperCompositorHost::ResourceReleased, | |
148 weak_factory_.GetWeakPtr(), | |
149 new_layer->resource_id)));; | |
150 } | |
151 texture_layer->SetPremultipliedAlpha(new_layer->texture.premult_alpha); | |
152 gfx::RectF rect = PP_ToGfxRectF(new_layer->texture.source_rect); | |
153 texture_layer->SetUV(rect.origin(), rect.bottom_right()); | |
154 } else if (new_layer->type == ppapi::CompositorLayerData::TYPE_IMAGE) { | |
155 if (!old_layer || new_layer->resource_id != old_layer->resource_id) { | |
156 scoped_refptr<cc::TextureLayer> image_layer( | |
157 static_cast<cc::TextureLayer*>(layer.get())); | |
158 EnterResourceNoLock<PPB_ImageData_API> enter( | |
159 new_layer->image.host_resource, true); | |
160 PP_ImageDataDesc desc; | |
161 enter.object()->Describe(&desc); | |
162 int handle; | |
163 uint32_t byte_count; | |
164 enter.object()->GetSharedMemory(&handle, &byte_count); | |
165 #if defined(OS_WIN) | |
166 base::SharedMemoryHandle shm_handle = | |
167 static_cast<base::SharedMemoryHandle>(_dup(handle)); | |
168 #else | |
169 base::SharedMemoryHandle shm_handle(dup(handle), false); | |
170 #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
| |
171 // Use a scoped_ptr to keep shared_memory alive until | |
172 // PepperCompositorHost::ImageReleased is called. | |
173 scoped_ptr<base::SharedMemory> shared_memory( | |
174 new base::SharedMemory(shm_handle, true)); | |
175 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
| |
176 cc::TextureMailbox mailbox(shared_memory.get(), | |
177 PP_ToGfxSize(desc.size)); | |
178 image_layer->SetTextureMailbox(mailbox, | |
179 cc::SingleReleaseCallback::Create( | |
180 base::Bind(&PepperCompositorHost::ImageReleased, | |
181 weak_factory_.GetWeakPtr(), | |
182 new_layer->resource_id, | |
183 base::Passed(&shared_memory)))); | |
184 | |
185 // ImageData is always premultiplied alpha. | |
186 image_layer->SetPremultipliedAlpha(true); | |
187 } | |
188 } | |
189 } | |
190 | |
191 int32_t PepperCompositorHost::OnHostMsgCommitLayers( | |
192 HostMessageContext* context, | |
193 const std::vector<ppapi::CompositorLayerData>& layers, | |
194 bool reset) { | |
195 // Do not support CommitLayers() on an unbounded compositor. | |
196 if (!bound_instance_) | |
197 return PP_ERROR_FAILED; | |
198 | |
199 if (commit_layers_reply_context_.is_valid()) { | |
200 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
| |
201 return PP_ERROR_INPROGRESS; | |
202 } | |
203 | |
204 commit_layers_reply_context_ = context->MakeReplyMessageContext(); | |
205 | |
206 // 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.
| |
207 // 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.
| |
208 for (size_t i = 0; i < layers.size(); ++i) { | |
209 const ppapi::CompositorLayerData& pp_layer = layers[i]; | |
210 // Make sure the layer type is not changed. | |
211 if (!reset) { | |
212 ppapi::CompositorLayerData* old_layer = | |
213 i >= pp_layers_.size() ? NULL : &pp_layers_[i]; | |
214 if (old_layer && old_layer->type != pp_layer.type) { | |
215 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
| |
216 return PP_ERROR_BADARGUMENT; | |
217 } | |
218 } | |
219 | |
220 if (pp_layer.type == ppapi::CompositorLayerData::TYPE_COLOR || | |
221 pp_layer.type == ppapi::CompositorLayerData::TYPE_TEXTURE) { | |
222 continue; | |
223 } | |
224 | |
225 // Check image layer. | |
226 if (pp_layer.type == ppapi::CompositorLayerData::TYPE_IMAGE) { | |
227 EnterResourceNoLock<PPB_ImageData_API> enter( | |
228 pp_layer.image.host_resource, true); | |
229 if (enter.failed()) { | |
230 NOTREACHED(); | |
piman
2014/06/04 13:19:42
same here
Peng
2014/06/10 16:20:28
Done.
| |
231 return PP_ERROR_BADRESOURCE; | |
232 } | |
233 | |
234 // TODO(penghuang): support all kinds of image. | |
235 PP_ImageDataDesc desc; | |
236 if (!enter.object()->Describe(&desc) || | |
237 desc.stride != desc.size.width * 4 || | |
238 desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL) { | |
239 NOTREACHED(); | |
piman
2014/06/04 13:19:43
same here
Peng
2014/06/10 16:20:28
Done.
| |
240 return PP_ERROR_BADARGUMENT; | |
241 } | |
242 | |
243 int handle; | |
244 uint32_t byte_count; | |
245 if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK) | |
246 return PP_ERROR_FAILED; | |
247 continue; | |
248 } | |
249 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.
| |
250 } | |
251 | |
252 // ResetLayers() has been called, we need rebuild layer stack. | |
253 if (reset) { | |
254 layer_->RemoveAllChildren(); | |
255 cc_layers_.clear(); | |
256 pp_layers_.clear(); | |
257 } | |
258 | |
259 for (size_t i = 0; i < layers.size(); ++i) { | |
260 const ppapi::CompositorLayerData& pp_layer = layers[i]; | |
261 ppapi::CompositorLayerData* old_layer = | |
262 i >= pp_layers_.size() ? NULL : &pp_layers_[i]; | |
263 scoped_refptr<cc::Layer> cc_layer = | |
264 i >= cc_layers_.size() ? NULL : cc_layers_[i]; | |
265 | |
266 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
| |
267 | |
268 if (!cc_layer) { | |
269 if (pp_layer.type == ppapi::CompositorLayerData::TYPE_COLOR) { | |
270 cc_layer = cc::SolidColorLayer::Create(); | |
271 } else if (pp_layer.type == ppapi::CompositorLayerData::TYPE_TEXTURE || | |
272 pp_layer.type == ppapi::CompositorLayerData::TYPE_IMAGE) { | |
273 cc_layer = cc::TextureLayer::CreateForMailbox(NULL); | |
274 } | |
275 cc_layer->SetIsDrawable(true); | |
276 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.
| |
277 } | |
278 | |
279 UpdateLayer(cc_layer, old_layer, &pp_layer); | |
280 | |
281 if (old_layer) { | |
282 *old_layer = pp_layer; | |
283 } else { | |
284 layer_->AddChild(cc_layer); | |
285 cc_layers_.push_back(cc_layer); | |
286 pp_layers_.push_back(pp_layer); | |
287 } | |
288 } | |
289 | |
290 return PP_OK_COMPLETIONPENDING; | |
291 } | |
292 | |
293 } // namespace content | |
OLD | NEW |