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 "components/guest_view/renderer/guest_view_container.h"
7 #include "components/guest_view/common/guest_view_constants.h"
8 #include "components/guest_view/common/guest_view_messages.h"
9 #include "components/guest_view/renderer/guest_view_request.h"
10 #include "content/public/renderer/render_frame.h"
11 #include "content/public/renderer/render_frame_observer.h"
12 #include "content/public/renderer/render_view.h"
13 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
17 using GuestViewContainerMap
= std::map
<int, guest_view::GuestViewContainer
*>;
18 static base::LazyInstance
<GuestViewContainerMap
> g_guest_view_container_map
=
19 LAZY_INSTANCE_INITIALIZER
;
23 namespace guest_view
{
25 class GuestViewContainer::RenderFrameLifetimeObserver
26 : public content::RenderFrameObserver
{
28 RenderFrameLifetimeObserver(GuestViewContainer
* container
,
29 content::RenderFrame
* render_frame
);
31 // content::RenderFrameObserver overrides.
32 void OnDestruct() override
;
35 GuestViewContainer
* container_
;
37 DISALLOW_COPY_AND_ASSIGN(RenderFrameLifetimeObserver
);
40 GuestViewContainer::RenderFrameLifetimeObserver::RenderFrameLifetimeObserver(
41 GuestViewContainer
* container
,
42 content::RenderFrame
* render_frame
)
43 : content::RenderFrameObserver(render_frame
),
44 container_(container
) {}
46 void GuestViewContainer::RenderFrameLifetimeObserver::OnDestruct() {
47 container_
->RenderFrameDestroyed();
50 GuestViewContainer::GuestViewContainer(content::RenderFrame
* render_frame
)
52 element_instance_id_(guest_view::kInstanceIDNone
),
53 render_frame_(render_frame
),
54 in_destruction_(false),
55 destruction_isolate_(nullptr),
56 weak_ptr_factory_(this) {
57 render_frame_lifetime_observer_
.reset(
58 new RenderFrameLifetimeObserver(this, render_frame_
));
61 GuestViewContainer::~GuestViewContainer() {
62 // Note: Cleanups should be done in GuestViewContainer::Destroy(), not here.
66 GuestViewContainer
* GuestViewContainer::FromID(int element_instance_id
) {
67 GuestViewContainerMap
* guest_view_containers
=
68 g_guest_view_container_map
.Pointer();
69 auto it
= guest_view_containers
->find(element_instance_id
);
70 return it
== guest_view_containers
->end() ? nullptr : it
->second
;
73 // Right now a GuestViewContainer can be destroyed in one of the following
76 // 1. If GuestViewContainer is driven by content/, the element (browser plugin)
77 // can destroy GuestViewContainer when the element is destroyed.
78 // 2. If GuestViewContainer is managed outside of content/, then the
79 // <webview> element's GC will destroy it.
80 // 3. If GuestViewContainer's embedder frame is destroyed, we'd also destroy
81 // GuestViewContainer.
82 void GuestViewContainer::Destroy(bool embedder_frame_destroyed
) {
86 in_destruction_
= true;
88 // Give our derived class an opportunity to perform some cleanup prior to
90 OnDestroy(embedder_frame_destroyed
);
92 RunDestructionCallback(embedder_frame_destroyed
);
94 // Invalidate weak references to us to avoid late arriving tasks from running
96 weak_ptr_factory_
.InvalidateWeakPtrs();
98 if (element_instance_id() != guest_view::kInstanceIDNone
)
99 g_guest_view_container_map
.Get().erase(element_instance_id());
101 if (pending_response_
.get())
102 pending_response_
->ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
104 while (pending_requests_
.size() > 0) {
105 linked_ptr
<GuestViewRequest
> pending_request
= pending_requests_
.front();
106 pending_requests_
.pop_front();
107 // Call the JavaScript callbacks with no arguments which implies an error.
108 pending_request
->ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
114 void GuestViewContainer::RegisterDestructionCallback(
115 v8::Local
<v8::Function
> callback
,
116 v8::Isolate
* isolate
) {
117 destruction_callback_
.Reset(isolate
, callback
);
118 destruction_isolate_
= isolate
;
121 void GuestViewContainer::RenderFrameDestroyed() {
122 OnRenderFrameDestroyed();
123 render_frame_
= nullptr;
124 Destroy(true /* embedder_frame_destroyed */);
127 void GuestViewContainer::IssueRequest(linked_ptr
<GuestViewRequest
> request
) {
128 EnqueueRequest(request
);
129 PerformPendingRequest();
132 void GuestViewContainer::EnqueueRequest(linked_ptr
<GuestViewRequest
> request
) {
133 pending_requests_
.push_back(request
);
136 void GuestViewContainer::PerformPendingRequest() {
137 if (!ready_
|| pending_requests_
.empty() || pending_response_
.get())
140 linked_ptr
<GuestViewRequest
> pending_request
= pending_requests_
.front();
141 pending_requests_
.pop_front();
142 pending_request
->PerformRequest();
143 pending_response_
= pending_request
;
146 void GuestViewContainer::HandlePendingResponseCallback(
147 const IPC::Message
& message
) {
148 CHECK(pending_response_
.get());
149 linked_ptr
<GuestViewRequest
> pending_response(pending_response_
.release());
150 pending_response
->HandleResponse(message
);
153 void GuestViewContainer::RunDestructionCallback(bool embedder_frame_destroyed
) {
154 // Do not attempt to run |destruction_callback_| if the embedder frame was
155 // destroyed. Trying to invoke callback on RenderFrame destruction results in
156 // assertion failure when calling WebScopedMicrotaskSuppression.
157 if (embedder_frame_destroyed
)
160 // Call the destruction callback, if one is registered.
161 if (!destruction_callback_
.IsEmpty()) {
162 v8::HandleScope
handle_scope(destruction_isolate_
);
163 v8::Local
<v8::Function
> callback
= v8::Local
<v8::Function
>::New(
164 destruction_isolate_
, destruction_callback_
);
165 v8::Local
<v8::Context
> context
= callback
->CreationContext();
166 if (context
.IsEmpty())
169 v8::Context::Scope
context_scope(context
);
170 blink::WebScopedMicrotaskSuppression suppression
;
172 callback
->Call(context
->Global(), 0 /* argc */, nullptr);
176 void GuestViewContainer::OnHandleCallback(const IPC::Message
& message
) {
177 // Handle the callback for the current request with a pending response.
178 HandlePendingResponseCallback(message
);
179 // Perform the subsequent request if one exists.
180 PerformPendingRequest();
183 bool GuestViewContainer::OnMessage(const IPC::Message
& message
) {
187 bool GuestViewContainer::OnMessageReceived(const IPC::Message
& message
) {
188 if (OnMessage(message
))
191 OnHandleCallback(message
);
195 void GuestViewContainer::Ready() {
197 CHECK(!pending_response_
.get());
198 PerformPendingRequest();
200 // Give the derived type an opportunity to perform some actions when the
201 // container acquires a geometry.
205 void GuestViewContainer::SetElementInstanceID(int element_instance_id
) {
206 DCHECK_EQ(element_instance_id_
, guest_view::kInstanceIDNone
);
207 element_instance_id_
= element_instance_id
;
209 DCHECK(!g_guest_view_container_map
.Get().count(element_instance_id
));
210 g_guest_view_container_map
.Get().insert(
211 std::make_pair(element_instance_id
, this));
214 void GuestViewContainer::DidDestroyElement() {
218 base::WeakPtr
<content::BrowserPluginDelegate
> GuestViewContainer::GetWeakPtr() {
219 return weak_ptr_factory_
.GetWeakPtr();
222 } // namespace guest_view