OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "components/html_viewer/html_document.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "base/command_line.h" | |
10 #include "base/macros.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/single_thread_task_runner.h" | |
13 #include "base/stl_util.h" | |
14 #include "base/strings/string_util.h" | |
15 #include "base/thread_task_runner_handle.h" | |
16 #include "base/time/time.h" | |
17 #include "components/html_viewer/blink_url_request_type_converters.h" | |
18 #include "components/html_viewer/devtools_agent_impl.h" | |
19 #include "components/html_viewer/document_resource_waiter.h" | |
20 #include "components/html_viewer/global_state.h" | |
21 #include "components/html_viewer/html_frame.h" | |
22 #include "components/html_viewer/html_frame_tree_manager.h" | |
23 #include "components/html_viewer/test_html_viewer_impl.h" | |
24 #include "components/html_viewer/web_url_loader_impl.h" | |
25 #include "components/mus/public/cpp/window.h" | |
26 #include "components/mus/public/cpp/window_tree_connection.h" | |
27 #include "components/mus/ws/ids.h" | |
28 #include "mojo/converters/geometry/geometry_type_converters.h" | |
29 #include "mojo/public/cpp/system/data_pipe.h" | |
30 #include "mojo/shell/public/cpp/application_impl.h" | |
31 #include "mojo/shell/public/interfaces/shell.mojom.h" | |
32 #include "third_party/WebKit/public/web/WebLocalFrame.h" | |
33 #include "ui/gfx/geometry/dip_util.h" | |
34 #include "ui/gfx/geometry/size.h" | |
35 | |
36 using mojo::AxProvider; | |
37 using mus::Window; | |
38 | |
39 namespace html_viewer { | |
40 namespace { | |
41 | |
42 const char kEnableTestInterface[] = "enable-html-viewer-test-interface"; | |
43 | |
44 bool IsTestInterfaceEnabled() { | |
45 return base::CommandLine::ForCurrentProcess()->HasSwitch( | |
46 kEnableTestInterface); | |
47 } | |
48 | |
49 } // namespace | |
50 | |
51 // A WindowTreeDelegate implementation that delegates to a (swappable) delegate. | |
52 // This is used when one HTMLDocument takes over for another delegate | |
53 // (OnSwap()). | |
54 class WindowTreeDelegateImpl : public mus::WindowTreeDelegate { | |
55 public: | |
56 explicit WindowTreeDelegateImpl(mus::WindowTreeDelegate* delegate) | |
57 : delegate_(delegate) {} | |
58 ~WindowTreeDelegateImpl() override {} | |
59 | |
60 void set_delegate(mus::WindowTreeDelegate* delegate) { delegate_ = delegate; } | |
61 | |
62 private: | |
63 // WindowTreeDelegate: | |
64 void OnEmbed(mus::Window* root) override { delegate_->OnEmbed(root); } | |
65 void OnUnembed(mus::Window* root) override { delegate_->OnUnembed(root); } | |
66 void OnConnectionLost(mus::WindowTreeConnection* connection) override { | |
67 delegate_->OnConnectionLost(connection); | |
68 } | |
69 | |
70 mus::WindowTreeDelegate* delegate_; | |
71 | |
72 DISALLOW_COPY_AND_ASSIGN(WindowTreeDelegateImpl); | |
73 }; | |
74 | |
75 HTMLDocument::BeforeLoadCache::BeforeLoadCache() {} | |
76 | |
77 HTMLDocument::BeforeLoadCache::~BeforeLoadCache() { | |
78 STLDeleteElements(&ax_provider_requests); | |
79 STLDeleteElements(&test_interface_requests); | |
80 } | |
81 | |
82 HTMLDocument::TransferableState::TransferableState() | |
83 : owns_window_tree_connection(false), root(nullptr) {} | |
84 | |
85 HTMLDocument::TransferableState::~TransferableState() {} | |
86 | |
87 void HTMLDocument::TransferableState::Move(TransferableState* other) { | |
88 owns_window_tree_connection = other->owns_window_tree_connection; | |
89 root = other->root; | |
90 window_tree_delegate_impl = std::move(other->window_tree_delegate_impl); | |
91 | |
92 other->root = nullptr; | |
93 other->owns_window_tree_connection = false; | |
94 } | |
95 | |
96 HTMLDocument::HTMLDocument(mojo::Shell* html_document_shell, | |
97 mojo::Connection* connection, | |
98 mojo::URLResponsePtr response, | |
99 GlobalState* global_state, | |
100 const DeleteCallback& delete_callback, | |
101 HTMLFactory* factory) | |
102 : app_refcount_(html_document_shell->CreateAppRefCount()), | |
103 html_document_shell_(html_document_shell), | |
104 connection_(connection), | |
105 global_state_(global_state), | |
106 frame_(nullptr), | |
107 delete_callback_(delete_callback), | |
108 factory_(factory) { | |
109 connection->AddService<web_view::mojom::FrameClient>(this); | |
110 connection->AddService<AxProvider>(this); | |
111 connection->AddService<mus::mojom::WindowTreeClient>(this); | |
112 connection->AddService<devtools_service::DevToolsAgent>(this); | |
113 if (IsTestInterfaceEnabled()) | |
114 connection->AddService<TestHTMLViewer>(this); | |
115 | |
116 resource_waiter_.reset( | |
117 new DocumentResourceWaiter(global_state_, std::move(response), this)); | |
118 } | |
119 | |
120 void HTMLDocument::Destroy() { | |
121 TRACE_EVENT0("html_viewer", "HTMLDocument::Destroy"); | |
122 if (resource_waiter_) { | |
123 mus::Window* root = resource_waiter_->root(); | |
124 if (root) { | |
125 resource_waiter_.reset(); | |
126 delete root->connection(); | |
127 } else { | |
128 delete this; | |
129 } | |
130 } else if (frame_) { | |
131 // Closing the frame ends up destroying the ViewManager, which triggers | |
132 // deleting this (OnConnectionLost()). | |
133 frame_->Close(); | |
134 } else if (transferable_state_.root) { | |
135 // This triggers deleting us. | |
136 if (transferable_state_.owns_window_tree_connection) | |
137 delete transferable_state_.root->connection(); | |
138 else | |
139 delete this; | |
140 } else { | |
141 delete this; | |
142 } | |
143 } | |
144 | |
145 HTMLDocument::~HTMLDocument() { | |
146 delete_callback_.Run(this); | |
147 | |
148 STLDeleteElements(&ax_providers_); | |
149 } | |
150 | |
151 void HTMLDocument::Load() { | |
152 TRACE_EVENT0("html_viewer", "HTMLDocument::Load"); | |
153 DCHECK(resource_waiter_ && resource_waiter_->is_ready()); | |
154 | |
155 // Note: |window| is null if we're taking over for an existing frame. | |
156 mus::Window* window = resource_waiter_->root(); | |
157 if (window) { | |
158 global_state_->InitIfNecessary( | |
159 window->viewport_metrics().size_in_pixels.To<gfx::Size>(), | |
160 window->viewport_metrics().device_pixel_ratio); | |
161 } | |
162 | |
163 scoped_ptr<WebURLRequestExtraData> extra_data(new WebURLRequestExtraData); | |
164 extra_data->synthetic_response = resource_waiter_->ReleaseURLResponse(); | |
165 | |
166 base::TimeTicks navigation_start_time = | |
167 resource_waiter_->navigation_start_time(); | |
168 frame_ = HTMLFrameTreeManager::CreateFrameAndAttachToTree( | |
169 global_state_, window, std::move(resource_waiter_), this); | |
170 | |
171 // If the frame wasn't created we can destroy ourself. | |
172 if (!frame_) { | |
173 Destroy(); | |
174 return; | |
175 } | |
176 | |
177 if (devtools_agent_request_.is_pending()) { | |
178 if (frame_->devtools_agent()) { | |
179 frame_->devtools_agent()->BindToRequest( | |
180 std::move(devtools_agent_request_)); | |
181 } else { | |
182 devtools_agent_request_ = | |
183 mojo::InterfaceRequest<devtools_service::DevToolsAgent>(); | |
184 } | |
185 } | |
186 | |
187 const GURL url(extra_data->synthetic_response->url.get()); | |
188 | |
189 blink::WebURLRequest web_request; | |
190 web_request.initialize(); | |
191 web_request.setURL(url); | |
192 web_request.setExtraData(extra_data.release()); | |
193 | |
194 frame_->LoadRequest(web_request, navigation_start_time); | |
195 } | |
196 | |
197 HTMLDocument::BeforeLoadCache* HTMLDocument::GetBeforeLoadCache() { | |
198 CHECK(!did_finish_local_frame_load_); | |
199 if (!before_load_cache_.get()) | |
200 before_load_cache_.reset(new BeforeLoadCache); | |
201 return before_load_cache_.get(); | |
202 } | |
203 | |
204 void HTMLDocument::OnEmbed(Window* root) { | |
205 transferable_state_.root = root; | |
206 resource_waiter_->SetRoot(root); | |
207 } | |
208 | |
209 void HTMLDocument::OnConnectionLost(mus::WindowTreeConnection* connection) { | |
210 delete this; | |
211 } | |
212 | |
213 void HTMLDocument::OnFrameDidFinishLoad() { | |
214 TRACE_EVENT0("html_viewer", "HTMLDocument::OnFrameDidFinishLoad"); | |
215 did_finish_local_frame_load_ = true; | |
216 scoped_ptr<BeforeLoadCache> before_load_cache = std::move(before_load_cache_); | |
217 if (!before_load_cache) | |
218 return; | |
219 | |
220 // Bind any pending AxProvider and TestHTMLViewer interface requests. | |
221 for (auto it : before_load_cache->ax_provider_requests) { | |
222 ax_providers_.insert(new AxProviderImpl( | |
223 frame_->frame_tree_manager()->GetWebView(), std::move(*it))); | |
224 } | |
225 for (auto it : before_load_cache->test_interface_requests) { | |
226 CHECK(IsTestInterfaceEnabled()); | |
227 test_html_viewers_.push_back(new TestHTMLViewerImpl( | |
228 frame_->web_frame()->toWebLocalFrame(), std::move(*it))); | |
229 } | |
230 } | |
231 | |
232 mojo::Shell* HTMLDocument::GetShell() { | |
233 return html_document_shell_; | |
234 } | |
235 | |
236 HTMLFactory* HTMLDocument::GetHTMLFactory() { | |
237 return factory_; | |
238 } | |
239 | |
240 void HTMLDocument::OnFrameSwappedToRemote() { | |
241 // When the frame becomes remote HTMLDocument is no longer needed. | |
242 frame_ = nullptr; | |
243 Destroy(); | |
244 } | |
245 | |
246 void HTMLDocument::OnSwap(HTMLFrame* frame, HTMLFrameDelegate* old_delegate) { | |
247 TRACE_EVENT0("html_viewer", "HTMLDocument::OnSwap"); | |
248 DCHECK(frame->IsLocal()); | |
249 DCHECK(frame->window()); | |
250 DCHECK(!frame_); | |
251 DCHECK(!transferable_state_.root); | |
252 if (!old_delegate) { | |
253 // We're taking over a child of a local root that isn't associated with a | |
254 // delegate. In this case the frame's window is not the root of the | |
255 // WindowTreeConnection. | |
256 transferable_state_.owns_window_tree_connection = false; | |
257 transferable_state_.root = frame->window(); | |
258 } else { | |
259 HTMLDocument* old_document = static_cast<HTMLDocument*>(old_delegate); | |
260 transferable_state_.Move(&old_document->transferable_state_); | |
261 if (transferable_state_.window_tree_delegate_impl) | |
262 transferable_state_.window_tree_delegate_impl->set_delegate(this); | |
263 old_document->frame_ = nullptr; | |
264 old_document->Destroy(); | |
265 } | |
266 } | |
267 | |
268 void HTMLDocument::OnFrameDestroyed() { | |
269 if (!transferable_state_.owns_window_tree_connection) | |
270 delete this; | |
271 } | |
272 | |
273 void HTMLDocument::Create(mojo::Connection* connection, | |
274 mojo::InterfaceRequest<AxProvider> request) { | |
275 if (!did_finish_local_frame_load_) { | |
276 // Cache AxProvider interface requests until the document finishes loading. | |
277 auto cached_request = new mojo::InterfaceRequest<AxProvider>(); | |
278 *cached_request = std::move(request); | |
279 GetBeforeLoadCache()->ax_provider_requests.insert(cached_request); | |
280 } else { | |
281 ax_providers_.insert( | |
282 new AxProviderImpl(frame_->web_view(), std::move(request))); | |
283 } | |
284 } | |
285 | |
286 void HTMLDocument::Create(mojo::Connection* connection, | |
287 mojo::InterfaceRequest<TestHTMLViewer> request) { | |
288 CHECK(IsTestInterfaceEnabled()); | |
289 if (!did_finish_local_frame_load_) { | |
290 auto cached_request = new mojo::InterfaceRequest<TestHTMLViewer>(); | |
291 *cached_request = std::move(request); | |
292 GetBeforeLoadCache()->test_interface_requests.insert(cached_request); | |
293 } else { | |
294 test_html_viewers_.push_back(new TestHTMLViewerImpl( | |
295 frame_->web_frame()->toWebLocalFrame(), std::move(request))); | |
296 } | |
297 } | |
298 | |
299 void HTMLDocument::Create( | |
300 mojo::Connection* connection, | |
301 mojo::InterfaceRequest<web_view::mojom::FrameClient> request) { | |
302 if (frame_) { | |
303 DVLOG(1) << "Request for FrameClient after one already vended."; | |
304 return; | |
305 } | |
306 resource_waiter_->Bind(std::move(request)); | |
307 } | |
308 | |
309 void HTMLDocument::Create( | |
310 mojo::Connection* connection, | |
311 mojo::InterfaceRequest<devtools_service::DevToolsAgent> request) { | |
312 if (frame_) { | |
313 if (frame_->devtools_agent()) | |
314 frame_->devtools_agent()->BindToRequest(std::move(request)); | |
315 } else { | |
316 devtools_agent_request_ = std::move(request); | |
317 } | |
318 } | |
319 | |
320 void HTMLDocument::Create( | |
321 mojo::Connection* connection, | |
322 mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request) { | |
323 DCHECK(!transferable_state_.window_tree_delegate_impl); | |
324 transferable_state_.window_tree_delegate_impl.reset( | |
325 new WindowTreeDelegateImpl(this)); | |
326 transferable_state_.owns_window_tree_connection = true; | |
327 mus::WindowTreeConnection::Create( | |
328 transferable_state_.window_tree_delegate_impl.get(), std::move(request), | |
329 mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED); | |
330 } | |
331 | |
332 } // namespace html_viewer | |
OLD | NEW |