new file mode 100644
--- /dev/null
+++ b/dom/canvas/BasicRenderingContext2D.cpp
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/BasicRenderingContext2D.h"
+
+namespace mozilla {
+namespace dom{
+
+// Cap sigma to avoid overly large temp surfaces.
+const mozilla::gfx::Float SIGMA_MAX = 100;
+
+const size_t MAX_STYLE_STACK_SIZE = 1024;
+
+/**
+ ** BasicRenderingContext2D impl
+ **/
+
+//
+// state
+//
+void
+BasicRenderingContext2D::Save()
+{
+ EnsureTarget();
+ mStyleStack[mStyleStack.Length() - 1].transform = mTarget->GetTransform();
+ mStyleStack.SetCapacity(mStyleStack.Length() + 1);
+ mStyleStack.AppendElement(CurrentState());
+
+ if (mStyleStack.Length() > MAX_STYLE_STACK_SIZE) {
+ // This is not fast, but is better than OOMing and shouldn't be hit by
+ // reasonable code.
+ mStyleStack.RemoveElementAt(0);
+ }
+}
+
+void
+BasicRenderingContext2D::Restore()
+{
+ if (mStyleStack.Length() - 1 == 0)
+ return;
+
+ TransformWillUpdate();
+
+ for (const auto& clipOrTransform : CurrentState().clipsAndTransforms) {
+ if (clipOrTransform.IsClip()) {
+ mTarget->PopClip();
+ }
+ }
+
+ mStyleStack.RemoveElementAt(mStyleStack.Length() - 1);
+
+ mTarget->SetTransform(CurrentState().transform);
+}
+
+//
+// path bits
+//
+void
+BasicRenderingContext2D::TransformWillUpdate()
+{
+ EnsureTarget();
+
+ // Store the matrix that would transform the current path to device
+ // space.
+ if (mPath || mPathBuilder) {
+ if (!mPathTransformWillUpdate) {
+ // If the transform has already been updated, but a device space builder
+ // has not been created yet mPathToDS contains the right transform to
+ // transform the current mPath into device space.
+ // We should leave it alone.
+ mPathToDS = mTarget->GetTransform();
+ }
+ mPathTransformWillUpdate = true;
+ }
+}
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/canvas/BasicRenderingContext2D.h
+++ b/dom/canvas/BasicRenderingContext2D.h
@@ -1,35 +1,56 @@
/* 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 BasicRenderingContext2D_h
#define BasicRenderingContext2D_h
+#include "FilterSupport.h"
#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
+#include "nsStyleStruct.h"
+#include "nsSVGEffects.h"
+
+using mozilla::gfx::FilterDescription;
namespace mozilla {
namespace dom {
class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap
CanvasImageSource;
+extern const mozilla::gfx::Float SIGMA_MAX;
+
/*
* BasicRenderingContext2D
*/
class BasicRenderingContext2D
{
public:
+ enum RenderingMode {
+ SoftwareBackendMode,
+ OpenGLBackendMode,
+ DefaultBackendMode
+ };
+
+ // This is created lazily so it is necessary to call EnsureTarget before
+ // accessing it. In the event of an error it will be equal to
+ // sErrorTarget.
+ RefPtr<mozilla::gfx::DrawTarget> mTarget;
+
+public:
+ explicit BasicRenderingContext2D(layers::LayersBackend aCompositorBackend)
+ : mPathTransformWillUpdate(false){};
//
// CanvasState
//
- virtual void Save() = 0;
- virtual void Restore() = 0;
+ void Save();
+ void Restore();
//
// CanvasTransform
//
virtual void Scale(double aX, double aY, mozilla::ErrorResult& aError) = 0;
virtual void Rotate(double aAngle, mozilla::ErrorResult& aError) = 0;
virtual void Translate(double aX,
double aY,
@@ -188,14 +209,264 @@ public:
double aY,
double aRadiusX,
double aRadiusY,
double aRotation,
double aStartAngle,
double aEndAngle,
bool aAnticlockwise,
ErrorResult& aError) = 0;
+protected:
+ enum class Style : uint8_t {
+ STROKE = 0,
+ FILL,
+ MAX
+ };
+
+ enum class TextAlign : uint8_t {
+ START,
+ END,
+ LEFT,
+ RIGHT,
+ CENTER
+ };
+
+ enum class TextBaseline : uint8_t {
+ TOP,
+ HANGING,
+ MIDDLE,
+ ALPHABETIC,
+ IDEOGRAPHIC,
+ BOTTOM
+ };
+
+ // A clip or a transform, recorded and restored in order.
+ struct ClipState {
+ explicit ClipState(mozilla::gfx::Path* aClip)
+ : clip(aClip)
+ {}
+
+ explicit ClipState(const mozilla::gfx::Matrix& aTransform)
+ : transform(aTransform)
+ {}
+
+ bool IsClip() const { return !!clip; }
+
+ RefPtr<mozilla::gfx::Path> clip;
+ mozilla::gfx::Matrix transform;
+ };
+
+ // state stack handling
+ class ContextState {
+ public:
+ ContextState() : textAlign(TextAlign::START),
+ textBaseline(TextBaseline::ALPHABETIC),
+ shadowColor(0),
+ lineWidth(1.0f),
+ miterLimit(10.0f),
+ globalAlpha(1.0f),
+ shadowBlur(0.0),
+ dashOffset(0.0f),
+ op(mozilla::gfx::CompositionOp::OP_OVER),
+ fillRule(mozilla::gfx::FillRule::FILL_WINDING),
+ lineCap(mozilla::gfx::CapStyle::BUTT),
+ lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL),
+ filterString(u"none"),
+ filterSourceGraphicTainted(false),
+ imageSmoothingEnabled(true),
+ fontExplicitLanguage(false)
+ { }
+
+ ContextState(const ContextState& aOther)
+ : fontGroup(aOther.fontGroup),
+ fontLanguage(aOther.fontLanguage),
+ fontFont(aOther.fontFont),
+ gradientStyles(aOther.gradientStyles),
+ patternStyles(aOther.patternStyles),
+ colorStyles(aOther.colorStyles),
+ font(aOther.font),
+ textAlign(aOther.textAlign),
+ textBaseline(aOther.textBaseline),
+ shadowColor(aOther.shadowColor),
+ transform(aOther.transform),
+ shadowOffset(aOther.shadowOffset),
+ lineWidth(aOther.lineWidth),
+ miterLimit(aOther.miterLimit),
+ globalAlpha(aOther.globalAlpha),
+ shadowBlur(aOther.shadowBlur),
+ dash(aOther.dash),
+ dashOffset(aOther.dashOffset),
+ op(aOther.op),
+ fillRule(aOther.fillRule),
+ lineCap(aOther.lineCap),
+ lineJoin(aOther.lineJoin),
+ filterString(aOther.filterString),
+ filterChain(aOther.filterChain),
+ filterChainObserver(aOther.filterChainObserver),
+ filter(aOther.filter),
+ filterAdditionalImages(aOther.filterAdditionalImages),
+ filterSourceGraphicTainted(aOther.filterSourceGraphicTainted),
+ imageSmoothingEnabled(aOther.imageSmoothingEnabled),
+ fontExplicitLanguage(aOther.fontExplicitLanguage)
+ { }
+
+ void SetColorStyle(Style aWhichStyle, nscolor aColor)
+ {
+ colorStyles[aWhichStyle] = aColor;
+ gradientStyles[aWhichStyle] = nullptr;
+ patternStyles[aWhichStyle] = nullptr;
+ }
+
+ void SetPatternStyle(Style aWhichStyle, CanvasPattern* aPat)
+ {
+ gradientStyles[aWhichStyle] = nullptr;
+ patternStyles[aWhichStyle] = aPat;
+ }
+
+ void SetGradientStyle(Style aWhichStyle, CanvasGradient* aGrad)
+ {
+ gradientStyles[aWhichStyle] = aGrad;
+ patternStyles[aWhichStyle] = nullptr;
+ }
+
+ /**
+ * returns true iff the given style is a solid color.
+ */
+ bool StyleIsColor(Style aWhichStyle) const
+ {
+ return !(patternStyles[aWhichStyle] || gradientStyles[aWhichStyle]);
+ }
+
+ int32_t ShadowBlurRadius() const
+ {
+ static const gfxFloat GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * 1.5;
+ return (int32_t)floor(ShadowBlurSigma() * GAUSSIAN_SCALE_FACTOR + 0.5);
+ }
+
+ mozilla::gfx::Float ShadowBlurSigma() const
+ {
+ return std::min(SIGMA_MAX, shadowBlur / 2.0f);
+ }
+
+ nsTArray<ClipState> clipsAndTransforms;
+
+ RefPtr<gfxFontGroup> fontGroup;
+ nsCOMPtr<nsIAtom> fontLanguage;
+ nsFont fontFont;
+
+ EnumeratedArray<Style, Style::MAX, RefPtr<CanvasGradient>> gradientStyles;
+ EnumeratedArray<Style, Style::MAX, RefPtr<CanvasPattern>> patternStyles;
+ EnumeratedArray<Style, Style::MAX, nscolor> colorStyles;
+
+ nsString font;
+ TextAlign textAlign;
+ TextBaseline textBaseline;
+
+ nscolor shadowColor;
+
+ mozilla::gfx::Matrix transform;
+ mozilla::gfx::Point shadowOffset;
+ mozilla::gfx::Float lineWidth;
+ mozilla::gfx::Float miterLimit;
+ mozilla::gfx::Float globalAlpha;
+ mozilla::gfx::Float shadowBlur;
+ nsTArray<mozilla::gfx::Float> dash;
+ mozilla::gfx::Float dashOffset;
+
+ mozilla::gfx::CompositionOp op;
+ mozilla::gfx::FillRule fillRule;
+ mozilla::gfx::CapStyle lineCap;
+ mozilla::gfx::JoinStyle lineJoin;
+
+ nsString filterString;
+ nsTArray<nsStyleFilter> filterChain;
+ RefPtr<nsSVGFilterChainObserver> filterChainObserver;
+ mozilla::gfx::FilterDescription filter;
+ nsTArray<RefPtr<mozilla::gfx::SourceSurface>> filterAdditionalImages;
+
+ // This keeps track of whether the canvas was "tainted" or not when
+ // we last used a filter. This is a security measure, whereby the
+ // canvas is flipped to write-only if a cross-origin image is drawn to it.
+ // This is to stop bad actors from reading back data they shouldn't have
+ // access to.
+ //
+ // This also limits what filters we can apply to the context; in particular
+ // feDisplacementMap is restricted.
+ //
+ // We keep track of this to ensure that if this gets out of sync with the
+ // tainted state of the canvas itself, we update our filters accordingly.
+ bool filterSourceGraphicTainted;
+
+ bool imageSmoothingEnabled;
+ bool fontExplicitLanguage;
+ };
+
+ AutoTArray<ContextState, 3> mStyleStack;
+
+ /**
+ * We also have a device space pathbuilder. The reason for this is as
+ * follows, when a path is being built, but the transform changes, we
+ * can no longer keep a single path in userspace, considering there's
+ * several 'user spaces' now. We therefore transform the current path
+ * into device space, and add all operations to this path in device
+ * space.
+ *
+ * When then finally executing a render, the Azure drawing API expects
+ * the path to be in userspace. We could then set an identity transform
+ * on the DrawTarget and do all drawing in device space. This is
+ * undesirable because it requires transforming patterns, gradients,
+ * clips, etc. into device space and it would not work for stroking.
+ * What we do instead is convert the path back to user space when it is
+ * drawn, and draw it with the current transform. This makes all drawing
+ * occur correctly.
+ *
+ * There's never both a device space path builder and a user space path
+ * builder present at the same time. There is also never a path and a
+ * path builder present at the same time. When writing proceeds on an
+ * existing path the Path is cleared and a new builder is created.
+ *
+ * mPath is always in user-space.
+ */
+ RefPtr<mozilla::gfx::Path> mPath;
+ RefPtr<mozilla::gfx::PathBuilder> mPathBuilder;
+ bool mPathTransformWillUpdate;
+ mozilla::gfx::Matrix mPathToDS;
+
+protected:
+ virtual bool AlreadyShutDown() const = 0;
+
+ /**
+ * Create the backing surfacing, if it doesn't exist. If there is an error
+ * in creating the target then it will put sErrorTarget in place. If there
+ * is in turn an error in creating the sErrorTarget then they would both
+ * be null so IsTargetValid() would still return null.
+ *
+ * Returns the actual rendering mode being used by the created target.
+ */
+ virtual RenderingMode
+ EnsureTarget(const gfx::Rect* aCoveredRect = nullptr,
+ RenderingMode aRenderMode = RenderingMode::DefaultBackendMode) = 0;
+
+ /**
+ * Check if the target is valid after calling EnsureTarget.
+ */
+ virtual bool IsTargetValid() const = 0;
+
+ inline ContextState& CurrentState() {
+ return mStyleStack[mStyleStack.Length() - 1];
+ }
+
+ inline const ContextState& CurrentState() const {
+ return mStyleStack[mStyleStack.Length() - 1];
+ }
+
+
+ /**
+ * Needs to be called before updating the transform. This makes a call to
+ * EnsureTarget() so you don't have to.
+ */
+ void TransformWillUpdate();
};
} // namespace dom
} // namespace mozilla
#endif /* BasicRenderingContext2D_h */
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -155,21 +155,16 @@ using namespace mozilla::css;
using namespace mozilla::gfx;
using namespace mozilla::image;
using namespace mozilla::ipc;
using namespace mozilla::layers;
namespace mozilla {
namespace dom {
-// Cap sigma to avoid overly large temp surfaces.
-const Float SIGMA_MAX = 100;
-
-const size_t MAX_STYLE_STACK_SIZE = 1024;
-
/* Memory reporter stuff */
static int64_t gCanvasAzureMemoryUsed = 0;
// This is KIND_OTHER because it's not always clear where in memory the pixels
// of a canvas are stored. Furthermore, this memory will be tracked by the
// underlying surface implementations. See bug 655638 for details.
class Canvas2dPixelsReporter final : public nsIMemoryReporter
{
@@ -1060,30 +1055,30 @@ NS_INTERFACE_MAP_END
uint32_t CanvasRenderingContext2D::sNumLivingContexts = 0;
DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
static bool sMaxContextsInitialized = false;
static int32_t sMaxContexts = 0;
CanvasRenderingContext2D::CanvasRenderingContext2D(layers::LayersBackend aCompositorBackend)
- : mRenderingMode(RenderingMode::OpenGLBackendMode)
+ : BasicRenderingContext2D(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)
, mIsEntireFrameInvalid(false)
, mPredictManyRedrawCalls(false)
, mIsCapturedFrameInvalid(false)
- , mPathTransformWillUpdate(false)
, mInvalidateCount(0)
{
if (!sMaxContextsInitialized) {
sMaxContexts = gfxPrefs::CanvasAzureAcceleratedLimit();
sMaxContextsInitialized = true;
}
sNumLivingContexts++;
@@ -2128,54 +2123,16 @@ CanvasRenderingContext2D::GetInputStream
SurfaceFormat
CanvasRenderingContext2D::GetSurfaceFormat() const
{
return mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
}
//
-// state
-//
-
-void
-CanvasRenderingContext2D::Save()
-{
- EnsureTarget();
- mStyleStack[mStyleStack.Length() - 1].transform = mTarget->GetTransform();
- mStyleStack.SetCapacity(mStyleStack.Length() + 1);
- mStyleStack.AppendElement(CurrentState());
-
- if (mStyleStack.Length() > MAX_STYLE_STACK_SIZE) {
- // This is not fast, but is better than OOMing and shouldn't be hit by
- // reasonable code.
- mStyleStack.RemoveElementAt(0);
- }
-}
-
-void
-CanvasRenderingContext2D::Restore()
-{
- if (mStyleStack.Length() - 1 == 0)
- return;
-
- TransformWillUpdate();
-
- for (const auto& clipOrTransform : CurrentState().clipsAndTransforms) {
- if (clipOrTransform.IsClip()) {
- mTarget->PopClip();
- }
- }
-
- mStyleStack.RemoveElementAt(mStyleStack.Length() - 1);
-
- mTarget->SetTransform(CurrentState().transform);
-}
-
-//
// transformations
//
void
CanvasRenderingContext2D::Scale(double aX, double aY, ErrorResult& aError)
{
TransformWillUpdate();
if (!IsTargetValid()) {
@@ -3586,35 +3543,16 @@ CanvasRenderingContext2D::EnsureUserSpac
mPathBuilder = mPath->CopyToBuilder(fillRule);
mPath = mPathBuilder->Finish();
mPathBuilder = nullptr;
}
NS_ASSERTION(mPath, "mPath should exist");
}
-void
-CanvasRenderingContext2D::TransformWillUpdate()
-{
- EnsureTarget();
-
- // Store the matrix that would transform the current path to device
- // space.
- if (mPath || mPathBuilder) {
- if (!mPathTransformWillUpdate) {
- // If the transform has already been updated, but a device space builder
- // has not been created yet mPathToDS contains the right transform to
- // transform the current mPath into device space.
- // We should leave it alone.
- mPathToDS = mTarget->GetTransform();
- }
- mPathTransformWillUpdate = true;
- }
-}
-
//
// text
//
void
CanvasRenderingContext2D::SetFont(const nsAString& aFont,
ErrorResult& aError)
{
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -21,40 +21,34 @@
#include "mozilla/dom/CanvasPattern.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/UniquePtr.h"
#include "gfx2DGlue.h"
#include "imgIEncoder.h"
#include "nsLayoutUtils.h"
#include "mozilla/EnumeratedArray.h"
-#include "FilterSupport.h"
-#include "nsSVGEffects.h"
#include "Layers.h"
class nsGlobalWindow;
class nsXULElement;
namespace mozilla {
namespace gl {
class SourceSurface;
} // namespace gl
namespace dom {
-class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
-typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource;
class ImageData;
class StringOrCanvasGradientOrCanvasPattern;
class OwningStringOrCanvasGradientOrCanvasPattern;
class TextMetrics;
class CanvasFilterChainObserver;
class CanvasPath;
-extern const mozilla::gfx::Float SIGMA_MAX;
-
template<typename T> class Optional;
struct CanvasBidiProcessor;
class CanvasRenderingContext2DUserData;
class CanvasDrawObserver;
class CanvasShutdownObserver;
/**
@@ -77,18 +71,16 @@ public:
if (!mCanvasElement || mCanvasElement->IsInNativeAnonymousSubtree()) {
return nullptr;
}
// corresponds to changes to the old bindings made in bug 745025
return mCanvasElement->GetOriginalCanvas();
}
- void Save() override;
- void Restore() override;
void Scale(double aX, double aY, mozilla::ErrorResult& aError) override;
void Rotate(double aAngle, mozilla::ErrorResult& aError) override;
void Translate(double aX, double aY, mozilla::ErrorResult& aError) override;
void Transform(double aM11, double aM12, double aM21, double aM22,
double aDx, double aDy, mozilla::ErrorResult& aError) override;
void SetTransform(double aM11, double aM12, double aM21, double aM22,
double aDx, double aDy, mozilla::ErrorResult& aError) override;
void ResetTransform(mozilla::ErrorResult& aError) override;
@@ -407,22 +399,16 @@ public:
}
}
void DrawWindow(nsGlobalWindow& aWindow, double aX, double aY,
double aW, double aH,
const nsAString& aBgColor, uint32_t aFlags,
mozilla::ErrorResult& aError);
- enum RenderingMode {
- SoftwareBackendMode,
- OpenGLBackendMode,
- DefaultBackendMode
- };
-
bool SwitchRenderingMode(RenderingMode aRenderingMode);
// Eventually this should be deprecated. Keeping for now to keep the binding functional.
void Demote();
nsresult Redraw();
virtual int32_t GetWidth() const override;
@@ -485,31 +471,24 @@ public:
*/
virtual void DidRefresh() override;
// this rect is in mTarget's current user space
void RedrawUser(const gfxRect& aR);
// nsISupports interface + CC
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(CanvasRenderingContext2D)
enum class CanvasMultiGetterType : uint8_t {
STRING = 0,
PATTERN = 1,
GRADIENT = 2
};
- enum class Style : uint8_t {
- STROKE = 0,
- FILL,
- MAX
- };
-
nsINode* GetParentObject()
{
return mCanvasElement;
}
void LineTo(const mozilla::gfx::Point& aPoint)
{
if (mPathBuilder) {
@@ -624,35 +603,30 @@ protected:
* device space.
* After calling this function mPathTransformWillUpdate will be false
*/
void EnsureWritablePath();
// Ensures a path in UserSpace is available.
void EnsureUserSpacePath(const CanvasWindingRule& aWinding = CanvasWindingRule::Nonzero);
- /**
- * Needs to be called before updating the transform. This makes a call to
- * EnsureTarget() so you don't have to.
- */
- void TransformWillUpdate();
-
// Report the fillRule has changed.
void FillRuleChanged();
- /**
+ /**
* Create the backing surfacing, if it doesn't exist. If there is an error
* in creating the target then it will put sErrorTarget in place. If there
* is in turn an error in creating the sErrorTarget then they would both
* be null so IsTargetValid() would still return null.
*
* Returns the actual rendering mode being used by the created target.
*/
- RenderingMode EnsureTarget(const gfx::Rect* aCoveredRect = nullptr,
- RenderingMode aRenderMode = RenderingMode::DefaultBackendMode);
+ virtual RenderingMode
+ EnsureTarget(const gfx::Rect* aCoveredRect = nullptr,
+ RenderingMode aRenderMode = RenderingMode::DefaultBackendMode) override;
void RestoreClipsAndTransformToTarget();
bool TrySkiaGLTarget(RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
bool TrySharedTarget(RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
@@ -688,17 +662,17 @@ protected:
* Returns the target to the buffer provider. i.e. this will queue a frame for
* rendering.
*/
void ReturnTarget(bool aForceReset = false);
/**
* Check if the target is valid after calling EnsureTarget.
*/
- bool IsTargetValid() const {
+ bool IsTargetValid() const override{
return !!mTarget && mTarget != sErrorTarget;
}
/**
* Returns the surface format this canvas should be allocated using. Takes
* into account mOpaque, platform requirements, etc.
*/
mozilla::gfx::SurfaceFormat GetSurfaceFormat() const;
@@ -771,34 +745,29 @@ protected:
bool mHasPendingStableStateCallback;
nsTArray<CanvasRenderingContext2DUserData*> mUserDatas;
// If mCanvasElement is not provided, then a docshell is
nsCOMPtr<nsIDocShell> mDocShell;
- // This is created lazily so it is necessary to call EnsureTarget before
- // accessing it. In the event of an error it will be equal to
- // sErrorTarget.
- RefPtr<mozilla::gfx::DrawTarget> mTarget;
-
RefPtr<mozilla::layers::PersistentBufferProvider> mBufferProvider;
uint32_t SkiaGLTex() const;
// This observes our draw calls at the beginning of the canvas
// lifetime and switches to software or GPU mode depending on
// what it thinks is best
CanvasDrawObserver* mDrawObserver;
void RemoveDrawObserver();
RefPtr<CanvasShutdownObserver> mShutdownObserver;
void RemoveShutdownObserver();
- bool AlreadyShutDown() const { return !mShutdownObserver; }
+ virtual bool AlreadyShutDown() const override{ return !mShutdownObserver; }
/**
* Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
* Redraw is called, reset to false when Render is called.
*/
bool mIsEntireFrameInvalid;
/**
* When this is set, the first call to Redraw(gfxRect) should set
@@ -833,21 +802,17 @@ protected:
*
* There's never both a device space path builder and a user space path
* builder present at the same time. There is also never a path and a
* path builder present at the same time. When writing proceeds on an
* existing path the Path is cleared and a new builder is created.
*
* mPath is always in user-space.
*/
- RefPtr<mozilla::gfx::Path> mPath;
RefPtr<mozilla::gfx::PathBuilder> mDSPathBuilder;
- RefPtr<mozilla::gfx::PathBuilder> mPathBuilder;
- bool mPathTransformWillUpdate;
- mozilla::gfx::Matrix mPathToDS;
/**
* Number of times we've invalidated before calling redraw
*/
uint32_t mInvalidateCount;
static const uint32_t kCanvasMaxInvalidateCount = 100;
/**
@@ -914,33 +879,16 @@ protected:
}
return CurrentState().op;
}
// text
protected:
- enum class TextAlign : uint8_t {
- START,
- END,
- LEFT,
- RIGHT,
- CENTER
- };
-
- enum class TextBaseline : uint8_t {
- TOP,
- HANGING,
- MIDDLE,
- ALPHABETIC,
- IDEOGRAPHIC,
- BOTTOM
- };
-
enum class TextDrawOperation : uint8_t {
FILL,
STROKE,
MEASURE
};
protected:
gfxFontGroup *GetCurrentFontStyle();
@@ -953,187 +901,16 @@ protected:
float aX,
float aY,
const Optional<double>& aMaxWidth,
TextDrawOperation aOp,
float* aWidth);
bool CheckSizeForSkiaGL(mozilla::gfx::IntSize aSize);
- // A clip or a transform, recorded and restored in order.
- struct ClipState {
- explicit ClipState(mozilla::gfx::Path* aClip)
- : clip(aClip)
- {}
-
- explicit ClipState(const mozilla::gfx::Matrix& aTransform)
- : transform(aTransform)
- {}
-
- bool IsClip() const { return !!clip; }
-
- RefPtr<mozilla::gfx::Path> clip;
- mozilla::gfx::Matrix transform;
- };
-
- // state stack handling
- class ContextState {
- public:
- ContextState() : textAlign(TextAlign::START),
- textBaseline(TextBaseline::ALPHABETIC),
- shadowColor(0),
- lineWidth(1.0f),
- miterLimit(10.0f),
- globalAlpha(1.0f),
- shadowBlur(0.0),
- dashOffset(0.0f),
- op(mozilla::gfx::CompositionOp::OP_OVER),
- fillRule(mozilla::gfx::FillRule::FILL_WINDING),
- lineCap(mozilla::gfx::CapStyle::BUTT),
- lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL),
- filterString(u"none"),
- filterSourceGraphicTainted(false),
- imageSmoothingEnabled(true),
- fontExplicitLanguage(false)
- { }
-
- ContextState(const ContextState& aOther)
- : fontGroup(aOther.fontGroup),
- fontLanguage(aOther.fontLanguage),
- fontFont(aOther.fontFont),
- gradientStyles(aOther.gradientStyles),
- patternStyles(aOther.patternStyles),
- colorStyles(aOther.colorStyles),
- font(aOther.font),
- textAlign(aOther.textAlign),
- textBaseline(aOther.textBaseline),
- shadowColor(aOther.shadowColor),
- transform(aOther.transform),
- shadowOffset(aOther.shadowOffset),
- lineWidth(aOther.lineWidth),
- miterLimit(aOther.miterLimit),
- globalAlpha(aOther.globalAlpha),
- shadowBlur(aOther.shadowBlur),
- dash(aOther.dash),
- dashOffset(aOther.dashOffset),
- op(aOther.op),
- fillRule(aOther.fillRule),
- lineCap(aOther.lineCap),
- lineJoin(aOther.lineJoin),
- filterString(aOther.filterString),
- filterChain(aOther.filterChain),
- filterChainObserver(aOther.filterChainObserver),
- filter(aOther.filter),
- filterAdditionalImages(aOther.filterAdditionalImages),
- filterSourceGraphicTainted(aOther.filterSourceGraphicTainted),
- imageSmoothingEnabled(aOther.imageSmoothingEnabled),
- fontExplicitLanguage(aOther.fontExplicitLanguage)
- { }
-
- void SetColorStyle(Style aWhichStyle, nscolor aColor)
- {
- colorStyles[aWhichStyle] = aColor;
- gradientStyles[aWhichStyle] = nullptr;
- patternStyles[aWhichStyle] = nullptr;
- }
-
- void SetPatternStyle(Style aWhichStyle, CanvasPattern* aPat)
- {
- gradientStyles[aWhichStyle] = nullptr;
- patternStyles[aWhichStyle] = aPat;
- }
-
- void SetGradientStyle(Style aWhichStyle, CanvasGradient* aGrad)
- {
- gradientStyles[aWhichStyle] = aGrad;
- patternStyles[aWhichStyle] = nullptr;
- }
-
- /**
- * returns true iff the given style is a solid color.
- */
- bool StyleIsColor(Style aWhichStyle) const
- {
- return !(patternStyles[aWhichStyle] || gradientStyles[aWhichStyle]);
- }
-
- int32_t ShadowBlurRadius() const
- {
- static const gfxFloat GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * 1.5;
- return (int32_t)floor(ShadowBlurSigma() * GAUSSIAN_SCALE_FACTOR + 0.5);
- }
-
- mozilla::gfx::Float ShadowBlurSigma() const
- {
- return std::min(SIGMA_MAX, shadowBlur / 2.0f);
- }
-
- nsTArray<ClipState> clipsAndTransforms;
-
- RefPtr<gfxFontGroup> fontGroup;
- nsCOMPtr<nsIAtom> fontLanguage;
- nsFont fontFont;
-
- EnumeratedArray<Style, Style::MAX, RefPtr<CanvasGradient>> gradientStyles;
- EnumeratedArray<Style, Style::MAX, RefPtr<CanvasPattern>> patternStyles;
- EnumeratedArray<Style, Style::MAX, nscolor> colorStyles;
-
- nsString font;
- TextAlign textAlign;
- TextBaseline textBaseline;
-
- nscolor shadowColor;
-
- mozilla::gfx::Matrix transform;
- mozilla::gfx::Point shadowOffset;
- mozilla::gfx::Float lineWidth;
- mozilla::gfx::Float miterLimit;
- mozilla::gfx::Float globalAlpha;
- mozilla::gfx::Float shadowBlur;
- nsTArray<mozilla::gfx::Float> dash;
- mozilla::gfx::Float dashOffset;
-
- mozilla::gfx::CompositionOp op;
- mozilla::gfx::FillRule fillRule;
- mozilla::gfx::CapStyle lineCap;
- mozilla::gfx::JoinStyle lineJoin;
-
- nsString filterString;
- nsTArray<nsStyleFilter> filterChain;
- RefPtr<nsSVGFilterChainObserver> filterChainObserver;
- mozilla::gfx::FilterDescription filter;
- nsTArray<RefPtr<mozilla::gfx::SourceSurface>> filterAdditionalImages;
-
- // This keeps track of whether the canvas was "tainted" or not when
- // we last used a filter. This is a security measure, whereby the
- // canvas is flipped to write-only if a cross-origin image is drawn to it.
- // This is to stop bad actors from reading back data they shouldn't have
- // access to.
- //
- // This also limits what filters we can apply to the context; in particular
- // feDisplacementMap is restricted.
- //
- // We keep track of this to ensure that if this gets out of sync with the
- // tainted state of the canvas itself, we update our filters accordingly.
- bool filterSourceGraphicTainted;
-
- bool imageSmoothingEnabled;
- bool fontExplicitLanguage;
- };
-
- AutoTArray<ContextState, 3> mStyleStack;
-
- inline ContextState& CurrentState() {
- return mStyleStack[mStyleStack.Length() - 1];
- }
-
- inline const ContextState& CurrentState() const {
- return mStyleStack[mStyleStack.Length() - 1];
- }
-
friend class CanvasGeneralPattern;
friend class CanvasFilterChainObserver;
friend class AdjustedTarget;
friend class AdjustedTargetForShadow;
friend class AdjustedTargetForFilter;
// other helpers
void GetAppUnitsValues(int32_t* aPerDevPixel, int32_t* aPerCSSPixel)
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -68,16 +68,17 @@ EXPORTS.mozilla.dom += [
'ImageData.h',
'OffscreenCanvas.h',
'TextMetrics.h',
'WebGLVertexArrayObject.h',
]
# Canvas 2D and common sources
UNIFIED_SOURCES += [
+ 'BasicRenderingContext2D.cpp',
'CanvasImageCache.cpp',
'CanvasRenderingContext2D.cpp',
'CanvasRenderingContextHelper.cpp',
'CanvasUtils.cpp',
'DocumentRendererChild.cpp',
'DocumentRendererParent.cpp',
'ImageBitmap.cpp',
'ImageBitmapColorUtils.cpp',