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 "mojo/services/html_viewer/html_document_view.h" 6 7#include "base/bind.h" 8#include "base/location.h" 9#include "base/message_loop/message_loop_proxy.h" 10#include "base/single_thread_task_runner.h" 11#include "base/strings/string_util.h" 12#include "base/thread_task_runner_handle.h" 13#include "mojo/public/cpp/application/connect.h" 14#include "mojo/public/cpp/application/service_provider_impl.h" 15#include "mojo/public/cpp/system/data_pipe.h" 16#include "mojo/public/interfaces/application/shell.mojom.h" 17#include "mojo/services/html_viewer/blink_input_events_type_converters.h" 18#include "mojo/services/html_viewer/blink_url_request_type_converters.h" 19#include "mojo/services/html_viewer/weblayertreeview_impl.h" 20#include "mojo/services/html_viewer/webmediaplayer_factory.h" 21#include "mojo/services/html_viewer/webstoragenamespace_impl.h" 22#include "mojo/services/html_viewer/weburlloader_impl.h" 23#include "mojo/services/public/cpp/view_manager/view.h" 24#include "mojo/services/public/interfaces/surfaces/surfaces_service.mojom.h" 25#include "skia/ext/refptr.h" 26#include "third_party/WebKit/public/platform/Platform.h" 27#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" 28#include "third_party/WebKit/public/web/WebConsoleMessage.h" 29#include "third_party/WebKit/public/web/WebDocument.h" 30#include "third_party/WebKit/public/web/WebElement.h" 31#include "third_party/WebKit/public/web/WebInputEvent.h" 32#include "third_party/WebKit/public/web/WebLocalFrame.h" 33#include "third_party/WebKit/public/web/WebScriptSource.h" 34#include "third_party/WebKit/public/web/WebSettings.h" 35#include "third_party/WebKit/public/web/WebView.h" 36#include "third_party/skia/include/core/SkCanvas.h" 37#include "third_party/skia/include/core/SkColor.h" 38#include "third_party/skia/include/core/SkDevice.h" 39 40namespace mojo { 41namespace { 42 43void ConfigureSettings(blink::WebSettings* settings) { 44 settings->setCookieEnabled(true); 45 settings->setDefaultFixedFontSize(13); 46 settings->setDefaultFontSize(16); 47 settings->setLoadsImagesAutomatically(true); 48 settings->setJavaScriptEnabled(true); 49} 50 51Target WebNavigationPolicyToNavigationTarget( 52 blink::WebNavigationPolicy policy) { 53 switch (policy) { 54 case blink::WebNavigationPolicyCurrentTab: 55 return TARGET_SOURCE_NODE; 56 case blink::WebNavigationPolicyNewBackgroundTab: 57 case blink::WebNavigationPolicyNewForegroundTab: 58 case blink::WebNavigationPolicyNewWindow: 59 case blink::WebNavigationPolicyNewPopup: 60 return TARGET_NEW_NODE; 61 default: 62 return TARGET_DEFAULT; 63 } 64} 65 66bool CanNavigateLocally(blink::WebFrame* frame, 67 const blink::WebURLRequest& request) { 68 // For now, we just load child frames locally. 69 // TODO(aa): In the future, this should use embedding to connect to a 70 // different instance of Blink if the frame is cross-origin. 71 if (frame->parent()) 72 return true; 73 74 // If we have extraData() it means we already have the url response 75 // (presumably because we are being called via Navigate()). In that case we 76 // can go ahead and navigate locally. 77 if (request.extraData()) 78 return true; 79 80 // Otherwise we don't know if we're the right app to handle this request. Ask 81 // host to do the navigation for us. 82 return false; 83} 84 85} // namespace 86 87HTMLDocumentView::HTMLDocumentView( 88 URLResponsePtr response, 89 InterfaceRequest<ServiceProvider> service_provider_request, 90 Shell* shell, 91 scoped_refptr<base::MessageLoopProxy> compositor_thread, 92 WebMediaPlayerFactory* web_media_player_factory) 93 : shell_(shell), 94 web_view_(NULL), 95 root_(NULL), 96 view_manager_client_factory_(shell, this), 97 compositor_thread_(compositor_thread), 98 web_media_player_factory_(web_media_player_factory), 99 weak_factory_(this) { 100 ServiceProviderImpl* exported_services = new ServiceProviderImpl(); 101 exported_services->AddService(&view_manager_client_factory_); 102 BindToRequest(exported_services, &service_provider_request); 103 Load(response.Pass()); 104} 105 106HTMLDocumentView::~HTMLDocumentView() { 107 if (web_view_) 108 web_view_->close(); 109 if (root_) 110 root_->RemoveObserver(this); 111} 112 113void HTMLDocumentView::OnEmbed( 114 ViewManager* view_manager, 115 View* root, 116 ServiceProviderImpl* embedee_service_provider_impl, 117 scoped_ptr<ServiceProvider> embedder_service_provider) { 118 root_ = root; 119 embedder_service_provider_ = embedder_service_provider.Pass(); 120 navigator_host_.set_service_provider(embedder_service_provider_.get()); 121 122 web_view_->resize(root_->bounds().size()); 123 web_layer_tree_view_impl_->setViewportSize(root_->bounds().size()); 124 web_layer_tree_view_impl_->set_view(root_); 125 root_->AddObserver(this); 126} 127 128void HTMLDocumentView::OnViewManagerDisconnected(ViewManager* view_manager) { 129 // TODO(aa): Need to figure out how shutdown works. 130} 131 132void HTMLDocumentView::Load(URLResponsePtr response) { 133 web_view_ = blink::WebView::create(this); 134 web_layer_tree_view_impl_->set_widget(web_view_); 135 ConfigureSettings(web_view_->settings()); 136 web_view_->setMainFrame(blink::WebLocalFrame::create(this)); 137 138 GURL url(response->url); 139 140 WebURLRequestExtraData* extra_data = new WebURLRequestExtraData; 141 extra_data->synthetic_response = response.Pass(); 142 143 blink::WebURLRequest web_request; 144 web_request.initialize(); 145 web_request.setURL(url); 146 web_request.setExtraData(extra_data); 147 148 web_view_->mainFrame()->loadRequest(web_request); 149} 150 151blink::WebStorageNamespace* HTMLDocumentView::createSessionStorageNamespace() { 152 return new WebStorageNamespaceImpl(); 153} 154 155void HTMLDocumentView::initializeLayerTreeView() { 156 ServiceProviderPtr surfaces_service_provider; 157 shell_->ConnectToApplication("mojo:mojo_surfaces_service", 158 Get(&surfaces_service_provider)); 159 InterfacePtr<SurfacesService> surfaces_service; 160 ConnectToService(surfaces_service_provider.get(), &surfaces_service); 161 162 ServiceProviderPtr gpu_service_provider; 163 // TODO(jamesr): Should be mojo:mojo_gpu_service 164 shell_->ConnectToApplication("mojo:mojo_native_viewport_service", 165 Get(&gpu_service_provider)); 166 InterfacePtr<Gpu> gpu_service; 167 ConnectToService(gpu_service_provider.get(), &gpu_service); 168 web_layer_tree_view_impl_.reset(new WebLayerTreeViewImpl( 169 compositor_thread_, surfaces_service.Pass(), gpu_service.Pass())); 170} 171 172blink::WebLayerTreeView* HTMLDocumentView::layerTreeView() { 173 return web_layer_tree_view_impl_.get(); 174} 175 176blink::WebMediaPlayer* HTMLDocumentView::createMediaPlayer( 177 blink::WebLocalFrame* frame, 178 const blink::WebURL& url, 179 blink::WebMediaPlayerClient* client) { 180 return web_media_player_factory_->CreateMediaPlayer(frame, url, client); 181} 182 183blink::WebMediaPlayer* HTMLDocumentView::createMediaPlayer( 184 blink::WebLocalFrame* frame, 185 const blink::WebURL& url, 186 blink::WebMediaPlayerClient* client, 187 blink::WebContentDecryptionModule* initial_cdm) { 188 return createMediaPlayer(frame, url, client); 189} 190 191blink::WebFrame* HTMLDocumentView::createChildFrame( 192 blink::WebLocalFrame* parent, 193 const blink::WebString& frameName) { 194 blink::WebLocalFrame* web_frame = blink::WebLocalFrame::create(this); 195 parent->appendChild(web_frame); 196 return web_frame; 197} 198 199void HTMLDocumentView::frameDetached(blink::WebFrame* frame) { 200 if (frame->parent()) 201 frame->parent()->removeChild(frame); 202 203 // |frame| is invalid after here. 204 frame->close(); 205} 206 207blink::WebCookieJar* HTMLDocumentView::cookieJar(blink::WebLocalFrame* frame) { 208 // TODO(darin): Blink does not fallback to the Platform provided WebCookieJar. 209 // Either it should, as it once did, or we should find another solution here. 210 return blink::Platform::current()->cookieJar(); 211} 212 213blink::WebNavigationPolicy HTMLDocumentView::decidePolicyForNavigation( 214 blink::WebLocalFrame* frame, blink::WebDataSource::ExtraData* data, 215 const blink::WebURLRequest& request, blink::WebNavigationType nav_type, 216 blink::WebNavigationPolicy default_policy, bool is_redirect) { 217 if (CanNavigateLocally(frame, request)) 218 return default_policy; 219 220 navigator_host_->RequestNavigate( 221 WebNavigationPolicyToNavigationTarget(default_policy), 222 URLRequest::From(request).Pass()); 223 224 return blink::WebNavigationPolicyIgnore; 225} 226 227void HTMLDocumentView::didAddMessageToConsole( 228 const blink::WebConsoleMessage& message, 229 const blink::WebString& source_name, 230 unsigned source_line, 231 const blink::WebString& stack_trace) { 232} 233 234void HTMLDocumentView::didNavigateWithinPage( 235 blink::WebLocalFrame* frame, const blink::WebHistoryItem& history_item, 236 blink::WebHistoryCommitType commit_type) { 237 navigator_host_->DidNavigateLocally(history_item.urlString().utf8()); 238} 239 240void HTMLDocumentView::OnViewBoundsChanged(View* view, 241 const gfx::Rect& old_bounds, 242 const gfx::Rect& new_bounds) { 243 DCHECK_EQ(view, root_); 244 web_view_->resize(view->bounds().size()); 245} 246 247void HTMLDocumentView::OnViewDestroyed(View* view) { 248 DCHECK_EQ(view, root_); 249 view->RemoveObserver(this); 250 root_ = NULL; 251} 252 253void HTMLDocumentView::OnViewInputEvent(View* view, const EventPtr& event) { 254 scoped_ptr<blink::WebInputEvent> web_event = 255 event.To<scoped_ptr<blink::WebInputEvent> >(); 256 if (web_event) 257 web_view_->handleInputEvent(*web_event); 258} 259 260} // namespace mojo 261