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.
5 #include "content/renderer/child_frame_compositing_helper.h"
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/layers/surface_layer.h"
13 #include "cc/output/context_provider.h"
14 #include "cc/output/copy_output_request.h"
15 #include "cc/output/copy_output_result.h"
16 #include "cc/resources/single_release_callback.h"
17 #include "content/child/thread_safe_sender.h"
18 #include "content/common/browser_plugin/browser_plugin_messages.h"
19 #include "content/common/frame_messages.h"
20 #include "content/common/gpu/client/context_provider_command_buffer.h"
21 #include "content/renderer/browser_plugin/browser_plugin.h"
22 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
23 #include "content/renderer/render_frame_impl.h"
24 #include "content/renderer/render_frame_proxy.h"
25 #include "content/renderer/render_thread_impl.h"
26 #include "skia/ext/image_operations.h"
27 #include "third_party/WebKit/public/web/WebFrame.h"
28 #include "third_party/WebKit/public/web/WebPluginContainer.h"
29 #include "third_party/khronos/GLES2/gl2.h"
30 #include "ui/gfx/geometry/size_conversions.h"
31 #include "ui/gfx/skia_util.h"
35 ChildFrameCompositingHelper
*
36 ChildFrameCompositingHelper::CreateForBrowserPlugin(
37 const base::WeakPtr
<BrowserPlugin
>& browser_plugin
) {
38 return new ChildFrameCompositingHelper(
39 browser_plugin
, nullptr, nullptr,
40 browser_plugin
->render_frame_routing_id());
43 ChildFrameCompositingHelper
*
44 ChildFrameCompositingHelper::CreateForRenderFrameProxy(
45 RenderFrameProxy
* render_frame_proxy
) {
46 return new ChildFrameCompositingHelper(base::WeakPtr
<BrowserPlugin
>(),
47 render_frame_proxy
->web_frame(),
49 render_frame_proxy
->routing_id());
52 ChildFrameCompositingHelper::ChildFrameCompositingHelper(
53 const base::WeakPtr
<BrowserPlugin
>& browser_plugin
,
54 blink::WebFrame
* frame
,
55 RenderFrameProxy
* render_frame_proxy
,
57 : host_routing_id_(host_routing_id
),
59 last_output_surface_id_(0),
63 browser_plugin_(browser_plugin
),
64 render_frame_proxy_(render_frame_proxy
),
68 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {
69 if (resource_collection_
.get())
70 resource_collection_
->SetClient(nullptr);
73 BrowserPluginManager
* ChildFrameCompositingHelper::GetBrowserPluginManager() {
77 return BrowserPluginManager::Get();
80 blink::WebPluginContainer
* ChildFrameCompositingHelper::GetContainer() {
84 return browser_plugin_
->container();
87 int ChildFrameCompositingHelper::GetInstanceID() {
91 return browser_plugin_
->browser_plugin_instance_id();
94 void ChildFrameCompositingHelper::SendCompositorFrameSwappedACKToBrowser(
95 FrameHostMsg_CompositorFrameSwappedACK_Params
& params
) {
96 // This function will be removed when BrowserPluginManager is removed and
97 // BrowserPlugin is modified to use a RenderFrame.
98 if (GetBrowserPluginManager()) {
99 GetBrowserPluginManager()->Send(
100 new BrowserPluginHostMsg_CompositorFrameSwappedACK(
101 GetInstanceID(), params
));
102 } else if (render_frame_proxy_
) {
103 render_frame_proxy_
->Send(
104 new FrameHostMsg_CompositorFrameSwappedACK(host_routing_id_
, params
));
108 void ChildFrameCompositingHelper::SendReclaimCompositorResourcesToBrowser(
109 FrameHostMsg_ReclaimCompositorResources_Params
& params
) {
110 // This function will be removed when BrowserPluginManager is removed and
111 // BrowserPlugin is modified to use a RenderFrame.
112 if (GetBrowserPluginManager()) {
113 GetBrowserPluginManager()->Send(
114 new BrowserPluginHostMsg_ReclaimCompositorResources(
115 GetInstanceID(), params
));
116 } else if (render_frame_proxy_
) {
117 render_frame_proxy_
->Send(
118 new FrameHostMsg_ReclaimCompositorResources(host_routing_id_
, params
));
122 void ChildFrameCompositingHelper::DidCommitCompositorFrame() {
123 if (!resource_collection_
.get() || !ack_pending_
)
126 FrameHostMsg_CompositorFrameSwappedACK_Params params
;
127 params
.producing_host_id
= last_host_id_
;
128 params
.producing_route_id
= last_route_id_
;
129 params
.output_surface_id
= last_output_surface_id_
;
130 resource_collection_
->TakeUnusedResourcesForChildCompositor(
131 ¶ms
.ack
.resources
);
133 SendCompositorFrameSwappedACKToBrowser(params
);
135 ack_pending_
= false;
138 void ChildFrameCompositingHelper::EnableCompositing(bool enable
) {
139 if (enable
&& !background_layer_
.get()) {
141 cc::SolidColorLayer::Create(cc_blink::WebLayerImpl::LayerSettings());
142 background_layer_
->SetMasksToBounds(true);
143 background_layer_
->SetBackgroundColor(
144 SkColorSetARGBInline(255, 255, 255, 255));
145 web_layer_
.reset(new cc_blink::WebLayerImpl(background_layer_
));
148 if (GetContainer()) {
149 GetContainer()->setWebLayer(enable
? web_layer_
.get() : nullptr);
151 frame_
->setRemoteWebLayer(enable
? web_layer_
.get() : nullptr);
155 void ChildFrameCompositingHelper::CheckSizeAndAdjustLayerProperties(
156 const gfx::Size
& new_size
,
157 float device_scale_factor
,
159 if (buffer_size_
!= new_size
) {
160 buffer_size_
= new_size
;
161 // The container size is in DIP, so is the layer size.
162 // Buffer size is in physical pixels, so we need to adjust
163 // it by the device scale factor.
164 gfx::Size device_scale_adjusted_size
= gfx::ToFlooredSize(
165 gfx::ScaleSize(buffer_size_
, 1.0f
/ device_scale_factor
));
166 layer
->SetBounds(device_scale_adjusted_size
);
169 // Manually manage background layer for transparent webview.
171 background_layer_
->SetIsDrawable(false);
174 void ChildFrameCompositingHelper::OnContainerDestroy() {
175 // If we have a pending ACK, then ACK now so we don't lose frames in the
177 DidCommitCompositorFrame();
180 GetContainer()->setWebLayer(nullptr);
182 if (resource_collection_
.get())
183 resource_collection_
->SetClient(nullptr);
185 ack_pending_
= false;
186 resource_collection_
= nullptr;
187 frame_provider_
= nullptr;
188 delegated_layer_
= nullptr;
189 background_layer_
= nullptr;
190 surface_layer_
= nullptr;
194 void ChildFrameCompositingHelper::ChildFrameGone() {
195 background_layer_
->SetBackgroundColor(SkColorSetARGBInline(255, 0, 128, 0));
196 background_layer_
->RemoveAllChildren();
197 background_layer_
->SetIsDrawable(true);
198 background_layer_
->SetContentsOpaque(true);
201 void ChildFrameCompositingHelper::OnCompositorFrameSwapped(
202 scoped_ptr
<cc::CompositorFrame
> frame
,
204 uint32 output_surface_id
,
206 base::SharedMemoryHandle handle
) {
207 cc::DelegatedFrameData
* frame_data
= frame
->delegated_frame_data
.get();
209 // Surface IDs and compositor frames should never be received
211 DCHECK(!surface_layer_
.get());
213 // Do nothing if we are getting destroyed or have no frame data.
214 if (!frame_data
|| !background_layer_
.get())
217 DCHECK(!frame_data
->render_pass_list
.empty());
218 cc::RenderPass
* root_pass
= frame_data
->render_pass_list
.back();
219 gfx::Size frame_size
= root_pass
->output_rect
.size();
221 if (last_route_id_
!= route_id
||
222 last_output_surface_id_
!= output_surface_id
||
223 last_host_id_
!= host_id
) {
224 // Resource ids are scoped by the output surface.
225 // If the originating output surface doesn't match the last one, it
226 // indicates the guest's output surface may have been recreated, in which
227 // case we should recreate the DelegatedRendererLayer, to avoid matching
228 // resources from the old one with resources from the new one which would
230 frame_provider_
= nullptr;
232 // Drop the cc::DelegatedFrameResourceCollection so that we will not return
233 // any resources from the old output surface with the new output surface id.
234 if (resource_collection_
.get()) {
235 resource_collection_
->SetClient(nullptr);
237 if (resource_collection_
->LoseAllResources())
238 SendReturnedDelegatedResources();
239 resource_collection_
= nullptr;
241 last_output_surface_id_
= output_surface_id
;
242 last_route_id_
= route_id
;
243 last_host_id_
= host_id
;
245 if (!resource_collection_
.get()) {
246 resource_collection_
= new cc::DelegatedFrameResourceCollection
;
247 resource_collection_
->SetClient(this);
249 if (!frame_provider_
.get() || frame_provider_
->frame_size() != frame_size
) {
250 frame_provider_
= new cc::DelegatedFrameProvider(
251 resource_collection_
.get(), frame
->delegated_frame_data
.Pass());
252 if (delegated_layer_
.get())
253 delegated_layer_
->RemoveFromParent();
254 delegated_layer_
= cc::DelegatedRendererLayer::Create(
255 cc_blink::WebLayerImpl::LayerSettings(), frame_provider_
.get());
256 delegated_layer_
->SetIsDrawable(true);
257 buffer_size_
= gfx::Size();
258 SetContentsOpaque(opaque_
);
259 background_layer_
->AddChild(delegated_layer_
);
261 frame_provider_
->SetFrameData(frame
->delegated_frame_data
.Pass());
264 CheckSizeAndAdjustLayerProperties(
265 frame_data
->render_pass_list
.back()->output_rect
.size(),
266 frame
->metadata
.device_scale_factor
,
267 delegated_layer_
.get());
273 void ChildFrameCompositingHelper::SatisfyCallback(
274 scoped_refptr
<ThreadSafeSender
> sender
,
276 cc::SurfaceSequence sequence
) {
277 // This may be called on either the main or impl thread.
278 sender
->Send(new FrameHostMsg_SatisfySequence(host_routing_id
, sequence
));
282 void ChildFrameCompositingHelper::RequireCallback(
283 scoped_refptr
<ThreadSafeSender
> sender
,
286 cc::SurfaceSequence sequence
) {
287 // This may be called on either the main or impl thread.
288 sender
->Send(new FrameHostMsg_RequireSequence(host_routing_id
, id
, sequence
));
291 void ChildFrameCompositingHelper::RequireCallbackBrowserPlugin(
292 scoped_refptr
<ThreadSafeSender
> sender
,
294 int browser_plugin_instance_id
,
296 cc::SurfaceSequence sequence
) {
297 // This may be called on either the main or impl thread.
298 sender
->Send(new BrowserPluginHostMsg_RequireSequence(
299 host_routing_id
, browser_plugin_instance_id
, id
, sequence
));
302 void ChildFrameCompositingHelper::OnSetSurface(
303 const cc::SurfaceId
& surface_id
,
304 const gfx::Size
& frame_size
,
306 const cc::SurfaceSequence
& sequence
) {
307 // Surface IDs and compositor frames should never be received
309 DCHECK(!delegated_layer_
.get());
311 // Do nothing if we are getting destroyed.
312 if (!background_layer_
.get())
315 if (!surface_layer_
.get()) {
316 scoped_refptr
<ThreadSafeSender
> sender(
317 RenderThreadImpl::current()->thread_safe_sender());
318 cc::SurfaceLayer::SatisfyCallback satisfy_callback
=
319 base::Bind(&ChildFrameCompositingHelper::SatisfyCallback
, sender
,
321 cc::SurfaceLayer::RequireCallback require_callback
=
323 ? base::Bind(&ChildFrameCompositingHelper::RequireCallback
, sender
,
326 &ChildFrameCompositingHelper::RequireCallbackBrowserPlugin
,
327 sender
, host_routing_id_
,
328 browser_plugin_
->browser_plugin_instance_id());
330 cc::SurfaceLayer::Create(cc_blink::WebLayerImpl::LayerSettings(),
331 satisfy_callback
, require_callback
);
333 surface_layer_
->SetSurfaceId(surface_id
, scale_factor
, frame_size
);
334 UpdateVisibility(true);
335 SetContentsOpaque(opaque_
);
336 background_layer_
->AddChild(surface_layer_
);
338 // The RWHV creates a destruction dependency on the surface that needs to be
339 // satisfied. Note: render_frame_proxy_ is null in the case our client is a
340 // BrowserPlugin; in this case the BrowserPlugin sends its own SatisfySequence
342 if (render_frame_proxy_
) {
343 render_frame_proxy_
->Send(
344 new FrameHostMsg_SatisfySequence(host_routing_id_
, sequence
));
345 } else if (browser_plugin_
.get()) {
346 browser_plugin_
->SendSatisfySequence(sequence
);
349 CheckSizeAndAdjustLayerProperties(frame_size
, scale_factor
,
350 surface_layer_
.get());
353 void ChildFrameCompositingHelper::UpdateVisibility(bool visible
) {
354 if (delegated_layer_
.get())
355 delegated_layer_
->SetIsDrawable(visible
);
356 if (surface_layer_
.get())
357 surface_layer_
->SetIsDrawable(visible
);
360 void ChildFrameCompositingHelper::UnusedResourcesAreAvailable() {
364 SendReturnedDelegatedResources();
367 void ChildFrameCompositingHelper::SendReturnedDelegatedResources() {
368 FrameHostMsg_ReclaimCompositorResources_Params params
;
369 if (resource_collection_
.get())
370 resource_collection_
->TakeUnusedResourcesForChildCompositor(
371 ¶ms
.ack
.resources
);
372 DCHECK(!params
.ack
.resources
.empty());
374 params
.route_id
= last_route_id_
;
375 params
.output_surface_id
= last_output_surface_id_
;
376 params
.renderer_host_id
= last_host_id_
;
377 SendReclaimCompositorResourcesToBrowser(params
);
380 void ChildFrameCompositingHelper::SetContentsOpaque(bool opaque
) {
382 if (delegated_layer_
.get())
383 delegated_layer_
->SetContentsOpaque(opaque_
);
384 if (surface_layer_
.get())
385 surface_layer_
->SetContentsOpaque(opaque_
);
388 } // namespace content