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/devtools_service/public/cpp/switches.h"
14 #include "components/html_viewer/blink_url_request_type_converters.h"
15 #include "components/html_viewer/devtools_agent_impl.h"
16 #include "components/html_viewer/document_resource_waiter.h"
17 #include "components/html_viewer/frame.h"
18 #include "components/html_viewer/frame_tree_manager.h"
19 #include "components/html_viewer/global_state.h"
20 #include "components/html_viewer/test_html_viewer_impl.h"
21 #include "components/html_viewer/web_url_loader_impl.h"
22 #include "components/view_manager/ids.h"
23 #include "components/view_manager/public/cpp/view.h"
24 #include "components/view_manager/public/cpp/view_manager.h"
25 #include "mojo/application/public/cpp/application_impl.h"
26 #include "mojo/application/public/cpp/connect.h"
27 #include "mojo/application/public/interfaces/shell.mojom.h"
28 #include "mojo/converters/geometry/geometry_type_converters.h"
29 #include "third_party/WebKit/public/web/WebLocalFrame.h"
30 #include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
31 #include "ui/gfx/geometry/dip_util.h"
32 #include "ui/gfx/geometry/size.h"
34 using mojo::AxProvider
;
37 namespace html_viewer
{
40 const char kEnableTestInterface
[] = "enable-html-viewer-test-interface";
42 bool IsTestInterfaceEnabled() {
43 return base::CommandLine::ForCurrentProcess()->HasSwitch(
44 kEnableTestInterface
);
47 bool EnableRemoteDebugging() {
48 return base::CommandLine::ForCurrentProcess()->HasSwitch(
49 devtools_service::kRemoteDebuggingPort
);
54 HTMLDocumentOOPIF::BeforeLoadCache::BeforeLoadCache() {
57 HTMLDocumentOOPIF::BeforeLoadCache::~BeforeLoadCache() {
58 STLDeleteElements(&ax_provider_requests
);
59 STLDeleteElements(&test_interface_requests
);
62 HTMLDocumentOOPIF::HTMLDocumentOOPIF(mojo::ApplicationImpl
* html_document_app
,
63 mojo::ApplicationConnection
* connection
,
64 mojo::URLResponsePtr response
,
65 GlobalState
* global_state
,
66 const DeleteCallback
& delete_callback
)
68 html_document_app
->app_lifetime_helper()->CreateAppRefCount()),
69 html_document_app_(html_document_app
),
70 connection_(connection
),
71 view_manager_client_factory_(html_document_app
->shell(), this),
72 global_state_(global_state
),
73 delete_callback_(delete_callback
) {
74 // TODO(sky): nuke headless. We're not going to care about it anymore.
75 DCHECK(!global_state_
->is_headless());
77 connection
->AddService(
78 static_cast<mojo::InterfaceFactory
<mandoline::FrameTreeClient
>*>(this));
79 connection
->AddService(static_cast<InterfaceFactory
<AxProvider
>*>(this));
80 connection
->AddService(&view_manager_client_factory_
);
81 if (IsTestInterfaceEnabled()) {
82 connection
->AddService(
83 static_cast<mojo::InterfaceFactory
<TestHTMLViewer
>*>(this));
86 resource_waiter_
.reset(
87 new DocumentResourceWaiter(global_state_
, response
.Pass(), this));
91 void HTMLDocumentOOPIF::Destroy() {
92 if (resource_waiter_
) {
93 mojo::View
* root
= resource_waiter_
->root();
95 root
->RemoveObserver(this);
96 resource_waiter_
.reset();
97 delete root
->view_manager();
102 DCHECK(frame_tree_manager_
);
103 mojo::ViewManager
* view_manager
=
104 frame_tree_manager_
->GetLocalFrame()->view()->view_manager();
105 frame_tree_manager_
.reset();
107 // Delete the ViewManager, which will trigger deleting us.
112 HTMLDocumentOOPIF::~HTMLDocumentOOPIF() {
113 delete_callback_
.Run(this);
115 STLDeleteElements(&ax_providers_
);
118 void HTMLDocumentOOPIF::LoadIfNecessary() {
119 if (!frame_tree_manager_
&& resource_waiter_
->IsReady())
123 void HTMLDocumentOOPIF::Load() {
124 DCHECK(resource_waiter_
&& resource_waiter_
->IsReady());
126 mojo::View
* view
= resource_waiter_
->root();
127 global_state_
->InitIfNecessary(
128 view
->viewport_metrics().size_in_pixels
.To
<gfx::Size
>(),
129 view
->viewport_metrics().device_pixel_ratio
);
131 mojo::InterfaceRequest
<mandoline::FrameTreeClient
> frame_tree_client_request
;
132 mandoline::FrameTreeServerPtr frame_tree_server
;
133 mojo::Array
<mandoline::FrameDataPtr
> frame_data
;
134 mojo::URLResponsePtr response
;
135 resource_waiter_
->Release(&frame_tree_client_request
, &frame_tree_server
,
136 &frame_data
, &response
);
137 resource_waiter_
.reset();
139 view
->RemoveObserver(this);
141 frame_tree_manager_
.reset(
142 new FrameTreeManager(global_state_
, html_document_app_
, connection_
,
143 view
->id(), frame_tree_server
.Pass()));
144 frame_tree_manager_
->set_delegate(this);
145 frame_tree_manager_binding_
.reset(
146 new mojo::Binding
<mandoline::FrameTreeClient
>(
147 frame_tree_manager_
.get(), frame_tree_client_request
.Pass()));
148 frame_tree_manager_
->Init(view
, frame_data
.Pass());
150 // TODO(yzshen): http://crbug.com/498986 Creating DevToolsAgentImpl instances
151 // causes html_viewer_apptests flakiness currently. Before we fix that we
152 // cannot enable remote debugging (which is required by Telemetry tests) on
154 if (EnableRemoteDebugging()) {
155 Frame
* frame
= frame_tree_manager_
->GetLocalFrame();
156 if (!frame
->parent()) {
157 devtools_agent_
.reset(new DevToolsAgentImpl(
158 frame
->web_frame()->toWebLocalFrame(), html_document_app_
->shell()));
162 WebURLRequestExtraData
* extra_data
= new WebURLRequestExtraData
;
163 extra_data
->synthetic_response
= response
.Pass();
165 const GURL
url(extra_data
->synthetic_response
->url
);
167 blink::WebURLRequest web_request
;
168 web_request
.initialize();
169 web_request
.setURL(url
);
170 web_request
.setExtraData(extra_data
);
172 frame_tree_manager_
->GetLocalWebFrame()->loadRequest(web_request
);
175 HTMLDocumentOOPIF::BeforeLoadCache
* HTMLDocumentOOPIF::GetBeforeLoadCache() {
176 CHECK(!did_finish_local_frame_load_
);
177 if (!before_load_cache_
.get())
178 before_load_cache_
.reset(new BeforeLoadCache
);
179 return before_load_cache_
.get();
182 void HTMLDocumentOOPIF::OnEmbed(View
* root
) {
183 // We're an observer until the document is loaded.
184 root
->AddObserver(this);
185 resource_waiter_
->set_root(root
);
190 void HTMLDocumentOOPIF::OnViewManagerDestroyed(
191 mojo::ViewManager
* view_manager
) {
195 void HTMLDocumentOOPIF::OnViewViewportMetricsChanged(
197 const mojo::ViewportMetrics
& old_metrics
,
198 const mojo::ViewportMetrics
& new_metrics
) {
202 void HTMLDocumentOOPIF::OnViewDestroyed(View
* view
) {
203 resource_waiter_
->root()->RemoveObserver(this);
204 resource_waiter_
->set_root(nullptr);
207 bool HTMLDocumentOOPIF::ShouldNavigateLocallyInMainFrame() {
208 return devtools_agent_
&& devtools_agent_
->handling_page_navigate_request();
211 void HTMLDocumentOOPIF::OnFrameDidFinishLoad(Frame
* frame
) {
212 // TODO(msw): Notify AxProvider clients of updates on child frame loads.
213 if (frame_tree_manager_
&&
214 frame
!= frame_tree_manager_
->GetLocalFrame()) {
218 did_finish_local_frame_load_
= true;
219 scoped_ptr
<BeforeLoadCache
> before_load_cache
= before_load_cache_
.Pass();
220 if (!before_load_cache
)
223 // Bind any pending AxProvider and TestHTMLViewer interface requests.
224 for (auto it
: before_load_cache
->ax_provider_requests
) {
225 ax_providers_
.insert(
226 new AxProviderImpl(frame_tree_manager_
->GetWebView(), it
->Pass()));
228 for (auto it
: before_load_cache
->test_interface_requests
) {
229 CHECK(IsTestInterfaceEnabled());
230 test_html_viewers_
.push_back(new TestHTMLViewerImpl(
231 frame_tree_manager_
->GetLocalWebFrame(), it
->Pass()));
235 void HTMLDocumentOOPIF::Create(mojo::ApplicationConnection
* connection
,
236 mojo::InterfaceRequest
<AxProvider
> request
) {
237 if (!did_finish_local_frame_load_
) {
238 // Cache AxProvider interface requests until the document finishes loading.
239 auto cached_request
= new mojo::InterfaceRequest
<AxProvider
>();
240 *cached_request
= request
.Pass();
241 GetBeforeLoadCache()->ax_provider_requests
.insert(cached_request
);
243 ax_providers_
.insert(new AxProviderImpl(
244 frame_tree_manager_
->GetLocalFrame()->web_view(), request
.Pass()));
248 void HTMLDocumentOOPIF::Create(mojo::ApplicationConnection
* connection
,
249 mojo::InterfaceRequest
<TestHTMLViewer
> request
) {
250 CHECK(IsTestInterfaceEnabled());
251 if (!did_finish_local_frame_load_
) {
252 auto cached_request
= new mojo::InterfaceRequest
<TestHTMLViewer
>();
253 *cached_request
= request
.Pass();
254 GetBeforeLoadCache()->test_interface_requests
.insert(cached_request
);
256 test_html_viewers_
.push_back(new TestHTMLViewerImpl(
257 frame_tree_manager_
->GetLocalWebFrame(), request
.Pass()));
261 void HTMLDocumentOOPIF::Create(
262 mojo::ApplicationConnection
* connection
,
263 mojo::InterfaceRequest
<mandoline::FrameTreeClient
> request
) {
264 if (frame_tree_manager_
.get() || frame_tree_manager_binding_
.get()) {
265 DVLOG(1) << "Request for FrameTreeClient after one already vended.";
268 resource_waiter_
->Bind(request
.Pass());
271 } // namespace html_viewer