• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 namespace content {
32 
33 ChildFrameCompositingHelper*
CreateForBrowserPlugin(const base::WeakPtr<BrowserPlugin> & browser_plugin)34 ChildFrameCompositingHelper::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 
40 ChildFrameCompositingHelper*
CreateForRenderFrameProxy(RenderFrameProxy * render_frame_proxy)41 ChildFrameCompositingHelper::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 
ChildFrameCompositingHelper(const base::WeakPtr<BrowserPlugin> & browser_plugin,blink::WebFrame * frame,RenderFrameProxy * render_frame_proxy,int host_routing_id)49 ChildFrameCompositingHelper::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 
~ChildFrameCompositingHelper()64 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {}
65 
GetBrowserPluginManager()66 BrowserPluginManager* ChildFrameCompositingHelper::GetBrowserPluginManager() {
67   if (!browser_plugin_)
68     return NULL;
69 
70   return browser_plugin_->browser_plugin_manager();
71 }
72 
GetContainer()73 blink::WebPluginContainer* ChildFrameCompositingHelper::GetContainer() {
74   if (!browser_plugin_)
75     return NULL;
76 
77   return browser_plugin_->container();
78 }
79 
GetInstanceID()80 int ChildFrameCompositingHelper::GetInstanceID() {
81   if (!browser_plugin_)
82     return 0;
83 
84   return browser_plugin_->browser_plugin_instance_id();
85 }
86 
SendCompositorFrameSwappedACKToBrowser(FrameHostMsg_CompositorFrameSwappedACK_Params & params)87 void 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 
SendReclaimCompositorResourcesToBrowser(FrameHostMsg_ReclaimCompositorResources_Params & params)101 void 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 
CopyFromCompositingSurface(int request_id,gfx::Rect source_rect,gfx::Size dest_size)115 void 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 
DidCommitCompositorFrame()130 void 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       &params.ack.resources);
140 
141   SendCompositorFrameSwappedACKToBrowser(params);
142 
143   ack_pending_ = false;
144 }
145 
EnableCompositing(bool enable)146 void 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 
CheckSizeAndAdjustLayerProperties(const gfx::Size & new_size,float device_scale_factor,cc::Layer * layer)162 void 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 
OnContainerDestroy()181 void 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 
ChildFrameGone()196 void 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 
OnCompositorFrameSwapped(scoped_ptr<cc::CompositorFrame> frame,int route_id,uint32 output_surface_id,int host_id,base::SharedMemoryHandle handle)203 void 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 
UpdateVisibility(bool visible)269 void ChildFrameCompositingHelper::UpdateVisibility(bool visible) {
270   if (delegated_layer_.get())
271     delegated_layer_->SetIsDrawable(visible);
272 }
273 
UnusedResourcesAreAvailable()274 void ChildFrameCompositingHelper::UnusedResourcesAreAvailable() {
275   if (ack_pending_)
276     return;
277 
278   SendReturnedDelegatedResources();
279 }
280 
SendReturnedDelegatedResources()281 void ChildFrameCompositingHelper::SendReturnedDelegatedResources() {
282   FrameHostMsg_ReclaimCompositorResources_Params params;
283   if (resource_collection_.get())
284     resource_collection_->TakeUnusedResourcesForChildCompositor(
285         &params.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 
SetContentsOpaque(bool opaque)294 void ChildFrameCompositingHelper::SetContentsOpaque(bool opaque) {
295   opaque_ = opaque;
296   if (delegated_layer_.get())
297     delegated_layer_->SetContentsOpaque(opaque_);
298 }
299 
CopyFromCompositingSurfaceHasResult(int request_id,gfx::Size dest_size,scoped_ptr<cc::CopyOutputResult> result)300 void 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