Bug 1096633 - Allow webgl/experimental-webgl aliasing. - r=kamidphish
authorJeff Gilbert <jgilbert@mozilla.com>
Mon, 10 Nov 2014 15:16:50 -0800
changeset 240477 7025a18fc63bdd98b777a038f8aeda2184d439c4
parent 240476 872f98f50872db60f668148257934769e4054cbe
child 240478 f85d4a0211e9f232b2c130b482c492f44b818aa5
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskamidphish
bugs1096633
milestone36.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 1096633 - Allow webgl/experimental-webgl aliasing. - r=kamidphish
dom/canvas/WebGL1Context.cpp
dom/canvas/WebGL1Context.h
dom/html/HTMLCanvasElement.cpp
dom/html/HTMLCanvasElement.h
layout/build/nsLayoutModule.cpp
widget/GfxInfoWebGL.cpp
--- a/dom/canvas/WebGL1Context.cpp
+++ b/dom/canvas/WebGL1Context.cpp
@@ -1,50 +1,51 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGL1Context.h"
+
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
-
 #include "mozilla/Telemetry.h"
 
-using namespace mozilla;
+namespace mozilla {
 
-// -----------------------------------------------------------------------------
-// CONSTRUCTOR & DESTRUCTOR
+/*static*/ WebGL1Context*
+WebGL1Context::Create()
+{
+    return new WebGL1Context();
+}
 
 WebGL1Context::WebGL1Context()
     : WebGLContext()
 {
-
 }
 
 WebGL1Context::~WebGL1Context()
 {
-
 }
 
-
-// -----------------------------------------------------------------------------
-// IMPLEMENT nsWrapperCache
+////////////////////////////////////////
+// nsWrapperCache
 
 JSObject*
-WebGL1Context::WrapObject(JSContext *cx)
+WebGL1Context::WrapObject(JSContext* cx)
 {
     return dom::WebGLRenderingContextBinding::Wrap(cx, this);
 }
 
+} // namespace mozilla
 
-// -----------------------------------------------------------------------------
-// INSTANCING nsIDOMWebGLRenderingContext
+////////////////////////////////////////
+// nsIDOMWebGLRenderingContext
 
 nsresult
-NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult)
+NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** out_result)
 {
     Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
-    nsIDOMWebGLRenderingContext* ctx = new WebGL1Context();
 
-    NS_ADDREF(*aResult = ctx);
+    nsIDOMWebGLRenderingContext* ctx = WebGL1Context::Create();
+
+    NS_ADDREF(*out_result = ctx);
     return NS_OK;
 }
-
--- a/dom/canvas/WebGL1Context.h
+++ b/dom/canvas/WebGL1Context.h
@@ -1,46 +1,35 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef WEBGL1CONTEXT_H_
-#define WEBGL1CONTEXT_H_
+#ifndef WEBGL_1_CONTEXT_H_
+#define WEBGL_1_CONTEXT_H_
 
 #include "WebGLContext.h"
 
 namespace mozilla {
 
 class WebGL1Context
     : public WebGLContext
 {
-// -----------------------------------------------------------------------------
-// PUBLIC
 public:
+    static WebGL1Context* Create();
 
-    // -------------------------------------------------------------------------
-    // CONSTRUCTOR & DESTRUCTOR
+private:
+    WebGL1Context();
 
-    WebGL1Context();
+public:
     virtual ~WebGL1Context();
 
-
-    // -------------------------------------------------------------------------
-    // IMPLEMENT WebGLContext
-
-    virtual bool IsWebGL2() const MOZ_OVERRIDE
-    {
+    virtual bool IsWebGL2() const MOZ_OVERRIDE {
         return false;
     }
 
-
-    // -------------------------------------------------------------------------
-    // IMPLEMENT nsWrapperCache
-
-    virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
-
-
+    // nsWrapperCache
+    virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
 };
 
 } // namespace mozilla
 
-#endif
+#endif // WEBGL_1_CONTEXT_H_
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -29,16 +29,17 @@
 #include "nsIWritablePropertyBag2.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsMathUtils.h"
 #include "nsNetUtil.h"
 #include "nsStreamUtils.h"
 #include "ActiveLayerTracker.h"
+#include "WebGL1Context.h"
 #include "WebGL2Context.h"
 
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas)
 
 namespace {
@@ -643,147 +644,131 @@ HTMLCanvasElement::MozGetAsFileImpl(cons
   nsRefPtr<File> file =
     File::CreateMemoryFile(win, imgData, (uint32_t)imgSize, aName, type,
                            PR_Now());
 
   file.forget(aResult);
   return NS_OK;
 }
 
-nsresult
-HTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
-                                    nsICanvasRenderingContextInternal **aContext)
+static bool
+GetCanvasContextType(const nsAString& str, CanvasContextType* const out_type)
 {
-  NS_ENSURE_ARG(aContext);
+  if (str.EqualsLiteral("2d")) {
+    *out_type = CanvasContextType::Canvas2D;
+    return true;
+  }
 
-  if (aContextId.EqualsLiteral("2d")) {
-    Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
-    nsRefPtr<CanvasRenderingContext2D> ctx =
-      new CanvasRenderingContext2D();
-
-    ctx->SetCanvasElement(this);
-    ctx.forget(aContext);
-    return NS_OK;
+  if (str.EqualsLiteral("experimental-webgl")) {
+    *out_type = CanvasContextType::WebGL1;
+    return true;
   }
 
-  if (WebGL2Context::IsSupported() &&
-      aContextId.EqualsLiteral("experimental-webgl2"))
-  {
-    Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
-    nsRefPtr<WebGL2Context> ctx = WebGL2Context::Create();
-
-    if (ctx == nullptr) {
-      return NS_ERROR_NOT_IMPLEMENTED;
-    }
-
-    ctx->SetCanvasElement(this);
-    ctx.forget(aContext);
-    return NS_OK;
+#ifdef MOZ_WEBGL_CONFORMANT
+  if (str.EqualsLiteral("webgl")) {
+    /* WebGL 1.0, $2.1 "Context Creation":
+     *   If the user agent supports both the webgl and experimental-webgl
+     *   canvas context types, they shall be treated as aliases.
+     */
+    *out_type = CanvasContextType::WebGL1;
+    return true;
   }
-
-  NS_ConvertUTF16toUTF8 ctxId(aContextId);
+#endif
 
-  // check that ctxId is clamped to A-Za-z0-9_-
-  for (uint32_t i = 0; i < ctxId.Length(); i++) {
-    if ((ctxId[i] < 'A' || ctxId[i] > 'Z') &&
-        (ctxId[i] < 'a' || ctxId[i] > 'z') &&
-        (ctxId[i] < '0' || ctxId[i] > '9') &&
-        (ctxId[i] != '-') &&
-        (ctxId[i] != '_'))
-    {
-      // XXX ERRMSG we need to report an error to developers here! (bug 329026)
-      return NS_OK;
+  if (WebGL2Context::IsSupported()) {
+    if (str.EqualsLiteral("experimental-webgl2")) {
+      *out_type = CanvasContextType::WebGL2;
+      return true;
     }
   }
 
-  nsCString ctxString("@mozilla.org/content/canvas-rendering-context;1?id=");
-  ctxString.Append(ctxId);
+  return false;
+}
+
+static already_AddRefed<nsICanvasRenderingContextInternal>
+CreateContextForCanvas(CanvasContextType contextType, HTMLCanvasElement* canvas)
+{
+  nsRefPtr<nsICanvasRenderingContextInternal> ret;
+
+  switch (contextType) {
+  case CanvasContextType::Canvas2D:
+    Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
+    ret = new CanvasRenderingContext2D();
+    break;
 
-  nsresult rv;
-  nsCOMPtr<nsICanvasRenderingContextInternal> ctx =
-    do_CreateInstance(ctxString.get(), &rv);
-  if (rv == NS_ERROR_OUT_OF_MEMORY) {
-    *aContext = nullptr;
-    return NS_ERROR_OUT_OF_MEMORY;
+  case CanvasContextType::WebGL1:
+    Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
+
+    ret = WebGL1Context::Create();
+    if (!ret)
+      return nullptr;
+    break;
+
+  case CanvasContextType::WebGL2:
+    Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
+
+    ret = WebGL2Context::Create();
+    if (!ret)
+      return nullptr;
+    break;
   }
-  if (NS_FAILED(rv)) {
-    *aContext = nullptr;
-    // XXX ERRMSG we need to report an error to developers here! (bug 329026)
-    return NS_OK;
-  }
+  MOZ_ASSERT(ret);
 
-  ctx->SetCanvasElement(this);
-  ctx.forget(aContext);
-  return NS_OK;
+  ret->SetCanvasElement(canvas);
+  return ret.forget();
 }
 
 nsresult
 HTMLCanvasElement::GetContext(const nsAString& aContextId,
                               nsISupports** aContext)
 {
   ErrorResult rv;
-  *aContext =
-    GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
+  *aContext = GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
   return rv.ErrorCode();
 }
 
-static bool
-IsContextIdWebGL(const nsAString& str)
-{
-  return str.EqualsLiteral("webgl") ||
-         str.EqualsLiteral("experimental-webgl");
-}
-
 already_AddRefed<nsISupports>
 HTMLCanvasElement::GetContext(JSContext* aCx,
                               const nsAString& aContextId,
                               JS::Handle<JS::Value> aContextOptions,
                               ErrorResult& rv)
 {
-  if (mCurrentContextId.IsEmpty()) {
-    rv = GetContextHelper(aContextId, getter_AddRefs(mCurrentContext));
-    if (rv.Failed() || !mCurrentContext) {
+  CanvasContextType contextType;
+  if (!GetCanvasContextType(aContextId, &contextType))
+    return nullptr;
+
+  if (!mCurrentContext) {
+    // This canvas doesn't have a context yet.
+
+    nsRefPtr<nsICanvasRenderingContextInternal> context;
+    context = CreateContextForCanvas(contextType, this);
+    if (!context)
       return nullptr;
-    }
 
     // Ensure that the context participates in CC.  Note that returning a
     // CC participant from QI doesn't addref.
-    nsXPCOMCycleCollectionParticipant *cp = nullptr;
-    CallQueryInterface(mCurrentContext, &cp);
+    nsXPCOMCycleCollectionParticipant* cp = nullptr;
+    CallQueryInterface(context, &cp);
     if (!cp) {
-      mCurrentContext = nullptr;
       rv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
+    mCurrentContext = context.forget();
+    mCurrentContextType = contextType;
+
     rv = UpdateContext(aCx, aContextOptions);
     if (rv.Failed()) {
       rv = NS_OK; // See bug 645792
       return nullptr;
     }
-    mCurrentContextId.Assign(aContextId);
-  }
-
-  if (!mCurrentContextId.Equals(aContextId)) {
-    if (IsContextIdWebGL(aContextId) &&
-        IsContextIdWebGL(mCurrentContextId))
-    {
-      // Warn when we get a request for a webgl context with an id that differs
-      // from the id it was created with.
-      nsCString creationId = NS_LossyConvertUTF16toASCII(mCurrentContextId);
-      nsCString requestId = NS_LossyConvertUTF16toASCII(aContextId);
-      JS_ReportWarning(aCx, "WebGL: Retrieving a WebGL context from a canvas "
-                            "via a request id ('%s') different from the id used "
-                            "to create the context ('%s') is not allowed.",
-                            requestId.get(),
-                            creationId.get());
-    }
-    
-    //XXX eventually allow for more than one active context on a given canvas
-    return nullptr;
+  } else {
+    // We already have a context of some type.
+    if (contextType != mCurrentContextType)
+      return nullptr;
   }
 
   nsCOMPtr<nsICanvasRenderingContextInternal> context = mCurrentContext;
   return context.forget();
 }
 
 NS_IMETHODIMP
 HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
@@ -793,32 +778,38 @@ HTMLCanvasElement::MozGetIPCContext(cons
     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // We only support 2d shmem contexts for now.
   if (!aContextId.EqualsLiteral("2d"))
     return NS_ERROR_INVALID_ARG;
 
-  if (mCurrentContextId.IsEmpty()) {
-    nsresult rv = GetContextHelper(aContextId, getter_AddRefs(mCurrentContext));
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (!mCurrentContext) {
+  CanvasContextType contextType = CanvasContextType::Canvas2D;
+
+  if (!mCurrentContext) {
+    // This canvas doesn't have a context yet.
+
+    nsRefPtr<nsICanvasRenderingContextInternal> context;
+    context = CreateContextForCanvas(contextType, this);
+    if (!context) {
+      *aContext = nullptr;
       return NS_OK;
     }
 
+    mCurrentContext = context;
     mCurrentContext->SetIsIPC(true);
-
-    rv = UpdateContext(nullptr, JS::NullHandleValue);
-    NS_ENSURE_SUCCESS(rv, rv);
+    mCurrentContextType = contextType;
 
-    mCurrentContextId.Assign(aContextId);
-  } else if (!mCurrentContextId.Equals(aContextId)) {
-    //XXX eventually allow for more than one active context on a given canvas
-    return NS_ERROR_INVALID_ARG;
+    nsresult rv = UpdateContext(nullptr, JS::NullHandleValue);
+    NS_ENSURE_SUCCESS(rv, rv);
+  } else {
+    // We already have a context of some type.
+    if (contextType != mCurrentContextType)
+      return NS_ERROR_INVALID_ARG;
   }
 
   NS_ADDREF (*aContext = mCurrentContext);
   return NS_OK;
 }
 
 nsresult
 HTMLCanvasElement::UpdateContext(JSContext* aCx, JS::Handle<JS::Value> aNewContextOptions)
@@ -826,31 +817,28 @@ HTMLCanvasElement::UpdateContext(JSConte
   if (!mCurrentContext)
     return NS_OK;
 
   nsIntSize sz = GetWidthHeight();
 
   nsresult rv = mCurrentContext->SetIsOpaque(HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque));
   if (NS_FAILED(rv)) {
     mCurrentContext = nullptr;
-    mCurrentContextId.Truncate();
     return rv;
   }
 
   rv = mCurrentContext->SetContextOptions(aCx, aNewContextOptions);
   if (NS_FAILED(rv)) {
     mCurrentContext = nullptr;
-    mCurrentContextId.Truncate();
     return rv;
   }
 
   rv = mCurrentContext->SetDimensions(sz.width, sz.height);
   if (NS_FAILED(rv)) {
     mCurrentContext = nullptr;
-    mCurrentContextId.Truncate();
     return rv;
   }
 
   return rv;
 }
 
 nsIntSize
 HTMLCanvasElement::GetSize()
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #if !defined(mozilla_dom_HTMLCanvasElement_h)
 #define mozilla_dom_HTMLCanvasElement_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/TypedEnum.h"
 #include "nsIDOMHTMLCanvasElement.h"
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsSize.h"
 #include "nsError.h"
 
 #include "mozilla/gfx/Rect.h"
 
@@ -30,16 +31,22 @@ class SourceSurface;
 
 namespace dom {
 
 class File;
 class FileCallback;
 class HTMLCanvasPrintState;
 class PrintCallback;
 
+MOZ_BEGIN_ENUM_CLASS(CanvasContextType, uint8_t)
+  Canvas2D,
+  WebGL1,
+  WebGL2
+MOZ_END_ENUM_CLASS(CanvasContextType)
+
 class HTMLCanvasElement MOZ_FINAL : public nsGenericHTMLElement,
                                     public nsIDOMHTMLCanvasElement
 {
   enum {
     DEFAULT_CANVAS_WIDTH = 300,
     DEFAULT_CANVAS_HEIGHT = 150
   };
 
@@ -224,21 +231,19 @@ protected:
                        nsIInputStream** aStream);
   nsresult ToDataURLImpl(JSContext* aCx,
                          const nsAString& aMimeType,
                          const JS::Value& aEncoderOptions,
                          nsAString& aDataURL);
   nsresult MozGetAsFileImpl(const nsAString& aName,
                             const nsAString& aType,
                             nsIDOMFile** aResult);
-  nsresult GetContextHelper(const nsAString& aContextId,
-                            nsICanvasRenderingContextInternal **aContext);
   void CallPrintCallback();
 
-  nsString mCurrentContextId;
+  CanvasContextType mCurrentContextType;
   nsRefPtr<HTMLCanvasElement> mOriginalCanvas;
   nsRefPtr<PrintCallback> mPrintCallback;
   nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
   nsRefPtr<HTMLCanvasPrintState> mPrintState;
 
 public:
   // Record whether this canvas should be write-only or not.
   // We set this when script paints an image from a different origin.
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -1124,20 +1124,17 @@ static const mozilla::Module::ContractID
   { "@mozilla.org/inspector/search;1?type=cssvalue", &kIN_CSSVALUESEARCH_CID },
   { IN_DOMUTILS_CONTRACTID, &kIN_DOMUTILS_CID },
   { "@mozilla.org/xml/xml-document;1", &kNS_XMLDOCUMENT_CID },
   { "@mozilla.org/svg/svg-document;1", &kNS_SVGDOCUMENT_CID },
   { "@mozilla.org/content/dom-selection;1", &kNS_DOMSELECTION_CID },
   { "@mozilla.org/content/post-content-iterator;1", &kNS_CONTENTITERATOR_CID },
   { "@mozilla.org/content/pre-content-iterator;1", &kNS_PRECONTENTITERATOR_CID },
   { "@mozilla.org/content/subtree-content-iterator;1", &kNS_SUBTREEITERATOR_CID },
-  { "@mozilla.org/content/canvas-rendering-context;1?id=experimental-webgl", &kNS_CANVASRENDERINGCONTEXTWEBGL_CID },
-#ifdef MOZ_WEBGL_CONFORMANT
   { "@mozilla.org/content/canvas-rendering-context;1?id=webgl", &kNS_CANVASRENDERINGCONTEXTWEBGL_CID },
-#endif
   { NS_DOC_ENCODER_CONTRACTID_BASE "text/xml", &kNS_TEXT_ENCODER_CID },
   { NS_DOC_ENCODER_CONTRACTID_BASE "application/xml", &kNS_TEXT_ENCODER_CID },
   { NS_DOC_ENCODER_CONTRACTID_BASE "application/xhtml+xml", &kNS_TEXT_ENCODER_CID },
   { NS_DOC_ENCODER_CONTRACTID_BASE "image/svg+xml", &kNS_TEXT_ENCODER_CID },
   { NS_DOC_ENCODER_CONTRACTID_BASE "text/html", &kNS_TEXT_ENCODER_CID },
   { NS_DOC_ENCODER_CONTRACTID_BASE "text/plain", &kNS_TEXT_ENCODER_CID },
   { NS_HTMLCOPY_ENCODER_CONTRACTID, &kNS_HTMLCOPY_TEXT_ENCODER_CID },
   { NS_CONTENTSERIALIZER_CONTRACTID_PREFIX "text/xml", &kNS_XMLCONTENTSERIALIZER_CID },
--- a/widget/GfxInfoWebGL.cpp
+++ b/widget/GfxInfoWebGL.cpp
@@ -24,17 +24,17 @@ GfxInfoWebGL::GetWebGLParameter(const ns
   else if (aParam.EqualsLiteral("renderer")) param = LOCAL_GL_RENDERER;
   else if (aParam.EqualsLiteral("version")) param = LOCAL_GL_VERSION;
   else if (aParam.EqualsLiteral("shading_language_version")) param = LOCAL_GL_SHADING_LANGUAGE_VERSION;
   else if (aParam.EqualsLiteral("extensions")) param = LOCAL_GL_EXTENSIONS;
   else if (aParam.EqualsLiteral("full-renderer")) param = 0;
   else return NS_ERROR_INVALID_ARG;
 
   nsCOMPtr<nsIDOMWebGLRenderingContext> webgl =
-    do_CreateInstance("@mozilla.org/content/canvas-rendering-context;1?id=experimental-webgl");
+    do_CreateInstance("@mozilla.org/content/canvas-rendering-context;1?id=webgl");
   if (!webgl)
     return NS_ERROR_NOT_AVAILABLE;
 
   nsCOMPtr<nsICanvasRenderingContextInternal> webglInternal =
     do_QueryInterface(webgl);
   if (!webglInternal)
     return NS_ERROR_NOT_AVAILABLE;