summaryrefslogtreecommitdiffstats
path: root/components/html_viewer
diff options
context:
space:
mode:
authorjam <jam@chromium.org>2015-04-22 13:38:16 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-22 20:39:00 +0000
commit81a5661f60738efa7dbbee0a72f2c1e15f6690f9 (patch)
tree27fe82ed9e8d8b504f6c731365df1fc9e2c3d1f6 /components/html_viewer
parentaa86d5f0d050b3322ed02d81e5f51787726f5511 (diff)
downloadchromium_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')
-rw-r--r--components/html_viewer/BUILD.gn242
-rw-r--r--components/html_viewer/DEPS26
-rw-r--r--components/html_viewer/OWNERS1
-rw-r--r--components/html_viewer/android/android_hooks.cc50
-rw-r--r--components/html_viewer/android/java/org/chromium/html_viewer/Main.java25
-rw-r--r--components/html_viewer/ax_provider_apptest.cc88
-rw-r--r--components/html_viewer/ax_provider_impl.cc86
-rw-r--r--components/html_viewer/ax_provider_impl.h39
-rw-r--r--components/html_viewer/ax_provider_impl_unittest.cc178
-rw-r--r--components/html_viewer/blink_basic_type_converters.cc46
-rw-r--r--components/html_viewer/blink_basic_type_converters.h52
-rw-r--r--components/html_viewer/blink_input_events_type_converters.cc190
-rw-r--r--components/html_viewer/blink_input_events_type_converters.h24
-rw-r--r--components/html_viewer/blink_platform_impl.cc323
-rw-r--r--components/html_viewer/blink_platform_impl.h120
-rw-r--r--components/html_viewer/blink_resource_constants.h127
-rw-r--r--components/html_viewer/blink_url_request_type_converters.cc110
-rw-r--r--components/html_viewer/blink_url_request_type_converters.h23
-rw-r--r--components/html_viewer/discardable_memory_allocator.cc151
-rw-r--r--components/html_viewer/discardable_memory_allocator.h61
-rw-r--r--components/html_viewer/discardable_memory_allocator_unittest.cc76
-rw-r--r--components/html_viewer/generate_blink_resource_map.py146
-rw-r--r--components/html_viewer/html_document.cc385
-rw-r--r--components/html_viewer/html_document.h177
-rw-r--r--components/html_viewer/html_viewer.cc254
-rw-r--r--components/html_viewer/html_viewer_version.rc46
-rw-r--r--components/html_viewer/mock_web_blob_registry_impl.cc121
-rw-r--r--components/html_viewer/mock_web_blob_registry_impl.h64
-rw-r--r--components/html_viewer/test_blink_platform_impl.cc23
-rw-r--r--components/html_viewer/test_blink_platform_impl.h31
-rw-r--r--components/html_viewer/touch_handler.cc187
-rw-r--r--components/html_viewer/touch_handler.h62
-rw-r--r--components/html_viewer/web_clipboard_impl.cc207
-rw-r--r--components/html_viewer/web_clipboard_impl.h49
-rw-r--r--components/html_viewer/web_cookie_jar_impl.cc71
-rw-r--r--components/html_viewer/web_cookie_jar_impl.h36
-rw-r--r--components/html_viewer/web_layer_tree_view_impl.cc254
-rw-r--r--components/html_viewer/web_layer_tree_view_impl.h136
-rw-r--r--components/html_viewer/web_media_player_factory.cc137
-rw-r--r--components/html_viewer/web_media_player_factory.h76
-rw-r--r--components/html_viewer/web_message_port_channel_impl.cc132
-rw-r--r--components/html_viewer/web_message_port_channel_impl.h45
-rw-r--r--components/html_viewer/web_mime_registry_impl.cc136
-rw-r--r--components/html_viewer/web_mime_registry_impl.h44
-rw-r--r--components/html_viewer/web_notification_manager_impl.cc63
-rw-r--r--components/html_viewer/web_notification_manager_impl.h46
-rw-r--r--components/html_viewer/web_scheduler_impl.cc67
-rw-r--r--components/html_viewer/web_scheduler_impl.h40
-rw-r--r--components/html_viewer/web_socket_handle_impl.cc219
-rw-r--r--components/html_viewer/web_socket_handle_impl.h63
-rw-r--r--components/html_viewer/web_storage_namespace_impl.cc41
-rw-r--r--components/html_viewer/web_storage_namespace_impl.h30
-rw-r--r--components/html_viewer/web_theme_engine_impl.cc203
-rw-r--r--components/html_viewer/web_theme_engine_impl.h31
-rw-r--r--components/html_viewer/web_thread_impl.cc187
-rw-r--r--components/html_viewer/web_thread_impl.h88
-rw-r--r--components/html_viewer/web_url_loader_impl.cc305
-rw-r--r--components/html_viewer/web_url_loader_impl.h78
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_