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/. */
6
7 #ifndef MOZILLA_GFX_PATHRECORDING_H_
8 #define MOZILLA_GFX_PATHRECORDING_H_
9
10 #include "2D.h"
11 #include <vector>
12 #include <ostream>
13
14 #include "PathHelpers.h"
15 #include "RecordingTypes.h"
16
17 namespace mozilla {
18 namespace gfx {
19
20 class PathOps {
21 public:
22 PathOps() = default;
23
24 template <class S>
25 explicit PathOps(S& aStream);
26
27 PathOps(const PathOps& aOther) = default;
28 PathOps& operator=(const PathOps&) = delete; // assign using std::move()!
29
30 PathOps(PathOps&& aOther) = default;
31 PathOps& operator=(PathOps&& aOther) = default;
32
33 template <class S>
34 void Record(S& aStream) const;
35
36 bool StreamToSink(PathSink& aPathSink) const;
37
38 PathOps TransformedCopy(const Matrix& aTransform) const;
39
40 size_t NumberOfOps() const;
41
MoveTo(const Point & aPoint)42 void MoveTo(const Point& aPoint) { AppendPathOp(OpType::OP_MOVETO, aPoint); }
43
LineTo(const Point & aPoint)44 void LineTo(const Point& aPoint) { AppendPathOp(OpType::OP_LINETO, aPoint); }
45
BezierTo(const Point & aCP1,const Point & aCP2,const Point & aCP3)46 void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) {
47 AppendPathOp(OpType::OP_BEZIERTO, ThreePoints{aCP1, aCP2, aCP3});
48 }
49
QuadraticBezierTo(const Point & aCP1,const Point & aCP2)50 void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) {
51 AppendPathOp(OpType::OP_QUADRATICBEZIERTO, TwoPoints{aCP1, aCP2});
52 }
53
Arc(const Point & aOrigin,float aRadius,float aStartAngle,float aEndAngle,bool aAntiClockwise)54 void Arc(const Point& aOrigin, float aRadius, float aStartAngle,
55 float aEndAngle, bool aAntiClockwise) {
56 AppendPathOp(OpType::OP_ARC, ArcParams{aOrigin, aRadius, aStartAngle,
57 aEndAngle, aAntiClockwise});
58 }
59
Close()60 void Close() {
61 size_t oldSize = mPathData.size();
62 mPathData.resize(oldSize + sizeof(OpType));
63 *reinterpret_cast<OpType*>(mPathData.data() + oldSize) = OpType::OP_CLOSE;
64 }
65
66 private:
67 enum class OpType : uint32_t {
68 OP_MOVETO = 0,
69 OP_LINETO,
70 OP_BEZIERTO,
71 OP_QUADRATICBEZIERTO,
72 OP_ARC,
73 OP_CLOSE,
74 OP_INVALID
75 };
76
77 template <typename T>
AppendPathOp(const OpType & aOpType,const T & aOpParams)78 void AppendPathOp(const OpType& aOpType, const T& aOpParams) {
79 size_t oldSize = mPathData.size();
80 mPathData.resize(oldSize + sizeof(OpType) + sizeof(T));
81 memcpy(mPathData.data() + oldSize, &aOpType, sizeof(OpType));
82 oldSize += sizeof(OpType);
83 memcpy(mPathData.data() + oldSize, &aOpParams, sizeof(T));
84 }
85
86 struct TwoPoints {
87 Point p1;
88 Point p2;
89 };
90
91 struct ThreePoints {
92 Point p1;
93 Point p2;
94 Point p3;
95 };
96
97 struct ArcParams {
98 Point origin;
99 float radius;
100 float startAngle;
101 float endAngle;
102 bool antiClockwise;
103 };
104
105 std::vector<uint8_t> mPathData;
106 };
107
108 template <class S>
PathOps(S & aStream)109 PathOps::PathOps(S& aStream) {
110 ReadVector(aStream, mPathData);
111 }
112
113 template <class S>
Record(S & aStream)114 inline void PathOps::Record(S& aStream) const {
115 WriteVector(aStream, mPathData);
116 }
117
118 class PathRecording;
119 class DrawEventRecorderPrivate;
120
121 class PathBuilderRecording final : public PathBuilder {
122 public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderRecording,override)123 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderRecording, override)
124
125 PathBuilderRecording(PathBuilder* aBuilder, FillRule aFillRule)
126 : mPathBuilder(aBuilder), mFillRule(aFillRule) {}
127
PathBuilderRecording(PathBuilder * aBuilder,const PathOps & aPathOps,FillRule aFillRule)128 PathBuilderRecording(PathBuilder* aBuilder, const PathOps& aPathOps,
129 FillRule aFillRule)
130 : mPathBuilder(aBuilder), mFillRule(aFillRule), mPathOps(aPathOps) {}
131
132 /* Move the current point in the path, any figure currently being drawn will
133 * be considered closed during fill operations, however when stroking the
134 * closing line segment will not be drawn.
135 */
136 void MoveTo(const Point& aPoint) final;
137
138 /* Add a linesegment to the current figure */
139 void LineTo(const Point& aPoint) final;
140
141 /* Add a cubic bezier curve to the current figure */
142 void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) final;
143
144 /* Add a quadratic bezier curve to the current figure */
145 void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) final;
146
147 /* Close the current figure, this will essentially generate a line segment
148 * from the current point to the starting point for the current figure
149 */
150 void Close() final;
151
152 /* Add an arc to the current figure */
153 void Arc(const Point& aOrigin, float aRadius, float aStartAngle,
154 float aEndAngle, bool aAntiClockwise) final;
155
156 /* Point the current subpath is at - or where the next subpath will start
157 * if there is no active subpath.
158 */
CurrentPoint()159 Point CurrentPoint() const final { return mPathBuilder->CurrentPoint(); }
160
BeginPoint()161 Point BeginPoint() const final { return mPathBuilder->BeginPoint(); }
162
SetCurrentPoint(const Point & aPoint)163 void SetCurrentPoint(const Point& aPoint) final {
164 mPathBuilder->SetCurrentPoint(aPoint);
165 }
166
SetBeginPoint(const Point & aPoint)167 void SetBeginPoint(const Point& aPoint) final {
168 mPathBuilder->SetBeginPoint(aPoint);
169 }
170
171 already_AddRefed<Path> Finish() final;
172
GetBackendType()173 BackendType GetBackendType() const final { return BackendType::RECORDING; }
174
175 private:
176 RefPtr<PathBuilder> mPathBuilder;
177 FillRule mFillRule;
178 PathOps mPathOps;
179 };
180
181 class PathRecording final : public Path {
182 public:
183 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathRecording, override)
184
185 PathRecording(Path* aPath, PathOps&& aOps, FillRule aFillRule,
186 const Point& aCurrentPoint, const Point& aBeginPoint);
187
188 ~PathRecording();
189
GetBackendType()190 BackendType GetBackendType() const final { return BackendType::RECORDING; }
191 already_AddRefed<PathBuilder> CopyToBuilder(FillRule aFillRule) const final;
192 already_AddRefed<PathBuilder> TransformedCopyToBuilder(
193 const Matrix& aTransform, FillRule aFillRule) const final;
ContainsPoint(const Point & aPoint,const Matrix & aTransform)194 bool ContainsPoint(const Point& aPoint,
195 const Matrix& aTransform) const final {
196 return mPath->ContainsPoint(aPoint, aTransform);
197 }
StrokeContainsPoint(const StrokeOptions & aStrokeOptions,const Point & aPoint,const Matrix & aTransform)198 bool StrokeContainsPoint(const StrokeOptions& aStrokeOptions,
199 const Point& aPoint,
200 const Matrix& aTransform) const final {
201 return mPath->StrokeContainsPoint(aStrokeOptions, aPoint, aTransform);
202 }
203
204 Rect GetBounds(const Matrix& aTransform = Matrix()) const final {
205 return mPath->GetBounds(aTransform);
206 }
207
208 Rect GetStrokedBounds(const StrokeOptions& aStrokeOptions,
209 const Matrix& aTransform = Matrix()) const final {
210 return mPath->GetStrokedBounds(aStrokeOptions, aTransform);
211 }
212
StreamToSink(PathSink * aSink)213 void StreamToSink(PathSink* aSink) const final { mPath->StreamToSink(aSink); }
214
GetFillRule()215 FillRule GetFillRule() const final { return mFillRule; }
216
217 private:
218 friend class DrawTargetWrapAndRecord;
219 friend class DrawTargetRecording;
220 friend class RecordedPathCreation;
221
222 RefPtr<Path> mPath;
223 PathOps mPathOps;
224 FillRule mFillRule;
225 Point mCurrentPoint;
226 Point mBeginPoint;
227
228 // Event recorders that have this path in their event stream.
229 std::vector<RefPtr<DrawEventRecorderPrivate>> mStoredRecorders;
230 };
231
232 } // namespace gfx
233 } // namespace mozilla
234
235 #endif /* MOZILLA_GFX_PATHRECORDING_H_ */
236