Bug 1096633 - Allow webgl/experimental-webgl aliasing. - r=kamidphish

This commit is contained in:
Jeff Gilbert 2014-11-10 15:16:50 -08:00
parent 30da52aa2b
commit 48006b5d6e
6 changed files with 129 additions and 149 deletions

View File

@ -4,47 +4,48 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGL1Context.h" #include "WebGL1Context.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/Telemetry.h" #include "mozilla/Telemetry.h"
using namespace mozilla; namespace mozilla {
// ----------------------------------------------------------------------------- /*static*/ WebGL1Context*
// CONSTRUCTOR & DESTRUCTOR WebGL1Context::Create()
{
return new WebGL1Context();
}
WebGL1Context::WebGL1Context() WebGL1Context::WebGL1Context()
: WebGLContext() : WebGLContext()
{ {
} }
WebGL1Context::~WebGL1Context() WebGL1Context::~WebGL1Context()
{ {
} }
////////////////////////////////////////
// ----------------------------------------------------------------------------- // nsWrapperCache
// IMPLEMENT nsWrapperCache
JSObject* JSObject*
WebGL1Context::WrapObject(JSContext *cx) WebGL1Context::WrapObject(JSContext* cx)
{ {
return dom::WebGLRenderingContextBinding::Wrap(cx, this); return dom::WebGLRenderingContextBinding::Wrap(cx, this);
} }
} // namespace mozilla
// ----------------------------------------------------------------------------- ////////////////////////////////////////
// INSTANCING nsIDOMWebGLRenderingContext // nsIDOMWebGLRenderingContext
nsresult nsresult
NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult) NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** out_result)
{ {
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); 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; return NS_OK;
} }

View File

@ -3,8 +3,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WEBGL1CONTEXT_H_ #ifndef WEBGL_1_CONTEXT_H_
#define WEBGL1CONTEXT_H_ #define WEBGL_1_CONTEXT_H_
#include "WebGLContext.h" #include "WebGLContext.h"
@ -13,34 +13,23 @@ namespace mozilla {
class WebGL1Context class WebGL1Context
: public WebGLContext : public WebGLContext
{ {
// -----------------------------------------------------------------------------
// PUBLIC
public: public:
static WebGL1Context* Create();
// ------------------------------------------------------------------------- private:
// CONSTRUCTOR & DESTRUCTOR
WebGL1Context(); WebGL1Context();
public:
virtual ~WebGL1Context(); virtual ~WebGL1Context();
virtual bool IsWebGL2() const MOZ_OVERRIDE {
// -------------------------------------------------------------------------
// IMPLEMENT WebGLContext
virtual bool IsWebGL2() const MOZ_OVERRIDE
{
return false; return false;
} }
// nsWrapperCache
// ------------------------------------------------------------------------- virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
// IMPLEMENT nsWrapperCache
virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
}; };
} // namespace mozilla } // namespace mozilla
#endif #endif // WEBGL_1_CONTEXT_H_

View File

@ -34,6 +34,7 @@
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsStreamUtils.h" #include "nsStreamUtils.h"
#include "ActiveLayerTracker.h" #include "ActiveLayerTracker.h"
#include "WebGL1Context.h"
#include "WebGL2Context.h" #include "WebGL2Context.h"
using namespace mozilla::layers; using namespace mozilla::layers;
@ -648,71 +649,71 @@ HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
return NS_OK; return NS_OK;
} }
nsresult static bool
HTMLCanvasElement::GetContextHelper(const nsAString& aContextId, GetCanvasContextType(const nsAString& str, CanvasContextType* const out_type)
nsICanvasRenderingContextInternal **aContext)
{ {
NS_ENSURE_ARG(aContext); if (str.EqualsLiteral("2d")) {
*out_type = CanvasContextType::Canvas2D;
return true;
}
if (aContextId.EqualsLiteral("2d")) { if (str.EqualsLiteral("experimental-webgl")) {
*out_type = CanvasContextType::WebGL1;
return true;
}
#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;
}
#endif
if (WebGL2Context::IsSupported()) {
if (str.EqualsLiteral("experimental-webgl2")) {
*out_type = CanvasContextType::WebGL2;
return true;
}
}
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); Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
nsRefPtr<CanvasRenderingContext2D> ctx = ret = new CanvasRenderingContext2D();
new CanvasRenderingContext2D(); break;
ctx->SetCanvasElement(this); case CanvasContextType::WebGL1:
ctx.forget(aContext);
return NS_OK;
}
if (WebGL2Context::IsSupported() &&
aContextId.EqualsLiteral("experimental-webgl2"))
{
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
nsRefPtr<WebGL2Context> ctx = WebGL2Context::Create();
if (ctx == nullptr) { ret = WebGL1Context::Create();
return NS_ERROR_NOT_IMPLEMENTED; if (!ret)
} return nullptr;
break;
ctx->SetCanvasElement(this); case CanvasContextType::WebGL2:
ctx.forget(aContext); Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
return NS_OK;
ret = WebGL2Context::Create();
if (!ret)
return nullptr;
break;
} }
MOZ_ASSERT(ret);
NS_ConvertUTF16toUTF8 ctxId(aContextId); ret->SetCanvasElement(canvas);
return ret.forget();
// 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;
}
}
nsCString ctxString("@mozilla.org/content/canvas-rendering-context;1?id=");
ctxString.Append(ctxId);
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;
}
if (NS_FAILED(rv)) {
*aContext = nullptr;
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
return NS_OK;
}
ctx->SetCanvasElement(this);
ctx.forget(aContext);
return NS_OK;
} }
nsresult nsresult
@ -720,65 +721,49 @@ HTMLCanvasElement::GetContext(const nsAString& aContextId,
nsISupports** aContext) nsISupports** aContext)
{ {
ErrorResult rv; ErrorResult rv;
*aContext = *aContext = GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
return rv.ErrorCode(); return rv.ErrorCode();
} }
static bool
IsContextIdWebGL(const nsAString& str)
{
return str.EqualsLiteral("webgl") ||
str.EqualsLiteral("experimental-webgl");
}
already_AddRefed<nsISupports> already_AddRefed<nsISupports>
HTMLCanvasElement::GetContext(JSContext* aCx, HTMLCanvasElement::GetContext(JSContext* aCx,
const nsAString& aContextId, const nsAString& aContextId,
JS::Handle<JS::Value> aContextOptions, JS::Handle<JS::Value> aContextOptions,
ErrorResult& rv) ErrorResult& rv)
{ {
if (mCurrentContextId.IsEmpty()) { CanvasContextType contextType;
rv = GetContextHelper(aContextId, getter_AddRefs(mCurrentContext)); if (!GetCanvasContextType(aContextId, &contextType))
if (rv.Failed() || !mCurrentContext) { return nullptr;
if (!mCurrentContext) {
// This canvas doesn't have a context yet.
nsRefPtr<nsICanvasRenderingContextInternal> context;
context = CreateContextForCanvas(contextType, this);
if (!context)
return nullptr; return nullptr;
}
// Ensure that the context participates in CC. Note that returning a // Ensure that the context participates in CC. Note that returning a
// CC participant from QI doesn't addref. // CC participant from QI doesn't addref.
nsXPCOMCycleCollectionParticipant *cp = nullptr; nsXPCOMCycleCollectionParticipant* cp = nullptr;
CallQueryInterface(mCurrentContext, &cp); CallQueryInterface(context, &cp);
if (!cp) { if (!cp) {
mCurrentContext = nullptr;
rv.Throw(NS_ERROR_FAILURE); rv.Throw(NS_ERROR_FAILURE);
return nullptr; return nullptr;
} }
mCurrentContext = context.forget();
mCurrentContextType = contextType;
rv = UpdateContext(aCx, aContextOptions); rv = UpdateContext(aCx, aContextOptions);
if (rv.Failed()) { if (rv.Failed()) {
rv = NS_OK; // See bug 645792 rv = NS_OK; // See bug 645792
return nullptr; return nullptr;
} }
mCurrentContextId.Assign(aContextId); } else {
} // We already have a context of some type.
if (contextType != mCurrentContextType)
if (!mCurrentContextId.Equals(aContextId)) { return nullptr;
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;
} }
nsCOMPtr<nsICanvasRenderingContextInternal> context = mCurrentContext; nsCOMPtr<nsICanvasRenderingContextInternal> context = mCurrentContext;
@ -798,22 +783,28 @@ HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
if (!aContextId.EqualsLiteral("2d")) if (!aContextId.EqualsLiteral("2d"))
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
if (mCurrentContextId.IsEmpty()) { CanvasContextType contextType = CanvasContextType::Canvas2D;
nsresult rv = GetContextHelper(aContextId, getter_AddRefs(mCurrentContext));
NS_ENSURE_SUCCESS(rv, rv); if (!mCurrentContext) {
if (!mCurrentContext) { // This canvas doesn't have a context yet.
nsRefPtr<nsICanvasRenderingContextInternal> context;
context = CreateContextForCanvas(contextType, this);
if (!context) {
*aContext = nullptr;
return NS_OK; return NS_OK;
} }
mCurrentContext = context;
mCurrentContext->SetIsIPC(true); mCurrentContext->SetIsIPC(true);
mCurrentContextType = contextType;
rv = UpdateContext(nullptr, JS::NullHandleValue); nsresult rv = UpdateContext(nullptr, JS::NullHandleValue);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} else {
mCurrentContextId.Assign(aContextId); // We already have a context of some type.
} else if (!mCurrentContextId.Equals(aContextId)) { if (contextType != mCurrentContextType)
//XXX eventually allow for more than one active context on a given canvas return NS_ERROR_INVALID_ARG;
return NS_ERROR_INVALID_ARG;
} }
NS_ADDREF (*aContext = mCurrentContext); NS_ADDREF (*aContext = mCurrentContext);
@ -831,21 +822,18 @@ HTMLCanvasElement::UpdateContext(JSContext* aCx, JS::Handle<JS::Value> aNewConte
nsresult rv = mCurrentContext->SetIsOpaque(HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque)); nsresult rv = mCurrentContext->SetIsOpaque(HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
mCurrentContext = nullptr; mCurrentContext = nullptr;
mCurrentContextId.Truncate();
return rv; return rv;
} }
rv = mCurrentContext->SetContextOptions(aCx, aNewContextOptions); rv = mCurrentContext->SetContextOptions(aCx, aNewContextOptions);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
mCurrentContext = nullptr; mCurrentContext = nullptr;
mCurrentContextId.Truncate();
return rv; return rv;
} }
rv = mCurrentContext->SetDimensions(sz.width, sz.height); rv = mCurrentContext->SetDimensions(sz.width, sz.height);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
mCurrentContext = nullptr; mCurrentContext = nullptr;
mCurrentContextId.Truncate();
return rv; return rv;
} }

View File

@ -7,6 +7,7 @@
#define mozilla_dom_HTMLCanvasElement_h #define mozilla_dom_HTMLCanvasElement_h
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/TypedEnum.h"
#include "nsIDOMHTMLCanvasElement.h" #include "nsIDOMHTMLCanvasElement.h"
#include "nsGenericHTMLElement.h" #include "nsGenericHTMLElement.h"
#include "nsGkAtoms.h" #include "nsGkAtoms.h"
@ -35,6 +36,12 @@ class FileCallback;
class HTMLCanvasPrintState; class HTMLCanvasPrintState;
class PrintCallback; class PrintCallback;
MOZ_BEGIN_ENUM_CLASS(CanvasContextType, uint8_t)
Canvas2D,
WebGL1,
WebGL2
MOZ_END_ENUM_CLASS(CanvasContextType)
class HTMLCanvasElement MOZ_FINAL : public nsGenericHTMLElement, class HTMLCanvasElement MOZ_FINAL : public nsGenericHTMLElement,
public nsIDOMHTMLCanvasElement public nsIDOMHTMLCanvasElement
{ {
@ -229,11 +236,9 @@ protected:
nsresult MozGetAsFileImpl(const nsAString& aName, nsresult MozGetAsFileImpl(const nsAString& aName,
const nsAString& aType, const nsAString& aType,
nsIDOMFile** aResult); nsIDOMFile** aResult);
nsresult GetContextHelper(const nsAString& aContextId,
nsICanvasRenderingContextInternal **aContext);
void CallPrintCallback(); void CallPrintCallback();
nsString mCurrentContextId; CanvasContextType mCurrentContextType;
nsRefPtr<HTMLCanvasElement> mOriginalCanvas; nsRefPtr<HTMLCanvasElement> mOriginalCanvas;
nsRefPtr<PrintCallback> mPrintCallback; nsRefPtr<PrintCallback> mPrintCallback;
nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext; nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;

View File

@ -1129,10 +1129,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
{ "@mozilla.org/content/post-content-iterator;1", &kNS_CONTENTITERATOR_CID }, { "@mozilla.org/content/post-content-iterator;1", &kNS_CONTENTITERATOR_CID },
{ "@mozilla.org/content/pre-content-iterator;1", &kNS_PRECONTENTITERATOR_CID }, { "@mozilla.org/content/pre-content-iterator;1", &kNS_PRECONTENTITERATOR_CID },
{ "@mozilla.org/content/subtree-content-iterator;1", &kNS_SUBTREEITERATOR_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 }, { "@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 "text/xml", &kNS_TEXT_ENCODER_CID },
{ NS_DOC_ENCODER_CONTRACTID_BASE "application/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 "application/xhtml+xml", &kNS_TEXT_ENCODER_CID },

View File

@ -29,7 +29,7 @@ GfxInfoWebGL::GetWebGLParameter(const nsAString& aParam, nsAString& aResult)
else return NS_ERROR_INVALID_ARG; else return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIDOMWebGLRenderingContext> webgl = 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) if (!webgl)
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;