diff options
author | sky <sky@chromium.org> | 2015-06-23 16:22:38 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-23 23:23:23 +0000 |
commit | 0c9bf63193891a0d2f5f60079214a5e7183f070b (patch) | |
tree | 745ca41693d856f17bd53b671f1a6c1ec9370e27 | |
parent | f5f91f945f8c03393460d7375f8837078f50cf85 (diff) | |
download | chromium_src-0c9bf63193891a0d2f5f60079214a5e7183f070b.zip chromium_src-0c9bf63193891a0d2f5f60079214a5e7183f070b.tar.gz chromium_src-0c9bf63193891a0d2f5f60079214a5e7183f070b.tar.bz2 |
Factors OOPIFs in mandoline to own HTMLDocument class
Having to support both in the same class at the same time is too
painful. I'm forking off a copy of HTMLDocument and will have it
exclusively handle the OOPIFs case. When OOPIFs is ready, will then
nuke the old and only have HTMLDocument again.
BUG=479172,490221
TEST=none
R=ben@chromium.org
Review URL: https://codereview.chromium.org/1206633002
Cr-Commit-Position: refs/heads/master@{#335802}
-rw-r--r-- | components/html_viewer/BUILD.gn | 2 | ||||
-rw-r--r-- | components/html_viewer/html_document.cc | 53 | ||||
-rw-r--r-- | components/html_viewer/html_document.h | 18 | ||||
-rw-r--r-- | components/html_viewer/html_document_oopif.cc | 497 | ||||
-rw-r--r-- | components/html_viewer/html_document_oopif.h | 199 | ||||
-rw-r--r-- | components/html_viewer/html_viewer.cc | 41 |
6 files changed, 736 insertions, 74 deletions
diff --git a/components/html_viewer/BUILD.gn b/components/html_viewer/BUILD.gn index 9b79e91..de1e990 100644 --- a/components/html_viewer/BUILD.gn +++ b/components/html_viewer/BUILD.gn @@ -75,6 +75,8 @@ source_set("lib") { "frame_tree_manager.h", "html_document.cc", "html_document.h", + "html_document_oopif.cc", + "html_document_oopif.h", "media_factory.cc", "media_factory.h", "mock_web_blob_registry_impl.cc", diff --git a/components/html_viewer/html_document.cc b/components/html_viewer/html_document.cc index a68478d2..03d4d91 100644 --- a/components/html_viewer/html_document.cc +++ b/components/html_viewer/html_document.cc @@ -62,13 +62,6 @@ using mojo::WeakBindToRequest; namespace html_viewer { namespace { -// Switch to enable out of process iframes. -const char kOOPIF[] = "oopifs"; - -bool EnableOOPIFs() { - return base::CommandLine::ForCurrentProcess()->HasSwitch(kOOPIF); -} - bool EnableRemoteDebugging() { return base::CommandLine::ForCurrentProcess()->HasSwitch( devtools_service::kRemoteDebuggingPort); @@ -133,8 +126,7 @@ mojo::Target WebNavigationPolicyToNavigationTarget( bool CanNavigateLocally(blink::WebFrame* frame, const blink::WebURLRequest& request) { // For now, we just load child frames locally. - // TODO(sky): this can be removed once we transition to oopifs. - if (!EnableOOPIFs() && frame->parent()) + if (frame->parent()) return true; // If we have extraData() it means we already have the url response @@ -164,11 +156,8 @@ HTMLDocument::HTMLDocument(mojo::ApplicationImpl* html_document_app, root_(nullptr), view_manager_client_factory_(html_document_app->shell(), this), setup_(setup), - frame_tree_manager_binding_(&frame_tree_manager_), delete_callback_(delete_callback) { connection->AddService( - static_cast<mojo::InterfaceFactory<mandoline::FrameTreeClient>*>(this)); - connection->AddService( static_cast<InterfaceFactory<mojo::AxProvider>*>(this)); connection->AddService(&view_manager_client_factory_); @@ -225,12 +214,6 @@ void HTMLDocument::Create(mojo::ApplicationConnection* connection, } } -void HTMLDocument::Create( - mojo::ApplicationConnection* connection, - mojo::InterfaceRequest<mandoline::FrameTreeClient> request) { - frame_tree_manager_binding_.Bind(request.Pass()); -} - void HTMLDocument::Load(URLResponsePtr response) { DCHECK(!web_view_); web_view_ = blink::WebView::create(this); @@ -265,15 +248,6 @@ void HTMLDocument::Load(URLResponsePtr response) { UpdateFocus(); } -void HTMLDocument::ConvertLocalFrameToRemoteFrame(blink::WebLocalFrame* frame) { - mojo::View* view = frame_to_view_[frame].view; - // TODO(sky): this leaks. Fix it. - blink::WebRemoteFrame* remote_frame = blink::WebRemoteFrame::create( - frame_to_view_[frame].scope, new RemoteFrameClientImpl(view)); - remote_frame->initializeFromFrame(frame); - frame->swap(remote_frame); -} - void HTMLDocument::UpdateWebviewSizeFromViewSize() { web_view_->setDeviceScaleFactor(setup_->device_pixel_ratio()); const gfx::Size size_in_pixels(root_->bounds().width, root_->bounds().height); @@ -347,18 +321,6 @@ blink::WebFrame* HTMLDocument::createChildFrame( blink::WebSandboxFlags sandboxFlags) { blink::WebLocalFrame* child_frame = blink::WebLocalFrame::create(scope, this); parent->appendChild(child_frame); - if (EnableOOPIFs()) { - // Create the view that will house the frame now. We embed only once we know - // the url. - mojo::View* child_frame_view = root_->view_manager()->CreateView(); - child_frame_view->SetVisible(true); - root_->AddChild(child_frame_view); - - ChildFrameData child_frame_data; - child_frame_data.view = child_frame_view; - child_frame_data.scope = scope; - frame_to_view_[child_frame] = child_frame_data; - } return child_frame; } @@ -394,19 +356,6 @@ blink::WebNavigationPolicy HTMLDocument::decidePolicyForNavigation( } std::string frame_name = info.frame ? info.frame->assignedName().utf8() : ""; - if (info.frame->parent() && EnableOOPIFs()) { - mojo::View* view = frame_to_view_[info.frame].view; - mojo::URLRequestPtr url_request = mojo::URLRequest::From(info.urlRequest); - view->EmbedAllowingReembed(url_request.Pass()); - // TODO(sky): I tried swapping the frame types here, but that resulted in - // the view never getting sized. Figure out why. - // TODO(sky): there are timing conditions here, and we should only do this - // once. - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&HTMLDocument::ConvertLocalFrameToRemoteFrame, - base::Unretained(this), info.frame)); - return blink::WebNavigationPolicyIgnore; - } if (CanNavigateLocally(info.frame, info.urlRequest)) return info.defaultPolicy; diff --git a/components/html_viewer/html_document.h b/components/html_viewer/html_document.h index c9dc997..4c9845d 100644 --- a/components/html_viewer/html_document.h +++ b/components/html_viewer/html_document.h @@ -5,19 +5,16 @@ #ifndef COMPONENTS_HTML_VIEWER_HTML_DOCUMENT_H_ #define COMPONENTS_HTML_VIEWER_HTML_DOCUMENT_H_ -#include <map> #include <set> #include "base/callback.h" #include "base/macros.h" #include "components/html_viewer/ax_provider_impl.h" -#include "components/html_viewer/frame_tree_manager.h" #include "components/html_viewer/touch_handler.h" #include "components/view_manager/public/cpp/view_manager_client_factory.h" #include "components/view_manager/public/cpp/view_manager_delegate.h" #include "components/view_manager/public/cpp/view_observer.h" #include "mandoline/services/navigation/public/interfaces/navigation.mojom.h" -#include "mandoline/tab/public/interfaces/frame_tree.mojom.h" #include "mojo/application/public/cpp/app_lifetime_helper.h" #include "mojo/application/public/cpp/interface_factory.h" #include "mojo/application/public/cpp/lazy_interface_ptr.h" @@ -55,8 +52,7 @@ class HTMLDocument : public blink::WebViewClient, public blink::WebFrameClient, public mojo::ViewManagerDelegate, public mojo::ViewObserver, - public mojo::InterfaceFactory<mojo::AxProvider>, - public mojo::InterfaceFactory<mandoline::FrameTreeClient> { + public mojo::InterfaceFactory<mojo::AxProvider> { public: using DeleteCallback = base::Callback<void(HTMLDocument*)>; @@ -80,8 +76,6 @@ class HTMLDocument : public blink::WebViewClient, blink::WebTreeScopeType scope; }; - using FrameToViewMap = std::map<blink::WebLocalFrame*, ChildFrameData>; - ~HTMLDocument() override; // Updates the size and scale factor of the webview and related classes from @@ -145,11 +139,6 @@ class HTMLDocument : public blink::WebViewClient, void Create(mojo::ApplicationConnection* connection, mojo::InterfaceRequest<mojo::AxProvider> request) override; - // mojo::InterfaceFactory<mandoline::FrameTreeClient> - void Create( - mojo::ApplicationConnection* connection, - mojo::InterfaceRequest<mandoline::FrameTreeClient> request) override; - void Load(mojo::URLResponsePtr response); // Converts a WebLocalFrame to a WebRemoteFrame. Used once we know the @@ -180,11 +169,6 @@ class HTMLDocument : public blink::WebViewClient, scoped_ptr<TouchHandler> touch_handler_; - FrameToViewMap frame_to_view_; - - FrameTreeManager frame_tree_manager_; - mojo::Binding<mandoline::FrameTreeClient> frame_tree_manager_binding_; - scoped_ptr<DevToolsAgentImpl> devtools_agent_; DeleteCallback delete_callback_; diff --git a/components/html_viewer/html_document_oopif.cc b/components/html_viewer/html_document_oopif.cc new file mode 100644 index 0000000..f4ec3808 --- /dev/null +++ b/components/html_viewer/html_document_oopif.cc @@ -0,0 +1,497 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/html_viewer/html_document_oopif.h" + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/location.h" +#include "base/memory/scoped_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/stl_util.h" +#include "base/strings/string_util.h" +#include "base/thread_task_runner_handle.h" +#include "components/devtools_service/public/cpp/switches.h" +#include "components/html_viewer/blink_input_events_type_converters.h" +#include "components/html_viewer/blink_url_request_type_converters.h" +#include "components/html_viewer/devtools_agent_impl.h" +#include "components/html_viewer/media_factory.h" +#include "components/html_viewer/setup.h" +#include "components/html_viewer/web_layer_tree_view_impl.h" +#include "components/html_viewer/web_storage_namespace_impl.h" +#include "components/html_viewer/web_url_loader_impl.h" +#include "components/view_manager/public/cpp/view.h" +#include "components/view_manager/public/cpp/view_manager.h" +#include "components/view_manager/public/cpp/view_property.h" +#include "components/view_manager/public/interfaces/surfaces.mojom.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "mojo/application/public/cpp/connect.h" +#include "mojo/application/public/interfaces/shell.mojom.h" +#include "mojo/converters/geometry/geometry_type_converters.h" +#include "skia/ext/refptr.h" +#include "third_party/WebKit/public/platform/Platform.h" +#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" +#include "third_party/WebKit/public/platform/WebSize.h" +#include "third_party/WebKit/public/web/WebConsoleMessage.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebElement.h" +#include "third_party/WebKit/public/web/WebInputEvent.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebRemoteFrame.h" +#include "third_party/WebKit/public/web/WebRemoteFrameClient.h" +#include "third_party/WebKit/public/web/WebScriptSource.h" +#include "third_party/WebKit/public/web/WebSettings.h" +#include "third_party/WebKit/public/web/WebView.h" +#include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkDevice.h" +#include "ui/gfx/geometry/dip_util.h" +#include "ui/gfx/geometry/size.h" + +using blink::WebString; +using mojo::AxProvider; +using mojo::Rect; +using mojo::ServiceProviderPtr; +using mojo::URLResponsePtr; +using mojo::View; +using mojo::ViewManager; +using mojo::WeakBindToRequest; + +namespace html_viewer { +namespace { + +bool EnableRemoteDebugging() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + devtools_service::kRemoteDebuggingPort); +} + +// WebRemoteFrameClient implementation used for OOPIFs. +// TODO(sky): this needs to talk to browser by way of an interface. +class RemoteFrameClientImpl : public blink::WebRemoteFrameClient { + public: + explicit RemoteFrameClientImpl(mojo::View* view) : view_(view) {} + ~RemoteFrameClientImpl() {} + + // WebRemoteFrameClient methods: + virtual void postMessageEvent(blink::WebLocalFrame* source_frame, + blink::WebRemoteFrame* target_frame, + blink::WebSecurityOrigin target_origin, + blink::WebDOMMessageEvent event) {} + virtual void initializeChildFrame(const blink::WebRect& frame_rect, + float scale_factor) { + mojo::Rect rect; + rect.x = frame_rect.x; + rect.y = frame_rect.y; + rect.width = frame_rect.width; + rect.height = frame_rect.height; + view_->SetBounds(rect); + } + virtual void navigate(const blink::WebURLRequest& request, + bool should_replace_current_entry) {} + virtual void reload(bool ignore_cache, bool is_client_redirect) {} + + virtual void forwardInputEvent(const blink::WebInputEvent* event) {} + + private: + mojo::View* const view_; + + DISALLOW_COPY_AND_ASSIGN(RemoteFrameClientImpl); +}; + +void ConfigureSettings(blink::WebSettings* settings) { + settings->setCookieEnabled(true); + settings->setDefaultFixedFontSize(13); + settings->setDefaultFontSize(16); + settings->setLoadsImagesAutomatically(true); + settings->setJavaScriptEnabled(true); +} + +mojo::Target WebNavigationPolicyToNavigationTarget( + blink::WebNavigationPolicy policy) { + switch (policy) { + case blink::WebNavigationPolicyCurrentTab: + return mojo::TARGET_SOURCE_NODE; + case blink::WebNavigationPolicyNewBackgroundTab: + case blink::WebNavigationPolicyNewForegroundTab: + case blink::WebNavigationPolicyNewWindow: + case blink::WebNavigationPolicyNewPopup: + return mojo::TARGET_NEW_NODE; + default: + return mojo::TARGET_DEFAULT; + } +} + +bool CanNavigateLocally(blink::WebFrame* frame, + const blink::WebURLRequest& request) { + // If we have extraData() it means we already have the url response + // (presumably because we are being called via Navigate()). In that case we + // can go ahead and navigate locally. + if (request.extraData()) + return true; + + // Otherwise we don't know if we're the right app to handle this request. Ask + // host to do the navigation for us. + return false; +} + +} // namespace + +HTMLDocumentOOPIF::HTMLDocumentOOPIF(mojo::ApplicationImpl* html_document_app, + mojo::ApplicationConnection* connection, + URLResponsePtr response, + Setup* setup, + const DeleteCallback& delete_callback) + : app_refcount_( + html_document_app->app_lifetime_helper()->CreateAppRefCount()), + html_document_app_(html_document_app), + response_(response.Pass()), + navigator_host_(connection->GetServiceProvider()), + web_view_(nullptr), + root_(nullptr), + view_manager_client_factory_(html_document_app->shell(), this), + setup_(setup), + frame_tree_manager_binding_(&frame_tree_manager_), + delete_callback_(delete_callback) { + connection->AddService( + static_cast<mojo::InterfaceFactory<mandoline::FrameTreeClient>*>(this)); + connection->AddService( + static_cast<InterfaceFactory<mojo::AxProvider>*>(this)); + connection->AddService(&view_manager_client_factory_); + + if (setup_->did_init()) + Load(response_.Pass()); +} + +void HTMLDocumentOOPIF::Destroy() { + // See comment in header for a description of lifetime. + if (root_) { + // Deleting the ViewManager calls back to OnViewManagerDestroyed() and + // triggers deletion. + delete root_->view_manager(); + } else { + delete this; + } +} + +HTMLDocumentOOPIF::~HTMLDocumentOOPIF() { + delete_callback_.Run(this); + + STLDeleteElements(&ax_providers_); + STLDeleteElements(&ax_provider_requests_); + + if (web_view_) + web_view_->close(); + if (root_) + root_->RemoveObserver(this); +} + +void HTMLDocumentOOPIF::OnEmbed(View* root) { + DCHECK(!setup_->is_headless()); + root_ = root; + root_->AddObserver(this); + UpdateFocus(); + + InitSetupAndLoadIfNecessary(); +} + +void HTMLDocumentOOPIF::OnViewManagerDestroyed(ViewManager* view_manager) { + delete this; +} + +void HTMLDocumentOOPIF::Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<AxProvider> request) { + if (!did_finish_load_) { + // Cache AxProvider interface requests until the document finishes loading. + auto cached_request = new mojo::InterfaceRequest<AxProvider>(); + *cached_request = request.Pass(); + ax_provider_requests_.insert(cached_request); + } else { + ax_providers_.insert(new AxProviderImpl(web_view_, request.Pass())); + } +} + +void HTMLDocumentOOPIF::Create( + mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mandoline::FrameTreeClient> request) { + frame_tree_manager_binding_.Bind(request.Pass()); +} + +void HTMLDocumentOOPIF::Load(URLResponsePtr response) { + DCHECK(!web_view_); + web_view_ = blink::WebView::create(this); + touch_handler_.reset(new TouchHandler(web_view_)); + web_layer_tree_view_impl_->set_widget(web_view_); + ConfigureSettings(web_view_->settings()); + + blink::WebLocalFrame* main_frame = + blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, this); + web_view_->setMainFrame(main_frame); + + // TODO(yzshen): http://crbug.com/498986 Creating DevToolsAgentImpl instances + // causes html_viewer_apptests flakiness currently. Before we fix that we + // cannot enable remote debugging (which is required by Telemetry tests) on + // the bots. + if (EnableRemoteDebugging()) { + devtools_agent_.reset( + new DevToolsAgentImpl(main_frame, html_document_app_->shell())); + } + + GURL url(response->url); + + WebURLRequestExtraData* extra_data = new WebURLRequestExtraData; + extra_data->synthetic_response = response.Pass(); + + blink::WebURLRequest web_request; + web_request.initialize(); + web_request.setURL(url); + web_request.setExtraData(extra_data); + + web_view_->mainFrame()->loadRequest(web_request); + UpdateFocus(); +} + +void HTMLDocumentOOPIF::ConvertLocalFrameToRemoteFrame( + blink::WebLocalFrame* frame) { + mojo::View* view = frame_to_view_[frame].view; + // TODO(sky): this leaks. Fix it. + blink::WebRemoteFrame* remote_frame = blink::WebRemoteFrame::create( + frame_to_view_[frame].scope, new RemoteFrameClientImpl(view)); + remote_frame->initializeFromFrame(frame); + frame->swap(remote_frame); +} + +void HTMLDocumentOOPIF::UpdateWebviewSizeFromViewSize() { + web_view_->setDeviceScaleFactor(setup_->device_pixel_ratio()); + const gfx::Size size_in_pixels(root_->bounds().width, root_->bounds().height); + const gfx::Size size_in_dips = gfx::ConvertSizeToDIP( + root_->viewport_metrics().device_pixel_ratio, size_in_pixels); + web_view_->resize( + blink::WebSize(size_in_dips.width(), size_in_dips.height())); + web_layer_tree_view_impl_->setViewportSize(size_in_pixels); +} + +void HTMLDocumentOOPIF::InitSetupAndLoadIfNecessary() { + DCHECK(root_); + if (root_->viewport_metrics().device_pixel_ratio == 0.f) + return; + + if (!web_view_) { + setup_->InitIfNecessary( + root_->viewport_metrics().size_in_pixels.To<gfx::Size>(), + root_->viewport_metrics().device_pixel_ratio); + Load(response_.Pass()); + } + + UpdateWebviewSizeFromViewSize(); + web_layer_tree_view_impl_->set_view(root_); +} + +blink::WebStorageNamespace* HTMLDocumentOOPIF::createSessionStorageNamespace() { + return new WebStorageNamespaceImpl(); +} + +void HTMLDocumentOOPIF::initializeLayerTreeView() { + if (setup_->is_headless()) { + web_layer_tree_view_impl_.reset(new WebLayerTreeViewImpl( + setup_->compositor_thread(), nullptr, nullptr, nullptr, nullptr)); + return; + } + + mojo::URLRequestPtr request(mojo::URLRequest::New()); + request->url = mojo::String::From("mojo:surfaces_service"); + mojo::SurfacePtr surface; + html_document_app_->ConnectToService(request.Pass(), &surface); + + // TODO(jamesr): Should be mojo:gpu_service + mojo::URLRequestPtr request2(mojo::URLRequest::New()); + request2->url = mojo::String::From("mojo:view_manager"); + mojo::GpuPtr gpu_service; + html_document_app_->ConnectToService(request2.Pass(), &gpu_service); + web_layer_tree_view_impl_.reset(new WebLayerTreeViewImpl( + setup_->compositor_thread(), setup_->gpu_memory_buffer_manager(), + setup_->raster_thread_helper()->task_graph_runner(), surface.Pass(), + gpu_service.Pass())); +} + +blink::WebLayerTreeView* HTMLDocumentOOPIF::layerTreeView() { + return web_layer_tree_view_impl_.get(); +} + +blink::WebMediaPlayer* HTMLDocumentOOPIF::createMediaPlayer( + blink::WebLocalFrame* frame, + const blink::WebURL& url, + blink::WebMediaPlayerClient* client, + blink::WebContentDecryptionModule* initial_cdm) { + return setup_->media_factory()->CreateMediaPlayer( + frame, url, client, initial_cdm, html_document_app_->shell()); +} + +blink::WebFrame* HTMLDocumentOOPIF::createChildFrame( + blink::WebLocalFrame* parent, + blink::WebTreeScopeType scope, + const blink::WebString& frameName, + blink::WebSandboxFlags sandboxFlags) { + blink::WebLocalFrame* child_frame = blink::WebLocalFrame::create(scope, this); + parent->appendChild(child_frame); + // Create the view that will house the frame now. We embed only once we know + // the url. + mojo::View* child_frame_view = root_->view_manager()->CreateView(); + child_frame_view->SetVisible(true); + root_->AddChild(child_frame_view); + + ChildFrameData child_frame_data; + child_frame_data.view = child_frame_view; + child_frame_data.scope = scope; + frame_to_view_[child_frame] = child_frame_data; + return child_frame; +} + +void HTMLDocumentOOPIF::frameDetached(blink::WebFrame* frame) { + frameDetached(frame, DetachType::Remove); +} + +void HTMLDocumentOOPIF::frameDetached(blink::WebFrame* frame, DetachType type) { + DCHECK(type == DetachType::Remove); + if (frame->parent()) + frame->parent()->removeChild(frame); + + if (devtools_agent_ && frame == devtools_agent_->frame()) + devtools_agent_.reset(); + + // |frame| is invalid after here. + frame->close(); +} + +blink::WebCookieJar* HTMLDocumentOOPIF::cookieJar(blink::WebLocalFrame* frame) { + // TODO(darin): Blink does not fallback to the Platform provided WebCookieJar. + // Either it should, as it once did, or we should find another solution here. + return blink::Platform::current()->cookieJar(); +} + +blink::WebNavigationPolicy HTMLDocumentOOPIF::decidePolicyForNavigation( + const NavigationPolicyInfo& info) { + // TODO(yzshen): Remove this check once the browser is able to navigate an + // existing html_viewer instance and about:blank page support is ready. + if (devtools_agent_ && devtools_agent_->frame() == info.frame && + devtools_agent_->handling_page_navigate_request()) { + return info.defaultPolicy; + } + + std::string frame_name = info.frame ? info.frame->assignedName().utf8() : ""; + if (info.frame->parent()) { + mojo::View* view = frame_to_view_[info.frame].view; + mojo::URLRequestPtr url_request = mojo::URLRequest::From(info.urlRequest); + view->EmbedAllowingReembed(url_request.Pass()); + // TODO(sky): I tried swapping the frame types here, but that resulted in + // the view never getting sized. Figure out why. + // TODO(sky): there are timing conditions here, and we should only do this + // once. + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&HTMLDocumentOOPIF::ConvertLocalFrameToRemoteFrame, + base::Unretained(this), info.frame)); + return blink::WebNavigationPolicyIgnore; + } + + if (CanNavigateLocally(info.frame, info.urlRequest)) + return info.defaultPolicy; + + if (navigator_host_.get()) { + mojo::URLRequestPtr url_request = mojo::URLRequest::From(info.urlRequest); + navigator_host_->RequestNavigate( + WebNavigationPolicyToNavigationTarget(info.defaultPolicy), + url_request.Pass()); + } + + return blink::WebNavigationPolicyIgnore; +} + +void HTMLDocumentOOPIF::didAddMessageToConsole( + const blink::WebConsoleMessage& message, + const blink::WebString& source_name, + unsigned source_line, + const blink::WebString& stack_trace) { + VLOG(1) << "[" << source_name.utf8() << "(" << source_line << ")] " + << message.text.utf8(); +} + +void HTMLDocumentOOPIF::didFinishLoad(blink::WebLocalFrame* frame) { + // TODO(msw): Notify AxProvider clients of updates on child frame loads. + did_finish_load_ = true; + // Bind any pending AxProviderImpl interface requests. + for (auto it : ax_provider_requests_) + ax_providers_.insert(new AxProviderImpl(web_view_, it->Pass())); + STLDeleteElements(&ax_provider_requests_); +} + +void HTMLDocumentOOPIF::didNavigateWithinPage( + blink::WebLocalFrame* frame, + const blink::WebHistoryItem& history_item, + blink::WebHistoryCommitType commit_type) { + if (navigator_host_.get()) + navigator_host_->DidNavigateLocally(history_item.urlString().utf8()); +} + +blink::WebEncryptedMediaClient* HTMLDocumentOOPIF::encryptedMediaClient() { + return setup_->media_factory()->GetEncryptedMediaClient(); +} + +void HTMLDocumentOOPIF::OnViewBoundsChanged(View* view, + const Rect& old_bounds, + const Rect& new_bounds) { + DCHECK_EQ(view, root_); + UpdateWebviewSizeFromViewSize(); +} + +void HTMLDocumentOOPIF::OnViewViewportMetricsChanged( + mojo::View* view, + const mojo::ViewportMetrics& old_metrics, + const mojo::ViewportMetrics& new_metrics) { + InitSetupAndLoadIfNecessary(); +} + +void HTMLDocumentOOPIF::OnViewDestroyed(View* view) { + DCHECK_EQ(view, root_); + root_ = nullptr; +} + +void HTMLDocumentOOPIF::OnViewInputEvent(View* view, + const mojo::EventPtr& event) { + if (event->pointer_data) { + // Blink expects coordintes to be in DIPs. + event->pointer_data->x /= setup_->device_pixel_ratio(); + event->pointer_data->y /= setup_->device_pixel_ratio(); + event->pointer_data->screen_x /= setup_->device_pixel_ratio(); + event->pointer_data->screen_y /= setup_->device_pixel_ratio(); + } + + if ((event->action == mojo::EVENT_TYPE_POINTER_DOWN || + event->action == mojo::EVENT_TYPE_POINTER_UP || + event->action == mojo::EVENT_TYPE_POINTER_CANCEL || + event->action == mojo::EVENT_TYPE_POINTER_MOVE) && + event->pointer_data->kind == mojo::POINTER_KIND_TOUCH) { + touch_handler_->OnTouchEvent(*event); + return; + } + scoped_ptr<blink::WebInputEvent> web_event = + event.To<scoped_ptr<blink::WebInputEvent>>(); + if (web_event) + web_view_->handleInputEvent(*web_event); +} + +void HTMLDocumentOOPIF::OnViewFocusChanged(mojo::View* gained_focus, + mojo::View* lost_focus) { + UpdateFocus(); +} + +void HTMLDocumentOOPIF::UpdateFocus() { + if (!web_view_) + return; + bool is_focused = root_ && root_->HasFocus(); + web_view_->setFocus(is_focused); + web_view_->setIsActive(is_focused); +} + +} // namespace html_viewer diff --git a/components/html_viewer/html_document_oopif.h b/components/html_viewer/html_document_oopif.h new file mode 100644 index 0000000..989992c --- /dev/null +++ b/components/html_viewer/html_document_oopif.h @@ -0,0 +1,199 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_HTML_VIEWER_HTML_DOCUMENT_OOPIF_H_ +#define COMPONENTS_HTML_VIEWER_HTML_DOCUMENT_OOPIF_H_ + +#include <map> +#include <set> + +#include "base/callback.h" +#include "base/macros.h" +#include "components/html_viewer/ax_provider_impl.h" +#include "components/html_viewer/frame_tree_manager.h" +#include "components/html_viewer/touch_handler.h" +#include "components/view_manager/public/cpp/view_manager_client_factory.h" +#include "components/view_manager/public/cpp/view_manager_delegate.h" +#include "components/view_manager/public/cpp/view_observer.h" +#include "mandoline/services/navigation/public/interfaces/navigation.mojom.h" +#include "mandoline/tab/public/interfaces/frame_tree.mojom.h" +#include "mojo/application/public/cpp/app_lifetime_helper.h" +#include "mojo/application/public/cpp/interface_factory.h" +#include "mojo/application/public/cpp/lazy_interface_ptr.h" +#include "mojo/application/public/cpp/service_provider_impl.h" +#include "mojo/application/public/interfaces/application.mojom.h" +#include "mojo/application/public/interfaces/content_handler.mojom.h" +#include "mojo/services/network/public/interfaces/url_loader.mojom.h" +#include "third_party/WebKit/public/web/WebFrameClient.h" +#include "third_party/WebKit/public/web/WebSandboxFlags.h" +#include "third_party/WebKit/public/web/WebViewClient.h" +#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h" + +namespace base { +class SingleThreadTaskRunner; +} + +namespace mojo { +class ViewManager; +class View; +} + +namespace html_viewer { + +class AxProviderImpl; +class DevToolsAgentImpl; +class Setup; +class WebLayerTreeViewImpl; + +// A view for a single HTML document. +// +// HTMLDocument is deleted in one of two ways: +// . When the View the HTMLDocument is embedded in is destroyed. +// . Explicitly by way of Destroy(). +class HTMLDocumentOOPIF + : public blink::WebViewClient, + public blink::WebFrameClient, + public mojo::ViewManagerDelegate, + public mojo::ViewObserver, + public mojo::InterfaceFactory<mojo::AxProvider>, + public mojo::InterfaceFactory<mandoline::FrameTreeClient> { + public: + using DeleteCallback = base::Callback<void(HTMLDocumentOOPIF*)>; + + // Load a new HTMLDocumentOOPIF with |response|. + // |html_document_app| is the application this app was created in, and + // |connection| the specific connection triggering this new instance. + // |setup| is used to obtain init type state (such as resources). + HTMLDocumentOOPIF(mojo::ApplicationImpl* html_document_app, + mojo::ApplicationConnection* connection, + mojo::URLResponsePtr response, + Setup* setup, + const DeleteCallback& delete_callback); + + // Deletes this object. + void Destroy(); + + private: + // Data associated with a child iframe. + struct ChildFrameData { + mojo::View* view; + blink::WebTreeScopeType scope; + }; + + using FrameToViewMap = std::map<blink::WebLocalFrame*, ChildFrameData>; + + ~HTMLDocumentOOPIF() override; + + // Updates the size and scale factor of the webview and related classes from + // |root_|. + void UpdateWebviewSizeFromViewSize(); + + void InitSetupAndLoadIfNecessary(); + + // WebViewClient methods: + virtual blink::WebStorageNamespace* createSessionStorageNamespace(); + + // WebWidgetClient methods: + void initializeLayerTreeView() override; + blink::WebLayerTreeView* layerTreeView() override; + + // WebFrameClient methods: + virtual blink::WebMediaPlayer* createMediaPlayer( + blink::WebLocalFrame* frame, + const blink::WebURL& url, + blink::WebMediaPlayerClient* client, + blink::WebContentDecryptionModule* initial_cdm); + virtual blink::WebFrame* createChildFrame( + blink::WebLocalFrame* parent, + blink::WebTreeScopeType scope, + const blink::WebString& frameName, + blink::WebSandboxFlags sandboxFlags); + virtual void frameDetached(blink::WebFrame* frame); + virtual void frameDetached(blink::WebFrame* frame, DetachType type); + virtual blink::WebCookieJar* cookieJar(blink::WebLocalFrame* frame); + virtual blink::WebNavigationPolicy decidePolicyForNavigation( + const NavigationPolicyInfo& info); + + virtual void didAddMessageToConsole(const blink::WebConsoleMessage& message, + const blink::WebString& source_name, + unsigned source_line, + const blink::WebString& stack_trace); + virtual void didFinishLoad(blink::WebLocalFrame* frame); + virtual void didNavigateWithinPage(blink::WebLocalFrame* frame, + const blink::WebHistoryItem& history_item, + blink::WebHistoryCommitType commit_type); + virtual blink::WebEncryptedMediaClient* encryptedMediaClient(); + + // ViewManagerDelegate methods: + void OnEmbed(mojo::View* root) override; + void OnViewManagerDestroyed(mojo::ViewManager* view_manager) override; + + // ViewObserver methods: + void OnViewBoundsChanged(mojo::View* view, + const mojo::Rect& old_bounds, + const mojo::Rect& new_bounds) override; + void OnViewViewportMetricsChanged( + mojo::View* view, + const mojo::ViewportMetrics& old_metrics, + const mojo::ViewportMetrics& new_metrics) override; + void OnViewDestroyed(mojo::View* view) override; + void OnViewInputEvent(mojo::View* view, const mojo::EventPtr& event) override; + void OnViewFocusChanged(mojo::View* gained_focus, + mojo::View* lost_focus) override; + + // mojo::InterfaceFactory<mojo::AxProvider> + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mojo::AxProvider> request) override; + + // mojo::InterfaceFactory<mandoline::FrameTreeClient> + void Create( + mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mandoline::FrameTreeClient> request) override; + + void Load(mojo::URLResponsePtr response); + + // Converts a WebLocalFrame to a WebRemoteFrame. Used once we know the + // url of a frame to trigger the navigation. + void ConvertLocalFrameToRemoteFrame(blink::WebLocalFrame* frame); + + // Updates the focus state of |web_view_| based on the focus state of |root_|. + void UpdateFocus(); + + scoped_ptr<mojo::AppRefCount> app_refcount_; + mojo::ApplicationImpl* html_document_app_; + mojo::URLResponsePtr response_; + mojo::LazyInterfacePtr<mojo::NavigatorHost> navigator_host_; + blink::WebView* web_view_; + mojo::View* root_; + mojo::ViewManagerClientFactory view_manager_client_factory_; + scoped_ptr<WebLayerTreeViewImpl> web_layer_tree_view_impl_; + scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_; + + // HTMLDocumentOOPIF owns these pointers; binding requests after document + // load. + std::set<mojo::InterfaceRequest<mojo::AxProvider>*> ax_provider_requests_; + std::set<AxProviderImpl*> ax_providers_; + + // A flag set on didFinishLoad. + bool did_finish_load_ = false; + + Setup* setup_; + + scoped_ptr<TouchHandler> touch_handler_; + + FrameToViewMap frame_to_view_; + + FrameTreeManager frame_tree_manager_; + mojo::Binding<mandoline::FrameTreeClient> frame_tree_manager_binding_; + + scoped_ptr<DevToolsAgentImpl> devtools_agent_; + + DeleteCallback delete_callback_; + + DISALLOW_COPY_AND_ASSIGN(HTMLDocumentOOPIF); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_HTML_DOCUMENT_OOPIF_H_ diff --git a/components/html_viewer/html_viewer.cc b/components/html_viewer/html_viewer.cc index fb5cfeb..f4cb7a5 100644 --- a/components/html_viewer/html_viewer.cc +++ b/components/html_viewer/html_viewer.cc @@ -12,6 +12,7 @@ #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" #include "components/html_viewer/html_document.h" +#include "components/html_viewer/html_document_oopif.h" #include "components/html_viewer/setup.h" #include "mojo/application/public/cpp/application_connection.h" #include "mojo/application/public/cpp/application_delegate.h" @@ -40,6 +41,15 @@ using mojo::URLLoaderPtr; using mojo::URLResponsePtr; namespace html_viewer { +namespace { + +// Switch to enable out of process iframes. +const char kOOPIF[] = "oopifs"; + +bool EnableOOPIFs() { + return base::CommandLine::ForCurrentProcess()->HasSwitch(kOOPIF); +} +} class HTMLViewer; @@ -68,6 +78,10 @@ class HTMLDocumentApplicationDelegate : public mojo::ApplicationDelegate { std::set<HTMLDocument*> documents(documents_); for (HTMLDocument* doc : documents) doc->Destroy(); + + std::set<HTMLDocumentOOPIF*> documents2(documents2_); + for (HTMLDocumentOOPIF* doc : documents2) + doc->Destroy(); } // Callback from the quit closure. We key off this rather than @@ -116,16 +130,29 @@ class HTMLDocumentApplicationDelegate : public mojo::ApplicationDelegate { documents_.erase(document); } + void OnHTMLDocumentDeleted2(HTMLDocumentOOPIF* document) { + DCHECK(documents2_.count(document) > 0); + documents2_.erase(document); + } + void OnResponseReceived(URLLoaderPtr loader, mojo::ApplicationConnection* connection, URLResponsePtr response) { // HTMLDocument is destroyed when the hosting view is destroyed, or // explicitly from our destructor. - HTMLDocument* document = new HTMLDocument( - &app_, connection, response.Pass(), setup_, - base::Bind(&HTMLDocumentApplicationDelegate::OnHTMLDocumentDeleted, - base::Unretained(this))); - documents_.insert(document); + if (EnableOOPIFs()) { + HTMLDocumentOOPIF* document = new HTMLDocumentOOPIF( + &app_, connection, response.Pass(), setup_, + base::Bind(&HTMLDocumentApplicationDelegate::OnHTMLDocumentDeleted2, + base::Unretained(this))); + documents2_.insert(document); + } else { + HTMLDocument* document = new HTMLDocument( + &app_, connection, response.Pass(), setup_, + base::Bind(&HTMLDocumentApplicationDelegate::OnHTMLDocumentDeleted, + base::Unretained(this))); + documents_.insert(document); + } } mojo::ApplicationImpl app_; @@ -141,6 +168,10 @@ class HTMLDocumentApplicationDelegate : public mojo::ApplicationDelegate { // HTMLDocument is deleted. std::set<HTMLDocument*> documents_; + // As we create HTMLDocuments they are added here. They are removed when the + // HTMLDocument is deleted. + std::set<HTMLDocumentOOPIF*> documents2_; + DISALLOW_COPY_AND_ASSIGN(HTMLDocumentApplicationDelegate); }; |