| 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 |