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/. */
#include "WebGL1Context.h"
#include "mozilla/dom/WebGLRenderingContextBinding.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;
}

View File

@ -3,8 +3,8 @@
* 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"
@ -13,34 +13,23 @@ namespace mozilla {
class WebGL1Context
: public WebGLContext
{
// -----------------------------------------------------------------------------
// PUBLIC
public:
static WebGL1Context* Create();
// -------------------------------------------------------------------------
// CONSTRUCTOR & DESTRUCTOR
private:
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_

View File

@ -34,6 +34,7 @@
#include "nsNetUtil.h"
#include "nsStreamUtils.h"
#include "ActiveLayerTracker.h"
#include "WebGL1Context.h"
#include "WebGL2Context.h"
using namespace mozilla::layers;
@ -648,71 +649,71 @@ HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
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")) {
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);
nsRefPtr<CanvasRenderingContext2D> ctx =
new CanvasRenderingContext2D();
ret = new CanvasRenderingContext2D();
break;
ctx->SetCanvasElement(this);
ctx.forget(aContext);
return NS_OK;
}
if (WebGL2Context::IsSupported() &&
aContextId.EqualsLiteral("experimental-webgl2"))
{
case CanvasContextType::WebGL1:
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
nsRefPtr<WebGL2Context> ctx = WebGL2Context::Create();
if (ctx == nullptr) {
return NS_ERROR_NOT_IMPLEMENTED;
}
ret = WebGL1Context::Create();
if (!ret)
return nullptr;
break;
ctx->SetCanvasElement(this);
ctx.forget(aContext);
return NS_OK;
case CanvasContextType::WebGL2:
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
ret = WebGL2Context::Create();
if (!ret)
return nullptr;
break;
}
MOZ_ASSERT(ret);
NS_ConvertUTF16toUTF8 ctxId(aContextId);
// 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;
ret->SetCanvasElement(canvas);
return ret.forget();
}
nsresult
@ -720,65 +721,49 @@ 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;
@ -798,22 +783,28 @@ HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
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);
mCurrentContextType = contextType;
rv = UpdateContext(nullptr, JS::NullHandleValue);
nsresult rv = UpdateContext(nullptr, JS::NullHandleValue);
NS_ENSURE_SUCCESS(rv, rv);
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;
} else {
// We already have a context of some type.
if (contextType != mCurrentContextType)
return NS_ERROR_INVALID_ARG;
}
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));
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;
}

View File

@ -7,6 +7,7 @@
#define mozilla_dom_HTMLCanvasElement_h
#include "mozilla/Attributes.h"
#include "mozilla/TypedEnum.h"
#include "nsIDOMHTMLCanvasElement.h"
#include "nsGenericHTMLElement.h"
#include "nsGkAtoms.h"
@ -35,6 +36,12 @@ 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
{
@ -229,11 +236,9 @@ protected:
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;

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/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 },

View File

@ -29,7 +29,7 @@ GfxInfoWebGL::GetWebGLParameter(const nsAString& aParam, nsAString& aResult)
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;