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/html_viewer/html_document_oopif.h"
7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "components/html_viewer/blink_url_request_type_converters.h"
14 #include "components/html_viewer/devtools_agent_impl.h"
15 #include "components/html_viewer/document_resource_waiter.h"
16 #include "components/html_viewer/global_state.h"
17 #include "components/html_viewer/html_frame.h"
18 #include "components/html_viewer/html_frame_tree_manager.h"
19 #include "components/html_viewer/test_html_viewer_impl.h"
20 #include "components/html_viewer/web_url_loader_impl.h"
21 #include "components/view_manager/ids.h"
22 #include "components/view_manager/public/cpp/view.h"
23 #include "components/view_manager/public/cpp/view_tree_connection.h"
24 #include "mojo/application/public/cpp/application_impl.h"
25 #include "mojo/application/public/cpp/connect.h"
26 #include "mojo/application/public/interfaces/shell.mojom.h"
27 #include "mojo/converters/geometry/geometry_type_converters.h"
28 #include "third_party/WebKit/public/web/WebLocalFrame.h"
29 #include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
30 #include "ui/gfx/geometry/dip_util.h"
31 #include "ui/gfx/geometry/size.h"
33 using mojo::AxProvider
;
36 namespace html_viewer
{
39 const char kEnableTestInterface
[] = "enable-html-viewer-test-interface";
41 bool IsTestInterfaceEnabled() {
42 return base::CommandLine::ForCurrentProcess()->HasSwitch(
43 kEnableTestInterface
);
48 // A ViewTreeDelegate implementation that delegates to a (swappable) delegate.
49 // This is used when one HTMLDocumentOOPIF takes over for another delegate
51 class ViewTreeDelegateImpl
: public mojo::ViewTreeDelegate
{
53 explicit ViewTreeDelegateImpl(mojo::ViewTreeDelegate
* delegate
)
54 : delegate_(delegate
) {}
55 ~ViewTreeDelegateImpl() override
{}
57 void set_delegate(mojo::ViewTreeDelegate
* delegate
) { delegate_
= delegate
; }
61 void OnEmbed(mojo::View
* root
) override
{ delegate_
->OnEmbed(root
); }
62 void OnUnembed() override
{ delegate_
->OnUnembed(); }
63 void OnConnectionLost(mojo::ViewTreeConnection
* connection
) override
{
64 delegate_
->OnConnectionLost(connection
);
67 mojo::ViewTreeDelegate
* delegate_
;
69 DISALLOW_COPY_AND_ASSIGN(ViewTreeDelegateImpl
);
72 HTMLDocumentOOPIF::BeforeLoadCache::BeforeLoadCache() {
75 HTMLDocumentOOPIF::BeforeLoadCache::~BeforeLoadCache() {
76 STLDeleteElements(&ax_provider_requests
);
77 STLDeleteElements(&test_interface_requests
);
80 HTMLDocumentOOPIF::TransferableState::TransferableState()
81 : owns_view_tree_connection(false), root(nullptr) {}
83 HTMLDocumentOOPIF::TransferableState::~TransferableState() {}
85 void HTMLDocumentOOPIF::TransferableState::Move(TransferableState
* other
) {
86 owns_view_tree_connection
= other
->owns_view_tree_connection
;
88 view_tree_delegate_impl
= other
->view_tree_delegate_impl
.Pass();
90 other
->root
= nullptr;
91 other
->owns_view_tree_connection
= false;
94 HTMLDocumentOOPIF::HTMLDocumentOOPIF(mojo::ApplicationImpl
* html_document_app
,
95 mojo::ApplicationConnection
* connection
,
96 mojo::URLResponsePtr response
,
97 GlobalState
* global_state
,
98 const DeleteCallback
& delete_callback
,
100 : app_refcount_(html_document_app
->app_lifetime_helper()
101 ->CreateAppRefCount()),
102 html_document_app_(html_document_app
),
103 connection_(connection
),
104 global_state_(global_state
),
106 delete_callback_(delete_callback
),
108 // TODO(sky): nuke headless. We're not going to care about it anymore.
109 DCHECK(!global_state_
->is_headless());
111 connection
->AddService
<web_view::FrameTreeClient
>(this);
112 connection
->AddService
<AxProvider
>(this);
113 connection
->AddService
<mojo::ViewTreeClient
>(this);
114 connection
->AddService
<devtools_service::DevToolsAgent
>(this);
115 if (IsTestInterfaceEnabled())
116 connection
->AddService
<TestHTMLViewer
>(this);
118 resource_waiter_
.reset(
119 new DocumentResourceWaiter(global_state_
, response
.Pass(), this));
122 void HTMLDocumentOOPIF::Destroy() {
123 if (resource_waiter_
) {
124 mojo::View
* root
= resource_waiter_
->root();
126 resource_waiter_
.reset();
127 delete root
->connection();
132 // Closing the frame ends up destroying the ViewManager, which triggers
133 // deleting this (OnConnectionLost()).
135 } else if (transferable_state_
.root
) {
136 // This triggers deleting us.
137 if (transferable_state_
.owns_view_tree_connection
)
138 delete transferable_state_
.root
->connection();
146 HTMLDocumentOOPIF::~HTMLDocumentOOPIF() {
147 delete_callback_
.Run(this);
149 STLDeleteElements(&ax_providers_
);
152 void HTMLDocumentOOPIF::Load() {
153 DCHECK(resource_waiter_
&& resource_waiter_
->is_ready());
155 // Note: |view| is null if we're taking over for an existing frame.
156 mojo::View
* view
= resource_waiter_
->root();
158 global_state_
->InitIfNecessary(
159 view
->viewport_metrics().size_in_pixels
.To
<gfx::Size
>(),
160 view
->viewport_metrics().device_pixel_ratio
);
163 scoped_ptr
<WebURLRequestExtraData
> extra_data(new WebURLRequestExtraData
);
164 extra_data
->synthetic_response
=
165 resource_waiter_
->ReleaseURLResponse().Pass();
167 frame_
= HTMLFrameTreeManager::CreateFrameAndAttachToTree(
168 global_state_
, view
, resource_waiter_
.Pass(), this);
170 // If the frame wasn't created we can destroy ourself.
176 if (devtools_agent_request_
.is_pending()) {
177 if (frame_
->devtools_agent()) {
178 frame_
->devtools_agent()->BindToRequest(devtools_agent_request_
.Pass());
180 devtools_agent_request_
=
181 mojo::InterfaceRequest
<devtools_service::DevToolsAgent
>();
185 const GURL
url(extra_data
->synthetic_response
->url
);
187 blink::WebURLRequest web_request
;
188 web_request
.initialize();
189 web_request
.setURL(url
);
190 web_request
.setExtraData(extra_data
.release());
192 frame_
->web_frame()->toWebLocalFrame()->loadRequest(web_request
);
195 HTMLDocumentOOPIF::BeforeLoadCache
* HTMLDocumentOOPIF::GetBeforeLoadCache() {
196 CHECK(!did_finish_local_frame_load_
);
197 if (!before_load_cache_
.get())
198 before_load_cache_
.reset(new BeforeLoadCache
);
199 return before_load_cache_
.get();
202 void HTMLDocumentOOPIF::OnEmbed(View
* root
) {
203 transferable_state_
.root
= root
;
204 resource_waiter_
->SetRoot(root
);
207 void HTMLDocumentOOPIF::OnConnectionLost(mojo::ViewTreeConnection
* connection
) {
211 void HTMLDocumentOOPIF::OnFrameDidFinishLoad() {
212 did_finish_local_frame_load_
= true;
213 scoped_ptr
<BeforeLoadCache
> before_load_cache
= before_load_cache_
.Pass();
214 if (!before_load_cache
)
217 // Bind any pending AxProvider and TestHTMLViewer interface requests.
218 for (auto it
: before_load_cache
->ax_provider_requests
) {
219 ax_providers_
.insert(new AxProviderImpl(
220 frame_
->frame_tree_manager()->GetWebView(), it
->Pass()));
222 for (auto it
: before_load_cache
->test_interface_requests
) {
223 CHECK(IsTestInterfaceEnabled());
224 test_html_viewers_
.push_back(new TestHTMLViewerImpl(
225 frame_
->web_frame()->toWebLocalFrame(), it
->Pass()));
229 mojo::ApplicationImpl
* HTMLDocumentOOPIF::GetApp() {
230 return html_document_app_
;
233 HTMLFactory
* HTMLDocumentOOPIF::GetHTMLFactory() {
237 void HTMLDocumentOOPIF::OnFrameSwappedToRemote() {
238 // When the frame becomes remote HTMLDocumentOOPIF is no longer needed.
243 void HTMLDocumentOOPIF::OnSwap(HTMLFrame
* frame
,
244 HTMLFrameDelegate
* old_delegate
) {
245 DCHECK(frame
->IsLocal());
246 DCHECK(frame
->view());
248 DCHECK(!transferable_state_
.root
);
250 // We're taking over a child of a local root that isn't associated with a
251 // delegate. In this case the frame's view is not the root of the
252 // ViewTreeConnection.
253 transferable_state_
.owns_view_tree_connection
= false;
254 transferable_state_
.root
= frame
->view();
256 HTMLDocumentOOPIF
* old_document
=
257 static_cast<HTMLDocumentOOPIF
*>(old_delegate
);
258 transferable_state_
.Move(&old_document
->transferable_state_
);
259 if (transferable_state_
.view_tree_delegate_impl
)
260 transferable_state_
.view_tree_delegate_impl
->set_delegate(this);
261 old_document
->frame_
= nullptr;
262 old_document
->Destroy();
266 void HTMLDocumentOOPIF::OnFrameDestroyed() {
267 if (!transferable_state_
.owns_view_tree_connection
)
271 void HTMLDocumentOOPIF::Create(mojo::ApplicationConnection
* connection
,
272 mojo::InterfaceRequest
<AxProvider
> request
) {
273 if (!did_finish_local_frame_load_
) {
274 // Cache AxProvider interface requests until the document finishes loading.
275 auto cached_request
= new mojo::InterfaceRequest
<AxProvider
>();
276 *cached_request
= request
.Pass();
277 GetBeforeLoadCache()->ax_provider_requests
.insert(cached_request
);
279 ax_providers_
.insert(
280 new AxProviderImpl(frame_
->web_view(), request
.Pass()));
284 void HTMLDocumentOOPIF::Create(mojo::ApplicationConnection
* connection
,
285 mojo::InterfaceRequest
<TestHTMLViewer
> request
) {
286 CHECK(IsTestInterfaceEnabled());
287 if (!did_finish_local_frame_load_
) {
288 auto cached_request
= new mojo::InterfaceRequest
<TestHTMLViewer
>();
289 *cached_request
= request
.Pass();
290 GetBeforeLoadCache()->test_interface_requests
.insert(cached_request
);
292 test_html_viewers_
.push_back(new TestHTMLViewerImpl(
293 frame_
->web_frame()->toWebLocalFrame(), request
.Pass()));
297 void HTMLDocumentOOPIF::Create(
298 mojo::ApplicationConnection
* connection
,
299 mojo::InterfaceRequest
<web_view::FrameTreeClient
> request
) {
301 DVLOG(1) << "Request for FrameTreeClient after one already vended.";
304 resource_waiter_
->Bind(request
.Pass());
307 void HTMLDocumentOOPIF::Create(
308 mojo::ApplicationConnection
* connection
,
309 mojo::InterfaceRequest
<devtools_service::DevToolsAgent
> request
) {
311 if (frame_
->devtools_agent())
312 frame_
->devtools_agent()->BindToRequest(request
.Pass());
314 devtools_agent_request_
= request
.Pass();
318 void HTMLDocumentOOPIF::Create(
319 mojo::ApplicationConnection
* connection
,
320 mojo::InterfaceRequest
<mojo::ViewTreeClient
> request
) {
321 DCHECK(!transferable_state_
.view_tree_delegate_impl
);
322 transferable_state_
.view_tree_delegate_impl
.reset(
323 new ViewTreeDelegateImpl(this));
324 transferable_state_
.owns_view_tree_connection
= true;
325 mojo::ViewTreeConnection::Create(
326 transferable_state_
.view_tree_delegate_impl
.get(), request
.Pass());
329 } // namespace html_viewer