diff options
author | jam <jam@chromium.org> | 2015-04-22 13:38:16 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-22 20:39:00 +0000 |
commit | 81a5661f60738efa7dbbee0a72f2c1e15f6690f9 (patch) | |
tree | 27fe82ed9e8d8b504f6c731365df1fc9e2c3d1f6 /components/html_viewer | |
parent | aa86d5f0d050b3322ed02d81e5f51787726f5511 (diff) | |
download | chromium_src-81a5661f60738efa7dbbee0a72f2c1e15f6690f9.zip chromium_src-81a5661f60738efa7dbbee0a72f2c1e15f6690f9.tar.gz chromium_src-81a5661f60738efa7dbbee0a72f2c1e15f6690f9.tar.bz2 |
Move html_viewer from mojo/services to components.
BUG=479353
TBR=jochen for DEPS
Review URL: https://codereview.chromium.org/1099303002
Cr-Commit-Position: refs/heads/master@{#326369}
Diffstat (limited to 'components/html_viewer')
58 files changed, 6318 insertions, 0 deletions
diff --git a/components/html_viewer/BUILD.gn b/components/html_viewer/BUILD.gn new file mode 100644 index 0000000..75856bc --- /dev/null +++ b/components/html_viewer/BUILD.gn @@ -0,0 +1,242 @@ +# 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. + +import("//testing/test.gni") +import("//third_party/mojo/src/mojo/public/mojo.gni") +import("//third_party/mojo/src/mojo/public/mojo_application.gni") +import("//tools/grit/repack.gni") + +# Repack this here. +repack("unified_blink_resources") { + sources = [ + "$root_gen_dir/blink/public/resources/blink_image_resources_100_percent.pak", + "$root_gen_dir/blink/public/resources/blink_resources.pak", + ] + output = "$target_gen_dir/unified_blink_resources.pak" + deps = [ + "//third_party/WebKit/public:image_resources", + "//third_party/WebKit/public:resources", + ] +} + +action("generate_blink_resource_map") { + script = "//components/html_viewer/generate_blink_resource_map.py" + args = [ + "--pak-file", + rebase_path("$target_gen_dir/unified_blink_resources.pak"), + "--header", + rebase_path("$target_gen_dir/blink_resource_map.h"), + "--cpp", + rebase_path("$target_gen_dir/blink_resource_map.cc"), + ] + outputs = [ + "$target_gen_dir/blink_resource_map.cc", + "$target_gen_dir/blink_resource_map.h", + ] + deps = [ + ":unified_blink_resources", + ] + public_deps = [ + "//third_party/WebKit/public:image_resources", + "//third_party/WebKit/public:resources", + ] +} + +source_set("lib") { + sources = [ + "$target_gen_dir/blink_resource_map.cc", + "$target_gen_dir/blink_resource_map.h", + "ax_provider_impl.cc", + "ax_provider_impl.h", + "blink_basic_type_converters.cc", + "blink_basic_type_converters.h", + "blink_input_events_type_converters.cc", + "blink_input_events_type_converters.h", + "blink_platform_impl.cc", + "blink_platform_impl.h", + "blink_resource_constants.h", + "blink_url_request_type_converters.cc", + "blink_url_request_type_converters.h", + "discardable_memory_allocator.cc", + "discardable_memory_allocator.h", + "html_document.cc", + "html_document.h", + "mock_web_blob_registry_impl.cc", + "mock_web_blob_registry_impl.h", + "touch_handler.cc", + "touch_handler.h", + "web_clipboard_impl.cc", + "web_clipboard_impl.h", + "web_cookie_jar_impl.cc", + "web_cookie_jar_impl.h", + "web_layer_tree_view_impl.cc", + "web_layer_tree_view_impl.h", + "web_media_player_factory.cc", + "web_media_player_factory.h", + "web_media_player_factory.h", + "web_message_port_channel_impl.cc", + "web_message_port_channel_impl.h", + "web_mime_registry_impl.cc", + "web_mime_registry_impl.h", + "web_notification_manager_impl.cc", + "web_notification_manager_impl.h", + "web_scheduler_impl.cc", + "web_scheduler_impl.h", + "web_socket_handle_impl.cc", + "web_socket_handle_impl.h", + "web_storage_namespace_impl.cc", + "web_storage_namespace_impl.h", + "web_theme_engine_impl.cc", + "web_theme_engine_impl.h", + "web_thread_impl.cc", + "web_thread_impl.h", + "web_url_loader_impl.cc", + "web_url_loader_impl.h", + ] + + include_dirs = [ "third_party/WebKit" ] + + deps = [ + "//base", + "//base/third_party/dynamic_annotations", + "//cc", + "//cc/blink", + "//cc/surfaces", + "//components/webcrypto", + "//gin", + "//media", + "//media/blink", + "//media/mojo", + "//mojo/application", + "//mojo/cc", + "//mojo/common", + "//mojo/converters/surfaces", + "//mojo/services/network/public/cpp", + "//mojo/services/network/public/interfaces", + "//net", + "//skia", + "//third_party/mojo/src/mojo/public/c/system:for_shared_library", + "//third_party/mojo/src/mojo/public/cpp/utility", + "//third_party/mojo/src/mojo/public/interfaces/application", + "//third_party/mojo_services/src/accessibility/public/interfaces", + "//third_party/mojo_services/src/clipboard/public/interfaces", + "//third_party/mojo_services/src/content_handler/public/interfaces", + "//third_party/mojo_services/src/gpu/public/interfaces", + "//third_party/mojo_services/src/input_events/public/interfaces", + "//third_party/mojo_services/src/navigation/public/interfaces", + "//third_party/mojo_services/src/surfaces/public/interfaces", + "//ui/events", + "//ui/events:gesture_detection", + "//ui/events/blink", + "//ui/events/gestures/blink", + "//ui/gfx/geometry", + "//ui/native_theme", + "//ui/resources:ui_test_pak", + "//url", + ] + + public_deps = [ + "//third_party/WebKit/public:blink", + "//third_party/mojo/src/mojo/public/cpp/bindings", + "//third_party/mojo_services/src/view_manager/public/cpp", + ":generate_blink_resource_map", + ] + + if (is_win) { + sources += [ "html_viewer_version.rc" ] + } +} + +if (is_android) { + import("//build/config/android/rules.gni") + + java_library_path = "$target_out_dir/java_library.dex.jar" + + mojo_android_application("html_viewer") { + input_so = "$root_out_dir/lib.stripped/libhtml_viewer_lib.so" + input_dex_jar = java_library_path + } + + shared_library("html_viewer_lib") { + sources = [ + "android/android_hooks.cc", + "html_viewer.cc", + ] + + deps = [ + ":html_viewer_jni_headers", + ":lib", + "//base", + "//ui/gfx:gfx_jni_headers", + ] + + data_deps = [ "//mojo/services/network:network" ] + } + + generate_jni("html_viewer_jni_headers") { + sources = [ + "android/java/org/chromium/html_viewer/Main.java", + ] + jni_package = "mojo/services/html_viewer" + } + + android_library("html_viewer_java_classes") { + java_files = [ "android/java/org/chromium/html_viewer/Main.java" ] + + deps = [ + "//base:base_java", + ] + } + + android_standalone_library("java_library") { + dex_path = java_library_path + + deps = [ + ":html_viewer_java_classes", + + # TODO(sky): this is WAY more than we need. We really only need + # DeviceDisplayInfo. Refactor to make this clearer. + "//ui/android:ui_java", + ] + } +} else { + mojo_native_application("html_viewer") { + sources = [ + "html_viewer.cc", + ] + deps = [ + ":lib", + ] + data_deps = [ "//mojo/services/network:network" ] + } +} + +test("tests") { + output_name = "html_viewer_unittests" + sources = [ + "ax_provider_impl_unittest.cc", + "discardable_memory_allocator_unittest.cc", + ] + deps = [ + ":lib", + "//base/test:run_all_unittests", + ] +} + +mojo_native_application("apptests") { + output_name = "html_viewer_apptests" + testonly = true + + sources = [ + "ax_provider_apptest.cc", + ] + + deps = [ + ":lib", + ":html_viewer", + "//mojo/application:test_support", + "//net:test_support", + "//testing/gtest", + ] +} diff --git a/components/html_viewer/DEPS b/components/html_viewer/DEPS new file mode 100644 index 0000000..c513c40 --- /dev/null +++ b/components/html_viewer/DEPS @@ -0,0 +1,26 @@ +include_rules = [ + "+base", + "+base/test", + "+blink/public/resources", + "+cc", + "+components/webcrypto", + "+gin", + "+media", + "+mojo/application", + "+mojo/cc", + "+mojo/common", + "+mojo/converters/surfaces", + "+mojo/public", + "+mojo/services/network", + "+net/base", + "+net/test/spawned_test_server", + "+skia", + "+third_party/mojo/src/mojo/public", + "+third_party/mojo_services/src", + "+third_party/WebKit/public", + "+third_party/skia/include", + "+ui/base", + "+ui/events", + "+ui/gfx/geometry", + "+ui/native_theme", +] diff --git a/components/html_viewer/OWNERS b/components/html_viewer/OWNERS new file mode 100644 index 0000000..90b3e80 --- /dev/null +++ b/components/html_viewer/OWNERS @@ -0,0 +1 @@ +sky@chromium.org diff --git a/components/html_viewer/android/android_hooks.cc b/components/html_viewer/android/android_hooks.cc new file mode 100644 index 0000000..ab553fe --- /dev/null +++ b/components/html_viewer/android/android_hooks.cc @@ -0,0 +1,50 @@ +// Copyright 2015 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 <vector> + +#include "base/android/base_jni_onload.h" +#include "base/android/jni_android.h" +#include "base/android/library_loader/library_loader_hooks.h" +#include "base/bind.h" +#include "components/html_viewer/jni/Main_jni.h" + +namespace { +bool RegisterJNI(JNIEnv* env) { + return true; +} + +bool Init() { + Java_Main_init(base::android::AttachCurrentThread(), + base::android::GetApplicationContext()); + return true; +} +} // namespace + +// This is called by the VM when the shared library is first loaded. +JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { + std::vector<base::android::RegisterCallback> register_callbacks; + register_callbacks.push_back(base::Bind(&RegisterJNI)); + register_callbacks.push_back(base::Bind(&RegisterNativesImpl)); + + std::vector<base::android::InitCallback> init_callbacks; + init_callbacks.push_back(base::Bind(&Init)); + + if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || + !base::android::OnJNIOnLoadInit(init_callbacks)) { + return -1; + } + + // There cannot be two AtExitManagers at the same time. Remove the one from + // LibraryLoader as ApplicationRunnerChromium also uses one. + base::android::LibraryLoaderExitHook(); + + return JNI_VERSION_1_4; +} + +extern "C" JNI_EXPORT void InitApplicationContext( + const base::android::JavaRef<jobject>& context) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::InitApplicationContext(env, context); +} diff --git a/components/html_viewer/android/java/org/chromium/html_viewer/Main.java b/components/html_viewer/android/java/org/chromium/html_viewer/Main.java new file mode 100644 index 0000000..87a7b59 --- /dev/null +++ b/components/html_viewer/android/java/org/chromium/html_viewer/Main.java @@ -0,0 +1,25 @@ +// Copyright 2015 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. + +package org.chromium.html_viewer; + +import android.content.Context; + +import org.chromium.base.CalledByNative; +import org.chromium.base.PathUtils; + +/** + * This class does setup for html_viewer. + */ +public final class Main { + private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "html_viewer"; + + private Main() {} + + @SuppressWarnings("unused") + @CalledByNative + private static void init(Context context) { + PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX, context); + } +} diff --git a/components/html_viewer/ax_provider_apptest.cc b/components/html_viewer/ax_provider_apptest.cc new file mode 100644 index 0000000..576b89a --- /dev/null +++ b/components/html_viewer/ax_provider_apptest.cc @@ -0,0 +1,88 @@ +// Copyright 2015 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 "base/bind.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "base/test/test_timeouts.h" +#include "mojo/application/application_test_base_chromium.h" +#include "mojo/public/cpp/application/application_impl.h" +#include "net/test/spawned_test_server/spawned_test_server.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/mojo_services/src/accessibility/public/interfaces/accessibility.mojom.h" + +namespace mojo { + +namespace { + +base::RunLoop* current_run_loop = nullptr; + +void TimeoutRunLoop(const base::Closure& timeout_task, bool* timeout) { + CHECK(current_run_loop); + *timeout = true; + timeout_task.Run(); +} + +bool DoRunLoopWithTimeout() { + if (current_run_loop != nullptr) + return false; + + bool timeout = false; + base::RunLoop run_loop; + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, base::Bind(&TimeoutRunLoop, run_loop.QuitClosure(), &timeout), + TestTimeouts::action_timeout()); + + current_run_loop = &run_loop; + current_run_loop->Run(); + current_run_loop = nullptr; + return !timeout; +} + +void QuitRunLoop() { + current_run_loop->Quit(); + current_run_loop = nullptr; +} + +// Returns true if the tree contains a text node with contents matching |text|. +bool AxTreeContainsText(const Array<AxNodePtr>& tree, const String& text) { + for (size_t i = 0; i < tree.size(); ++i) { + if (!tree[i]->text.is_null() && tree[i]->text->content == text) + return true; + } + return false; +} + +} // namespace + +typedef test::ApplicationTestBase AXProviderTest; + +TEST_F(AXProviderTest, HelloWorld) { + // Start a test server for net/data/test.html access. + net::SpawnedTestServer server( + net::SpawnedTestServer::TYPE_HTTP, net::SpawnedTestServer::kLocalhost, + base::FilePath(FILE_PATH_LITERAL("net/data"))); + ASSERT_TRUE(server.Start()); + + // Connect to the URL through the mojo:html_viewer content handler. + const uint16_t assigned_port = server.host_port_pair().port(); + ApplicationConnection* connection = application_impl()->ConnectToApplication( + base::StringPrintf("http://127.0.0.1:%u/files/test.html", assigned_port)); + + // Connect to the AxProvider of the HTML document and get the AxTree. + AxProviderPtr ax_provider; + connection->ConnectToService(&ax_provider); + Array<AxNodePtr> ax_tree; + ax_provider->GetTree([&ax_tree](Array<AxNodePtr> tree) { + ax_tree = tree.Pass(); + QuitRunLoop(); + }); + ASSERT_TRUE(DoRunLoopWithTimeout()); + + EXPECT_TRUE(AxTreeContainsText(ax_tree, "Hello ")); + EXPECT_TRUE(AxTreeContainsText(ax_tree, "World!")); + EXPECT_FALSE(AxTreeContainsText(ax_tree, "foo")); +} + +} // namespace mojo
\ No newline at end of file diff --git a/components/html_viewer/ax_provider_impl.cc b/components/html_viewer/ax_provider_impl.cc new file mode 100644 index 0000000..bc7dc3c --- /dev/null +++ b/components/html_viewer/ax_provider_impl.cc @@ -0,0 +1,86 @@ +// 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/ax_provider_impl.h" + +#include "components/html_viewer/blink_basic_type_converters.h" +#include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/web/WebAXObject.h" +#include "third_party/WebKit/public/web/WebSettings.h" +#include "third_party/WebKit/public/web/WebView.h" + +using blink::WebAXObject; +using blink::WebURL; +using blink::WebView; + +using mojo::Array; +using mojo::AxNodePtr; +using mojo::String; + +namespace html_viewer { + +AxProviderImpl::AxProviderImpl(WebView* web_view) : web_view_(web_view) { +} + +void AxProviderImpl::GetTree( + const mojo::Callback<void(Array<AxNodePtr> nodes)>& callback) { + web_view_->settings()->setAccessibilityEnabled(true); + web_view_->settings()->setInlineTextBoxAccessibilityEnabled(true); + + Array<AxNodePtr> result; + Populate(web_view_->accessibilityObject(), 0, 0, &result); + callback.Run(result.Pass()); +} + +int AxProviderImpl::Populate(const WebAXObject& ax_object, + int parent_id, + int next_sibling_id, + Array<AxNodePtr>* result) { + AxNodePtr ax_node(ConvertAxNode(ax_object, parent_id, next_sibling_id)); + int ax_node_id = ax_node->id; + if (ax_node.is_null()) + return 0; + + result->push_back(ax_node.Pass()); + + unsigned num_children = ax_object.childCount(); + next_sibling_id = 0; + for (unsigned i = 0; i < num_children; ++i) { + int new_id = Populate(ax_object.childAt(num_children - i - 1), + ax_node_id, + next_sibling_id, + result); + if (new_id != 0) + next_sibling_id = new_id; + } + + return ax_node_id; +} + +AxNodePtr AxProviderImpl::ConvertAxNode(const WebAXObject& ax_object, + int parent_id, + int next_sibling_id) { + AxNodePtr result; + if (!const_cast<WebAXObject&>(ax_object).updateLayoutAndCheckValidity()) + return result.Pass(); + + result = mojo::AxNode::New(); + result->id = static_cast<int>(ax_object.axID()); + result->parent_id = parent_id; + result->next_sibling_id = next_sibling_id; + result->bounds = mojo::Rect::From(ax_object.boundingBoxRect()); + + if (ax_object.isAnchor()) { + result->link = mojo::AxLink::New(); + result->link->url = String::From(ax_object.url().string()); + } else if (ax_object.childCount() == 0 && + !ax_object.stringValue().isEmpty()) { + result->text = mojo::AxText::New(); + result->text->content = String::From(ax_object.stringValue()); + } + + return result.Pass(); +} + +} // namespace html_viewer diff --git a/components/html_viewer/ax_provider_impl.h b/components/html_viewer/ax_provider_impl.h new file mode 100644 index 0000000..cea1d45 --- /dev/null +++ b/components/html_viewer/ax_provider_impl.h @@ -0,0 +1,39 @@ +// 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_AX_PROVIDER_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_AX_PROVIDER_IMPL_H_ + +#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h" +#include "third_party/mojo_services/src/accessibility/public/interfaces/accessibility.mojom.h" + +namespace blink { +class WebAXObject; +class WebView; +} // namespace blink + +namespace html_viewer { + +// Caller must ensure that |web_view| outlives AxProviderImpl. +class AxProviderImpl : public mojo::InterfaceImpl<mojo::AxProvider> { + public: + explicit AxProviderImpl(blink::WebView* web_view); + void GetTree(const mojo::Callback<void(mojo::Array<mojo::AxNodePtr> nodes)>& + callback) override; + + private: + int Populate(const blink::WebAXObject& ax_object, + int parent_id, + int next_sibling_id, + mojo::Array<mojo::AxNodePtr>* result); + mojo::AxNodePtr ConvertAxNode(const blink::WebAXObject& ax_object, + int parent_id, + int next_sibling_id); + + blink::WebView* web_view_; +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_AX_PROVIDER_IMPL_H_ diff --git a/components/html_viewer/ax_provider_impl_unittest.cc b/components/html_viewer/ax_provider_impl_unittest.cc new file mode 100644 index 0000000..f8688d3 --- /dev/null +++ b/components/html_viewer/ax_provider_impl_unittest.cc @@ -0,0 +1,178 @@ +// 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/ax_provider_impl.h" + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "components/html_viewer/blink_platform_impl.h" +#include "gin/v8_initializer.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/WebData.h" +#include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/web/WebFrameClient.h" +#include "third_party/WebKit/public/web/WebKit.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebView.h" +#include "third_party/WebKit/public/web/WebViewClient.h" +#include "url/gurl.h" + +using blink::WebData; +using blink::WebLocalFrame; +using blink::WebFrameClient; +using blink::WebURL; +using blink::WebView; +using blink::WebViewClient; + +using mojo::Array; +using mojo::AxNode; +using mojo::AxNodePtr; + +namespace { + +class TestWebFrameClient : public WebFrameClient { + public: + ~TestWebFrameClient() override {} + void didStopLoading() override { base::MessageLoop::current()->Quit(); } +}; + +class TestWebViewClient : public WebViewClient { + public: + bool allowsBrokenNullLayerTreeView() const override { return true; } + virtual ~TestWebViewClient() {} +}; + +class AxProviderImplTest : public testing::Test { + public: + AxProviderImplTest() { +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) + gin::V8Initializer::LoadV8Snapshot(); +#endif + blink::initialize(new html_viewer::BlinkPlatformImpl(nullptr)); + } + + ~AxProviderImplTest() override { blink::shutdown(); } + + private: + base::MessageLoopForUI message_loop; +}; + +struct NodeCatcher { + void OnNodes(Array<AxNodePtr> nodes) { this->nodes = nodes.Pass(); } + Array<AxNodePtr> nodes; +}; + +AxNodePtr CreateNode(int id, + int parent_id, + int next_sibling_id, + const mojo::RectPtr& bounds, + const std::string& url, + const std::string& text) { + AxNodePtr node(AxNode::New()); + node->id = id; + node->parent_id = parent_id; + node->next_sibling_id = next_sibling_id; + node->bounds = bounds.Clone(); + + if (!url.empty()) { + node->link = mojo::AxLink::New(); + node->link->url = url; + } + if (!text.empty()) { + node->text = mojo::AxText::New(); + node->text->content = text; + } + return node.Pass(); +} + +} // namespace + +TEST_F(AxProviderImplTest, Basic) { + TestWebViewClient web_view_client; + TestWebFrameClient web_frame_client; + WebView* view = WebView::create(&web_view_client); + view->setMainFrame(WebLocalFrame::create(&web_frame_client)); + view->mainFrame()->loadHTMLString( + WebData( + "<html><body>foo<a " + "href='http://monkey.net'>bar</a>baz</body></html>"), + WebURL(GURL("http://someplace.net"))); + base::MessageLoop::current()->Run(); + + html_viewer::AxProviderImpl ax_provider_impl(view); + NodeCatcher catcher; + ax_provider_impl.GetTree( + base::Bind(&NodeCatcher::OnNodes, base::Unretained(&catcher))); + + std::map<uint32, AxNode*> lookup; + for (size_t i = 0; i < catcher.nodes.size(); ++i) { + auto& node = catcher.nodes[i]; + lookup[node->id] = node.get(); + } + + typedef decltype(lookup)::value_type MapEntry; + auto is_link = [](MapEntry pair) { return !pair.second->link.is_null(); }; + auto is_text = [](MapEntry pair, const char* content) { + return !pair.second->text.is_null() && + pair.second->text->content.To<std::string>() == content; + }; + auto is_foo = [&is_text](MapEntry pair) { return is_text(pair, "foo"); }; + auto is_bar = [&is_text](MapEntry pair) { return is_text(pair, "bar"); }; + auto is_baz = [&is_text](MapEntry pair) { return is_text(pair, "baz"); }; + + EXPECT_EQ(1, std::count_if(lookup.begin(), lookup.end(), is_link)); + EXPECT_EQ(1, std::count_if(lookup.begin(), lookup.end(), is_foo)); + EXPECT_EQ(1, std::count_if(lookup.begin(), lookup.end(), is_bar)); + EXPECT_EQ(1, std::count_if(lookup.begin(), lookup.end(), is_baz)); + + auto root = lookup[1u]; + auto link = std::find_if(lookup.begin(), lookup.end(), is_link)->second; + auto foo = std::find_if(lookup.begin(), lookup.end(), is_foo)->second; + auto bar = std::find_if(lookup.begin(), lookup.end(), is_bar)->second; + auto baz = std::find_if(lookup.begin(), lookup.end(), is_baz)->second; + + // Test basic content of each node. The properties we copy (like parent_id) + // here are tested differently below. + EXPECT_TRUE(CreateNode(root->id, 0, 0, root->bounds, "", "")->Equals(*root)); + EXPECT_TRUE(CreateNode(foo->id, foo->parent_id, 0, foo->bounds, "", "foo") + ->Equals(*foo)); + EXPECT_TRUE(CreateNode(bar->id, bar->parent_id, 0, bar->bounds, "", "bar") + ->Equals(*bar)); + EXPECT_TRUE(CreateNode(baz->id, baz->parent_id, 0, baz->bounds, "", "baz") + ->Equals(*baz)); + EXPECT_TRUE(CreateNode(link->id, + link->parent_id, + link->next_sibling_id, + link->bounds, + "http://monkey.net/", + "")->Equals(*link)); + + auto is_descendant_of = [&lookup](uint32 id, uint32 ancestor) { + for (; (id = lookup[id]->parent_id) != 0;) { + if (id == ancestor) + return true; + } + return false; + }; + + EXPECT_TRUE(is_descendant_of(bar->id, link->id)); + for (auto pair : lookup) { + AxNode* node = pair.second; + if (node != root) + EXPECT_TRUE(is_descendant_of(node->id, 1u)); + if (node != link && node != foo && node != bar && node != baz) { + EXPECT_TRUE(CreateNode(node->id, + node->parent_id, + node->next_sibling_id, + node->bounds, + "", + "")); + } + } + + // TODO(aa): Test bounds. + // TODO(aa): Test sibling ordering of foo/bar/baz. + + view->close(); +} diff --git a/components/html_viewer/blink_basic_type_converters.cc b/components/html_viewer/blink_basic_type_converters.cc new file mode 100644 index 0000000..f7a5ff4 --- /dev/null +++ b/components/html_viewer/blink_basic_type_converters.cc @@ -0,0 +1,46 @@ +// 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/blink_basic_type_converters.h" + +#include "third_party/WebKit/public/platform/WebRect.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/mojo/src/mojo/public/cpp/bindings/string.h" + +using blink::WebRect; +using blink::WebString; + +namespace mojo { + +// static +String TypeConverter<String, WebString>::Convert(const WebString& str) { + return String(str.utf8()); +} + +// static +WebString TypeConverter<WebString, String>::Convert(const String& str) { + return WebString::fromUTF8(str.get()); +} + +// static +RectPtr TypeConverter<RectPtr, WebRect>::Convert(const WebRect& input) { + RectPtr result(Rect::New()); + result->x = input.x; + result->y = input.y; + result->width = input.width; + result->height = input.height; + return result.Pass(); +}; + +// static +Array<uint8_t> TypeConverter<Array<uint8_t>, blink::WebString>::Convert( + const blink::WebString& input) { + std::string utf8 = input.utf8(); + Array<uint8_t> result(utf8.size()); + for (size_t i = 0; i < utf8.size(); ++i) + result[i] = utf8[i]; + return result.Pass(); +} + +} // namespace mojo diff --git a/components/html_viewer/blink_basic_type_converters.h b/components/html_viewer/blink_basic_type_converters.h new file mode 100644 index 0000000..ad2d08b --- /dev/null +++ b/components/html_viewer/blink_basic_type_converters.h @@ -0,0 +1,52 @@ +// 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_BLINK_BASIC_TYPE_CONVERTERS_H_ +#define COMPONENTS_HTML_VIEWER_BLINK_BASIC_TYPE_CONVERTERS_H_ + +#include "third_party/mojo/src/mojo/public/cpp/bindings/type_converter.h" + +#include "third_party/WebKit/public/platform/WebVector.h" +#include "third_party/mojo/src/mojo/public/cpp/bindings/array.h" +#include "third_party/mojo_services/src/geometry/public/interfaces/geometry.mojom.h" + +namespace blink { +struct WebRect; +class WebString; +} + +namespace mojo { +class String; + +template<> +struct TypeConverter<String, blink::WebString> { + static String Convert(const blink::WebString& str); +}; +template<> +struct TypeConverter<blink::WebString, String> { + static blink::WebString Convert(const String& str); +}; +template <> +struct TypeConverter<Array<uint8_t>, blink::WebString> { + static Array<uint8_t> Convert(const blink::WebString& input); +}; + +template <> +struct TypeConverter<RectPtr, blink::WebRect> { + static RectPtr Convert(const blink::WebRect& input); +}; + +template<typename T, typename U> +struct TypeConverter<Array<T>, blink::WebVector<U> > { + static Array<T> Convert(const blink::WebVector<U>& vector) { + Array<T> array(vector.size()); + for (size_t i = 0; i < vector.size(); ++i) + array[i] = TypeConverter<T, U>::Convert(vector[i]); + return array.Pass(); + } +}; + +} // namespace mojo + +#endif // COMPONENTS_HTML_VIEWER_BLINK_BASIC_TYPE_CONVERTERS_H_ diff --git a/components/html_viewer/blink_input_events_type_converters.cc b/components/html_viewer/blink_input_events_type_converters.cc new file mode 100644 index 0000000..0fd8366 --- /dev/null +++ b/components/html_viewer/blink_input_events_type_converters.cc @@ -0,0 +1,190 @@ +// 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/blink_input_events_type_converters.h" + +#include "base/logging.h" +#include "base/time/time.h" +#include "third_party/WebKit/public/web/WebInputEvent.h" +#include "third_party/mojo_services/src/input_events/public/interfaces/input_event_constants.mojom.h" + +namespace mojo { +namespace { + +// Used for scrolling. This matches Firefox behavior. +const int kPixelsPerTick = 53; + +double EventTimeToWebEventTime(const EventPtr& event) { + return base::TimeDelta::FromInternalValue(event->time_stamp).InSecondsF(); +} + +int EventFlagsToWebEventModifiers(int flags) { + int modifiers = 0; + + if (flags & mojo::EVENT_FLAGS_SHIFT_DOWN) + modifiers |= blink::WebInputEvent::ShiftKey; + if (flags & mojo::EVENT_FLAGS_CONTROL_DOWN) + modifiers |= blink::WebInputEvent::ControlKey; + if (flags & mojo::EVENT_FLAGS_ALT_DOWN) + modifiers |= blink::WebInputEvent::AltKey; + // TODO(beng): MetaKey/META_MASK + if (flags & mojo::EVENT_FLAGS_LEFT_MOUSE_BUTTON) + modifiers |= blink::WebInputEvent::LeftButtonDown; + if (flags & mojo::EVENT_FLAGS_MIDDLE_MOUSE_BUTTON) + modifiers |= blink::WebInputEvent::MiddleButtonDown; + if (flags & mojo::EVENT_FLAGS_RIGHT_MOUSE_BUTTON) + modifiers |= blink::WebInputEvent::RightButtonDown; + if (flags & mojo::EVENT_FLAGS_CAPS_LOCK_DOWN) + modifiers |= blink::WebInputEvent::CapsLockOn; + return modifiers; +} + +int EventFlagsToWebInputEventModifiers(int flags) { + return + (flags & mojo::EVENT_FLAGS_SHIFT_DOWN ? + blink::WebInputEvent::ShiftKey : 0) | + (flags & mojo::EVENT_FLAGS_CONTROL_DOWN ? + blink::WebInputEvent::ControlKey : 0) | + (flags & mojo::EVENT_FLAGS_CAPS_LOCK_DOWN ? + blink::WebInputEvent::CapsLockOn : 0) | + (flags & mojo::EVENT_FLAGS_ALT_DOWN ? + blink::WebInputEvent::AltKey : 0); +} + +int GetClickCount(int flags) { + if (flags & mojo::MOUSE_EVENT_FLAGS_IS_TRIPLE_CLICK) + return 3; + else if (flags & mojo::MOUSE_EVENT_FLAGS_IS_DOUBLE_CLICK) + return 2; + + return 1; +} + +void SetWebMouseEventLocation(const mojo::PointerData& pointer_data, + blink::WebMouseEvent* web_event) { + web_event->x = static_cast<int>(pointer_data.x); + web_event->y = static_cast<int>(pointer_data.y); + web_event->globalX = static_cast<int>(pointer_data.screen_x); + web_event->globalY = static_cast<int>(pointer_data.screen_y); +} + +scoped_ptr<blink::WebInputEvent> BuildWebMouseEventFrom(const EventPtr& event) { + scoped_ptr<blink::WebMouseEvent> web_event(new blink::WebMouseEvent); + + SetWebMouseEventLocation(*(event->pointer_data), web_event.get()); + + web_event->modifiers = EventFlagsToWebEventModifiers(event->flags); + web_event->timeStampSeconds = EventTimeToWebEventTime(event); + + web_event->button = blink::WebMouseEvent::ButtonNone; + if (event->flags & mojo::EVENT_FLAGS_LEFT_MOUSE_BUTTON) + web_event->button = blink::WebMouseEvent::ButtonLeft; + if (event->flags & mojo::EVENT_FLAGS_MIDDLE_MOUSE_BUTTON) + web_event->button = blink::WebMouseEvent::ButtonMiddle; + if (event->flags & mojo::EVENT_FLAGS_RIGHT_MOUSE_BUTTON) + web_event->button = blink::WebMouseEvent::ButtonRight; + + switch (event->action) { + case mojo::EVENT_TYPE_POINTER_DOWN: + web_event->type = blink::WebInputEvent::MouseDown; + break; + case mojo::EVENT_TYPE_POINTER_UP: + web_event->type = blink::WebInputEvent::MouseUp; + break; + case mojo::EVENT_TYPE_POINTER_MOVE: + web_event->type = blink::WebInputEvent::MouseMove; + break; + default: + NOTIMPLEMENTED() << "Received unexpected event: " << event->action; + break; + } + + web_event->clickCount = GetClickCount(event->flags); + + return web_event.Pass(); +} + +scoped_ptr<blink::WebInputEvent> BuildWebKeyboardEvent( + const EventPtr& event) { + scoped_ptr<blink::WebKeyboardEvent> web_event(new blink::WebKeyboardEvent); + + web_event->modifiers = EventFlagsToWebInputEventModifiers(event->flags); + web_event->timeStampSeconds = EventTimeToWebEventTime(event); + + switch (event->action) { + case EVENT_TYPE_KEY_PRESSED: + web_event->type = event->key_data->is_char ? blink::WebInputEvent::Char : + blink::WebInputEvent::RawKeyDown; + break; + case EVENT_TYPE_KEY_RELEASED: + web_event->type = blink::WebInputEvent::KeyUp; + break; + default: + NOTREACHED(); + } + + if (web_event->modifiers & blink::WebInputEvent::AltKey) + web_event->isSystemKey = true; + + web_event->windowsKeyCode = event->key_data->windows_key_code; + web_event->nativeKeyCode = event->key_data->native_key_code; + web_event->text[0] = event->key_data->text; + web_event->unmodifiedText[0] = event->key_data->unmodified_text; + + web_event->setKeyIdentifierFromWindowsKeyCode(); + return web_event.Pass(); +} + +scoped_ptr<blink::WebInputEvent> BuildWebMouseWheelEventFrom( + const EventPtr& event) { + scoped_ptr<blink::WebMouseWheelEvent> web_event( + new blink::WebMouseWheelEvent); + web_event->type = blink::WebInputEvent::MouseWheel; + web_event->button = blink::WebMouseEvent::ButtonNone; + web_event->modifiers = EventFlagsToWebEventModifiers(event->flags); + web_event->timeStampSeconds = EventTimeToWebEventTime(event); + + SetWebMouseEventLocation(*(event->pointer_data), web_event.get()); + + if ((event->flags & mojo::EVENT_FLAGS_SHIFT_DOWN) != 0 && + event->pointer_data->horizontal_wheel == 0) { + web_event->deltaX = event->pointer_data->horizontal_wheel; + web_event->deltaY = 0; + } else { + web_event->deltaX = event->pointer_data->horizontal_wheel; + web_event->deltaY = event->pointer_data->vertical_wheel; + } + + // TODO(sky): resole this, doesn't work for desktop. + web_event->wheelTicksX = web_event->deltaX / kPixelsPerTick; + web_event->wheelTicksY = web_event->deltaY / kPixelsPerTick; + + return web_event.Pass(); +} + +} // namespace + +// static +scoped_ptr<blink::WebInputEvent> +TypeConverter<scoped_ptr<blink::WebInputEvent>, EventPtr>::Convert( + const EventPtr& event) { + 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) { + if (event->pointer_data->horizontal_wheel != 0 || + event->pointer_data->vertical_wheel != 0) { + return BuildWebMouseWheelEventFrom(event); + } + if (event->pointer_data->kind == mojo::POINTER_KIND_MOUSE) + return BuildWebMouseEventFrom(event); + } else if ((event->action == mojo::EVENT_TYPE_KEY_PRESSED || + event->action == mojo::EVENT_TYPE_KEY_RELEASED) && + event->key_data) { + return BuildWebKeyboardEvent(event); + } + return nullptr; +} + +} // namespace mojo diff --git a/components/html_viewer/blink_input_events_type_converters.h b/components/html_viewer/blink_input_events_type_converters.h new file mode 100644 index 0000000..6ea239c --- /dev/null +++ b/components/html_viewer/blink_input_events_type_converters.h @@ -0,0 +1,24 @@ +// 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_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_ +#define COMPONENTS_HTML_VIEWER_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_ + +#include "base/memory/scoped_ptr.h" +#include "third_party/mojo_services/src/input_events/public/interfaces/input_events.mojom.h" + +namespace blink { +class WebInputEvent; +} + +namespace mojo { + +template <> +struct TypeConverter<scoped_ptr<blink::WebInputEvent>, EventPtr> { + static scoped_ptr<blink::WebInputEvent> Convert(const EventPtr& input); +}; + +} // namespace mojo + +#endif // COMPONENTS_HTML_VIEWER_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_ diff --git a/components/html_viewer/blink_platform_impl.cc b/components/html_viewer/blink_platform_impl.cc new file mode 100644 index 0000000..4c4ff85 --- /dev/null +++ b/components/html_viewer/blink_platform_impl.cc @@ -0,0 +1,323 @@ +// 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/blink_platform_impl.h" + +#include <cmath> + +#include "base/command_line.h" +#include "base/rand_util.h" +#include "base/stl_util.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/platform_thread.h" +#include "base/time/time.h" +#include "components/html_viewer/blink_resource_constants.h" +#include "components/html_viewer/web_clipboard_impl.h" +#include "components/html_viewer/web_cookie_jar_impl.h" +#include "components/html_viewer/web_message_port_channel_impl.h" +#include "components/html_viewer/web_socket_handle_impl.h" +#include "components/html_viewer/web_thread_impl.h" +#include "components/html_viewer/web_url_loader_impl.h" +#include "net/base/data_url.h" +#include "net/base/mime_util.h" +#include "net/base/net_errors.h" +#include "net/base/net_util.h" +#include "third_party/WebKit/public/platform/WebWaitableEvent.h" +#include "third_party/mojo/src/mojo/public/cpp/application/application_impl.h" +#include "ui/events/gestures/blink/web_gesture_curve_impl.h" + +namespace html_viewer { +namespace { + +// Allows overriding user agent scring. +const char kUserAgentSwitch[] = "user-agent"; + +// TODO(darin): Figure out what our UA should really be. +const char kDefaultUserAgentString[] = + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/42.0.2311.68 Safari/537.36"; + +class WebWaitableEventImpl : public blink::WebWaitableEvent { + public: + WebWaitableEventImpl() : impl_(new base::WaitableEvent(false, false)) {} + ~WebWaitableEventImpl() override {} + + void wait() override { impl_->Wait(); } + void signal() override { impl_->Signal(); } + + base::WaitableEvent* impl() { + return impl_.get(); + } + + private: + scoped_ptr<base::WaitableEvent> impl_; + DISALLOW_COPY_AND_ASSIGN(WebWaitableEventImpl); +}; + +} // namespace + +BlinkPlatformImpl::BlinkPlatformImpl(mojo::ApplicationImpl* app) + : main_loop_(base::MessageLoop::current()), + shared_timer_func_(NULL), + shared_timer_fire_time_(0.0), + shared_timer_fire_time_was_set_while_suspended_(false), + shared_timer_suspended_(0), + current_thread_slot_(&DestroyCurrentThread), + scheduler_(main_loop_->message_loop_proxy()) { + if (app) { + app->ConnectToService("mojo:network_service", &network_service_); + + mojo::CookieStorePtr cookie_store; + network_service_->GetCookieStore(GetProxy(&cookie_store)); + cookie_jar_.reset(new WebCookieJarImpl(cookie_store.Pass())); + + mojo::ClipboardPtr clipboard; + app->ConnectToService("mojo:clipboard", &clipboard); + clipboard_.reset(new WebClipboardImpl(clipboard.Pass())); + } +} + +BlinkPlatformImpl::~BlinkPlatformImpl() { +} + +blink::WebCookieJar* BlinkPlatformImpl::cookieJar() { + return cookie_jar_.get(); +} + +blink::WebClipboard* BlinkPlatformImpl::clipboard() { + return clipboard_.get(); +} + +blink::WebMimeRegistry* BlinkPlatformImpl::mimeRegistry() { + return &mime_registry_; +} + +blink::WebThemeEngine* BlinkPlatformImpl::themeEngine() { + return &theme_engine_; +} + +blink::WebScheduler* BlinkPlatformImpl::scheduler() { + return &scheduler_; +} + +blink::WebString BlinkPlatformImpl::defaultLocale() { + return blink::WebString::fromUTF8("en-US"); +} + +blink::WebBlobRegistry* BlinkPlatformImpl::blobRegistry() { + return &blob_registry_; +} + +double BlinkPlatformImpl::currentTime() { + return base::Time::Now().ToDoubleT(); +} + +double BlinkPlatformImpl::monotonicallyIncreasingTime() { + return base::TimeTicks::Now().ToInternalValue() / + static_cast<double>(base::Time::kMicrosecondsPerSecond); +} + +void BlinkPlatformImpl::cryptographicallyRandomValues(unsigned char* buffer, + size_t length) { + base::RandBytes(buffer, length); +} + +void BlinkPlatformImpl::setSharedTimerFiredFunction(void (*func)()) { + shared_timer_func_ = func; +} + +void BlinkPlatformImpl::setSharedTimerFireInterval( + double interval_seconds) { + shared_timer_fire_time_ = interval_seconds + monotonicallyIncreasingTime(); + if (shared_timer_suspended_) { + shared_timer_fire_time_was_set_while_suspended_ = true; + return; + } + + // By converting between double and int64 representation, we run the risk + // of losing precision due to rounding errors. Performing computations in + // microseconds reduces this risk somewhat. But there still is the potential + // of us computing a fire time for the timer that is shorter than what we + // need. + // As the event loop will check event deadlines prior to actually firing + // them, there is a risk of needlessly rescheduling events and of + // needlessly looping if sleep times are too short even by small amounts. + // This results in measurable performance degradation unless we use ceil() to + // always round up the sleep times. + int64 interval = static_cast<int64>( + ceil(interval_seconds * base::Time::kMillisecondsPerSecond) + * base::Time::kMicrosecondsPerMillisecond); + + if (interval < 0) + interval = 0; + + shared_timer_.Stop(); + shared_timer_.Start(FROM_HERE, base::TimeDelta::FromMicroseconds(interval), + this, &BlinkPlatformImpl::DoTimeout); +} + +void BlinkPlatformImpl::stopSharedTimer() { + shared_timer_.Stop(); +} + +void BlinkPlatformImpl::callOnMainThread( + void (*func)(void*), void* context) { + main_loop_->PostTask(FROM_HERE, base::Bind(func, context)); +} + +bool BlinkPlatformImpl::isThreadedCompositingEnabled() { + return true; +} + +blink::WebCompositorSupport* BlinkPlatformImpl::compositorSupport() { + return &compositor_support_; +} + +void BlinkPlatformImpl::createMessageChannel( + blink::WebMessagePortChannel** channel1, + blink::WebMessagePortChannel** channel2) { + WebMessagePortChannelImpl::CreatePair(channel1, channel2); +} + +blink::WebScrollbarBehavior* BlinkPlatformImpl::scrollbarBehavior() { + return &scrollbar_behavior_; +} + +const unsigned char* BlinkPlatformImpl::getTraceCategoryEnabledFlag( + const char* category_name) { + static const unsigned char buf[] = "*"; + return buf; +} + +blink::WebData BlinkPlatformImpl::loadResource(const char* resource) { + for (size_t i = 0; i < arraysize(kDataResources); ++i) { + if (!strcmp(resource, kDataResources[i].name)) { + int length; + const unsigned char* data = + blink_resource_map_.GetResource(kDataResources[i].id, &length); + CHECK(data != nullptr && length > 0); + return blink::WebData(reinterpret_cast<const char*>(data), length); + } + } + NOTREACHED() << "Requested resource is unavailable: " << resource; + return blink::WebData(); +} + +blink::WebURLLoader* BlinkPlatformImpl::createURLLoader() { + return new WebURLLoaderImpl(network_service_.get(), &blob_registry_); +} + +blink::WebSocketHandle* BlinkPlatformImpl::createWebSocketHandle() { + return new WebSocketHandleImpl(network_service_.get()); +} + +blink::WebString BlinkPlatformImpl::userAgent() { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(kUserAgentSwitch)) { + return blink::WebString::fromUTF8( + command_line->GetSwitchValueASCII(kUserAgentSwitch)); + } + return blink::WebString::fromUTF8(kDefaultUserAgentString); +} + +blink::WebData BlinkPlatformImpl::parseDataURL( + const blink::WebURL& url, + blink::WebString& mimetype_out, + blink::WebString& charset_out) { + std::string mimetype, charset, data; + if (net::DataURL::Parse(url, &mimetype, &charset, &data) + && net::IsSupportedMimeType(mimetype)) { + mimetype_out = blink::WebString::fromUTF8(mimetype); + charset_out = blink::WebString::fromUTF8(charset); + return data; + } + return blink::WebData(); +} + +blink::WebURLError BlinkPlatformImpl::cancelledError(const blink::WebURL& url) + const { + blink::WebURLError error; + error.domain = blink::WebString::fromUTF8(net::kErrorDomain); + error.reason = net::ERR_ABORTED; + error.unreachableURL = url; + error.staleCopyInCache = false; + error.isCancellation = true; + return error; +} + +bool BlinkPlatformImpl::isReservedIPAddress( + const blink::WebString& host) const { + net::IPAddressNumber address; + if (!net::ParseURLHostnameToNumber(host.utf8(), &address)) + return false; + return net::IsIPAddressReserved(address); +} + +blink::WebThread* BlinkPlatformImpl::createThread(const char* name) { + return new WebThreadImpl(name); +} + +blink::WebThread* BlinkPlatformImpl::currentThread() { + WebThreadImplForMessageLoop* thread = + static_cast<WebThreadImplForMessageLoop*>(current_thread_slot_.Get()); + if (thread) + return (thread); + + scoped_refptr<base::MessageLoopProxy> message_loop = + base::MessageLoopProxy::current(); + if (!message_loop.get()) + return NULL; + + thread = new WebThreadImplForMessageLoop(message_loop.get()); + current_thread_slot_.Set(thread); + return thread; +} + +void BlinkPlatformImpl::yieldCurrentThread() { + base::PlatformThread::YieldCurrentThread(); +} + +blink::WebWaitableEvent* BlinkPlatformImpl::createWaitableEvent() { + return new WebWaitableEventImpl(); +} + +blink::WebWaitableEvent* BlinkPlatformImpl::waitMultipleEvents( + const blink::WebVector<blink::WebWaitableEvent*>& web_events) { + std::vector<base::WaitableEvent*> events; + for (size_t i = 0; i < web_events.size(); ++i) + events.push_back(static_cast<WebWaitableEventImpl*>(web_events[i])->impl()); + size_t idx = base::WaitableEvent::WaitMany( + vector_as_array(&events), events.size()); + DCHECK_LT(idx, web_events.size()); + return web_events[idx]; +} + +blink::WebGestureCurve* BlinkPlatformImpl::createFlingAnimationCurve( + blink::WebGestureDevice device_source, + const blink::WebFloatPoint& velocity, + const blink::WebSize& cumulative_scroll) { + const bool is_main_thread = true; + return ui::WebGestureCurveImpl::CreateFromDefaultPlatformCurve( + gfx::Vector2dF(velocity.x, velocity.y), + gfx::Vector2dF(cumulative_scroll.width, cumulative_scroll.height), + is_main_thread).release(); +} + +blink::WebCrypto* BlinkPlatformImpl::crypto() { + return &web_crypto_; +} + +blink::WebNotificationManager* +BlinkPlatformImpl::notificationManager() { + return &web_notification_manager_; +} + +// static +void BlinkPlatformImpl::DestroyCurrentThread(void* thread) { + WebThreadImplForMessageLoop* impl = + static_cast<WebThreadImplForMessageLoop*>(thread); + delete impl; +} + +} // namespace html_viewer diff --git a/components/html_viewer/blink_platform_impl.h b/components/html_viewer/blink_platform_impl.h new file mode 100644 index 0000000..3f9a803 --- /dev/null +++ b/components/html_viewer/blink_platform_impl.h @@ -0,0 +1,120 @@ +// 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_BLINK_PLATFORM_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_BLINK_PLATFORM_IMPL_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/threading/thread_local_storage.h" +#include "base/timer/timer.h" +#include "cc/blink/web_compositor_support_impl.h" +#include "components/html_viewer/blink_resource_map.h" +#include "components/html_viewer/mock_web_blob_registry_impl.h" +#include "components/html_viewer/web_mime_registry_impl.h" +#include "components/html_viewer/web_notification_manager_impl.h" +#include "components/html_viewer/web_scheduler_impl.h" +#include "components/html_viewer/web_theme_engine_impl.h" +#include "components/webcrypto/webcrypto_impl.h" +#include "mojo/services/network/public/interfaces/network_service.mojom.h" +#include "third_party/WebKit/public/platform/Platform.h" +#include "third_party/WebKit/public/platform/WebScrollbarBehavior.h" + +namespace mojo { +class ApplicationImpl; +} + +namespace html_viewer { + +class WebClipboardImpl; +class WebCookieJarImpl; + +class BlinkPlatformImpl : public blink::Platform { + public: + // |app| may be null in tests. + explicit BlinkPlatformImpl(mojo::ApplicationImpl* app); + virtual ~BlinkPlatformImpl(); + + // blink::Platform methods: + virtual blink::WebCookieJar* cookieJar(); + virtual blink::WebClipboard* clipboard(); + virtual blink::WebMimeRegistry* mimeRegistry(); + virtual blink::WebThemeEngine* themeEngine(); + virtual blink::WebScheduler* scheduler(); + virtual blink::WebString defaultLocale(); + virtual blink::WebBlobRegistry* blobRegistry(); + virtual double currentTime(); + virtual double monotonicallyIncreasingTime(); + virtual void cryptographicallyRandomValues(unsigned char* buffer, + size_t length); + virtual void setSharedTimerFiredFunction(void (*func)()); + virtual void setSharedTimerFireInterval(double interval_seconds); + virtual void stopSharedTimer(); + virtual void callOnMainThread(void (*func)(void*), void* context); + virtual bool isThreadedCompositingEnabled(); + virtual blink::WebCompositorSupport* compositorSupport(); + void createMessageChannel(blink::WebMessagePortChannel** channel1, + blink::WebMessagePortChannel** channel2) override; + virtual blink::WebURLLoader* createURLLoader(); + virtual blink::WebSocketHandle* createWebSocketHandle(); + virtual blink::WebString userAgent(); + virtual blink::WebData parseDataURL( + const blink::WebURL& url, blink::WebString& mime_type, + blink::WebString& charset); + virtual bool isReservedIPAddress(const blink::WebString& host) const; + virtual blink::WebURLError cancelledError(const blink::WebURL& url) const; + virtual blink::WebThread* createThread(const char* name); + virtual blink::WebThread* currentThread(); + virtual void yieldCurrentThread(); + virtual blink::WebWaitableEvent* createWaitableEvent(); + virtual blink::WebWaitableEvent* waitMultipleEvents( + const blink::WebVector<blink::WebWaitableEvent*>& events); + virtual blink::WebScrollbarBehavior* scrollbarBehavior(); + virtual const unsigned char* getTraceCategoryEnabledFlag( + const char* category_name); + virtual blink::WebData loadResource(const char* name); + virtual blink::WebGestureCurve* createFlingAnimationCurve( + blink::WebGestureDevice device_source, + const blink::WebFloatPoint& velocity, + const blink::WebSize& cumulative_scroll); + virtual blink::WebCrypto* crypto(); + virtual blink::WebNotificationManager* notificationManager(); + + private: + void SuspendSharedTimer(); + void ResumeSharedTimer(); + + void DoTimeout() { + if (shared_timer_func_ && !shared_timer_suspended_) + shared_timer_func_(); + } + + static void DestroyCurrentThread(void*); + + base::MessageLoop* main_loop_; + base::OneShotTimer<BlinkPlatformImpl> shared_timer_; + void (*shared_timer_func_)(); + double shared_timer_fire_time_; + bool shared_timer_fire_time_was_set_while_suspended_; + int shared_timer_suspended_; // counter + base::ThreadLocalStorage::Slot current_thread_slot_; + cc_blink::WebCompositorSupportImpl compositor_support_; + WebThemeEngineImpl theme_engine_; + WebMimeRegistryImpl mime_registry_; + WebSchedulerImpl scheduler_; + webcrypto::WebCryptoImpl web_crypto_; + WebNotificationManagerImpl web_notification_manager_; + blink::WebScrollbarBehavior scrollbar_behavior_; + BlinkResourceMap blink_resource_map_; + mojo::NetworkServicePtr network_service_; + MockWebBlobRegistryImpl blob_registry_; + scoped_ptr<WebCookieJarImpl> cookie_jar_; + scoped_ptr<WebClipboardImpl> clipboard_; + + DISALLOW_COPY_AND_ASSIGN(BlinkPlatformImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_BLINK_PLATFORM_IMPL_H_ diff --git a/components/html_viewer/blink_resource_constants.h b/components/html_viewer/blink_resource_constants.h new file mode 100644 index 0000000..49c5a71 --- /dev/null +++ b/components/html_viewer/blink_resource_constants.h @@ -0,0 +1,127 @@ +// Copyright 2015 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_BLINK_RESOURCE_CONSTANTS_H_ +#define COMPONENTS_HTML_VIEWER_BLINK_RESOURCE_CONSTANTS_H_ + +#include "blink/public/resources/grit/blink_image_resources.h" +#include "blink/public/resources/grit/blink_resources.h" + +namespace html_viewer { + +struct DataResource { + const char* name; + int id; +}; + +const DataResource kDataResources[] = { + {"missingImage", IDR_BROKENIMAGE}, + // Skipping missingImage@2x + {"mediaplayerPause", IDR_MEDIAPLAYER_PAUSE_BUTTON}, + {"mediaplayerPauseHover", IDR_MEDIAPLAYER_PAUSE_BUTTON_HOVER}, + {"mediaplayerPauseDown", IDR_MEDIAPLAYER_PAUSE_BUTTON_DOWN}, + {"mediaplayerPlay", IDR_MEDIAPLAYER_PLAY_BUTTON}, + {"mediaplayerPlayHover", IDR_MEDIAPLAYER_PLAY_BUTTON_HOVER}, + {"mediaplayerPlayDown", IDR_MEDIAPLAYER_PLAY_BUTTON_DOWN}, + {"mediaplayerPlayDisabled", IDR_MEDIAPLAYER_PLAY_BUTTON_DISABLED}, + {"mediaplayerSoundLevel3", IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON}, + {"mediaplayerSoundLevel3Hover", IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON_HOVER}, + {"mediaplayerSoundLevel3Down", IDR_MEDIAPLAYER_SOUND_LEVEL3_BUTTON_DOWN}, + {"mediaplayerSoundLevel2", IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON}, + {"mediaplayerSoundLevel2Hover", IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON_HOVER}, + {"mediaplayerSoundLevel2Down", IDR_MEDIAPLAYER_SOUND_LEVEL2_BUTTON_DOWN}, + {"mediaplayerSoundLevel1", IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON}, + {"mediaplayerSoundLevel1Hover", IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON_HOVER}, + {"mediaplayerSoundLevel1Down", IDR_MEDIAPLAYER_SOUND_LEVEL1_BUTTON_DOWN}, + {"mediaplayerSoundLevel0", IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON}, + {"mediaplayerSoundLevel0Hover", IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON_HOVER}, + {"mediaplayerSoundLevel0Down", IDR_MEDIAPLAYER_SOUND_LEVEL0_BUTTON_DOWN}, + {"mediaplayerSoundDisabled", IDR_MEDIAPLAYER_SOUND_DISABLED}, + {"mediaplayerSliderThumb", IDR_MEDIAPLAYER_SLIDER_THUMB}, + {"mediaplayerSliderThumbHover", IDR_MEDIAPLAYER_SLIDER_THUMB_HOVER}, + {"mediaplayerSliderThumbDown", IDR_MEDIAPLAYER_SLIDER_THUMB_DOWN}, + {"mediaplayerVolumeSliderThumb", IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB}, + {"mediaplayerVolumeSliderThumbHover", + IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_HOVER}, + {"mediaplayerVolumeSliderThumbDown", + IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_DOWN}, + {"mediaplayerVolumeSliderThumbDisabled", + IDR_MEDIAPLAYER_VOLUME_SLIDER_THUMB_DISABLED}, + {"mediaplayerClosedCaption", IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON}, + {"mediaplayerClosedCaptionHover", + IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_HOVER}, + {"mediaplayerClosedCaptionDown", + IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_DOWN}, + {"mediaplayerClosedCaptionDisabled", + IDR_MEDIAPLAYER_CLOSEDCAPTION_BUTTON_DISABLED}, + {"mediaplayerFullscreen", IDR_MEDIAPLAYER_FULLSCREEN_BUTTON}, + {"mediaplayerFullscreenHover", IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_HOVER}, + {"mediaplayerFullscreenDown", IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DOWN}, + {"mediaplayerCastOff", IDR_MEDIAPLAYER_CAST_BUTTON_OFF}, + {"mediaplayerCastOn", IDR_MEDIAPLAYER_CAST_BUTTON_ON}, + {"mediaplayerFullscreenDisabled", + IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DISABLED}, + {"mediaplayerOverlayCastOff", IDR_MEDIAPLAYER_OVERLAY_CAST_BUTTON_OFF}, + {"mediaplayerOverlayPlay", IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON}, + {"panIcon", IDR_PAN_SCROLL_ICON}, + {"searchCancel", IDR_SEARCH_CANCEL}, + {"searchCancelPressed", IDR_SEARCH_CANCEL_PRESSED}, + {"searchMagnifier", IDR_SEARCH_MAGNIFIER}, + {"searchMagnifierResults", IDR_SEARCH_MAGNIFIER_RESULTS}, + {"textAreaResizeCorner", IDR_TEXTAREA_RESIZER}, + // Skipping "textAreaResizeCorner@2x" + {"generatePassword", IDR_PASSWORD_GENERATION_ICON}, + {"generatePasswordHover", IDR_PASSWORD_GENERATION_ICON_HOVER}, + {"html.css", IDR_UASTYLE_HTML_CSS}, + {"quirks.css", IDR_UASTYLE_QUIRKS_CSS}, + {"view-source.css", IDR_UASTYLE_VIEW_SOURCE_CSS}, + {"themeChromium.css", IDR_UASTYLE_THEME_CHROMIUM_CSS}, +#if defined(OS_ANDROID) + {"themeChromiumAndroid.css", IDR_UASTYLE_THEME_CHROMIUM_ANDROID_CSS}, + {"mediaControlsAndroid.css", IDR_UASTYLE_MEDIA_CONTROLS_ANDROID_CSS}, +#endif +#if !defined(OS_WIN) + {"themeChromiumLinux.css", IDR_UASTYLE_THEME_CHROMIUM_LINUX_CSS}, +#endif + {"themeChromiumSkia.css", IDR_UASTYLE_THEME_CHROMIUM_SKIA_CSS}, + {"themeInputMultipleFields.css", + IDR_UASTYLE_THEME_INPUT_MULTIPLE_FIELDS_CSS}, +#if defined(OS_MACOSX) + {"themeMac.css", IDR_UASTYLE_THEME_MAC_CSS}, +#endif + {"themeWin.css", IDR_UASTYLE_THEME_WIN_CSS}, + {"themeWinQuirks.css", IDR_UASTYLE_THEME_WIN_QUIRKS_CSS}, + {"svg.css", IDR_UASTYLE_SVG_CSS}, + {"navigationTransitions.css", IDR_UASTYLE_NAVIGATION_TRANSITIONS_CSS}, + {"mathml.css", IDR_UASTYLE_MATHML_CSS}, + {"mediaControls.css", IDR_UASTYLE_MEDIA_CONTROLS_CSS}, + {"fullscreen.css", IDR_UASTYLE_FULLSCREEN_CSS}, + {"xhtmlmp.css", IDR_UASTYLE_XHTMLMP_CSS}, + {"viewportAndroid.css", IDR_UASTYLE_VIEWPORT_ANDROID_CSS}, + {"InspectorOverlayPage.html", IDR_INSPECTOR_OVERLAY_PAGE_HTML}, + {"InjectedScriptSource.js", IDR_INSPECTOR_INJECTED_SCRIPT_SOURCE_JS}, + {"DebuggerScriptSource.js", IDR_INSPECTOR_DEBUGGER_SCRIPT_SOURCE_JS}, + {"DocumentExecCommand.js", IDR_PRIVATE_SCRIPT_DOCUMENTEXECCOMMAND_JS}, + {"DocumentXMLTreeViewer.css", IDR_PRIVATE_SCRIPT_DOCUMENTXMLTREEVIEWER_CSS}, + {"DocumentXMLTreeViewer.js", IDR_PRIVATE_SCRIPT_DOCUMENTXMLTREEVIEWER_JS}, + {"HTMLMarqueeElement.js", IDR_PRIVATE_SCRIPT_HTMLMARQUEEELEMENT_JS}, + {"PluginPlaceholderElement.js", + IDR_PRIVATE_SCRIPT_PLUGINPLACEHOLDERELEMENT_JS}, + {"PrivateScriptRunner.js", IDR_PRIVATE_SCRIPT_PRIVATESCRIPTRUNNER_JS}, +#ifdef IDR_PICKER_COMMON_JS + {"pickerCommon.js", IDR_PICKER_COMMON_JS}, + {"pickerCommon.css", IDR_PICKER_COMMON_CSS}, + {"calendarPicker.js", IDR_CALENDAR_PICKER_JS}, + {"calendarPicker.css", IDR_CALENDAR_PICKER_CSS}, + {"pickerButton.css", IDR_PICKER_BUTTON_CSS}, + {"suggestionPicker.js", IDR_SUGGESTION_PICKER_JS}, + {"suggestionPicker.css", IDR_SUGGESTION_PICKER_CSS}, + {"colorSuggestionPicker.js", IDR_COLOR_SUGGESTION_PICKER_JS}, + {"colorSuggestionPicker.css", IDR_COLOR_SUGGESTION_PICKER_CSS} +#endif +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_BLINK_RESOURCE_CONSTANTS_H_ diff --git a/components/html_viewer/blink_url_request_type_converters.cc b/components/html_viewer/blink_url_request_type_converters.cc new file mode 100644 index 0000000..29fbbe69 --- /dev/null +++ b/components/html_viewer/blink_url_request_type_converters.cc @@ -0,0 +1,110 @@ +// 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/blink_url_request_type_converters.h" + +#include "base/strings/string_util.h" +#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" +#include "third_party/WebKit/public/platform/WebURLRequest.h" +#include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h" + +namespace mojo { +namespace { + +// Ripped from web_url_loader_impl.cc. +class HeaderFlattener : public blink::WebHTTPHeaderVisitor { + public: + HeaderFlattener() : has_accept_header_(false) {} + + void visitHeader(const blink::WebString& name, + const blink::WebString& value) override { + // Headers are latin1. + const std::string& name_latin1 = name.latin1(); + const std::string& value_latin1 = value.latin1(); + + // Skip over referrer headers found in the header map because we already + // pulled it out as a separate parameter. + if (LowerCaseEqualsASCII(name_latin1, "referer")) + return; + + if (LowerCaseEqualsASCII(name_latin1, "accept")) + has_accept_header_ = true; + + buffer_.push_back(name_latin1 + ": " + value_latin1); + } + + Array<String> GetBuffer() { + // In some cases, WebKit doesn't add an Accept header, but not having the + // header confuses some web servers. See bug 808613. + if (!has_accept_header_) { + buffer_.push_back("Accept: */*"); + has_accept_header_ = true; + } + return buffer_.Pass(); + } + + private: + Array<String> buffer_; + bool has_accept_header_; +}; + +void AddRequestBody(URLRequest* url_request, + const blink::WebURLRequest& request) { + if (request.httpBody().isNull()) + return; + + uint32_t i = 0; + blink::WebHTTPBody::Element element; + while (request.httpBody().elementAt(i++, element)) { + switch (element.type) { + case blink::WebHTTPBody::Element::TypeData: + if (!element.data.isEmpty()) { + // WebKit sometimes gives up empty data to append. These aren't + // necessary so we just optimize those out here. + uint32_t num_bytes = static_cast<uint32_t>(element.data.size()); + MojoCreateDataPipeOptions options; + options.struct_size = sizeof(MojoCreateDataPipeOptions); + options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; + options.element_num_bytes = 1; + options.capacity_num_bytes = num_bytes; + DataPipe data_pipe(options); + url_request->body.push_back( + data_pipe.consumer_handle.Pass()); + WriteDataRaw(data_pipe.producer_handle.get(), + element.data.data(), + &num_bytes, + MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); + } + break; + case blink::WebHTTPBody::Element::TypeFile: + case blink::WebHTTPBody::Element::TypeFileSystemURL: + case blink::WebHTTPBody::Element::TypeBlob: + // TODO(mpcomplete): handle these. + NOTIMPLEMENTED(); + break; + default: + NOTREACHED(); + } + } +} + +} // namespace + +URLRequestPtr TypeConverter<URLRequestPtr, blink::WebURLRequest>::Convert( + const blink::WebURLRequest& request) { + URLRequestPtr url_request(URLRequest::New()); + url_request->url = request.url().string().utf8(); + url_request->method = request.httpMethod().utf8(); + + HeaderFlattener flattener; + request.visitHTTPHeaderFields(&flattener); + url_request->headers = flattener.GetBuffer().Pass(); + + AddRequestBody(url_request.get(), request); + + return url_request.Pass(); +} + +} // namespace mojo + diff --git a/components/html_viewer/blink_url_request_type_converters.h b/components/html_viewer/blink_url_request_type_converters.h new file mode 100644 index 0000000..7812a7c --- /dev/null +++ b/components/html_viewer/blink_url_request_type_converters.h @@ -0,0 +1,23 @@ +// 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_BLINK_URL_REQUEST_TYPE_CONVERTERS_H_ +#define COMPONENTS_HTML_VIEWER_BLINK_URL_REQUEST_TYPE_CONVERTERS_H_ + +#include "mojo/services/network/public/interfaces/url_loader.mojom.h" + +namespace blink { +class WebURLRequest; +} + +namespace mojo { + +template <> +struct TypeConverter<URLRequestPtr, blink::WebURLRequest> { + static URLRequestPtr Convert(const blink::WebURLRequest& request); +}; + +} // namespace mojo + +#endif // COMPONENTS_HTML_VIEWER_BLINK_URL_REQUEST_TYPE_CONVERTERS_H_ diff --git a/components/html_viewer/discardable_memory_allocator.cc b/components/html_viewer/discardable_memory_allocator.cc new file mode 100644 index 0000000..f76deee --- /dev/null +++ b/components/html_viewer/discardable_memory_allocator.cc @@ -0,0 +1,151 @@ +// Copyright 2015 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/discardable_memory_allocator.h" + +#include "base/memory/discardable_memory.h" +#include "base/memory/weak_ptr.h" +#include "base/stl_util.h" + +namespace html_viewer { + +// Represents an actual memory chunk. This is an object owned by +// DiscardableMemoryAllocator. DiscardableMemoryChunkImpl are passed to the +// rest of the program, and access this memory through a weak ptr. +class DiscardableMemoryAllocator::OwnedMemoryChunk { + public: + OwnedMemoryChunk(size_t size, DiscardableMemoryAllocator* allocator) + : is_locked_(true), + size_(size), + data_(new uint8_t[size]), + allocator_(allocator), + weak_factory_(this) {} + ~OwnedMemoryChunk() {} + + void Lock() { + DCHECK(!is_locked_); + is_locked_ = true; + allocator_->NotifyLocked(unlocked_position_); + } + + void Unlock() { + DCHECK(is_locked_); + is_locked_ = false; + unlocked_position_ = allocator_->NotifyUnlocked(this); + } + + bool is_locked() const { return is_locked_; } + size_t size() const { return size_; } + void* data() const { + DCHECK(is_locked_); + return data_.get(); + } + + base::WeakPtr<OwnedMemoryChunk> GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + + private: + bool is_locked_; + size_t size_; + scoped_ptr<uint8_t[]> data_; + DiscardableMemoryAllocator* allocator_; + + std::list<OwnedMemoryChunk*>::iterator unlocked_position_; + + base::WeakPtrFactory<OwnedMemoryChunk> weak_factory_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(OwnedMemoryChunk); +}; + +namespace { + +// Interface to the rest of the program. These objects are owned outside of the +// allocator and wrap a weak ptr. +class DiscardableMemoryChunkImpl : public base::DiscardableMemory { + public: + explicit DiscardableMemoryChunkImpl( + base::WeakPtr<DiscardableMemoryAllocator::OwnedMemoryChunk> chunk) + : memory_chunk_(chunk) {} + ~DiscardableMemoryChunkImpl() override { + // Either the memory chunk is invalid (because the backing has gone away), + // or the memory chunk is unlocked (because leaving the chunk locked once + // we deallocate means the chunk will never get cleaned up). + DCHECK(!memory_chunk_ || !memory_chunk_->is_locked()); + } + + // Overridden from DiscardableMemoryChunk: + bool Lock() override { + if (!memory_chunk_) + return false; + + memory_chunk_->Lock(); + return true; + } + + void Unlock() override { + DCHECK(memory_chunk_); + memory_chunk_->Unlock(); + } + + void* data() const override { + if (memory_chunk_) + return memory_chunk_->data(); + return nullptr; + } + + private: + base::WeakPtr<DiscardableMemoryAllocator::OwnedMemoryChunk> memory_chunk_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(DiscardableMemoryChunkImpl); +}; + +} // namespace + +DiscardableMemoryAllocator::DiscardableMemoryAllocator( + size_t desired_max_memory) + : desired_max_memory_(desired_max_memory), + total_live_memory_(0u), + locked_chunks_(0) { +} + +DiscardableMemoryAllocator::~DiscardableMemoryAllocator() { + DCHECK_EQ(0, locked_chunks_); + STLDeleteElements(&live_unlocked_chunks_); +} + +scoped_ptr<base::DiscardableMemory> +DiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size) { + OwnedMemoryChunk* chunk = new OwnedMemoryChunk(size, this); + total_live_memory_ += size; + locked_chunks_++; + + // Go through the list of unlocked live chunks starting from the least + // recently used, freeing as many as we can until we get our size under the + // desired maximum. + auto it = live_unlocked_chunks_.begin(); + while (total_live_memory_ > desired_max_memory_ && + it != live_unlocked_chunks_.end()) { + total_live_memory_ -= (*it)->size(); + delete *it; + it = live_unlocked_chunks_.erase(it); + } + + return make_scoped_ptr(new DiscardableMemoryChunkImpl(chunk->GetWeakPtr())); +} + +std::list<DiscardableMemoryAllocator::OwnedMemoryChunk*>::iterator +DiscardableMemoryAllocator::NotifyUnlocked( + DiscardableMemoryAllocator::OwnedMemoryChunk* chunk) { + locked_chunks_--; + return live_unlocked_chunks_.insert(live_unlocked_chunks_.end(), chunk); +} + +void DiscardableMemoryAllocator::NotifyLocked( + std::list<OwnedMemoryChunk*>::iterator it) { + locked_chunks_++; + live_unlocked_chunks_.erase(it); +} + +} // namespace html_viewer diff --git a/components/html_viewer/discardable_memory_allocator.h b/components/html_viewer/discardable_memory_allocator.h new file mode 100644 index 0000000..be7f063 --- /dev/null +++ b/components/html_viewer/discardable_memory_allocator.h @@ -0,0 +1,61 @@ +// Copyright 2015 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_DISCARDABLE_MEMORY_ALLOCATOR_H_ +#define COMPONENTS_HTML_VIEWER_DISCARDABLE_MEMORY_ALLOCATOR_H_ + +#include <list> + +#include "base/memory/discardable_memory_allocator.h" + +namespace html_viewer { + +// A discarable memory allocator which will unallocate chunks on new +// allocations. +class DiscardableMemoryAllocator : public base::DiscardableMemoryAllocator { + public: + class OwnedMemoryChunk; + + explicit DiscardableMemoryAllocator(size_t desired_max_memory); + ~DiscardableMemoryAllocator() override; + + // Overridden from DiscardableMemoryAllocator: + scoped_ptr<base::DiscardableMemory> AllocateLockedDiscardableMemory( + size_t size) override; + + private: + friend class OwnedMemoryChunk; + + // Called by OwnedMemoryChunks when they are unlocked. This puts them at the + // end of the live_unlocked_chunks_ list and passes an iterator to their + // position in the unlocked chunk list. + std::list<OwnedMemoryChunk*>::iterator NotifyUnlocked( + OwnedMemoryChunk* chunk); + + // Called by OwnedMemoryChunks when they are locked. This removes the passed + // in unlocked chunk list. + void NotifyLocked(std::list<OwnedMemoryChunk*>::iterator it); + + // The amount of memory we can allocate before we try to free unlocked + // chunks. We can go over this amount if all callers keep their discardable + // chunks locked. + const size_t desired_max_memory_; + + // A count of the sum of memory. Used to trigger discarding the oldest + // memory. + size_t total_live_memory_; + + // The number of locked chunks. + int locked_chunks_; + + // A linked list of unlocked allocated chunks so that the tail is most + // recently accessed chunks. + std::list<OwnedMemoryChunk*> live_unlocked_chunks_; + + DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryAllocator); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_DISCARDABLE_MEMORY_ALLOCATOR_H_ diff --git a/components/html_viewer/discardable_memory_allocator_unittest.cc b/components/html_viewer/discardable_memory_allocator_unittest.cc new file mode 100644 index 0000000..cc73fb0 --- /dev/null +++ b/components/html_viewer/discardable_memory_allocator_unittest.cc @@ -0,0 +1,76 @@ +// Copyright 2015 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/discardable_memory_allocator.h" + +#include "base/memory/discardable_memory.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace html_viewer { +namespace { + +const size_t kOneKilobyte = 1024; +const size_t kAlmostOneMegabyte = 1023 * kOneKilobyte; +const size_t kOneMegabyte = 1024 * kOneKilobyte; + +TEST(DiscardableMemoryAllocator, Basic) { + scoped_ptr<base::DiscardableMemory> chunk; + + { + DiscardableMemoryAllocator allocator(kOneMegabyte); + + // Make sure the chunk is locked when allocated. In debug mode, we will + // dcheck. + chunk = allocator.AllocateLockedDiscardableMemory(kOneKilobyte); + chunk->Unlock(); + + // Make sure we can lock a chunk. + EXPECT_TRUE(chunk->Lock()); + chunk->Unlock(); + } + + // The chunk's backing should have disappeared with the allocator. + EXPECT_FALSE(chunk->Lock()); +} + +TEST(DiscardableMemoryAllocator, DiscardChunks) { + DiscardableMemoryAllocator allocator(kOneMegabyte); + + scoped_ptr<base::DiscardableMemory> chunk_to_remove = + allocator.AllocateLockedDiscardableMemory(kAlmostOneMegabyte); + chunk_to_remove->Unlock(); + + // Allocating a second chunk should deallocate the first one due to memory + // pressure, since we only have one megabyte available. + scoped_ptr<base::DiscardableMemory> chunk_to_keep = + allocator.AllocateLockedDiscardableMemory(kAlmostOneMegabyte); + + // Fail to get a lock because allocating the second chunk removed the first. + EXPECT_FALSE(chunk_to_remove->Lock()); + + chunk_to_keep->Unlock(); +} + +TEST(DiscardableMemoryAllocator, DontDiscardLiveChunks) { + DiscardableMemoryAllocator allocator(kOneMegabyte); + + scoped_ptr<base::DiscardableMemory> chunk_one = + allocator.AllocateLockedDiscardableMemory(kAlmostOneMegabyte); + scoped_ptr<base::DiscardableMemory> chunk_two = + allocator.AllocateLockedDiscardableMemory(kAlmostOneMegabyte); + scoped_ptr<base::DiscardableMemory> chunk_three = + allocator.AllocateLockedDiscardableMemory(kAlmostOneMegabyte); + + // These accesses will fail if the underlying weak ptr has been deallocated. + EXPECT_NE(nullptr, chunk_one->data()); + EXPECT_NE(nullptr, chunk_two->data()); + EXPECT_NE(nullptr, chunk_three->data()); + + chunk_one->Unlock(); + chunk_two->Unlock(); + chunk_three->Unlock(); +} + +} // namespace +} // namespace html_viewer diff --git a/components/html_viewer/generate_blink_resource_map.py b/components/html_viewer/generate_blink_resource_map.py new file mode 100644 index 0000000..e60be14 --- /dev/null +++ b/components/html_viewer/generate_blink_resource_map.py @@ -0,0 +1,146 @@ +# Copyright 2015 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. + +from string import Template + +import optparse +import os +import sys + +try: + grit_module_path = os.path.join( + os.path.dirname(__file__), '..', '..', 'tools', 'grit') + sys.path.insert(0, grit_module_path) + from grit.format import data_pack as DataPack +except ImportError, e: + print 'ImportError: ', e + sys.exit(-1) + +header_template = \ +"""// Copyright 2015 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_BLINK_RESOURCE_MAP_H_ +#define COMPONENTS_HTML_VIEWER_BLINK_RESOURCE_MAP_H_ + +#include <map> + +namespace html_viewer { + +class BlinkResourceMap { + public: + BlinkResourceMap(); + const unsigned char* GetResource(int id, int* length); + + private: + struct ResourceEntry { + const unsigned char* data; + int length; + + ResourceEntry() + : data(nullptr) + , length(0) { + } + + ResourceEntry(const unsigned char* data, int length) + : data(data) + , length(length) { + } + }; + typedef std::map<int, ResourceEntry> ResourceMap; + ResourceMap resources_; +}; + +} // namespace html_viewer +#endif // COMPONENTS_HTML_VIEWER_BLINK_RESOURCE_MAP_H_""" + +cpp_template = \ +"""// Copyright 2015 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 "$header_file_name" + +#include "base/macros.h" + +namespace html_viewer { + +$definitions + +BlinkResourceMap::BlinkResourceMap() +{ + $map_initializer +} + +const unsigned char* BlinkResourceMap::GetResource(int id, int* length) +{ + ResourceMap::iterator it = resources_.find(id); + if (it == resources_.end()) { + *length = 0; + return nullptr; + } + *length = it->second.length; + return it->second.data; +} + +} // namespace html_viewer""" + +def main(): + parser = optparse.OptionParser( + usage='Usage: %prog --pak-file PAK_FILE --header HEADER --cpp CPP\n') + parser.add_option('-i', '--pak-file', action='store', dest='pak_file', + help='The .pak file to be extracted.') + parser.add_option('', '--header', action='store', dest='header_file', + help='Header file to be generated.') + parser.add_option('', '--cpp', action='store', dest='cpp_file', + help='C++ file to be generated.') + + (options, _) = parser.parse_args() + if (not options.pak_file or not options.header_file or not options.cpp_file): + parser.print_help() + sys.exit(-1) + + header_file = open(options.header_file, 'w+') + cpp_file = open(options.cpp_file, 'w+') + + pak_contents = DataPack.ReadDataPack(options.pak_file) + resourceIds = [] + + header_contents = dict() + cpp_contents = dict() + + definitions = [] + + for (resId, data) in pak_contents.resources.iteritems(): + resourceIds.append(resId) + hex_values = ['0x{0:02x}'.format(ord(char)) for char in data] + f = lambda A, n=12: [A[i:i+n] for i in range(0, len(A), n)] + hex_values_string = ',\n '.join(', '.join(x) for x in f(hex_values)) + cpp_definition = \ + 'const unsigned char kResource%s[%d] = {\n %s \n};' % \ + (str(resId), len(hex_values), hex_values_string) + definitions.append(cpp_definition) + + header_file_contents = Template(header_template).substitute(header_contents) + header_file.write(header_file_contents) + header_file.close() + + map_initializer = [] + for resId in resourceIds: + insert_statement = \ + 'resources_.insert(std::pair<int, ResourceEntry>(\n' \ + ' %s, ResourceEntry(kResource%s, arraysize(kResource%s))));' + map_initializer.append( \ + insert_statement % (str(resId), str(resId), str(resId))) + + cpp_contents['definitions']= '\n'.join(definitions) + cpp_contents['header_file_name'] = os.path.basename(options.header_file) + cpp_contents['map_initializer'] = '\n '.join(map_initializer) + cpp_file_contents = Template(cpp_template).substitute(cpp_contents) + cpp_file.write(cpp_file_contents) + cpp_file.close() + +if __name__ == '__main__': + main() diff --git a/components/html_viewer/html_document.cc b/components/html_viewer/html_document.cc new file mode 100644 index 0000000..e1b57cf --- /dev/null +++ b/components/html_viewer/html_document.cc @@ -0,0 +1,385 @@ +// 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.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop_proxy.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/html_viewer/blink_input_events_type_converters.h" +#include "components/html_viewer/blink_url_request_type_converters.h" +#include "components/html_viewer/web_layer_tree_view_impl.h" +#include "components/html_viewer/web_media_player_factory.h" +#include "components/html_viewer/web_storage_namespace_impl.h" +#include "components/html_viewer/web_url_loader_impl.h" +#include "media/blink/webencryptedmediaclient_impl.h" +#include "media/cdm/default_cdm_factory.h" +#include "media/filters/default_media_permission.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/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/application/application_impl.h" +#include "third_party/mojo/src/mojo/public/cpp/application/connect.h" +#include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h" +#include "third_party/mojo/src/mojo/public/interfaces/application/shell.mojom.h" +#include "third_party/mojo_services/src/surfaces/public/interfaces/surfaces.mojom.h" +#include "third_party/mojo_services/src/view_manager/public/cpp/view.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" + +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 { + +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) { + // For now, we just load child frames locally. + // TODO(aa): In the future, this should use embedding to connect to a + // different instance of Blink if the frame is cross-origin. + if (frame->parent()) + return true; + + // 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; + + // mojo::NavigatorHost doesn't accept POSTs, so for now reuse this instance. + // TODO(jam): improve this (and copy logic from RenderFrameImpl's version) + // when we have multi-process. + if (EqualsASCII(request.httpMethod(), "POST")) + return true; + + // Logging into Gmail fails when the referrer isn't sent with a request. + // TODO(jam): pass referrer and other HTTP data to NavigatorHost so we can + // use a new process in this case. + if (!request.httpHeaderField(blink::WebString::fromUTF8("Referer")).isEmpty()) + 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 + +HTMLDocument::HTMLDocument( + mojo::InterfaceRequest<mojo::ServiceProvider> services, + URLResponsePtr response, + mojo::Shell* shell, + scoped_refptr<base::MessageLoopProxy> compositor_thread, + WebMediaPlayerFactory* web_media_player_factory, + bool is_headless) + : response_(response.Pass()), + shell_(shell), + web_view_(nullptr), + root_(nullptr), + view_manager_client_factory_(shell_, this), + compositor_thread_(compositor_thread), + web_media_player_factory_(web_media_player_factory), + is_headless_(is_headless), + device_pixel_ratio_(1.0) { + exported_services_.AddService(this); + exported_services_.AddService(&view_manager_client_factory_); + exported_services_.Bind(services.Pass()); + Load(response_.Pass()); +} + +HTMLDocument::~HTMLDocument() { + STLDeleteElements(&ax_providers_); + STLDeleteElements(&ax_provider_requests_); + + if (web_view_) + web_view_->close(); + if (root_) + root_->RemoveObserver(this); +} + +void HTMLDocument::OnEmbed( + View* root, + mojo::InterfaceRequest<mojo::ServiceProvider> services, + mojo::ServiceProviderPtr exposed_services) { + DCHECK(!is_headless_); + root_ = root; + embedder_service_provider_ = exposed_services.Pass(); + navigator_host_.set_service_provider(embedder_service_provider_.get()); + UpdateWebviewSizeFromViewSize(); + web_layer_tree_view_impl_->set_view(root_); + root_->AddObserver(this); +} + +void HTMLDocument::OnViewManagerDisconnected(ViewManager* view_manager) { + // TODO(aa): Need to figure out how shutdown works. +} + +void HTMLDocument::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( + WeakBindToRequest(new AxProviderImpl(web_view_), &request)); + } +} + +void HTMLDocument::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()); + web_view_->setMainFrame(blink::WebLocalFrame::create(this)); + + 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); +} + +void HTMLDocument::UpdateWebviewSizeFromViewSize() { + device_pixel_ratio_ = root_->viewport_metrics().device_pixel_ratio; + web_view_->setDeviceScaleFactor(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); +} + +blink::WebStorageNamespace* HTMLDocument::createSessionStorageNamespace() { + return new WebStorageNamespaceImpl(); +} + +void HTMLDocument::initializeLayerTreeView() { + if (is_headless_) { + web_layer_tree_view_impl_.reset( + new WebLayerTreeViewImpl(compositor_thread_, nullptr, nullptr)); + return; + } + + ServiceProviderPtr surfaces_service_provider; + shell_->ConnectToApplication("mojo:surfaces_service", + GetProxy(&surfaces_service_provider), nullptr); + mojo::SurfacePtr surface; + ConnectToService(surfaces_service_provider.get(), &surface); + + ServiceProviderPtr gpu_service_provider; + // TODO(jamesr): Should be mojo:gpu_service + shell_->ConnectToApplication("mojo:native_viewport_service", + GetProxy(&gpu_service_provider), nullptr); + mojo::GpuPtr gpu_service; + ConnectToService(gpu_service_provider.get(), &gpu_service); + web_layer_tree_view_impl_.reset(new WebLayerTreeViewImpl( + compositor_thread_, surface.Pass(), gpu_service.Pass())); +} + +blink::WebLayerTreeView* HTMLDocument::layerTreeView() { + return web_layer_tree_view_impl_.get(); +} + +blink::WebMediaPlayer* HTMLDocument::createMediaPlayer( + blink::WebLocalFrame* frame, + const blink::WebURL& url, + blink::WebMediaPlayerClient* client) { + return createMediaPlayer(frame, url, client, nullptr); +} + +blink::WebMediaPlayer* HTMLDocument::createMediaPlayer( + blink::WebLocalFrame* frame, + const blink::WebURL& url, + blink::WebMediaPlayerClient* client, + blink::WebContentDecryptionModule* initial_cdm) { + blink::WebMediaPlayer* player = + web_media_player_factory_ + ? web_media_player_factory_->CreateMediaPlayer( + frame, url, client, GetMediaPermission(), GetCdmFactory(), + initial_cdm, shell_) + : nullptr; + return player; +} + +blink::WebFrame* HTMLDocument::createChildFrame( + blink::WebLocalFrame* parent, + const blink::WebString& frameName, + blink::WebSandboxFlags sandboxFlags) { + blink::WebLocalFrame* web_frame = blink::WebLocalFrame::create(this); + parent->appendChild(web_frame); + return web_frame; +} + +void HTMLDocument::frameDetached(blink::WebFrame* frame) { + if (frame->parent()) + frame->parent()->removeChild(frame); + + // |frame| is invalid after here. + frame->close(); +} + +blink::WebCookieJar* HTMLDocument::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 HTMLDocument::decidePolicyForNavigation( + blink::WebLocalFrame* frame, + blink::WebDataSource::ExtraData* data, + const blink::WebURLRequest& request, + blink::WebNavigationType nav_type, + blink::WebNavigationPolicy default_policy, + bool is_redirect) { + if (CanNavigateLocally(frame, request)) + return default_policy; + + if (navigator_host_.get()) { + navigator_host_->RequestNavigate( + WebNavigationPolicyToNavigationTarget(default_policy), + mojo::URLRequest::From(request).Pass()); + } + + return blink::WebNavigationPolicyIgnore; +} + +void HTMLDocument::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 HTMLDocument::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(WeakBindToRequest(new AxProviderImpl(web_view_), it)); + STLDeleteElements(&ax_provider_requests_); +} + +void HTMLDocument::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* HTMLDocument::encryptedMediaClient() { + if (!web_encrypted_media_client_) { + web_encrypted_media_client_.reset(new media::WebEncryptedMediaClientImpl( + GetCdmFactory(), GetMediaPermission())); + } + return web_encrypted_media_client_.get(); +} + +void HTMLDocument::OnViewBoundsChanged(View* view, + const Rect& old_bounds, + const Rect& new_bounds) { + DCHECK_EQ(view, root_); + UpdateWebviewSizeFromViewSize(); +} + +void HTMLDocument::OnViewDestroyed(View* view) { + DCHECK_EQ(view, root_); + root_ = nullptr; + delete this; + mojo::ApplicationImpl::Terminate(); +} + +void HTMLDocument::OnViewInputEvent(View* view, const mojo::EventPtr& event) { + if (event->pointer_data) { + // Blink expects coordintes to be in DIPs. + event->pointer_data->x /= device_pixel_ratio_; + event->pointer_data->y /= device_pixel_ratio_; + event->pointer_data->screen_x /= device_pixel_ratio_; + event->pointer_data->screen_y /= 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); +} + +media::MediaPermission* HTMLDocument::GetMediaPermission() { + if (!media_permission_) + media_permission_.reset(new media::DefaultMediaPermission(true)); + return media_permission_.get(); +} + +media::CdmFactory* HTMLDocument::GetCdmFactory() { + if (!cdm_factory_) + cdm_factory_.reset(new media::DefaultCdmFactory()); + return cdm_factory_.get(); +} + +} // namespace html_viewer diff --git a/components/html_viewer/html_document.h b/components/html_viewer/html_document.h new file mode 100644 index 0000000..4068888 --- /dev/null +++ b/components/html_viewer/html_document.h @@ -0,0 +1,177 @@ +// 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_H_ +#define COMPONENTS_HTML_VIEWER_HTML_DOCUMENT_H_ + +#include <set> + +#include "base/callback.h" +#include "base/macros.h" +#include "components/html_viewer/ax_provider_impl.h" +#include "components/html_viewer/touch_handler.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/application/interface_factory.h" +#include "third_party/mojo/src/mojo/public/cpp/application/lazy_interface_ptr.h" +#include "third_party/mojo/src/mojo/public/cpp/application/service_provider_impl.h" +#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h" +#include "third_party/mojo/src/mojo/public/interfaces/application/application.mojom.h" +#include "third_party/mojo_services/src/content_handler/public/interfaces/content_handler.mojom.h" +#include "third_party/mojo_services/src/navigation/public/interfaces/navigation.mojom.h" +#include "third_party/mojo_services/src/view_manager/public/cpp/view_manager_client_factory.h" +#include "third_party/mojo_services/src/view_manager/public/cpp/view_manager_delegate.h" +#include "third_party/mojo_services/src/view_manager/public/cpp/view_observer.h" + +namespace base { +class MessageLoopProxy; +} + +namespace media { +class CdmFactory; +class MediaPermission; +class WebEncryptedMediaClientImpl; +} + +namespace mojo { +class ViewManager; +class View; +} + +namespace html_viewer { + +class AxProviderImpl; +class WebLayerTreeViewImpl; +class WebMediaPlayerFactory; + +// A view for a single HTML document. +class HTMLDocument : public blink::WebViewClient, + public blink::WebFrameClient, + public mojo::ViewManagerDelegate, + public mojo::ViewObserver, + public mojo::InterfaceFactory<mojo::AxProvider> { + public: + // Load a new HTMLDocument with |response|. + // + // |services| should be used to implement a ServiceProvider which exposes + // services to the connecting application. + // Commonly, the connecting application is the ViewManager and it will + // request ViewManagerClient. + // + // |shell| is the Shell connection for this mojo::Application. + HTMLDocument(mojo::InterfaceRequest<mojo::ServiceProvider> services, + mojo::URLResponsePtr response, + mojo::Shell* shell, + scoped_refptr<base::MessageLoopProxy> compositor_thread, + WebMediaPlayerFactory* web_media_player_factory, + bool is_headless); + ~HTMLDocument() override; + + private: + // Updates the size and scale factor of the webview and related classes from + // |root_|. + void UpdateWebviewSizeFromViewSize(); + + // 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); + 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, + const blink::WebString& frameName, + blink::WebSandboxFlags sandboxFlags); + virtual void frameDetached(blink::WebFrame*); + virtual blink::WebCookieJar* cookieJar(blink::WebLocalFrame* frame); + virtual blink::WebNavigationPolicy decidePolicyForNavigation( + blink::WebLocalFrame* frame, + blink::WebDataSource::ExtraData* data, + const blink::WebURLRequest& request, + blink::WebNavigationType nav_type, + blink::WebNavigationPolicy default_policy, + bool isRedirect); + 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, + mojo::InterfaceRequest<mojo::ServiceProvider> services, + mojo::ServiceProviderPtr exposed_services) override; + void OnViewManagerDisconnected(mojo::ViewManager* view_manager) override; + + // ViewObserver methods: + void OnViewBoundsChanged(mojo::View* view, + const mojo::Rect& old_bounds, + const mojo::Rect& new_bounds) override; + void OnViewDestroyed(mojo::View* view) override; + void OnViewInputEvent(mojo::View* view, const mojo::EventPtr& event) override; + + // mojo::InterfaceFactory<mojo::AxProvider> + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mojo::AxProvider> request) override; + + void Load(mojo::URLResponsePtr response); + + media::MediaPermission* GetMediaPermission(); + media::CdmFactory* GetCdmFactory(); + + mojo::URLResponsePtr response_; + mojo::ServiceProviderImpl exported_services_; + mojo::ServiceProviderPtr embedder_service_provider_; + mojo::Shell* shell_; + 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::MessageLoopProxy> compositor_thread_; + WebMediaPlayerFactory* web_media_player_factory_; + + // EncryptedMediaClient attached to this frame; lazily initialized. + scoped_ptr<media::WebEncryptedMediaClientImpl> web_encrypted_media_client_; + + scoped_ptr<media::MediaPermission> media_permission_; + scoped_ptr<media::CdmFactory> cdm_factory_; + + // HTMLDocument 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; + + // Set if the content will never be displayed. + bool is_headless_; + + scoped_ptr<TouchHandler> touch_handler_; + + float device_pixel_ratio_; + + DISALLOW_COPY_AND_ASSIGN(HTMLDocument); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_HTML_DOCUMENT_H_ diff --git a/components/html_viewer/html_viewer.cc b/components/html_viewer/html_viewer.cc new file mode 100644 index 0000000..d71d043 --- /dev/null +++ b/components/html_viewer/html_viewer.cc @@ -0,0 +1,254 @@ +// 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 "base/command_line.h" +#include "base/i18n/icu_util.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/path_service.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/thread.h" +#include "components/html_viewer/blink_platform_impl.h" +#include "components/html_viewer/discardable_memory_allocator.h" +#include "components/html_viewer/html_document.h" +#include "components/html_viewer/web_media_player_factory.h" +#include "gin/v8_initializer.h" +#include "mojo/application/application_runner_chromium.h" +#include "mojo/services/network/public/interfaces/network_service.mojom.h" +#include "third_party/WebKit/public/web/WebKit.h" +#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" +#include "third_party/mojo/src/mojo/public/c/system/main.h" +#include "third_party/mojo/src/mojo/public/cpp/application/application_connection.h" +#include "third_party/mojo/src/mojo/public/cpp/application/application_delegate.h" +#include "third_party/mojo/src/mojo/public/cpp/application/application_impl.h" +#include "third_party/mojo/src/mojo/public/cpp/application/connect.h" +#include "third_party/mojo/src/mojo/public/cpp/application/interface_factory_impl.h" +#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h" +#include "third_party/mojo_services/src/content_handler/public/interfaces/content_handler.mojom.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/ui_base_paths.h" + +using mojo::ApplicationConnection; +using mojo::Array; +using mojo::BindToRequest; +using mojo::ContentHandler; +using mojo::InterfaceRequest; +using mojo::ServiceProvider; +using mojo::ServiceProviderPtr; +using mojo::ShellPtr; +using mojo::String; +using mojo::URLLoaderPtr; +using mojo::URLResponsePtr; + +namespace html_viewer { + +// Switches for html_viewer. + +// Enable MediaRenderer in media pipeline instead of using the internal +// media::Renderer implementation. +const char kEnableMojoMediaRenderer[] = "enable-mojo-media-renderer"; + +// Disables support for (unprefixed) Encrypted Media Extensions. +const char kDisableEncryptedMedia[] = "disable-encrypted-media"; + +// Prevents creation of any output surface. +const char kIsHeadless[] = "is-headless"; + +size_t kDesiredMaxMemory = 20 * 1024 * 1024; + +class HTMLViewer; + +class HTMLViewerApplication : public mojo::Application { + public: + HTMLViewerApplication(InterfaceRequest<Application> request, + URLResponsePtr response, + scoped_refptr<base::MessageLoopProxy> compositor_thread, + WebMediaPlayerFactory* web_media_player_factory, + bool is_headless) + : url_(response->url), + binding_(this, request.Pass()), + initial_response_(response.Pass()), + compositor_thread_(compositor_thread), + web_media_player_factory_(web_media_player_factory), + is_headless_(is_headless) {} + + void Initialize(ShellPtr shell, + Array<String> args, + const String& url) override { + ServiceProviderPtr service_provider; + shell_ = shell.Pass(); + shell_->ConnectToApplication("mojo:network_service", + GetProxy(&service_provider), nullptr); + ConnectToService(service_provider.get(), &network_service_); + } + + void AcceptConnection(const String& requestor_url, + InterfaceRequest<ServiceProvider> services, + ServiceProviderPtr exposed_services, + const String& url) override { + if (initial_response_) { + OnResponseReceived(URLLoaderPtr(), services.Pass(), + initial_response_.Pass()); + } else { + URLLoaderPtr loader; + network_service_->CreateURLLoader(GetProxy(&loader)); + mojo::URLRequestPtr request(mojo::URLRequest::New()); + request->url = url_; + request->auto_follow_redirects = true; + + // |loader| will be pass to the OnResponseReceived method through a + // callback. Because order of evaluation is undefined, a reference to the + // raw pointer is needed. + mojo::URLLoader* raw_loader = loader.get(); + raw_loader->Start( + request.Pass(), + base::Bind(&HTMLViewerApplication::OnResponseReceived, + base::Unretained(this), base::Passed(&loader), + base::Passed(&services))); + } + } + + void RequestQuit() override {} + + private: + void OnResponseReceived(URLLoaderPtr loader, + InterfaceRequest<ServiceProvider> services, + URLResponsePtr response) { + new HTMLDocument(services.Pass(), response.Pass(), shell_.get(), + compositor_thread_, web_media_player_factory_, + is_headless_); + } + + String url_; + mojo::StrongBinding<mojo::Application> binding_; + ShellPtr shell_; + mojo::NetworkServicePtr network_service_; + URLResponsePtr initial_response_; + scoped_refptr<base::MessageLoopProxy> compositor_thread_; + WebMediaPlayerFactory* web_media_player_factory_; + bool is_headless_; +}; + +class ContentHandlerImpl : public mojo::InterfaceImpl<ContentHandler> { + public: + ContentHandlerImpl(scoped_refptr<base::MessageLoopProxy> compositor_thread, + WebMediaPlayerFactory* web_media_player_factory, + bool is_headless) + : compositor_thread_(compositor_thread), + web_media_player_factory_(web_media_player_factory), + is_headless_(is_headless) {} + ~ContentHandlerImpl() override {} + + private: + // Overridden from ContentHandler: + void StartApplication(InterfaceRequest<mojo::Application> request, + URLResponsePtr response) override { + new HTMLViewerApplication(request.Pass(), response.Pass(), + compositor_thread_, web_media_player_factory_, + is_headless_); + } + + scoped_refptr<base::MessageLoopProxy> compositor_thread_; + WebMediaPlayerFactory* web_media_player_factory_; + bool is_headless_; + + DISALLOW_COPY_AND_ASSIGN(ContentHandlerImpl); +}; + +class HTMLViewer : public mojo::ApplicationDelegate, + public mojo::InterfaceFactory<ContentHandler> { + public: + HTMLViewer() + : discardable_memory_allocator_(kDesiredMaxMemory), + compositor_thread_("compositor thread") {} + + ~HTMLViewer() override { blink::shutdown(); } + + private: + // Overridden from ApplicationDelegate: + void Initialize(mojo::ApplicationImpl* app) override { + base::DiscardableMemoryAllocator::SetInstance( + &discardable_memory_allocator_); + + blink_platform_.reset(new BlinkPlatformImpl(app)); +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) + // Note: this requires file system access. + gin::V8Initializer::LoadV8Snapshot(); +#endif + blink::initialize(blink_platform_.get()); + base::i18n::InitializeICU(); + + ui::RegisterPathProvider(); + + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + + logging::LoggingSettings settings; + settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; + logging::InitLogging(settings); + // Display process ID, thread ID and timestamp in logs. + logging::SetLogItems(true, true, true, false); + + if (command_line->HasSwitch(kDisableEncryptedMedia)) + blink::WebRuntimeFeatures::enableEncryptedMedia(false); + + is_headless_ = command_line->HasSwitch(kIsHeadless); + if (!is_headless_) { + // TODO(sky): consider putting this into the .so so that we don't need + // file system access. + base::FilePath ui_test_pak_path; + CHECK(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path)); + ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path); + } + + compositor_thread_.Start(); +#if defined(OS_ANDROID) + // TODO(sky): Get WebMediaPlayerFactory working on android. + NOTIMPLEMENTED(); +#else + bool enable_mojo_media_renderer = + command_line->HasSwitch(kEnableMojoMediaRenderer); + + web_media_player_factory_.reset(new WebMediaPlayerFactory( + compositor_thread_.message_loop_proxy(), enable_mojo_media_renderer)); +#endif + } + + bool ConfigureIncomingConnection(ApplicationConnection* connection) override { + connection->AddService(this); + return true; + } + + // Overridden from InterfaceFactory<ContentHandler> + void Create(ApplicationConnection* connection, + mojo::InterfaceRequest<ContentHandler> request) override { + BindToRequest( + new ContentHandlerImpl(compositor_thread_.message_loop_proxy(), + web_media_player_factory_.get(), is_headless_), + &request); + } + + // Skia requires that we have one of these. Unlike the one used in chrome, + // this doesn't use purgable shared memory. Instead, it tries to free the + // oldest unlocked chunks on allocation. + // + // TODO(erg): In the long run, delete this allocator and get the real shared + // memory based purging allocator working here. + DiscardableMemoryAllocator discardable_memory_allocator_; + + scoped_ptr<BlinkPlatformImpl> blink_platform_; + base::Thread compositor_thread_; + scoped_ptr<WebMediaPlayerFactory> web_media_player_factory_; + // Set if the content will never be displayed. + bool is_headless_; + + DISALLOW_COPY_AND_ASSIGN(HTMLViewer); +}; + +} // namespace html_viewer + +MojoResult MojoMain(MojoHandle shell_handle) { + mojo::ApplicationRunnerChromium runner(new html_viewer::HTMLViewer); + return runner.Run(shell_handle); +} diff --git a/components/html_viewer/html_viewer_version.rc b/components/html_viewer/html_viewer_version.rc new file mode 100644 index 0000000..1626afa --- /dev/null +++ b/components/html_viewer/html_viewer_version.rc @@ -0,0 +1,46 @@ +// Copyright 2015 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 <verrsrc.h> + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "The Chromium Authors" + VALUE "FileDescription", "Chromium" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "html_viewer_dll" + VALUE "LegalCopyright", "Copyright 2015 The Chromium Authors. All rights reserved." + VALUE "OriginalFilename", "html_viewer.mojo" + VALUE "ProductName", "Chromium" + VALUE "ProductVersion", "1.0.0.0" + VALUE "CompanyShortName", "The Chromium Authors" + VALUE "ProductShortName", "Chromium" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + diff --git a/components/html_viewer/mock_web_blob_registry_impl.cc b/components/html_viewer/mock_web_blob_registry_impl.cc new file mode 100644 index 0000000..02cff57 --- /dev/null +++ b/components/html_viewer/mock_web_blob_registry_impl.cc @@ -0,0 +1,121 @@ +// Copyright 2015 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/mock_web_blob_registry_impl.h" + +#include "third_party/WebKit/public/platform/WebBlobData.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/platform/WebVector.h" + +using blink::WebBlobData; +using blink::WebString; +using blink::WebURL; +using blink::WebVector; + +namespace html_viewer { + +MockWebBlobRegistryImpl::MockWebBlobRegistryImpl() { +} + +MockWebBlobRegistryImpl::~MockWebBlobRegistryImpl() { +} + +void MockWebBlobRegistryImpl::registerBlobData(const WebString& uuid, + const WebBlobData& data) { + const std::string uuid_str(uuid.utf8()); + blob_ref_count_map_[uuid_str] = 1; + scoped_ptr<ScopedVector<blink::WebBlobData::Item>> items( + new ScopedVector<blink::WebBlobData::Item>); + items->reserve(data.itemCount()); + for (size_t i = 0; i < data.itemCount(); ++i) { + scoped_ptr<blink::WebBlobData::Item> item(new blink::WebBlobData::Item); + data.itemAt(i, *item); + items->push_back(item.release()); + } + blob_data_items_map_.set(uuid_str, items.Pass()); +} + +void MockWebBlobRegistryImpl::addBlobDataRef(const WebString& uuid) { + blob_ref_count_map_[uuid.utf8()]++; +} + +void MockWebBlobRegistryImpl::removeBlobDataRef(const WebString& uuid) { + const std::string uuid_str(uuid.utf8()); + auto it = blob_ref_count_map_.find(uuid_str); + if (it != blob_ref_count_map_.end() && !--it->second) { + blob_data_items_map_.erase(uuid_str); + blob_ref_count_map_.erase(it); + } +} + +void MockWebBlobRegistryImpl::registerPublicBlobURL(const WebURL& url, + const WebString& uuid) { + public_url_to_uuid_[url.spec()] = uuid; + addBlobDataRef(uuid); +} + +void MockWebBlobRegistryImpl::revokePublicBlobURL(const WebURL& url) { + auto it = public_url_to_uuid_.find(url.spec()); + if (it != public_url_to_uuid_.end()) { + removeBlobDataRef(it->second); + public_url_to_uuid_.erase(it); + } +} + +void MockWebBlobRegistryImpl::registerStreamURL(const WebURL& url, + const WebString& content_type) { + NOTIMPLEMENTED(); +} + +void MockWebBlobRegistryImpl::registerStreamURL(const WebURL& url, + const blink::WebURL& src_url) { + NOTIMPLEMENTED(); +} + +void MockWebBlobRegistryImpl::addDataToStream(const WebURL& url, + const char* data, + size_t length) { + NOTIMPLEMENTED(); +} + +void MockWebBlobRegistryImpl::flushStream(const WebURL& url) { + NOTIMPLEMENTED(); +} + +void MockWebBlobRegistryImpl::finalizeStream(const WebURL& url) { + NOTIMPLEMENTED(); +} + +void MockWebBlobRegistryImpl::abortStream(const WebURL& url) { + NOTIMPLEMENTED(); +} + +void MockWebBlobRegistryImpl::unregisterStreamURL(const WebURL& url) { + NOTIMPLEMENTED(); +} + +bool MockWebBlobRegistryImpl::GetUUIDForURL(const blink::WebURL& url, + blink::WebString* uuid) const { + auto it = public_url_to_uuid_.find(url.spec()); + if (it != public_url_to_uuid_.end()) { + *uuid = it->second; + return true; + } + + return false; +} + +bool MockWebBlobRegistryImpl::GetBlobItems( + const WebString& uuid, + WebVector<WebBlobData::Item*>* items) const { + ScopedVector<WebBlobData::Item>* item_vector = + blob_data_items_map_.get(uuid.utf8()); + if (!item_vector) + return false; + *items = item_vector->get(); + return true; +} + +} // namespace html_viewer diff --git a/components/html_viewer/mock_web_blob_registry_impl.h b/components/html_viewer/mock_web_blob_registry_impl.h new file mode 100644 index 0000000..8c8acbb --- /dev/null +++ b/components/html_viewer/mock_web_blob_registry_impl.h @@ -0,0 +1,64 @@ +// Copyright 2015 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_MOCK_WEB_BLOB_REGISTRY_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_MOCK_WEB_BLOB_REGISTRY_IMPL_H_ + +#include <map> + +#include "base/containers/scoped_ptr_hash_map.h" +#include "base/macros.h" +#include "base/memory/scoped_vector.h" +#include "third_party/WebKit/public/platform/WebBlobData.h" +#include "third_party/WebKit/public/platform/WebBlobRegistry.h" +#include "third_party/WebKit/public/platform/WebVector.h" + +namespace html_viewer { + +// TODO(erg): For now, this is a just a copy of content's testing +// mock. Eventually, this should be turned into a real implementation, but this +// at least lets us get github working. +class MockWebBlobRegistryImpl : public blink::WebBlobRegistry { + public: + MockWebBlobRegistryImpl(); + virtual ~MockWebBlobRegistryImpl(); + + virtual void registerBlobData(const blink::WebString& uuid, + const blink::WebBlobData& data); + virtual void addBlobDataRef(const blink::WebString& uuid); + virtual void removeBlobDataRef(const blink::WebString& uuid); + virtual void registerPublicBlobURL(const blink::WebURL&, + const blink::WebString& uuid); + virtual void revokePublicBlobURL(const blink::WebURL&); + + // Additional support for Streams. + virtual void registerStreamURL(const blink::WebURL& url, + const blink::WebString& content_type); + virtual void registerStreamURL(const blink::WebURL& url, + const blink::WebURL& src_url); + virtual void addDataToStream(const blink::WebURL& url, + const char* data, + size_t length); + virtual void flushStream(const blink::WebURL& url); + virtual void finalizeStream(const blink::WebURL& url); + virtual void abortStream(const blink::WebURL& url); + virtual void unregisterStreamURL(const blink::WebURL& url); + + bool GetUUIDForURL(const blink::WebURL& url, blink::WebString* uuid) const; + bool GetBlobItems(const blink::WebString& uuid, + blink::WebVector<blink::WebBlobData::Item*>* items) const; + + private: + base::ScopedPtrHashMap<std::string, ScopedVector<blink::WebBlobData::Item>> + blob_data_items_map_; + std::map<std::string, int> blob_ref_count_map_; + + std::map<std::string, blink::WebString> public_url_to_uuid_; + + DISALLOW_COPY_AND_ASSIGN(MockWebBlobRegistryImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_MOCK_WEB_BLOB_REGISTRY_IMPL_H_ diff --git a/components/html_viewer/test_blink_platform_impl.cc b/components/html_viewer/test_blink_platform_impl.cc new file mode 100644 index 0000000..700502d --- /dev/null +++ b/components/html_viewer/test_blink_platform_impl.cc @@ -0,0 +1,23 @@ +// 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/test_blink_platform_impl.h" + +namespace html_viewer { + +TestBlinkPlatformImpl::TestBlinkPlatformImpl() { +} + +TestBlinkPlatformImpl::~TestBlinkPlatformImpl() { +} + +blink::WebCookieJar* BlinkPlatformImpl::cookieJar() { + return cookie_jar_.get(); +} + +blink::WebClipboard* BlinkPlatformImpl::clipboard() { + return clipboard_.get(); +} + +} // namespace html_viewer diff --git a/components/html_viewer/test_blink_platform_impl.h b/components/html_viewer/test_blink_platform_impl.h new file mode 100644 index 0000000..c3b6768 --- /dev/null +++ b/components/html_viewer/test_blink_platform_impl.h @@ -0,0 +1,31 @@ +// 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_TEST_BLINK_PLATFORM_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_TEST_BLINK_PLATFORM_IMPL_H_ + +#include "components/html_viewer/blink_platform_impl.h" + +#include "third_party/WebKit/public/platform/WebClipboard.h" +#include "third_party/WebKit/public/platform/WebCookieJar.h" + +namespace html_viewer { + +class TestBlinkPlatformImpl : public BlinkPlatformImpl { + public: + TestBlinkPlatformImpl(); + ~TestBlinkPlatformImpl() override; + + private: + // blink::Platform methods: + virtual blink::WebCookieJar* cookieJar(); + virtual blink::WebClipboard* clipboard(); + + blink::WebClipboard clipboard_; + blink::WebCookieJar cookie_jar_; +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_TEST_BLINK_PLATFORM_IMPL_H_ diff --git a/components/html_viewer/touch_handler.cc b/components/html_viewer/touch_handler.cc new file mode 100644 index 0000000..e968e60 --- /dev/null +++ b/components/html_viewer/touch_handler.cc @@ -0,0 +1,187 @@ +// Copyright 2015 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/touch_handler.h" + +#include "third_party/WebKit/public/web/WebInputEvent.h" +#include "third_party/WebKit/public/web/WebView.h" +#include "third_party/mojo_services/src/input_events/public/interfaces/input_events.mojom.h" +#include "ui/events/blink/blink_event_util.h" +#include "ui/events/gesture_detection/gesture_provider_config_helper.h" +#include "ui/events/gesture_detection/motion_event_generic.h" + +namespace html_viewer { +namespace { + +void SetPropertiesFromEvent(const mojo::Event& event, + ui::PointerProperties* properties) { + properties->id = event.pointer_data->pointer_id; + properties->x = event.pointer_data->x; + properties->y = event.pointer_data->y; + properties->raw_x = event.pointer_data->screen_x; + properties->raw_y = event.pointer_data->screen_y; + properties->pressure = event.pointer_data->pressure; + properties->touch_major = event.pointer_data->radius_major; + properties->touch_minor = event.pointer_data->radius_minor; + properties->orientation = event.pointer_data->orientation; + // TODO(sky): Add support for tool_type. +} + +} // namespace + +TouchHandler::TouchHandler(blink::WebView* web_view) + : web_view_(web_view), + gesture_provider_(ui::GetGestureProviderConfig( + ui::GestureProviderConfigType::CURRENT_PLATFORM), + this) { +} + +TouchHandler::~TouchHandler() { +} + +void TouchHandler::OnTouchEvent(const mojo::Event& event) { + if (!UpdateMotionEvent(event)) + return; + + SendMotionEventToGestureProvider(); + + PostProcessMotionEvent(event); +} + +void TouchHandler::OnGestureEvent(const ui::GestureEventData& gesture) { + blink::WebGestureEvent web_gesture = + CreateWebGestureEventFromGestureEventData(gesture); + // TODO(jdduke): Remove this workaround after Android fixes UiAutomator to + // stop providing shift meta values to synthetic MotionEvents. This prevents + // unintended shift+click interpretation of all accessibility clicks. + // See crbug.com/443247. + if (web_gesture.type == blink::WebInputEvent::GestureTap && + web_gesture.modifiers == blink::WebInputEvent::ShiftKey) { + web_gesture.modifiers = 0; + } + web_view_->handleInputEvent(web_gesture); +} + +bool TouchHandler::UpdateMotionEvent(const mojo::Event& event) { + ui::PointerProperties properties; + SetPropertiesFromEvent(event, &properties); + + const base::TimeTicks timestamp( + base::TimeTicks::FromInternalValue(event.time_stamp)); + if (current_motion_event_.get()) { + current_motion_event_->set_id(current_motion_event_->GetId() + 1); + current_motion_event_->set_event_time(timestamp); + } + + switch (event.action) { + case mojo::EVENT_TYPE_POINTER_DOWN: + if (!current_motion_event_.get()) { + current_motion_event_.reset(new ui::MotionEventGeneric( + ui::MotionEvent::ACTION_DOWN, timestamp, properties)); + } else { + const int index = + current_motion_event_->FindPointerIndexOfId(properties.id); + if (index != -1) { + DVLOG(1) << "pointer down and pointer already down id=" + << properties.id; + return false; + } + current_motion_event_->PushPointer(properties); + current_motion_event_->set_action(ui::MotionEvent::ACTION_POINTER_DOWN); + current_motion_event_->set_action_index(static_cast<int>(index)); + } + return true; + + case mojo::EVENT_TYPE_POINTER_UP: { + if (!current_motion_event_.get()) { + DVLOG(1) << "pointer up with no event, id=" << properties.id; + return false; + } + const int index = + current_motion_event_->FindPointerIndexOfId(properties.id); + if (index == -1) { + DVLOG(1) << "pointer up and pointer not down id=" << properties.id; + return false; + } + current_motion_event_->pointer(index) = properties; + current_motion_event_->set_action( + current_motion_event_->GetPointerCount() == 1 + ? ui::MotionEvent::ACTION_UP + : ui::MotionEvent::ACTION_POINTER_UP); + current_motion_event_->set_action_index(static_cast<int>(index)); + return true; + } + + case mojo::EVENT_TYPE_POINTER_MOVE: { + if (!current_motion_event_.get()) { + DVLOG(1) << "pointer move with no event, id=" << properties.id; + return false; + } + const int index = + current_motion_event_->FindPointerIndexOfId(properties.id); + if (index == -1) { + DVLOG(1) << "pointer move and pointer not down id=" << properties.id; + return false; + } + current_motion_event_->pointer(index) = properties; + current_motion_event_->set_action(ui::MotionEvent::ACTION_MOVE); + current_motion_event_->set_action_index(static_cast<int>(index)); + return true; + } + + case mojo::EVENT_TYPE_POINTER_CANCEL: { + if (!current_motion_event_.get()) { + DVLOG(1) << "canel with no event, id=" << properties.id; + return false; + } + const int index = + current_motion_event_->FindPointerIndexOfId(properties.id); + if (index == -1) { + DVLOG(1) << "cancel and pointer not down id=" << properties.id; + return false; + } + current_motion_event_->pointer(index) = properties; + current_motion_event_->set_action(ui::MotionEvent::ACTION_CANCEL); + current_motion_event_->set_action_index(0); + return true; + } + + default: + NOTREACHED(); + } + return false; +} + +void TouchHandler::SendMotionEventToGestureProvider() { + ui::FilteredGestureProvider::TouchHandlingResult result = + gesture_provider_.OnTouchEvent(*current_motion_event_); + if (!result.succeeded) + return; + + blink::WebTouchEvent web_event = ui::CreateWebTouchEventFromMotionEvent( + *current_motion_event_, result.did_generate_scroll); + gesture_provider_.OnSyncTouchEventAck(web_view_->handleInputEvent(web_event)); +} + +void TouchHandler::PostProcessMotionEvent(const mojo::Event& event) { + switch (event.action) { + case mojo::EVENT_TYPE_POINTER_UP: { + const int index = current_motion_event_->FindPointerIndexOfId( + event.pointer_data->pointer_id); + current_motion_event_->RemovePointerAt(index); + if (current_motion_event_->GetPointerCount() == 0) + current_motion_event_.reset(); + break; + } + + case mojo::EVENT_TYPE_POINTER_CANCEL: + current_motion_event_.reset(); + break; + + default: + break; + } +} + +} // namespace html_viewer diff --git a/components/html_viewer/touch_handler.h b/components/html_viewer/touch_handler.h new file mode 100644 index 0000000..460a3d5 --- /dev/null +++ b/components/html_viewer/touch_handler.h @@ -0,0 +1,62 @@ +// Copyright 2015 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_TOUCH_HANDLER_H_ +#define COMPONENTS_HTML_VIEWER_TOUCH_HANDLER_H_ + +#include "base/basictypes.h" +#include "ui/events/gesture_detection/filtered_gesture_provider.h" + +namespace blink { +class WebView; +} + +namespace mojo { +class Event; +} + +namespace ui { +class MotionEventGeneric; +} + +namespace html_viewer { + +// TouchHandler is responsible for converting touch events into gesture events. +// It does this by converting mojo::Events into a MotionEventGeneric and using +// FilteredGestureProvider. +class TouchHandler : public ui::GestureProviderClient { + public: + explicit TouchHandler(blink::WebView* web_view); + ~TouchHandler() override; + + void OnTouchEvent(const mojo::Event& event); + + // ui::GestureProviderClient implementation. + void OnGestureEvent(const ui::GestureEventData& gesture) override; + + private: + // Updates |current_motion_event_| from |event|. Returns true on success. + bool UpdateMotionEvent(const mojo::Event& event); + + // Sends |current_motion_event_| to the GestureProvider and WebView. + void SendMotionEventToGestureProvider(); + + // Does post processing after sending |current_motion_event_| to the + // GestureProvider. + void PostProcessMotionEvent(const mojo::Event& event); + + blink::WebView* web_view_; + + ui::FilteredGestureProvider gesture_provider_; + + // As touch events are received they are converted to this event. If null no + // touch events are in progress. + scoped_ptr<ui::MotionEventGeneric> current_motion_event_; + + DISALLOW_COPY_AND_ASSIGN(TouchHandler); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_TOUCH_HANDLER_H_ diff --git a/components/html_viewer/web_clipboard_impl.cc b/components/html_viewer/web_clipboard_impl.cc new file mode 100644 index 0000000..8810c3d --- /dev/null +++ b/components/html_viewer/web_clipboard_impl.cc @@ -0,0 +1,207 @@ +// 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/web_clipboard_impl.h" + +#include "base/bind.h" +#include "components/html_viewer/blink_basic_type_converters.h" + +using mojo::Array; +using mojo::Clipboard; +using mojo::Map; +using mojo::String; + +namespace html_viewer { +namespace { + +void CopyUint64(uint64_t* output, uint64_t input) { + *output = input; +} + +void CopyWebString(blink::WebString* output, const Array<uint8_t>& input) { + // blink does not differentiate between the requested data type not existing + // and the empty string. + if (input.is_null()) { + output->reset(); + } else { + *output = blink::WebString::fromUTF8( + reinterpret_cast<const char*>(&input.front()), + input.size()); + } +} + +void CopyURL(blink::WebURL* pageURL, const Array<uint8_t>& input) { + if (input.is_null()) { + *pageURL = blink::WebURL(); + } else { + *pageURL = GURL(std::string(reinterpret_cast<const char*>(&input.front()), + input.size())); + } +} + +void CopyVectorString(std::vector<std::string>* output, + const Array<String>& input) { + *output = input.To<std::vector<std::string> >(); +} + +template <typename T, typename U> +bool Contains(const std::vector<T>& v, const U& item) { + return std::find(v.begin(), v.end(), item) != v.end(); +} + +const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; + +} // namespace + +WebClipboardImpl::WebClipboardImpl(mojo::ClipboardPtr clipboard) + : clipboard_(clipboard.Pass()) { +} + +WebClipboardImpl::~WebClipboardImpl() { +} + +uint64_t WebClipboardImpl::sequenceNumber(Buffer buffer) { + mojo::Clipboard::Type clipboard_type = ConvertBufferType(buffer); + + uint64_t number = 0; + clipboard_->GetSequenceNumber(clipboard_type, + base::Bind(&CopyUint64, &number)); + + // Force this to be synchronous. + clipboard_.WaitForIncomingMethodCall(); + return number; +} + +bool WebClipboardImpl::isFormatAvailable(Format format, Buffer buffer) { + Clipboard::Type clipboard_type = ConvertBufferType(buffer); + + std::vector<std::string> types; + clipboard_->GetAvailableMimeTypes( + clipboard_type, base::Bind(&CopyVectorString, &types)); + + // Force this to be synchronous. + clipboard_.WaitForIncomingMethodCall(); + + switch (format) { + case FormatPlainText: + return Contains(types, Clipboard::MIME_TYPE_TEXT); + case FormatHTML: + return Contains(types, Clipboard::MIME_TYPE_HTML); + case FormatSmartPaste: + return Contains(types, kMimeTypeWebkitSmartPaste); + case FormatBookmark: + // This might be difficult. + return false; + } + + return false; +} + +blink::WebVector<blink::WebString> WebClipboardImpl::readAvailableTypes( + Buffer buffer, + bool* contains_filenames) { + Clipboard::Type clipboard_type = ConvertBufferType(buffer); + + std::vector<std::string> types; + clipboard_->GetAvailableMimeTypes( + clipboard_type, base::Bind(&CopyVectorString, &types)); + + // Force this to be synchronous. + clipboard_.WaitForIncomingMethodCall(); + + // AFAICT, every instance of setting contains_filenames is false. + *contains_filenames = false; + + blink::WebVector<blink::WebString> output(types.size()); + for (size_t i = 0; i < types.size(); ++i) { + output[i] = blink::WebString::fromUTF8(types[i]); + } + + return output; +} + +blink::WebString WebClipboardImpl::readPlainText(Buffer buffer) { + Clipboard::Type type = ConvertBufferType(buffer); + + blink::WebString text; + clipboard_->ReadMimeType(type, Clipboard::MIME_TYPE_TEXT, + base::Bind(&CopyWebString, &text)); + + // Force this to be synchronous. + clipboard_.WaitForIncomingMethodCall(); + + return text; +} + +blink::WebString WebClipboardImpl::readHTML(Buffer buffer, + blink::WebURL* page_url, + unsigned* fragment_start, + unsigned* fragment_end) { + Clipboard::Type type = ConvertBufferType(buffer); + + blink::WebString html; + clipboard_->ReadMimeType(type, Clipboard::MIME_TYPE_HTML, + base::Bind(&CopyWebString, &html)); + clipboard_.WaitForIncomingMethodCall(); + + *fragment_start = 0; + *fragment_end = static_cast<unsigned>(html.length()); + + clipboard_->ReadMimeType(type, Clipboard::MIME_TYPE_URL, + base::Bind(&CopyURL, page_url)); + clipboard_.WaitForIncomingMethodCall(); + + return html; +} + +blink::WebString WebClipboardImpl::readCustomData( + Buffer buffer, + const blink::WebString& mime_type) { + Clipboard::Type clipboard_type = ConvertBufferType(buffer); + + blink::WebString data; + clipboard_->ReadMimeType( + clipboard_type, mime_type.utf8(), base::Bind(&CopyWebString, &data)); + + // Force this to be synchronous. + clipboard_.WaitForIncomingMethodCall(); + + return data; +} + +void WebClipboardImpl::writePlainText(const blink::WebString& plain_text) { + Map<String, Array<uint8_t>> data; + data[Clipboard::MIME_TYPE_TEXT] = Array<uint8_t>::From(plain_text); + + clipboard_->WriteClipboardData(Clipboard::TYPE_COPY_PASTE, data.Pass()); +} + +void WebClipboardImpl::writeHTML(const blink::WebString& html_text, + const blink::WebURL& source_url, + const blink::WebString& plain_text, + bool writeSmartPaste) { + Map<String, Array<uint8_t>> data; + data[Clipboard::MIME_TYPE_TEXT] = Array<uint8_t>::From(plain_text); + data[Clipboard::MIME_TYPE_HTML] = Array<uint8_t>::From(html_text); + data[Clipboard::MIME_TYPE_URL] = Array<uint8_t>::From(source_url.string()); + + if (writeSmartPaste) + data[kMimeTypeWebkitSmartPaste] = Array<uint8_t>::From(blink::WebString()); + + clipboard_->WriteClipboardData(Clipboard::TYPE_COPY_PASTE, data.Pass()); +} + +Clipboard::Type WebClipboardImpl::ConvertBufferType(Buffer buffer) { + switch (buffer) { + case BufferStandard: + return Clipboard::TYPE_COPY_PASTE; + case BufferSelection: + return Clipboard::TYPE_SELECTION; + } + + NOTREACHED(); + return Clipboard::TYPE_COPY_PASTE; +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_clipboard_impl.h b/components/html_viewer/web_clipboard_impl.h new file mode 100644 index 0000000..f671e31 --- /dev/null +++ b/components/html_viewer/web_clipboard_impl.h @@ -0,0 +1,49 @@ +// 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_WEB_CLIPBOARD_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_CLIPBOARD_IMPL_H_ + +#include "third_party/WebKit/public/platform/WebClipboard.h" +#include "third_party/mojo_services/src/clipboard/public/interfaces/clipboard.mojom.h" + +namespace html_viewer { + +class WebClipboardImpl : public blink::WebClipboard { + public: + WebClipboardImpl(mojo::ClipboardPtr clipboard); + virtual ~WebClipboardImpl(); + + // blink::WebClipboard methods: + virtual uint64_t sequenceNumber(Buffer); + virtual bool isFormatAvailable(Format, Buffer); + virtual blink::WebVector<blink::WebString> readAvailableTypes( + Buffer buffer, + bool* contains_filenames); + virtual blink::WebString readPlainText(Buffer buffer); + virtual blink::WebString readHTML(Buffer buffer, + blink::WebURL* page_url, + unsigned* fragment_start, + unsigned* fragment_end); + // TODO(erg): readImage() + virtual blink::WebString readCustomData(Buffer buffer, + const blink::WebString& type); + virtual void writePlainText(const blink::WebString& plain_text); + virtual void writeHTML(const blink::WebString& html_text, + const blink::WebURL& source_url, + const blink::WebString& plain_text, + bool write_smart_paste); + + private: + // Changes webkit buffers to mojo Clipboard::Types. + mojo::Clipboard::Type ConvertBufferType(Buffer buffer); + + mojo::ClipboardPtr clipboard_; + + DISALLOW_COPY_AND_ASSIGN(WebClipboardImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_CLIPBOARD_IMPL_H_ diff --git a/components/html_viewer/web_cookie_jar_impl.cc b/components/html_viewer/web_cookie_jar_impl.cc new file mode 100644 index 0000000..019acfb --- /dev/null +++ b/components/html_viewer/web_cookie_jar_impl.cc @@ -0,0 +1,71 @@ +// 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/web_cookie_jar_impl.h" + +#include "base/bind.h" +#include "third_party/WebKit/public/platform/WebURL.h" + +using mojo::String; + +namespace html_viewer { +namespace { + +void CopyBool(bool* output, bool input) { + *output = input; +} + +void CopyString(String* output, const String& input) { + *output = input; +} + +} // namespace + +WebCookieJarImpl::WebCookieJarImpl(mojo::CookieStorePtr store) + : store_(store.Pass()) { +} + +WebCookieJarImpl::~WebCookieJarImpl() { +} + +void WebCookieJarImpl::setCookie(const blink::WebURL& url, + const blink::WebURL& first_party_for_cookies, + const blink::WebString& cookie) { + bool success; + store_->Set(url.string().utf8(), cookie.utf8(), + base::Bind(&CopyBool, &success)); + + // Wait to ensure the cookie was set before advancing. That way any + // subsequent URL request will see the changes to the cookie store. + // + // TODO(darin): Consider using associated message pipes for the CookieStore + // and URLLoader, so that we could let this method call run asynchronously + // without suffering an ordering problem. See crbug/386825. + // + store_.WaitForIncomingMethodCall(); +} + +blink::WebString WebCookieJarImpl::cookies( + const blink::WebURL& url, + const blink::WebURL& first_party_for_cookies) { + String result; + store_->Get(url.string().utf8(), base::Bind(&CopyString, &result)); + + // Wait for the result. Since every outbound request we make to the cookie + // store is followed up with WaitForIncomingMethodCall, we can be sure that + // the next incoming method call will be the response to our request. + store_.WaitForIncomingMethodCall(); + if (!result) + return blink::WebString(); + + return blink::WebString::fromUTF8(result); +} + +blink::WebString WebCookieJarImpl::cookieRequestHeaderFieldValue( + const blink::WebURL& url, + const blink::WebURL& first_party_for_cookies) { + return cookies(url, first_party_for_cookies); +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_cookie_jar_impl.h b/components/html_viewer/web_cookie_jar_impl.h new file mode 100644 index 0000000..bec897e --- /dev/null +++ b/components/html_viewer/web_cookie_jar_impl.h @@ -0,0 +1,36 @@ +// 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_WEB_COOKIE_JAR_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_COOKIE_JAR_IMPL_H_ + +#include "mojo/services/network/public/interfaces/cookie_store.mojom.h" +#include "third_party/WebKit/public/platform/WebCookieJar.h" + +namespace html_viewer { + +class WebCookieJarImpl : public blink::WebCookieJar { + public: + explicit WebCookieJarImpl(mojo::CookieStorePtr store); + virtual ~WebCookieJarImpl(); + + // blink::WebCookieJar methods: + virtual void setCookie(const blink::WebURL& url, + const blink::WebURL& first_party_for_cookies, + const blink::WebString& cookie); + virtual blink::WebString cookies( + const blink::WebURL& url, + const blink::WebURL& first_party_for_cookies); + virtual blink::WebString cookieRequestHeaderFieldValue( + const blink::WebURL& url, + const blink::WebURL& first_party_for_cookies); + + private: + mojo::CookieStorePtr store_; + DISALLOW_COPY_AND_ASSIGN(WebCookieJarImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_COOKIE_JAR_IMPL_H_ diff --git a/components/html_viewer/web_layer_tree_view_impl.cc b/components/html_viewer/web_layer_tree_view_impl.cc new file mode 100644 index 0000000..94f1485 --- /dev/null +++ b/components/html_viewer/web_layer_tree_view_impl.cc @@ -0,0 +1,254 @@ +// 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/web_layer_tree_view_impl.h" + +#include "base/message_loop/message_loop_proxy.h" +#include "cc/blink/web_layer_impl.h" +#include "cc/layers/layer.h" +#include "cc/output/begin_frame_args.h" +#include "cc/scheduler/begin_frame_source.h" +#include "cc/trees/layer_tree_host.h" +#include "mojo/cc/context_provider_mojo.h" +#include "mojo/cc/output_surface_mojo.h" +#include "mojo/converters/surfaces/surfaces_type_converters.h" +#include "third_party/WebKit/public/web/WebWidget.h" +#include "third_party/mojo_services/src/view_manager/public/cpp/view.h" + +namespace html_viewer { + +WebLayerTreeViewImpl::WebLayerTreeViewImpl( + scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy, + mojo::SurfacePtr surface, + mojo::GpuPtr gpu_service) + : widget_(NULL), + view_(NULL), + main_thread_compositor_task_runner_(base::MessageLoopProxy::current()), + weak_factory_(this) { + main_thread_bound_weak_ptr_ = weak_factory_.GetWeakPtr(); + + cc::LayerTreeSettings settings; + + // For web contents, layer transforms should scale up the contents of layers + // to keep content always crisp when possible. + settings.layer_transforms_should_scale_layer_contents = true; + + cc::SharedBitmapManager* shared_bitmap_manager = nullptr; + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = nullptr; + cc::TaskGraphRunner* task_graph_runner = nullptr; + + layer_tree_host_ = + cc::LayerTreeHost::CreateThreaded(this, + shared_bitmap_manager, + gpu_memory_buffer_manager, + task_graph_runner, + settings, + base::MessageLoopProxy::current(), + compositor_message_loop_proxy, + nullptr); + DCHECK(layer_tree_host_); + + if (surface && gpu_service) { + mojo::CommandBufferPtr cb; + gpu_service->CreateOffscreenGLES2Context(GetProxy(&cb)); + scoped_refptr<cc::ContextProvider> context_provider( + new mojo::ContextProviderMojo(cb.PassMessagePipe())); + output_surface_.reset( + new mojo::OutputSurfaceMojo(this, context_provider, surface.Pass())); + } + layer_tree_host_->SetLayerTreeHostClientReady(); +} + +WebLayerTreeViewImpl::~WebLayerTreeViewImpl() { +} + +void WebLayerTreeViewImpl::WillBeginMainFrame() { +} + +void WebLayerTreeViewImpl::DidBeginMainFrame() { +} + +void WebLayerTreeViewImpl::BeginMainFrameNotExpectedSoon() { +} + +void WebLayerTreeViewImpl::BeginMainFrame(const cc::BeginFrameArgs& args) { + VLOG(2) << "WebLayerTreeViewImpl::BeginMainFrame"; + double frame_time_sec = (args.frame_time - base::TimeTicks()).InSecondsF(); + double deadline_sec = (args.deadline - base::TimeTicks()).InSecondsF(); + double interval_sec = args.interval.InSecondsF(); + blink::WebBeginFrameArgs web_begin_frame_args( + frame_time_sec, deadline_sec, interval_sec); + widget_->beginFrame(web_begin_frame_args); +} + +void WebLayerTreeViewImpl::Layout() { + widget_->layout(); +} + +void WebLayerTreeViewImpl::ApplyViewportDeltas( + const gfx::Vector2dF& inner_delta, + const gfx::Vector2dF& outer_delta, + const gfx::Vector2dF& elastic_overscroll_delta, + float page_scale, + float top_controls_delta) { + widget_->applyViewportDeltas( + inner_delta, + outer_delta, + elastic_overscroll_delta, + page_scale, + top_controls_delta); +} + +void WebLayerTreeViewImpl::ApplyViewportDeltas( + const gfx::Vector2d& scroll_delta, + float page_scale, + float top_controls_delta) { + widget_->applyViewportDeltas(scroll_delta, page_scale, top_controls_delta); +} + +void WebLayerTreeViewImpl::RequestNewOutputSurface() { + if (output_surface_.get()) + layer_tree_host_->SetOutputSurface(output_surface_.Pass()); +} + +void WebLayerTreeViewImpl::DidFailToInitializeOutputSurface() { + RequestNewOutputSurface(); +} + +void WebLayerTreeViewImpl::DidInitializeOutputSurface() { +} + +void WebLayerTreeViewImpl::WillCommit() { +} + +void WebLayerTreeViewImpl::DidCommit() { +} + +void WebLayerTreeViewImpl::DidCommitAndDrawFrame() { +} + +void WebLayerTreeViewImpl::DidCompleteSwapBuffers() { +} + +void WebLayerTreeViewImpl::setRootLayer(const blink::WebLayer& layer) { + layer_tree_host_->SetRootLayer( + static_cast<const cc_blink::WebLayerImpl*>(&layer)->layer()); +} + +void WebLayerTreeViewImpl::clearRootLayer() { + layer_tree_host_->SetRootLayer(scoped_refptr<cc::Layer>()); +} + +void WebLayerTreeViewImpl::setViewportSize( + const blink::WebSize& device_viewport_size) { + layer_tree_host_->SetViewportSize(device_viewport_size); +} + +blink::WebSize WebLayerTreeViewImpl::deviceViewportSize() const { + return layer_tree_host_->device_viewport_size(); +} + +void WebLayerTreeViewImpl::setDeviceScaleFactor(float device_scale_factor) { + layer_tree_host_->SetDeviceScaleFactor(device_scale_factor); +} + +float WebLayerTreeViewImpl::deviceScaleFactor() const { + return layer_tree_host_->device_scale_factor(); +} + +void WebLayerTreeViewImpl::setBackgroundColor(blink::WebColor color) { + layer_tree_host_->set_background_color(color); +} + +void WebLayerTreeViewImpl::setHasTransparentBackground( + bool has_transparent_background) { + layer_tree_host_->set_has_transparent_background(has_transparent_background); +} + +void WebLayerTreeViewImpl::setVisible(bool visible) { + layer_tree_host_->SetVisible(visible); +} + +void WebLayerTreeViewImpl::setPageScaleFactorAndLimits(float page_scale_factor, + float minimum, + float maximum) { + layer_tree_host_->SetPageScaleFactorAndLimits( + page_scale_factor, minimum, maximum); +} + +void WebLayerTreeViewImpl::registerForAnimations(blink::WebLayer* layer) { + cc::Layer* cc_layer = static_cast<cc_blink::WebLayerImpl*>(layer)->layer(); + cc_layer->layer_animation_controller()->SetAnimationRegistrar( + layer_tree_host_->animation_registrar()); +} + +void WebLayerTreeViewImpl::registerViewportLayers( + const blink::WebLayer* overscrollElasticityLayer, + const blink::WebLayer* pageScaleLayer, + const blink::WebLayer* innerViewportScrollLayer, + const blink::WebLayer* outerViewportScrollLayer) { + layer_tree_host_->RegisterViewportLayers( + // The scroll elasticity layer will only exist when using pinch virtual + // viewports. + overscrollElasticityLayer + ? static_cast<const cc_blink::WebLayerImpl*>( + overscrollElasticityLayer)->layer() + : NULL, + static_cast<const cc_blink::WebLayerImpl*>(pageScaleLayer)->layer(), + static_cast<const cc_blink::WebLayerImpl*>(innerViewportScrollLayer) + ->layer(), + // The outer viewport layer will only exist when using pinch virtual + // viewports. + outerViewportScrollLayer + ? static_cast<const cc_blink::WebLayerImpl*>(outerViewportScrollLayer) + ->layer() + : NULL); +} + +void WebLayerTreeViewImpl::clearViewportLayers() { + layer_tree_host_->RegisterViewportLayers(scoped_refptr<cc::Layer>(), + scoped_refptr<cc::Layer>(), + scoped_refptr<cc::Layer>(), + scoped_refptr<cc::Layer>()); +} + +void WebLayerTreeViewImpl::startPageScaleAnimation( + const blink::WebPoint& destination, + bool use_anchor, + float new_page_scale, + double duration_sec) { + base::TimeDelta duration = base::TimeDelta::FromMicroseconds( + duration_sec * base::Time::kMicrosecondsPerSecond); + layer_tree_host_->StartPageScaleAnimation( + gfx::Vector2d(destination.x, destination.y), + use_anchor, + new_page_scale, + duration); +} + +void WebLayerTreeViewImpl::setNeedsAnimate() { + layer_tree_host_->SetNeedsAnimate(); +} + +bool WebLayerTreeViewImpl::commitRequested() const { + return layer_tree_host_->CommitRequested(); +} + +void WebLayerTreeViewImpl::finishAllRendering() { + layer_tree_host_->FinishAllRendering(); +} + +void WebLayerTreeViewImpl::DidCreateSurface(cc::SurfaceId id) { + main_thread_compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&WebLayerTreeViewImpl::DidCreateSurfaceOnMainThread, + main_thread_bound_weak_ptr_, + id)); +} + +void WebLayerTreeViewImpl::DidCreateSurfaceOnMainThread(cc::SurfaceId id) { + view_->SetSurfaceId(mojo::SurfaceId::From(id)); +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_layer_tree_view_impl.h b/components/html_viewer/web_layer_tree_view_impl.h new file mode 100644 index 0000000..b2c352a --- /dev/null +++ b/components/html_viewer/web_layer_tree_view_impl.h @@ -0,0 +1,136 @@ +// 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_WEB_LAYER_TREE_VIEW_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_LAYER_TREE_VIEW_IMPL_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "cc/trees/layer_tree_host_client.h" +#include "mojo/cc/output_surface_mojo.h" +#include "third_party/WebKit/public/platform/WebLayerTreeView.h" +#include "third_party/mojo_services/src/gpu/public/interfaces/gpu.mojom.h" +#include "third_party/mojo_services/src/surfaces/public/interfaces/surfaces.mojom.h" + +namespace base { +class MessageLoopProxy; +} + +namespace blink { +class WebWidget; +} + +namespace cc { +class LayerTreeHost; +} + +namespace mojo { +class View; +} + +namespace html_viewer { + +class WebLayerTreeViewImpl : public blink::WebLayerTreeView, + public cc::LayerTreeHostClient, + public mojo::OutputSurfaceMojoClient { + public: + WebLayerTreeViewImpl( + scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy, + mojo::SurfacePtr surface, + mojo::GpuPtr gpu_service); + ~WebLayerTreeViewImpl() override; + + void set_widget(blink::WebWidget* widget) { widget_ = widget; } + void set_view(mojo::View* view) { view_ = view; } + + // cc::LayerTreeHostClient implementation. + void WillBeginMainFrame() override; + void DidBeginMainFrame() override; + void BeginMainFrame(const cc::BeginFrameArgs& args) override; + void BeginMainFrameNotExpectedSoon() override; + void Layout() override; + void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, + const gfx::Vector2dF& outer_delta, + const gfx::Vector2dF& elastic_overscroll_delta, + float page_scale, + float top_controls_delta) override; + void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta, + float page_scale, + float top_controls_delta) override; + void RequestNewOutputSurface() override; + void DidFailToInitializeOutputSurface() override; + void DidInitializeOutputSurface() override; + void WillCommit() override; + void DidCommit() override; + void DidCommitAndDrawFrame() override; + void DidCompleteSwapBuffers() override; + void DidCompletePageScaleAnimation() override {} + void RateLimitSharedMainThreadContext() override {} + + // blink::WebLayerTreeView implementation. + virtual void setRootLayer(const blink::WebLayer& layer); + virtual void clearRootLayer(); + virtual void setViewportSize(const blink::WebSize& device_viewport_size); + virtual blink::WebSize deviceViewportSize() const; + virtual void setDeviceScaleFactor(float); + virtual float deviceScaleFactor() const; + virtual void setBackgroundColor(blink::WebColor color); + virtual void setHasTransparentBackground(bool has_transparent_background); + virtual void setVisible(bool visible); + virtual void setPageScaleFactorAndLimits(float page_scale_factor, + float minimum, + float maximum); + virtual void startPageScaleAnimation(const blink::WebPoint& destination, + bool use_anchor, + float new_page_scale, + double duration_sec); + virtual void heuristicsForGpuRasterizationUpdated(bool matches_heuristic) {} + virtual void setNeedsAnimate(); + virtual bool commitRequested() const; + virtual void didStopFlinging() {} + virtual void compositeAndReadbackAsync( + blink::WebCompositeAndReadbackAsyncCallback* callback) {} + virtual void finishAllRendering(); + virtual void setDeferCommits(bool defer_commits) {} + virtual void registerForAnimations(blink::WebLayer* layer); + virtual void registerViewportLayers( + const blink::WebLayer* overscrollElasticityLayer, + const blink::WebLayer* pageScaleLayerLayer, + const blink::WebLayer* innerViewportScrollLayer, + const blink::WebLayer* outerViewportScrollLayer); + virtual void clearViewportLayers(); + virtual void registerSelection(const blink::WebSelectionBound& start, + const blink::WebSelectionBound& end) {} + virtual void clearSelection() {} + virtual void setShowFPSCounter(bool) {} + virtual void setShowPaintRects(bool) {} + virtual void setShowDebugBorders(bool) {} + virtual void setContinuousPaintingEnabled(bool) {} + virtual void setShowScrollBottleneckRects(bool) {} + + // OutputSurfaceMojoClient implementation. + void DidCreateSurface(cc::SurfaceId id) override; + + private: + void DidCreateSurfaceOnMainThread(cc::SurfaceId id); + + // widget_ and view_ will outlive us. + blink::WebWidget* widget_; + mojo::View* view_; + scoped_ptr<cc::LayerTreeHost> layer_tree_host_; + scoped_ptr<cc::OutputSurface> output_surface_; + scoped_refptr<base::SingleThreadTaskRunner> + main_thread_compositor_task_runner_; + base::WeakPtr<WebLayerTreeViewImpl> main_thread_bound_weak_ptr_; + + base::WeakPtrFactory<WebLayerTreeViewImpl> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(WebLayerTreeViewImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_LAYER_TREE_VIEW_IMPL_H_ diff --git a/components/html_viewer/web_media_player_factory.cc b/components/html_viewer/web_media_player_factory.cc new file mode 100644 index 0000000..0de85f3 --- /dev/null +++ b/components/html_viewer/web_media_player_factory.cc @@ -0,0 +1,137 @@ +// 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/web_media_player_factory.h" + +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "base/threading/thread.h" +#include "media/audio/audio_manager.h" +#include "media/audio/audio_manager_base.h" +#include "media/audio/audio_output_stream_sink.h" +#include "media/base/audio_hardware_config.h" +#include "media/base/media.h" +#include "media/base/media_log.h" +#include "media/blink/webmediaplayer_impl.h" +#include "media/blink/webmediaplayer_params.h" +#include "media/cdm/default_cdm_factory.h" +#include "media/mojo/interfaces/media_renderer.mojom.h" +#include "media/mojo/services/mojo_renderer_factory.h" +#include "media/renderers/default_renderer_factory.h" +#include "media/renderers/gpu_video_accelerator_factories.h" +#include "third_party/mojo/src/mojo/public/cpp/application/connect.h" +#include "third_party/mojo/src/mojo/public/interfaces/application/shell.mojom.h" + +using mojo::ServiceProviderPtr; + +namespace html_viewer { + +#if !defined(OS_ANDROID) +namespace { + +class RendererServiceProvider + : public media::MojoRendererFactory::ServiceProvider { + public: + explicit RendererServiceProvider(ServiceProviderPtr service_provider_ptr) + : service_provider_ptr_(service_provider_ptr.Pass()) {} + ~RendererServiceProvider() final {} + + void ConnectToService( + mojo::InterfacePtr<mojo::MediaRenderer>* media_renderer_ptr) final { + mojo::ConnectToService(service_provider_ptr_.get(), media_renderer_ptr); + } + + private: + ServiceProviderPtr service_provider_ptr_; + + DISALLOW_COPY_AND_ASSIGN(RendererServiceProvider); +}; + +} // namespace +#endif + +WebMediaPlayerFactory::WebMediaPlayerFactory( + const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner, + bool enable_mojo_media_renderer) + : compositor_task_runner_(compositor_task_runner), + enable_mojo_media_renderer_(enable_mojo_media_renderer), + media_thread_("Media"), + audio_manager_(media::AudioManager::Create(&fake_audio_log_factory_)), + audio_hardware_config_( + audio_manager_->GetInputStreamParameters( + media::AudioManagerBase::kDefaultDeviceId), + audio_manager_->GetDefaultOutputStreamParameters()) { + + if (!media::IsMediaLibraryInitialized()) { + base::FilePath module_dir; + CHECK(PathService::Get(base::DIR_EXE, &module_dir)); + CHECK(media::InitializeMediaLibrary(module_dir)); + } +} + +WebMediaPlayerFactory::~WebMediaPlayerFactory() { +} + +blink::WebMediaPlayer* WebMediaPlayerFactory::CreateMediaPlayer( + blink::WebLocalFrame* frame, + const blink::WebURL& url, + blink::WebMediaPlayerClient* client, + media::MediaPermission* media_permission, + media::CdmFactory* cdm_factory, + blink::WebContentDecryptionModule* initial_cdm, + mojo::Shell* shell) { +#if defined(OS_ANDROID) + return nullptr; +#else + scoped_refptr<media::MediaLog> media_log(new media::MediaLog()); + scoped_ptr<media::RendererFactory> media_renderer_factory; + + if (enable_mojo_media_renderer_) { + ServiceProviderPtr media_renderer_service_provider; + shell->ConnectToApplication( + "mojo:media", GetProxy(&media_renderer_service_provider), nullptr); + media_renderer_factory.reset(new media::MojoRendererFactory(make_scoped_ptr( + new RendererServiceProvider(media_renderer_service_provider.Pass())))); + } else { + media_renderer_factory.reset( + new media::DefaultRendererFactory(media_log, + nullptr, // No GPU factory. + GetAudioHardwareConfig())); + } + + media::WebMediaPlayerParams params( + media::WebMediaPlayerParams::DeferLoadCB(), CreateAudioRendererSink(), + media_log, GetMediaThreadTaskRunner(), compositor_task_runner_, + media::WebMediaPlayerParams::Context3DCB(), media_permission, + initial_cdm); + base::WeakPtr<media::WebMediaPlayerDelegate> delegate; + + return new media::WebMediaPlayerImpl(frame, client, delegate, + media_renderer_factory.Pass(), + cdm_factory, params); +#endif +} + +const media::AudioHardwareConfig& +WebMediaPlayerFactory::GetAudioHardwareConfig() { + return audio_hardware_config_; +} + +scoped_refptr<media::AudioRendererSink> +WebMediaPlayerFactory::CreateAudioRendererSink() { + // TODO(dalecurtis): Replace this with an interface to an actual mojo service; + // the AudioOutputStreamSink will not work in sandboxed processes. + return new media::AudioOutputStreamSink(); +} + +scoped_refptr<base::SingleThreadTaskRunner> +WebMediaPlayerFactory::GetMediaThreadTaskRunner() { + if (!media_thread_.IsRunning()) + media_thread_.Start(); + + return media_thread_.message_loop_proxy(); +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_media_player_factory.h b/components/html_viewer/web_media_player_factory.h new file mode 100644 index 0000000..360a696 --- /dev/null +++ b/components/html_viewer/web_media_player_factory.h @@ -0,0 +1,76 @@ +// 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_WEB_MEDIA_PLAYER_FACTORY_H_ +#define COMPONENTS_HTML_VIEWER_WEB_MEDIA_PLAYER_FACTORY_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/thread.h" +#include "media/audio/fake_audio_log_factory.h" +#include "media/base/audio_hardware_config.h" + +namespace base { +class SingleThreadTaskRunner; +} + +namespace blink { +class WebContentDecryptionModule; +class WebMediaPlayer; +class WebLocalFrame; +class WebURL; +class WebMediaPlayerClient; +} + +namespace media { +class AudioManager; +class AudioRendererSink; +class CdmFactory; +class MediaPermission; +} + +namespace mojo { +class Shell; +} + +namespace html_viewer { + +// Helper class used to create blink::WebMediaPlayer objects. +// This class stores the "global state" shared across all WebMediaPlayer +// instances. +class WebMediaPlayerFactory { + public: + explicit WebMediaPlayerFactory(const scoped_refptr< + base::SingleThreadTaskRunner>& compositor_task_runner, + bool enable_mojo_media_renderer); + ~WebMediaPlayerFactory(); + + blink::WebMediaPlayer* CreateMediaPlayer( + blink::WebLocalFrame* frame, + const blink::WebURL& url, + blink::WebMediaPlayerClient* client, + media::MediaPermission* media_permission, + media::CdmFactory* cdm_factory, + blink::WebContentDecryptionModule* initial_cdm, + mojo::Shell* shell); + + private: + const media::AudioHardwareConfig& GetAudioHardwareConfig(); + scoped_refptr<media::AudioRendererSink> CreateAudioRendererSink(); + scoped_refptr<base::SingleThreadTaskRunner> GetMediaThreadTaskRunner(); + + scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_; + const bool enable_mojo_media_renderer_; + base::Thread media_thread_; + media::FakeAudioLogFactory fake_audio_log_factory_; + scoped_ptr<media::AudioManager> audio_manager_; + media::AudioHardwareConfig audio_hardware_config_; + + DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerFactory); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_MEDIA_PLAYER_FACTORY_H_ diff --git a/components/html_viewer/web_message_port_channel_impl.cc b/components/html_viewer/web_message_port_channel_impl.cc new file mode 100644 index 0000000..45e75fc --- /dev/null +++ b/components/html_viewer/web_message_port_channel_impl.cc @@ -0,0 +1,132 @@ +// Copyright 2015 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/web_message_port_channel_impl.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/strings/string16.h" +#include "third_party/WebKit/public/platform/WebMessagePortChannelClient.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h" + +using blink::WebMessagePortChannel; +using blink::WebMessagePortChannelArray; +using blink::WebMessagePortChannelClient; +using blink::WebString; + +namespace html_viewer { + +void WebMessagePortChannelImpl::CreatePair( + blink::WebMessagePortChannel** channel1, + blink::WebMessagePortChannel** channel2) { + mojo::ScopedMessagePipeHandle pipe1; + mojo::ScopedMessagePipeHandle pipe2; + MojoResult result = mojo::CreateMessagePipe(nullptr, &pipe1, &pipe2); + if (result != MOJO_RESULT_OK) { + NOTREACHED(); + return; + } + + *channel1 = new WebMessagePortChannelImpl(pipe1.Pass());; + *channel2 = new WebMessagePortChannelImpl(pipe2.Pass()); +} + +WebMessagePortChannelImpl::WebMessagePortChannelImpl( + mojo::ScopedMessagePipeHandle pipe) + : client_(nullptr), pipe_(pipe.Pass()) { + WaitForNextMessage(); +} + +WebMessagePortChannelImpl::~WebMessagePortChannelImpl() { +} + +void WebMessagePortChannelImpl::setClient(WebMessagePortChannelClient* client) { + client_ = client; +} + +void WebMessagePortChannelImpl::destroy() { + setClient(nullptr); + delete this; +} + +void WebMessagePortChannelImpl::postMessage( + const WebString& message_as_string, + WebMessagePortChannelArray* channels) { + base::string16 string = message_as_string; + + std::vector<MojoHandle> handles; + if (channels) { + for (size_t i = 0; i < channels->size(); ++i) { + WebMessagePortChannelImpl* channel = + static_cast<WebMessagePortChannelImpl*>((*channels)[i]); + handles.push_back(channel->pipe_.release().value()); + channel->handle_watcher_.Stop(); + } + delete channels; + } + + uint32_t num_handles = static_cast<uint32_t>(handles.size()); + MojoHandle* handles_ptr = handles.empty() ? nullptr : &handles[0]; + + MojoResult result = MojoWriteMessage( + pipe_.get().value(), string.c_str(), + static_cast<uint32_t>(string.length() * sizeof(base::char16)), + handles_ptr, num_handles, MOJO_WRITE_MESSAGE_FLAG_NONE); + DCHECK_EQ(MOJO_RESULT_OK, result); +} + +bool WebMessagePortChannelImpl::tryGetMessage( + WebString* message, + WebMessagePortChannelArray& channels) { + uint32_t num_bytes = 0; + uint32_t num_handles = 0; + MojoResult result = MojoReadMessage( + pipe_.get().value(), nullptr, &num_bytes, nullptr, &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + if (result != MOJO_RESULT_RESOURCE_EXHAUSTED) + return false; + + base::string16 message16; + CHECK(num_bytes % sizeof(base::char16) == 0); + message16.resize(num_bytes / sizeof(base::char16)); + std::vector<MojoHandle> handles; + handles.resize(num_handles); + + MojoHandle* handles_ptr = handles.empty() ? nullptr : &handles[0]; + result = MojoReadMessage( + pipe_.get().value(), &message16[0], &num_bytes, handles_ptr, &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + if (result != MOJO_RESULT_OK) { + NOTREACHED(); + return false; + } + + *message = message16; + WebMessagePortChannelArray ports(handles.size()); + for (size_t i = 0; i < handles.size(); ++i) { + mojo::MessagePipeHandle mph(handles[i]); + mojo::ScopedMessagePipeHandle handle(mph); + ports[i] = new WebMessagePortChannelImpl(handle.Pass()); + } + channels = ports; + return true; +} + +void WebMessagePortChannelImpl::WaitForNextMessage() { + handle_watcher_.Start( + pipe_.get(), + MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, + base::Bind(&WebMessagePortChannelImpl::OnMessageAvailable, + base::Unretained(this))); +} + +void WebMessagePortChannelImpl::OnMessageAvailable(MojoResult result) { + DCHECK_EQ(MOJO_RESULT_OK, result); + client_->messageAvailable(); + WaitForNextMessage(); +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_message_port_channel_impl.h b/components/html_viewer/web_message_port_channel_impl.h new file mode 100644 index 0000000..8c723bc --- /dev/null +++ b/components/html_viewer/web_message_port_channel_impl.h @@ -0,0 +1,45 @@ +// Copyright 2015 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_WEB_MESSAGE_PORT_CHANNEL_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_MESSAGE_PORT_CHANNEL_IMPL_H_ + +#include "base/basictypes.h" +#include "mojo/common/handle_watcher.h" +#include "third_party/WebKit/public/platform/WebMessagePortChannel.h" +#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h" + +namespace html_viewer { + +class WebMessagePortChannelImpl : public blink::WebMessagePortChannel { + public: + static void CreatePair( + blink::WebMessagePortChannel** channel1, + blink::WebMessagePortChannel** channel2); + + private: + explicit WebMessagePortChannelImpl(mojo::ScopedMessagePipeHandle pipe); + virtual ~WebMessagePortChannelImpl(); + + // blink::WebMessagePortChannel implementation. + virtual void setClient(blink::WebMessagePortChannelClient* client); + virtual void destroy(); + virtual void postMessage(const blink::WebString& message, + blink::WebMessagePortChannelArray* channels); + virtual bool tryGetMessage(blink::WebString* message, + blink::WebMessagePortChannelArray& channels); + + void WaitForNextMessage(); + void OnMessageAvailable(MojoResult result); + + blink::WebMessagePortChannelClient* client_; + mojo::ScopedMessagePipeHandle pipe_; + mojo::common::HandleWatcher handle_watcher_; + + DISALLOW_COPY_AND_ASSIGN(WebMessagePortChannelImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_MESSAGE_PORT_CHANNEL_IMPL_H_ diff --git a/components/html_viewer/web_mime_registry_impl.cc b/components/html_viewer/web_mime_registry_impl.cc new file mode 100644 index 0000000..46c7c03 --- /dev/null +++ b/components/html_viewer/web_mime_registry_impl.cc @@ -0,0 +1,136 @@ +// 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/web_mime_registry_impl.h" + +#include "base/files/file_path.h" +#include "base/strings/string_util.h" +#include "base/strings/sys_string_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "media/base/key_systems.h" +#include "media/filters/stream_parser_factory.h" +#include "net/base/mime_util.h" +#include "third_party/WebKit/public/platform/WebString.h" + +namespace html_viewer { +namespace { + +std::string ToASCIIOrEmpty(const blink::WebString& string) { + return base::IsStringASCII(string) ? base::UTF16ToASCII(string) + : std::string(); +} + +} // namespace + +blink::WebMimeRegistry::SupportsType WebMimeRegistryImpl::supportsMIMEType( + const blink::WebString& mime_type) { + return net::IsSupportedMimeType(ToASCIIOrEmpty(mime_type)) ? + blink::WebMimeRegistry::IsSupported : + blink::WebMimeRegistry::IsNotSupported; +} + +blink::WebMimeRegistry::SupportsType WebMimeRegistryImpl::supportsImageMIMEType( + const blink::WebString& mime_type) { + return net::IsSupportedImageMimeType(ToASCIIOrEmpty(mime_type)) ? + blink::WebMimeRegistry::IsSupported : + blink::WebMimeRegistry::IsNotSupported; +} + +blink::WebMimeRegistry::SupportsType +WebMimeRegistryImpl::supportsImagePrefixedMIMEType( + const blink::WebString& mime_type) { + std::string ascii_mime_type = ToASCIIOrEmpty(mime_type); + return (net::IsSupportedImageMimeType(ascii_mime_type) || + (StartsWithASCII(ascii_mime_type, "image/", true) && + net::IsSupportedNonImageMimeType(ascii_mime_type))) + ? WebMimeRegistry::IsSupported + : WebMimeRegistry::IsNotSupported; +} + +blink::WebMimeRegistry::SupportsType + WebMimeRegistryImpl::supportsJavaScriptMIMEType( + const blink::WebString& mime_type) { + return net::IsSupportedJavascriptMimeType(ToASCIIOrEmpty(mime_type)) ? + blink::WebMimeRegistry::IsSupported : + blink::WebMimeRegistry::IsNotSupported; +} + +blink::WebMimeRegistry::SupportsType WebMimeRegistryImpl::supportsMediaMIMEType( + const blink::WebString& mime_type, + const blink::WebString& codecs, + const blink::WebString& key_system) { + const std::string mime_type_ascii = ToASCIIOrEmpty(mime_type); + // Not supporting the container is a flat-out no. + if (!net::IsSupportedMediaMimeType(mime_type_ascii)) + return IsNotSupported; + + // Mojo does not currently support any key systems. + if (!key_system.isEmpty()) + return IsNotSupported; + + // Check list of strict codecs to see if it is supported. + if (net::IsStrictMediaMimeType(mime_type_ascii)) { + // Check if the codecs are a perfect match. + std::vector<std::string> strict_codecs; + net::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, false); + return static_cast<WebMimeRegistry::SupportsType>( + net::IsSupportedStrictMediaMimeType(mime_type_ascii, strict_codecs)); + } + + // If we don't recognize the codec, it's possible we support it. + std::vector<std::string> parsed_codecs; + net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codecs, true); + if (!net::AreSupportedMediaCodecs(parsed_codecs)) + return MayBeSupported; + + // Otherwise we have a perfect match. + return IsSupported; +} + +bool WebMimeRegistryImpl::supportsMediaSourceMIMEType( + const blink::WebString& mime_type, + const blink::WebString& codecs) { + const std::string mime_type_ascii = ToASCIIOrEmpty(mime_type); + if (mime_type_ascii.empty()) + return false; + + std::vector<std::string> parsed_codec_ids; + net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false); + return media::StreamParserFactory::IsTypeSupported(mime_type_ascii, + parsed_codec_ids); +} + +blink::WebMimeRegistry::SupportsType + WebMimeRegistryImpl::supportsNonImageMIMEType( + const blink::WebString& mime_type) { + return net::IsSupportedNonImageMimeType(ToASCIIOrEmpty(mime_type)) ? + blink::WebMimeRegistry::IsSupported : + blink::WebMimeRegistry::IsNotSupported; +} + +blink::WebString WebMimeRegistryImpl::mimeTypeForExtension( + const blink::WebString& file_extension) { + std::string mime_type; + net::GetMimeTypeFromExtension( + base::FilePath::FromUTF16Unsafe(file_extension).value(), &mime_type); + return blink::WebString::fromUTF8(mime_type); +} + +blink::WebString WebMimeRegistryImpl::wellKnownMimeTypeForExtension( + const blink::WebString& file_extension) { + std::string mime_type; + net::GetWellKnownMimeTypeFromExtension( + base::FilePath::FromUTF16Unsafe(file_extension).value(), &mime_type); + return blink::WebString::fromUTF8(mime_type); +} + +blink::WebString WebMimeRegistryImpl::mimeTypeFromFile( + const blink::WebString& file_path) { + std::string mime_type; + net::GetMimeTypeFromFile(base::FilePath::FromUTF16Unsafe(file_path), + &mime_type); + return blink::WebString::fromUTF8(mime_type); +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_mime_registry_impl.h b/components/html_viewer/web_mime_registry_impl.h new file mode 100644 index 0000000..17f7f1b --- /dev/null +++ b/components/html_viewer/web_mime_registry_impl.h @@ -0,0 +1,44 @@ +// 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_WEB_MIME_REGISTRY_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_MIME_REGISTRY_IMPL_H_ + +#include "base/compiler_specific.h" +#include "third_party/WebKit/public/platform/WebMimeRegistry.h" + +namespace html_viewer { + +class WebMimeRegistryImpl : public blink::WebMimeRegistry { + public: + WebMimeRegistryImpl() {} + virtual ~WebMimeRegistryImpl() {} + + // WebMimeRegistry methods: + virtual blink::WebMimeRegistry::SupportsType supportsMIMEType( + const blink::WebString& mime_type); + virtual blink::WebMimeRegistry::SupportsType supportsImageMIMEType( + const blink::WebString& mime_type); + virtual blink::WebMimeRegistry::SupportsType supportsImagePrefixedMIMEType( + const blink::WebString& mime_type); + virtual blink::WebMimeRegistry::SupportsType supportsJavaScriptMIMEType( + const blink::WebString& mime_type); + virtual blink::WebMimeRegistry::SupportsType supportsMediaMIMEType( + const blink::WebString& mime_type, + const blink::WebString& codecs, + const blink::WebString& key_system); + virtual bool supportsMediaSourceMIMEType(const blink::WebString& mime_type, + const blink::WebString& codecs); + virtual blink::WebMimeRegistry::SupportsType supportsNonImageMIMEType( + const blink::WebString& mime_type); + virtual blink::WebString mimeTypeForExtension( + const blink::WebString& extension); + virtual blink::WebString wellKnownMimeTypeForExtension( + const blink::WebString& extension); + virtual blink::WebString mimeTypeFromFile(const blink::WebString& path); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_MIME_REGISTRY_IMPL_H_ diff --git a/components/html_viewer/web_notification_manager_impl.cc b/components/html_viewer/web_notification_manager_impl.cc new file mode 100644 index 0000000..c597ec2 --- /dev/null +++ b/components/html_viewer/web_notification_manager_impl.cc @@ -0,0 +1,63 @@ +// Copyright 2015 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/web_notification_manager_impl.h" + +#include "base/logging.h" + +namespace html_viewer { + +WebNotificationManagerImpl::WebNotificationManagerImpl() {} + +WebNotificationManagerImpl::~WebNotificationManagerImpl() {} + +void WebNotificationManagerImpl::show(const blink::WebSerializedOrigin&, + const blink::WebNotificationData&, + blink::WebNotificationDelegate*) { + NOTIMPLEMENTED(); +} + +void WebNotificationManagerImpl::showPersistent( + const blink::WebSerializedOrigin&, + const blink::WebNotificationData&, + blink::WebServiceWorkerRegistration*, + blink::WebNotificationShowCallbacks*) { + NOTIMPLEMENTED(); +} + +void WebNotificationManagerImpl::getNotifications( + const blink::WebString& filterTag, + blink::WebServiceWorkerRegistration*, + blink::WebNotificationGetCallbacks*) { + NOTIMPLEMENTED(); +} + +void WebNotificationManagerImpl::close(blink::WebNotificationDelegate*) { + NOTIMPLEMENTED(); +} + +void WebNotificationManagerImpl::closePersistent( + const blink::WebSerializedOrigin&, + int64_t persistentNotificationId) { + NOTIMPLEMENTED(); +} + +void WebNotificationManagerImpl::closePersistent( + const blink::WebSerializedOrigin&, + const blink::WebString& persistentNotificationId) { + NOTIMPLEMENTED(); +} + +void WebNotificationManagerImpl::notifyDelegateDestroyed( + blink::WebNotificationDelegate*) { + NOTIMPLEMENTED(); +} + +blink::WebNotificationPermission WebNotificationManagerImpl::checkPermission( + const blink::WebSerializedOrigin&) { + NOTIMPLEMENTED(); + return blink::WebNotificationPermission(); +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_notification_manager_impl.h b/components/html_viewer/web_notification_manager_impl.h new file mode 100644 index 0000000..1110aca --- /dev/null +++ b/components/html_viewer/web_notification_manager_impl.h @@ -0,0 +1,46 @@ +// Copyright 2015 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_WEB_NOTIFICATION_MANAGER_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_NOTIFICATION_MANAGER_IMPL_H_ + +#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationManager.h" + +namespace html_viewer { + +// TODO(erg): This class is currently a stub; blink expects this object to +// exist, and several websites will trigger notifications these days. +class WebNotificationManagerImpl : public blink::WebNotificationManager { + public: + WebNotificationManagerImpl(); + virtual ~WebNotificationManagerImpl(); + + // blink::WebNotificationManager methods: + virtual void show(const blink::WebSerializedOrigin&, + const blink::WebNotificationData&, + blink::WebNotificationDelegate*); + virtual void showPersistent(const blink::WebSerializedOrigin&, + const blink::WebNotificationData&, + blink::WebServiceWorkerRegistration*, + blink::WebNotificationShowCallbacks*); + virtual void getNotifications(const blink::WebString& filterTag, + blink::WebServiceWorkerRegistration*, + blink::WebNotificationGetCallbacks*); + virtual void close(blink::WebNotificationDelegate*); + virtual void closePersistent(const blink::WebSerializedOrigin&, + int64_t persistentNotificationId); + virtual void closePersistent( + const blink::WebSerializedOrigin&, + const blink::WebString& persistentNotificationId); + virtual void notifyDelegateDestroyed(blink::WebNotificationDelegate*); + virtual blink::WebNotificationPermission checkPermission( + const blink::WebSerializedOrigin&); + + private: + DISALLOW_COPY_AND_ASSIGN(WebNotificationManagerImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_NOTIFICATION_MANAGER_IMPL_H_ diff --git a/components/html_viewer/web_scheduler_impl.cc b/components/html_viewer/web_scheduler_impl.cc new file mode 100644 index 0000000..7f1ada5 --- /dev/null +++ b/components/html_viewer/web_scheduler_impl.cc @@ -0,0 +1,67 @@ +// Copyright 2015 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. + +// An implementation of WebThread in terms of base::MessageLoop and +// base::Thread + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/tracked_objects.h" +#include "components/html_viewer/web_scheduler_impl.h" + +namespace html_viewer { + +WebSchedulerImpl::WebSchedulerImpl( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : task_runner_(task_runner) { +} + +WebSchedulerImpl::~WebSchedulerImpl() { +} + +void WebSchedulerImpl::postIdleTask(const blink::WebTraceLocation& web_location, + blink::WebThread::IdleTask* task) { + scoped_ptr<blink::WebThread::IdleTask> scoped_task(task); + tracked_objects::Location location(web_location.functionName(), + web_location.fileName(), -1, nullptr); + task_runner_->PostTask(location, base::Bind(&WebSchedulerImpl::RunIdleTask, + base::Passed(&scoped_task))); +} + +void WebSchedulerImpl::postLoadingTask( + const blink::WebTraceLocation& web_location, + blink::WebThread::Task* task) { + scoped_ptr<blink::WebThread::Task> scoped_task(task); + tracked_objects::Location location(web_location.functionName(), + web_location.fileName(), -1, nullptr); + task_runner_->PostTask(location, base::Bind(&WebSchedulerImpl::RunTask, + base::Passed(&scoped_task))); +} + +void WebSchedulerImpl::postTimerTask( + const blink::WebTraceLocation& web_location, + blink::WebThread::Task* task, + long long delayMs) { + scoped_ptr<blink::WebThread::Task> scoped_task(task); + tracked_objects::Location location(web_location.functionName(), + web_location.fileName(), -1, nullptr); + task_runner_->PostDelayedTask( + location, + base::Bind(&WebSchedulerImpl::RunTask, base::Passed(&scoped_task)), + base::TimeDelta::FromMilliseconds(delayMs)); +} + +// static +void WebSchedulerImpl::RunIdleTask( + scoped_ptr<blink::WebThread::IdleTask> task) { + // TODO(davemoore) Implement idle scheduling. + task->run(0); +} + +// static +void WebSchedulerImpl::RunTask(scoped_ptr<blink::WebThread::Task> task) { + task->run(); +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_scheduler_impl.h b/components/html_viewer/web_scheduler_impl.h new file mode 100644 index 0000000..e0d754f --- /dev/null +++ b/components/html_viewer/web_scheduler_impl.h @@ -0,0 +1,40 @@ +// Copyright 2015 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_WEB_SCHEDULER_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_SCHEDULER_IMPL_H_ + +#include "third_party/WebKit/public/platform/WebScheduler.h" +#include "third_party/WebKit/public/platform/WebThread.h" +#include "third_party/WebKit/public/platform/WebTraceLocation.h" + +namespace html_viewer { + +class WebSchedulerImpl : public blink::WebScheduler { + public: + explicit WebSchedulerImpl( + scoped_refptr<base::SingleThreadTaskRunner> task_runner); + virtual ~WebSchedulerImpl(); + + private: + // blink::WebScheduler overrides. + virtual void postIdleTask(const blink::WebTraceLocation& location, + blink::WebThread::IdleTask* task); + virtual void postLoadingTask(const blink::WebTraceLocation& location, + blink::WebThread::Task* task); + virtual void postTimerTask(const blink::WebTraceLocation& location, + blink::WebThread::Task* task, + long long delayMs); + + static void RunIdleTask(scoped_ptr<blink::WebThread::IdleTask> task); + static void RunTask(scoped_ptr<blink::WebThread::Task> task); + + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + DISALLOW_COPY_AND_ASSIGN(WebSchedulerImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_SCHEDULER_IMPL_H_ diff --git a/components/html_viewer/web_socket_handle_impl.cc b/components/html_viewer/web_socket_handle_impl.cc new file mode 100644 index 0000000..59d9160 --- /dev/null +++ b/components/html_viewer/web_socket_handle_impl.cc @@ -0,0 +1,219 @@ +// 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/web_socket_handle_impl.h" + +#include <vector> + +#include "base/bind.h" +#include "base/macros.h" +#include "base/memory/scoped_vector.h" +#include "components/html_viewer/blink_basic_type_converters.h" +#include "mojo/services/network/public/cpp/web_socket_read_queue.h" +#include "mojo/services/network/public/cpp/web_socket_write_queue.h" +#include "mojo/services/network/public/interfaces/network_service.mojom.h" +#include "third_party/WebKit/public/platform/WebSerializedOrigin.h" +#include "third_party/WebKit/public/platform/WebSocketHandleClient.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/platform/WebVector.h" + +using blink::WebSerializedOrigin; +using blink::WebSocketHandle; +using blink::WebSocketHandleClient; +using blink::WebString; +using blink::WebURL; +using blink::WebVector; + +using mojo::ConvertTo; +using mojo::String; +using mojo::WebSocket; +using mojo::WebSocketReadQueue; + +namespace mojo { + +template<> +struct TypeConverter<WebSocket::MessageType, WebSocketHandle::MessageType> { + static WebSocket::MessageType Convert(WebSocketHandle::MessageType type) { + DCHECK(type == WebSocketHandle::MessageTypeContinuation || + type == WebSocketHandle::MessageTypeText || + type == WebSocketHandle::MessageTypeBinary); + typedef WebSocket::MessageType MessageType; + COMPILE_ASSERT( + static_cast<MessageType>(WebSocketHandle::MessageTypeContinuation) == + WebSocket::MESSAGE_TYPE_CONTINUATION, + enum_values_must_match_for_message_type); + COMPILE_ASSERT( + static_cast<MessageType>(WebSocketHandle::MessageTypeText) == + WebSocket::MESSAGE_TYPE_TEXT, + enum_values_must_match_for_message_type); + COMPILE_ASSERT( + static_cast<MessageType>(WebSocketHandle::MessageTypeBinary) == + WebSocket::MESSAGE_TYPE_BINARY, + enum_values_must_match_for_message_type); + return static_cast<WebSocket::MessageType>(type); + } +}; + +template<> +struct TypeConverter<WebSocketHandle::MessageType, WebSocket::MessageType> { + static WebSocketHandle::MessageType Convert(WebSocket::MessageType type) { + DCHECK(type == WebSocket::MESSAGE_TYPE_CONTINUATION || + type == WebSocket::MESSAGE_TYPE_TEXT || + type == WebSocket::MESSAGE_TYPE_BINARY); + return static_cast<WebSocketHandle::MessageType>(type); + } +}; + +} // namespace mojo + +namespace html_viewer { + +// This class forms a bridge from the mojo WebSocketClient interface and the +// Blink WebSocketHandleClient interface. +class WebSocketClientImpl : public mojo::InterfaceImpl<mojo::WebSocketClient> { + public: + explicit WebSocketClientImpl(WebSocketHandleImpl* handle, + blink::WebSocketHandleClient* client) + : handle_(handle), client_(client) {} + ~WebSocketClientImpl() override {} + + private: + // WebSocketClient methods: + void DidConnect(const String& selected_subprotocol, + const String& extensions, + mojo::ScopedDataPipeConsumerHandle receive_stream) override { + blink::WebSocketHandleClient* client = client_; + WebSocketHandleImpl* handle = handle_; + receive_stream_ = receive_stream.Pass(); + read_queue_.reset(new WebSocketReadQueue(receive_stream_.get())); + client->didConnect(handle, + selected_subprotocol.To<WebString>(), + extensions.To<WebString>()); + // |handle| can be deleted here. + } + + void DidReceiveData(bool fin, + WebSocket::MessageType type, + uint32_t num_bytes) override { + read_queue_->Read(num_bytes, + base::Bind(&WebSocketClientImpl::DidReadFromReceiveStream, + base::Unretained(this), + fin, type, num_bytes)); + } + + void DidReceiveFlowControl(int64_t quota) override { + client_->didReceiveFlowControl(handle_, quota); + // |handle| can be deleted here. + } + + void DidFail(const String& message) override { + blink::WebSocketHandleClient* client = client_; + WebSocketHandleImpl* handle = handle_; + handle->Disconnect(); // deletes |this| + client->didFail(handle, message.To<WebString>()); + // |handle| can be deleted here. + } + + void DidClose(bool was_clean, uint16_t code, const String& reason) override { + blink::WebSocketHandleClient* client = client_; + WebSocketHandleImpl* handle = handle_; + handle->Disconnect(); // deletes |this| + client->didClose(handle, was_clean, code, reason.To<WebString>()); + // |handle| can be deleted here. + } + + void DidReadFromReceiveStream(bool fin, + WebSocket::MessageType type, + uint32_t num_bytes, + const char* data) { + client_->didReceiveData(handle_, + fin, + ConvertTo<WebSocketHandle::MessageType>(type), + data, + num_bytes); + // |handle_| can be deleted here. + } + + // |handle_| owns this object, so it is guaranteed to outlive us. + WebSocketHandleImpl* handle_; + blink::WebSocketHandleClient* client_; + mojo::ScopedDataPipeConsumerHandle receive_stream_; + scoped_ptr<WebSocketReadQueue> read_queue_; + + DISALLOW_COPY_AND_ASSIGN(WebSocketClientImpl); +}; + +WebSocketHandleImpl::WebSocketHandleImpl(mojo::NetworkService* network_service) + : did_close_(false) { + network_service->CreateWebSocket(GetProxy(&web_socket_)); +} + +WebSocketHandleImpl::~WebSocketHandleImpl() { + if (!did_close_) { + // The connection is abruptly disconnected by the renderer without + // closing handshake. + web_socket_->Close(WebSocket::kAbnormalCloseCode, String()); + } +} + +void WebSocketHandleImpl::connect(const WebURL& url, + const WebVector<WebString>& protocols, + const WebSerializedOrigin& origin, + WebSocketHandleClient* client) { + client_.reset(new WebSocketClientImpl(this, client)); + mojo::WebSocketClientPtr client_ptr; + // TODO(mpcomplete): Is this the right ownership model? Or should mojo own + // |client_|? + WeakBindToProxy(client_.get(), &client_ptr); + + mojo::DataPipe data_pipe; + send_stream_ = data_pipe.producer_handle.Pass(); + write_queue_.reset(new mojo::WebSocketWriteQueue(send_stream_.get())); + web_socket_->Connect(url.string().utf8(), + mojo::Array<String>::From(protocols), + origin.string().utf8(), data_pipe.consumer_handle.Pass(), + client_ptr.Pass()); +} + +void WebSocketHandleImpl::send(bool fin, + WebSocketHandle::MessageType type, + const char* data, + size_t size) { + if (!client_) + return; + + uint32_t size32 = static_cast<uint32_t>(size); + write_queue_->Write( + data, size32, + base::Bind(&WebSocketHandleImpl::DidWriteToSendStream, + base::Unretained(this), + fin, type, size32)); +} + +void WebSocketHandleImpl::flowControl(int64_t quota) { + if (!client_) + return; + + web_socket_->FlowControl(quota); +} + +void WebSocketHandleImpl::close(unsigned short code, const WebString& reason) { + web_socket_->Close(code, reason.utf8()); +} + +void WebSocketHandleImpl::DidWriteToSendStream( + bool fin, + WebSocketHandle::MessageType type, + uint32_t num_bytes, + const char* data) { + web_socket_->Send(fin, ConvertTo<WebSocket::MessageType>(type), num_bytes); +} + +void WebSocketHandleImpl::Disconnect() { + did_close_ = true; + client_.reset(); +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_socket_handle_impl.h b/components/html_viewer/web_socket_handle_impl.h new file mode 100644 index 0000000..0456228 --- /dev/null +++ b/components/html_viewer/web_socket_handle_impl.h @@ -0,0 +1,63 @@ +// 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_WEB_SOCKET_HANDLE_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_SOCKET_HANDLE_IMPL_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/common/handle_watcher.h" +#include "mojo/services/network/public/interfaces/web_socket.mojom.h" +#include "third_party/WebKit/public/platform/WebSocketHandle.h" + +namespace mojo { +class NetworkService; +class WebSocketWriteQueue; +} + +namespace html_viewer { + +class WebSocketClientImpl; + +// Implements WebSocketHandle by talking to the mojo WebSocket interface. +class WebSocketHandleImpl : public blink::WebSocketHandle { + public: + explicit WebSocketHandleImpl(mojo::NetworkService* network_service); + + private: + friend class WebSocketClientImpl; + + virtual ~WebSocketHandleImpl(); + + // blink::WebSocketHandle methods: + virtual void connect(const blink::WebURL& url, + const blink::WebVector<blink::WebString>& protocols, + const blink::WebSerializedOrigin& origin, + blink::WebSocketHandleClient*); + virtual void send(bool fin, MessageType, const char* data, size_t size); + virtual void flowControl(int64_t quota); + virtual void close(unsigned short code, const blink::WebString& reason); + + // Called when we finished writing to |send_stream_|. + void DidWriteToSendStream(bool fin, + WebSocketHandle::MessageType type, + uint32_t num_bytes, + const char* data); + + // Called when the socket is closed. + void Disconnect(); + + mojo::WebSocketPtr web_socket_; + scoped_ptr<WebSocketClientImpl> client_; + mojo::ScopedDataPipeProducerHandle send_stream_; + scoped_ptr<mojo::WebSocketWriteQueue> write_queue_; + // True if close() was called. + bool did_close_; + + DISALLOW_COPY_AND_ASSIGN(WebSocketHandleImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_SOCKET_HANDLE_IMPL_H_ diff --git a/components/html_viewer/web_storage_namespace_impl.cc b/components/html_viewer/web_storage_namespace_impl.cc new file mode 100644 index 0000000..f61a63f --- /dev/null +++ b/components/html_viewer/web_storage_namespace_impl.cc @@ -0,0 +1,41 @@ +// 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/web_storage_namespace_impl.h" + +#include <stdio.h> + +#include "third_party/WebKit/public/platform/WebStorageArea.h" + +namespace html_viewer { +namespace { + +class DummyWebStorageAreaImpl : public blink::WebStorageArea { + public: + unsigned length() override { return 0; } + blink::WebString key(unsigned index) override { return blink::WebString(); } + blink::WebString getItem(const blink::WebString& key) override { + return blink::WebString(); + } +}; + +} // namespace + +WebStorageNamespaceImpl::WebStorageNamespaceImpl() { +} + +WebStorageNamespaceImpl::~WebStorageNamespaceImpl() { +} + +blink::WebStorageArea* WebStorageNamespaceImpl::createStorageArea( + const blink::WebString& origin) { + return new DummyWebStorageAreaImpl(); +} + +bool WebStorageNamespaceImpl::isSameNamespace( + const blink::WebStorageNamespace&) const { + return false; +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_storage_namespace_impl.h b/components/html_viewer/web_storage_namespace_impl.h new file mode 100644 index 0000000..1c199aa --- /dev/null +++ b/components/html_viewer/web_storage_namespace_impl.h @@ -0,0 +1,30 @@ +// 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_WEB_STORAGE_NAMESPACE_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_STORAGE_NAMESPACE_IMPL_H_ + +#include "base/macros.h" +#include "third_party/WebKit/public/platform/WebStorageNamespace.h" + +namespace html_viewer { + +class WebStorageNamespaceImpl : public blink::WebStorageNamespace { + public: + WebStorageNamespaceImpl(); + + private: + virtual ~WebStorageNamespaceImpl(); + + // blink::WebStorageNamespace methods: + virtual blink::WebStorageArea* createStorageArea( + const blink::WebString& origin); + virtual bool isSameNamespace(const blink::WebStorageNamespace&) const; + + DISALLOW_COPY_AND_ASSIGN(WebStorageNamespaceImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_STORAGE_NAMESPACE_IMPL_H_ diff --git a/components/html_viewer/web_theme_engine_impl.cc b/components/html_viewer/web_theme_engine_impl.cc new file mode 100644 index 0000000..69518ee --- /dev/null +++ b/components/html_viewer/web_theme_engine_impl.cc @@ -0,0 +1,203 @@ +// 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/web_theme_engine_impl.h" + +#include "skia/ext/platform_canvas.h" +#include "third_party/WebKit/public/platform/WebRect.h" +#include "third_party/WebKit/public/platform/WebSize.h" +#include "ui/native_theme/native_theme.h" + +using blink::WebCanvas; +using blink::WebColor; +using blink::WebRect; +using blink::WebThemeEngine; + +namespace html_viewer { +namespace { + +ui::NativeTheme::Part NativeThemePart(WebThemeEngine::Part part) { + switch (part) { + case WebThemeEngine::PartScrollbarDownArrow: + return ui::NativeTheme::kScrollbarDownArrow; + case WebThemeEngine::PartScrollbarLeftArrow: + return ui::NativeTheme::kScrollbarLeftArrow; + case WebThemeEngine::PartScrollbarRightArrow: + return ui::NativeTheme::kScrollbarRightArrow; + case WebThemeEngine::PartScrollbarUpArrow: + return ui::NativeTheme::kScrollbarUpArrow; + case WebThemeEngine::PartScrollbarHorizontalThumb: + return ui::NativeTheme::kScrollbarHorizontalThumb; + case WebThemeEngine::PartScrollbarVerticalThumb: + return ui::NativeTheme::kScrollbarVerticalThumb; + case WebThemeEngine::PartScrollbarHorizontalTrack: + return ui::NativeTheme::kScrollbarHorizontalTrack; + case WebThemeEngine::PartScrollbarVerticalTrack: + return ui::NativeTheme::kScrollbarVerticalTrack; + case WebThemeEngine::PartScrollbarCorner: + return ui::NativeTheme::kScrollbarCorner; + case WebThemeEngine::PartCheckbox: + return ui::NativeTheme::kCheckbox; + case WebThemeEngine::PartRadio: + return ui::NativeTheme::kRadio; + case WebThemeEngine::PartButton: + return ui::NativeTheme::kPushButton; + case WebThemeEngine::PartTextField: + return ui::NativeTheme::kTextField; + case WebThemeEngine::PartMenuList: + return ui::NativeTheme::kMenuList; + case WebThemeEngine::PartSliderTrack: + return ui::NativeTheme::kSliderTrack; + case WebThemeEngine::PartSliderThumb: + return ui::NativeTheme::kSliderThumb; + case WebThemeEngine::PartInnerSpinButton: + return ui::NativeTheme::kInnerSpinButton; + case WebThemeEngine::PartProgressBar: + return ui::NativeTheme::kProgressBar; + default: + return ui::NativeTheme::kScrollbarDownArrow; + } +} + +ui::NativeTheme::State NativeThemeState(WebThemeEngine::State state) { + switch (state) { + case WebThemeEngine::StateDisabled: + return ui::NativeTheme::kDisabled; + case WebThemeEngine::StateHover: + return ui::NativeTheme::kHovered; + case WebThemeEngine::StateNormal: + return ui::NativeTheme::kNormal; + case WebThemeEngine::StatePressed: + return ui::NativeTheme::kPressed; + default: + return ui::NativeTheme::kDisabled; + } +} + +void GetNativeThemeExtraParams( + WebThemeEngine::Part part, + WebThemeEngine::State state, + const WebThemeEngine::ExtraParams* extra_params, + ui::NativeTheme::ExtraParams* native_theme_extra_params) { + switch (part) { + case WebThemeEngine::PartScrollbarHorizontalTrack: + case WebThemeEngine::PartScrollbarVerticalTrack: + native_theme_extra_params->scrollbar_track.track_x = + extra_params->scrollbarTrack.trackX; + native_theme_extra_params->scrollbar_track.track_y = + extra_params->scrollbarTrack.trackY; + native_theme_extra_params->scrollbar_track.track_width = + extra_params->scrollbarTrack.trackWidth; + native_theme_extra_params->scrollbar_track.track_height = + extra_params->scrollbarTrack.trackHeight; + break; + case WebThemeEngine::PartCheckbox: + native_theme_extra_params->button.checked = extra_params->button.checked; + native_theme_extra_params->button.indeterminate = + extra_params->button.indeterminate; + break; + case WebThemeEngine::PartRadio: + native_theme_extra_params->button.checked = extra_params->button.checked; + break; + case WebThemeEngine::PartButton: + native_theme_extra_params->button.is_default = + extra_params->button.isDefault; + native_theme_extra_params->button.has_border = + extra_params->button.hasBorder; + // Native buttons have a different focus style. + native_theme_extra_params->button.is_focused = false; + native_theme_extra_params->button.background_color = + extra_params->button.backgroundColor; + break; + case WebThemeEngine::PartTextField: + native_theme_extra_params->text_field.is_text_area = + extra_params->textField.isTextArea; + native_theme_extra_params->text_field.is_listbox = + extra_params->textField.isListbox; + native_theme_extra_params->text_field.background_color = + extra_params->textField.backgroundColor; + break; + case WebThemeEngine::PartMenuList: + native_theme_extra_params->menu_list.has_border = + extra_params->menuList.hasBorder; + native_theme_extra_params->menu_list.has_border_radius = + extra_params->menuList.hasBorderRadius; + native_theme_extra_params->menu_list.arrow_x = + extra_params->menuList.arrowX; + native_theme_extra_params->menu_list.arrow_y = + extra_params->menuList.arrowY; + native_theme_extra_params->menu_list.background_color = + extra_params->menuList.backgroundColor; + break; + case WebThemeEngine::PartSliderTrack: + case WebThemeEngine::PartSliderThumb: + native_theme_extra_params->slider.vertical = + extra_params->slider.vertical; + native_theme_extra_params->slider.in_drag = extra_params->slider.inDrag; + break; + case WebThemeEngine::PartInnerSpinButton: + native_theme_extra_params->inner_spin.spin_up = + extra_params->innerSpin.spinUp; + native_theme_extra_params->inner_spin.read_only = + extra_params->innerSpin.readOnly; + break; + case WebThemeEngine::PartProgressBar: + native_theme_extra_params->progress_bar.determinate = + extra_params->progressBar.determinate; + native_theme_extra_params->progress_bar.value_rect_x = + extra_params->progressBar.valueRectX; + native_theme_extra_params->progress_bar.value_rect_y = + extra_params->progressBar.valueRectY; + native_theme_extra_params->progress_bar.value_rect_width = + extra_params->progressBar.valueRectWidth; + native_theme_extra_params->progress_bar.value_rect_height = + extra_params->progressBar.valueRectHeight; + break; + default: + break; // Parts that have no extra params get here. + } +} + +} // namespace + +blink::WebSize WebThemeEngineImpl::getSize(WebThemeEngine::Part part) { + ui::NativeTheme::ExtraParams extra; + return ui::NativeTheme::instance()->GetPartSize(NativeThemePart(part), + ui::NativeTheme::kNormal, + extra); +} + +void WebThemeEngineImpl::paint( + blink::WebCanvas* canvas, + WebThemeEngine::Part part, + WebThemeEngine::State state, + const blink::WebRect& rect, + const WebThemeEngine::ExtraParams* extra_params) { + ui::NativeTheme::ExtraParams native_theme_extra_params; + GetNativeThemeExtraParams( + part, state, extra_params, &native_theme_extra_params); + ui::NativeTheme::instance()->Paint( + canvas, + NativeThemePart(part), + NativeThemeState(state), + gfx::Rect(rect), + native_theme_extra_params); +} + +void WebThemeEngineImpl::paintStateTransition(blink::WebCanvas* canvas, + WebThemeEngine::Part part, + WebThemeEngine::State startState, + WebThemeEngine::State endState, + double progress, + const blink::WebRect& rect) { + ui::NativeTheme::instance()->PaintStateTransition( + canvas, + NativeThemePart(part), + NativeThemeState(startState), + NativeThemeState(endState), + progress, + gfx::Rect(rect)); +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_theme_engine_impl.h b/components/html_viewer/web_theme_engine_impl.h new file mode 100644 index 0000000..e146e9d --- /dev/null +++ b/components/html_viewer/web_theme_engine_impl.h @@ -0,0 +1,31 @@ +// 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_WEB_THEME_ENGINE_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_THEME_ENGINE_IMPL_H_ + +#include "third_party/WebKit/public/platform/WebThemeEngine.h" + +namespace html_viewer { + +class WebThemeEngineImpl : public blink::WebThemeEngine { + public: + // WebThemeEngine methods: + virtual blink::WebSize getSize(blink::WebThemeEngine::Part); + virtual void paint(blink::WebCanvas* canvas, + blink::WebThemeEngine::Part part, + blink::WebThemeEngine::State state, + const blink::WebRect& rect, + const blink::WebThemeEngine::ExtraParams* extra_params); + virtual void paintStateTransition(blink::WebCanvas* canvas, + blink::WebThemeEngine::Part part, + blink::WebThemeEngine::State startState, + blink::WebThemeEngine::State endState, + double progress, + const blink::WebRect& rect); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_THEME_ENGINE_IMPL_H_ diff --git a/components/html_viewer/web_thread_impl.cc b/components/html_viewer/web_thread_impl.cc new file mode 100644 index 0000000..6f3bb53 --- /dev/null +++ b/components/html_viewer/web_thread_impl.cc @@ -0,0 +1,187 @@ +// 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. + +// An implementation of WebThread in terms of base::MessageLoop and +// base::Thread + +#include "components/html_viewer/web_thread_impl.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/message_loop/message_loop.h" +#include "base/pending_task.h" +#include "base/threading/platform_thread.h" +#include "third_party/WebKit/public/platform/WebTraceLocation.h" + +namespace html_viewer { + +WebThreadBase::WebThreadBase() {} +WebThreadBase::~WebThreadBase() {} + +class WebThreadBase::TaskObserverAdapter + : public base::MessageLoop::TaskObserver { + public: + TaskObserverAdapter(WebThread::TaskObserver* observer) + : observer_(observer) {} + + void WillProcessTask(const base::PendingTask& pending_task) override { + observer_->willProcessTask(); + } + + void DidProcessTask(const base::PendingTask& pending_task) override { + observer_->didProcessTask(); + } + +private: + WebThread::TaskObserver* observer_; +}; + +void WebThreadBase::addTaskObserver(TaskObserver* observer) { + CHECK(isCurrentThread()); + std::pair<TaskObserverMap::iterator, bool> result = task_observer_map_.insert( + std::make_pair(observer, static_cast<TaskObserverAdapter*>(NULL))); + if (result.second) + result.first->second = new TaskObserverAdapter(observer); + base::MessageLoop::current()->AddTaskObserver(result.first->second); +} + +void WebThreadBase::removeTaskObserver(TaskObserver* observer) { + CHECK(isCurrentThread()); + TaskObserverMap::iterator iter = task_observer_map_.find(observer); + if (iter == task_observer_map_.end()) + return; + base::MessageLoop::current()->RemoveTaskObserver(iter->second); + delete iter->second; + task_observer_map_.erase(iter); +} + +WebThreadImpl::WebThreadImpl(const char* name) + : thread_(new base::Thread(name)), + web_scheduler_(new WebSchedulerImpl(thread_->task_runner())) { + thread_->Start(); +} + +// RunWebThreadTask takes the ownership of |task| from base::Closure and +// deletes it on the first invocation of the closure for thread-safety. +// base::Closure made from RunWebThreadTask is copyable but Closure::Run +// should be called at most only once. +// This is because WebThread::Task can contain RefPtr to a +// thread-unsafe-reference-counted object (e.g. WorkerThreadTask can contain +// RefPtr to WebKit's StringImpl), and if we don't delete |task| here, +// it causes a race condition as follows: +// [A] In task->run(), more RefPtr's to the refcounted object can be created, +// and the reference counter of the object can be modified via these +// RefPtr's (as intended) on the thread where the task is executed. +// [B] However, base::Closure still retains the ownership of WebThread::Task +// even after RunWebThreadTask is called. +// When base::Closure is deleted, WebThread::Task is deleted and the +// reference counter of the object is decreased by one, possibly from a +// different thread from [A], which is a race condition. +// Taking the ownership of |task| here by using scoped_ptr and base::Passed +// removes the reference counter modification of [B] and the race condition. +// When the closure never runs at all, the corresponding WebThread::Task is +// destructed when base::Closure is deleted (like [B]). In this case, there +// are no reference counter modification like [A] (because task->run() is not +// executed), so there are no race conditions. +// See https://crbug.com/390851 for more details. +static void RunWebThreadTask(scoped_ptr<blink::WebThread::Task> task) { + task->run(); +} + +void WebThreadImpl::postTask(const blink::WebTraceLocation& location, + Task* task) { + postDelayedTask(location, task, 0); +} + +void WebThreadImpl::postDelayedTask(const blink::WebTraceLocation& web_location, + Task* task, + long long delay_ms) { + tracked_objects::Location location(web_location.functionName(), + web_location.fileName(), -1, nullptr); + thread_->message_loop()->PostDelayedTask( + location, + base::Bind(RunWebThreadTask, base::Passed(make_scoped_ptr(task))), + base::TimeDelta::FromMilliseconds(delay_ms)); +} + +void WebThreadImpl::enterRunLoop() { + CHECK(isCurrentThread()); + CHECK(!thread_->message_loop()->is_running()); // We don't support nesting. + thread_->message_loop()->Run(); +} + +void WebThreadImpl::exitRunLoop() { + CHECK(isCurrentThread()); + CHECK(thread_->message_loop()->is_running()); + thread_->message_loop()->Quit(); +} + +blink::WebScheduler* WebThreadImpl::scheduler() const { + return web_scheduler_.get(); +} + +bool WebThreadImpl::isCurrentThread() const { + return thread_->thread_id() == base::PlatformThread::CurrentId(); +} + +blink::PlatformThreadId WebThreadImpl::threadId() const { + return thread_->thread_id(); +} + +WebThreadImpl::~WebThreadImpl() { + thread_->Stop(); +} + +WebThreadImplForMessageLoop::WebThreadImplForMessageLoop( + base::MessageLoopProxy* message_loop) + : message_loop_(message_loop), + web_scheduler_(new WebSchedulerImpl(message_loop_)) { +} + +void WebThreadImplForMessageLoop::postTask( + const blink::WebTraceLocation& location, + Task* task) { + postDelayedTask(location, task, 0); +} + +void WebThreadImplForMessageLoop::postDelayedTask( + const blink::WebTraceLocation& web_location, + Task* task, + long long delay_ms) { + tracked_objects::Location location(web_location.functionName(), + web_location.fileName(), -1, nullptr); + message_loop_->PostDelayedTask( + location, + base::Bind(RunWebThreadTask, base::Passed(make_scoped_ptr(task))), + base::TimeDelta::FromMilliseconds(delay_ms)); +} + +void WebThreadImplForMessageLoop::enterRunLoop() { + CHECK(isCurrentThread()); + // We don't support nesting. + CHECK(!base::MessageLoop::current()->is_running()); + base::MessageLoop::current()->Run(); +} + +void WebThreadImplForMessageLoop::exitRunLoop() { + CHECK(isCurrentThread()); + CHECK(base::MessageLoop::current()->is_running()); + base::MessageLoop::current()->Quit(); +} + +blink::WebScheduler* WebThreadImplForMessageLoop::scheduler() const { + return web_scheduler_.get(); +} + +bool WebThreadImplForMessageLoop::isCurrentThread() const { + return message_loop_->BelongsToCurrentThread(); +} + +blink::PlatformThreadId WebThreadImplForMessageLoop::threadId() const { + return thread_id_; +} + +WebThreadImplForMessageLoop::~WebThreadImplForMessageLoop() {} + +} // namespace html_viewer diff --git a/components/html_viewer/web_thread_impl.h b/components/html_viewer/web_thread_impl.h new file mode 100644 index 0000000..b9fc804 --- /dev/null +++ b/components/html_viewer/web_thread_impl.h @@ -0,0 +1,88 @@ +// 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_WEB_THREAD_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_THREAD_IMPL_H_ + +#include <map> + +#include "base/memory/scoped_ptr.h" +#include "base/threading/thread.h" +#include "components/html_viewer/web_scheduler_impl.h" +#include "third_party/WebKit/public/platform/WebThread.h" + +namespace html_viewer { + +class WebThreadBase : public blink::WebThread { + public: + virtual ~WebThreadBase(); + + virtual void addTaskObserver(TaskObserver* observer); + virtual void removeTaskObserver(TaskObserver* observer); + + virtual bool isCurrentThread() const = 0; + + protected: + WebThreadBase(); + + private: + class TaskObserverAdapter; + + typedef std::map<TaskObserver*, TaskObserverAdapter*> TaskObserverMap; + TaskObserverMap task_observer_map_; +}; + +class WebThreadImpl : public WebThreadBase { + public: + explicit WebThreadImpl(const char* name); + ~WebThreadImpl() override; + + virtual void postTask(const blink::WebTraceLocation& location, Task* task); + virtual void postDelayedTask(const blink::WebTraceLocation& location, + Task* task, + long long delay_ms); + + virtual void enterRunLoop(); + virtual void exitRunLoop(); + + virtual blink::WebScheduler* scheduler() const; + + base::MessageLoop* message_loop() const { return thread_->message_loop(); } + + bool isCurrentThread() const override; + virtual blink::PlatformThreadId threadId() const; + + private: + scoped_ptr<base::Thread> thread_; + scoped_ptr<WebSchedulerImpl> web_scheduler_; +}; + +class WebThreadImplForMessageLoop : public WebThreadBase { + public: + explicit WebThreadImplForMessageLoop( + base::MessageLoopProxy* message_loop); + ~WebThreadImplForMessageLoop() override; + + virtual void postTask(const blink::WebTraceLocation& location, Task* task); + virtual void postDelayedTask(const blink::WebTraceLocation& location, + Task* task, + long long delay_ms); + + virtual void enterRunLoop(); + virtual void exitRunLoop(); + + virtual blink::WebScheduler* scheduler() const; + + private: + bool isCurrentThread() const override; + virtual blink::PlatformThreadId threadId() const; + + scoped_refptr<base::MessageLoopProxy> message_loop_; + scoped_ptr<WebSchedulerImpl> web_scheduler_; + blink::PlatformThreadId thread_id_; +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_THREAD_IMPL_H_ diff --git a/components/html_viewer/web_url_loader_impl.cc b/components/html_viewer/web_url_loader_impl.cc new file mode 100644 index 0000000..b4874b2f --- /dev/null +++ b/components/html_viewer/web_url_loader_impl.cc @@ -0,0 +1,305 @@ +// 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/web_url_loader_impl.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/strings/string_util.h" +#include "base/thread_task_runner_handle.h" +#include "components/html_viewer/blink_url_request_type_converters.h" +#include "mojo/common/common_type_converters.h" +#include "mojo/common/url_type_converters.h" +#include "mojo/services/network/public/interfaces/network_service.mojom.h" +#include "net/base/net_errors.h" +#include "third_party/WebKit/public/platform/WebURLError.h" +#include "third_party/WebKit/public/platform/WebURLLoadTiming.h" +#include "third_party/WebKit/public/platform/WebURLLoaderClient.h" +#include "third_party/WebKit/public/platform/WebURLResponse.h" + +using blink::WebString; +using mojo::URLResponsePtr; + +namespace html_viewer { +namespace { + +blink::WebURLResponse::HTTPVersion StatusLineToHTTPVersion( + const mojo::String& status_line) { + if (status_line.is_null()) + return blink::WebURLResponse::HTTP_0_9; + + if (StartsWithASCII(status_line, "HTTP/1.0", true)) + return blink::WebURLResponse::HTTP_1_0; + + if (StartsWithASCII(status_line, "HTTP/1.1", true)) + return blink::WebURLResponse::HTTP_1_1; + + return blink::WebURLResponse::Unknown; +} + +blink::WebURLResponse ToWebURLResponse(const URLResponsePtr& url_response) { + blink::WebURLResponse result; + result.initialize(); + result.setURL(GURL(url_response->url)); + result.setMIMEType(blink::WebString::fromUTF8(url_response->mime_type)); + result.setTextEncodingName(blink::WebString::fromUTF8(url_response->charset)); + result.setHTTPVersion(StatusLineToHTTPVersion(url_response->status_line)); + result.setHTTPStatusCode(url_response->status_code); + result.setExpectedContentLength(-1); // Not available. + + // TODO(darin): Initialize timing properly. + blink::WebURLLoadTiming timing; + timing.initialize(); + result.setLoadTiming(timing); + + for (size_t i = 0; i < url_response->headers.size(); ++i) { + const std::string& header_line = url_response->headers[i]; + size_t first_colon = header_line.find(":"); + + if (first_colon == std::string::npos || first_colon == 0) + continue; + + std::string value; + TrimWhitespaceASCII(header_line.substr(first_colon + 1), + base::TRIM_LEADING, + &value); + result.setHTTPHeaderField( + blink::WebString::fromUTF8(header_line.substr(0, first_colon)), + blink::WebString::fromUTF8(value)); + } + + return result; +} + +} // namespace + +WebURLRequestExtraData::WebURLRequestExtraData() { +} + +WebURLRequestExtraData::~WebURLRequestExtraData() { +} + +WebURLLoaderImpl::WebURLLoaderImpl(mojo::NetworkService* network_service, + MockWebBlobRegistryImpl* web_blob_registry) + : client_(NULL), + web_blob_registry_(web_blob_registry), + referrer_policy_(blink::WebReferrerPolicyDefault), + weak_factory_(this) { + network_service->CreateURLLoader(GetProxy(&url_loader_)); +} + +WebURLLoaderImpl::~WebURLLoaderImpl() { +} + +void WebURLLoaderImpl::loadSynchronously( + const blink::WebURLRequest& request, + blink::WebURLResponse& response, + blink::WebURLError& error, + blink::WebData& data) { + NOTIMPLEMENTED(); +} + +void WebURLLoaderImpl::loadAsynchronously(const blink::WebURLRequest& request, + blink::WebURLLoaderClient* client) { + client_ = client; + url_ = request.url(); + + mojo::URLRequestPtr url_request = mojo::URLRequest::From(request); + url_request->auto_follow_redirects = false; + referrer_policy_ = request.referrerPolicy(); + GURL referrer_url( + request.httpHeaderField(WebString::fromUTF8("Referer")).latin1()); + url_request->referrer = referrer_url.spec(); + + if (request.extraData()) { + WebURLRequestExtraData* extra_data = + static_cast<WebURLRequestExtraData*>(request.extraData()); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&WebURLLoaderImpl::OnReceivedResponse, + weak_factory_.GetWeakPtr(), + request, + base::Passed(&extra_data->synthetic_response))); + return; + } + + blink::WebString uuid; + if (web_blob_registry_->GetUUIDForURL(url_, &uuid)) { + blink::WebVector<blink::WebBlobData::Item*> items; + if (web_blob_registry_->GetBlobItems(uuid, &items)) { + // The blob data exists in our service, and we don't want to create a + // data pipe just to do a funny dance where at the end, we stuff data + // from memory into data pipes so we can read back the data. + OnReceiveWebBlobData(request, items); + return; + } + } + + url_loader_->Start(url_request.Pass(), + base::Bind(&WebURLLoaderImpl::OnReceivedResponse, + weak_factory_.GetWeakPtr(), request)); +} + +void WebURLLoaderImpl::cancel() { + url_loader_.reset(); + response_body_stream_.reset(); + + URLResponsePtr failed_response(mojo::URLResponse::New()); + failed_response->url = mojo::String::From(url_); + failed_response->error = mojo::NetworkError::New(); + failed_response->error->code = net::ERR_ABORTED; + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&WebURLLoaderImpl::OnReceivedResponse, + weak_factory_.GetWeakPtr(), + blink::WebURLRequest(), + base::Passed(&failed_response))); +} + +void WebURLLoaderImpl::setDefersLoading(bool defers_loading) { + NOTIMPLEMENTED(); +} + +void WebURLLoaderImpl::OnReceivedResponse(const blink::WebURLRequest& request, + URLResponsePtr url_response) { + url_ = GURL(url_response->url); + + if (url_response->error) { + OnReceivedError(url_response.Pass()); + } else if (url_response->redirect_url) { + OnReceivedRedirect(request, url_response.Pass()); + } else { + base::WeakPtr<WebURLLoaderImpl> self(weak_factory_.GetWeakPtr()); + client_->didReceiveResponse(this, ToWebURLResponse(url_response)); + + // We may have been deleted during didReceiveResponse. + if (!self) + return; + + // Start streaming data + response_body_stream_ = url_response->body.Pass(); + ReadMore(); + } +} + +void WebURLLoaderImpl::OnReceivedError(URLResponsePtr url_response) { + blink::WebURLError web_error; + web_error.domain = blink::WebString::fromUTF8(net::kErrorDomain); + web_error.reason = url_response->error->code; + web_error.unreachableURL = GURL(url_response->url); + web_error.staleCopyInCache = false; + web_error.isCancellation = + url_response->error->code == net::ERR_ABORTED ? true : false; + + client_->didFail(this, web_error); +} + +void WebURLLoaderImpl::OnReceivedRedirect(const blink::WebURLRequest& request, + URLResponsePtr url_response) { + // TODO(erg): setFirstPartyForCookies() and setHTTPReferrer() are unset here. + blink::WebURLRequest new_request; + new_request.initialize(); + new_request.setURL(GURL(url_response->redirect_url)); + new_request.setDownloadToFile(request.downloadToFile()); + new_request.setRequestContext(request.requestContext()); + new_request.setFrameType(request.frameType()); + new_request.setSkipServiceWorker(request.skipServiceWorker()); + new_request.setFetchRequestMode(request.fetchRequestMode()); + new_request.setFetchCredentialsMode(request.fetchCredentialsMode()); + new_request.setHTTPReferrer( + WebString::fromUTF8(url_response->redirect_referrer), + referrer_policy_); + + std::string old_method = request.httpMethod().utf8(); + new_request.setHTTPMethod( + blink::WebString::fromUTF8(url_response->redirect_method)); + if (url_response->redirect_method == old_method) + new_request.setHTTPBody(request.httpBody()); + + base::WeakPtr<WebURLLoaderImpl> self(weak_factory_.GetWeakPtr()); + client_->willSendRequest(this, new_request, ToWebURLResponse(url_response)); + // TODO(darin): Check if new_request was rejected. + + // We may have been deleted during willSendRequest. + if (!self) + return; + + url_loader_->FollowRedirect( + base::Bind(&WebURLLoaderImpl::OnReceivedResponse, + weak_factory_.GetWeakPtr(), + request)); +} + +void WebURLLoaderImpl::OnReceiveWebBlobData( + const blink::WebURLRequest& request, + const blink::WebVector<blink::WebBlobData::Item*>& items) { + blink::WebURLResponse result; + result.initialize(); + result.setURL(url_); + result.setHTTPStatusCode(200); + result.setExpectedContentLength(-1); // Not available. + + base::WeakPtr<WebURLLoaderImpl> self(weak_factory_.GetWeakPtr()); + client_->didReceiveResponse(this, result); + + // We may have been deleted during didReceiveResponse. + if (!self) + return; + + // Send a receive data for each blob item. + for (size_t i = 0; i < items.size(); ++i) { + client_->didReceiveData(this, items[i]->data.data(), items[i]->data.size(), + -1); + } + + // Send a closing finish. + double finish_time = base::Time::Now().ToDoubleT(); + client_->didFinishLoading( + this, finish_time, blink::WebURLLoaderClient::kUnknownEncodedDataLength); +} + +void WebURLLoaderImpl::ReadMore() { + const void* buf; + uint32_t buf_size; + MojoResult rv = BeginReadDataRaw(response_body_stream_.get(), + &buf, + &buf_size, + MOJO_READ_DATA_FLAG_NONE); + if (rv == MOJO_RESULT_OK) { + base::WeakPtr<WebURLLoaderImpl> self(weak_factory_.GetWeakPtr()); + client_->didReceiveData(this, static_cast<const char*>(buf), buf_size, -1); + // We may have been deleted durining didReceiveData. + if (!self) + return; + EndReadDataRaw(response_body_stream_.get(), buf_size); + WaitToReadMore(); + } else if (rv == MOJO_RESULT_SHOULD_WAIT) { + WaitToReadMore(); + } else if (rv == MOJO_RESULT_FAILED_PRECONDITION) { + // We reached end-of-file. + double finish_time = base::Time::Now().ToDoubleT(); + client_->didFinishLoading( + this, + finish_time, + blink::WebURLLoaderClient::kUnknownEncodedDataLength); + } else { + // TODO(darin): Oops! + } +} + +void WebURLLoaderImpl::WaitToReadMore() { + handle_watcher_.Start( + response_body_stream_.get(), + MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, + base::Bind(&WebURLLoaderImpl::OnResponseBodyStreamReady, + weak_factory_.GetWeakPtr())); +} + +void WebURLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { + ReadMore(); +} + +} // namespace html_viewer diff --git a/components/html_viewer/web_url_loader_impl.h b/components/html_viewer/web_url_loader_impl.h new file mode 100644 index 0000000..4a92a8a --- /dev/null +++ b/components/html_viewer/web_url_loader_impl.h @@ -0,0 +1,78 @@ +// 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_WEB_URL_LOADER_IMPL_H_ +#define COMPONENTS_HTML_VIEWER_WEB_URL_LOADER_IMPL_H_ + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/html_viewer/mock_web_blob_registry_impl.h" +#include "mojo/common/handle_watcher.h" +#include "mojo/services/network/public/interfaces/url_loader.mojom.h" +#include "third_party/WebKit/public/platform/WebBlobData.h" +#include "third_party/WebKit/public/platform/WebReferrerPolicy.h" +#include "third_party/WebKit/public/platform/WebURLLoader.h" +#include "third_party/WebKit/public/platform/WebURLRequest.h" + +namespace mojo { +class NetworkService; +} + +namespace html_viewer { + +// The concrete type of WebURLRequest::ExtraData. +class WebURLRequestExtraData : public blink::WebURLRequest::ExtraData { + public: + WebURLRequestExtraData(); + virtual ~WebURLRequestExtraData(); + + mojo::URLResponsePtr synthetic_response; +}; + +class WebURLLoaderImpl : public blink::WebURLLoader { + public: + explicit WebURLLoaderImpl(mojo::NetworkService* network_service, + MockWebBlobRegistryImpl* web_blob_registry); + + private: + virtual ~WebURLLoaderImpl(); + + // blink::WebURLLoader methods: + virtual void loadSynchronously(const blink::WebURLRequest& request, + blink::WebURLResponse& response, + blink::WebURLError& error, + blink::WebData& data); + virtual void loadAsynchronously(const blink::WebURLRequest&, + blink::WebURLLoaderClient* client); + virtual void cancel(); + virtual void setDefersLoading(bool defers_loading); + + void OnReceivedResponse(const blink::WebURLRequest& request, + mojo::URLResponsePtr response); + void OnReceivedError(mojo::URLResponsePtr response); + void OnReceivedRedirect(const blink::WebURLRequest& request, + mojo::URLResponsePtr response); + void OnReceiveWebBlobData( + const blink::WebURLRequest& request, + const blink::WebVector<blink::WebBlobData::Item*>& items); + void ReadMore(); + void WaitToReadMore(); + void OnResponseBodyStreamReady(MojoResult result); + + blink::WebURLLoaderClient* client_; + MockWebBlobRegistryImpl* web_blob_registry_; + GURL url_; + blink::WebReferrerPolicy referrer_policy_; + mojo::URLLoaderPtr url_loader_; + mojo::ScopedDataPipeConsumerHandle response_body_stream_; + mojo::common::HandleWatcher handle_watcher_; + + base::WeakPtrFactory<WebURLLoaderImpl> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(WebURLLoaderImpl); +}; + +} // namespace html_viewer + +#endif // COMPONENTS_HTML_VIEWER_WEB_URL_LOADER_IMPL_H_ |