[webview] Add dart webview on top of chromium

Change-Id: I8d7ab0fcca8c0995599bbe3467debdf847303408
diff --git a/public/lib/webview/BUILD.gn b/public/lib/webview/BUILD.gn
new file mode 100644
index 0000000..a1331ae
--- /dev/null
+++ b/public/lib/webview/BUILD.gn
@@ -0,0 +1,23 @@
+# Copyright 2018 The Fuchsia 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("//build/dart/dart_library.gni")
+
+dart_library("webview") {
+  package_name = "webview"
+
+  sources = [
+    "webview.dart",
+  ]
+
+  deps = [
+    "//sdk/fidl/fuchsia.sys",
+    "//sdk/fidl/fuchsia.ui.views",
+    "//topaz/public/dart/fuchsia_logger",
+    "//topaz/public/dart/fuchsia_scenic_flutter",
+    "//topaz/runtime/chromium:chromium.web",
+    "//zircon/public/fidl/fuchsia-io",
+    "//zircon/public/fidl/fuchsia-mem",
+  ]
+}
diff --git a/public/lib/webview/OWNERS b/public/lib/webview/OWNERS
new file mode 100644
index 0000000..dbb45dc
--- /dev/null
+++ b/public/lib/webview/OWNERS
@@ -0,0 +1,2 @@
+miguelfrde@google.com
+*
diff --git a/public/lib/webview/analysis_options.yaml b/public/lib/webview/analysis_options.yaml
new file mode 100644
index 0000000..f0cea8a
--- /dev/null
+++ b/public/lib/webview/analysis_options.yaml
@@ -0,0 +1,5 @@
+# Copyright 2018 The Fuchsia 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: ../../../tools/analysis_options.yaml
diff --git a/public/lib/webview/lib/src/webview.dart b/public/lib/webview/lib/src/webview.dart
new file mode 100644
index 0000000..462afaa
--- /dev/null
+++ b/public/lib/webview/lib/src/webview.dart
@@ -0,0 +1,99 @@
+// Copyright 2018 The Fuchsia 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 'dart:convert' show utf8;
+import 'dart:io';
+
+import 'package:fidl/fidl.dart';
+import 'package:fidl_chromium_web/fidl_async.dart' as web;
+import 'package:fidl_fuchsia_mem/fidl_async.dart' as fuchsia_mem;
+import 'package:fidl_fuchsia_io/fidl_async.dart' as fidl_io;
+import 'package:fidl_fuchsia_sys/fidl_async.dart' as sys;
+import 'package:fidl_fuchsia_ui_views/fidl_async.dart' as views;
+import 'package:fuchsia_logger/logger.dart';
+import 'package:fuchsia_scenic_flutter/child_view_connection.dart'
+    show ChildViewConnection;
+import 'package:zircon/zircon.dart';
+
+class ChromiumWebView {
+  final sys.ServiceProvider serviceProvider;
+  final web.ContextProviderProxy _contextProvider = web.ContextProviderProxy();
+  final web.ContextProxy _context = web.ContextProxy();
+  final web.FrameProxy _frame = web.FrameProxy();
+  final web.NavigationControllerProxy _navigationController =
+      web.NavigationControllerProxy();
+
+  final web.NavigationEventObserverBinding _navigationEventObserverBinding =
+      web.NavigationEventObserverBinding();
+
+  ChildViewConnection _childViewConnection;
+
+  ChromiumWebView(
+    this.serviceProvider, {
+    web.LogLevel javascriptLogLevel = web.LogLevel.none,
+  }) {
+    final contextProviderProxyRequest = _contextProvider.ctrl.request();
+    serviceProvider.connectToService(_contextProvider.ctrl.$serviceName,
+        contextProviderProxyRequest.passChannel());
+    if (!Directory('/svc').existsSync()) {
+      log.shout('no /svc directory');
+      return;
+    }
+    final channel = Channel.fromFile('/svc');
+    final web.CreateContextParams params = web.CreateContextParams(
+        serviceDirectory: InterfaceHandle<fidl_io.Directory>(channel));
+    _contextProvider.create(params, _context.ctrl.request());
+    _context.createFrame(_frame.ctrl.request());
+
+    // Create a token pair for the newly-created View.
+    final tokenPair = EventPairPair();
+    assert(tokenPair.status == ZX.OK);
+    final viewHolderToken = views.ViewHolderToken(value: tokenPair.first);
+    final viewToken = views.ViewToken(value: tokenPair.second);
+
+    _frame.createView2(viewToken.value, null, null);
+    _childViewConnection = ChildViewConnection(viewHolderToken);
+    _frame
+      ..getNavigationController(_navigationController.ctrl.request())
+      ..setJavaScriptLogLevel(javascriptLogLevel);
+  }
+
+  ChildViewConnection get childViewConnection => _childViewConnection;
+
+  web.NavigationControllerProxy get controller => _navigationController;
+
+  void setNavigationEventObserver(web.NavigationEventObserver observer) {
+    _frame.setNavigationEventObserver(
+        _navigationEventObserverBinding.wrap(observer));
+  }
+
+  Future<bool> injectJavascript(
+    String script,
+    List<String> origins, {
+    web.ExecuteMode executeMode = web.ExecuteMode.onPageLoad,
+  }) {
+    final vmo = SizedVmo.fromUint8List(utf8.encode(script));
+    final buffer = fuchsia_mem.Buffer(vmo: vmo, size: vmo.size);
+    return _frame.executeJavaScript(origins, buffer, executeMode);
+  }
+
+  Future<bool> postMessage(String message, String targetOrigin,
+      {InterfaceRequest<web.MessagePort> outgoingMessagePortRequest}) {
+    final vmo = SizedVmo.fromUint8List(utf8.encode(message));
+    var msg = web.WebMessage(
+      data: fuchsia_mem.Buffer(vmo: vmo, size: vmo.size),
+      outgoingTransfer: outgoingMessagePortRequest != null
+          ? web.OutgoingTransferable.withMessagePort(outgoingMessagePortRequest)
+          : null,
+    );
+    return _frame.postMessage(msg, targetOrigin);
+  }
+
+  void dispose() {
+    _navigationController.ctrl.close();
+    _frame.ctrl.close();
+    _context.ctrl.close();
+    _contextProvider.ctrl.close();
+  }
+}
diff --git a/public/lib/webview/lib/webview.dart b/public/lib/webview/lib/webview.dart
new file mode 100644
index 0000000..5853a51
--- /dev/null
+++ b/public/lib/webview/lib/webview.dart
@@ -0,0 +1,5 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+export 'src/webview.dart';
diff --git a/public/lib/webview/pubspec.yaml b/public/lib/webview/pubspec.yaml
new file mode 100644
index 0000000..8db0f51
--- /dev/null
+++ b/public/lib/webview/pubspec.yaml
@@ -0,0 +1,5 @@
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+name: webview