Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / components / html_viewer / html_document.cc
blob88f1ae012260b165028db5729d5d9c071a07aacd
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.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/mus/ids.h"
22 #include "components/mus/public/cpp/view.h"
23 #include "components/mus/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;
34 using mus::View;
36 namespace html_viewer {
37 namespace {
39 const char kEnableTestInterface[] = "enable-html-viewer-test-interface";
41 bool IsTestInterfaceEnabled() {
42 return base::CommandLine::ForCurrentProcess()->HasSwitch(
43 kEnableTestInterface);
46 } // namespace
48 // A ViewTreeDelegate implementation that delegates to a (swappable) delegate.
49 // This is used when one HTMLDocument takes over for another delegate
50 // (OnSwap()).
51 class ViewTreeDelegateImpl : public mus::ViewTreeDelegate {
52 public:
53 explicit ViewTreeDelegateImpl(mus::ViewTreeDelegate* delegate)
54 : delegate_(delegate) {}
55 ~ViewTreeDelegateImpl() override {}
57 void set_delegate(mus::ViewTreeDelegate* delegate) { delegate_ = delegate; }
59 private:
60 // ViewTreeDelegate:
61 void OnEmbed(mus::View* root) override { delegate_->OnEmbed(root); }
62 void OnUnembed() override { delegate_->OnUnembed(); }
63 void OnConnectionLost(mus::ViewTreeConnection* connection) override {
64 delegate_->OnConnectionLost(connection);
67 mus::ViewTreeDelegate* delegate_;
69 DISALLOW_COPY_AND_ASSIGN(ViewTreeDelegateImpl);
72 HTMLDocument::BeforeLoadCache::BeforeLoadCache() {}
74 HTMLDocument::BeforeLoadCache::~BeforeLoadCache() {
75 STLDeleteElements(&ax_provider_requests);
76 STLDeleteElements(&test_interface_requests);
79 HTMLDocument::TransferableState::TransferableState()
80 : owns_view_tree_connection(false), root(nullptr) {}
82 HTMLDocument::TransferableState::~TransferableState() {}
84 void HTMLDocument::TransferableState::Move(TransferableState* other) {
85 owns_view_tree_connection = other->owns_view_tree_connection;
86 root = other->root;
87 view_tree_delegate_impl = other->view_tree_delegate_impl.Pass();
89 other->root = nullptr;
90 other->owns_view_tree_connection = false;
93 HTMLDocument::HTMLDocument(mojo::ApplicationImpl* html_document_app,
94 mojo::ApplicationConnection* connection,
95 mojo::URLResponsePtr response,
96 GlobalState* global_state,
97 const DeleteCallback& delete_callback,
98 HTMLFactory* factory)
99 : app_refcount_(html_document_app->app_lifetime_helper()
100 ->CreateAppRefCount()),
101 html_document_app_(html_document_app),
102 connection_(connection),
103 global_state_(global_state),
104 frame_(nullptr),
105 delete_callback_(delete_callback),
106 factory_(factory) {
107 connection->AddService<web_view::mojom::FrameClient>(this);
108 connection->AddService<AxProvider>(this);
109 connection->AddService<mojo::ViewTreeClient>(this);
110 connection->AddService<devtools_service::DevToolsAgent>(this);
111 if (IsTestInterfaceEnabled())
112 connection->AddService<TestHTMLViewer>(this);
114 resource_waiter_.reset(
115 new DocumentResourceWaiter(global_state_, response.Pass(), this));
118 void HTMLDocument::Destroy() {
119 if (resource_waiter_) {
120 mus::View* root = resource_waiter_->root();
121 if (root) {
122 resource_waiter_.reset();
123 delete root->connection();
124 } else {
125 delete this;
127 } else if (frame_) {
128 // Closing the frame ends up destroying the ViewManager, which triggers
129 // deleting this (OnConnectionLost()).
130 frame_->Close();
131 } else if (transferable_state_.root) {
132 // This triggers deleting us.
133 if (transferable_state_.owns_view_tree_connection)
134 delete transferable_state_.root->connection();
135 else
136 delete this;
137 } else {
138 delete this;
142 HTMLDocument::~HTMLDocument() {
143 delete_callback_.Run(this);
145 STLDeleteElements(&ax_providers_);
148 void HTMLDocument::Load() {
149 DCHECK(resource_waiter_ && resource_waiter_->is_ready());
151 // Note: |view| is null if we're taking over for an existing frame.
152 mus::View* view = resource_waiter_->root();
153 if (view) {
154 global_state_->InitIfNecessary(
155 view->viewport_metrics().size_in_pixels.To<gfx::Size>(),
156 view->viewport_metrics().device_pixel_ratio);
159 scoped_ptr<WebURLRequestExtraData> extra_data(new WebURLRequestExtraData);
160 extra_data->synthetic_response =
161 resource_waiter_->ReleaseURLResponse().Pass();
163 frame_ = HTMLFrameTreeManager::CreateFrameAndAttachToTree(
164 global_state_, view, resource_waiter_.Pass(), this);
166 // If the frame wasn't created we can destroy ourself.
167 if (!frame_) {
168 Destroy();
169 return;
172 if (devtools_agent_request_.is_pending()) {
173 if (frame_->devtools_agent()) {
174 frame_->devtools_agent()->BindToRequest(devtools_agent_request_.Pass());
175 } else {
176 devtools_agent_request_ =
177 mojo::InterfaceRequest<devtools_service::DevToolsAgent>();
181 const GURL url(extra_data->synthetic_response->url);
183 blink::WebURLRequest web_request;
184 web_request.initialize();
185 web_request.setURL(url);
186 web_request.setExtraData(extra_data.release());
188 frame_->web_frame()->toWebLocalFrame()->loadRequest(web_request);
191 HTMLDocument::BeforeLoadCache* HTMLDocument::GetBeforeLoadCache() {
192 CHECK(!did_finish_local_frame_load_);
193 if (!before_load_cache_.get())
194 before_load_cache_.reset(new BeforeLoadCache);
195 return before_load_cache_.get();
198 void HTMLDocument::OnEmbed(View* root) {
199 transferable_state_.root = root;
200 resource_waiter_->SetRoot(root);
203 void HTMLDocument::OnConnectionLost(mus::ViewTreeConnection* connection) {
204 delete this;
207 void HTMLDocument::OnFrameDidFinishLoad() {
208 did_finish_local_frame_load_ = true;
209 scoped_ptr<BeforeLoadCache> before_load_cache = before_load_cache_.Pass();
210 if (!before_load_cache)
211 return;
213 // Bind any pending AxProvider and TestHTMLViewer interface requests.
214 for (auto it : before_load_cache->ax_provider_requests) {
215 ax_providers_.insert(new AxProviderImpl(
216 frame_->frame_tree_manager()->GetWebView(), it->Pass()));
218 for (auto it : before_load_cache->test_interface_requests) {
219 CHECK(IsTestInterfaceEnabled());
220 test_html_viewers_.push_back(new TestHTMLViewerImpl(
221 frame_->web_frame()->toWebLocalFrame(), it->Pass()));
225 mojo::ApplicationImpl* HTMLDocument::GetApp() {
226 return html_document_app_;
229 HTMLFactory* HTMLDocument::GetHTMLFactory() {
230 return factory_;
233 void HTMLDocument::OnFrameSwappedToRemote() {
234 // When the frame becomes remote HTMLDocument is no longer needed.
235 frame_ = nullptr;
236 Destroy();
239 void HTMLDocument::OnSwap(HTMLFrame* frame, HTMLFrameDelegate* old_delegate) {
240 DCHECK(frame->IsLocal());
241 DCHECK(frame->view());
242 DCHECK(!frame_);
243 DCHECK(!transferable_state_.root);
244 if (!old_delegate) {
245 // We're taking over a child of a local root that isn't associated with a
246 // delegate. In this case the frame's view is not the root of the
247 // ViewTreeConnection.
248 transferable_state_.owns_view_tree_connection = false;
249 transferable_state_.root = frame->view();
250 } else {
251 HTMLDocument* old_document = static_cast<HTMLDocument*>(old_delegate);
252 transferable_state_.Move(&old_document->transferable_state_);
253 if (transferable_state_.view_tree_delegate_impl)
254 transferable_state_.view_tree_delegate_impl->set_delegate(this);
255 old_document->frame_ = nullptr;
256 old_document->Destroy();
260 void HTMLDocument::OnFrameDestroyed() {
261 if (!transferable_state_.owns_view_tree_connection)
262 delete this;
265 void HTMLDocument::Create(mojo::ApplicationConnection* connection,
266 mojo::InterfaceRequest<AxProvider> request) {
267 if (!did_finish_local_frame_load_) {
268 // Cache AxProvider interface requests until the document finishes loading.
269 auto cached_request = new mojo::InterfaceRequest<AxProvider>();
270 *cached_request = request.Pass();
271 GetBeforeLoadCache()->ax_provider_requests.insert(cached_request);
272 } else {
273 ax_providers_.insert(
274 new AxProviderImpl(frame_->web_view(), request.Pass()));
278 void HTMLDocument::Create(mojo::ApplicationConnection* connection,
279 mojo::InterfaceRequest<TestHTMLViewer> request) {
280 CHECK(IsTestInterfaceEnabled());
281 if (!did_finish_local_frame_load_) {
282 auto cached_request = new mojo::InterfaceRequest<TestHTMLViewer>();
283 *cached_request = request.Pass();
284 GetBeforeLoadCache()->test_interface_requests.insert(cached_request);
285 } else {
286 test_html_viewers_.push_back(new TestHTMLViewerImpl(
287 frame_->web_frame()->toWebLocalFrame(), request.Pass()));
291 void HTMLDocument::Create(
292 mojo::ApplicationConnection* connection,
293 mojo::InterfaceRequest<web_view::mojom::FrameClient> request) {
294 if (frame_) {
295 DVLOG(1) << "Request for FrameClient after one already vended.";
296 return;
298 resource_waiter_->Bind(request.Pass());
301 void HTMLDocument::Create(
302 mojo::ApplicationConnection* connection,
303 mojo::InterfaceRequest<devtools_service::DevToolsAgent> request) {
304 if (frame_) {
305 if (frame_->devtools_agent())
306 frame_->devtools_agent()->BindToRequest(request.Pass());
307 } else {
308 devtools_agent_request_ = request.Pass();
312 void HTMLDocument::Create(
313 mojo::ApplicationConnection* connection,
314 mojo::InterfaceRequest<mojo::ViewTreeClient> request) {
315 DCHECK(!transferable_state_.view_tree_delegate_impl);
316 transferable_state_.view_tree_delegate_impl.reset(
317 new ViewTreeDelegateImpl(this));
318 transferable_state_.owns_view_tree_connection = true;
319 mus::ViewTreeConnection::Create(
320 transferable_state_.view_tree_delegate_impl.get(), request.Pass());
323 } // namespace html_viewer