Skip to content

Commit 5e2d197

Browse files
author
Swarup Ukil
committed
Bug 1921501 - Support parsing of <control-point> in shape(). r=boris,longsonr,firefox-style-system-reviewers,firefox-svg-reviewers,layout-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D270455
1 parent 1a30d73 commit 5e2d197

File tree

19 files changed

+486
-208
lines changed

19 files changed

+486
-208
lines changed

dom/svg/SVGAnimatedPathSegList.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ static StyleCommandEndPoint<float> MakeEndPoint(PositionType type, float x,
3939
}
4040
}
4141

42+
static StyleControlPoint<float> MakeControlPoint(PositionType type, float x,
43+
float y) {
44+
if (type == PositionType::Absolute) {
45+
return StyleControlPoint<float>::Position({x, y});
46+
} else {
47+
return StyleControlPoint<float>::Relative(
48+
StyleRelativeControlPoint<float>{{x, y}, StyleControlReference::None});
49+
}
50+
}
51+
4252
class MOZ_STACK_CLASS SVGPathSegmentInitWrapper final {
4353
public:
4454
explicit SVGPathSegmentInitWrapper(const SVGPathSegmentInit& aSVGPathSegment)
@@ -87,24 +97,30 @@ class MOZ_STACK_CLASS SVGPathSegmentInitWrapper final {
8797
return StylePathCommand::CubicCurve(
8898
MakeEndPoint(PositionType::Absolute, mInit.mValues[4],
8999
mInit.mValues[5]),
90-
{mInit.mValues[0], mInit.mValues[1]},
91-
{mInit.mValues[2], mInit.mValues[3]});
100+
MakeControlPoint(PositionType::Absolute, mInit.mValues[0],
101+
mInit.mValues[1]),
102+
MakeControlPoint(PositionType::Absolute, mInit.mValues[2],
103+
mInit.mValues[3]));
92104
case 'c':
93105
return StylePathCommand::CubicCurve(
94106
MakeEndPoint(PositionType::Relative, mInit.mValues[4],
95107
mInit.mValues[5]),
96-
{mInit.mValues[0], mInit.mValues[1]},
97-
{mInit.mValues[2], mInit.mValues[3]});
108+
MakeControlPoint(PositionType::Relative, mInit.mValues[0],
109+
mInit.mValues[1]),
110+
MakeControlPoint(PositionType::Relative, mInit.mValues[2],
111+
mInit.mValues[3]));
98112
case 'Q':
99113
return StylePathCommand::QuadCurve(
100114
MakeEndPoint(PositionType::Absolute, mInit.mValues[2],
101115
mInit.mValues[3]),
102-
{mInit.mValues[0], mInit.mValues[1]});
116+
MakeControlPoint(PositionType::Absolute, mInit.mValues[0],
117+
mInit.mValues[1]));
103118
case 'q':
104119
return StylePathCommand::QuadCurve(
105120
MakeEndPoint(PositionType::Relative, mInit.mValues[2],
106121
mInit.mValues[3]),
107-
{mInit.mValues[0], mInit.mValues[1]});
122+
MakeControlPoint(PositionType::Relative, mInit.mValues[0],
123+
mInit.mValues[1]));
108124
case 'A':
109125
return StylePathCommand::Arc(
110126
MakeEndPoint(PositionType::Absolute, mInit.mValues[5],
@@ -133,12 +149,14 @@ class MOZ_STACK_CLASS SVGPathSegmentInitWrapper final {
133149
return StylePathCommand::SmoothCubic(
134150
MakeEndPoint(PositionType::Absolute, mInit.mValues[2],
135151
mInit.mValues[3]),
136-
{mInit.mValues[0], mInit.mValues[1]});
152+
MakeControlPoint(PositionType::Absolute, mInit.mValues[0],
153+
mInit.mValues[1]));
137154
case 's':
138155
return StylePathCommand::SmoothCubic(
139156
MakeEndPoint(PositionType::Relative, mInit.mValues[2],
140157
mInit.mValues[3]),
141-
{mInit.mValues[0], mInit.mValues[1]});
158+
MakeControlPoint(PositionType::Relative, mInit.mValues[0],
159+
mInit.mValues[1]));
142160
case 'T':
143161
return StylePathCommand::SmoothQuad(MakeEndPoint(
144162
PositionType::Absolute, mInit.mValues[0], mInit.mValues[1]));

dom/svg/SVGPathData.cpp

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ static already_AddRefed<Path> BuildPathInternal(
245245

246246
for (const auto& cmd : aPath) {
247247
seg = &cmd;
248+
bool isRelative = false;
248249
switch (cmd.tag) {
249250
case Command::Tag::Close:
250251
// set this early to allow drawing of square caps for "M{x},{y} Z":
@@ -271,15 +272,13 @@ static already_AddRefed<Path> BuildPathInternal(
271272
break;
272273
}
273274
case Command::Tag::CubicCurve:
274-
cp1 = cmd.cubic_curve.control1.ToGfxPoint(aPercentageBasis);
275-
cp2 = cmd.cubic_curve.control2.ToGfxPoint(aPercentageBasis);
275+
isRelative = cmd.cubic_curve.point.IsByCoordinate();
276276
segEnd = cmd.cubic_curve.point.ToGfxPoint(aPercentageBasis);
277-
278-
if (cmd.cubic_curve.point.IsByCoordinate()) {
279-
cp1 += segStart;
280-
cp2 += segStart;
281-
segEnd += segStart;
282-
}
277+
segEnd = isRelative ? segEnd + segStart : segEnd;
278+
cp1 = cmd.cubic_curve.control1.ToGfxPoint(segStart, segEnd, isRelative,
279+
aPercentageBasis);
280+
cp2 = cmd.cubic_curve.control2.ToGfxPoint(segStart, segEnd, isRelative,
281+
aPercentageBasis);
283282

284283
if (segEnd != segStart || segEnd != cp1 || segEnd != cp2) {
285284
subpathHasLength = true;
@@ -288,13 +287,12 @@ static already_AddRefed<Path> BuildPathInternal(
288287
break;
289288

290289
case Command::Tag::QuadCurve:
291-
cp1 = cmd.quad_curve.control1.ToGfxPoint(aPercentageBasis);
290+
isRelative = cmd.quad_curve.point.IsByCoordinate();
292291
segEnd = cmd.quad_curve.point.ToGfxPoint(aPercentageBasis);
293-
294-
if (cmd.quad_curve.point.IsByCoordinate()) {
295-
cp1 += segStart;
296-
segEnd += segStart; // set before setting tcp2!
297-
}
292+
segEnd = isRelative ? segEnd + segStart
293+
: segEnd; // set before setting tcp2!
294+
cp1 = cmd.quad_curve.control1.ToGfxPoint(segStart, segEnd, isRelative,
295+
aPercentageBasis);
298296

299297
// Convert quadratic curve to cubic curve:
300298
tcp1 = segStart + (cp1 - segStart) * 2 / 3;
@@ -359,14 +357,12 @@ static already_AddRefed<Path> BuildPathInternal(
359357
break;
360358
}
361359
case Command::Tag::SmoothCubic:
362-
cp1 = prevSeg && prevSeg->IsCubicType() ? segStart * 2 - cp2 : segStart;
363-
cp2 = cmd.smooth_cubic.control2.ToGfxPoint(aPercentageBasis);
360+
isRelative = cmd.smooth_cubic.point.IsByCoordinate();
364361
segEnd = cmd.smooth_cubic.point.ToGfxPoint(aPercentageBasis);
365-
366-
if (cmd.smooth_cubic.point.IsByCoordinate()) {
367-
cp2 += segStart;
368-
segEnd += segStart;
369-
}
362+
segEnd = isRelative ? segEnd + segStart : segEnd;
363+
cp1 = prevSeg && prevSeg->IsCubicType() ? segStart * 2 - cp2 : segStart;
364+
cp2 = cmd.smooth_cubic.control2.ToGfxPoint(segStart, segEnd, isRelative,
365+
aPercentageBasis);
370366

371367
if (segEnd != segStart || segEnd != cp1 || segEnd != cp2) {
372368
subpathHasLength = true;
@@ -546,6 +542,7 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
546542
Point& segStart = prevSegEnd;
547543
Point segEnd;
548544
float segStartAngle, segEndAngle;
545+
bool isRelative = false;
549546

550547
switch (cmd.tag) // to find segStartAngle, segEnd and segEndAngle
551548
{
@@ -570,15 +567,15 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
570567
break;
571568
}
572569
case StylePathCommand::Tag::CubicCurve: {
573-
Point cp1 = cmd.cubic_curve.control1.ToGfxPoint() * aZoom;
574-
Point cp2 = cmd.cubic_curve.control2.ToGfxPoint() * aZoom;
570+
isRelative = cmd.cubic_curve.point.IsByCoordinate();
575571
segEnd = cmd.cubic_curve.point.ToGfxPoint() * aZoom;
576-
577-
if (cmd.cubic_curve.point.IsByCoordinate()) {
578-
cp1 += segStart;
579-
cp2 += segStart;
580-
segEnd += segStart;
581-
}
572+
segEnd = isRelative ? segEnd + segStart : segEnd;
573+
Point cp1 =
574+
cmd.cubic_curve.control1.ToGfxPoint(segStart, segEnd, isRelative) *
575+
aZoom;
576+
Point cp2 =
577+
cmd.cubic_curve.control2.ToGfxPoint(segStart, segEnd, isRelative) *
578+
aZoom;
582579

583580
prevCP = cp2;
584581
segStartAngle = AngleOfVector(
@@ -588,13 +585,13 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
588585
break;
589586
}
590587
case StylePathCommand::Tag::QuadCurve: {
591-
Point cp1 = cmd.quad_curve.control1.ToGfxPoint() * aZoom;
588+
isRelative = cmd.quad_curve.point.IsByCoordinate();
592589
segEnd = cmd.quad_curve.point.ToGfxPoint() * aZoom;
593-
594-
if (cmd.quad_curve.point.IsByCoordinate()) {
595-
cp1 += segStart;
596-
segEnd += segStart; // set before setting tcp2!
597-
}
590+
segEnd = isRelative ? segEnd + segStart
591+
: segEnd; // set before setting tcp2!
592+
Point cp1 =
593+
cmd.quad_curve.control1.ToGfxPoint(segStart, segEnd, isRelative) *
594+
aZoom;
598595

599596
prevCP = cp1;
600597
segStartAngle = AngleOfVector(cp1 == segStart ? segEnd : cp1, segStart);
@@ -665,13 +662,12 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
665662
const Point& cp1 = prevSeg && prevSeg->IsCubicType()
666663
? segStart * 2 - prevCP
667664
: segStart;
668-
Point cp2 = cmd.smooth_cubic.control2.ToGfxPoint() * aZoom;
665+
isRelative = cmd.smooth_cubic.point.IsByCoordinate();
669666
segEnd = cmd.smooth_cubic.point.ToGfxPoint() * aZoom;
670-
671-
if (cmd.smooth_cubic.point.IsByCoordinate()) {
672-
cp2 += segStart;
673-
segEnd += segStart;
674-
}
667+
segEnd = isRelative ? segEnd + segStart : segEnd;
668+
Point cp2 =
669+
cmd.smooth_cubic.control2.ToGfxPoint(segStart, segEnd, isRelative) *
670+
aZoom;
675671

676672
prevCP = cp2;
677673
segStartAngle = AngleOfVector(

dom/svg/SVGPathElement.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ static void CreatePathSegments(SVGPathElement* aPathElement,
139139
auto curve = StylePathCommand::CubicCurve(
140140
StyleCommandEndPoint<StyleCSSFloat>::ToPosition(
141141
{segEnd.x, segEnd.y}),
142-
StyleCoordinatePair<StyleCSSFloat>{cp1.x, cp1.y},
143-
StyleCoordinatePair<StyleCSSFloat>{cp2.x, cp2.y});
142+
StyleControlPoint<StyleCSSFloat>::Position({cp1.x, cp1.y}),
143+
StyleControlPoint<StyleCSSFloat>::Position({cp2.x, cp2.y}));
144144
aValues.AppendElement(new SVGPathSegment(aPathElement, curve));
145145
}
146146
break;

dom/svg/SVGPathSegUtils.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,10 @@ void SVGPathSegUtils::TraversePathSegment(const StylePathCommand& aCommand,
134134
? aState.pos + aCommand.cubic_curve.point.ToGfxPoint()
135135
: aCommand.cubic_curve.point.ToGfxPoint();
136136
if (aState.ShouldUpdateLengthAndControlPoints()) {
137-
Point cp1 = aCommand.cubic_curve.control1.ToGfxPoint();
138-
Point cp2 = aCommand.cubic_curve.control2.ToGfxPoint();
139-
if (isRelative) {
140-
cp1 += aState.pos;
141-
cp2 += aState.pos;
142-
}
137+
Point cp1 = aCommand.cubic_curve.control1.ToGfxPoint(aState.pos, to,
138+
isRelative);
139+
Point cp2 = aCommand.cubic_curve.control2.ToGfxPoint(aState.pos, to,
140+
isRelative);
143141
aState.length +=
144142
(float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
145143
aState.cp2 = cp2;
@@ -154,9 +152,8 @@ void SVGPathSegUtils::TraversePathSegment(const StylePathCommand& aCommand,
154152
? aState.pos + aCommand.quad_curve.point.ToGfxPoint()
155153
: aCommand.quad_curve.point.ToGfxPoint();
156154
if (aState.ShouldUpdateLengthAndControlPoints()) {
157-
Point cp = isRelative
158-
? aState.pos + aCommand.quad_curve.control1.ToGfxPoint()
159-
: aCommand.quad_curve.control1.ToGfxPoint();
155+
Point cp =
156+
aCommand.quad_curve.control1.ToGfxPoint(aState.pos, to, isRelative);
160157
aState.length += (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
161158
aState.cp1 = cp;
162159
aState.cp2 = to;
@@ -220,9 +217,8 @@ void SVGPathSegUtils::TraversePathSegment(const StylePathCommand& aCommand,
220217
: aCommand.smooth_cubic.point.ToGfxPoint();
221218
if (aState.ShouldUpdateLengthAndControlPoints()) {
222219
Point cp1 = aState.pos - (aState.cp2 - aState.pos);
223-
Point cp2 = isRelative ? aState.pos +
224-
aCommand.smooth_cubic.control2.ToGfxPoint()
225-
: aCommand.smooth_cubic.control2.ToGfxPoint();
220+
Point cp2 = aCommand.smooth_cubic.control2.ToGfxPoint(aState.pos, to,
221+
isRelative);
226222
aState.length +=
227223
(float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
228224
aState.cp2 = cp2;

dom/svg/SVGPathSegment.cpp

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGPathSegment, mSVGPathElement)
2020

2121
//----------------------------------------------------------------------
2222
// Implementation
23-
void SVGPathSegment::AppendPoint(
23+
void SVGPathSegment::AppendEndPoint(
2424
const StyleCommandEndPoint<StyleCSSFloat>& point) {
2525
if (point.IsToPosition()) {
2626
const auto& pos = point.AsToPosition();
@@ -33,6 +33,19 @@ void SVGPathSegment::AppendPoint(
3333
}
3434
}
3535

36+
void SVGPathSegment::AppendControlPoint(
37+
const StyleControlPoint<StyleCSSFloat>& point) {
38+
if (point.IsPosition()) {
39+
const auto& pos = point.AsPosition();
40+
mValues.AppendElement(pos.horizontal);
41+
mValues.AppendElement(pos.vertical);
42+
} else if (point.IsRelative()) {
43+
const auto& rel_point = point.AsRelative();
44+
mValues.AppendElement(rel_point.coord.x);
45+
mValues.AppendElement(rel_point.coord.y);
46+
}
47+
}
48+
3649
SVGPathSegment::SVGPathSegment(SVGPathElement* aSVGPathElement,
3750
const StylePathCommand& aCommand)
3851
: mSVGPathElement(aSVGPathElement) {
@@ -42,27 +55,24 @@ SVGPathSegment::SVGPathSegment(SVGPathElement* aSVGPathElement,
4255
break;
4356
case StylePathCommand::Tag::Move:
4457
mCommand.AssignLiteral(aCommand.move.point.IsToPosition() ? "M" : "m");
45-
AppendPoint(aCommand.move.point);
58+
AppendEndPoint(aCommand.move.point);
4659
break;
4760
case StylePathCommand::Tag::Line:
4861
mCommand.AssignLiteral(aCommand.line.point.IsToPosition() ? "L" : "l");
49-
AppendPoint(aCommand.line.point);
62+
AppendEndPoint(aCommand.line.point);
5063
break;
5164
case StylePathCommand::Tag::CubicCurve:
5265
mCommand.AssignLiteral(aCommand.cubic_curve.point.IsToPosition() ? "C"
5366
: "c");
54-
mValues.AppendElement(aCommand.cubic_curve.control1.x);
55-
mValues.AppendElement(aCommand.cubic_curve.control1.y);
56-
mValues.AppendElement(aCommand.cubic_curve.control2.x);
57-
mValues.AppendElement(aCommand.cubic_curve.control2.y);
58-
AppendPoint(aCommand.cubic_curve.point);
67+
AppendControlPoint(aCommand.cubic_curve.control1);
68+
AppendControlPoint(aCommand.cubic_curve.control2);
69+
AppendEndPoint(aCommand.cubic_curve.point);
5970
break;
6071
case StylePathCommand::Tag::QuadCurve:
6172
mCommand.AssignLiteral(aCommand.quad_curve.point.IsToPosition() ? "Q"
6273
: "q");
63-
mValues.AppendElement(aCommand.quad_curve.control1.x);
64-
mValues.AppendElement(aCommand.quad_curve.control1.y);
65-
AppendPoint(aCommand.quad_curve.point);
74+
AppendControlPoint(aCommand.quad_curve.control1);
75+
AppendEndPoint(aCommand.quad_curve.point);
6676
break;
6777
case StylePathCommand::Tag::Arc:
6878
mCommand.AssignLiteral(aCommand.arc.point.IsToPosition() ? "A" : "a");
@@ -71,7 +81,7 @@ SVGPathSegment::SVGPathSegment(SVGPathElement* aSVGPathElement,
7181
mValues.AppendElement(aCommand.arc.rotate);
7282
mValues.AppendElement(aCommand.arc.arc_size == StyleArcSize::Large);
7383
mValues.AppendElement(aCommand.arc.arc_sweep == StyleArcSweep::Cw);
74-
AppendPoint(aCommand.arc.point);
84+
AppendEndPoint(aCommand.arc.point);
7585
break;
7686
case StylePathCommand::Tag::HLine:
7787
mCommand.AssignLiteral(aCommand.h_line.by_to == StyleByTo::To ? "H"
@@ -86,14 +96,13 @@ SVGPathSegment::SVGPathSegment(SVGPathElement* aSVGPathElement,
8696
case StylePathCommand::Tag::SmoothCubic:
8797
mCommand.AssignLiteral(aCommand.smooth_cubic.point.IsToPosition() ? "S"
8898
: "s");
89-
mValues.AppendElement(aCommand.smooth_cubic.control2.x);
90-
mValues.AppendElement(aCommand.smooth_cubic.control2.y);
91-
AppendPoint(aCommand.smooth_cubic.point);
99+
AppendControlPoint(aCommand.smooth_cubic.control2);
100+
AppendEndPoint(aCommand.smooth_cubic.point);
92101
break;
93102
case StylePathCommand::Tag::SmoothQuad:
94103
mCommand.AssignLiteral(aCommand.smooth_quad.point.IsToPosition() ? "T"
95104
: "t");
96-
AppendPoint(aCommand.smooth_quad.point);
105+
AppendEndPoint(aCommand.smooth_quad.point);
97106
break;
98107
}
99108
}

dom/svg/SVGPathSegment.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ class SVGPathSegment final : public nsWrapperCache {
4242
RefPtr<SVGPathElement> mSVGPathElement;
4343
nsString mCommand;
4444
nsTArray<float> mValues;
45-
void AppendPoint(const StyleCommandEndPoint<StyleCSSFloat>& point);
45+
void AppendEndPoint(const StyleCommandEndPoint<StyleCSSFloat>& point);
46+
void AppendControlPoint(const StyleControlPoint<StyleCSSFloat>& point);
4647
};
4748

4849
} // namespace mozilla::dom

layout/inspector/tests/test_bug877690.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@
293293

294294
// Regression test for bug 1255379.
295295
var shapeFunction = [ "close", "evenodd", "nonzero", "by", "to", "cw", "ccw",
296-
"small", "large" ];
296+
"small", "large", "end", "origin", "start"];
297297
var expected = [ "inherit", "initial", "unset", "revert", "revert-layer",
298298
"none", "url", "polygon", "circle", "ellipse", "inset",
299299
"path", "rect", "xywh", "fill-box", "stroke-box",

0 commit comments

Comments
 (0)