Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / renderer / child_frame_compositing_helper.cc
blobadec05be8e643a2a0f4ccb28ddc124bda9d6ac26
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"
33 namespace content {
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(),
48 render_frame_proxy,
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,
56 int host_routing_id)
57 : host_routing_id_(host_routing_id),
58 last_route_id_(0),
59 last_output_surface_id_(0),
60 last_host_id_(0),
61 ack_pending_(true),
62 opaque_(true),
63 browser_plugin_(browser_plugin),
64 render_frame_proxy_(render_frame_proxy),
65 frame_(frame) {
68 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {
69 if (resource_collection_.get())
70 resource_collection_->SetClient(nullptr);
73 BrowserPluginManager* ChildFrameCompositingHelper::GetBrowserPluginManager() {
74 if (!browser_plugin_)
75 return nullptr;
77 return BrowserPluginManager::Get();
80 blink::WebPluginContainer* ChildFrameCompositingHelper::GetContainer() {
81 if (!browser_plugin_)
82 return nullptr;
84 return browser_plugin_->container();
87 int ChildFrameCompositingHelper::GetInstanceID() {
88 if (!browser_plugin_)
89 return 0;
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_)
124 return;
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 &params.ack.resources);
133 SendCompositorFrameSwappedACKToBrowser(params);
135 ack_pending_ = false;
138 void ChildFrameCompositingHelper::EnableCompositing(bool enable) {
139 if (enable && !background_layer_.get()) {
140 background_layer_ =
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);
150 } else if (frame_) {
151 frame_->setRemoteWebLayer(enable ? web_layer_.get() : nullptr);
155 void ChildFrameCompositingHelper::CheckSizeAndAdjustLayerProperties(
156 const gfx::Size& new_size,
157 float device_scale_factor,
158 cc::Layer* layer) {
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.
170 if (!opaque_)
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
176 // future.
177 DidCommitCompositorFrame();
179 if (GetContainer())
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;
191 web_layer_.reset();
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,
203 int route_id,
204 uint32 output_surface_id,
205 int host_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
210 // interchangeably.
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())
215 return;
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
229 // have the same id.
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_);
260 } else {
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());
269 ack_pending_ = true;
272 // static
273 void ChildFrameCompositingHelper::SatisfyCallback(
274 scoped_refptr<ThreadSafeSender> sender,
275 int host_routing_id,
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));
281 // static
282 void ChildFrameCompositingHelper::SatisfyCallbackBrowserPlugin(
283 scoped_refptr<ThreadSafeSender> sender,
284 int host_routing_id,
285 int browser_plugin_instance_id,
286 cc::SurfaceSequence sequence) {
287 sender->Send(new BrowserPluginHostMsg_SatisfySequence(
288 host_routing_id, browser_plugin_instance_id, sequence));
291 // static
292 void ChildFrameCompositingHelper::RequireCallback(
293 scoped_refptr<ThreadSafeSender> sender,
294 int host_routing_id,
295 cc::SurfaceId id,
296 cc::SurfaceSequence sequence) {
297 // This may be called on either the main or impl thread.
298 sender->Send(new FrameHostMsg_RequireSequence(host_routing_id, id, sequence));
301 void ChildFrameCompositingHelper::RequireCallbackBrowserPlugin(
302 scoped_refptr<ThreadSafeSender> sender,
303 int host_routing_id,
304 int browser_plugin_instance_id,
305 cc::SurfaceId id,
306 cc::SurfaceSequence sequence) {
307 // This may be called on either the main or impl thread.
308 sender->Send(new BrowserPluginHostMsg_RequireSequence(
309 host_routing_id, browser_plugin_instance_id, id, sequence));
312 void ChildFrameCompositingHelper::OnSetSurface(
313 const cc::SurfaceId& surface_id,
314 const gfx::Size& frame_size,
315 float scale_factor,
316 const cc::SurfaceSequence& sequence) {
317 // Surface IDs and compositor frames should never be received
318 // interchangably.
319 DCHECK(!delegated_layer_.get());
321 // Do nothing if we are getting destroyed.
322 if (!background_layer_.get())
323 return;
325 if (!surface_layer_.get()) {
326 scoped_refptr<ThreadSafeSender> sender(
327 RenderThreadImpl::current()->thread_safe_sender());
328 cc::SurfaceLayer::SatisfyCallback satisfy_callback =
329 render_frame_proxy_
330 ? base::Bind(&ChildFrameCompositingHelper::SatisfyCallback, sender,
331 host_routing_id_)
332 : base::Bind(
333 &ChildFrameCompositingHelper::SatisfyCallbackBrowserPlugin,
334 sender, host_routing_id_,
335 browser_plugin_->browser_plugin_instance_id());
336 cc::SurfaceLayer::RequireCallback require_callback =
337 render_frame_proxy_
338 ? base::Bind(&ChildFrameCompositingHelper::RequireCallback, sender,
339 host_routing_id_)
340 : base::Bind(
341 &ChildFrameCompositingHelper::RequireCallbackBrowserPlugin,
342 sender, host_routing_id_,
343 browser_plugin_->browser_plugin_instance_id());
344 surface_layer_ =
345 cc::SurfaceLayer::Create(cc_blink::WebLayerImpl::LayerSettings(),
346 satisfy_callback, require_callback);
348 surface_layer_->SetSurfaceId(surface_id, scale_factor, frame_size);
349 UpdateVisibility(true);
350 SetContentsOpaque(opaque_);
351 background_layer_->AddChild(surface_layer_);
353 // The RWHV creates a destruction dependency on the surface that needs to be
354 // satisfied. Note: render_frame_proxy_ is null in the case our client is a
355 // BrowserPlugin; in this case the BrowserPlugin sends its own SatisfySequence
356 // message.
357 if (render_frame_proxy_) {
358 render_frame_proxy_->Send(
359 new FrameHostMsg_SatisfySequence(host_routing_id_, sequence));
360 } else if (browser_plugin_.get()) {
361 browser_plugin_->SendSatisfySequence(sequence);
364 CheckSizeAndAdjustLayerProperties(frame_size, scale_factor,
365 surface_layer_.get());
368 void ChildFrameCompositingHelper::UpdateVisibility(bool visible) {
369 if (delegated_layer_.get())
370 delegated_layer_->SetIsDrawable(visible);
371 if (surface_layer_.get())
372 surface_layer_->SetIsDrawable(visible);
375 void ChildFrameCompositingHelper::UnusedResourcesAreAvailable() {
376 if (ack_pending_)
377 return;
379 SendReturnedDelegatedResources();
382 void ChildFrameCompositingHelper::SendReturnedDelegatedResources() {
383 FrameHostMsg_ReclaimCompositorResources_Params params;
384 if (resource_collection_.get())
385 resource_collection_->TakeUnusedResourcesForChildCompositor(
386 &params.ack.resources);
387 DCHECK(!params.ack.resources.empty());
389 params.route_id = last_route_id_;
390 params.output_surface_id = last_output_surface_id_;
391 params.renderer_host_id = last_host_id_;
392 SendReclaimCompositorResourcesToBrowser(params);
395 void ChildFrameCompositingHelper::SetContentsOpaque(bool opaque) {
396 opaque_ = opaque;
397 if (delegated_layer_.get())
398 delegated_layer_->SetContentsOpaque(opaque_);
399 if (surface_layer_.get())
400 surface_layer_->SetContentsOpaque(opaque_);
403 } // namespace content