Inline NetLog IPv6 reachability events.
[chromium-blink-merge.git] / components / html_viewer / html_document.cc
blob227dae3280360905fbce1ceccaabcbc185e17b14
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/bind.h"
8 #include "base/location.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "components/html_viewer/blink_input_events_type_converters.h"
16 #include "components/html_viewer/blink_url_request_type_converters.h"
17 #include "components/html_viewer/web_layer_tree_view_impl.h"
18 #include "components/html_viewer/web_media_player_factory.h"
19 #include "components/html_viewer/web_storage_namespace_impl.h"
20 #include "components/html_viewer/web_url_loader_impl.h"
21 #include "components/surfaces/public/interfaces/surfaces.mojom.h"
22 #include "components/view_manager/public/cpp/view.h"
23 #include "media/blink/webencryptedmediaclient_impl.h"
24 #include "media/cdm/default_cdm_factory.h"
25 #include "media/filters/default_media_permission.h"
26 #include "skia/ext/refptr.h"
27 #include "third_party/WebKit/public/platform/Platform.h"
28 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
29 #include "third_party/WebKit/public/platform/WebSize.h"
30 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
31 #include "third_party/WebKit/public/web/WebDocument.h"
32 #include "third_party/WebKit/public/web/WebElement.h"
33 #include "third_party/WebKit/public/web/WebInputEvent.h"
34 #include "third_party/WebKit/public/web/WebLocalFrame.h"
35 #include "third_party/WebKit/public/web/WebScriptSource.h"
36 #include "third_party/WebKit/public/web/WebSettings.h"
37 #include "third_party/WebKit/public/web/WebView.h"
38 #include "third_party/mojo/src/mojo/public/cpp/application/application_impl.h"
39 #include "third_party/mojo/src/mojo/public/cpp/application/connect.h"
40 #include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
41 #include "third_party/mojo/src/mojo/public/interfaces/application/shell.mojom.h"
42 #include "third_party/skia/include/core/SkCanvas.h"
43 #include "third_party/skia/include/core/SkColor.h"
44 #include "third_party/skia/include/core/SkDevice.h"
45 #include "ui/gfx/geometry/dip_util.h"
47 using mojo::AxProvider;
48 using mojo::Rect;
49 using mojo::ServiceProviderPtr;
50 using mojo::URLResponsePtr;
51 using mojo::View;
52 using mojo::ViewManager;
53 using mojo::WeakBindToRequest;
55 namespace html_viewer {
56 namespace {
58 void ConfigureSettings(blink::WebSettings* settings) {
59 settings->setCookieEnabled(true);
60 settings->setDefaultFixedFontSize(13);
61 settings->setDefaultFontSize(16);
62 settings->setLoadsImagesAutomatically(true);
63 settings->setJavaScriptEnabled(true);
66 mojo::Target WebNavigationPolicyToNavigationTarget(
67 blink::WebNavigationPolicy policy) {
68 switch (policy) {
69 case blink::WebNavigationPolicyCurrentTab:
70 return mojo::TARGET_SOURCE_NODE;
71 case blink::WebNavigationPolicyNewBackgroundTab:
72 case blink::WebNavigationPolicyNewForegroundTab:
73 case blink::WebNavigationPolicyNewWindow:
74 case blink::WebNavigationPolicyNewPopup:
75 return mojo::TARGET_NEW_NODE;
76 default:
77 return mojo::TARGET_DEFAULT;
81 bool CanNavigateLocally(blink::WebFrame* frame,
82 const blink::WebURLRequest& request) {
83 // For now, we just load child frames locally.
84 // TODO(aa): In the future, this should use embedding to connect to a
85 // different instance of Blink if the frame is cross-origin.
86 if (frame->parent())
87 return true;
89 // If we have extraData() it means we already have the url response
90 // (presumably because we are being called via Navigate()). In that case we
91 // can go ahead and navigate locally.
92 if (request.extraData())
93 return true;
95 // mojo::NavigatorHost doesn't accept POSTs, so for now reuse this instance.
96 // TODO(jam): improve this (and copy logic from RenderFrameImpl's version)
97 // when we have multi-process.
98 if (EqualsASCII(request.httpMethod(), "POST"))
99 return true;
101 // Logging into Gmail fails when the referrer isn't sent with a request.
102 // TODO(jam): pass referrer and other HTTP data to NavigatorHost so we can
103 // use a new process in this case.
104 if (!request.httpHeaderField(blink::WebString::fromUTF8("Referer")).isEmpty())
105 return true;
107 // Otherwise we don't know if we're the right app to handle this request. Ask
108 // host to do the navigation for us.
109 return false;
112 } // namespace
114 HTMLDocument::HTMLDocument(
115 mojo::InterfaceRequest<mojo::ServiceProvider> services,
116 URLResponsePtr response,
117 mojo::Shell* shell,
118 scoped_refptr<base::MessageLoopProxy> compositor_thread,
119 WebMediaPlayerFactory* web_media_player_factory,
120 bool is_headless)
121 : response_(response.Pass()),
122 shell_(shell),
123 web_view_(nullptr),
124 root_(nullptr),
125 view_manager_client_factory_(shell_, this),
126 compositor_thread_(compositor_thread),
127 web_media_player_factory_(web_media_player_factory),
128 is_headless_(is_headless),
129 device_pixel_ratio_(1.0) {
130 exported_services_.AddService(this);
131 exported_services_.AddService(&view_manager_client_factory_);
132 exported_services_.Bind(services.Pass());
133 Load(response_.Pass());
136 HTMLDocument::~HTMLDocument() {
137 STLDeleteElements(&ax_providers_);
138 STLDeleteElements(&ax_provider_requests_);
140 if (web_view_)
141 web_view_->close();
142 if (root_)
143 root_->RemoveObserver(this);
146 void HTMLDocument::OnEmbed(
147 View* root,
148 mojo::InterfaceRequest<mojo::ServiceProvider> services,
149 mojo::ServiceProviderPtr exposed_services) {
150 DCHECK(!is_headless_);
151 root_ = root;
152 embedder_service_provider_ = exposed_services.Pass();
153 navigator_host_.set_service_provider(embedder_service_provider_.get());
154 UpdateWebviewSizeFromViewSize();
155 web_layer_tree_view_impl_->set_view(root_);
156 root_->AddObserver(this);
159 void HTMLDocument::OnViewManagerDisconnected(ViewManager* view_manager) {
160 // TODO(aa): Need to figure out how shutdown works.
163 void HTMLDocument::Create(mojo::ApplicationConnection* connection,
164 mojo::InterfaceRequest<AxProvider> request) {
165 if (!did_finish_load_) {
166 // Cache AxProvider interface requests until the document finishes loading.
167 auto cached_request = new mojo::InterfaceRequest<AxProvider>();
168 *cached_request = request.Pass();
169 ax_provider_requests_.insert(cached_request);
170 } else {
171 ax_providers_.insert(
172 WeakBindToRequest(new AxProviderImpl(web_view_), &request));
176 void HTMLDocument::Load(URLResponsePtr response) {
177 DCHECK(!web_view_);
178 web_view_ = blink::WebView::create(this);
179 touch_handler_.reset(new TouchHandler(web_view_));
180 web_layer_tree_view_impl_->set_widget(web_view_);
181 ConfigureSettings(web_view_->settings());
182 web_view_->setMainFrame(blink::WebLocalFrame::create(this));
184 GURL url(response->url);
186 WebURLRequestExtraData* extra_data = new WebURLRequestExtraData;
187 extra_data->synthetic_response = response.Pass();
189 blink::WebURLRequest web_request;
190 web_request.initialize();
191 web_request.setURL(url);
192 web_request.setExtraData(extra_data);
194 web_view_->mainFrame()->loadRequest(web_request);
197 void HTMLDocument::UpdateWebviewSizeFromViewSize() {
198 device_pixel_ratio_ = root_->viewport_metrics().device_pixel_ratio;
199 web_view_->setDeviceScaleFactor(device_pixel_ratio_);
200 const gfx::Size size_in_pixels(root_->bounds().width, root_->bounds().height);
201 const gfx::Size size_in_dips = gfx::ConvertSizeToDIP(
202 root_->viewport_metrics().device_pixel_ratio, size_in_pixels);
203 web_view_->resize(
204 blink::WebSize(size_in_dips.width(), size_in_dips.height()));
205 web_layer_tree_view_impl_->setViewportSize(size_in_pixels);
208 blink::WebStorageNamespace* HTMLDocument::createSessionStorageNamespace() {
209 return new WebStorageNamespaceImpl();
212 void HTMLDocument::initializeLayerTreeView() {
213 if (is_headless_) {
214 web_layer_tree_view_impl_.reset(
215 new WebLayerTreeViewImpl(compositor_thread_, nullptr, nullptr));
216 return;
219 ServiceProviderPtr surfaces_service_provider;
220 shell_->ConnectToApplication("mojo:surfaces_service",
221 GetProxy(&surfaces_service_provider), nullptr);
222 mojo::SurfacePtr surface;
223 ConnectToService(surfaces_service_provider.get(), &surface);
225 ServiceProviderPtr gpu_service_provider;
226 // TODO(jamesr): Should be mojo:gpu_service
227 shell_->ConnectToApplication("mojo:native_viewport_service",
228 GetProxy(&gpu_service_provider), nullptr);
229 mojo::GpuPtr gpu_service;
230 ConnectToService(gpu_service_provider.get(), &gpu_service);
231 web_layer_tree_view_impl_.reset(new WebLayerTreeViewImpl(
232 compositor_thread_, surface.Pass(), gpu_service.Pass()));
235 blink::WebLayerTreeView* HTMLDocument::layerTreeView() {
236 return web_layer_tree_view_impl_.get();
239 blink::WebMediaPlayer* HTMLDocument::createMediaPlayer(
240 blink::WebLocalFrame* frame,
241 const blink::WebURL& url,
242 blink::WebMediaPlayerClient* client) {
243 return createMediaPlayer(frame, url, client, nullptr);
246 blink::WebMediaPlayer* HTMLDocument::createMediaPlayer(
247 blink::WebLocalFrame* frame,
248 const blink::WebURL& url,
249 blink::WebMediaPlayerClient* client,
250 blink::WebContentDecryptionModule* initial_cdm) {
251 blink::WebMediaPlayer* player =
252 web_media_player_factory_
253 ? web_media_player_factory_->CreateMediaPlayer(
254 frame, url, client, GetMediaPermission(), GetCdmFactory(),
255 initial_cdm, shell_)
256 : nullptr;
257 return player;
260 blink::WebFrame* HTMLDocument::createChildFrame(
261 blink::WebLocalFrame* parent,
262 const blink::WebString& frameName,
263 blink::WebSandboxFlags sandboxFlags) {
264 blink::WebLocalFrame* web_frame = blink::WebLocalFrame::create(this);
265 parent->appendChild(web_frame);
266 return web_frame;
269 void HTMLDocument::frameDetached(blink::WebFrame* frame) {
270 if (frame->parent())
271 frame->parent()->removeChild(frame);
273 // |frame| is invalid after here.
274 frame->close();
277 blink::WebCookieJar* HTMLDocument::cookieJar(blink::WebLocalFrame* frame) {
278 // TODO(darin): Blink does not fallback to the Platform provided WebCookieJar.
279 // Either it should, as it once did, or we should find another solution here.
280 return blink::Platform::current()->cookieJar();
283 blink::WebNavigationPolicy HTMLDocument::decidePolicyForNavigation(
284 blink::WebLocalFrame* frame,
285 blink::WebDataSource::ExtraData* data,
286 const blink::WebURLRequest& request,
287 blink::WebNavigationType nav_type,
288 blink::WebNavigationPolicy default_policy,
289 bool is_redirect) {
290 if (CanNavigateLocally(frame, request))
291 return default_policy;
293 if (navigator_host_.get()) {
294 navigator_host_->RequestNavigate(
295 WebNavigationPolicyToNavigationTarget(default_policy),
296 mojo::URLRequest::From(request).Pass());
299 return blink::WebNavigationPolicyIgnore;
302 void HTMLDocument::didAddMessageToConsole(
303 const blink::WebConsoleMessage& message,
304 const blink::WebString& source_name,
305 unsigned source_line,
306 const blink::WebString& stack_trace) {
307 VLOG(1) << "[" << source_name.utf8() << "(" << source_line << ")] "
308 << message.text.utf8();
311 void HTMLDocument::didFinishLoad(blink::WebLocalFrame* frame) {
312 // TODO(msw): Notify AxProvider clients of updates on child frame loads.
313 did_finish_load_ = true;
314 // Bind any pending AxProviderImpl interface requests.
315 for (auto it : ax_provider_requests_)
316 ax_providers_.insert(WeakBindToRequest(new AxProviderImpl(web_view_), it));
317 STLDeleteElements(&ax_provider_requests_);
320 void HTMLDocument::didNavigateWithinPage(
321 blink::WebLocalFrame* frame,
322 const blink::WebHistoryItem& history_item,
323 blink::WebHistoryCommitType commit_type) {
324 if (navigator_host_.get())
325 navigator_host_->DidNavigateLocally(history_item.urlString().utf8());
328 blink::WebEncryptedMediaClient* HTMLDocument::encryptedMediaClient() {
329 if (!web_encrypted_media_client_) {
330 web_encrypted_media_client_.reset(new media::WebEncryptedMediaClientImpl(
331 GetCdmFactory(), GetMediaPermission()));
333 return web_encrypted_media_client_.get();
336 void HTMLDocument::OnViewBoundsChanged(View* view,
337 const Rect& old_bounds,
338 const Rect& new_bounds) {
339 DCHECK_EQ(view, root_);
340 UpdateWebviewSizeFromViewSize();
343 void HTMLDocument::OnViewDestroyed(View* view) {
344 DCHECK_EQ(view, root_);
345 root_ = nullptr;
346 delete this;
347 mojo::ApplicationImpl::Terminate();
350 void HTMLDocument::OnViewInputEvent(View* view, const mojo::EventPtr& event) {
351 if (event->pointer_data) {
352 // Blink expects coordintes to be in DIPs.
353 event->pointer_data->x /= device_pixel_ratio_;
354 event->pointer_data->y /= device_pixel_ratio_;
355 event->pointer_data->screen_x /= device_pixel_ratio_;
356 event->pointer_data->screen_y /= device_pixel_ratio_;
359 if ((event->action == mojo::EVENT_TYPE_POINTER_DOWN ||
360 event->action == mojo::EVENT_TYPE_POINTER_UP ||
361 event->action == mojo::EVENT_TYPE_POINTER_CANCEL ||
362 event->action == mojo::EVENT_TYPE_POINTER_MOVE) &&
363 event->pointer_data->kind == mojo::POINTER_KIND_TOUCH) {
364 touch_handler_->OnTouchEvent(*event);
365 return;
367 scoped_ptr<blink::WebInputEvent> web_event =
368 event.To<scoped_ptr<blink::WebInputEvent>>();
369 if (web_event)
370 web_view_->handleInputEvent(*web_event);
373 media::MediaPermission* HTMLDocument::GetMediaPermission() {
374 if (!media_permission_)
375 media_permission_.reset(new media::DefaultMediaPermission(true));
376 return media_permission_.get();
379 media::CdmFactory* HTMLDocument::GetCdmFactory() {
380 if (!cdm_factory_)
381 cdm_factory_.reset(new media::DefaultCdmFactory());
382 return cdm_factory_.get();
385 } // namespace html_viewer