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 "mozilla/dom/SVGPathElement.h"
11 #include "DOMSVGPathSeg.h"
12 #include "DOMSVGPathSegList.h"
13 #include "SVGGeometryProperty.h"
14 #include "gfx2DGlue.h"
15 #include "gfxPlatform.h"
16 #include "nsGkAtoms.h"
18 #include "nsStyleConsts.h"
19 #include "nsStyleStruct.h"
20 #include "nsWindowSizes.h"
21 #include "mozilla/dom/SVGPathElementBinding.h"
22 #include "mozilla/gfx/2D.h"
23 #include "mozilla/RefPtr.h"
24 #include "mozilla/SVGContentUtils.h"
26 NS_IMPL_NS_NEW_SVG_ELEMENT(Path
)
28 using namespace mozilla::gfx
;
33 JSObject
* SVGPathElement::WrapNode(JSContext
* aCx
,
34 JS::Handle
<JSObject
*> aGivenProto
) {
35 return SVGPathElement_Binding::Wrap(aCx
, this, aGivenProto
);
38 //----------------------------------------------------------------------
41 SVGPathElement::SVGPathElement(
42 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
43 : SVGPathElementBase(std::move(aNodeInfo
)) {}
45 //----------------------------------------------------------------------
46 // memory reporting methods
48 void SVGPathElement::AddSizeOfExcludingThis(nsWindowSizes
& aSizes
,
49 size_t* aNodeSize
) const {
50 SVGPathElementBase::AddSizeOfExcludingThis(aSizes
, aNodeSize
);
51 *aNodeSize
+= mD
.SizeOfExcludingThis(aSizes
.mState
.mMallocSizeOf
);
54 //----------------------------------------------------------------------
57 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGPathElement
)
59 uint32_t SVGPathElement::GetPathSegAtLength(float distance
) {
60 return mD
.GetAnimValue().GetPathSegAtLength(distance
);
63 already_AddRefed
<DOMSVGPathSegClosePath
>
64 SVGPathElement::CreateSVGPathSegClosePath() {
65 RefPtr
<DOMSVGPathSegClosePath
> pathSeg
= new DOMSVGPathSegClosePath();
66 return pathSeg
.forget();
69 already_AddRefed
<DOMSVGPathSegMovetoAbs
>
70 SVGPathElement::CreateSVGPathSegMovetoAbs(float x
, float y
) {
71 RefPtr
<DOMSVGPathSegMovetoAbs
> pathSeg
= new DOMSVGPathSegMovetoAbs(x
, y
);
72 return pathSeg
.forget();
75 already_AddRefed
<DOMSVGPathSegMovetoRel
>
76 SVGPathElement::CreateSVGPathSegMovetoRel(float x
, float y
) {
77 RefPtr
<DOMSVGPathSegMovetoRel
> pathSeg
= new DOMSVGPathSegMovetoRel(x
, y
);
78 return pathSeg
.forget();
81 already_AddRefed
<DOMSVGPathSegLinetoAbs
>
82 SVGPathElement::CreateSVGPathSegLinetoAbs(float x
, float y
) {
83 RefPtr
<DOMSVGPathSegLinetoAbs
> pathSeg
= new DOMSVGPathSegLinetoAbs(x
, y
);
84 return pathSeg
.forget();
87 already_AddRefed
<DOMSVGPathSegLinetoRel
>
88 SVGPathElement::CreateSVGPathSegLinetoRel(float x
, float y
) {
89 RefPtr
<DOMSVGPathSegLinetoRel
> pathSeg
= new DOMSVGPathSegLinetoRel(x
, y
);
90 return pathSeg
.forget();
93 already_AddRefed
<DOMSVGPathSegCurvetoCubicAbs
>
94 SVGPathElement::CreateSVGPathSegCurvetoCubicAbs(float x
, float y
, float x1
,
95 float y1
, float x2
, float y2
) {
96 // Note that we swap from DOM API argument order to the argument order used
97 // in the <path> element's 'd' attribute (i.e. we put the arguments for the
98 // end point of the segment last instead of first).
99 RefPtr
<DOMSVGPathSegCurvetoCubicAbs
> pathSeg
=
100 new DOMSVGPathSegCurvetoCubicAbs(x1
, y1
, x2
, y2
, x
, y
);
101 return pathSeg
.forget();
104 already_AddRefed
<DOMSVGPathSegCurvetoCubicRel
>
105 SVGPathElement::CreateSVGPathSegCurvetoCubicRel(float x
, float y
, float x1
,
106 float y1
, float x2
, float y2
) {
107 // See comment in CreateSVGPathSegCurvetoCubicAbs
108 RefPtr
<DOMSVGPathSegCurvetoCubicRel
> pathSeg
=
109 new DOMSVGPathSegCurvetoCubicRel(x1
, y1
, x2
, y2
, x
, y
);
110 return pathSeg
.forget();
113 already_AddRefed
<DOMSVGPathSegCurvetoQuadraticAbs
>
114 SVGPathElement::CreateSVGPathSegCurvetoQuadraticAbs(float x
, float y
, float x1
,
116 // See comment in CreateSVGPathSegCurvetoCubicAbs
117 RefPtr
<DOMSVGPathSegCurvetoQuadraticAbs
> pathSeg
=
118 new DOMSVGPathSegCurvetoQuadraticAbs(x1
, y1
, x
, y
);
119 return pathSeg
.forget();
122 already_AddRefed
<DOMSVGPathSegCurvetoQuadraticRel
>
123 SVGPathElement::CreateSVGPathSegCurvetoQuadraticRel(float x
, float y
, float x1
,
125 // See comment in CreateSVGPathSegCurvetoCubicAbs
126 RefPtr
<DOMSVGPathSegCurvetoQuadraticRel
> pathSeg
=
127 new DOMSVGPathSegCurvetoQuadraticRel(x1
, y1
, x
, y
);
128 return pathSeg
.forget();
131 already_AddRefed
<DOMSVGPathSegArcAbs
> SVGPathElement::CreateSVGPathSegArcAbs(
132 float x
, float y
, float r1
, float r2
, float angle
, bool largeArcFlag
,
134 // See comment in CreateSVGPathSegCurvetoCubicAbs
135 RefPtr
<DOMSVGPathSegArcAbs
> pathSeg
=
136 new DOMSVGPathSegArcAbs(r1
, r2
, angle
, largeArcFlag
, sweepFlag
, x
, y
);
137 return pathSeg
.forget();
140 already_AddRefed
<DOMSVGPathSegArcRel
> SVGPathElement::CreateSVGPathSegArcRel(
141 float x
, float y
, float r1
, float r2
, float angle
, bool largeArcFlag
,
143 // See comment in CreateSVGPathSegCurvetoCubicAbs
144 RefPtr
<DOMSVGPathSegArcRel
> pathSeg
=
145 new DOMSVGPathSegArcRel(r1
, r2
, angle
, largeArcFlag
, sweepFlag
, x
, y
);
146 return pathSeg
.forget();
149 already_AddRefed
<DOMSVGPathSegLinetoHorizontalAbs
>
150 SVGPathElement::CreateSVGPathSegLinetoHorizontalAbs(float x
) {
151 RefPtr
<DOMSVGPathSegLinetoHorizontalAbs
> pathSeg
=
152 new DOMSVGPathSegLinetoHorizontalAbs(x
);
153 return pathSeg
.forget();
156 already_AddRefed
<DOMSVGPathSegLinetoHorizontalRel
>
157 SVGPathElement::CreateSVGPathSegLinetoHorizontalRel(float x
) {
158 RefPtr
<DOMSVGPathSegLinetoHorizontalRel
> pathSeg
=
159 new DOMSVGPathSegLinetoHorizontalRel(x
);
160 return pathSeg
.forget();
163 already_AddRefed
<DOMSVGPathSegLinetoVerticalAbs
>
164 SVGPathElement::CreateSVGPathSegLinetoVerticalAbs(float y
) {
165 RefPtr
<DOMSVGPathSegLinetoVerticalAbs
> pathSeg
=
166 new DOMSVGPathSegLinetoVerticalAbs(y
);
167 return pathSeg
.forget();
170 already_AddRefed
<DOMSVGPathSegLinetoVerticalRel
>
171 SVGPathElement::CreateSVGPathSegLinetoVerticalRel(float y
) {
172 RefPtr
<DOMSVGPathSegLinetoVerticalRel
> pathSeg
=
173 new DOMSVGPathSegLinetoVerticalRel(y
);
174 return pathSeg
.forget();
177 already_AddRefed
<DOMSVGPathSegCurvetoCubicSmoothAbs
>
178 SVGPathElement::CreateSVGPathSegCurvetoCubicSmoothAbs(float x
, float y
,
179 float x2
, float y2
) {
180 // See comment in CreateSVGPathSegCurvetoCubicAbs
181 RefPtr
<DOMSVGPathSegCurvetoCubicSmoothAbs
> pathSeg
=
182 new DOMSVGPathSegCurvetoCubicSmoothAbs(x2
, y2
, x
, y
);
183 return pathSeg
.forget();
186 already_AddRefed
<DOMSVGPathSegCurvetoCubicSmoothRel
>
187 SVGPathElement::CreateSVGPathSegCurvetoCubicSmoothRel(float x
, float y
,
188 float x2
, float y2
) {
189 // See comment in CreateSVGPathSegCurvetoCubicAbs
190 RefPtr
<DOMSVGPathSegCurvetoCubicSmoothRel
> pathSeg
=
191 new DOMSVGPathSegCurvetoCubicSmoothRel(x2
, y2
, x
, y
);
192 return pathSeg
.forget();
195 already_AddRefed
<DOMSVGPathSegCurvetoQuadraticSmoothAbs
>
196 SVGPathElement::CreateSVGPathSegCurvetoQuadraticSmoothAbs(float x
, float y
) {
197 RefPtr
<DOMSVGPathSegCurvetoQuadraticSmoothAbs
> pathSeg
=
198 new DOMSVGPathSegCurvetoQuadraticSmoothAbs(x
, y
);
199 return pathSeg
.forget();
202 already_AddRefed
<DOMSVGPathSegCurvetoQuadraticSmoothRel
>
203 SVGPathElement::CreateSVGPathSegCurvetoQuadraticSmoothRel(float x
, float y
) {
204 RefPtr
<DOMSVGPathSegCurvetoQuadraticSmoothRel
> pathSeg
=
205 new DOMSVGPathSegCurvetoQuadraticSmoothRel(x
, y
);
206 return pathSeg
.forget();
209 already_AddRefed
<DOMSVGPathSegList
> SVGPathElement::PathSegList() {
210 return DOMSVGPathSegList::GetDOMWrapper(mD
.GetBaseValKey(), this, false);
213 already_AddRefed
<DOMSVGPathSegList
> SVGPathElement::AnimatedPathSegList() {
214 return DOMSVGPathSegList::GetDOMWrapper(mD
.GetAnimValKey(), this, true);
217 //----------------------------------------------------------------------
218 // SVGElement methods
221 bool SVGPathElement::HasValidDimensions() const {
222 return !mD
.GetAnimValue().IsEmpty();
225 //----------------------------------------------------------------------
226 // nsIContent methods
229 SVGPathElement::IsAttributeMapped(const nsAtom
* name
) const {
230 static const MappedAttributeEntry
* const map
[] = {sMarkersMap
};
232 return FindAttributeDependence(name
, map
) ||
233 SVGPathElementBase::IsAttributeMapped(name
);
236 already_AddRefed
<Path
> SVGPathElement::GetOrBuildPathForMeasuring() {
237 return mD
.GetAnimValue().BuildPathForMeasuring();
240 //----------------------------------------------------------------------
241 // SVGGeometryElement methods
243 bool SVGPathElement::AttributeDefinesGeometry(const nsAtom
* aName
) {
244 return aName
== nsGkAtoms::d
|| aName
== nsGkAtoms::pathLength
;
247 bool SVGPathElement::IsMarkable() { return true; }
249 void SVGPathElement::GetMarkPoints(nsTArray
<SVGMark
>* aMarks
) {
250 mD
.GetAnimValue().GetMarkerPositioningData(aMarks
);
253 already_AddRefed
<Path
> SVGPathElement::BuildPath(PathBuilder
* aBuilder
) {
254 // The Moz2D PathBuilder that our SVGPathData will be using only cares about
255 // the fill rule. However, in order to fulfill the requirements of the SVG
256 // spec regarding zero length sub-paths when square line caps are in use,
257 // SVGPathData needs to know our stroke-linecap style and, if "square", then
258 // also our stroke width. See the comment for
259 // ApproximateZeroLengthSubpathSquareCaps for more info.
261 auto strokeLineCap
= StyleStrokeLinecap::Butt
;
262 Float strokeWidth
= 0;
264 SVGGeometryProperty::DoForComputedStyle(this, [&](const ComputedStyle
* s
) {
265 const nsStyleSVG
* style
= s
->StyleSVG();
266 // Note: the path that we return may be used for hit-testing, and SVG
267 // exposes hit-testing of strokes that are not actually painted. For that
268 // reason we do not check for eStyleSVGPaintType_None or check the stroke
270 if (style
->mStrokeLinecap
!= StyleStrokeLinecap::Butt
) {
271 strokeLineCap
= style
->mStrokeLinecap
;
272 strokeWidth
= SVGContentUtils::GetStrokeWidth(this, s
, nullptr);
276 return mD
.GetAnimValue().BuildPath(aBuilder
, strokeLineCap
, strokeWidth
);
280 } // namespace mozilla