OLD | NEW |
| (Empty) |
1 // Copyright 2015 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_application_delegate.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/macros.h" | |
11 #include "components/html_viewer/global_state.h" | |
12 #include "components/html_viewer/html_document.h" | |
13 #include "mojo/shell/public/cpp/shell_client.h" | |
14 | |
15 namespace html_viewer { | |
16 | |
17 // ServiceConnectorQueue records all incoming service requests and processes | |
18 // them once PushRequestsTo() is called. This is useful if you need to delay | |
19 // processing incoming service requests. | |
20 class HTMLDocumentApplicationDelegate::ServiceConnectorQueue | |
21 : public mojo::ServiceConnector { | |
22 public: | |
23 ServiceConnectorQueue() {} | |
24 ~ServiceConnectorQueue() override {} | |
25 | |
26 void PushRequestsTo(mojo::Connection* connection) { | |
27 ScopedVector<Request> requests; | |
28 requests_.swap(requests); | |
29 for (Request* request : requests) { | |
30 connection->GetLocalServiceProvider()->ConnectToService( | |
31 request->interface_name, std::move(request->handle)); | |
32 } | |
33 } | |
34 | |
35 private: | |
36 struct Request { | |
37 std::string interface_name; | |
38 mojo::ScopedMessagePipeHandle handle; | |
39 }; | |
40 | |
41 // mojo::ServiceConnector: | |
42 void ConnectToService(mojo::Connection* connection, | |
43 const std::string& interface_name, | |
44 mojo::ScopedMessagePipeHandle handle) override { | |
45 scoped_ptr<Request> request(new Request); | |
46 request->interface_name = interface_name; | |
47 request->handle = std::move(handle); | |
48 requests_.push_back(std::move(request)); | |
49 } | |
50 | |
51 ScopedVector<Request> requests_; | |
52 | |
53 DISALLOW_COPY_AND_ASSIGN(ServiceConnectorQueue); | |
54 }; | |
55 | |
56 HTMLDocumentApplicationDelegate::HTMLDocumentApplicationDelegate( | |
57 mojo::ApplicationRequest request, | |
58 mojo::URLResponsePtr response, | |
59 GlobalState* global_state, | |
60 scoped_ptr<mojo::AppRefCount> parent_app_refcount, | |
61 const mojo::Callback<void()>& destruct_callback) | |
62 : app_(this, | |
63 std::move(request), | |
64 base::Bind(&HTMLDocumentApplicationDelegate::OnTerminate, | |
65 base::Unretained(this))), | |
66 parent_app_refcount_(std::move(parent_app_refcount)), | |
67 url_(response->url), | |
68 initial_response_(std::move(response)), | |
69 global_state_(global_state), | |
70 html_factory_(this), | |
71 destruct_callback_(destruct_callback), | |
72 weak_factory_(this) {} | |
73 | |
74 HTMLDocumentApplicationDelegate::~HTMLDocumentApplicationDelegate() { | |
75 // Deleting the documents is going to trigger a callback to | |
76 // OnHTMLDocumentDeleted() and remove from |documents_|. Copy the set so we | |
77 // don't have to worry about the set being modified out from under us. | |
78 std::set<HTMLDocument*> documents2(documents2_); | |
79 for (HTMLDocument* doc : documents2) | |
80 doc->Destroy(); | |
81 DCHECK(documents2_.empty()); | |
82 destruct_callback_.Run(); | |
83 } | |
84 | |
85 // Callback from the quit closure. We key off this rather than | |
86 // mojo::ShellClient::Quit() as we don't want to shut down the messageloop | |
87 // when we quit (the messageloop is shared among multiple | |
88 // HTMLDocumentApplicationDelegates). | |
89 void HTMLDocumentApplicationDelegate::OnTerminate() { | |
90 delete this; | |
91 } | |
92 | |
93 // mojo::ShellClient; | |
94 void HTMLDocumentApplicationDelegate::Initialize(mojo::Shell* shell, | |
95 const std::string& url, | |
96 uint32_t id) { | |
97 app_.ConnectToService("mojo:network_service", &url_loader_factory_); | |
98 } | |
99 | |
100 bool HTMLDocumentApplicationDelegate::AcceptConnection( | |
101 mojo::Connection* connection) { | |
102 if (initial_response_) { | |
103 OnResponseReceived(nullptr, mojo::URLLoaderPtr(), connection, nullptr, | |
104 std::move(initial_response_)); | |
105 } else if (url_ == "about:blank") { | |
106 // This is a little unfortunate. At the browser side, when starting a new | |
107 // app for "about:blank", the application manager uses | |
108 // mojo::shell::AboutFetcher to construct a response for "about:blank". | |
109 // However, when an app for "about:blank" already exists, it is reused and | |
110 // we end up here. We cannot fetch the URL using mojo::URLLoader because it | |
111 // is not an actual Web resource. | |
112 // TODO(yzshen): find out a better approach. | |
113 mojo::URLResponsePtr response(mojo::URLResponse::New()); | |
114 response->url = url_; | |
115 response->status_code = 200; | |
116 response->mime_type = "text/html"; | |
117 OnResponseReceived(nullptr, mojo::URLLoaderPtr(), connection, nullptr, | |
118 std::move(response)); | |
119 } else { | |
120 // HTMLDocument provides services, but is created asynchronously. Queue up | |
121 // requests until the HTMLDocument is created. | |
122 scoped_ptr<ServiceConnectorQueue> service_connector_queue( | |
123 new ServiceConnectorQueue); | |
124 connection->SetServiceConnector(service_connector_queue.get()); | |
125 | |
126 mojo::URLLoaderPtr loader; | |
127 url_loader_factory_->CreateURLLoader(GetProxy(&loader)); | |
128 mojo::URLRequestPtr request(mojo::URLRequest::New()); | |
129 request->url = url_; | |
130 request->auto_follow_redirects = true; | |
131 | |
132 // |loader| will be passed to the OnResponseReceived method through a | |
133 // callback. Because order of evaluation is undefined, a reference to the | |
134 // raw pointer is needed. | |
135 mojo::URLLoader* raw_loader = loader.get(); | |
136 // The app needs to stay alive while waiting for the response to be | |
137 // available. | |
138 scoped_ptr<mojo::AppRefCount> app_retainer(app_.CreateAppRefCount()); | |
139 raw_loader->Start( | |
140 std::move(request), | |
141 base::Bind(&HTMLDocumentApplicationDelegate::OnResponseReceived, | |
142 weak_factory_.GetWeakPtr(), base::Passed(&app_retainer), | |
143 base::Passed(&loader), connection, | |
144 base::Passed(&service_connector_queue))); | |
145 } | |
146 return true; | |
147 } | |
148 | |
149 void HTMLDocumentApplicationDelegate::OnHTMLDocumentDeleted2( | |
150 HTMLDocument* document) { | |
151 DCHECK(documents2_.count(document) > 0); | |
152 documents2_.erase(document); | |
153 } | |
154 | |
155 void HTMLDocumentApplicationDelegate::OnResponseReceived( | |
156 scoped_ptr<mojo::AppRefCount> app_refcount, | |
157 mojo::URLLoaderPtr loader, | |
158 mojo::Connection* connection, | |
159 scoped_ptr<ServiceConnectorQueue> connector_queue, | |
160 mojo::URLResponsePtr response) { | |
161 // HTMLDocument is destroyed when the hosting view is destroyed, or | |
162 // explicitly from our destructor. | |
163 HTMLDocument* document = new HTMLDocument( | |
164 &app_, connection, std::move(response), global_state_, | |
165 base::Bind(&HTMLDocumentApplicationDelegate::OnHTMLDocumentDeleted2, | |
166 base::Unretained(this)), | |
167 html_factory_); | |
168 documents2_.insert(document); | |
169 | |
170 if (connector_queue) { | |
171 connector_queue->PushRequestsTo(connection); | |
172 connection->SetServiceConnector(nullptr); | |
173 } | |
174 } | |
175 | |
176 HTMLFrame* HTMLDocumentApplicationDelegate::CreateHTMLFrame( | |
177 HTMLFrame::CreateParams* params) { | |
178 return new HTMLFrame(params); | |
179 } | |
180 | |
181 HTMLWidgetRootLocal* HTMLDocumentApplicationDelegate::CreateHTMLWidgetRootLocal( | |
182 HTMLWidgetRootLocal::CreateParams* params) { | |
183 return new HTMLWidgetRootLocal(params); | |
184 } | |
185 | |
186 } // namespace html_viewer | |
OLD | NEW |