Chromium Code Reviews| 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 static_cast<base::SharedMemoryHandle>(_dup(handle)); | |
|
piman
2014/06/10 22:37:06
I don't think you can use _dup to duplicate win32
Peng
2014/06/10 23:03:32
Done.
| |
| 100 #else | |
| 101 base::SharedMemoryHandle shm_handle(dup(handle), false); | |
| 102 #endif | |
| 103 image_shm->reset(new base::SharedMemory(shm_handle, true)); | |
| 104 if (!(*image_shm)->Map(desc.stride * desc.size.height)) { | |
| 105 image_shm->reset(); | |
| 106 return PP_ERROR_NOMEMORY; | |
| 107 } | |
| 108 return PP_OK; | |
| 109 } | |
| 110 | |
| 111 return PP_ERROR_BADARGUMENT; | |
| 112 } | |
| 113 | |
| 114 } // namespace | |
| 115 | |
| 116 PepperCompositorHost::PepperCompositorHost( | |
| 117 RendererPpapiHost* host, | |
| 118 PP_Instance instance, | |
| 119 PP_Resource resource) | |
| 120 : ResourceHost(host->GetPpapiHost(), instance, resource), | |
| 121 bound_instance_(NULL), | |
| 122 weak_factory_(this) { | |
| 123 layer_ = cc::Layer::Create(); | |
| 124 // TODO(penghuang): SetMasksToBounds() can be expensive if the layer is | |
| 125 // transformed. Possibly better could be to explicitly clip the child layers | |
| 126 // (by modifying their bounds). | |
| 127 layer_->SetMasksToBounds(true); | |
| 128 layer_->SetIsDrawable(true); | |
| 129 } | |
| 130 | |
| 131 PepperCompositorHost::~PepperCompositorHost() { | |
| 132 // Unbind from the instance when destroyed if we're still bound. | |
| 133 if (bound_instance_) | |
| 134 bound_instance_->BindGraphics(bound_instance_->pp_instance(), 0); | |
| 135 } | |
| 136 | |
| 137 bool PepperCompositorHost::BindToInstance( | |
| 138 PepperPluginInstanceImpl* new_instance) { | |
| 139 if (new_instance && new_instance->pp_instance() != pp_instance()) | |
| 140 return false; // Can't bind other instance's contexts. | |
| 141 if (bound_instance_ == new_instance) | |
| 142 return true; // Rebinding the same device, nothing to do. | |
| 143 if (bound_instance_ && new_instance) | |
| 144 return false; // Can't change a bound device. | |
| 145 bound_instance_ = new_instance; | |
| 146 return true; | |
| 147 } | |
| 148 | |
| 149 void PepperCompositorHost::ViewInitiatedPaint() { | |
| 150 if (!commit_layers_reply_context_.is_valid()) | |
| 151 return; | |
| 152 host()->SendReply(commit_layers_reply_context_, | |
| 153 PpapiPluginMsg_Compositor_CommitLayersReply()); | |
| 154 commit_layers_reply_context_ = ppapi::host::ReplyMessageContext(); | |
| 155 } | |
| 156 | |
| 157 void PepperCompositorHost::ViewFlushedPaint() {} | |
| 158 | |
| 159 void PepperCompositorHost::UpdateLayer( | |
| 160 const scoped_refptr<cc::Layer>& layer, | |
| 161 const ppapi::CompositorLayerData* old_layer, | |
| 162 const ppapi::CompositorLayerData* new_layer, | |
| 163 scoped_ptr<base::SharedMemory> image_shm) { | |
| 164 // Always update properties on cc::Layer, because cc::Layer | |
| 165 // will ignore any setting with unchanged value. | |
| 166 layer->SetIsDrawable(true); | |
| 167 layer->SetBlendMode(SkXfermode::kSrcOver_Mode); | |
| 168 layer->SetOpacity(new_layer->common.opacity); | |
| 169 layer->SetBounds(PP_ToGfxSize(new_layer->common.size)); | |
| 170 layer->SetTransformOrigin(gfx::Point3F(new_layer->common.size.width / 2, | |
| 171 new_layer->common.size.height / 2, | |
| 172 0.0f)); | |
| 173 | |
| 174 gfx::Transform transform(gfx::Transform::kSkipInitialization); | |
| 175 transform.matrix().setColMajorf(new_layer->common.transform.matrix); | |
| 176 layer->SetTransform(transform); | |
| 177 | |
| 178 // Consider a (0,0,0,0) rect as no clip rect. | |
| 179 if (new_layer->common.clip_rect.point.x != 0 || | |
| 180 new_layer->common.clip_rect.point.y != 0 || | |
| 181 new_layer->common.clip_rect.size.width != 0 || | |
| 182 new_layer->common.clip_rect.size.height != 0) { | |
| 183 scoped_refptr<cc::Layer> clip_parent = layer->parent(); | |
| 184 if (clip_parent == layer_) { | |
| 185 // Create a clip parent layer, if it does not exist. | |
| 186 clip_parent = cc::Layer::Create(); | |
| 187 clip_parent->SetMasksToBounds(true); | |
| 188 clip_parent->SetIsDrawable(true); | |
| 189 layer_->ReplaceChild(layer, clip_parent); | |
| 190 clip_parent->AddChild(layer); | |
| 191 } | |
| 192 gfx::Point position = PP_ToGfxPoint(new_layer->common.clip_rect.point); | |
| 193 clip_parent->SetPosition(position); | |
| 194 clip_parent->SetBounds(PP_ToGfxSize(new_layer->common.clip_rect.size)); | |
| 195 layer->SetPosition(gfx::Point(-position.x(), -position.y())); | |
| 196 } else if (layer->parent() != layer_) { | |
| 197 // Remove the clip parent layer. | |
| 198 layer_->ReplaceChild(layer->parent(), layer); | |
| 199 layer->SetPosition(gfx::Point()); | |
| 200 } | |
| 201 | |
| 202 if (new_layer->color) { | |
| 203 layer->SetBackgroundColor(SkColorSetARGBMacro( | |
| 204 new_layer->color->alpha * 255, | |
| 205 new_layer->color->red * 255, | |
| 206 new_layer->color->green * 255, | |
| 207 new_layer->color->blue * 255)); | |
| 208 return; | |
| 209 } | |
| 210 | |
| 211 if (new_layer->texture) { | |
| 212 scoped_refptr<cc::TextureLayer> texture_layer( | |
| 213 static_cast<cc::TextureLayer*>(layer.get())); | |
| 214 if (!old_layer || | |
| 215 new_layer->common.resource_id != old_layer->common.resource_id) { | |
| 216 cc::TextureMailbox mailbox(new_layer->texture->mailbox, | |
| 217 GL_TEXTURE_2D, | |
| 218 new_layer->texture->sync_point); | |
| 219 texture_layer->SetTextureMailbox(mailbox, | |
| 220 cc::SingleReleaseCallback::Create( | |
| 221 base::Bind(&PepperCompositorHost::ResourceReleased, | |
| 222 weak_factory_.GetWeakPtr(), | |
| 223 new_layer->common.resource_id)));; | |
| 224 } | |
| 225 texture_layer->SetPremultipliedAlpha(new_layer->texture->premult_alpha); | |
| 226 gfx::RectF rect = PP_ToGfxRectF(new_layer->texture->source_rect); | |
| 227 texture_layer->SetUV(rect.origin(), rect.bottom_right()); | |
| 228 return; | |
| 229 } | |
| 230 | |
| 231 if (new_layer->image) { | |
| 232 if (!old_layer || | |
| 233 new_layer->common.resource_id != old_layer->common.resource_id) { | |
| 234 scoped_refptr<cc::TextureLayer> image_layer( | |
| 235 static_cast<cc::TextureLayer*>(layer.get())); | |
| 236 EnterResourceNoLock<PPB_ImageData_API> enter(new_layer->image->resource, | |
| 237 true); | |
| 238 DCHECK(enter.succeeded()); | |
| 239 | |
| 240 // TODO(penghuang): support all kinds of image. | |
| 241 PP_ImageDataDesc desc; | |
| 242 PP_Bool rv = enter.object()->Describe(&desc); | |
| 243 DCHECK_EQ(rv, PP_TRUE); | |
| 244 DCHECK_EQ(desc.stride, desc.size.width * 4); | |
| 245 DCHECK_EQ(desc.format, PP_IMAGEDATAFORMAT_RGBA_PREMUL); | |
| 246 | |
| 247 cc::TextureMailbox mailbox(image_shm.get(), | |
| 248 PP_ToGfxSize(desc.size)); | |
| 249 image_layer->SetTextureMailbox(mailbox, | |
| 250 cc::SingleReleaseCallback::Create( | |
| 251 base::Bind(&PepperCompositorHost::ImageReleased, | |
| 252 weak_factory_.GetWeakPtr(), | |
| 253 new_layer->common.resource_id, | |
| 254 base::Passed(&image_shm)))); | |
| 255 | |
| 256 // ImageData is always premultiplied alpha. | |
| 257 image_layer->SetPremultipliedAlpha(true); | |
| 258 } | |
| 259 return; | |
| 260 } | |
| 261 // Should not be reached. | |
| 262 DCHECK(false); | |
|
piman
2014/06/10 22:37:06
NOTREACHED() is ok here.
Peng
2014/06/10 23:03:32
Done.
| |
| 263 } | |
| 264 | |
| 265 void PepperCompositorHost::ResourceReleased(int32_t id, | |
| 266 uint32_t sync_point, | |
| 267 bool is_lost) { | |
| 268 host()->SendUnsolicitedReply( | |
| 269 pp_resource(), | |
| 270 PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost)); | |
| 271 } | |
| 272 | |
| 273 void PepperCompositorHost::ImageReleased( | |
| 274 int32_t id, | |
| 275 const scoped_ptr<base::SharedMemory>& shared_memory, | |
| 276 uint32_t sync_point, | |
| 277 bool is_lost) { | |
| 278 ResourceReleased(id, sync_point, is_lost); | |
| 279 } | |
| 280 | |
| 281 int32_t PepperCompositorHost::OnResourceMessageReceived( | |
| 282 const IPC::Message& msg, | |
| 283 HostMessageContext* context) { | |
| 284 PPAPI_BEGIN_MESSAGE_MAP(PepperCompositorHost, msg) | |
| 285 PPAPI_DISPATCH_HOST_RESOURCE_CALL( | |
| 286 PpapiHostMsg_Compositor_CommitLayers, OnHostMsgCommitLayers) | |
| 287 PPAPI_END_MESSAGE_MAP() | |
| 288 return ppapi::host::ResourceHost::OnResourceMessageReceived(msg, context); | |
| 289 } | |
| 290 | |
| 291 bool PepperCompositorHost::IsCompositorHost() { | |
| 292 return true; | |
| 293 } | |
| 294 | |
| 295 int32_t PepperCompositorHost::OnHostMsgCommitLayers( | |
| 296 HostMessageContext* context, | |
| 297 const std::vector<ppapi::CompositorLayerData>& layers, | |
| 298 bool reset) { | |
| 299 // Do not support CommitLayers() on an unbounded compositor. | |
| 300 if (!bound_instance_) | |
| 301 return PP_ERROR_FAILED; | |
| 302 | |
| 303 if (commit_layers_reply_context_.is_valid()) | |
| 304 return PP_ERROR_INPROGRESS; | |
| 305 | |
| 306 commit_layers_reply_context_ = context->MakeReplyMessageContext(); | |
| 307 | |
| 308 scoped_ptr<base::SharedMemory> image_shms[layers.size()]; | |
| 309 // Verfiy the layers first, if an error happens, we will return the error to | |
| 310 // plugin and keep current layers set by the previous CommitLayers() | |
| 311 // unchanged. | |
| 312 for (size_t i = 0; i < layers.size(); ++i) { | |
| 313 const ppapi::CompositorLayerData* old_layer = NULL; | |
| 314 if (!reset && i < layers_.size()) | |
| 315 old_layer = &layers_[i].pp_layer; | |
| 316 int32_t rv = VerifyCommittedLayer(old_layer, &layers[i], &image_shms[i]); | |
| 317 if (rv != PP_OK) | |
| 318 return rv; | |
| 319 } | |
| 320 | |
| 321 // ResetLayers() has been called, we need rebuild layer stack. | |
| 322 if (reset) { | |
| 323 layer_->RemoveAllChildren(); | |
| 324 layers_.clear(); | |
| 325 } | |
| 326 | |
| 327 for (size_t i = 0; i < layers.size(); ++i) { | |
| 328 const ppapi::CompositorLayerData* pp_layer = &layers[i]; | |
| 329 LayerData* data = i >= layers_.size() ? NULL : &layers_[i]; | |
| 330 DCHECK(!data || data->cc_layer); | |
| 331 scoped_refptr<cc::Layer> cc_layer = data ? data->cc_layer : NULL; | |
| 332 ppapi::CompositorLayerData* old_layer = data ? &data->pp_layer : NULL; | |
| 333 | |
| 334 if (!cc_layer) { | |
| 335 if (pp_layer->color) | |
| 336 cc_layer = cc::SolidColorLayer::Create(); | |
| 337 else if (pp_layer->texture || pp_layer->image) | |
| 338 cc_layer = cc::TextureLayer::CreateForMailbox(NULL); | |
| 339 layer_->AddChild(cc_layer); | |
| 340 } | |
| 341 | |
| 342 UpdateLayer(cc_layer, old_layer, pp_layer, image_shms[i].Pass()); | |
| 343 | |
| 344 if (old_layer) | |
| 345 *old_layer = *pp_layer; | |
| 346 else | |
| 347 layers_.push_back(LayerData(cc_layer, *pp_layer)); | |
| 348 } | |
| 349 | |
| 350 return PP_OK_COMPLETIONPENDING; | |
| 351 } | |
| 352 | |
| 353 } // namespace content | |
| OLD | NEW |