PathRecording.h (7854B)
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 struct Circle { 21 Point origin; 22 float radius; 23 bool closed = false; 24 }; 25 26 struct Line { 27 Point origin; 28 Point destination; 29 }; 30 31 class PathOps { 32 public: 33 PathOps() = default; 34 35 template <class S> 36 explicit PathOps(S& aStream); 37 38 PathOps(const PathOps& aOther) = default; 39 PathOps& operator=(const PathOps&) = delete; // assign using std::move()! 40 41 PathOps(PathOps&& aOther) = default; 42 PathOps& operator=(PathOps&& aOther) = default; 43 44 template <class S> 45 void Record(S& aStream) const; 46 47 bool StreamToSink(PathSink& aPathSink) const; 48 49 bool CheckedStreamToSink(PathSink& aPathSink) const; 50 51 PathOps TransformedCopy(const Matrix& aTransform) const; 52 53 void TransformInPlace(const Matrix& aTransform); 54 55 size_t NumberOfOps() const; 56 57 private: 58 enum class OpType : uint32_t { 59 OP_MOVETO = 0, 60 OP_LINETO, 61 OP_BEZIERTO, 62 OP_QUADRATICBEZIERTO, 63 OP_ARC_CW, 64 OP_ARC_CCW, 65 OP_CLOSE, 66 OP_INVALID 67 }; 68 69 template <typename T> 70 void AppendPathOp(const T& aOpData) { 71 mPathData.insert(mPathData.end(), (const uint8_t*)(&aOpData), 72 (const uint8_t*)(&aOpData + 1)); 73 } 74 75 template <typename T> 76 void AppendPathOp(const OpType& aOpType, const T& aOpParams) { 77 AppendPathOp(aOpType); 78 AppendPathOp(aOpParams); 79 } 80 81 struct TwoPoints { 82 Point p1; 83 Point p2; 84 }; 85 86 struct ThreePoints { 87 Point p1; 88 Point p2; 89 Point p3; 90 }; 91 92 struct ArcParams { 93 Matrix transform; 94 float startAngle; 95 float endAngle; 96 97 Point GetOrigin() const { return transform.GetTranslation(); } 98 Maybe<float> GetRadius() const; 99 100 void ToSink(PathSink& aPathSink, bool aAntiClockwise) const; 101 }; 102 103 public: 104 void MoveTo(const Point& aPoint) { AppendPathOp(OpType::OP_MOVETO, aPoint); } 105 106 void LineTo(const Point& aPoint) { AppendPathOp(OpType::OP_LINETO, aPoint); } 107 108 void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) { 109 AppendPathOp(OpType::OP_BEZIERTO, ThreePoints{aCP1, aCP2, aCP3}); 110 } 111 112 void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) { 113 AppendPathOp(OpType::OP_QUADRATICBEZIERTO, TwoPoints{aCP1, aCP2}); 114 } 115 116 void Arc(const Matrix& aTransform, float aStartAngle, float aEndAngle, 117 bool aAntiClockwise) { 118 AppendPathOp(aAntiClockwise ? OpType::OP_ARC_CCW : OpType::OP_ARC_CW, 119 ArcParams{aTransform, aStartAngle, aEndAngle}); 120 } 121 122 void Arc(const Point& aOrigin, float aRadius, float aStartAngle, 123 float aEndAngle, bool aAntiClockwise) { 124 Arc(Matrix(aRadius, 0.0f, 0.0f, aRadius, aOrigin.x, aOrigin.y), aStartAngle, 125 aEndAngle, aAntiClockwise); 126 } 127 128 void Close() { AppendPathOp(OpType::OP_CLOSE); } 129 130 Maybe<Circle> AsCircle() const; 131 Maybe<Line> AsLine() const; 132 133 bool IsActive() const { return !mPathData.empty(); } 134 135 bool IsEmpty() const; 136 137 private: 138 std::vector<uint8_t> mPathData; 139 }; 140 141 template <class S> 142 PathOps::PathOps(S& aStream) { 143 ReadVector(aStream, mPathData); 144 } 145 146 template <class S> 147 inline void PathOps::Record(S& aStream) const { 148 WriteVector(aStream, mPathData); 149 } 150 151 class PathRecording; 152 class DrawEventRecorderPrivate; 153 154 class PathBuilderRecording final : public PathBuilder { 155 public: 156 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderRecording, override) 157 158 PathBuilderRecording(BackendType aBackend, FillRule aFillRule) 159 : mBackendType(aBackend), mFillRule(aFillRule) {} 160 161 PathBuilderRecording(BackendType aBackend, PathOps&& aPathOps, 162 FillRule aFillRule) 163 : mBackendType(aBackend), 164 mFillRule(aFillRule), 165 mPathOps(std::move(aPathOps)) {} 166 167 /* Move the current point in the path, any figure currently being drawn will 168 * be considered closed during fill operations, however when stroking the 169 * closing line segment will not be drawn. 170 */ 171 void MoveTo(const Point& aPoint) final; 172 173 /* Add a linesegment to the current figure */ 174 void LineTo(const Point& aPoint) final; 175 176 /* Add a cubic bezier curve to the current figure */ 177 void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) final; 178 179 /* Add a quadratic bezier curve to the current figure */ 180 void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) final; 181 182 /* Close the current figure, this will essentially generate a line segment 183 * from the current point to the starting point for the current figure 184 */ 185 void Close() final; 186 187 /* Add an arc to the current figure */ 188 void Arc(const Point& aOrigin, float aRadius, float aStartAngle, 189 float aEndAngle, bool aAntiClockwise) final; 190 191 already_AddRefed<Path> Finish() final; 192 193 BackendType GetBackendType() const final { return BackendType::RECORDING; } 194 195 bool IsActive() const final { return mPathOps.IsActive(); } 196 197 private: 198 BackendType mBackendType; 199 FillRule mFillRule; 200 PathOps mPathOps; 201 }; 202 203 class PathRecording final : public Path { 204 public: 205 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathRecording, override) 206 207 PathRecording(BackendType aBackend, PathOps&& aOps, FillRule aFillRule, 208 const Point& aCurrentPoint, const Point& aBeginPoint); 209 210 ~PathRecording(); 211 212 BackendType GetBackendType() const final { return BackendType::RECORDING; } 213 already_AddRefed<PathBuilder> CopyToBuilder(FillRule aFillRule) const final; 214 already_AddRefed<PathBuilder> TransformedCopyToBuilder( 215 const Matrix& aTransform, FillRule aFillRule) const final; 216 already_AddRefed<PathBuilder> MoveToBuilder(FillRule aFillRule) final; 217 already_AddRefed<PathBuilder> TransformedMoveToBuilder( 218 const Matrix& aTransform, FillRule aFillRule) final; 219 220 bool ContainsPoint(const Point& aPoint, 221 const Matrix& aTransform) const final { 222 EnsurePath(); 223 return mPath->ContainsPoint(aPoint, aTransform); 224 } 225 bool StrokeContainsPoint(const StrokeOptions& aStrokeOptions, 226 const Point& aPoint, 227 const Matrix& aTransform) const final { 228 EnsurePath(); 229 return mPath->StrokeContainsPoint(aStrokeOptions, aPoint, aTransform); 230 } 231 232 Rect GetBounds(const Matrix& aTransform = Matrix()) const final { 233 EnsurePath(); 234 return mPath->GetBounds(aTransform); 235 } 236 237 Rect GetStrokedBounds(const StrokeOptions& aStrokeOptions, 238 const Matrix& aTransform = Matrix()) const final { 239 EnsurePath(); 240 return mPath->GetStrokedBounds(aStrokeOptions, aTransform); 241 } 242 243 Maybe<Rect> AsRect() const final { 244 EnsurePath(); 245 return mPath->AsRect(); 246 } 247 248 Maybe<Circle> AsCircle() const { return mPathOps.AsCircle(); } 249 Maybe<Line> AsLine() const { return mPathOps.AsLine(); } 250 251 void StreamToSink(PathSink* aSink) const final { 252 mPathOps.StreamToSink(*aSink); 253 } 254 255 FillRule GetFillRule() const final { return mFillRule; } 256 257 bool IsEmpty() const final { return mPathOps.IsEmpty(); } 258 259 private: 260 friend class DrawTargetWrapAndRecord; 261 friend class DrawTargetRecording; 262 friend class RecordedPathCreation; 263 264 void EnsurePath() const; 265 266 BackendType mBackendType; 267 mutable RefPtr<Path> mPath; 268 PathOps mPathOps; 269 FillRule mFillRule; 270 Point mCurrentPoint; 271 Point mBeginPoint; 272 273 // Event recorders that have this path in their event stream. 274 std::vector<RefPtr<DrawEventRecorderPrivate>> mStoredRecorders; 275 }; 276 277 } // namespace gfx 278 } // namespace mozilla 279 280 #endif /* MOZILLA_GFX_PATHRECORDING_H_ */