From e5b55a65aca3d54e926771a31610533070553b8d Mon Sep 17 00:00:00 2001 From: Nicholas Cameron Date: Thu, 26 Jul 2012 18:48:24 +1200 Subject: [PATCH] Back out bug 746883, bug 764125, bug 761895, bug 746883, bug 748116 --- .../src/nsCanvasRenderingContext2DAzure.cpp | 171 +++++------ .../src/nsCanvasRenderingContext2DAzure.h | 14 +- content/canvas/test/Makefile.in | 1 - content/canvas/test/test_bug764125.html | 36 --- content/canvas/test/test_canvas.html | 48 +-- gfx/2d/2D.h | 2 +- gfx/2d/DrawTargetCairo.cpp | 280 +++++------------- gfx/2d/DrawTargetCairo.h | 7 +- gfx/2d/Factory.cpp | 18 +- gfx/2d/HelpersSkia.h | 2 +- gfx/2d/PathCairo.cpp | 28 +- gfx/2d/PathCairo.h | 4 - gfx/2d/SourceSurfaceCairo.cpp | 1 - gfx/2d/Types.h | 2 +- gfx/layers/d3d10/LayerManagerD3D10.cpp | 5 +- gfx/layers/d3d9/CanvasLayerD3D9.cpp | 18 +- gfx/layers/opengl/CanvasLayerOGL.cpp | 14 +- gfx/thebes/gfxAndroidPlatform.cpp | 15 +- gfx/thebes/gfxAndroidPlatform.h | 4 +- gfx/thebes/gfxFont.cpp | 2 +- gfx/thebes/gfxFont.h | 3 +- gfx/thebes/gfxPlatform.cpp | 216 +++++--------- gfx/thebes/gfxPlatform.h | 65 ++-- gfx/thebes/gfxPlatformGtk.cpp | 22 +- gfx/thebes/gfxPlatformGtk.h | 4 +- gfx/thebes/gfxPlatformMac.cpp | 41 ++- gfx/thebes/gfxPlatformMac.h | 4 +- gfx/thebes/gfxQtPlatform.cpp | 7 + gfx/thebes/gfxQtPlatform.h | 2 + gfx/thebes/gfxWindowsPlatform.cpp | 90 +++--- gfx/thebes/gfxWindowsPlatform.h | 4 +- modules/libpref/src/init/all.js | 7 - widget/android/GfxInfo.cpp | 6 + widget/android/GfxInfo.h | 1 + widget/cocoa/GfxInfo.h | 1 + widget/cocoa/GfxInfo.mm | 14 + widget/nsIGfxInfo.idl | 1 + widget/windows/GfxInfo.cpp | 20 ++ widget/windows/GfxInfo.h | 1 + widget/windows/TaskbarPreview.cpp | 2 +- widget/xpwidgets/GfxInfoX11.cpp | 6 + widget/xpwidgets/GfxInfoX11.h | 1 + 42 files changed, 475 insertions(+), 715 deletions(-) delete mode 100644 content/canvas/test/test_bug764125.html diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp index 5c037ff45fff..2de4293bbebd 100644 --- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp @@ -549,11 +549,37 @@ PRUint8 (*nsCanvasRenderingContext2DAzure::sPremultiplyTable)[256] = nsnull; namespace mozilla { namespace dom { +static bool +AzureCanvasEnabledOnPlatform() +{ +#ifdef XP_WIN + if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() != + gfxWindowsPlatform::RENDER_DIRECT2D || + !gfxWindowsPlatform::GetPlatform()->DWriteEnabled()) { + static bool checkedPref = false; + static bool preferSkia; + if (!checkedPref) { + preferSkia = Preferences::GetBool("gfx.canvas.azure.prefer-skia", false); + checkedPref = true; + } + return preferSkia; + } +#elif !defined(XP_MACOSX) && !defined(ANDROID) && !defined(LINUX) + return false; +#endif + return true; +} + bool AzureCanvasEnabled() { - BackendType dontCare; - return gfxPlatform::GetPlatform()->SupportsAzureCanvas(dontCare); + static bool checkedPref = false; + static bool azureEnabled; + if (!checkedPref) { + azureEnabled = Preferences::GetBool("gfx.canvas.azure.enabled", false); + checkedPref = true; + } + return azureEnabled && AzureCanvasEnabledOnPlatform(); } } @@ -562,9 +588,7 @@ AzureCanvasEnabled() nsresult NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult) { - // XXX[nrc] remove this check when Thebes canvas is removed - // (because we will always support Azure) - if (!AzureCanvasEnabled()) { + if (!AzureCanvasEnabledOnPlatform()) { return NS_ERROR_NOT_AVAILABLE; } @@ -890,12 +914,30 @@ nsCanvasRenderingContext2DAzure::SetDimensions(PRInt32 width, PRInt32 height) } nsresult -nsCanvasRenderingContext2DAzure::Initialize(PRInt32 width, PRInt32 height) +nsCanvasRenderingContext2DAzure::InitializeWithTarget(DrawTarget *target, PRInt32 width, PRInt32 height) { + Reset(); + + NS_ASSERTION(mCanvasElement, "Must have a canvas element!"); + mDocShell = nsnull; + mWidth = width; mHeight = height; - if (!mValid) { + // This first time this is called on this object is via + // nsHTMLCanvasElement::GetContext. If target was non-null then mTarget is + // non-null, otherwise we'll return an error here and GetContext won't + // return this context object and we'll never enter this code again. + // All other times this method is called, if target is null then + // mTarget won't be changed, i.e. it will remain non-null, or else it + // will be set to non-null. + // In all cases, any usable canvas context will have non-null mTarget. + + if (target) { + mValid = true; + mTarget = target; + } else { + mValid = false; // Create a dummy target in the hopes that it will help us deal with users // calling into us after having changed the size where the size resulted // in an inability to create a correct DrawTarget. @@ -927,45 +969,6 @@ nsCanvasRenderingContext2DAzure::Initialize(PRInt32 width, PRInt32 height) return mValid ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } -nsresult -nsCanvasRenderingContext2DAzure::InitializeWithTarget(DrawTarget *target, PRInt32 width, PRInt32 height) -{ - Reset(); - - NS_ASSERTION(mCanvasElement, "Must have a canvas element!"); - mDocShell = nsnull; - - // This first time this is called on this object is via - // nsHTMLCanvasElement::GetContext. If target was non-null then mTarget is - // non-null, otherwise we'll return an error here and GetContext won't - // return this context object and we'll never enter this code again. - // All other times this method is called, if target is null then - // mTarget won't be changed, i.e. it will remain non-null, or else it - // will be set to non-null. - // In all cases, any usable canvas context will have non-null mTarget. - - if (target) { - mValid = true; - mTarget = target; - } else { - mValid = false; - } - - return Initialize(width, height); -} - -NS_IMETHODIMP -nsCanvasRenderingContext2DAzure::InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height) -{ - mDocShell = shell; - mThebesSurface = surface; - - mTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surface, IntSize(width, height)); - mValid = mTarget != nsnull; - - return Initialize(width, height); -} - NS_IMETHODIMP nsCanvasRenderingContext2DAzure::SetIsOpaque(bool isOpaque) { @@ -2490,7 +2493,6 @@ nsCanvasRenderingContext2DAzure::EnsureWritablePath() } if (!mPath) { - NS_ASSERTION(!mPathTransformWillUpdate, "mPathTransformWillUpdate should be false, if all paths are null"); mPathBuilder = mTarget->CreatePathBuilder(fillRule); } else if (!mPathTransformWillUpdate) { mPathBuilder = mPath->CopyToBuilder(fillRule); @@ -2502,7 +2504,7 @@ nsCanvasRenderingContext2DAzure::EnsureWritablePath() } void -nsCanvasRenderingContext2DAzure::EnsureUserSpacePath(bool aCommitTransform /* = true */) +nsCanvasRenderingContext2DAzure::EnsureUserSpacePath() { FillRule fillRule = CurrentState().fillRule; @@ -2515,9 +2517,7 @@ nsCanvasRenderingContext2DAzure::EnsureUserSpacePath(bool aCommitTransform /* = mPathBuilder = nsnull; } - if (aCommitTransform && - mPath && - mPathTransformWillUpdate) { + if (mPath && mPathTransformWillUpdate) { mDSPathBuilder = mPath->TransformedCopyToBuilder(mPathToDS, fillRule); mPath = nsnull; @@ -2531,7 +2531,6 @@ nsCanvasRenderingContext2DAzure::EnsureUserSpacePath(bool aCommitTransform /* = Matrix inverse = mTarget->GetTransform(); if (!inverse.Invert()) { - NS_WARNING("Could not invert transform"); return; } @@ -2545,8 +2544,6 @@ nsCanvasRenderingContext2DAzure::EnsureUserSpacePath(bool aCommitTransform /* = mPathBuilder = mPath->CopyToBuilder(fillRule); mPath = mPathBuilder->Finish(); } - - NS_ASSERTION(mPath, "mPath should exist"); } void @@ -3047,7 +3044,7 @@ struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiP const gfxTextRun::CompressedGlyph *glyphs = mTextRun->GetCharacterGlyphs(); RefPtr scaledFont = - gfxPlatform::GetPlatform()->GetScaledFontForFont(mCtx->mTarget, font); + gfxPlatform::GetPlatform()->GetScaledFontForFont(font); if (!scaledFont) { // This can occur when something switched DirectWrite off. @@ -3107,21 +3104,21 @@ struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiP AdjustedTarget(mCtx)-> FillGlyphs(scaledFont, buffer, CanvasGeneralPattern(). - ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_FILL, mCtx->mTarget), - DrawOptions(mState->globalAlpha, mCtx->UsedOperation())); + ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_FILL, mCtx->mTarget), + DrawOptions(mState->globalAlpha, mCtx->UsedOperation())); } else if (mOp == nsCanvasRenderingContext2DAzure::TEXT_DRAW_OPERATION_STROKE) { RefPtr path = scaledFont->GetPathForGlyphs(buffer, mCtx->mTarget); const ContextState& state = *mState; AdjustedTarget(mCtx)-> Stroke(path, CanvasGeneralPattern(). - ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_STROKE, mCtx->mTarget), - StrokeOptions(state.lineWidth, state.lineJoin, - state.lineCap, state.miterLimit, - state.dash.Length(), - state.dash.Elements(), - state.dashOffset), - DrawOptions(state.globalAlpha, mCtx->UsedOperation())); + ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_STROKE, mCtx->mTarget), + StrokeOptions(state.lineWidth, state.lineJoin, + state.lineCap, state.miterLimit, + state.dash.Length(), + state.dash.Elements(), + state.dashOffset), + DrawOptions(state.globalAlpha, mCtx->UsedOperation())); } } @@ -3610,14 +3607,9 @@ nsCanvasRenderingContext2DAzure::IsPointInPath(double x, double y) return false; } - EnsureUserSpacePath(false); - if (!mPath) { - return false; - } - if (mPathTransformWillUpdate) { - return mPath->ContainsPoint(Point(x, y), mPathToDS); - } - return mPath->ContainsPoint(Point(x, y), mTarget->GetTransform()); + EnsureUserSpacePath(); + + return mPath && mPath->ContainsPoint(Point(x, y), mTarget->GetTransform()); } NS_IMETHODIMP @@ -3676,14 +3668,12 @@ nsCanvasRenderingContext2DAzure::DrawImage(const HTMLImageOrCanvasOrVideoElement // This might not be an Azure canvas! srcSurf = srcCanvas->GetSurfaceSnapshot(); - if (srcSurf) { - if (mCanvasElement) { - // Do security check here. - CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement, - element->NodePrincipal(), - canvas->IsWriteOnly(), - false); - } + if (srcSurf && mCanvasElement) { + // Do security check here. + CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement, + element->NodePrincipal(), + canvas->IsWriteOnly(), + false); imgSize = gfxIntSize(srcSurf->GetSize().width, srcSurf->GetSize().height); } } @@ -4265,12 +4255,11 @@ nsCanvasRenderingContext2DAzure::GetImageDataArray(JSContext* aCx, RefPtr readback; if (!srcReadRect.IsEmpty()) { RefPtr snapshot = mTarget->Snapshot(); - if (snapshot) { - readback = snapshot->GetDataSurface(); - srcStride = readback->Stride(); - src = readback->GetData() + srcReadRect.y * srcStride + srcReadRect.x * 4; - } + readback = snapshot->GetDataSurface(); + + srcStride = readback->Stride(); + src = readback->GetData() + srcReadRect.y * srcStride + srcReadRect.x * 4; } // make sure sUnpremultiplyTable has been created @@ -4278,8 +4267,6 @@ nsCanvasRenderingContext2DAzure::GetImageDataArray(JSContext* aCx, // NOTE! dst is the same as src, and this relies on reading // from src and advancing that ptr before writing to dst. - // NOTE! I'm not sure that it is, I think this comment might have been - // inherited from Thebes canvas and is no longer true uint8_t* dst = data + dstWriteRect.y * (aWidth * 4) + dstWriteRect.x * 4; for (int32_t j = 0; j < dstWriteRect.height; ++j) { @@ -4611,8 +4598,8 @@ static PRUint8 g2DContextLayerUserData; already_AddRefed nsCanvasRenderingContext2DAzure::GetCanvasLayer(nsDisplayListBuilder* aBuilder, - CanvasLayer *aOldLayer, - LayerManager *aManager) + CanvasLayer *aOldLayer, + LayerManager *aManager) { if (!mValid) { return nsnull; @@ -4682,9 +4669,3 @@ nsCanvasRenderingContext2DAzure::MarkContextClean() mInvalidateCount = 0; } - -bool -nsCanvasRenderingContext2DAzure::ShouldForceInactiveLayer(LayerManager *aManager) -{ - return !aManager->CanUseCanvasLayerForSize(gfxIntSize(mWidth, mHeight)); -} diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.h b/content/canvas/src/nsCanvasRenderingContext2DAzure.h index 36086da20a6e..b1b7602c95d4 100644 --- a/content/canvas/src/nsCanvasRenderingContext2DAzure.h +++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.h @@ -464,7 +464,8 @@ public: // nsICanvasRenderingContextInternal NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height); - NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height); + NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height) + { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter, @@ -482,7 +483,6 @@ public: already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, CanvasLayer *aOldLayer, LayerManager *aManager); - virtual bool ShouldForceInactiveLayer(LayerManager *aManager); void MarkContextClean(); NS_IMETHOD SetIsIPC(bool isIPC); // this rect is in canvas device space @@ -542,11 +542,6 @@ protected: uint32_t aWidth, uint32_t aHeight, JSObject** aRetval); - /** - * Internal method to complete initialisation, expects mTarget to have been set - */ - nsresult Initialize(PRInt32 width, PRInt32 height); - nsresult InitializeWithTarget(mozilla::gfx::DrawTarget *surface, PRInt32 width, PRInt32 height); @@ -601,14 +596,11 @@ protected: /* This function ensures there is a writable pathbuilder available, this * pathbuilder may be working in user space or in device space or * device space. - * After calling this function mPathTransformWillUpdate will be false */ void EnsureWritablePath(); // Ensures a path in UserSpace is available. - // If aCommitTransform is true, then any transform on the context will be - // used for the path. - void EnsureUserSpacePath(bool aCommitTransform = true); + void EnsureUserSpacePath(); void TransformWillUpdate(); diff --git a/content/canvas/test/Makefile.in b/content/canvas/test/Makefile.in index 65edc5ac57ac..711f748b86b6 100644 --- a/content/canvas/test/Makefile.in +++ b/content/canvas/test/Makefile.in @@ -55,7 +55,6 @@ MOCHITEST_FILES = \ test_canvas_strokeStyle_getter.html \ test_bug613794.html \ test_bug753758.html \ - test_bug764125.html \ test_drawImage_edge_cases.html \ $(NULL) diff --git a/content/canvas/test/test_bug764125.html b/content/canvas/test/test_bug764125.html deleted file mode 100644 index 5b15c0ea85de..000000000000 --- a/content/canvas/test/test_bug764125.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Test for Bug 764125 - - - - -Mozilla Bug 764125 -

- -
-
-
- - diff --git a/content/canvas/test/test_canvas.html b/content/canvas/test/test_canvas.html index 967024618076..a7dd554c4c0e 100644 --- a/content/canvas/test/test_canvas.html +++ b/content/canvas/test/test_canvas.html @@ -18,10 +18,6 @@ function IsD2DEnabled() { return enabled; } -function IsLinux() { - return navigator.platform.indexOf("Linux") == 0; -} - function IsMacOSX10_5orOlder() { var is105orOlder = false; @@ -44,8 +40,7 @@ function IsAzureEnabled() { try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureBackend; - enabled = (backend != "none"); + enabled = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).AzureEnabled; } catch (e) { } return enabled; @@ -63,18 +58,6 @@ function IsAzureSkia() { return enabled; } -function IsAzureCairo() { - var enabled = false; - - try { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureBackend; - enabled = (backend == "cairo"); - } catch (e) { } - - return enabled; -} - @@ -11312,24 +11295,10 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); isPixel(ctx, 1,1, 0,255,0,255, 0); isPixel(ctx, 98,1, 0,255,0,255, 0); isPixel(ctx, 1,48, 0,255,0,255, 0); -// Fails on Linux with Azure/Cairo only -// The arc is drawn badly due to Cairo limitations, the error only becomes -// apparent on Linux because of anti-aliasing, probably due to X. -// The limitation is that Cairo draws arcs by stroking perpendicular to the arc, -// and at very large stroke thicknesses, this becomes a fan. Where exactly the -// 'blades' of the fan appear seems to depend on exactly how the arc is defined -// and the platform. So if the blades of the fan are where pixels are tested it -// passes the test, if the testing pixels fall in between the blades, then we fail. -// With Thebes/Cairo, we were rendering wrong, but got lucky with the test, now -// we are not so lucky. -// Bug 764125 -if (IsAzureCairo() && IsLinux()) { - todo_isPixel(ctx, 20,48, 0,255,0,255, 0); -} else { - isPixel(ctx, 20,48, 0,255,0,255, 0); -} +isPixel(ctx, 20,48, 0,255,0,255, 0); isPixel(ctx, 98,48, 0,255,0,255, 0); + } @@ -14688,14 +14657,9 @@ isPixel(ctx, 0,25, 0,255,0,255, 0); isPixel(ctx, 50,25, 0,255,0,255, 0); isPixel(ctx, 99,25, 0,255,0,255, 0); isPixel(ctx, 0,49, 0,255,0,255, 0); -if (IsAzureEnabled() && IsAzureCairo()) { - // Bug 764108 - todo_isPixel(ctx, 50,49, 0,255,0,255, 0); - todo_isPixel(ctx, 99,49, 0,255,0,255, 0); -} else { - isPixel(ctx, 50,49, 0,255,0,255, 0); - isPixel(ctx, 99,49, 0,255,0,255, 0); -} +isPixel(ctx, 50,49, 0,255,0,255, 0); +isPixel(ctx, 99,49, 0,255,0,255, 0); + } diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 093481e85cad..73b17888cf03 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -802,7 +802,7 @@ class GFX2D_API Factory public: static bool HasSSE2(); - static TemporaryRef CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize); + static TemporaryRef CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface); static TemporaryRef CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat); diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp index c36d30358704..972d8fe54091 100644 --- a/gfx/2d/DrawTargetCairo.cpp +++ b/gfx/2d/DrawTargetCairo.cpp @@ -13,8 +13,6 @@ #include "cairo.h" #include "Blur.h" -#include "Logging.h" -#include "Tools.h" #ifdef CAIRO_HAS_QUARTZ_SURFACE #include "cairo-quartz.h" @@ -118,51 +116,6 @@ PatternIsCompatible(const Pattern& aPattern) } } -static cairo_user_data_key_t surfaceDataKey; - -void -ReleaseData(void* aData) -{ - static_cast(aData)->Release(); -} - -/** - * Returns cairo surface for the given SourceSurface. - * If possible, it will use the cairo_surface associated with aSurface, - * otherwise, it will create a new cairo_surface. - * In either case, the caller must call cairo_surface_destroy on the - * result when it is done with it. - */ -cairo_surface_t* -GetCairoSurfaceForSourceSurface(SourceSurface *aSurface) -{ - if (aSurface->GetType() == SURFACE_CAIRO) { - cairo_surface_t* surf = static_cast(aSurface)->GetSurface(); - cairo_surface_reference(surf); - return surf; - } - - if (aSurface->GetType() == SURFACE_CAIRO_IMAGE) { - cairo_surface_t* surf = - static_cast(aSurface)->GetSurface(); - cairo_surface_reference(surf); - return surf; - } - - RefPtr data = aSurface->GetDataSurface(); - cairo_surface_t* surf = - cairo_image_surface_create_for_data(data->GetData(), - GfxFormatToCairoFormat(data->GetFormat()), - data->GetSize().width, - data->GetSize().height, - data->Stride()); - cairo_surface_set_user_data(surf, - &surfaceDataKey, - data.forget().drop(), - ReleaseData); - return surf; -} - // Never returns NULL. As such, you must always pass in Cairo-compatible // patterns, most notably gradients with a GradientStopCairo. // The pattern returned must have cairo_pattern_destroy() called on it by the @@ -187,7 +140,28 @@ GfxPatternToCairoPattern(const Pattern& aPattern, Float aAlpha) case PATTERN_SURFACE: { const SurfacePattern& pattern = static_cast(aPattern); - cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(pattern.mSurface); + cairo_surface_t* surf; + + // After this block, |surf| always has an extra cairo reference to be + // destroyed. This makes creating new surfaces or reusing old ones more + // uniform. + if (pattern.mSurface->GetType() == SURFACE_CAIRO) { + const SourceSurfaceCairo* source = static_cast(pattern.mSurface.get()); + surf = source->GetSurface(); + cairo_surface_reference(surf); + } else if (pattern.mSurface->GetType() == SURFACE_CAIRO_IMAGE) { + const DataSourceSurfaceCairo* source = + static_cast(pattern.mSurface.get()); + surf = source->GetSurface(); + cairo_surface_reference(surf); + } else { + RefPtr source = pattern.mSurface->GetDataSurface(); + surf = cairo_image_surface_create_for_data(source->GetData(), + GfxFormatToCairoFormat(source->GetFormat()), + source->GetSize().width, + source->GetSize().height, + source->Stride()); + } pat = cairo_pattern_create_for_surface(surf); cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(pattern.mFilter)); @@ -244,21 +218,6 @@ GfxPatternToCairoPattern(const Pattern& aPattern, Float aAlpha) return pat; } -/** - * Returns true iff the the given operator should affect areas of the - * destination where the source is transparent. Among other things, this - * implies that a fully transparent source would still affect the canvas. - */ -static bool -OperatorAffectsUncoveredAreas(CompositionOp op) -{ - return op == OP_IN || - op == OP_OUT || - op == OP_DEST_IN || - op == OP_DEST_ATOP || - op == OP_DEST_OUT; -} - static bool NeedIntermediateSurface(const Pattern& aPattern, const DrawOptions& aOptions) { @@ -285,28 +244,29 @@ DrawTargetCairo::~DrawTargetCairo() mPathObserver->ForgetDrawTarget(); } cairo_destroy(mContext); - if (mSurface) { - cairo_surface_destroy(mSurface); - } } IntSize DrawTargetCairo::GetSize() { - return mSize; + return IntSize(); } TemporaryRef DrawTargetCairo::Snapshot() { - IntSize size = GetSize(); + cairo_surface_t* csurf = cairo_get_target(mContext); + IntSize size; + if (GetCairoSurfaceSize(csurf, size)) { + cairo_content_t content = cairo_surface_get_content(csurf); + RefPtr surf = new SourceSurfaceCairo(csurf, size, + CairoContentToGfxFormat(content), + this); + AppendSnapshot(surf); + return surf; + } - cairo_content_t content = cairo_surface_get_content(mSurface); - RefPtr surf = new SourceSurfaceCairo(mSurface, size, - CairoContentToGfxFormat(content), - this); - AppendSnapshot(surf); - return surf; + return NULL; } void @@ -335,40 +295,29 @@ DrawTargetCairo::DrawSurface(SourceSurface *aSurface, float sy = aSource.Height() / aDest.Height(); cairo_matrix_t src_mat; - cairo_matrix_init_translate(&src_mat, aSource.X(), aSource.Y()); - cairo_matrix_scale(&src_mat, sx, sy); + cairo_matrix_init_scale(&src_mat, sx, sy); + cairo_matrix_translate(&src_mat, aSource.X(), aSource.Y()); + + cairo_surface_t* surf = NULL; + if (aSurface->GetType() == SURFACE_CAIRO) { + surf = static_cast(aSurface)->GetSurface(); + } - cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(aSurface); cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf); - cairo_surface_destroy(surf); - cairo_pattern_set_matrix(pat, &src_mat); cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(aSurfOptions.mFilter)); - cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD); cairo_save(mContext); - cairo_translate(mContext, aDest.X(), aDest.Y()); - - if (OperatorAffectsUncoveredAreas(aOptions.mCompositionOp) || - aOptions.mCompositionOp == OP_SOURCE) { - cairo_push_group(mContext); - cairo_new_path(mContext); - cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height()); - //TODO[nrc] remove comments if test ok - //cairo_clip(mContext); - cairo_set_source(mContext, pat); - //cairo_paint(mContext); - cairo_fill(mContext); - cairo_pop_group_to_source(mContext); - } else { - cairo_new_path(mContext); - cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height()); - cairo_clip(mContext); - cairo_set_source(mContext, pat); - } cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); + cairo_translate(mContext, aDest.X(), aDest.Y()); + + cairo_set_source(mContext, pat); + + cairo_new_path(mContext); + cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height()); + cairo_clip(mContext); cairo_paint_with_alpha(mContext, aOptions.mAlpha); cairo_restore(mContext); @@ -384,11 +333,13 @@ DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface, Float aSigma, CompositionOp aOperator) { + WillChange(); + if (aSurface->GetType() != SURFACE_CAIRO) { return; } - WillChange(); + SourceSurfaceCairo* source = static_cast(aSurface); Float width = aSurface->GetSize().width; Float height = aSurface->GetSize().height; @@ -402,19 +353,16 @@ DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface, } IntSize blursize = blur.GetSize(); + cairo_surface_t* blursurf = cairo_image_surface_create_for_data(blur.GetData(), CAIRO_FORMAT_A8, blursize.width, blursize.height, blur.GetStride()); - ClearSurfaceForUnboundedSource(aOperator); - // Draw the source surface into the surface we're going to blur. - SourceSurfaceCairo* source = static_cast(aSurface); cairo_surface_t* surf = source->GetSurface(); cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf); - cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD); cairo_t* ctx = cairo_create(blursurf); @@ -431,39 +379,26 @@ DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface, // Blur the result, then use that blurred result as a mask to draw the shadow // colour to the surface. blur.Blur(); + cairo_save(mContext); - cairo_set_operator(mContext, GfxOpToCairoOp(aOperator)); + + cairo_set_operator(mContext, CAIRO_OPERATOR_OVER); + cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a); + cairo_identity_matrix(mContext); cairo_translate(mContext, aDest.x, aDest.y); - if (OperatorAffectsUncoveredAreas(aOperator) || - aOperator == OP_SOURCE){ - cairo_push_group(mContext); - cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a); - cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y); - cairo_pop_group_to_source(mContext); - cairo_paint(mContext); + cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y); - // Now that the shadow has been drawn, we can draw the surface on top. - cairo_push_group(mContext); - cairo_new_path(mContext); - cairo_rectangle(mContext, 0, 0, width, height); - //TODO[nrc] remove comments if test ok - //cairo_clip(mContext); - cairo_set_source(mContext, pat); - //cairo_paint(mContext); - cairo_fill(mContext); - cairo_pop_group_to_source(mContext); - } else { - cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a); - cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y); + // Now that the shadow has been drawn, we can draw the surface on top. - // Now that the shadow has been drawn, we can draw the surface on top. - cairo_set_source(mContext, pat); - cairo_new_path(mContext); - cairo_rectangle(mContext, 0, 0, width, height); - cairo_clip(mContext); - } + cairo_set_operator(mContext, GfxOpToCairoOp(aOperator)); + + cairo_set_source(mContext, pat); + + cairo_new_path(mContext); + cairo_rectangle(mContext, 0, 0, width, height); + cairo_clip(mContext); cairo_paint(mContext); @@ -485,12 +420,9 @@ DrawTargetCairo::DrawPattern(const Pattern& aPattern, cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha); cairo_set_source(mContext, pat); - if (NeedIntermediateSurface(aPattern, aOptions) || - OperatorAffectsUncoveredAreas(aOptions.mCompositionOp)) { + if (NeedIntermediateSurface(aPattern, aOptions)) { cairo_push_group_with_content(mContext, CAIRO_CONTENT_COLOR_ALPHA); - ClearSurfaceForUnboundedSource(aOptions.mCompositionOp); - // Don't want operators to be applied twice cairo_set_operator(mContext, CAIRO_OPERATOR_OVER); @@ -507,7 +439,6 @@ DrawTargetCairo::DrawPattern(const Pattern& aPattern, cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); cairo_paint_with_alpha(mContext, aOptions.mAlpha); } else { - ClearSurfaceForUnboundedSource(aOptions.mCompositionOp); cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); if (aDrawType == DRAW_STROKE) { @@ -536,31 +467,10 @@ DrawTargetCairo::FillRect(const Rect &aRect, void DrawTargetCairo::CopySurface(SourceSurface *aSurface, - const IntRect &aSource, - const IntPoint &aDest) + const IntRect &aSourceRect, + const IntPoint &aDestination) { AutoPrepareForDrawing prep(this, mContext); - - if (!aSurface || aSurface->GetType() != SURFACE_CAIRO) { - gfxWarning() << "Unsupported surface type specified"; - return; - } - - cairo_surface_t* surf = static_cast(aSurface)->GetSurface(); - - cairo_save(mContext); - - cairo_identity_matrix(mContext); - - cairo_set_source_surface(mContext, surf, aDest.x - aSource.x, aDest.y - aSource.y); - cairo_set_operator(mContext, CAIRO_OPERATOR_SOURCE); - - cairo_reset_clip(mContext); - cairo_new_path(mContext); - cairo_rectangle(mContext, aDest.x, aDest.y, aSource.width, aSource.height); - cairo_fill(mContext); - - cairo_restore(mContext); } void @@ -726,19 +636,6 @@ DrawTargetCairo::CreatePathBuilder(FillRule aFillRule /* = FILL_WINDING */) cons return builder; } -void -DrawTargetCairo::ClearSurfaceForUnboundedSource(const CompositionOp &aOperator) -{ - if (aOperator != OP_SOURCE) - return; - cairo_set_operator(mContext, CAIRO_OPERATOR_CLEAR); - // It doesn't really matter what the source is here, since Paint - // isn't bounded by the source and the mask covers the entire clip - // region. - cairo_paint(mContext); -} - - TemporaryRef DrawTargetCairo::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode) const { @@ -746,40 +643,19 @@ DrawTargetCairo::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, E return stops; } -/** - * Copies pixel data from aData into aSurface; aData must have the dimensions - * given in aSize, with a stride of aStride bytes and aPixelWidth bytes per pixel - */ -static void -CopyDataToCairoSurface(cairo_surface_t* aSurface, - unsigned char *aData, - const IntSize &aSize, - int32_t aStride, - int32_t aPixelWidth) -{ - unsigned char* surfData = cairo_image_surface_get_data(aSurface); - for (int32_t y = 0; y < aSize.height; ++y) { - memcpy(surfData + y * aSize.width * aPixelWidth, - aData + y * aStride, - aSize.width * aPixelWidth); - } - cairo_surface_mark_dirty(aSurface); -} - TemporaryRef DrawTargetCairo::CreateSourceSurfaceFromData(unsigned char *aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat) const { - cairo_surface_t* surf = cairo_image_surface_create(GfxFormatToCairoFormat(aFormat), - aSize.width, - aSize.height); - CopyDataToCairoSurface(surf, aData, aSize, aStride, BytesPerPixel(aFormat)); - + cairo_surface_t* surf = cairo_image_surface_create_for_data(aData, + GfxFormatToCairoFormat(aFormat), + aSize.width, + aSize.height, + aStride); RefPtr source_surf = new SourceSurfaceCairo(surf, aSize, aFormat); cairo_surface_destroy(surf); - return source_surf; } @@ -814,7 +690,7 @@ DrawTargetCairo::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFo if (!cairo_surface_status(similar)) { RefPtr target = new DrawTargetCairo(); - target->Init(similar, aSize); + target->Init(similar); return target; } @@ -822,13 +698,9 @@ DrawTargetCairo::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFo } bool -DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize) +DrawTargetCairo::Init(cairo_surface_t* aSurface) { mContext = cairo_create(aSurface); - mSurface = aSurface; - cairo_surface_reference(mSurface); - mSize = aSize; - mFormat = CairoContentToGfxFormat(cairo_surface_get_content(aSurface)); return true; } diff --git a/gfx/2d/DrawTargetCairo.h b/gfx/2d/DrawTargetCairo.h index d5369ba3e592..8d409bb44168 100644 --- a/gfx/2d/DrawTargetCairo.h +++ b/gfx/2d/DrawTargetCairo.h @@ -123,7 +123,7 @@ public: virtual void *GetNativeSurface(NativeSurfaceType aType); - bool Init(cairo_surface_t* aSurface, const IntSize& aSize); + bool Init(cairo_surface_t* aSurface); void SetPathObserver(CairoPathContext* aPathObserver); @@ -155,13 +155,8 @@ private: // methods // target; for example, because we're going to be destroyed. void MarkSnapshotsIndependent(); - // If the current operator is "source" then clear the destination before we - // draw into it, to simulate the effect of an unbounded source operator. - void ClearSurfaceForUnboundedSource(const CompositionOp &aOperator); private: // data cairo_t* mContext; - cairo_surface_t* mSurface; - IntSize mSize; std::vector mSnapshots; mutable RefPtr mPathObserver; }; diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index 71174a76807c..7e5d4e098779 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -239,10 +239,6 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz { return new ScaledFontDWrite(static_cast(aNativeFont.mFont), aSize); } - case NATIVE_FONT_GDI_FONT_FACE: - { - return new ScaledFontWin(static_cast(aNativeFont.mFont), aSize); - } #endif #ifdef XP_MACOSX case NATIVE_FONT_MAC_FONT_FACE: @@ -251,6 +247,12 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz } #endif #ifdef USE_SKIA +#ifdef WIN32 + case NATIVE_FONT_GDI_FONT_FACE: + { + return new ScaledFontWin(static_cast(aNativeFont.mFont), aSize); + } +#endif #ifdef MOZ_ENABLE_FREETYPE case NATIVE_FONT_SKIA_FONT_FACE: { @@ -261,9 +263,7 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz #ifdef USE_CAIRO case NATIVE_FONT_CAIRO_FONT_FACE: { - ScaledFontBase* fontBase = new ScaledFontBase(aSize); - fontBase->SetCairoScaledFont(static_cast(aNativeFont.mFont)); - return fontBase; + return new ScaledFontBase(aSize); } #endif default: @@ -367,11 +367,11 @@ Factory::GetD2DVRAMUsageSourceSurface() #endif // XP_WIN TemporaryRef -Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize) +Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface) { #ifdef USE_CAIRO RefPtr newTarget = new DrawTargetCairo(); - if (newTarget->Init(aSurface, aSize)) { + if (newTarget->Init(aSurface)) { return newTarget; } diff --git a/gfx/2d/HelpersSkia.h b/gfx/2d/HelpersSkia.h index 6e22c5935bda..38ab0900f113 100644 --- a/gfx/2d/HelpersSkia.h +++ b/gfx/2d/HelpersSkia.h @@ -76,7 +76,7 @@ JoinStyleToSkiaJoin(JoinStyle aJoin) static inline bool StrokeOptionsToPaint(SkPaint& aPaint, const StrokeOptions &aOptions) { - // Skia renders 0 width strokes with a width of 1 (and in black), + // Skia rendewrs 0 width strokes with a width of 1 (and in black), // so we should just skip the draw call entirely. if (!aOptions.mLineWidth) { return false; diff --git a/gfx/2d/PathCairo.cpp b/gfx/2d/PathCairo.cpp index 87e06d9d2183..1d92d27b94e2 100644 --- a/gfx/2d/PathCairo.cpp +++ b/gfx/2d/PathCairo.cpp @@ -44,28 +44,6 @@ CairoPathContext::~CairoPathContext() cairo_destroy(mContext); } -void -CairoPathContext::ObserveTarget(DrawTargetCairo* aDrawTarget) -{ - if (!aDrawTarget) { - return; - } - - if (mDrawTarget) { - mDrawTarget->SetPathObserver(NULL); - } - mDrawTarget = aDrawTarget; - - // If there is a transform on the path, then we must have a separate context - // from the draw target, so we cannot be its observer - if (!mTransform.IsIdentity()) { - ForgetDrawTarget(); - return; - } - - mDrawTarget->SetPathObserver(this); -} - void CairoPathContext::DuplicateContextAndPath(const Matrix& aMatrix /* = Matrix() */) { @@ -342,7 +320,11 @@ PathCairo::CopyPathTo(cairo_t* aContext, DrawTargetCairo* aDrawTarget) // Since aDrawTarget wants us to be the current path on its context, we // should also listen to it for updates to that path (as an optimization). - mPathContext->ObserveTarget(aDrawTarget); + // The easiest way to do this is to just recreate mPathContext, since it + // registers with aDrawTarget for updates. + mPathContext = new CairoPathContext(aContext, aDrawTarget, + mPathContext->GetFillRule(), + mPathContext->GetTransform()); } } diff --git a/gfx/2d/PathCairo.h b/gfx/2d/PathCairo.h index e1dd07d642c9..099af08a979f 100644 --- a/gfx/2d/PathCairo.h +++ b/gfx/2d/PathCairo.h @@ -68,10 +68,6 @@ public: // Returns true if this CairoPathContext represents path. bool ContainsPath(const Path* path); - // add ourselves as an observer of aDrawTarget, if possible - // if we succeed, then mDrawTarget is set to aDrawTarget - void ObserveTarget(DrawTargetCairo* aDrawTarget); - cairo_t* GetContext() const { return mContext; } DrawTargetCairo* GetDrawTarget() const { return mDrawTarget; } Matrix GetTransform() const { return mTransform; } diff --git a/gfx/2d/SourceSurfaceCairo.cpp b/gfx/2d/SourceSurfaceCairo.cpp index 9370c73d067a..94085e4b592b 100644 --- a/gfx/2d/SourceSurfaceCairo.cpp +++ b/gfx/2d/SourceSurfaceCairo.cpp @@ -103,7 +103,6 @@ SourceSurfaceCairo::DrawTargetWillChange() cairo_set_source(ctx, pat); cairo_paint(ctx); cairo_destroy(ctx); - cairo_pattern_destroy(pat); // Swap in this new surface. cairo_surface_destroy(mSurface); diff --git a/gfx/2d/Types.h b/gfx/2d/Types.h index 4749cff069f8..601c3632e873 100644 --- a/gfx/2d/Types.h +++ b/gfx/2d/Types.h @@ -38,7 +38,7 @@ enum SurfaceFormat enum BackendType { - BACKEND_NONE = 0, + BACKEND_NONE, BACKEND_DIRECT2D, BACKEND_COREGRAPHICS, BACKEND_CAIRO, diff --git a/gfx/layers/d3d10/LayerManagerD3D10.cpp b/gfx/layers/d3d10/LayerManagerD3D10.cpp index 6b61cf4436b9..4d7d5b4bb3ac 100644 --- a/gfx/layers/d3d10/LayerManagerD3D10.cpp +++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp @@ -484,11 +484,8 @@ TemporaryRef LayerManagerD3D10::CreateDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) { - BackendType backend; if ((aFormat != FORMAT_B8G8R8A8 && - aFormat != FORMAT_B8G8R8X8) || - !gfxPlatform::GetPlatform()->SupportsAzureCanvas(backend) || - backend != BACKEND_DIRECT2D) { + aFormat != FORMAT_B8G8R8X8)) { return LayerManager::CreateDrawTarget(aSize, aFormat); } diff --git a/gfx/layers/d3d9/CanvasLayerD3D9.cpp b/gfx/layers/d3d9/CanvasLayerD3D9.cpp index b410abec5da2..522b59c3cdf7 100644 --- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp +++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp @@ -32,7 +32,6 @@ CanvasLayerD3D9::Initialize(const Data& aData) if (aData.mDrawTarget) { mDrawTarget = aData.mDrawTarget; - mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); mNeedsYFlip = false; mDataIsPremultiplied = true; } else if (aData.mSurface) { @@ -140,11 +139,18 @@ CanvasLayerD3D9::UpdateSurface() D3DLOCKED_RECT lockedRect = textureLock.GetLockRect(); nsRefPtr sourceSurface; + nsRefPtr tempSurface; + if (mDrawTarget) { + tempSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); + } + else { + tempSurface = mSurface; + } - if (mSurface->GetType() == gfxASurface::SurfaceTypeWin32) { - sourceSurface = mSurface->GetAsImageSurface(); - } else if (mSurface->GetType() == gfxASurface::SurfaceTypeImage) { - sourceSurface = static_cast(mSurface.get()); + if (tempSurface->GetType() == gfxASurface::SurfaceTypeWin32) { + sourceSurface = tempSurface->GetAsImageSurface(); + } else if (tempSurface->GetType() == gfxASurface::SurfaceTypeImage) { + sourceSurface = static_cast(tempSurface.get()); if (sourceSurface->Format() != gfxASurface::ImageFormatARGB32 && sourceSurface->Format() != gfxASurface::ImageFormatRGB24) { @@ -155,7 +161,7 @@ CanvasLayerD3D9::UpdateSurface() gfxASurface::ImageFormatARGB32); nsRefPtr ctx = new gfxContext(sourceSurface); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->SetSource(mSurface); + ctx->SetSource(tempSurface); ctx->Paint(); } diff --git a/gfx/layers/opengl/CanvasLayerOGL.cpp b/gfx/layers/opengl/CanvasLayerOGL.cpp index 14a3f87d18b4..a6b3150b4b32 100644 --- a/gfx/layers/opengl/CanvasLayerOGL.cpp +++ b/gfx/layers/opengl/CanvasLayerOGL.cpp @@ -75,7 +75,6 @@ CanvasLayerOGL::Initialize(const Data& aData) if (aData.mDrawTarget) { mDrawTarget = aData.mDrawTarget; - mCanvasSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); mNeedsYFlip = false; } else if (aData.mSurface) { mCanvasSurface = aData.mSurface; @@ -163,7 +162,11 @@ CanvasLayerOGL::UpdateSurface() } else { nsRefPtr updatedAreaSurface; - if (mCanvasSurface) { + if (mDrawTarget) { + // TODO: This is suboptimal - We should have direct handling for the surface types instead of + // going via a gfxASurface. + updatedAreaSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); + } else if (mCanvasSurface) { updatedAreaSurface = mCanvasSurface; } else if (mCanvasGLContext) { gfxIntSize size(mBounds.width, mBounds.height); @@ -223,8 +226,13 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination, drawRect.IntersectRect(drawRect, GetEffectiveVisibleRegion().GetBounds()); + nsRefPtr surf = mCanvasSurface; + if (mDrawTarget) { + surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); + } + mLayerProgram = - gl()->UploadSurfaceToTexture(mCanvasSurface, + gl()->UploadSurfaceToTexture(surf, nsIntRect(0, 0, drawRect.width, drawRect.height), mTexture, true, diff --git a/gfx/thebes/gfxAndroidPlatform.cpp b/gfx/thebes/gfxAndroidPlatform.cpp index 1ca2d7cb708c..d723c3504d43 100644 --- a/gfx/thebes/gfxAndroidPlatform.cpp +++ b/gfx/thebes/gfxAndroidPlatform.cpp @@ -161,19 +161,16 @@ gfxAndroidPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, } RefPtr -gfxAndroidPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) +gfxAndroidPlatform::GetScaledFontForFont(gfxFont *aFont) { - NativeFont nativeFont; - if (aTarget->GetType() == BACKEND_CAIRO) { - nativeFont.mType = NATIVE_FONT_CAIRO_FONT_FACE; - nativeFont.mFont = NULL; - return Factory::CreateScaledFontWithCairo(nativeFont, aFont->GetAdjustedSize(), aFont->GetCairoScaledFont()); - } - NS_ASSERTION(aFont->GetType() == gfxFont::FONT_TYPE_FT2, "Expecting Freetype font"); + NativeFont nativeFont; nativeFont.mType = NATIVE_FONT_SKIA_FONT_FACE; nativeFont.mFont = static_cast(aFont)->GetFontOptions(); - return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); + RefPtr scaledFont = + Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); + + return scaledFont; } bool diff --git a/gfx/thebes/gfxAndroidPlatform.h b/gfx/thebes/gfxAndroidPlatform.h index c9274f88190c..baa20ebac277 100644 --- a/gfx/thebes/gfxAndroidPlatform.h +++ b/gfx/thebes/gfxAndroidPlatform.h @@ -33,10 +33,12 @@ public: CreateOffscreenSurface(const gfxIntSize& size, gfxASurface::gfxContentType contentType); + virtual bool SupportsAzure(mozilla::gfx::BackendType& aBackend) { aBackend = mozilla::gfx::BACKEND_SKIA; return true; } + virtual gfxImageFormat GetOffscreenFormat() { return mOffscreenFormat; } mozilla::RefPtr - GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont); + GetScaledFontForFont(gfxFont *aFont); // to support IPC font list (sharing between chrome and content) void GetFontList(InfallibleTArray* retValue); diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index f6bfd48ac4df..b2b2b6a9dba6 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -1783,7 +1783,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd, } else { RefPtr scaledFont = - gfxPlatform::GetPlatform()->GetScaledFontForFont(dt, this); + gfxPlatform::GetPlatform()->GetScaledFontForFont(this); if (!scaledFont) { return; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 1df7415422df..ac8e23768795 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -1547,8 +1547,7 @@ public: FONT_TYPE_GDI, FONT_TYPE_FT2, FONT_TYPE_MAC, - FONT_TYPE_OS2, - FONT_TYPE_CAIRO + FONT_TYPE_OS2 } FontType; virtual FontType GetType() const = 0; diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index a9039a283f1b..1f3c27700024 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -48,7 +48,6 @@ #include "nsTArray.h" #include "nsUnicharUtilCIID.h" #include "nsILocaleService.h" -#include "nsReadableUtils.h" #include "nsWeakReference.h" @@ -76,7 +75,6 @@ using namespace mozilla::layers; gfxPlatform *gPlatform = nsnull; static bool gEverInitialized = false; -static nsTArray* gBackendList = nsnull; // These two may point to the same profile static qcms_profile *gCMSOutputProfile = nsnull; @@ -213,7 +211,7 @@ static const char *gPrefLangNames[] = { }; gfxPlatform::gfxPlatform() - : mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureCanvasBackendInfo) + : mAzureBackendCollector(this, &gfxPlatform::GetAzureBackendInfo) { mUseHarfBuzzScripts = UNINITIALIZED_VALUE; mAllowDownloadableFonts = UNINITIALIZED_VALUE; @@ -225,8 +223,11 @@ gfxPlatform::gfxPlatform() #endif mBidiNumeralOption = UNINITIALIZED_VALUE; - PRUint32 backendMask = (1 << BACKEND_CAIRO) | (1 << BACKEND_SKIA); - InitCanvasBackend(backendMask); + if (Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) { + mPreferredDrawTargetBackend = BACKEND_SKIA; + } else { + mPreferredDrawTargetBackend = BACKEND_NONE; + } } gfxPlatform* @@ -406,9 +407,6 @@ gfxPlatform::Shutdown() CompositorParent::ShutDown(); - delete gBackendList; - gBackendList = nsnull; - delete gPlatform; gPlatform = nsnull; } @@ -475,9 +473,9 @@ gfxPlatform::OptimizeImage(gfxImageSurface *aSurface, cairo_user_data_key_t kDrawTarget; RefPtr -gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize) +gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface) { - RefPtr drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize); + RefPtr drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface()); aSurface->SetData(&kDrawTarget, drawTarget, NULL); return drawTarget; } @@ -534,8 +532,11 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa if (!srcBuffer) { nsRefPtr imgSurface = aSurface->GetAsImageSurface(); - bool isWin32ImageSurf = imgSurface && - aSurface->GetType() == gfxASurface::SurfaceTypeWin32; + bool isWin32ImageSurf = false; + + if (imgSurface && aSurface->GetType() != gfxASurface::SurfaceTypeWin32) { + isWin32ImageSurf = true; + } if (!imgSurface) { imgSurface = new gfxImageSurface(aSurface->GetSize(), OptimalFormatForContent(aSurface->GetContentType())); @@ -571,8 +572,8 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa if (!srcBuffer) { // We need to check if our gfxASurface will keep the underlying data - // alive. This is true if gfxASurface actually -is- an ImageSurface or - // if it is a gfxWindowsSurface which supports GetAsImageSurface. + // alive! This is true if gfxASurface actually -is- an ImageSurface or + // if it is a gfxWindowsSurface which supportes GetAsImageSurface. if (imgSurface != aSurface && !isWin32ImageSurf) { // This shouldn't happen for now, it can be easily supported by making // a copy. For now let's just abort. @@ -604,73 +605,77 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa } RefPtr -gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) +gfxPlatform::GetScaledFontForFont(gfxFont *aFont) { NativeFont nativeFont; nativeFont.mType = NATIVE_FONT_CAIRO_FONT_FACE; - nativeFont.mFont = aFont->GetCairoScaledFont(); + nativeFont.mFont = aFont; RefPtr scaledFont = Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); return scaledFont; } -cairo_user_data_key_t kDrawSourceSurface; -static void -DataSourceSurfaceDestroy(void *dataSourceSurface) +UserDataKey kThebesSurfaceKey; +void +DestroyThebesSurface(void *data) { - static_cast(dataSourceSurface)->Release(); -} - -cairo_user_data_key_t kDrawTargetForSurface; -static void -DataDrawTargetDestroy(void *aTarget) -{ - static_cast(aTarget)->Release(); + gfxASurface *surface = static_cast(data); + surface->Release(); } already_AddRefed gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) { + // If we have already created a thebes surface, we can just return it. + void *surface = aTarget->GetUserData(&kThebesSurfaceKey); + if (surface) { + nsRefPtr surf = static_cast(surface); + return surf.forget(); + } + + nsRefPtr surf; if (aTarget->GetType() == BACKEND_CAIRO) { cairo_surface_t* csurf = static_cast(aTarget->GetNativeSurface(NATIVE_SURFACE_CAIRO_SURFACE)); - return gfxASurface::Wrap(csurf); + surf = gfxASurface::Wrap(csurf); + } else { + // The semantics of this part of the function are sort of weird. If we + // don't have direct support for the backend, we snapshot the first time + // and then return the snapshotted surface for the lifetime of the draw + // target. Sometimes it seems like this works out, but it seems like it + // might result in no updates ever. + RefPtr source = aTarget->Snapshot(); + RefPtr data = source->GetDataSurface(); + + if (!data) { + return NULL; + } + + IntSize size = data->GetSize(); + gfxASurface::gfxImageFormat format = OptimalFormatForContent(ContentForFormat(data->GetFormat())); + + // We need to make a copy here because data might change its data under us + nsRefPtr imageSurf = new gfxImageSurface(gfxIntSize(size.width, size.height), format, false); + + bool resultOfCopy = imageSurf->CopyFrom(source); + NS_ASSERTION(resultOfCopy, "Failed to copy surface."); + surf = imageSurf; } - // The semantics of this part of the function are sort of weird. If we - // don't have direct support for the backend, we snapshot the first time - // and then return the snapshotted surface for the lifetime of the draw - // target. Sometimes it seems like this works out, but it seems like it - // might result in no updates ever. - RefPtr source = aTarget->Snapshot(); - RefPtr data = source->GetDataSurface(); - - if (!data) { - return NULL; - } - - IntSize size = data->GetSize(); - gfxASurface::gfxImageFormat format = OptimalFormatForContent(ContentForFormat(data->GetFormat())); - - - nsRefPtr surf = - new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height), - data->Stride(), format); - - surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy); - // keep the draw target alive as long as we need its data - aTarget->AddRef(); - surf->SetData(&kDrawTargetForSurface, aTarget, DataDrawTargetDestroy); + // add a reference to be held by the drawTarget + // careful, the reference graph is getting complicated here + surf->AddRef(); + aTarget->AddUserData(&kThebesSurfaceKey, surf.get(), DestroyThebesSurface); return surf.forget(); } RefPtr -gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat) +gfxPlatform::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aFormat) { BackendType backend; - if (!SupportsAzureCanvas(backend)) { + if (!SupportsAzure(backend)) { return NULL; } @@ -682,70 +687,26 @@ gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSi // now, but this might need to change in the future (using // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all // backends). - if (aBackend == BACKEND_CAIRO) { + if (backend == BACKEND_CAIRO) { nsRefPtr surf = CreateOffscreenSurface(ThebesIntSize(aSize), ContentForFormat(aFormat)); - if (!surf) { - return NULL; - } - return CreateDrawTargetForSurface(surf, aSize); + return CreateDrawTargetForSurface(surf); } else { - return Factory::CreateDrawTarget(aBackend, aSize, aFormat); + return Factory::CreateDrawTarget(backend, aSize, aFormat); } } -RefPtr -gfxPlatform::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aFormat) -{ - BackendType backend; - if (!SupportsAzureCanvas(backend)) { - return NULL; - } - - RefPtr target = CreateDrawTargetForBackend(backend, aSize, aFormat); - if (target || - mFallbackCanvasBackend == BACKEND_NONE) { - return target; - } - - return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat); -} - - RefPtr gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat) { BackendType backend; - if (!SupportsAzureCanvas(backend)) { + if (!SupportsAzure(backend)) { return NULL; } return Factory::CreateDrawTargetForData(backend, aData, aSize, aStride, aFormat); } -bool -gfxPlatform::SupportsAzureCanvas(BackendType& aBackend) -{ - NS_ASSERTION(mFallbackCanvasBackend == BACKEND_NONE || mPreferredCanvasBackend != BACKEND_NONE, - "fallback backend with no preferred backend"); - aBackend = mPreferredCanvasBackend; - return mPreferredCanvasBackend != BACKEND_NONE; -} - -/* static */ BackendType -gfxPlatform::BackendTypeForName(const nsCString& aName) -{ - if (aName.EqualsLiteral("cairo")) - return BACKEND_CAIRO; - if (aName.EqualsLiteral("skia")) - return BACKEND_SKIA; - if (aName.EqualsLiteral("direct2d")) - return BACKEND_DIRECT2D; - if (aName.EqualsLiteral("cg")) - return BACKEND_COREGRAPHICS; - return BACKEND_NONE; -} - nsresult gfxPlatform::GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, @@ -1166,53 +1127,20 @@ gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], PRUint32& aLen, eFontPre } } -void -gfxPlatform::InitCanvasBackend(PRUint32 aBackendBitmask) -{ - if (!Preferences::GetBool("gfx.canvas.azure.enabled", false)) { - mPreferredCanvasBackend = BACKEND_NONE; - mFallbackCanvasBackend = BACKEND_NONE; - return; - } - - mPreferredCanvasBackend = GetCanvasBackendPref(aBackendBitmask); - mFallbackCanvasBackend = GetCanvasBackendPref(aBackendBitmask & ~(1 << mPreferredCanvasBackend)); -} - -/* static */ BackendType -gfxPlatform::GetCanvasBackendPref(PRUint32 aBackendBitmask) -{ - if (!gBackendList) { - gBackendList = new nsTArray(); - nsCString prefString; - if (NS_SUCCEEDED(Preferences::GetCString("gfx.canvas.azure.backends", &prefString))) { - ParseString(prefString, ',', *gBackendList); - } - } - - for (PRUint32 i = 0; i < gBackendList->Length(); ++i) { - BackendType result = BackendTypeForName((*gBackendList)[i]); - if ((1 << result) & aBackendBitmask) { - return result; - } - } - return BACKEND_NONE; -} - bool gfxPlatform::UseProgressiveTilePainting() { - static bool sUseProgressiveTilePainting; - static bool sUseProgressiveTilePaintingPrefCached = false; + static bool sUseProgressiveTilePainting; + static bool sUseProgressiveTilePaintingPrefCached = false; - if (!sUseProgressiveTilePaintingPrefCached) { - sUseProgressiveTilePaintingPrefCached = true; - mozilla::Preferences::AddBoolVarCache(&sUseProgressiveTilePainting, - "layers.progressive-paint", - false); - } + if (!sUseProgressiveTilePaintingPrefCached) { + sUseProgressiveTilePaintingPrefCached = true; + mozilla::Preferences::AddBoolVarCache(&sUseProgressiveTilePainting, + "layers.progressive-paint", + false); + } - return sUseProgressiveTilePainting; + return sUseProgressiveTilePainting; } bool diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 81fe98b1ca66..e87944a85039 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -38,6 +38,9 @@ class gfxTextRun; class nsIURI; class nsIAtom; +extern mozilla::gfx::UserDataKey kThebesSurfaceKey; +void DestroyThebesSurface(void *data); + extern cairo_user_data_key_t kDrawTarget; // pref lang id's for font prefs @@ -127,7 +130,7 @@ GetBackendName(mozilla::gfx::BackendType aBackend) case mozilla::gfx::BACKEND_NONE: return "none"; } - MOZ_NOT_REACHED("Incomplete switch"); + MOZ_NOT_REACHED("Incomplet switch"); } class THEBES_API gfxPlatform { @@ -169,21 +172,18 @@ public: gfxASurface::gfxImageFormat format); virtual mozilla::RefPtr - CreateDrawTargetForSurface(gfxASurface *aSurface, const mozilla::gfx::IntSize& aSize); + CreateDrawTargetForSurface(gfxASurface *aSurface); /* - * Creates a SourceSurface for a gfxASurface. This function does no caching, - * so the caller should cache the gfxASurface if it will be used frequently. - * The returned surface keeps a reference to aTarget, so it is OK to keep the - * surface, even if aTarget changes. - * aTarget should not keep a reference to the returned surface because that - * will cause a cycle. + * Creates a SourceSurface for a gfxASurface. This surface should -not- be + * held around by the user after the underlying gfxASurface has been + * destroyed as a copy of the data is not guaranteed. */ virtual mozilla::RefPtr GetSourceSurfaceForSurface(mozilla::gfx::DrawTarget *aTarget, gfxASurface *aSurface); virtual mozilla::RefPtr - GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont); + GetScaledFontForFont(gfxFont *aFont); virtual already_AddRefed GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget); @@ -195,12 +195,13 @@ public: CreateDrawTargetForData(unsigned char* aData, const mozilla::gfx::IntSize& aSize, int32_t aStride, mozilla::gfx::SurfaceFormat aFormat); - // aBackend will be set to the preferred backend for Azure canvas - bool SupportsAzureCanvas(mozilla::gfx::BackendType& aBackend); + virtual bool SupportsAzure(mozilla::gfx::BackendType& aBackend) { return false; } - // aObj will contain the preferred backend for Azure canvas - void GetAzureCanvasBackendInfo(mozilla::widget::InfoObject &aObj) { - aObj.DefineProperty("AzureBackend", GetBackendName(mPreferredCanvasBackend)); + void GetAzureBackendInfo(mozilla::widget::InfoObject &aObj) { + mozilla::gfx::BackendType backend; + if (SupportsAzure(backend)) { + aObj.DefineProperty("AzureBackend", GetBackendName(backend)); + } } /* @@ -454,30 +455,7 @@ protected: void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang); - - /** - * Helper method, creates a draw target for a specific Azure backend. - * Used by CreateOffscreenDrawTarget. - */ - mozilla::RefPtr - CreateDrawTargetForBackend(mozilla::gfx::BackendType aBackend, - const mozilla::gfx::IntSize& aSize, - mozilla::gfx::SurfaceFormat aFormat); - - /** - * Initialise the preferred and fallback canvas backends - * aBackendBitmask specifies the backends which are acceptable to the caller. - * The backend used is determined by aBackendBitmask and the order specified - * by the gfx.canvas.azure.backends pref. - */ - void InitCanvasBackend(PRUint32 aBackendBitmask); - /** - * returns the first backend named in the pref gfx.canvas.azure.backends - * which is a component of aBackendBitmask, a bitmask of backend types - */ - static mozilla::gfx::BackendType GetCanvasBackendPref(PRUint32 aBackendBitmask); - static mozilla::gfx::BackendType BackendTypeForName(const nsCString& aName); - + PRInt8 mAllowDownloadableFonts; PRInt8 mDownloadableFontsSanitize; #ifdef MOZ_GRAPHITE @@ -493,6 +471,9 @@ protected: // which scripts should be shaped with harfbuzz PRInt32 mUseHarfBuzzScripts; + // The preferred draw target backend to use + mozilla::gfx::BackendType mPreferredDrawTargetBackend; + private: /** * Start up Thebes. @@ -505,13 +486,7 @@ private: nsTArray mCJKPrefLangs; nsCOMPtr mSRGBOverrideObserver; nsCOMPtr mFontPrefsObserver; - - // The preferred draw target backend to use for canvas - mozilla::gfx::BackendType mPreferredCanvasBackend; - // The fallback draw target backend to use for canvas, if the preferred backend fails - mozilla::gfx::BackendType mFallbackCanvasBackend; - - mozilla::widget::GfxInfoCollector mAzureCanvasBackendCollector; + mozilla::widget::GfxInfoCollector mAzureBackendCollector; bool mWorkAroundDriverBugs; }; diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp index 2a5cabda585e..0d4d95ed5f0b 100644 --- a/gfx/thebes/gfxPlatformGtk.cpp +++ b/gfx/thebes/gfxPlatformGtk.cpp @@ -730,16 +730,22 @@ gfxPlatformGtk::GetGdkDrawable(gfxASurface *target) #endif RefPtr -gfxPlatformGtk::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) +gfxPlatformGtk::GetScaledFontForFont(gfxFont *aFont) { - NativeFont nativeFont; - if (aTarget->GetType() == BACKEND_CAIRO) { - nativeFont.mType = NATIVE_FONT_CAIRO_FONT_FACE; - nativeFont.mFont = NULL; - return Factory::CreateScaledFontWithCairo(nativeFont, aFont->GetAdjustedSize(), aFont->GetCairoScaledFont()); - } NS_ASSERTION(aFont->GetType() == gfxFont::FONT_TYPE_FT2, "Expecting Freetype font"); + NativeFont nativeFont; nativeFont.mType = NATIVE_FONT_SKIA_FONT_FACE; nativeFont.mFont = static_cast(aFont)->GetFontOptions(); - return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); + RefPtr scaledFont = + Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); + + return scaledFont; } + +bool +gfxPlatformGtk::SupportsAzure(BackendType& aBackend) +{ + aBackend = BACKEND_SKIA; + return true; +} + diff --git a/gfx/thebes/gfxPlatformGtk.h b/gfx/thebes/gfxPlatformGtk.h index 27c8f125f18f..672b20ea56ea 100644 --- a/gfx/thebes/gfxPlatformGtk.h +++ b/gfx/thebes/gfxPlatformGtk.h @@ -36,7 +36,9 @@ public: gfxASurface::gfxContentType contentType); mozilla::RefPtr - GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont); + GetScaledFontForFont(gfxFont *aFont); + + virtual bool SupportsAzure(mozilla::gfx::BackendType& aBackend); nsresult GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, diff --git a/gfx/thebes/gfxPlatformMac.cpp b/gfx/thebes/gfxPlatformMac.cpp index eb5beaf33b4b..9a5c2b5e7283 100644 --- a/gfx/thebes/gfxPlatformMac.cpp +++ b/gfx/thebes/gfxPlatformMac.cpp @@ -69,9 +69,6 @@ gfxPlatformMac::gfxPlatformMac() DisableFontActivation(); } mFontAntiAliasingThreshold = ReadAntiAliasingThreshold(); - - PRUint32 backendMask = (1 << BACKEND_CAIRO) | (1 << BACKEND_SKIA) | (1 << BACKEND_COREGRAPHICS); - InitCanvasBackend(backendMask); } gfxPlatformMac::~gfxPlatformMac() @@ -136,12 +133,24 @@ gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface, } RefPtr -gfxPlatformMac::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) +gfxPlatformMac::GetScaledFontForFont(gfxFont *aFont) { gfxMacFont *font = static_cast(aFont); return font->GetScaledFont(); } +bool +gfxPlatformMac::SupportsAzure(BackendType& aBackend) +{ + if (mPreferredDrawTargetBackend != BACKEND_NONE) { + aBackend = mPreferredDrawTargetBackend; + } else { + aBackend = BACKEND_COREGRAPHICS; + } + + return true; +} + nsresult gfxPlatformMac::ResolveFontName(const nsAString& aFontName, FontResolverCallback aCallback, @@ -380,16 +389,26 @@ already_AddRefed gfxPlatformMac::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) { if (aTarget->GetType() == BACKEND_COREGRAPHICS) { - CGContextRef cg = static_cast(aTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT)); + void *surface = aTarget->GetUserData(&kThebesSurfaceKey); + if (surface) { + nsRefPtr surf = static_cast(surface); + return surf.forget(); + } else { + CGContextRef cg = static_cast(aTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT)); - //XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize - IntSize intSize = aTarget->GetSize(); - gfxIntSize size(intSize.width, intSize.height); + //XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize + IntSize intSize = aTarget->GetSize(); + gfxIntSize size(intSize.width, intSize.height); - nsRefPtr surf = - new gfxQuartzSurface(cg, size); + nsRefPtr surf = + new gfxQuartzSurface(cg, size); - return surf.forget(); + // add a reference to be held by the drawTarget + surf->AddRef(); + aTarget->AddUserData(&kThebesSurfaceKey, surf.get(), DestroyThebesSurface); + + return surf.forget(); + } } return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); diff --git a/gfx/thebes/gfxPlatformMac.h b/gfx/thebes/gfxPlatformMac.h index 0bd0204b41fb..a0aa17a7e762 100644 --- a/gfx/thebes/gfxPlatformMac.h +++ b/gfx/thebes/gfxPlatformMac.h @@ -39,7 +39,9 @@ public: gfxASurface::gfxImageFormat format); mozilla::RefPtr - GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont); + GetScaledFontForFont(gfxFont *aFont); + + virtual bool SupportsAzure(mozilla::gfx::BackendType& aBackend); nsresult ResolveFontName(const nsAString& aFontName, FontResolverCallback aCallback, diff --git a/gfx/thebes/gfxQtPlatform.cpp b/gfx/thebes/gfxQtPlatform.cpp index fec92da45306..dca667ff3c13 100644 --- a/gfx/thebes/gfxQtPlatform.cpp +++ b/gfx/thebes/gfxQtPlatform.cpp @@ -606,3 +606,10 @@ gfxQtPlatform::GetOffscreenFormat() return sOffscreenFormat; } +bool +gfxQtPlatform::SupportsAzure(BackendType& aBackend) +{ + aBackend = BACKEND_SKIA; + return true; +} + diff --git a/gfx/thebes/gfxQtPlatform.h b/gfx/thebes/gfxQtPlatform.h index 3e6aaca1a622..ac95fc5cf656 100644 --- a/gfx/thebes/gfxQtPlatform.h +++ b/gfx/thebes/gfxQtPlatform.h @@ -47,6 +47,8 @@ public: already_AddRefed CreateOffscreenSurface(const gfxIntSize& size, gfxASurface::gfxContentType contentType); + virtual bool SupportsAzure(mozilla::gfx::BackendType& aBackend); + nsresult GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, nsTArray& aListOfFonts); diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 50302b7f7ae0..cdab97d2a4a2 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -515,14 +515,6 @@ gfxWindowsPlatform::UpdateRenderMode() } } #endif - - PRUint32 backendMask = 1 << BACKEND_CAIRO; - if (mRenderMode == RENDER_DIRECT2D) { - backendMask |= 1 << BACKEND_DIRECT2D; - } else { - backendMask |= 1 << BACKEND_SKIA; - } - InitCanvasBackend(backendMask); } void @@ -772,7 +764,7 @@ gfxWindowsPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize, } RefPtr -gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) +gfxWindowsPlatform::GetScaledFontForFont(gfxFont *aFont) { if (aFont->GetType() == gfxFont::FONT_TYPE_DWRITE) { gfxDWriteFont *font = static_cast(aFont); @@ -794,14 +786,10 @@ gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) LOGFONT lf; GetObject(static_cast(aFont)->GetHFONT(), sizeof(LOGFONT), &lf); nativeFont.mFont = &lf; + RefPtr scaledFont = + Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); - if (aTarget->GetType() == BACKEND_CAIRO) { - return Factory::CreateScaledFontWithCairo(nativeFont, - aFont->GetAdjustedSize(), - aFont->GetCairoScaledFont()); - } - - return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); + return scaledFont; } already_AddRefed @@ -809,32 +797,64 @@ gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) { #ifdef XP_WIN if (aTarget->GetType() == BACKEND_DIRECT2D) { - if (!GetD2DDevice()) { - // We no longer have a D2D device, can't do this. - return NULL; + void *surface = aTarget->GetUserData(&kThebesSurfaceKey); + if (surface) { + nsRefPtr surf = static_cast(surface); + return surf.forget(); + } else { + if (!GetD2DDevice()) { + // We no longer have a D2D device, can't do this. + return NULL; + } + + RefPtr texture = + static_cast(aTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE)); + + if (!texture) { + return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); + } + + aTarget->Flush(); + + nsRefPtr surf = + new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat())); + + // add a reference to be held by the drawTarget + surf->AddRef(); + aTarget->AddUserData(&kThebesSurfaceKey, surf.get(), DestroyThebesSurface); + /* "It might be worth it to clear cairo surfaces associated with a drawtarget. + The strong reference means for example for D2D that cairo's scratch surface + will be kept alive (well after a user being done) and consume extra VRAM. + We can deal with this in a follow-up though." */ + + // shouldn't this hold a reference? + surf->SetData(&kDrawTarget, aTarget, NULL); + return surf.forget(); } - - RefPtr texture = - static_cast(aTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE)); - - if (!texture) { - return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); - } - - aTarget->Flush(); - - nsRefPtr surf = - new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat())); - - // shouldn't this hold a reference? - surf->SetData(&kDrawTarget, aTarget, NULL); - return surf.forget(); } #endif return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); } +bool +gfxWindowsPlatform::SupportsAzure(BackendType& aBackend) +{ +#ifdef CAIRO_HAS_D2D_SURFACE + if (mRenderMode == RENDER_DIRECT2D) { + aBackend = BACKEND_DIRECT2D; + return true; + } +#endif + + if (mPreferredDrawTargetBackend != BACKEND_NONE) { + aBackend = mPreferredDrawTargetBackend; + return true; + } + + return false; +} + nsresult gfxWindowsPlatform::GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index 2a2ce29cfbe8..32d1a8d9e0af 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -108,9 +108,11 @@ public: gfxASurface::gfxContentType aContentType); virtual mozilla::RefPtr - GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont); + GetScaledFontForFont(gfxFont *aFont); virtual already_AddRefed GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget); + + virtual bool SupportsAzure(mozilla::gfx::BackendType& aBackend); enum RenderMode { /* Use GDI and windows surfaces */ diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 9c076b777f9f..d9b8eb657e8f 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -225,17 +225,10 @@ pref("gfx.font_rendering.directwrite.use_gdi_table_loading", true); #ifdef XP_WIN pref("gfx.canvas.azure.enabled", true); -// comma separated list of backends to use in order of preference -// e.g., pref("gfx.canvas.azure.backends", "direct2d,skia,cairo"); -pref("gfx.canvas.azure.backends", "direct2d"); pref("gfx.content.azure.enabled", true); #else #ifdef XP_MACOSX pref("gfx.canvas.azure.enabled", true); -pref("gfx.canvas.azure.backends", "cg"); -#else -pref("gfx.canvas.azure.enabled", false); -pref("gfx.canvas.azure.backends", "cairo,skia"); #endif #endif diff --git a/widget/android/GfxInfo.cpp b/widget/android/GfxInfo.cpp index 40ce2df67484..2525b6ff373e 100644 --- a/widget/android/GfxInfo.cpp +++ b/widget/android/GfxInfo.cpp @@ -43,6 +43,12 @@ GfxInfo::GetDWriteEnabled(bool *aEnabled) return NS_ERROR_FAILURE; } +nsresult +GfxInfo::GetAzureEnabled(bool *aEnabled) +{ + return NS_ERROR_FAILURE; +} + /* readonly attribute DOMString DWriteVersion; */ NS_IMETHODIMP GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion) diff --git a/widget/android/GfxInfo.h b/widget/android/GfxInfo.h index 44c52577e92a..8adffbbce8d0 100644 --- a/widget/android/GfxInfo.h +++ b/widget/android/GfxInfo.h @@ -25,6 +25,7 @@ public: // rest is brought forward from GfxInfoBase. NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled); NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled); + NS_IMETHOD GetAzureEnabled(bool *aAzureEnabled); NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion); NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams); NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription); diff --git a/widget/cocoa/GfxInfo.h b/widget/cocoa/GfxInfo.h index b1b7aaad9b60..c6131a467d5a 100644 --- a/widget/cocoa/GfxInfo.h +++ b/widget/cocoa/GfxInfo.h @@ -24,6 +24,7 @@ public: // rest is brought forward from GfxInfoBase. NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled); NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled); + NS_IMETHOD GetAzureEnabled(bool *aAzureEnabled); NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion); NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams); NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription); diff --git a/widget/cocoa/GfxInfo.mm b/widget/cocoa/GfxInfo.mm index 18a0d4e9e8a6..60c95d052465 100644 --- a/widget/cocoa/GfxInfo.mm +++ b/widget/cocoa/GfxInfo.mm @@ -154,6 +154,20 @@ GfxInfo::GetD2DEnabled(bool *aEnabled) return NS_ERROR_FAILURE; } +NS_IMETHODIMP +GfxInfo::GetAzureEnabled(bool *aEnabled) +{ + bool azure = false; + nsresult rv = mozilla::Preferences::GetBool("gfx.canvas.azure.enabled", &azure); + + if (NS_SUCCEEDED(rv) && azure) { + *aEnabled = true; + } else { + *aEnabled = false; + } + return NS_OK; +} + NS_IMETHODIMP GfxInfo::GetDWriteEnabled(bool *aEnabled) { diff --git a/widget/nsIGfxInfo.idl b/widget/nsIGfxInfo.idl index 45504c941eff..89998ae370bc 100644 --- a/widget/nsIGfxInfo.idl +++ b/widget/nsIGfxInfo.idl @@ -16,6 +16,7 @@ interface nsIGfxInfo : nsISupports */ readonly attribute boolean D2DEnabled; readonly attribute boolean DWriteEnabled; + readonly attribute boolean AzureEnabled; readonly attribute DOMString DWriteVersion; readonly attribute DOMString cleartypeParameters; diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp index 0fbf8ba4169a..b495ec093bbd 100644 --- a/widget/windows/GfxInfo.cpp +++ b/widget/windows/GfxInfo.cpp @@ -59,6 +59,26 @@ GfxInfo::GetDWriteEnabled(bool *aEnabled) return NS_OK; } +nsresult +GfxInfo::GetAzureEnabled(bool *aEnabled) +{ + *aEnabled = false; + + bool d2dEnabled = + gfxWindowsPlatform::GetPlatform()->GetRenderMode() == gfxWindowsPlatform::RENDER_DIRECT2D; + + if (d2dEnabled) { + bool azure = false; + nsresult rv = mozilla::Preferences::GetBool("gfx.canvas.azure.enabled", &azure); + + if (NS_SUCCEEDED(rv) && azure) { + *aEnabled = true; + } + } + + return NS_OK; +} + /* readonly attribute DOMString DWriteVersion; */ NS_IMETHODIMP GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion) diff --git a/widget/windows/GfxInfo.h b/widget/windows/GfxInfo.h index af82666b61df..f9327c40313b 100644 --- a/widget/windows/GfxInfo.h +++ b/widget/windows/GfxInfo.h @@ -22,6 +22,7 @@ public: // rest is brought forward from GfxInfoBase. NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled); NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled); + NS_IMETHOD GetAzureEnabled(bool *aAzureEnabled); NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion); NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams); NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription); diff --git a/widget/windows/TaskbarPreview.cpp b/widget/windows/TaskbarPreview.cpp index 2960068f72fd..25d86746624a 100644 --- a/widget/windows/TaskbarPreview.cpp +++ b/widget/windows/TaskbarPreview.cpp @@ -61,7 +61,7 @@ GetRenderingContext(nsIDocShell *shell, gfxASurface *surface, if (!ctx) { // create the canvas rendering context - ctx = do_CreateInstance("@mozilla.org/content/canvas-rendering-context;1?id=2d", &rv); + ctx = do_CreateInstance("@mozilla.org/content/2dthebes-canvas-rendering-context;1", &rv); if (NS_FAILED(rv)) { NS_WARNING("Could not create nsICanvasRenderingContext2D for tab previews!"); return rv; diff --git a/widget/xpwidgets/GfxInfoX11.cpp b/widget/xpwidgets/GfxInfoX11.cpp index eaa114ddddc9..57a6e2858dce 100644 --- a/widget/xpwidgets/GfxInfoX11.cpp +++ b/widget/xpwidgets/GfxInfoX11.cpp @@ -370,6 +370,12 @@ GfxInfo::GetDWriteEnabled(bool *aEnabled) return NS_ERROR_FAILURE; } +NS_IMETHODIMP +GfxInfo::GetAzureEnabled(bool *aEnabled) +{ + return NS_ERROR_FAILURE; +} + /* readonly attribute DOMString DWriteVersion; */ NS_IMETHODIMP GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion) diff --git a/widget/xpwidgets/GfxInfoX11.h b/widget/xpwidgets/GfxInfoX11.h index 44a6d5319eb7..2b5116f78303 100644 --- a/widget/xpwidgets/GfxInfoX11.h +++ b/widget/xpwidgets/GfxInfoX11.h @@ -21,6 +21,7 @@ public: // rest is brought forward from GfxInfoBase. NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled); NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled); + NS_IMETHOD GetAzureEnabled(bool *aAzureEnabled); NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion); NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams); NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription);