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