| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/renderer/child_frame_compositing_helper.h" |
| |
| #include <utility> |
| |
| #include "base/command_line.h" |
| #include "cc/blink/web_layer_impl.h" |
| #include "cc/layers/picture_image_layer.h" |
| #include "cc/layers/solid_color_layer.h" |
| #include "cc/layers/surface_layer.h" |
| #include "cc/paint/paint_image.h" |
| #include "cc/paint/paint_image_builder.h" |
| #include "components/viz/common/frame_sinks/copy_output_request.h" |
| #include "components/viz/common/frame_sinks/copy_output_result.h" |
| #include "components/viz/common/gpu/context_provider.h" |
| #include "components/viz/common/resources/single_release_callback.h" |
| #include "components/viz/common/surfaces/sequence_surface_reference_factory.h" |
| #include "components/viz/common/surfaces/stub_surface_reference_factory.h" |
| #include "components/viz/common/switches.h" |
| #include "content/child/thread_safe_sender.h" |
| #include "content/common/browser_plugin/browser_plugin_messages.h" |
| #include "content/common/content_switches_internal.h" |
| #include "content/common/frame_messages.h" |
| #include "content/public/common/content_client.h" |
| #include "content/public/renderer/content_renderer_client.h" |
| #include "content/renderer/browser_plugin/browser_plugin.h" |
| #include "content/renderer/browser_plugin/browser_plugin_manager.h" |
| #include "content/renderer/render_frame_impl.h" |
| #include "content/renderer/render_frame_proxy.h" |
| #include "content/renderer/render_thread_impl.h" |
| #include "services/ui/public/cpp/gpu/context_provider_command_buffer.h" |
| #include "skia/ext/image_operations.h" |
| #include "third_party/WebKit/public/web/WebPluginContainer.h" |
| #include "third_party/WebKit/public/web/WebRemoteFrame.h" |
| #include "third_party/khronos/GLES2/gl2.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "third_party/skia/include/core/SkImage.h" |
| #include "ui/gfx/geometry/point_f.h" |
| #include "ui/gfx/geometry/size_conversions.h" |
| #include "ui/gfx/skia_util.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| class IframeSurfaceReferenceFactory |
| : public viz::SequenceSurfaceReferenceFactory { |
| public: |
| IframeSurfaceReferenceFactory(scoped_refptr<ThreadSafeSender> sender, |
| int routing_id) |
| : sender_(std::move(sender)), routing_id_(routing_id) {} |
| |
| void AddPendingSequence(const viz::SurfaceSequence& sequence) { |
| ReleasePendingSequenceIfNecessary(); |
| pending_sequence_ = sequence; |
| } |
| |
| private: |
| ~IframeSurfaceReferenceFactory() override { |
| ReleasePendingSequenceIfNecessary(); |
| } |
| |
| void ReleasePendingSequenceIfNecessary() const { |
| if (pending_sequence_.is_valid()) { |
| sender_->Send( |
| new FrameHostMsg_SatisfySequence(routing_id_, pending_sequence_)); |
| pending_sequence_ = viz::SurfaceSequence(); |
| } |
| } |
| |
| // cc::SequenceSurfaceReferenceFactory implementation: |
| void RequireSequence(const viz::SurfaceId& surface_id, |
| const viz::SurfaceSequence& sequence) const override { |
| sender_->Send( |
| new FrameHostMsg_RequireSequence(routing_id_, surface_id, sequence)); |
| // If there is a temporary reference that was waiting on a new one to be |
| // created, it is now safe to release it. |
| ReleasePendingSequenceIfNecessary(); |
| } |
| |
| void SatisfySequence(const viz::SurfaceSequence& sequence) const override { |
| sender_->Send(new FrameHostMsg_SatisfySequence(routing_id_, sequence)); |
| } |
| |
| const scoped_refptr<ThreadSafeSender> sender_; |
| mutable viz::SurfaceSequence pending_sequence_; |
| const int routing_id_; |
| |
| DISALLOW_COPY_AND_ASSIGN(IframeSurfaceReferenceFactory); |
| }; |
| |
| class BrowserPluginSurfaceReferenceFactory |
| : public viz::SequenceSurfaceReferenceFactory { |
| public: |
| BrowserPluginSurfaceReferenceFactory(scoped_refptr<ThreadSafeSender> sender, |
| int routing_id, |
| int browser_plugin_instance_id) |
| : sender_(std::move(sender)), |
| routing_id_(routing_id), |
| browser_plugin_instance_id_(browser_plugin_instance_id) {} |
| |
| void AddPendingSequence(const viz::SurfaceSequence& sequence) { |
| ReleasePendingSequenceIfNecessary(); |
| pending_sequence_ = sequence; |
| } |
| |
| private: |
| ~BrowserPluginSurfaceReferenceFactory() override { |
| ReleasePendingSequenceIfNecessary(); |
| } |
| |
| void ReleasePendingSequenceIfNecessary() const { |
| if (pending_sequence_.is_valid()) { |
| sender_->Send(new BrowserPluginHostMsg_SatisfySequence( |
| routing_id_, browser_plugin_instance_id_, pending_sequence_)); |
| pending_sequence_ = viz::SurfaceSequence(); |
| } |
| } |
| |
| // cc::SequenceSurfaceRefrenceFactory implementation: |
| void SatisfySequence(const viz::SurfaceSequence& seq) const override { |
| sender_->Send(new BrowserPluginHostMsg_SatisfySequence( |
| routing_id_, browser_plugin_instance_id_, seq)); |
| } |
| |
| void RequireSequence(const viz::SurfaceId& surface_id, |
| const viz::SurfaceSequence& sequence) const override { |
| sender_->Send(new BrowserPluginHostMsg_RequireSequence( |
| routing_id_, browser_plugin_instance_id_, surface_id, sequence)); |
| // If there is a temporary reference that was waiting on a new one to be |
| // created, it is now safe to release it. |
| ReleasePendingSequenceIfNecessary(); |
| } |
| |
| const scoped_refptr<ThreadSafeSender> sender_; |
| mutable viz::SurfaceSequence pending_sequence_; |
| const int routing_id_; |
| const int browser_plugin_instance_id_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BrowserPluginSurfaceReferenceFactory); |
| }; |
| |
| } // namespace |
| |
| ChildFrameCompositingHelper* |
| ChildFrameCompositingHelper::CreateForBrowserPlugin( |
| const base::WeakPtr<BrowserPlugin>& browser_plugin) { |
| return new ChildFrameCompositingHelper( |
| browser_plugin, nullptr, nullptr, |
| browser_plugin->render_frame_routing_id()); |
| } |
| |
| ChildFrameCompositingHelper* |
| ChildFrameCompositingHelper::CreateForRenderFrameProxy( |
| RenderFrameProxy* render_frame_proxy) { |
| return new ChildFrameCompositingHelper( |
| base::WeakPtr<BrowserPlugin>(), render_frame_proxy->web_frame(), |
| render_frame_proxy, render_frame_proxy->routing_id()); |
| } |
| |
| ChildFrameCompositingHelper::ChildFrameCompositingHelper( |
| const base::WeakPtr<BrowserPlugin>& browser_plugin, |
| blink::WebRemoteFrame* frame, |
| RenderFrameProxy* render_frame_proxy, |
| int host_routing_id) |
| : host_routing_id_(host_routing_id), |
| browser_plugin_(browser_plugin), |
| render_frame_proxy_(render_frame_proxy), |
| frame_(frame) { |
| enable_surface_references_ = |
| !base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDisableSurfaceReferences); |
| if (enable_surface_references_) { |
| surface_reference_factory_ = new viz::StubSurfaceReferenceFactory(); |
| } else { |
| scoped_refptr<ThreadSafeSender> sender( |
| RenderThreadImpl::current()->thread_safe_sender()); |
| if (render_frame_proxy_) { |
| surface_reference_factory_ = |
| new IframeSurfaceReferenceFactory(sender, host_routing_id_); |
| } else { |
| surface_reference_factory_ = new BrowserPluginSurfaceReferenceFactory( |
| sender, host_routing_id_, |
| browser_plugin_->browser_plugin_instance_id()); |
| } |
| } |
| } |
| |
| ChildFrameCompositingHelper::~ChildFrameCompositingHelper() { |
| } |
| |
| blink::WebPluginContainer* ChildFrameCompositingHelper::GetContainer() { |
| if (!browser_plugin_) |
| return nullptr; |
| |
| return browser_plugin_->Container(); |
| } |
| |
| void ChildFrameCompositingHelper::UpdateWebLayer( |
| std::unique_ptr<blink::WebLayer> layer) { |
| if (GetContainer()) { |
| GetContainer()->SetWebLayer(layer.get()); |
| } else if (frame_) { |
| frame_->SetWebLayer(layer.get()); |
| } |
| web_layer_ = std::move(layer); |
| } |
| |
| void ChildFrameCompositingHelper::OnContainerDestroy() { |
| UpdateWebLayer(nullptr); |
| } |
| |
| void ChildFrameCompositingHelper::ChildFrameGone() { |
| scoped_refptr<cc::SolidColorLayer> crashed_layer = |
| cc::SolidColorLayer::Create(); |
| crashed_layer->SetMasksToBounds(true); |
| crashed_layer->SetBackgroundColor(SK_ColorBLACK); |
| |
| if (web_layer_) { |
| SkBitmap* sad_bitmap = |
| GetContentClient()->renderer()->GetSadWebViewBitmap(); |
| if (sad_bitmap && web_layer_->Bounds().width > sad_bitmap->width() && |
| web_layer_->Bounds().height > sad_bitmap->height()) { |
| scoped_refptr<cc::PictureImageLayer> sad_layer = |
| cc::PictureImageLayer::Create(); |
| sad_layer->SetImage(cc::PaintImageBuilder::WithDefault() |
| .set_id(cc::PaintImage::kNonLazyStableId) |
| .set_image(SkImage::MakeFromBitmap(*sad_bitmap)) |
| .TakePaintImage()); |
| sad_layer->SetBounds( |
| gfx::Size(sad_bitmap->width(), sad_bitmap->height())); |
| sad_layer->SetPosition(gfx::PointF( |
| (web_layer_->Bounds().width - sad_bitmap->width()) / 2, |
| (web_layer_->Bounds().height - sad_bitmap->height()) / 2)); |
| sad_layer->SetIsDrawable(true); |
| |
| crashed_layer->AddChild(sad_layer); |
| } |
| } |
| |
| std::unique_ptr<blink::WebLayer> layer( |
| new cc_blink::WebLayerImpl(crashed_layer)); |
| UpdateWebLayer(std::move(layer)); |
| } |
| |
| void ChildFrameCompositingHelper::SetPrimarySurfaceId( |
| const viz::SurfaceId& surface_id, |
| const gfx::Size& frame_size_in_dip) { |
| if (last_primary_surface_id_ == surface_id) |
| return; |
| |
| last_primary_surface_id_ = surface_id; |
| |
| surface_layer_ = cc::SurfaceLayer::Create(surface_reference_factory_); |
| surface_layer_->SetMasksToBounds(true); |
| surface_layer_->SetDefaultBackgroundColor(SK_ColorTRANSPARENT); |
| |
| surface_layer_->SetPrimarySurfaceId(surface_id); |
| surface_layer_->SetFallbackSurfaceId(fallback_surface_id_); |
| |
| std::unique_ptr<cc_blink::WebLayerImpl> layer( |
| new cc_blink::WebLayerImpl(surface_layer_)); |
| // TODO(lfg): Investigate if it's possible to propagate the information about |
| // the child surface's opacity. https://crbug.com/629851. |
| layer->SetOpaque(false); |
| layer->SetContentsOpaqueIsFixed(true); |
| UpdateWebLayer(std::move(layer)); |
| |
| UpdateVisibility(true); |
| |
| static_cast<cc_blink::WebLayerImpl*>(web_layer_.get()) |
| ->layer() |
| ->SetBounds(frame_size_in_dip); |
| } |
| |
| void ChildFrameCompositingHelper::SetFallbackSurfaceId( |
| const viz::SurfaceId& surface_id, |
| const gfx::Size& frame_size_in_dip, |
| const viz::SurfaceSequence& sequence) { |
| if (fallback_surface_id_ == surface_id) |
| return; |
| |
| fallback_surface_id_ = surface_id; |
| // The RWHV creates a destruction dependency on the surface that needs to be |
| // satisfied. The reference factory will satisfy it when a new reference has |
| // been created. |
| if (!enable_surface_references_) { |
| if (render_frame_proxy_) { |
| static_cast<IframeSurfaceReferenceFactory*>( |
| surface_reference_factory_.get()) |
| ->AddPendingSequence(sequence); |
| } else { |
| static_cast<BrowserPluginSurfaceReferenceFactory*>( |
| surface_reference_factory_.get()) |
| ->AddPendingSequence(sequence); |
| } |
| } |
| |
| if (!surface_layer_) { |
| SetPrimarySurfaceId(surface_id, frame_size_in_dip); |
| return; |
| } |
| |
| surface_layer_->SetFallbackSurfaceId(surface_id); |
| } |
| |
| void ChildFrameCompositingHelper::UpdateVisibility(bool visible) { |
| if (web_layer_) |
| web_layer_->SetDrawsContent(visible); |
| } |
| |
| } // namespace content |