Bug 1309913: Pass the compositor type to canvas on creation. r?dvander
MozReview-Commit-ID: F29GQbuXJgj
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1048,18 +1048,19 @@ NS_INTERFACE_MAP_END
// Initialize our static variables.
uint32_t CanvasRenderingContext2D::sNumLivingContexts = 0;
DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
-CanvasRenderingContext2D::CanvasRenderingContext2D()
+CanvasRenderingContext2D::CanvasRenderingContext2D(layers::LayersBackend aCompositorBackend)
: mRenderingMode(RenderingMode::OpenGLBackendMode)
+ , mCompositorBackend(aCompositorBackend)
// these are the default values from the Canvas spec
, mWidth(0), mHeight(0)
, mZero(false), mOpaque(false)
, mResetLayer(true)
, mIPC(false)
, mIsSkiaGL(false)
, mHasPendingStableStateCallback(false)
, mDrawObserver(nullptr)
@@ -1070,17 +1071,17 @@ CanvasRenderingContext2D::CanvasRenderin
, mInvalidateCount(0)
{
sNumLivingContexts++;
mShutdownObserver = new CanvasShutdownObserver(this);
nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
// The default is to use OpenGL mode
- if (gfxPlatform::GetPlatform()->AllowOpenGLCanvas()) {
+ if (AllowOpenGLCanvas()) {
mDrawObserver = new CanvasDrawObserver(this);
} else {
mRenderingMode = RenderingMode::SoftwareBackendMode;
}
}
CanvasRenderingContext2D::~CanvasRenderingContext2D()
{
@@ -1316,28 +1317,48 @@ CanvasRenderingContext2D::RedrawUser(con
++mInvalidateCount;
return;
}
gfx::Rect newr = mTarget->GetTransform().TransformBounds(ToRect(aR));
Redraw(newr);
}
+bool
+CanvasRenderingContext2D::AllowOpenGLCanvas() const
+{
+ // If we somehow didn't have the correct compositor in the constructor,
+ // we could do something like this to get it:
+ //
+ // HTMLCanvasElement* el = GetCanvas();
+ // if (el) {
+ // mCompositorBackend = el->GetCompositorBackendType();
+ // }
+ //
+ // We could have LAYERS_NONE if there was no widget at the time of
+ // canvas creation, but in that case the
+ // HTMLCanvasElement::GetCompositorBackendType would return LAYERS_NONE
+ // as well, so it wouldn't help much.
+
+ return (mCompositorBackend == LayersBackend::LAYERS_OPENGL) &&
+ gfxPlatform::GetPlatform()->AllowOpenGLCanvas();
+}
+
bool CanvasRenderingContext2D::SwitchRenderingMode(RenderingMode aRenderingMode)
{
if (!IsTargetValid() || mRenderingMode == aRenderingMode) {
return false;
}
MOZ_ASSERT(mBufferProvider);
#ifdef USE_SKIA_GPU
// Do not attempt to switch into GL mode if the platform doesn't allow it.
if ((aRenderingMode == RenderingMode::OpenGLBackendMode) &&
- !gfxPlatform::GetPlatform()->AllowOpenGLCanvas()) {
+ !AllowOpenGLCanvas()) {
return false;
}
#endif
RefPtr<PersistentBufferProvider> oldBufferProvider = mBufferProvider;
// Return the old target to the buffer provider.
// We need to do this before calling EnsureTarget.
@@ -1703,23 +1724,20 @@ LayerManagerFromCanvasElement(nsINode* a
bool
CanvasRenderingContext2D::TrySkiaGLTarget(RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider)
{
aOutDT = nullptr;
aOutProvider = nullptr;
-
mIsSkiaGL = false;
IntSize size(mWidth, mHeight);
- if (!gfxPlatform::GetPlatform()->AllowOpenGLCanvas() ||
- !CheckSizeForSkiaGL(size)) {
-
+ if (!AllowOpenGLCanvas() || !CheckSizeForSkiaGL(size)) {
return false;
}
RefPtr<LayerManager> layerManager = LayerManagerFromCanvasElement(mCanvasElement);
if (!layerManager) {
return false;
@@ -4755,17 +4773,17 @@ CanvasRenderingContext2D::DrawImage(cons
nsLayoutUtils::DirectDrawInfo drawInfo;
#ifdef USE_SKIA_GPU
if (mRenderingMode == RenderingMode::OpenGLBackendMode &&
mIsSkiaGL &&
!srcSurf &&
aImage.IsHTMLVideoElement() &&
- gfxPlatform::GetPlatform()->AllowOpenGLCanvas()) {
+ AllowOpenGLCanvas()) {
mozilla::gl::GLContext* gl = gfxPlatform::GetPlatform()->GetSkiaGLGlue()->GetGLContext();
MOZ_ASSERT(gl);
HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement();
if (!video) {
return;
}
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -61,23 +61,23 @@ class CanvasShutdownObserver;
**/
class CanvasRenderingContext2D final :
public nsICanvasRenderingContextInternal,
public nsWrapperCache
{
virtual ~CanvasRenderingContext2D();
public:
- CanvasRenderingContext2D();
+ explicit CanvasRenderingContext2D(layers::LayersBackend aCompositorBackend);
virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
HTMLCanvasElement* GetCanvas() const
{
- if (mCanvasElement->IsInNativeAnonymousSubtree()) {
+ if (!mCanvasElement || mCanvasElement->IsInNativeAnonymousSubtree()) {
return nullptr;
}
// corresponds to changes to the old bindings made in bug 745025
return mCanvasElement->GetOriginalCanvas();
}
void Save();
@@ -533,16 +533,20 @@ public:
// Given a point, return hit region ID if it exists
nsString GetHitRegion(const mozilla::gfx::Point& aPoint) override;
// return true and fills in the bound rect if element has a hit region.
bool GetHitRegionRect(Element* aElement, nsRect& aRect) override;
void OnShutdown();
+
+ // Check the global setup, as well as the compositor type:
+ bool AllowOpenGLCanvas() const;
+
protected:
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
uint32_t aWidth, uint32_t aHeight,
JSObject** aRetval);
nsresult PutImageData_explicit(int32_t aX, int32_t aY, uint32_t aW, uint32_t aH,
dom::Uint8ClampedArray* aArray,
bool aHasDirtyRect, int32_t aDirtyX, int32_t aDirtyY,
@@ -728,16 +732,18 @@ protected:
static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
static void DemoteOldestContextIfNecessary();
static void AddDemotableContext(CanvasRenderingContext2D* aContext);
static void RemoveDemotableContext(CanvasRenderingContext2D* aContext);
RenderingMode mRenderingMode;
+ layers::LayersBackend mCompositorBackend;
+
// Member vars
int32_t mWidth, mHeight;
// This is true when the canvas is valid, but of zero size, this requires
// specific behavior on some operations.
bool mZero;
bool mOpaque;
--- a/dom/canvas/CanvasRenderingContextHelper.cpp
+++ b/dom/canvas/CanvasRenderingContextHelper.cpp
@@ -118,26 +118,33 @@ CanvasRenderingContextHelper::ToBlob(JSC
format,
GetWidthHeight(),
callback);
}
already_AddRefed<nsICanvasRenderingContextInternal>
CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType)
{
+ return CreateContextHelper(aContextType, layers::LayersBackend::LAYERS_NONE);
+}
+
+already_AddRefed<nsICanvasRenderingContextInternal>
+CanvasRenderingContextHelper::CreateContextHelper(CanvasContextType aContextType,
+ layers::LayersBackend aCompositorBackend)
+{
MOZ_ASSERT(aContextType != CanvasContextType::NoContext);
RefPtr<nsICanvasRenderingContextInternal> ret;
switch (aContextType) {
case CanvasContextType::NoContext:
break;
case CanvasContextType::Canvas2D:
Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
- ret = new CanvasRenderingContext2D();
+ ret = new CanvasRenderingContext2D(aCompositorBackend);
break;
case CanvasContextType::WebGL1:
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
ret = WebGL1Context::Create();
if (!ret)
return nullptr;
--- a/dom/canvas/CanvasRenderingContextHelper.h
+++ b/dom/canvas/CanvasRenderingContextHelper.h
@@ -2,16 +2,17 @@
/* 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 MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_
#define MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_
#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/layers/LayersTypes.h"
#include "nsSize.h"
class nsICanvasRenderingContextInternal;
class nsIGlobalObject;
namespace mozilla {
class ErrorResult;
@@ -61,16 +62,20 @@ protected:
void ToBlob(JSContext* aCx, nsIGlobalObject* aGlobal, EncodeCompleteCallback* aCallback,
const nsAString& aType, JS::Handle<JS::Value> aParams,
ErrorResult& aRv);
virtual already_AddRefed<nsICanvasRenderingContextInternal>
CreateContext(CanvasContextType aContextType);
+ already_AddRefed<nsICanvasRenderingContextInternal>
+ CreateContextHelper(CanvasContextType aContextType,
+ layers::LayersBackend aCompositorBackend);
+
virtual nsIntSize GetWidthHeight() = 0;
CanvasContextType mCurrentContextType;
nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
};
} // namespace dom
} // namespace mozilla
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -395,18 +395,19 @@ NS_IMPL_ELEMENT_CLONE(HTMLCanvasElement)
HTMLCanvasElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return HTMLCanvasElementBinding::Wrap(aCx, this, aGivenProto);
}
already_AddRefed<nsICanvasRenderingContextInternal>
HTMLCanvasElement::CreateContext(CanvasContextType aContextType)
{
+ // Note that the compositor backend will be LAYERS_NONE if there is no widget.
RefPtr<nsICanvasRenderingContextInternal> ret =
- CanvasRenderingContextHelper::CreateContext(aContextType);
+ CreateContextHelper(aContextType, GetCompositorBackendType());
// Add Observer for webgl canvas.
if (aContextType == CanvasContextType::WebGL1 ||
aContextType == CanvasContextType::WebGL2) {
if (!mContextObserver) {
mContextObserver = new HTMLCanvasElementObserver(this);
}
}
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1251,20 +1251,25 @@ gfxPlatform::SupportsAzureContentForDraw
return SupportsAzureContentForType(aTarget->GetBackendType());
}
bool gfxPlatform::AllowOpenGLCanvas()
{
// For now, only allow Skia+OpenGL, unless it's blocked.
// Allow acceleration on Skia if the preference is set, unless it's blocked
// as long as we have the accelerated layers
- if (gfxPrefs::CanvasAzureAccelerated() &&
- mCompositorBackend == LayersBackend::LAYERS_OPENGL &&
- (GetContentBackendFor(mCompositorBackend) == BackendType::SKIA))
- {
+
+ // The compositor backend is only set correctly in the parent process,
+ // so we let content process always assume correct compositor backend.
+ // The callers have to do the right thing.
+ bool correctBackend = !XRE_IsParentProcess() ||
+ ((mCompositorBackend == LayersBackend::LAYERS_OPENGL) &&
+ (GetContentBackendFor(mCompositorBackend) == BackendType::SKIA));
+
+ if (gfxPrefs::CanvasAzureAccelerated() && correctBackend) {
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
int32_t status;
nsCString discardFailureId;
return !gfxInfo ||
(NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION,
discardFailureId,
&status)) &&
status == nsIGfxInfo::FEATURE_STATUS_OK);
--- a/layout/reftests/canvas/reftest.list
+++ b/layout/reftests/canvas/reftest.list
@@ -61,22 +61,20 @@ random-if(!d2d) != text-subpixel-1.html
## if they have an Emoji font installed when running the tests.)
## WAS: random-if(OSX==1007) != text-emoji.html text-emoji-notref.html
# With Skia canvas on OS X (bug 932958) it fails even on 10.8 and 10.10.
random-if(cocoaWidget&&azureSkia) random-if(!cocoaWidget||OSX==1006||OSX==1007) != text-emoji.html text-emoji-notref.html
# azure quartz uses CGDrawLinearGradient instead of DrawShading
# so we have less control over degenerate behaviour as tested by this
# test
-# This test should pass with SkiaGL, but due to bug 1309913, e10s prevents SkiaGL from working.
-fails-if((azureSkia&&!azureSkiaGL)||azureQuartz||(azureSkiaGL&&(browserIsRemote||Android))) == linear-gradient-1a.html linear-gradient-1-ref.html
+fails-if((azureSkia&&!azureSkiaGL)||azureQuartz||(azureSkiaGL&&Android)) == linear-gradient-1a.html linear-gradient-1-ref.html
# this passes with cairo on 10.7 and 10.8 but not with azure for reasons unknown
-# This test should pass with SkiaGL, but due to bug 1309913, e10s prevents SkiaGL from working.
-fails-if((azureSkia&&!azureSkiaGL)||azureQuartz||(azureSkiaGL&&(browserIsRemote||Android))) == linear-gradient-1b.html linear-gradient-1-ref.html
+fails-if((azureSkia&&!azureSkiaGL)||azureQuartz||(azureSkiaGL&&Android)) == linear-gradient-1b.html linear-gradient-1-ref.html
== zero-dimensions.html zero-dimensions-ref.html
!= evenodd-fill-1.html nonzero-fill-1.html
== evenodd-fill-1.html evenodd-fill-ref.html
== dash-sanity.html data:text/html,<body>Pass
fuzzy-if(azureSkia||skiaContent,9,470) random-if(Android) == dash-1.html dash-1-ref.svg # Bug 668412 (really is android-specific, not IPC-specific)