Bug 1212477 - Needs a way to access to <canvas>'s context (2d, webgl) from Anonymous Content API; r=roc;r=smaug
authorMatteo Ferretti <mferretti@mozilla.com>
Sun, 15 Nov 2015 14:48:32 +0100
changeset 272608 1ac9ea5105b3eff45f70972d9ac85086b764c214
parent 272607 e96f64e2b9d9dd3dfe9b8ba56d088834d80aea2b
child 272609 6c47167e26a8cf40b038f3906e3202fcaed5b2db
push id68012
push userarchaeopteryx@coole-files.de
push dateSun, 15 Nov 2015 13:54:45 +0000
treeherdermozilla-inbound@8084077bd124 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, smaug
bugs1212477
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1212477 - Needs a way to access to <canvas>'s context (2d, webgl) from Anonymous Content API; r=roc;r=smaug
dom/base/AnonymousContent.cpp
dom/base/AnonymousContent.h
dom/base/test/mochitest.ini
dom/base/test/test_anonymousContent_api.html
dom/base/test/test_anonymousContent_canvas.html
dom/canvas/CanvasRenderingContext2D.h
dom/canvas/WebGLContext.cpp
dom/webidl/AnonymousContent.webidl
--- a/dom/base/AnonymousContent.cpp
+++ b/dom/base/AnonymousContent.cpp
@@ -6,16 +6,17 @@
 
 #include "AnonymousContent.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/AnonymousContentBinding.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDocument.h"
 #include "nsIDOMHTMLCollection.h"
 #include "nsStyledElement.h"
+#include "HTMLCanvasElement.h"
 
 namespace mozilla {
 namespace dom {
 
 // Ref counting and cycle collection
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AnonymousContent, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AnonymousContent, Release)
 NS_IMPL_CYCLE_COLLECTION(AnonymousContent, mContentNode)
@@ -107,16 +108,40 @@ AnonymousContent::RemoveAttributeForElem
   if (!element) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return;
   }
 
   element->RemoveAttribute(aName, aRv);
 }
 
+already_AddRefed<nsISupports>
+AnonymousContent::GetCanvasContext(const nsAString& aElementId,
+                                   const nsAString& aContextId,
+                                   ErrorResult& aRv)
+{
+  Element* element = GetElementById(aElementId);
+
+  if (!element) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return nullptr;
+  }
+
+  if (!element->IsHTMLElement(nsGkAtoms::canvas)) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsISupports> context;
+
+  HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(element);
+  canvas->GetContext(aContextId, getter_AddRefs(context));
+
+  return context.forget();
+}
+
 Element*
 AnonymousContent::GetElementById(const nsAString& aElementId)
 {
   // This can be made faster in the future if needed.
   nsCOMPtr<nsIAtom> elementId = do_GetAtom(aElementId);
   for (nsIContent* kid = mContentNode->GetFirstChild(); kid;
        kid = kid->GetNextNode(mContentNode)) {
     if (!kid->IsElement()) {
--- a/dom/base/AnonymousContent.h
+++ b/dom/base/AnonymousContent.h
@@ -47,16 +47,20 @@ public:
                               const nsAString& aName,
                               DOMString& aValue,
                               ErrorResult& aRv);
 
   void RemoveAttributeForElement(const nsAString& aElementId,
                                  const nsAString& aName,
                                  ErrorResult& aRv);
 
+  already_AddRefed<nsISupports> GetCanvasContext(const nsAString& aElementId,
+                                                 const nsAString& aContextId,
+                                                 ErrorResult& aRv);
+
 private:
   ~AnonymousContent();
   Element* GetElementById(const nsAString& aElementId);
   nsCOMPtr<Element> mContentNode;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -254,16 +254,17 @@ support-files =
   performance_observer.html
   test_anonymousContent_style_csp.html^headers^
   file_explicit_user_agent.sjs
   referrer_change_server.sjs
   file_change_policy_redirect.html
 
 [test_anonymousContent_api.html]
 [test_anonymousContent_append_after_reflow.html]
+[test_anonymousContent_canvas.html]
 [test_anonymousContent_insert.html]
 [test_anonymousContent_manipulate_content.html]
 [test_anonymousContent_style_csp.html]
 [test_applet_alternate_content.html]
 [test_appname_override.html]
 [test_async_setTimeout_stack.html]
 [test_async_setTimeout_stack_across_globals.html]
 [test_audioWindowUtils.html]
--- a/dom/base/test/test_anonymousContent_api.html
+++ b/dom/base/test/test_anonymousContent_api.html
@@ -40,16 +40,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   // Testing the API of the returned object
   let div = document.createElement("div");
   div.textContent = "this is a test element";
   let anonymousContent = chromeDocument.insertAnonymousContent(div);
   ok(anonymousContent, "AnonymousContent object returned");
 
   let members = ["getTextContentForElement", "setTextContentForElement",
                  "getAttributeForElement", "setAttributeForElement",
-                 "removeAttributeForElement"];
+                 "removeAttributeForElement", "getCanvasContext"];
   for (let member of members) {
     ok(member in anonymousContent, "AnonymousContent object defines " + member);
   }
   chromeDocument.removeAnonymousContent(anonymousContent);
   </script>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_anonymousContent_canvas.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1212477
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1212477 - Needs a way to access to &lt;canvas&gt;'s context (2d, webgl) from Anonymous Content API</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1212477">Mozilla Bug 1212477</a>
+  <div>
+    <div id="id" class="test">text content</div>
+    <canvas id="canvas2d"></canvas>
+    <canvas id="canvas-webgl"></canvas>
+    <canvas id="canvas-foo"></canvas>
+  </div>
+  <script type="application/javascript;version=1.8">
+    let chromeDocument = SpecialPowers.wrap(document);
+    let testElement = document.querySelector("div");
+
+    let anonymousContent = chromeDocument.insertAnonymousContent(testElement);
+
+    is(anonymousContent.getCanvasContext("id", "2d"), null,
+        "Context is null for non-canvas elements");
+
+    let context2d = anonymousContent.getCanvasContext("canvas2d", "2d");
+
+    is(context2d.toString(), "[object CanvasRenderingContext2D]",
+        "2D Context is returned properly");
+
+    is(context2d.canvas, null,
+        "context's canvas property is null in anonymous content");
+
+    is (anonymousContent.getCanvasContext("canvas-foo", "foo"), null,
+        "Context is null for unknown context type");
+
+    SimpleTest.doesThrow(
+      () => anonymousContent.getCanvasContext("foo", "2d"),
+      "NS_ERROR_NOT_AVAILABLE",
+      "Get a context using unexisting id should throw"
+    );
+
+    let webgl = anonymousContent.getCanvasContext("canvas-webgl", "webgl");
+
+    is(webgl.toString(), "[object WebGLRenderingContext]",
+        "WebGL Context is returned properly");
+
+    is(webgl.canvas, null,
+        "WebGL context's canvas property is null in anonymous content");
+
+    chromeDocument.removeAnonymousContent(anonymousContent);
+  </script>
+</body>
+</html>
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -66,16 +66,20 @@ class CanvasRenderingContext2D final :
 
 public:
   CanvasRenderingContext2D();
 
   virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
   HTMLCanvasElement* GetCanvas() const
   {
+    if (mCanvasElement->IsInNativeAnonymousSubtree()) {
+      return nullptr;
+    }
+
     // corresponds to changes to the old bindings made in bug 745025
     return mCanvasElement->GetOriginalCanvas();
   }
 
   void Save();
   void Restore();
   void Scale(double x, double y, mozilla::ErrorResult& error);
   void Rotate(double angle, mozilla::ErrorResult& error);
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1230,17 +1230,22 @@ WebGLContext::Commit()
     }
 }
 
 void
 WebGLContext::GetCanvas(Nullable<dom::OwningHTMLCanvasElementOrOffscreenCanvas>& retval)
 {
     if (mCanvasElement) {
         MOZ_RELEASE_ASSERT(!mOffscreenCanvas);
-        retval.SetValue().SetAsHTMLCanvasElement() = mCanvasElement;
+
+        if (mCanvasElement->IsInNativeAnonymousSubtree()) {
+          retval.SetNull();
+        } else {
+          retval.SetValue().SetAsHTMLCanvasElement() = mCanvasElement;
+        }
     } else if (mOffscreenCanvas) {
         retval.SetValue().SetAsOffscreenCanvas() = mOffscreenCanvas;
     } else {
         retval.SetNull();
     }
 }
 
 void
--- a/dom/webidl/AnonymousContent.webidl
+++ b/dom/webidl/AnonymousContent.webidl
@@ -48,9 +48,17 @@ interface AnonymousContent {
                               DOMString value);
 
   /**
    * Remove an attribute from an element inside this custom anonymous content.
    */
   [Throws]
   void removeAttributeForElement(DOMString elementId,
                                  DOMString attributeName);
+
+  /**
+   * Get the canvas' context for the element specified if it's a <canvas>
+   * node, `null` otherwise.
+   */
+  [Throws]
+  nsISupports? getCanvasContext(DOMString elementId,
+                                DOMString contextId);
 };