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/SVGMarkerElement.h"
10 #include "DOMSVGAngle.h"
11 #include "SVGAnimatedPreserveAspectRatio.h"
13 #include "mozilla/ArrayUtils.h"
14 #include "mozilla/dom/SVGGeometryElement.h"
15 #include "mozilla/dom/SVGLengthBinding.h"
16 #include "mozilla/dom/SVGMarkerElementBinding.h"
17 #include "mozilla/gfx/Matrix.h"
18 #include "mozilla/FloatingPoint.h"
19 #include "mozilla/RefPtr.h"
20 #include "SVGContentUtils.h"
22 using namespace mozilla::gfx
;
23 using namespace mozilla::dom::SVGMarkerElement_Binding
;
25 NS_IMPL_NS_NEW_SVG_ELEMENT(Marker
)
27 namespace mozilla::dom
{
29 using namespace SVGAngle_Binding
;
31 JSObject
* SVGMarkerElement::WrapNode(JSContext
* aCx
,
32 JS::Handle
<JSObject
*> aGivenProto
) {
33 return SVGMarkerElement_Binding::Wrap(aCx
, this, aGivenProto
);
36 SVGElement::LengthInfo
SVGMarkerElement::sLengthInfo
[4] = {
37 {nsGkAtoms::refX
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
39 {nsGkAtoms::refY
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
41 {nsGkAtoms::markerWidth
, 3, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
43 {nsGkAtoms::markerHeight
, 3, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
47 SVGEnumMapping
SVGMarkerElement::sUnitsMap
[] = {
48 {nsGkAtoms::strokeWidth
, SVG_MARKERUNITS_STROKEWIDTH
},
49 {nsGkAtoms::userSpaceOnUse
, SVG_MARKERUNITS_USERSPACEONUSE
},
52 SVGElement::EnumInfo
SVGMarkerElement::sEnumInfo
[1] = {
53 {nsGkAtoms::markerUnits
, sUnitsMap
, SVG_MARKERUNITS_STROKEWIDTH
}};
55 //----------------------------------------------------------------------
58 SVGMarkerElement::SVGMarkerElement(
59 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
60 : SVGMarkerElementBase(std::move(aNodeInfo
)), mCoordCtx(nullptr) {}
62 //----------------------------------------------------------------------
65 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGMarkerElement
)
67 //----------------------------------------------------------------------
69 already_AddRefed
<SVGAnimatedRect
> SVGMarkerElement::ViewBox() {
70 return mViewBox
.ToSVGAnimatedRect(this);
73 already_AddRefed
<DOMSVGAnimatedPreserveAspectRatio
>
74 SVGMarkerElement::PreserveAspectRatio() {
75 return mPreserveAspectRatio
.ToDOMAnimatedPreserveAspectRatio(this);
78 //----------------------------------------------------------------------
80 already_AddRefed
<DOMSVGAnimatedLength
> SVGMarkerElement::RefX() {
81 return mLengthAttributes
[REFX
].ToDOMAnimatedLength(this);
84 already_AddRefed
<DOMSVGAnimatedLength
> SVGMarkerElement::RefY() {
85 return mLengthAttributes
[REFY
].ToDOMAnimatedLength(this);
88 already_AddRefed
<DOMSVGAnimatedEnumeration
> SVGMarkerElement::MarkerUnits() {
89 return mEnumAttributes
[MARKERUNITS
].ToDOMAnimatedEnum(this);
92 already_AddRefed
<DOMSVGAnimatedLength
> SVGMarkerElement::MarkerWidth() {
93 return mLengthAttributes
[MARKERWIDTH
].ToDOMAnimatedLength(this);
96 already_AddRefed
<DOMSVGAnimatedLength
> SVGMarkerElement::MarkerHeight() {
97 return mLengthAttributes
[MARKERHEIGHT
].ToDOMAnimatedLength(this);
100 already_AddRefed
<DOMSVGAnimatedEnumeration
> SVGMarkerElement::OrientType() {
101 return mOrient
.ToDOMAnimatedEnum(this);
104 already_AddRefed
<DOMSVGAnimatedAngle
> SVGMarkerElement::OrientAngle() {
105 return mOrient
.ToDOMAnimatedAngle(this);
108 void SVGMarkerElement::SetOrientToAuto() {
109 mOrient
.SetBaseType(SVG_MARKER_ORIENT_AUTO
, this, IgnoreErrors());
112 void SVGMarkerElement::SetOrientToAngle(DOMSVGAngle
& aAngle
) {
114 aAngle
.GetValueAsString(angle
);
115 mOrient
.SetBaseValueString(angle
, this, true);
118 //----------------------------------------------------------------------
119 // SVGElement methods
121 void SVGMarkerElement::SetParentCoordCtxProvider(SVGViewportElement
* aContext
) {
122 mCoordCtx
= aContext
;
123 mViewBoxToViewportTransform
= nullptr;
127 bool SVGMarkerElement::HasValidDimensions() const {
128 return (!mLengthAttributes
[MARKERWIDTH
].IsExplicitlySet() ||
129 mLengthAttributes
[MARKERWIDTH
].GetAnimValInSpecifiedUnits() > 0) &&
130 (!mLengthAttributes
[MARKERHEIGHT
].IsExplicitlySet() ||
131 mLengthAttributes
[MARKERHEIGHT
].GetAnimValInSpecifiedUnits() > 0);
134 SVGElement::LengthAttributesInfo
SVGMarkerElement::GetLengthInfo() {
135 return LengthAttributesInfo(mLengthAttributes
, sLengthInfo
,
136 std::size(sLengthInfo
));
139 SVGElement::EnumAttributesInfo
SVGMarkerElement::GetEnumInfo() {
140 return EnumAttributesInfo(mEnumAttributes
, sEnumInfo
, std::size(sEnumInfo
));
143 SVGAnimatedOrient
* SVGMarkerElement::GetAnimatedOrient() { return &mOrient
; }
145 SVGAnimatedViewBox
* SVGMarkerElement::GetAnimatedViewBox() { return &mViewBox
; }
147 SVGAnimatedPreserveAspectRatio
*
148 SVGMarkerElement::GetAnimatedPreserveAspectRatio() {
149 return &mPreserveAspectRatio
;
152 //----------------------------------------------------------------------
155 gfx::Matrix
SVGMarkerElement::GetMarkerTransform(float aStrokeWidth
,
156 const SVGMark
& aMark
) {
158 mEnumAttributes
[MARKERUNITS
].GetAnimValue() == SVG_MARKERUNITS_STROKEWIDTH
163 switch (mOrient
.GetAnimType()) {
164 case SVG_MARKER_ORIENT_AUTO
:
167 case SVG_MARKER_ORIENT_AUTO_START_REVERSE
:
168 angle
= aMark
.angle
+ (aMark
.type
== SVGMark::eStart
? M_PI
: 0.0f
);
170 default: // SVG_MARKER_ORIENT_ANGLE
171 angle
= mOrient
.GetAnimValue() * M_PI
/ 180.0f
;
175 return gfx::Matrix(cos(angle
) * scale
, sin(angle
) * scale
,
176 -sin(angle
) * scale
, cos(angle
) * scale
, aMark
.x
, aMark
.y
);
179 SVGViewBox
SVGMarkerElement::GetViewBox() {
180 if (mViewBox
.HasRect()) {
181 float zoom
= UserSpaceMetrics::GetZoom(this);
182 return mViewBox
.GetAnimValue() * zoom
;
185 0, 0, mLengthAttributes
[MARKERWIDTH
].GetAnimValueWithZoom(mCoordCtx
),
186 mLengthAttributes
[MARKERHEIGHT
].GetAnimValueWithZoom(mCoordCtx
));
189 gfx::Matrix
SVGMarkerElement::GetViewBoxTransform() {
190 if (!mViewBoxToViewportTransform
) {
191 float viewportWidth
=
192 mLengthAttributes
[MARKERWIDTH
].GetAnimValueWithZoom(mCoordCtx
);
193 float viewportHeight
=
194 mLengthAttributes
[MARKERHEIGHT
].GetAnimValueWithZoom(mCoordCtx
);
196 SVGViewBox viewbox
= GetViewBox();
198 MOZ_ASSERT(viewbox
.width
> 0.0f
&& viewbox
.height
> 0.0f
,
199 "Rendering should be disabled");
201 gfx::Matrix viewBoxTM
= SVGContentUtils::GetViewBoxTransform(
202 viewportWidth
, viewportHeight
, viewbox
.x
, viewbox
.y
, viewbox
.width
,
203 viewbox
.height
, mPreserveAspectRatio
);
205 float refX
= mLengthAttributes
[REFX
].GetAnimValueWithZoom(mCoordCtx
);
206 float refY
= mLengthAttributes
[REFY
].GetAnimValueWithZoom(mCoordCtx
);
208 gfx::Point ref
= viewBoxTM
.TransformPoint(gfx::Point(refX
, refY
));
210 Matrix TM
= viewBoxTM
;
211 TM
.PostTranslate(-ref
.x
, -ref
.y
);
213 mViewBoxToViewportTransform
= MakeUnique
<gfx::Matrix
>(TM
);
216 return *mViewBoxToViewportTransform
;
219 } // namespace mozilla::dom