/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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_PATHRECORDING_H_ #define MOZILLA_GFX_PATHRECORDING_H_ #include "2D.h" #include #include #include "PathHelpers.h" #include "RecordingTypes.h" namespace mozilla { namespace gfx { struct Circle { Point origin; float radius; bool closed = false; }; struct Line { Point origin; Point destination; }; class PathOps { public: PathOps() = default; template explicit PathOps(S& aStream); PathOps(const PathOps& aOther) = default; PathOps& operator=(const PathOps&) = delete; // assign using std::move()! PathOps(PathOps&& aOther) = default; PathOps& operator=(PathOps&& aOther) = default; template void Record(S& aStream) const; bool StreamToSink(PathSink& aPathSink) const; bool CheckedStreamToSink(PathSink& aPathSink) const; PathOps TransformedCopy(const Matrix& aTransform) const; void TransformInPlace(const Matrix& aTransform); size_t NumberOfOps() const; private: enum class OpType : uint32_t { OP_MOVETO = 0, OP_LINETO, OP_BEZIERTO, OP_QUADRATICBEZIERTO, OP_ARC_CW, OP_ARC_CCW, OP_CLOSE, OP_INVALID }; template void AppendPathOp(const T& aOpData) { mPathData.insert(mPathData.end(), (const uint8_t*)(&aOpData), (const uint8_t*)(&aOpData + 1)); } template void AppendPathOp(const OpType& aOpType, const T& aOpParams) { AppendPathOp(aOpType); AppendPathOp(aOpParams); } struct TwoPoints { Point p1; Point p2; }; struct ThreePoints { Point p1; Point p2; Point p3; }; struct ArcParams { Matrix transform; float startAngle; float endAngle; Point GetOrigin() const { return transform.GetTranslation(); } Maybe GetRadius() const; void ToSink(PathSink& aPathSink, bool aAntiClockwise) const; }; public: void MoveTo(const Point& aPoint) { AppendPathOp(OpType::OP_MOVETO, aPoint); } void LineTo(const Point& aPoint) { AppendPathOp(OpType::OP_LINETO, aPoint); } void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) { AppendPathOp(OpType::OP_BEZIERTO, ThreePoints{aCP1, aCP2, aCP3}); } void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) { AppendPathOp(OpType::OP_QUADRATICBEZIERTO, TwoPoints{aCP1, aCP2}); } void Arc(const Matrix& aTransform, float aStartAngle, float aEndAngle, bool aAntiClockwise) { AppendPathOp(aAntiClockwise ? OpType::OP_ARC_CCW : OpType::OP_ARC_CW, ArcParams{aTransform, aStartAngle, aEndAngle}); } void Arc(const Point& aOrigin, float aRadius, float aStartAngle, float aEndAngle, bool aAntiClockwise) { Arc(Matrix(aRadius, 0.0f, 0.0f, aRadius, aOrigin.x, aOrigin.y), aStartAngle, aEndAngle, aAntiClockwise); } void Close() { AppendPathOp(OpType::OP_CLOSE); } Maybe AsCircle() const; Maybe AsLine() const; bool IsActive() const { return !mPathData.empty(); } bool IsEmpty() const; private: std::vector mPathData; }; template PathOps::PathOps(S& aStream) { ReadVector(aStream, mPathData); } template inline void PathOps::Record(S& aStream) const { WriteVector(aStream, mPathData); } class PathRecording; class DrawEventRecorderPrivate; class PathBuilderRecording final : public PathBuilder { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderRecording, override) PathBuilderRecording(BackendType aBackend, FillRule aFillRule) : mBackendType(aBackend), mFillRule(aFillRule) {} PathBuilderRecording(BackendType aBackend, PathOps&& aPathOps, FillRule aFillRule) : mBackendType(aBackend), mFillRule(aFillRule), mPathOps(std::move(aPathOps)) {} /* Move the current point in the path, any figure currently being drawn will * be considered closed during fill operations, however when stroking the * closing line segment will not be drawn. */ void MoveTo(const Point& aPoint) final; /* Add a linesegment to the current figure */ void LineTo(const Point& aPoint) final; /* Add a cubic bezier curve to the current figure */ void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) final; /* Add a quadratic bezier curve to the current figure */ void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) final; /* Close the current figure, this will essentially generate a line segment * from the current point to the starting point for the current figure */ void Close() final; /* Add an arc to the current figure */ void Arc(const Point& aOrigin, float aRadius, float aStartAngle, float aEndAngle, bool aAntiClockwise) final; already_AddRefed Finish() final; BackendType GetBackendType() const final { return BackendType::RECORDING; } bool IsActive() const final { return mPathOps.IsActive(); } private: BackendType mBackendType; FillRule mFillRule; PathOps mPathOps; }; class PathRecording final : public Path { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathRecording, override) PathRecording(BackendType aBackend, PathOps&& aOps, FillRule aFillRule, const Point& aCurrentPoint, const Point& aBeginPoint); ~PathRecording(); BackendType GetBackendType() const final { return BackendType::RECORDING; } already_AddRefed CopyToBuilder(FillRule aFillRule) const final; already_AddRefed TransformedCopyToBuilder( const Matrix& aTransform, FillRule aFillRule) const final; already_AddRefed MoveToBuilder(FillRule aFillRule) final; already_AddRefed TransformedMoveToBuilder( const Matrix& aTransform, FillRule aFillRule) final; bool ContainsPoint(const Point& aPoint, const Matrix& aTransform) const final { EnsurePath(); return mPath->ContainsPoint(aPoint, aTransform); } bool StrokeContainsPoint(const StrokeOptions& aStrokeOptions, const Point& aPoint, const Matrix& aTransform) const final { EnsurePath(); return mPath->StrokeContainsPoint(aStrokeOptions, aPoint, aTransform); } Rect GetBounds(const Matrix& aTransform = Matrix()) const final { EnsurePath(); return mPath->GetBounds(aTransform); } Rect GetStrokedBounds(const StrokeOptions& aStrokeOptions, const Matrix& aTransform = Matrix()) const final { EnsurePath(); return mPath->GetStrokedBounds(aStrokeOptions, aTransform); } Maybe AsRect() const final { EnsurePath(); return mPath->AsRect(); } Maybe AsCircle() const { return mPathOps.AsCircle(); } Maybe AsLine() const { return mPathOps.AsLine(); } void StreamToSink(PathSink* aSink) const final { mPathOps.StreamToSink(*aSink); } FillRule GetFillRule() const final { return mFillRule; } bool IsEmpty() const final { return mPathOps.IsEmpty(); } private: friend class DrawTargetWrapAndRecord; friend class DrawTargetRecording; friend class RecordedPathCreation; void EnsurePath() const; BackendType mBackendType; mutable RefPtr mPath; PathOps mPathOps; FillRule mFillRule; Point mCurrentPoint; Point mBeginPoint; // Event recorders that have this path in their event stream. std::vector> mStoredRecorders; }; } // namespace gfx } // namespace mozilla #endif /* MOZILLA_GFX_PATHRECORDING_H_ */