diff --git a/gfx/2d/PathRecording.cpp b/gfx/2d/PathRecording.cpp index 21e210daa8b8..5d1edfd994fd 100644 --- a/gfx/2d/PathRecording.cpp +++ b/gfx/2d/PathRecording.cpp @@ -150,52 +150,63 @@ size_t PathOps::NumberOfOps() const { void PathBuilderRecording::MoveTo(const Point& aPoint) { mPathOps.MoveTo(aPoint); - mPathBuilder->MoveTo(aPoint); + mBeginPoint = aPoint; + mCurrentPoint = aPoint; } void PathBuilderRecording::LineTo(const Point& aPoint) { mPathOps.LineTo(aPoint); - mPathBuilder->LineTo(aPoint); + mCurrentPoint = aPoint; } void PathBuilderRecording::BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) { mPathOps.BezierTo(aCP1, aCP2, aCP3); - mPathBuilder->BezierTo(aCP1, aCP2, aCP3); + mCurrentPoint = aCP3; } void PathBuilderRecording::QuadraticBezierTo(const Point& aCP1, const Point& aCP2) { mPathOps.QuadraticBezierTo(aCP1, aCP2); - mPathBuilder->QuadraticBezierTo(aCP1, aCP2); + mCurrentPoint = aCP2; } void PathBuilderRecording::Close() { mPathOps.Close(); - mPathBuilder->Close(); + mCurrentPoint = mBeginPoint; } void PathBuilderRecording::Arc(const Point& aOrigin, float aRadius, float aStartAngle, float aEndAngle, bool aAntiClockwise) { mPathOps.Arc(aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise); - mPathBuilder->Arc(aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise); + + // This just lets ArcToBezier override the current point without modifying + // path ops or having to instantiate a path. + struct CurrentPointTracker { + PathBuilderRecording* mPathBuilder; + + void LineTo(const Point& aPoint) { mPathBuilder->SetCurrentPoint(aPoint); } + + void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) { + mPathBuilder->SetCurrentPoint(aCP3); + } + } tracker = {this}; + + ArcToBezier(&tracker, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, + aAntiClockwise); } already_AddRefed PathBuilderRecording::Finish() { - // We rely on mPathBuilder to track begin and current point, but that stops - // when we call Finish, so we need to store them first. - Point beginPoint = BeginPoint(); - Point currentPoint = CurrentPoint(); - RefPtr path = mPathBuilder->Finish(); - return MakeAndAddRef(path, std::move(mPathOps), mFillRule, - currentPoint, beginPoint); + return MakeAndAddRef(std::move(mPathBuilder), + std::move(mPathOps), mFillRule, + mBeginPoint, mCurrentPoint); } -PathRecording::PathRecording(Path* aPath, PathOps&& aOps, FillRule aFillRule, - const Point& aCurrentPoint, +PathRecording::PathRecording(RefPtr&& aPathBuilder, PathOps&& aOps, + FillRule aFillRule, const Point& aCurrentPoint, const Point& aBeginPoint) - : mPath(aPath), + : mPathBuilder(std::move(aPathBuilder)), mPathOps(std::move(aOps)), mFillRule(aFillRule), mCurrentPoint(aCurrentPoint), @@ -208,8 +219,23 @@ PathRecording::~PathRecording() { } } +void PathRecording::EnsurePath() const { + if (mPath) { + return; + } + MOZ_ASSERT(!!mPathBuilder); + if (!mPathOps.StreamToSink(*mPathBuilder)) { + MOZ_ASSERT(false, "Failed to stream PathOps to PathBuilder"); + } else { + mPath = mPathBuilder->Finish(); + MOZ_ASSERT(!!mPath, "Failed finishing Path from PathBuilder"); + } + mPathBuilder = nullptr; +} + already_AddRefed PathRecording::CopyToBuilder( FillRule aFillRule) const { + EnsurePath(); RefPtr pathBuilder = mPath->CopyToBuilder(aFillRule); RefPtr recording = new PathBuilderRecording(pathBuilder, mPathOps, aFillRule); @@ -220,6 +246,7 @@ already_AddRefed PathRecording::CopyToBuilder( already_AddRefed PathRecording::TransformedCopyToBuilder( const Matrix& aTransform, FillRule aFillRule) const { + EnsurePath(); RefPtr pathBuilder = mPath->TransformedCopyToBuilder(aTransform, aFillRule); RefPtr recording = new PathBuilderRecording( diff --git a/gfx/2d/PathRecording.h b/gfx/2d/PathRecording.h index 78cd04674f98..6bcabd8ab808 100644 --- a/gfx/2d/PathRecording.h +++ b/gfx/2d/PathRecording.h @@ -153,21 +153,6 @@ class PathBuilderRecording final : public PathBuilder { void Arc(const Point& aOrigin, float aRadius, float aStartAngle, float aEndAngle, bool aAntiClockwise) final; - /* Point the current subpath is at - or where the next subpath will start - * if there is no active subpath. - */ - Point CurrentPoint() const final { return mPathBuilder->CurrentPoint(); } - - Point BeginPoint() const final { return mPathBuilder->BeginPoint(); } - - void SetCurrentPoint(const Point& aPoint) final { - mPathBuilder->SetCurrentPoint(aPoint); - } - - void SetBeginPoint(const Point& aPoint) final { - mPathBuilder->SetBeginPoint(aPoint); - } - already_AddRefed Finish() final; BackendType GetBackendType() const final { return BackendType::RECORDING; } @@ -182,7 +167,7 @@ class PathRecording final : public Path { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathRecording, override) - PathRecording(Path* aPath, PathOps&& aOps, FillRule aFillRule, + PathRecording(RefPtr&& aPath, PathOps&& aOps, FillRule aFillRule, const Point& aCurrentPoint, const Point& aBeginPoint); ~PathRecording(); @@ -193,26 +178,35 @@ class PathRecording final : public Path { const Matrix& aTransform, FillRule aFillRule) const 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 { return mPath->AsRect(); } + Maybe AsRect() const final { + EnsurePath(); + return mPath->AsRect(); + } - void StreamToSink(PathSink* aSink) const final { mPath->StreamToSink(aSink); } + void StreamToSink(PathSink* aSink) const final { + mPathOps.StreamToSink(*aSink); + } FillRule GetFillRule() const final { return mFillRule; } @@ -221,7 +215,10 @@ class PathRecording final : public Path { friend class DrawTargetRecording; friend class RecordedPathCreation; - RefPtr mPath; + void EnsurePath() const; + + mutable RefPtr mPathBuilder; + mutable RefPtr mPath; PathOps mPathOps; FillRule mFillRule; Point mCurrentPoint;