1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "PathRecording.h"
8 #include "DrawEventRecorder.h"
9 #include "RecordedEventImpl.h"
14 #define NEXT_PARAMS(_type) \
15 const _type params = *reinterpret_cast<const _type*>(nextByte); \
16 nextByte += sizeof(_type);
18 bool PathOps::StreamToSink(PathSink
& aPathSink
) const {
19 if (mPathData
.empty()) {
23 const uint8_t* nextByte
= mPathData
.data();
24 const uint8_t* end
= nextByte
+ mPathData
.size();
25 while (nextByte
< end
) {
26 const OpType opType
= *reinterpret_cast<const OpType
*>(nextByte
);
27 nextByte
+= sizeof(OpType
);
29 case OpType::OP_MOVETO
: {
31 aPathSink
.MoveTo(params
);
34 case OpType::OP_LINETO
: {
36 aPathSink
.LineTo(params
);
39 case OpType::OP_BEZIERTO
: {
40 NEXT_PARAMS(ThreePoints
)
41 aPathSink
.BezierTo(params
.p1
, params
.p2
, params
.p3
);
44 case OpType::OP_QUADRATICBEZIERTO
: {
45 NEXT_PARAMS(TwoPoints
)
46 aPathSink
.QuadraticBezierTo(params
.p1
, params
.p2
);
49 case OpType::OP_ARC
: {
50 NEXT_PARAMS(ArcParams
)
51 aPathSink
.Arc(params
.origin
, params
.radius
, params
.startAngle
,
52 params
.endAngle
, params
.antiClockwise
);
55 case OpType::OP_CLOSE
:
66 PathOps
PathOps::TransformedCopy(const Matrix
& aTransform
) const {
68 const uint8_t* nextByte
= mPathData
.data();
69 const uint8_t* end
= nextByte
+ mPathData
.size();
70 while (nextByte
< end
) {
71 const OpType opType
= *reinterpret_cast<const OpType
*>(nextByte
);
72 nextByte
+= sizeof(OpType
);
74 case OpType::OP_MOVETO
: {
76 newPathOps
.MoveTo(aTransform
.TransformPoint(params
));
79 case OpType::OP_LINETO
: {
81 newPathOps
.LineTo(aTransform
.TransformPoint(params
));
84 case OpType::OP_BEZIERTO
: {
85 NEXT_PARAMS(ThreePoints
)
86 newPathOps
.BezierTo(aTransform
.TransformPoint(params
.p1
),
87 aTransform
.TransformPoint(params
.p2
),
88 aTransform
.TransformPoint(params
.p3
));
91 case OpType::OP_QUADRATICBEZIERTO
: {
92 NEXT_PARAMS(TwoPoints
)
93 newPathOps
.QuadraticBezierTo(aTransform
.TransformPoint(params
.p1
),
94 aTransform
.TransformPoint(params
.p2
));
97 case OpType::OP_ARC
: {
98 NEXT_PARAMS(ArcParams
)
99 ArcToBezier(&newPathOps
, params
.origin
,
100 gfx::Size(params
.radius
, params
.radius
), params
.startAngle
,
101 params
.endAngle
, params
.antiClockwise
, 0.0f
, aTransform
);
104 case OpType::OP_CLOSE
:
108 MOZ_CRASH("We control mOpTypes, so this should never happen.");
117 size_t PathOps::NumberOfOps() const {
119 const uint8_t* nextByte
= mPathData
.data();
120 const uint8_t* end
= nextByte
+ mPathData
.size();
121 while (nextByte
< end
) {
123 const OpType opType
= *reinterpret_cast<const OpType
*>(nextByte
);
124 nextByte
+= sizeof(OpType
);
126 case OpType::OP_MOVETO
:
127 nextByte
+= sizeof(Point
);
129 case OpType::OP_LINETO
:
130 nextByte
+= sizeof(Point
);
132 case OpType::OP_BEZIERTO
:
133 nextByte
+= sizeof(ThreePoints
);
135 case OpType::OP_QUADRATICBEZIERTO
:
136 nextByte
+= sizeof(TwoPoints
);
139 nextByte
+= sizeof(ArcParams
);
141 case OpType::OP_CLOSE
:
144 MOZ_CRASH("We control mOpTypes, so this should never happen.");
151 void PathBuilderRecording::MoveTo(const Point
& aPoint
) {
152 mPathOps
.MoveTo(aPoint
);
153 mPathBuilder
->MoveTo(aPoint
);
156 void PathBuilderRecording::LineTo(const Point
& aPoint
) {
157 mPathOps
.LineTo(aPoint
);
158 mPathBuilder
->LineTo(aPoint
);
161 void PathBuilderRecording::BezierTo(const Point
& aCP1
, const Point
& aCP2
,
163 mPathOps
.BezierTo(aCP1
, aCP2
, aCP3
);
164 mPathBuilder
->BezierTo(aCP1
, aCP2
, aCP3
);
167 void PathBuilderRecording::QuadraticBezierTo(const Point
& aCP1
,
169 mPathOps
.QuadraticBezierTo(aCP1
, aCP2
);
170 mPathBuilder
->QuadraticBezierTo(aCP1
, aCP2
);
173 void PathBuilderRecording::Close() {
175 mPathBuilder
->Close();
178 void PathBuilderRecording::Arc(const Point
& aOrigin
, float aRadius
,
179 float aStartAngle
, float aEndAngle
,
180 bool aAntiClockwise
) {
181 mPathOps
.Arc(aOrigin
, aRadius
, aStartAngle
, aEndAngle
, aAntiClockwise
);
182 mPathBuilder
->Arc(aOrigin
, aRadius
, aStartAngle
, aEndAngle
, aAntiClockwise
);
185 already_AddRefed
<Path
> PathBuilderRecording::Finish() {
186 // We rely on mPathBuilder to track begin and current point, but that stops
187 // when we call Finish, so we need to store them first.
188 Point beginPoint
= BeginPoint();
189 Point currentPoint
= CurrentPoint();
190 RefPtr
<Path
> path
= mPathBuilder
->Finish();
191 return MakeAndAddRef
<PathRecording
>(path
, std::move(mPathOps
), mFillRule
,
192 currentPoint
, beginPoint
);
195 PathRecording::PathRecording(Path
* aPath
, PathOps
&& aOps
, FillRule aFillRule
,
196 const Point
& aCurrentPoint
,
197 const Point
& aBeginPoint
)
199 mPathOps(std::move(aOps
)),
200 mFillRule(aFillRule
),
201 mCurrentPoint(aCurrentPoint
),
202 mBeginPoint(aBeginPoint
) {}
204 PathRecording::~PathRecording() {
205 for (size_t i
= 0; i
< mStoredRecorders
.size(); i
++) {
206 mStoredRecorders
[i
]->RemoveStoredObject(this);
207 mStoredRecorders
[i
]->RecordEvent(RecordedPathDestruction(this));
211 already_AddRefed
<PathBuilder
> PathRecording::CopyToBuilder(
212 FillRule aFillRule
) const {
213 RefPtr
<PathBuilder
> pathBuilder
= mPath
->CopyToBuilder(aFillRule
);
214 RefPtr
<PathBuilderRecording
> recording
=
215 new PathBuilderRecording(pathBuilder
, mPathOps
, aFillRule
);
216 recording
->SetCurrentPoint(mCurrentPoint
);
217 recording
->SetBeginPoint(mBeginPoint
);
218 return recording
.forget();
221 already_AddRefed
<PathBuilder
> PathRecording::TransformedCopyToBuilder(
222 const Matrix
& aTransform
, FillRule aFillRule
) const {
223 RefPtr
<PathBuilder
> pathBuilder
=
224 mPath
->TransformedCopyToBuilder(aTransform
, aFillRule
);
225 RefPtr
<PathBuilderRecording
> recording
= new PathBuilderRecording(
226 pathBuilder
, mPathOps
.TransformedCopy(aTransform
), aFillRule
);
228 recording
->SetCurrentPoint(aTransform
.TransformPoint(mCurrentPoint
));
229 recording
->SetBeginPoint(aTransform
.TransformPoint(mBeginPoint
));
231 return recording
.forget();
235 } // namespace mozilla