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/child_frame_compositing_helper.h" 6 7#include "cc/blink/web_layer_impl.h" 8#include "cc/layers/delegated_frame_provider.h" 9#include "cc/layers/delegated_frame_resource_collection.h" 10#include "cc/layers/delegated_renderer_layer.h" 11#include "cc/layers/solid_color_layer.h" 12#include "cc/output/context_provider.h" 13#include "cc/output/copy_output_request.h" 14#include "cc/output/copy_output_result.h" 15#include "cc/resources/single_release_callback.h" 16#include "content/common/browser_plugin/browser_plugin_messages.h" 17#include "content/common/frame_messages.h" 18#include "content/common/gpu/client/context_provider_command_buffer.h" 19#include "content/renderer/browser_plugin/browser_plugin.h" 20#include "content/renderer/browser_plugin/browser_plugin_manager.h" 21#include "content/renderer/render_frame_impl.h" 22#include "content/renderer/render_frame_proxy.h" 23#include "content/renderer/render_thread_impl.h" 24#include "skia/ext/image_operations.h" 25#include "third_party/WebKit/public/web/WebFrame.h" 26#include "third_party/WebKit/public/web/WebPluginContainer.h" 27#include "third_party/khronos/GLES2/gl2.h" 28#include "ui/gfx/size_conversions.h" 29#include "ui/gfx/skia_util.h" 30 31namespace content { 32 33ChildFrameCompositingHelper* 34ChildFrameCompositingHelper::CreateForBrowserPlugin( 35 const base::WeakPtr<BrowserPlugin>& browser_plugin) { 36 return new ChildFrameCompositingHelper( 37 browser_plugin, NULL, NULL, browser_plugin->render_view_routing_id()); 38} 39 40ChildFrameCompositingHelper* 41ChildFrameCompositingHelper::CreateForRenderFrameProxy( 42 RenderFrameProxy* render_frame_proxy) { 43 return new ChildFrameCompositingHelper(base::WeakPtr<BrowserPlugin>(), 44 render_frame_proxy->web_frame(), 45 render_frame_proxy, 46 render_frame_proxy->routing_id()); 47} 48 49ChildFrameCompositingHelper::ChildFrameCompositingHelper( 50 const base::WeakPtr<BrowserPlugin>& browser_plugin, 51 blink::WebFrame* frame, 52 RenderFrameProxy* render_frame_proxy, 53 int host_routing_id) 54 : host_routing_id_(host_routing_id), 55 last_route_id_(0), 56 last_output_surface_id_(0), 57 last_host_id_(0), 58 ack_pending_(true), 59 opaque_(true), 60 browser_plugin_(browser_plugin), 61 render_frame_proxy_(render_frame_proxy), 62 frame_(frame) {} 63 64ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {} 65 66BrowserPluginManager* ChildFrameCompositingHelper::GetBrowserPluginManager() { 67 if (!browser_plugin_) 68 return NULL; 69 70 return browser_plugin_->browser_plugin_manager(); 71} 72 73blink::WebPluginContainer* ChildFrameCompositingHelper::GetContainer() { 74 if (!browser_plugin_) 75 return NULL; 76 77 return browser_plugin_->container(); 78} 79 80int ChildFrameCompositingHelper::GetInstanceID() { 81 if (!browser_plugin_) 82 return 0; 83 84 return browser_plugin_->browser_plugin_instance_id(); 85} 86 87void ChildFrameCompositingHelper::SendCompositorFrameSwappedACKToBrowser( 88 FrameHostMsg_CompositorFrameSwappedACK_Params& params) { 89 // This function will be removed when BrowserPluginManager is removed and 90 // BrowserPlugin is modified to use a RenderFrame. 91 if (GetBrowserPluginManager()) { 92 GetBrowserPluginManager()->Send( 93 new BrowserPluginHostMsg_CompositorFrameSwappedACK( 94 host_routing_id_, GetInstanceID(), params)); 95 } else if (render_frame_proxy_) { 96 render_frame_proxy_->Send( 97 new FrameHostMsg_CompositorFrameSwappedACK(host_routing_id_, params)); 98 } 99} 100 101void ChildFrameCompositingHelper::SendReclaimCompositorResourcesToBrowser( 102 FrameHostMsg_ReclaimCompositorResources_Params& params) { 103 // This function will be removed when BrowserPluginManager is removed and 104 // BrowserPlugin is modified to use a RenderFrame. 105 if (GetBrowserPluginManager()) { 106 GetBrowserPluginManager()->Send( 107 new BrowserPluginHostMsg_ReclaimCompositorResources( 108 host_routing_id_, GetInstanceID(), params)); 109 } else if (render_frame_proxy_) { 110 render_frame_proxy_->Send( 111 new FrameHostMsg_ReclaimCompositorResources(host_routing_id_, params)); 112 } 113} 114 115void ChildFrameCompositingHelper::CopyFromCompositingSurface( 116 int request_id, 117 gfx::Rect source_rect, 118 gfx::Size dest_size) { 119 CHECK(background_layer_.get()); 120 scoped_ptr<cc::CopyOutputRequest> request = 121 cc::CopyOutputRequest::CreateBitmapRequest(base::Bind( 122 &ChildFrameCompositingHelper::CopyFromCompositingSurfaceHasResult, 123 this, 124 request_id, 125 dest_size)); 126 request->set_area(source_rect); 127 background_layer_->RequestCopyOfOutput(request.Pass()); 128} 129 130void ChildFrameCompositingHelper::DidCommitCompositorFrame() { 131 if (!resource_collection_.get() || !ack_pending_) 132 return; 133 134 FrameHostMsg_CompositorFrameSwappedACK_Params params; 135 params.producing_host_id = last_host_id_; 136 params.producing_route_id = last_route_id_; 137 params.output_surface_id = last_output_surface_id_; 138 resource_collection_->TakeUnusedResourcesForChildCompositor( 139 ¶ms.ack.resources); 140 141 SendCompositorFrameSwappedACKToBrowser(params); 142 143 ack_pending_ = false; 144} 145 146void ChildFrameCompositingHelper::EnableCompositing(bool enable) { 147 if (enable && !background_layer_.get()) { 148 background_layer_ = cc::SolidColorLayer::Create(); 149 background_layer_->SetMasksToBounds(true); 150 background_layer_->SetBackgroundColor( 151 SkColorSetARGBInline(255, 255, 255, 255)); 152 web_layer_.reset(new cc_blink::WebLayerImpl(background_layer_)); 153 } 154 155 if (GetContainer()) { 156 GetContainer()->setWebLayer(enable ? web_layer_.get() : NULL); 157 } else if (frame_) { 158 frame_->setRemoteWebLayer(enable ? web_layer_.get() : NULL); 159 } 160} 161 162void ChildFrameCompositingHelper::CheckSizeAndAdjustLayerProperties( 163 const gfx::Size& new_size, 164 float device_scale_factor, 165 cc::Layer* layer) { 166 if (buffer_size_ != new_size) { 167 buffer_size_ = new_size; 168 // The container size is in DIP, so is the layer size. 169 // Buffer size is in physical pixels, so we need to adjust 170 // it by the device scale factor. 171 gfx::Size device_scale_adjusted_size = gfx::ToFlooredSize( 172 gfx::ScaleSize(buffer_size_, 1.0f / device_scale_factor)); 173 layer->SetBounds(device_scale_adjusted_size); 174 } 175 176 // Manually manage background layer for transparent webview. 177 if (!opaque_) 178 background_layer_->SetIsDrawable(false); 179} 180 181void ChildFrameCompositingHelper::OnContainerDestroy() { 182 if (GetContainer()) 183 GetContainer()->setWebLayer(NULL); 184 185 if (resource_collection_.get()) 186 resource_collection_->SetClient(NULL); 187 188 ack_pending_ = false; 189 resource_collection_ = NULL; 190 frame_provider_ = NULL; 191 delegated_layer_ = NULL; 192 background_layer_ = NULL; 193 web_layer_.reset(); 194} 195 196void ChildFrameCompositingHelper::ChildFrameGone() { 197 background_layer_->SetBackgroundColor(SkColorSetARGBInline(255, 0, 128, 0)); 198 background_layer_->RemoveAllChildren(); 199 background_layer_->SetIsDrawable(true); 200 background_layer_->SetContentsOpaque(true); 201} 202 203void ChildFrameCompositingHelper::OnCompositorFrameSwapped( 204 scoped_ptr<cc::CompositorFrame> frame, 205 int route_id, 206 uint32 output_surface_id, 207 int host_id, 208 base::SharedMemoryHandle handle) { 209 cc::DelegatedFrameData* frame_data = frame->delegated_frame_data.get(); 210 // Do nothing if we are getting destroyed or have no frame data. 211 if (!frame_data || !background_layer_.get()) 212 return; 213 214 DCHECK(!frame_data->render_pass_list.empty()); 215 cc::RenderPass* root_pass = frame_data->render_pass_list.back(); 216 gfx::Size frame_size = root_pass->output_rect.size(); 217 218 if (last_route_id_ != route_id || 219 last_output_surface_id_ != output_surface_id || 220 last_host_id_ != host_id) { 221 // Resource ids are scoped by the output surface. 222 // If the originating output surface doesn't match the last one, it 223 // indicates the guest's output surface may have been recreated, in which 224 // case we should recreate the DelegatedRendererLayer, to avoid matching 225 // resources from the old one with resources from the new one which would 226 // have the same id. 227 frame_provider_ = NULL; 228 229 // Drop the cc::DelegatedFrameResourceCollection so that we will not return 230 // any resources from the old output surface with the new output surface id. 231 if (resource_collection_.get()) { 232 resource_collection_->SetClient(NULL); 233 234 if (resource_collection_->LoseAllResources()) 235 SendReturnedDelegatedResources(); 236 resource_collection_ = NULL; 237 } 238 last_output_surface_id_ = output_surface_id; 239 last_route_id_ = route_id; 240 last_host_id_ = host_id; 241 } 242 if (!resource_collection_.get()) { 243 resource_collection_ = new cc::DelegatedFrameResourceCollection; 244 resource_collection_->SetClient(this); 245 } 246 if (!frame_provider_.get() || frame_provider_->frame_size() != frame_size) { 247 frame_provider_ = new cc::DelegatedFrameProvider( 248 resource_collection_.get(), frame->delegated_frame_data.Pass()); 249 if (delegated_layer_.get()) 250 delegated_layer_->RemoveFromParent(); 251 delegated_layer_ = 252 cc::DelegatedRendererLayer::Create(frame_provider_.get()); 253 delegated_layer_->SetIsDrawable(true); 254 buffer_size_ = gfx::Size(); 255 SetContentsOpaque(opaque_); 256 background_layer_->AddChild(delegated_layer_); 257 } else { 258 frame_provider_->SetFrameData(frame->delegated_frame_data.Pass()); 259 } 260 261 CheckSizeAndAdjustLayerProperties( 262 frame_data->render_pass_list.back()->output_rect.size(), 263 frame->metadata.device_scale_factor, 264 delegated_layer_.get()); 265 266 ack_pending_ = true; 267} 268 269void ChildFrameCompositingHelper::UpdateVisibility(bool visible) { 270 if (delegated_layer_.get()) 271 delegated_layer_->SetIsDrawable(visible); 272} 273 274void ChildFrameCompositingHelper::UnusedResourcesAreAvailable() { 275 if (ack_pending_) 276 return; 277 278 SendReturnedDelegatedResources(); 279} 280 281void ChildFrameCompositingHelper::SendReturnedDelegatedResources() { 282 FrameHostMsg_ReclaimCompositorResources_Params params; 283 if (resource_collection_.get()) 284 resource_collection_->TakeUnusedResourcesForChildCompositor( 285 ¶ms.ack.resources); 286 DCHECK(!params.ack.resources.empty()); 287 288 params.route_id = last_route_id_; 289 params.output_surface_id = last_output_surface_id_; 290 params.renderer_host_id = last_host_id_; 291 SendReclaimCompositorResourcesToBrowser(params); 292} 293 294void ChildFrameCompositingHelper::SetContentsOpaque(bool opaque) { 295 opaque_ = opaque; 296 if (delegated_layer_.get()) 297 delegated_layer_->SetContentsOpaque(opaque_); 298} 299 300void ChildFrameCompositingHelper::CopyFromCompositingSurfaceHasResult( 301 int request_id, 302 gfx::Size dest_size, 303 scoped_ptr<cc::CopyOutputResult> result) { 304 scoped_ptr<SkBitmap> bitmap; 305 if (result && result->HasBitmap() && !result->size().IsEmpty()) 306 bitmap = result->TakeBitmap(); 307 308 SkBitmap resized_bitmap; 309 if (bitmap) { 310 resized_bitmap = 311 skia::ImageOperations::Resize(*bitmap, 312 skia::ImageOperations::RESIZE_BEST, 313 dest_size.width(), 314 dest_size.height()); 315 } 316 if (GetBrowserPluginManager()) { 317 GetBrowserPluginManager()->Send( 318 new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck( 319 host_routing_id_, GetInstanceID(), request_id, resized_bitmap)); 320 } 321} 322 323} // namespace content 324