diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:44:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:44:51 +0000 |
commit | 9e3c08db40b8916968b9f30096c7be3f00ce9647 (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /gfx/2d/PathRecording.cpp | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/2d/PathRecording.cpp')
-rw-r--r-- | gfx/2d/PathRecording.cpp | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/gfx/2d/PathRecording.cpp b/gfx/2d/PathRecording.cpp new file mode 100644 index 0000000000..a3aaea442a --- /dev/null +++ b/gfx/2d/PathRecording.cpp @@ -0,0 +1,307 @@ +/* -*- 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/. */ + +#include "PathRecording.h" +#include "DrawEventRecorder.h" +#include "RecordedEventImpl.h" + +namespace mozilla { +namespace gfx { + +#define NEXT_PARAMS(_type) \ + const _type params = *reinterpret_cast<const _type*>(nextByte); \ + nextByte += sizeof(_type); + +bool PathOps::StreamToSink(PathSink& aPathSink) const { + if (mPathData.empty()) { + return true; + } + + const uint8_t* nextByte = mPathData.data(); + const uint8_t* end = nextByte + mPathData.size(); + while (nextByte < end) { + const OpType opType = *reinterpret_cast<const OpType*>(nextByte); + nextByte += sizeof(OpType); + switch (opType) { + case OpType::OP_MOVETO: { + NEXT_PARAMS(Point) + aPathSink.MoveTo(params); + break; + } + case OpType::OP_LINETO: { + NEXT_PARAMS(Point) + aPathSink.LineTo(params); + break; + } + case OpType::OP_BEZIERTO: { + NEXT_PARAMS(ThreePoints) + aPathSink.BezierTo(params.p1, params.p2, params.p3); + break; + } + case OpType::OP_QUADRATICBEZIERTO: { + NEXT_PARAMS(TwoPoints) + aPathSink.QuadraticBezierTo(params.p1, params.p2); + break; + } + case OpType::OP_ARC: { + NEXT_PARAMS(ArcParams) + aPathSink.Arc(params.origin, params.radius, params.startAngle, + params.endAngle, params.antiClockwise); + break; + } + case OpType::OP_CLOSE: + aPathSink.Close(); + break; + default: + return false; + } + } + + return true; +} + +#define CHECKED_NEXT_PARAMS(_type) \ + if (nextByte + sizeof(_type) > end) { \ + return false; \ + } \ + NEXT_PARAMS(_type) + +bool PathOps::CheckedStreamToSink(PathSink& aPathSink) const { + if (mPathData.empty()) { + return true; + } + + const uint8_t* nextByte = mPathData.data(); + const uint8_t* end = nextByte + mPathData.size(); + while (true) { + if (nextByte == end) { + break; + } + + if (nextByte + sizeof(OpType) > end) { + return false; + } + + const OpType opType = *reinterpret_cast<const OpType*>(nextByte); + nextByte += sizeof(OpType); + switch (opType) { + case OpType::OP_MOVETO: { + CHECKED_NEXT_PARAMS(Point) + aPathSink.MoveTo(params); + break; + } + case OpType::OP_LINETO: { + CHECKED_NEXT_PARAMS(Point) + aPathSink.LineTo(params); + break; + } + case OpType::OP_BEZIERTO: { + CHECKED_NEXT_PARAMS(ThreePoints) + aPathSink.BezierTo(params.p1, params.p2, params.p3); + break; + } + case OpType::OP_QUADRATICBEZIERTO: { + CHECKED_NEXT_PARAMS(TwoPoints) + aPathSink.QuadraticBezierTo(params.p1, params.p2); + break; + } + case OpType::OP_ARC: { + CHECKED_NEXT_PARAMS(ArcParams) + aPathSink.Arc(params.origin, params.radius, params.startAngle, + params.endAngle, params.antiClockwise); + break; + } + case OpType::OP_CLOSE: + aPathSink.Close(); + break; + default: + return false; + } + } + + return true; +} +#undef CHECKED_NEXT_PARAMS + +PathOps PathOps::TransformedCopy(const Matrix& aTransform) const { + PathOps newPathOps; + const uint8_t* nextByte = mPathData.data(); + const uint8_t* end = nextByte + mPathData.size(); + while (nextByte < end) { + const OpType opType = *reinterpret_cast<const OpType*>(nextByte); + nextByte += sizeof(OpType); + switch (opType) { + case OpType::OP_MOVETO: { + NEXT_PARAMS(Point) + newPathOps.MoveTo(aTransform.TransformPoint(params)); + break; + } + case OpType::OP_LINETO: { + NEXT_PARAMS(Point) + newPathOps.LineTo(aTransform.TransformPoint(params)); + break; + } + case OpType::OP_BEZIERTO: { + NEXT_PARAMS(ThreePoints) + newPathOps.BezierTo(aTransform.TransformPoint(params.p1), + aTransform.TransformPoint(params.p2), + aTransform.TransformPoint(params.p3)); + break; + } + case OpType::OP_QUADRATICBEZIERTO: { + NEXT_PARAMS(TwoPoints) + newPathOps.QuadraticBezierTo(aTransform.TransformPoint(params.p1), + aTransform.TransformPoint(params.p2)); + break; + } + case OpType::OP_ARC: { + NEXT_PARAMS(ArcParams) + ArcToBezier(&newPathOps, params.origin, + gfx::Size(params.radius, params.radius), params.startAngle, + params.endAngle, params.antiClockwise, 0.0f, aTransform); + break; + } + case OpType::OP_CLOSE: + newPathOps.Close(); + break; + default: + MOZ_CRASH("We control mOpTypes, so this should never happen."); + } + } + + return newPathOps; +} + +#undef NEXT_PARAMS + +size_t PathOps::NumberOfOps() const { + size_t size = 0; + const uint8_t* nextByte = mPathData.data(); + const uint8_t* end = nextByte + mPathData.size(); + while (nextByte < end) { + size++; + const OpType opType = *reinterpret_cast<const OpType*>(nextByte); + nextByte += sizeof(OpType); + switch (opType) { + case OpType::OP_MOVETO: + nextByte += sizeof(Point); + break; + case OpType::OP_LINETO: + nextByte += sizeof(Point); + break; + case OpType::OP_BEZIERTO: + nextByte += sizeof(ThreePoints); + break; + case OpType::OP_QUADRATICBEZIERTO: + nextByte += sizeof(TwoPoints); + break; + case OpType::OP_ARC: + nextByte += sizeof(ArcParams); + break; + case OpType::OP_CLOSE: + break; + default: + MOZ_CRASH("We control mOpTypes, so this should never happen."); + } + } + + return size; +} + +void PathBuilderRecording::MoveTo(const Point& aPoint) { + mPathOps.MoveTo(aPoint); + mBeginPoint = aPoint; + mCurrentPoint = aPoint; +} + +void PathBuilderRecording::LineTo(const Point& aPoint) { + mPathOps.LineTo(aPoint); + mCurrentPoint = aPoint; +} + +void PathBuilderRecording::BezierTo(const Point& aCP1, const Point& aCP2, + const Point& aCP3) { + mPathOps.BezierTo(aCP1, aCP2, aCP3); + mCurrentPoint = aCP3; +} + +void PathBuilderRecording::QuadraticBezierTo(const Point& aCP1, + const Point& aCP2) { + mPathOps.QuadraticBezierTo(aCP1, aCP2); + mCurrentPoint = aCP2; +} + +void PathBuilderRecording::Close() { + mPathOps.Close(); + mCurrentPoint = mBeginPoint; +} + +void PathBuilderRecording::Arc(const Point& aOrigin, float aRadius, + float aStartAngle, float aEndAngle, + bool aAntiClockwise) { + mPathOps.Arc(aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise); + + mCurrentPoint = aOrigin + Point(cosf(aEndAngle), sinf(aEndAngle)) * aRadius; +} + +already_AddRefed<Path> PathBuilderRecording::Finish() { + return MakeAndAddRef<PathRecording>(mBackendType, std::move(mPathOps), + mFillRule, mBeginPoint, mCurrentPoint); +} + +PathRecording::PathRecording(BackendType aBackend, PathOps&& aOps, + FillRule aFillRule, const Point& aCurrentPoint, + const Point& aBeginPoint) + : mBackendType(aBackend), + mPathOps(std::move(aOps)), + mFillRule(aFillRule), + mCurrentPoint(aCurrentPoint), + mBeginPoint(aBeginPoint) {} + +PathRecording::~PathRecording() { + for (size_t i = 0; i < mStoredRecorders.size(); i++) { + mStoredRecorders[i]->RemoveStoredObject(this); + mStoredRecorders[i]->RecordEvent(RecordedPathDestruction(this)); + } +} + +void PathRecording::EnsurePath() const { + if (mPath) { + return; + } + if (RefPtr<PathBuilder> pathBuilder = + Factory::CreatePathBuilder(mBackendType, mFillRule)) { + if (!mPathOps.StreamToSink(*pathBuilder)) { + MOZ_ASSERT(false, "Failed to stream PathOps to PathBuilder"); + } else { + mPath = pathBuilder->Finish(); + MOZ_ASSERT(!!mPath, "Failed finishing Path from PathBuilder"); + } + } else { + MOZ_ASSERT(false, "Failed to create PathBuilder for PathRecording"); + } +} + +already_AddRefed<PathBuilder> PathRecording::CopyToBuilder( + FillRule aFillRule) const { + RefPtr<PathBuilderRecording> recording = + new PathBuilderRecording(mBackendType, PathOps(mPathOps), aFillRule); + recording->SetCurrentPoint(mCurrentPoint); + recording->SetBeginPoint(mBeginPoint); + return recording.forget(); +} + +already_AddRefed<PathBuilder> PathRecording::TransformedCopyToBuilder( + const Matrix& aTransform, FillRule aFillRule) const { + RefPtr<PathBuilderRecording> recording = new PathBuilderRecording( + mBackendType, mPathOps.TransformedCopy(aTransform), aFillRule); + recording->SetCurrentPoint(aTransform.TransformPoint(mCurrentPoint)); + recording->SetBeginPoint(aTransform.TransformPoint(mBeginPoint)); + return recording.forget(); +} + +} // namespace gfx +} // namespace mozilla |