summaryrefslogtreecommitdiffstats
path: root/gfx/2d/DrawCommand.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/2d/DrawCommand.h')
-rw-r--r--gfx/2d/DrawCommand.h594
1 files changed, 594 insertions, 0 deletions
diff --git a/gfx/2d/DrawCommand.h b/gfx/2d/DrawCommand.h
new file mode 100644
index 000000000..eb415c70a
--- /dev/null
+++ b/gfx/2d/DrawCommand.h
@@ -0,0 +1,594 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_DRAWCOMMAND_H_
+#define MOZILLA_GFX_DRAWCOMMAND_H_
+
+#include <math.h>
+
+#include "2D.h"
+#include "Filters.h"
+#include <vector>
+
+namespace mozilla {
+namespace gfx {
+
+enum class CommandType : int8_t {
+ DRAWSURFACE = 0,
+ DRAWFILTER,
+ DRAWSURFACEWITHSHADOW,
+ CLEARRECT,
+ COPYSURFACE,
+ COPYRECT,
+ FILLRECT,
+ STROKERECT,
+ STROKELINE,
+ STROKE,
+ FILL,
+ FILLGLYPHS,
+ MASK,
+ MASKSURFACE,
+ PUSHCLIP,
+ PUSHCLIPRECT,
+ POPCLIP,
+ SETTRANSFORM,
+ FLUSH
+};
+
+class DrawingCommand
+{
+public:
+ virtual ~DrawingCommand() {}
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aTransform = nullptr) const = 0;
+
+ virtual bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const { return false; }
+
+protected:
+ explicit DrawingCommand(CommandType aType)
+ : mType(aType)
+ {
+ }
+
+ CommandType GetType() { return mType; }
+
+private:
+ CommandType mType;
+};
+
+class StoredPattern
+{
+public:
+ explicit StoredPattern(const Pattern& aPattern)
+ {
+ Assign(aPattern);
+ }
+
+ void Assign(const Pattern& aPattern)
+ {
+ switch (aPattern.GetType()) {
+ case PatternType::COLOR:
+ new (mColor)ColorPattern(*static_cast<const ColorPattern*>(&aPattern));
+ return;
+ case PatternType::SURFACE:
+ {
+ SurfacePattern* surfPat = new (mSurface)SurfacePattern(*static_cast<const SurfacePattern*>(&aPattern));
+ surfPat->mSurface->GuaranteePersistance();
+ return;
+ }
+ case PatternType::LINEAR_GRADIENT:
+ new (mLinear)LinearGradientPattern(*static_cast<const LinearGradientPattern*>(&aPattern));
+ return;
+ case PatternType::RADIAL_GRADIENT:
+ new (mRadial)RadialGradientPattern(*static_cast<const RadialGradientPattern*>(&aPattern));
+ return;
+ }
+ }
+
+ ~StoredPattern()
+ {
+ reinterpret_cast<Pattern*>(mPattern)->~Pattern();
+ }
+
+ operator Pattern&()
+ {
+ return *reinterpret_cast<Pattern*>(mPattern);
+ }
+
+ operator const Pattern&() const
+ {
+ return *reinterpret_cast<const Pattern*>(mPattern);
+ }
+
+ StoredPattern(const StoredPattern& aPattern)
+ {
+ Assign(aPattern);
+ }
+
+private:
+ StoredPattern operator=(const StoredPattern& aOther)
+ {
+ // Block this so that we notice if someone's doing excessive assigning.
+ return *this;
+ }
+
+ union {
+ char mPattern[sizeof(Pattern)];
+ char mColor[sizeof(ColorPattern)];
+ char mLinear[sizeof(LinearGradientPattern)];
+ char mRadial[sizeof(RadialGradientPattern)];
+ char mSurface[sizeof(SurfacePattern)];
+ };
+};
+
+class DrawSurfaceCommand : public DrawingCommand
+{
+public:
+ DrawSurfaceCommand(SourceSurface *aSurface, const Rect& aDest,
+ const Rect& aSource, const DrawSurfaceOptions& aSurfOptions,
+ const DrawOptions& aOptions)
+ : DrawingCommand(CommandType::DRAWSURFACE)
+ , mSurface(aSurface), mDest(aDest)
+ , mSource(aSource), mSurfOptions(aSurfOptions)
+ , mOptions(aOptions)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->DrawSurface(mSurface, mDest, mSource, mSurfOptions, mOptions);
+ }
+
+private:
+ RefPtr<SourceSurface> mSurface;
+ Rect mDest;
+ Rect mSource;
+ DrawSurfaceOptions mSurfOptions;
+ DrawOptions mOptions;
+};
+
+class DrawFilterCommand : public DrawingCommand
+{
+public:
+ DrawFilterCommand(FilterNode* aFilter, const Rect& aSourceRect,
+ const Point& aDestPoint, const DrawOptions& aOptions)
+ : DrawingCommand(CommandType::DRAWSURFACE)
+ , mFilter(aFilter), mSourceRect(aSourceRect)
+ , mDestPoint(aDestPoint), mOptions(aOptions)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->DrawFilter(mFilter, mSourceRect, mDestPoint, mOptions);
+ }
+
+private:
+ RefPtr<FilterNode> mFilter;
+ Rect mSourceRect;
+ Point mDestPoint;
+ DrawOptions mOptions;
+};
+
+class ClearRectCommand : public DrawingCommand
+{
+public:
+ explicit ClearRectCommand(const Rect& aRect)
+ : DrawingCommand(CommandType::CLEARRECT)
+ , mRect(aRect)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->ClearRect(mRect);
+ }
+
+private:
+ Rect mRect;
+};
+
+class CopySurfaceCommand : public DrawingCommand
+{
+public:
+ CopySurfaceCommand(SourceSurface* aSurface,
+ const IntRect& aSourceRect,
+ const IntPoint& aDestination)
+ : DrawingCommand(CommandType::COPYSURFACE)
+ , mSurface(aSurface)
+ , mSourceRect(aSourceRect)
+ , mDestination(aDestination)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aTransform) const
+ {
+ MOZ_ASSERT(!aTransform || !aTransform->HasNonIntegerTranslation());
+ Point dest(Float(mDestination.x), Float(mDestination.y));
+ if (aTransform) {
+ dest = aTransform->TransformPoint(dest);
+ }
+ aDT->CopySurface(mSurface, mSourceRect, IntPoint(uint32_t(dest.x), uint32_t(dest.y)));
+ }
+
+private:
+ RefPtr<SourceSurface> mSurface;
+ IntRect mSourceRect;
+ IntPoint mDestination;
+};
+
+class FillRectCommand : public DrawingCommand
+{
+public:
+ FillRectCommand(const Rect& aRect,
+ const Pattern& aPattern,
+ const DrawOptions& aOptions)
+ : DrawingCommand(CommandType::FILLRECT)
+ , mRect(aRect)
+ , mPattern(aPattern)
+ , mOptions(aOptions)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->FillRect(mRect, mPattern, mOptions);
+ }
+
+ bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const
+ {
+ aDeviceRect = aTransform.TransformBounds(mRect);
+ return true;
+ }
+
+private:
+ Rect mRect;
+ StoredPattern mPattern;
+ DrawOptions mOptions;
+};
+
+class StrokeRectCommand : public DrawingCommand
+{
+public:
+ StrokeRectCommand(const Rect& aRect,
+ const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions,
+ const DrawOptions& aOptions)
+ : DrawingCommand(CommandType::STROKERECT)
+ , mRect(aRect)
+ , mPattern(aPattern)
+ , mStrokeOptions(aStrokeOptions)
+ , mOptions(aOptions)
+ {
+ if (aStrokeOptions.mDashLength) {
+ mDashes.resize(aStrokeOptions.mDashLength);
+ mStrokeOptions.mDashPattern = &mDashes.front();
+ memcpy(&mDashes.front(), aStrokeOptions.mDashPattern, mStrokeOptions.mDashLength * sizeof(Float));
+ }
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->StrokeRect(mRect, mPattern, mStrokeOptions, mOptions);
+ }
+
+private:
+ Rect mRect;
+ StoredPattern mPattern;
+ StrokeOptions mStrokeOptions;
+ DrawOptions mOptions;
+ std::vector<Float> mDashes;
+};
+
+class StrokeLineCommand : public DrawingCommand
+{
+public:
+ StrokeLineCommand(const Point& aStart,
+ const Point& aEnd,
+ const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions,
+ const DrawOptions& aOptions)
+ : DrawingCommand(CommandType::STROKELINE)
+ , mStart(aStart)
+ , mEnd(aEnd)
+ , mPattern(aPattern)
+ , mStrokeOptions(aStrokeOptions)
+ , mOptions(aOptions)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->StrokeLine(mStart, mEnd, mPattern, mStrokeOptions, mOptions);
+ }
+
+private:
+ Point mStart;
+ Point mEnd;
+ StoredPattern mPattern;
+ StrokeOptions mStrokeOptions;
+ DrawOptions mOptions;
+};
+
+class FillCommand : public DrawingCommand
+{
+public:
+ FillCommand(const Path* aPath,
+ const Pattern& aPattern,
+ const DrawOptions& aOptions)
+ : DrawingCommand(CommandType::FILL)
+ , mPath(const_cast<Path*>(aPath))
+ , mPattern(aPattern)
+ , mOptions(aOptions)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->Fill(mPath, mPattern, mOptions);
+ }
+
+ bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const
+ {
+ aDeviceRect = mPath->GetBounds(aTransform);
+ return true;
+ }
+
+private:
+ RefPtr<Path> mPath;
+ StoredPattern mPattern;
+ DrawOptions mOptions;
+};
+
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880
+#endif
+
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.707106781186547524400844362104849039
+#endif
+
+// The logic for this comes from _cairo_stroke_style_max_distance_from_path
+static Rect
+PathExtentsToMaxStrokeExtents(const StrokeOptions &aStrokeOptions,
+ const Rect &aRect,
+ const Matrix &aTransform)
+{
+ double styleExpansionFactor = 0.5f;
+
+ if (aStrokeOptions.mLineCap == CapStyle::SQUARE) {
+ styleExpansionFactor = M_SQRT1_2;
+ }
+
+ if (aStrokeOptions.mLineJoin == JoinStyle::MITER &&
+ styleExpansionFactor < M_SQRT2 * aStrokeOptions.mMiterLimit) {
+ styleExpansionFactor = M_SQRT2 * aStrokeOptions.mMiterLimit;
+ }
+
+ styleExpansionFactor *= aStrokeOptions.mLineWidth;
+
+ double dx = styleExpansionFactor * hypot(aTransform._11, aTransform._21);
+ double dy = styleExpansionFactor * hypot(aTransform._22, aTransform._12);
+
+ Rect result = aRect;
+ result.Inflate(dx, dy);
+ return result;
+}
+
+class StrokeCommand : public DrawingCommand
+{
+public:
+ StrokeCommand(const Path* aPath,
+ const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions,
+ const DrawOptions& aOptions)
+ : DrawingCommand(CommandType::STROKE)
+ , mPath(const_cast<Path*>(aPath))
+ , mPattern(aPattern)
+ , mStrokeOptions(aStrokeOptions)
+ , mOptions(aOptions)
+ {
+ if (aStrokeOptions.mDashLength) {
+ mDashes.resize(aStrokeOptions.mDashLength);
+ mStrokeOptions.mDashPattern = &mDashes.front();
+ memcpy(&mDashes.front(), aStrokeOptions.mDashPattern, mStrokeOptions.mDashLength * sizeof(Float));
+ }
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->Stroke(mPath, mPattern, mStrokeOptions, mOptions);
+ }
+
+ bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const
+ {
+ aDeviceRect = PathExtentsToMaxStrokeExtents(mStrokeOptions, mPath->GetBounds(aTransform), aTransform);
+ return true;
+ }
+
+private:
+ RefPtr<Path> mPath;
+ StoredPattern mPattern;
+ StrokeOptions mStrokeOptions;
+ DrawOptions mOptions;
+ std::vector<Float> mDashes;
+};
+
+class FillGlyphsCommand : public DrawingCommand
+{
+public:
+ FillGlyphsCommand(ScaledFont* aFont,
+ const GlyphBuffer& aBuffer,
+ const Pattern& aPattern,
+ const DrawOptions& aOptions,
+ const GlyphRenderingOptions* aRenderingOptions)
+ : DrawingCommand(CommandType::FILLGLYPHS)
+ , mFont(aFont)
+ , mPattern(aPattern)
+ , mOptions(aOptions)
+ , mRenderingOptions(const_cast<GlyphRenderingOptions*>(aRenderingOptions))
+ {
+ mGlyphs.resize(aBuffer.mNumGlyphs);
+ memcpy(&mGlyphs.front(), aBuffer.mGlyphs, sizeof(Glyph) * aBuffer.mNumGlyphs);
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ GlyphBuffer buf;
+ buf.mNumGlyphs = mGlyphs.size();
+ buf.mGlyphs = &mGlyphs.front();
+ aDT->FillGlyphs(mFont, buf, mPattern, mOptions, mRenderingOptions);
+ }
+
+private:
+ RefPtr<ScaledFont> mFont;
+ std::vector<Glyph> mGlyphs;
+ StoredPattern mPattern;
+ DrawOptions mOptions;
+ RefPtr<GlyphRenderingOptions> mRenderingOptions;
+};
+
+class MaskCommand : public DrawingCommand
+{
+public:
+ MaskCommand(const Pattern& aSource,
+ const Pattern& aMask,
+ const DrawOptions& aOptions)
+ : DrawingCommand(CommandType::MASK)
+ , mSource(aSource)
+ , mMask(aMask)
+ , mOptions(aOptions)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->Mask(mSource, mMask, mOptions);
+ }
+
+private:
+ StoredPattern mSource;
+ StoredPattern mMask;
+ DrawOptions mOptions;
+};
+
+class MaskSurfaceCommand : public DrawingCommand
+{
+public:
+ MaskSurfaceCommand(const Pattern& aSource,
+ const SourceSurface* aMask,
+ const Point& aOffset,
+ const DrawOptions& aOptions)
+ : DrawingCommand(CommandType::MASKSURFACE)
+ , mSource(aSource)
+ , mMask(const_cast<SourceSurface*>(aMask))
+ , mOffset(aOffset)
+ , mOptions(aOptions)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->MaskSurface(mSource, mMask, mOffset, mOptions);
+ }
+
+private:
+ StoredPattern mSource;
+ RefPtr<SourceSurface> mMask;
+ Point mOffset;
+ DrawOptions mOptions;
+};
+
+class PushClipCommand : public DrawingCommand
+{
+public:
+ explicit PushClipCommand(const Path* aPath)
+ : DrawingCommand(CommandType::PUSHCLIP)
+ , mPath(const_cast<Path*>(aPath))
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->PushClip(mPath);
+ }
+
+private:
+ RefPtr<Path> mPath;
+};
+
+class PushClipRectCommand : public DrawingCommand
+{
+public:
+ explicit PushClipRectCommand(const Rect& aRect)
+ : DrawingCommand(CommandType::PUSHCLIPRECT)
+ , mRect(aRect)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->PushClipRect(mRect);
+ }
+
+private:
+ Rect mRect;
+};
+
+class PopClipCommand : public DrawingCommand
+{
+public:
+ PopClipCommand()
+ : DrawingCommand(CommandType::POPCLIP)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->PopClip();
+ }
+};
+
+class SetTransformCommand : public DrawingCommand
+{
+public:
+ explicit SetTransformCommand(const Matrix& aTransform)
+ : DrawingCommand(CommandType::SETTRANSFORM)
+ , mTransform(aTransform)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aMatrix) const
+ {
+ if (aMatrix) {
+ aDT->SetTransform(mTransform * (*aMatrix));
+ } else {
+ aDT->SetTransform(mTransform);
+ }
+ }
+
+private:
+ Matrix mTransform;
+};
+
+class FlushCommand : public DrawingCommand
+{
+public:
+ explicit FlushCommand()
+ : DrawingCommand(CommandType::FLUSH)
+ {
+ }
+
+ virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
+ {
+ aDT->Flush();
+ }
+};
+
+} // namespace gfx
+
+} // namespace mozilla
+
+#endif /* MOZILLA_GFX_DRAWCOMMAND_H_ */