Popular sites on the NTP: Try to keep the ordering constant
[chromium-blink-merge.git] / components / guest_view / renderer / guest_view_container.cc
blobecdc446d803142ea74e062f72ed066c57e81816f
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"
15 namespace {
17 using GuestViewContainerMap = std::map<int, guest_view::GuestViewContainer*>;
18 static base::LazyInstance<GuestViewContainerMap> g_guest_view_container_map =
19 LAZY_INSTANCE_INITIALIZER;
21 } // namespace
23 namespace guest_view {
25 class GuestViewContainer::RenderFrameLifetimeObserver
26 : public content::RenderFrameObserver {
27 public:
28 RenderFrameLifetimeObserver(GuestViewContainer* container,
29 content::RenderFrame* render_frame);
31 // content::RenderFrameObserver overrides.
32 void OnDestruct() override;
34 private:
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)
51 : ready_(false),
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.
65 // static.
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
74 // ways:
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) {
83 if (in_destruction_)
84 return;
86 in_destruction_ = true;
88 // Give our derived class an opportunity to perform some cleanup prior to
89 // destruction.
90 OnDestroy(embedder_frame_destroyed);
92 RunDestructionCallback(embedder_frame_destroyed);
94 // Invalidate weak references to us to avoid late arriving tasks from running
95 // during destruction
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);
111 delete this;
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())
138 return;
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)
158 return;
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())
167 return;
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) {
184 return false;
187 bool GuestViewContainer::OnMessageReceived(const IPC::Message& message) {
188 if (OnMessage(message))
189 return true;
191 OnHandleCallback(message);
192 return true;
195 void GuestViewContainer::Ready() {
196 ready_ = true;
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.
202 OnReady();
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() {
215 Destroy(false);
218 base::WeakPtr<content::BrowserPluginDelegate> GuestViewContainer::GetWeakPtr() {
219 return weak_ptr_factory_.GetWeakPtr();
222 } // namespace guest_view