Bug 1431255 - Expose xpc::GetXBLScope() to frame script, load page widgets scripts draft
authorTimothy Guan-tin Chien <timdream@gmail.com>
Wed, 27 Jun 2018 11:34:07 -0700
changeset 811642 f11cb42dfa635f2ceb9331262343842cf56a56d2
parent 811641 c7f98e9a0af567473276aa3a95f55f0a628ab01b
child 811643 450833af6d345d4b98f9491b08ae2453cfcdab7f
push id114383
push usertimdream@gmail.com
push dateWed, 27 Jun 2018 23:34:04 +0000
bugs1431255
milestone63.0a1
Bug 1431255 - Expose xpc::GetXBLScope() to frame script, load page widgets scripts This patch create the basic structure on how the widget script can be loaded and be pointed to the Shadow Root. The patch right now short circuit the original per-window XBL sandbox to the frame script, to be replaced with per-origin sandbox. MozReview-Commit-ID: J6W4PDQWMcN
browser/base/content/tab-content.js
js/xpconnect/idl/xpccomponents.idl
js/xpconnect/src/XPCComponents.cpp
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -493,8 +493,74 @@ addEventListener("MozAfterPaint", functi
 
 // Remove this once bug 1397365 is fixed.
 addEventListener("MozAfterPaint", function onFirstNonBlankPaint() {
   if (content.document.documentURI == "about:blank" && !content.opener)
     return;
   removeEventListener("MozAfterPaint", onFirstNonBlankPaint);
   sendAsyncMessage("Browser:FirstNonBlankPaint");
 });
+
+class PageWidgets {
+  constructor() {
+    addEventListener("PageWidgetBindToTree", this);
+    addEventListener("PageWidgetUnbindFromTree", this);
+
+    this.widgets = new WeakMap();
+  }
+
+  handleEvent(aEvent) {
+    switch (aEvent.type) {
+      case "PageWidgetBindToTree":
+        this.setupSandbox(aEvent.target);
+        break;
+      case "PageWidgetUnbindFromTree":
+        this.teardownSandbox(aEvent.target);
+        break;
+    }
+  }
+
+  setupSandbox(aElement) {
+    let shadowRoot = aElement.openOrClosedShadowRoot;
+    let sandbox = Cu.getUASandbox(aElement);
+
+    let uri;
+    let widgetName;
+    switch (aElement.localName) {
+      case "video":
+      case "audio":
+        // TODO (videocontrols)
+        break;
+      case "input":
+        // TODO (datetimebox)
+        break;
+      case "applet":
+      case "embed":
+      case "object":
+        // TODO (pluginProblems)
+        break;
+    }
+
+    if (!uri || !widgetName) {
+      return;
+    }
+
+    if (!sandbox[widgetName]) {
+      Services.scriptloader.loadSubScript(uri, sandbox, "UTF-8");
+    }
+
+    let widget = new sandbox[widgetName](shadowRoot);
+    this.widgets.set(aElement, widget);
+  }
+
+  teardownSandbox(aElement) {
+    let widget = this.widgets.get(aElement);
+    if (!widget) {
+      return;
+    }
+    if (typeof widget.destructor == "function") {
+      widget.destructor();
+    }
+    this.widgets.delete(aElement);
+  }
+}
+
+new PageWidgets();
--- a/js/xpconnect/idl/xpccomponents.idl
+++ b/js/xpconnect/idl/xpccomponents.idl
@@ -14,16 +14,17 @@ interface nsIClassInfo;
 interface nsIComponentManager;
 interface nsICycleCollectorListener;
 interface nsIFile;
 interface nsIURI;
 interface nsIJSCID;
 interface nsIJSIID;
 interface nsIPrincipal;
 interface nsIStackFrame;
+webidl Element;
 
 /**
 * interface of Components.interfacesByID
 * (interesting stuff only reflected into JavaScript)
 */
 [scriptable, uuid(f235ef76-9919-478b-aa0f-282d994ddf76)]
 interface nsIXPCComponents_InterfacesByID : nsISupports
 {
@@ -171,16 +172,22 @@ interface nsIXPCComponents_Utils : nsISu
      */
     [implicit_jscontext,optional_argc]
     jsval evalInSandbox(in AString source, in jsval sandbox,
                         [optional] in jsval version,
                         [optional] in AUTF8String filename,
                         [optional] in long lineNo);
 
     /*
+     * Get the sandbox for running JS-implemented UA widgets (video controls etc.)
+     */
+    [implicit_jscontext]
+    jsval getUASandbox(in Element hostElement);
+
+    /*
      * getSandboxMetadata is designed to be called from JavaScript only.
      *
      * getSandboxMetadata retrieves the metadata associated with
      * a sandbox object. It will return undefined if there
      * is no metadata attached to the sandbox.
      *
      * var s = C.u.Sandbox(..., { metadata: "metadata" });
      * var metadata = C.u.getSandboxMetadata(s);
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2162,16 +2162,38 @@ nsXPCComponents_Utils::EvalInSandbox(con
             lineNo = frame->GetLineNumber(cx);
         }
     }
 
     return xpc::EvalInSandbox(cx, sandbox, source, filename, lineNo, retval);
 }
 
 NS_IMETHODIMP
+nsXPCComponents_Utils::GetUASandbox(mozilla::dom::Element* hostElement,
+                                    JSContext* cx,
+                                    MutableHandleValue rval)
+{
+    rval.set(UndefinedValue());
+
+    JSObject* wrapper = hostElement->AsContent()->GetWrapper();
+    if (!wrapper) {
+      return NS_ERROR_FAILURE;
+    }
+    JS::Rooted<JSObject*> scope(cx, xpc::GetXBLScope(cx, wrapper));
+    JS::Rooted<JS::Value> jsValue(cx);
+    if (!ToJSValue(cx, scope, &jsValue)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    rval.set(jsValue);
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 nsXPCComponents_Utils::GetSandboxMetadata(HandleValue sandboxVal,
                                           JSContext* cx, MutableHandleValue rval)
 {
     if (!sandboxVal.isObject())
         return NS_ERROR_INVALID_ARG;
 
     RootedObject sandbox(cx, &sandboxVal.toObject());
     sandbox = js::CheckedUnwrap(sandbox);