Index: components/framelet/renderer/framelet_container.cc |
diff --git a/components/framelet/renderer/framelet_container.cc b/components/framelet/renderer/framelet_container.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9009ba0a5142a7633aa93d1b388e6728c63ca424 |
--- /dev/null |
+++ b/components/framelet/renderer/framelet_container.cc |
@@ -0,0 +1,389 @@ |
+// Copyright 2015 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 "components/framelet/renderer/framelet_container.h" |
+ |
+#include "cc/blink/web_layer_impl.h" |
+#include "cc/layers/solid_color_layer.h" |
+#include "cc/layers/surface_layer.h" |
+#include "components/framelet/common/framelet_constants.h" |
+#include "components/framelet/common/framelet_messages.h" |
+#include "components/guest_view/common/guest_view_constants.h" |
+#include "components/guest_view/common/guest_view_messages.h" |
+#include "components/guest_view/renderer/guest_view_request.h" |
+#include "content/public/renderer/render_frame.h" |
+#include "content/public/renderer/render_thread.h" |
+#include "content/public/renderer/render_view.h" |
+#include "grit/components_scaled_resources.h" |
+#include "third_party/WebKit/public/web/WebDocument.h" |
+#include "third_party/WebKit/public/web/WebFramelet.h" |
+#include "third_party/WebKit/public/web/WebLocalFrame.h" |
+#include "ui/base/resource/resource_bundle.h" |
+ |
+namespace framelet { |
+ |
+namespace { |
+ |
+class FrameletCreateRequest : public guest_view::GuestViewRequest { |
+ public: |
+ FrameletCreateRequest(FrameletContainer* framelet_container, |
+ ResourceMonitoring resource_monitoring) |
+ : guest_view::GuestViewRequest(framelet_container), |
+ resource_monitoring_(resource_monitoring) {} |
+ |
+ ~FrameletCreateRequest() override {} |
+ |
+ void PerformRequest() override { |
+ DCHECK_NE(container()->element_instance_id(), guest_view::kInstanceIDNone); |
+ if (!container() || !container()->render_frame()) |
+ return; |
+ |
+ // TODO(fsamuel): This is a bit annoying. Maybe container should be a |
+ // // template method? |
+ FrameletContainer* framelet_container = |
+ static_cast<FrameletContainer*>(container()); |
+ // TODO(fsamuel): We need a mechanism to detach/destroy a guest before |
+ // creating a new one. |
+ DCHECK(!framelet_container->has_guest()); |
+ |
+ scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue()); |
+ params->SetInteger(guest_view::kElementWidth, |
+ framelet_container->element_size().width()); |
+ params->SetInteger(guest_view::kElementHeight, |
+ framelet_container->element_size().height()); |
+ params->SetString(guest_view::kUrl, framelet_container->url().spec()); |
+ params->SetBoolean(framelet::kFocused, framelet_container->focused()); |
+ params->SetBoolean(framelet::kVisible, framelet_container->visible()); |
+ params->SetBoolean(framelet::kMonitorResources, |
+ resource_monitoring_ == ResourceMonitoring::ENABLED); |
+ |
+ container()->render_frame()->Send(new ChromeGuestViewHostMsg_CreateFramelet( |
+ container()->render_frame()->GetRoutingID(), |
+ container()->element_instance_id(), *params)); |
+ } |
+ |
+ void HandleResponse(const IPC::Message& message) override { |
+ CHECK_EQ(message.type(), |
+ static_cast<uint32_t>(ChromeGuestViewMsg_CreateFramelet_ACK::ID)); |
+ ChromeGuestViewMsg_CreateFramelet_ACK::Param param; |
+ if (!ChromeGuestViewMsg_CreateFramelet_ACK::Read(&message, ¶m)) |
+ return; |
+ |
+ int guest_instance_id = base::get<1>(param); |
+ static_cast<FrameletContainer*>(container())->Attach(guest_instance_id); |
+ } |
+ |
+ void HandleDefaultResponse() override {} |
+ |
+ private: |
+ ResourceMonitoring resource_monitoring_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(FrameletCreateRequest); |
+}; |
+ |
+class FrameletAttachRequest : public guest_view::GuestViewRequest { |
+ public: |
+ explicit FrameletAttachRequest(FrameletContainer* framelet_container) |
+ : guest_view::GuestViewRequest(framelet_container) {} |
+ |
+ ~FrameletAttachRequest() override {} |
+ |
+ void PerformRequest() override { |
+ if (!container() || !container()->render_frame()) |
+ return; |
+ |
+ // TODO(fsamuel): This is a bit annoying. Maybe container should be a |
+ // // template method? |
+ FrameletContainer* framelet_container = |
+ static_cast<FrameletContainer*>(container()); |
+ |
+ DCHECK(framelet_container->has_guest()); |
+ |
+ scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue()); |
+ params->SetInteger(guest_view::kElementWidth, |
+ framelet_container->element_size().width()); |
+ params->SetInteger(guest_view::kElementHeight, |
+ framelet_container->element_size().height()); |
+ params->SetBoolean(framelet::kFocused, framelet_container->focused()); |
+ params->SetBoolean(framelet::kVisible, framelet_container->visible()); |
+ |
+ // Step 1, send the attach params to guest_view/. |
+ container()->render_frame()->Send(new GuestViewHostMsg_AttachGuest( |
+ container()->element_instance_id(), |
+ framelet_container->guest_instance_id(), *params)); |
+ |
+ // Step 1, Attach to FrameletGuest. |
+ container()->render_frame()->Send(new ChromeGuestViewHostMsg_AttachFramelet( |
+ container()->render_frame()->GetRoutingID(), |
+ container()->element_instance_id(), |
+ framelet_container->guest_instance_id(), *params)); |
+ } |
+ |
+ void HandleResponse(const IPC::Message& message) override { |
+ CHECK_EQ(message.type(), |
+ static_cast<uint32_t>(GuestViewMsg_GuestAttached::ID)); |
+ // TODO(fsamuel): We probably don't care about the ontent window here, |
+ // but it would be nice to be able to postMessage. |
+ } |
+ |
+ void HandleDefaultResponse() override {} |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(FrameletAttachRequest); |
+}; |
+ |
+class FrameletDestroyRequest : public guest_view::GuestViewRequest { |
+ public: |
+ explicit FrameletDestroyRequest(FrameletContainer* framelet_container) |
+ : guest_view::GuestViewRequest(framelet_container) {} |
+ |
+ ~FrameletDestroyRequest() override {} |
+ |
+ void PerformRequest() override { |
+ if (!container() || !container()->render_frame()) |
+ return; |
+ |
+ container()->render_frame()->Send( |
+ new ChromeGuestViewHostMsg_DestroyFramelet( |
+ container()->element_instance_id())); |
+ |
+ static_cast<FrameletContainer*>(container())->Detach(); |
+ } |
+ |
+ void HandleResponse(const IPC::Message& message) override { |
+ CHECK_EQ(message.type(), |
+ static_cast<uint32_t>(ChromeGuestViewMsg_DestroyFramelet_ACK::ID)); |
+ } |
+ |
+ void HandleDefaultResponse() override {} |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(FrameletDestroyRequest); |
+}; |
+ |
+} // namespace |
+ |
+FrameletContainer::FrameletContainer(content::RenderFrame* render_frame, |
+ const GURL& url, |
+ IPC::Sender* thread_safe_sender) |
+ : GuestViewContainer(render_frame), |
+ guest_instance_id_(guest_view::kInstanceIDNone), |
+ focused_(false), |
+ visible_(false), |
+ killed_(false), |
+ url_(url), |
+ thread_safe_sender_(thread_safe_sender), |
+ framelet_(nullptr), |
+ solid_layer_( |
+ cc::SolidColorLayer::Create(cc_blink::WebLayerImpl::LayerSettings())), |
+ click_to_play_image_(ResourceBundle::GetSharedInstance().GetImageNamed( |
+ IDR_FRAMELET_CLICK_TO_PLAY)), |
+ click_to_play_layer_(cc::UIResourceLayer::Create( |
+ cc_blink::WebLayerImpl::LayerSettings())) { |
+ SetElementInstanceID(content::RenderThread::Get()->GenerateRoutingID()); |
+} |
+ |
+FrameletContainer::~FrameletContainer() {} |
+ |
+void FrameletContainer::Attach(int guest_instance_id) { |
+ // Reset the layers. |
+ solid_layer_->SetIsDrawable(false); |
+ click_to_play_layer_->SetIsDrawable(false); |
+ DCHECK(!has_guest()); |
+ guest_instance_id_ = guest_instance_id; |
+ linked_ptr<guest_view::GuestViewRequest> request( |
+ new FrameletAttachRequest(this)); |
+ IssueRequest(request); |
+} |
+ |
+void FrameletContainer::Detach() { |
+ guest_instance_id_ = guest_view::kInstanceIDNone; |
+} |
+ |
+bool FrameletContainer::OnMessage(const IPC::Message& message) { |
+ bool handled = true; |
+ IPC_BEGIN_MESSAGE_MAP(FrameletContainer, message) |
+ IPC_MESSAGE_HANDLER(ChromeGuestViewMsg_ReportMemoryUsage, |
+ OnReportMemoryUsage) |
+ IPC_MESSAGE_HANDLER(ChromeGuestViewMsg_SetChildFrameSurface, |
+ OnSetChildFrameSurface) |
+ IPC_MESSAGE_UNHANDLED(handled = false) |
+ IPC_END_MESSAGE_MAP() |
+ return handled; |
+} |
+ |
+void FrameletContainer::didAttach(blink::WebFramelet* framelet) { |
+ framelet_ = framelet; |
+ // Only create a Framelet if we have a non-zero size. |
+ CreateFrameletIfReady(ResourceMonitoring::ENABLED); |
+} |
+ |
+void FrameletContainer::didDetach() { |
+ linked_ptr<guest_view::GuestViewRequest> request( |
+ new FrameletDestroyRequest(this)); |
+ IssueRequest(request); |
+} |
+ |
+void FrameletContainer::forwardInputEvent( |
+ const blink::WebInputEvent* input_event) { |
+ if (!has_guest()) { |
+ // If this guest has been killed. |
+ // TODO(fsamuel): We want a platform-agnostic way to detect click. |
+ bool click = input_event->type == blink::WebInputEvent::GestureTap || |
+ ((input_event->type == blink::WebInputEvent::MouseUp) && |
+ (static_cast<const blink::WebMouseEvent*>(input_event) |
+ ->clickCount == 1)); |
+ if (killed_ && click) { |
+ CreateFrameletIfReady(ResourceMonitoring::DISABLED); |
+ return; |
+ } |
+ } |
+ |
+ render_frame()->Send(new ChromeGuestViewHostMsg_ForwardInputEvent( |
+ element_instance_id(), input_event)); |
+} |
+ |
+void FrameletContainer::frameRectsChanged(const blink::WebRect& frame_rect) { |
+ element_size_ = gfx::Size(frame_rect.width, frame_rect.height); |
+ UpdateClickToPlayLayerPosition(); |
+ if (!ready_) { |
+ ready_ = true; |
+ CreateFrameletIfReady(ResourceMonitoring::ENABLED); |
+ return; |
+ } |
+ if (!has_guest()) |
+ return; |
+ render_frame()->Send(new ChromeGuestViewHostMsg_ResizeFramelet( |
+ element_instance_id(), element_size_)); |
+} |
+ |
+void FrameletContainer::updateFocus(bool focused, |
+ blink::WebFocusType focus_type) { |
+ focused_ = focused; |
+ focus_type_ = focus_type; |
+ if (!has_guest()) |
+ return; |
+ render_frame()->Send(new ChromeGuestViewHostMsg_SetFocus( |
+ element_instance_id(), focused, focus_type)); |
+} |
+ |
+void FrameletContainer::updateVisibility(bool visible) { |
+ visible_ = visible; |
+ if (!has_guest()) |
+ return; |
+ render_frame()->Send(new ChromeGuestViewHostMsg_SetContainerVisible( |
+ element_instance_id(), visible)); |
+} |
+ |
+void FrameletContainer::CreateFrameletIfReady( |
+ ResourceMonitoring resource_monitoring) { |
+ if (!ready_ || !framelet_) |
+ return; |
+ killed_ = false; |
+ // We might already have a guest at this point that is in the process of being |
+ // destroyed. We don't need to worry about that now, we'll find out about it |
+ // when this request is handled in queue order. |
+ linked_ptr<guest_view::GuestViewRequest> request( |
+ new FrameletCreateRequest(this, resource_monitoring)); |
+ IssueRequest(request); |
+} |
+ |
+void FrameletContainer::UpdateClickToPlayLayerPosition() { |
+ gfx::PointF position( |
+ (element_size().width() - click_to_play_image_.Size().width()) / 2.f, |
+ (element_size().height() - click_to_play_image_.Size().height()) / 2.f); |
+ click_to_play_layer_->SetPosition(position); |
+} |
+ |
+void FrameletContainer::OnReportMemoryUsage( |
+ int element_instance_id, |
+ const ResourceUsageLevel& memory_usage) { |
+ // TODO(fsamuel): Do something useful with the heap size. |
+ switch (memory_usage) { |
+ case ResourceUsageLevel::LOW: { |
+ solid_layer_->SetIsDrawable(false); |
+ click_to_play_layer_->SetIsDrawable(false); |
+ return; |
+ } |
+ case ResourceUsageLevel::MEDIUM: { |
+ solid_layer_->SetIsDrawable(true); |
+ solid_layer_->SetBackgroundColor(SkColorSetARGBInline(255, 255, 255, 0)); |
+ click_to_play_layer_->SetIsDrawable(false); |
+ return; |
+ } |
+ case ResourceUsageLevel::HIGH: { |
+ solid_layer_->SetIsDrawable(true); |
+ solid_layer_->SetBackgroundColor(SkColorSetARGBInline(255, 255, 0, 0)); |
+ click_to_play_layer_->SetIsDrawable(false); |
+ return; |
+ } |
+ case ResourceUsageLevel::CRITICAL: { |
+ killed_ = true; |
+ solid_layer_->SetIsDrawable(true); |
+ solid_layer_->SetBackgroundColor(SkColorSetARGBInline(255, 0, 0, 0)); |
+ click_to_play_layer_->SetIsDrawable(true); |
+ // Kill the guest. |
+ linked_ptr<guest_view::GuestViewRequest> request( |
+ new FrameletDestroyRequest(this)); |
+ IssueRequest(request); |
+ return; |
+ } |
+ default: |
+ DCHECK(false); |
+ } |
+} |
+ |
+void FrameletContainer::OnSetChildFrameSurface( |
+ int element_instance_id, |
+ const cc::SurfaceId& surface_id, |
+ const gfx::Size& frame_size, |
+ float scale_factor, |
+ const cc::SurfaceSequence& sequence) { |
+ cc::SurfaceLayer::SatisfyCallback satisfy_callback = base::Bind( |
+ &FrameletContainer::SatisfyCallbackOnCompositorThread, |
+ thread_safe_sender_, render_frame()->GetRoutingID(), element_instance_id); |
+ cc::SurfaceLayer::RequireCallback require_callback = base::Bind( |
+ &FrameletContainer::RequireCallbackOnCompositorThread, |
+ thread_safe_sender_, render_frame()->GetRoutingID(), element_instance_id); |
+ scoped_refptr<cc::SurfaceLayer> surface_layer = |
+ cc::SurfaceLayer::Create(cc_blink::WebLayerImpl::LayerSettings(), |
+ satisfy_callback, require_callback); |
+ surface_layer->SetSurfaceId(surface_id, scale_factor, frame_size); |
+ gfx::Size frame_size_in_dip( |
+ gfx::ScaleToFlooredSize(frame_size, 1.0f / scale_factor)); |
+ surface_layer->SetBounds(frame_size_in_dip); |
+ |
+ solid_layer_->SetMasksToBounds(true); |
+ solid_layer_->SetBounds(frame_size_in_dip); |
+ solid_layer_->SetBackgroundColor(SkColorSetARGBInline(255, 0, 0, 192)); |
+ solid_layer_->SetIsDrawable(false); |
+ solid_layer_->SetOpacity(0.5f); |
+ surface_layer->AddChild(solid_layer_); |
+ |
+ SkBitmap* bitmap = const_cast<SkBitmap*>(click_to_play_image_.ToSkBitmap()); |
+ click_to_play_layer_->SetMasksToBounds(true); |
+ click_to_play_layer_->SetBounds(click_to_play_image_.Size()); |
+ click_to_play_layer_->SetBitmap(*bitmap); |
+ click_to_play_layer_->SetOpacity(0.75f); |
+ surface_layer->AddChild(click_to_play_layer_); |
+ |
+ blink::WebLayer* layer = new cc_blink::WebLayerImpl(surface_layer); |
+ framelet_->setWebLayer(layer); |
+ web_layer_.reset(layer); |
+} |
+ |
+void FrameletContainer::SatisfyCallbackOnCompositorThread( |
+ IPC::Sender* sender, |
+ int host_routing_id, |
+ int element_instance_id, |
+ cc::SurfaceSequence sequence) {} |
+ |
+void FrameletContainer::RequireCallbackOnCompositorThread( |
+ IPC::Sender* sender, |
+ int host_routing_id, |
+ int element_instance_id, |
+ cc::SurfaceId id, |
+ cc::SurfaceSequence sequence) {} |
+ |
+} // namespace framelet |