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