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/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"
33 ChildFrameCompositingHelper
*
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());
40 ChildFrameCompositingHelper
*
41 ChildFrameCompositingHelper::CreateForRenderFrameProxy(
42 RenderFrameProxy
* render_frame_proxy
) {
43 return new ChildFrameCompositingHelper(base::WeakPtr
<BrowserPlugin
>(),
44 render_frame_proxy
->web_frame(),
46 render_frame_proxy
->routing_id());
49 ChildFrameCompositingHelper::ChildFrameCompositingHelper(
50 const base::WeakPtr
<BrowserPlugin
>& browser_plugin
,
51 blink::WebFrame
* frame
,
52 RenderFrameProxy
* render_frame_proxy
,
54 : host_routing_id_(host_routing_id
),
56 last_output_surface_id_(0),
60 browser_plugin_(browser_plugin
),
61 render_frame_proxy_(render_frame_proxy
),
64 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {}
66 BrowserPluginManager
* ChildFrameCompositingHelper::GetBrowserPluginManager() {
70 return browser_plugin_
->browser_plugin_manager();
73 blink::WebPluginContainer
* ChildFrameCompositingHelper::GetContainer() {
77 return browser_plugin_
->container();
80 int ChildFrameCompositingHelper::GetInstanceID() {
84 return browser_plugin_
->browser_plugin_instance_id();
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
));
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
));
115 void ChildFrameCompositingHelper::CopyFromCompositingSurface(
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
,
126 request
->set_area(source_rect
);
127 background_layer_
->RequestCopyOfOutput(request
.Pass());
130 void ChildFrameCompositingHelper::DidCommitCompositorFrame() {
131 if (!resource_collection_
.get() || !ack_pending_
)
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
);
141 SendCompositorFrameSwappedACKToBrowser(params
);
143 ack_pending_
= false;
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_
));
155 if (GetContainer()) {
156 GetContainer()->setWebLayer(enable
? web_layer_
.get() : NULL
);
158 frame_
->setRemoteWebLayer(enable
? web_layer_
.get() : NULL
);
162 void ChildFrameCompositingHelper::CheckSizeAndAdjustLayerProperties(
163 const gfx::Size
& new_size
,
164 float device_scale_factor
,
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
);
176 // Manually manage background layer for transparent webview.
178 background_layer_
->SetIsDrawable(false);
181 void ChildFrameCompositingHelper::OnContainerDestroy() {
183 GetContainer()->setWebLayer(NULL
);
185 if (resource_collection_
.get())
186 resource_collection_
->SetClient(NULL
);
188 ack_pending_
= false;
189 resource_collection_
= NULL
;
190 frame_provider_
= NULL
;
191 delegated_layer_
= NULL
;
192 background_layer_
= NULL
;
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);
203 void ChildFrameCompositingHelper::OnCompositorFrameSwapped(
204 scoped_ptr
<cc::CompositorFrame
> frame
,
206 uint32 output_surface_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())
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();
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
227 frame_provider_
= NULL
;
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
);
234 if (resource_collection_
->LoseAllResources())
235 SendReturnedDelegatedResources();
236 resource_collection_
= NULL
;
238 last_output_surface_id_
= output_surface_id
;
239 last_route_id_
= route_id
;
240 last_host_id_
= host_id
;
242 if (!resource_collection_
.get()) {
243 resource_collection_
= new cc::DelegatedFrameResourceCollection
;
244 resource_collection_
->SetClient(this);
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();
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_
);
258 frame_provider_
->SetFrameData(frame
->delegated_frame_data
.Pass());
261 CheckSizeAndAdjustLayerProperties(
262 frame_data
->render_pass_list
.back()->output_rect
.size(),
263 frame
->metadata
.device_scale_factor
,
264 delegated_layer_
.get());
269 void ChildFrameCompositingHelper::UpdateVisibility(bool visible
) {
270 if (delegated_layer_
.get())
271 delegated_layer_
->SetIsDrawable(visible
);
274 void ChildFrameCompositingHelper::UnusedResourcesAreAvailable() {
278 SendReturnedDelegatedResources();
281 void 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());
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
);
294 void ChildFrameCompositingHelper::SetContentsOpaque(bool opaque
) {
296 if (delegated_layer_
.get())
297 delegated_layer_
->SetContentsOpaque(opaque_
);
300 void ChildFrameCompositingHelper::CopyFromCompositingSurfaceHasResult(
303 scoped_ptr
<cc::CopyOutputResult
> result
) {
304 scoped_ptr
<SkBitmap
> bitmap
;
305 if (result
&& result
->HasBitmap() && !result
->size().IsEmpty())
306 bitmap
= result
->TakeBitmap();
308 SkBitmap resized_bitmap
;
311 skia::ImageOperations::Resize(*bitmap
,
312 skia::ImageOperations::RESIZE_BEST
,
316 if (GetBrowserPluginManager()) {
317 GetBrowserPluginManager()->Send(
318 new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck(
319 host_routing_id_
, GetInstanceID(), request_id
, resized_bitmap
));
323 } // namespace content