| 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
|
|
|