Bug 1641886 [wpt PR 23851] - Support interpolating contain-intrinsic-size, a=testonly
[gecko.git] / gfx / 2d / PathRecording.cpp
blob21e210daa8b881567a591d8428d3ddf2088736d6
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"
11 namespace mozilla {
12 namespace gfx {
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()) {
20 return true;
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);
28 switch (opType) {
29 case OpType::OP_MOVETO: {
30 NEXT_PARAMS(Point)
31 aPathSink.MoveTo(params);
32 break;
34 case OpType::OP_LINETO: {
35 NEXT_PARAMS(Point)
36 aPathSink.LineTo(params);
37 break;
39 case OpType::OP_BEZIERTO: {
40 NEXT_PARAMS(ThreePoints)
41 aPathSink.BezierTo(params.p1, params.p2, params.p3);
42 break;
44 case OpType::OP_QUADRATICBEZIERTO: {
45 NEXT_PARAMS(TwoPoints)
46 aPathSink.QuadraticBezierTo(params.p1, params.p2);
47 break;
49 case OpType::OP_ARC: {
50 NEXT_PARAMS(ArcParams)
51 aPathSink.Arc(params.origin, params.radius, params.startAngle,
52 params.endAngle, params.antiClockwise);
53 break;
55 case OpType::OP_CLOSE:
56 aPathSink.Close();
57 break;
58 default:
59 return false;
63 return true;
66 PathOps PathOps::TransformedCopy(const Matrix& aTransform) const {
67 PathOps newPathOps;
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);
73 switch (opType) {
74 case OpType::OP_MOVETO: {
75 NEXT_PARAMS(Point)
76 newPathOps.MoveTo(aTransform.TransformPoint(params));
77 break;
79 case OpType::OP_LINETO: {
80 NEXT_PARAMS(Point)
81 newPathOps.LineTo(aTransform.TransformPoint(params));
82 break;
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));
89 break;
91 case OpType::OP_QUADRATICBEZIERTO: {
92 NEXT_PARAMS(TwoPoints)
93 newPathOps.QuadraticBezierTo(aTransform.TransformPoint(params.p1),
94 aTransform.TransformPoint(params.p2));
95 break;
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);
102 break;
104 case OpType::OP_CLOSE:
105 newPathOps.Close();
106 break;
107 default:
108 MOZ_CRASH("We control mOpTypes, so this should never happen.");
112 return newPathOps;
115 #undef NEXT_PARAMS
117 size_t PathOps::NumberOfOps() const {
118 size_t size = 0;
119 const uint8_t* nextByte = mPathData.data();
120 const uint8_t* end = nextByte + mPathData.size();
121 while (nextByte < end) {
122 size++;
123 const OpType opType = *reinterpret_cast<const OpType*>(nextByte);
124 nextByte += sizeof(OpType);
125 switch (opType) {
126 case OpType::OP_MOVETO:
127 nextByte += sizeof(Point);
128 break;
129 case OpType::OP_LINETO:
130 nextByte += sizeof(Point);
131 break;
132 case OpType::OP_BEZIERTO:
133 nextByte += sizeof(ThreePoints);
134 break;
135 case OpType::OP_QUADRATICBEZIERTO:
136 nextByte += sizeof(TwoPoints);
137 break;
138 case OpType::OP_ARC:
139 nextByte += sizeof(ArcParams);
140 break;
141 case OpType::OP_CLOSE:
142 break;
143 default:
144 MOZ_CRASH("We control mOpTypes, so this should never happen.");
148 return size;
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,
162 const Point& aCP3) {
163 mPathOps.BezierTo(aCP1, aCP2, aCP3);
164 mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
167 void PathBuilderRecording::QuadraticBezierTo(const Point& aCP1,
168 const Point& aCP2) {
169 mPathOps.QuadraticBezierTo(aCP1, aCP2);
170 mPathBuilder->QuadraticBezierTo(aCP1, aCP2);
173 void PathBuilderRecording::Close() {
174 mPathOps.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)
198 : mPath(aPath),
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();
234 } // namespace gfx
235 } // namespace mozilla