SVGMarkerElement.cpp (7378B)
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 #include "mozilla/dom/SVGMarkerElement.h" 8 9 #include "DOMSVGAngle.h" 10 #include "SVGAnimatedPreserveAspectRatio.h" 11 #include "SVGContentUtils.h" 12 #include "mozilla/dom/SVGGeometryElement.h" 13 #include "mozilla/dom/SVGLengthBinding.h" 14 #include "mozilla/dom/SVGMarkerElementBinding.h" 15 #include "mozilla/gfx/Matrix.h" 16 #include "nsError.h" 17 #include "nsGkAtoms.h" 18 19 using namespace mozilla::gfx; 20 using namespace mozilla::dom::SVGMarkerElement_Binding; 21 22 NS_IMPL_NS_NEW_SVG_ELEMENT(Marker) 23 24 namespace mozilla::dom { 25 26 using namespace SVGAngle_Binding; 27 28 JSObject* SVGMarkerElement::WrapNode(JSContext* aCx, 29 JS::Handle<JSObject*> aGivenProto) { 30 return SVGMarkerElement_Binding::Wrap(aCx, this, aGivenProto); 31 } 32 33 SVGElement::LengthInfo SVGMarkerElement::sLengthInfo[4] = { 34 {nsGkAtoms::refX, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, 35 SVGContentUtils::X}, 36 {nsGkAtoms::refY, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, 37 SVGContentUtils::Y}, 38 {nsGkAtoms::markerWidth, 3, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, 39 SVGContentUtils::X}, 40 {nsGkAtoms::markerHeight, 3, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, 41 SVGContentUtils::Y}, 42 }; 43 44 SVGEnumMapping SVGMarkerElement::sUnitsMap[] = { 45 {nsGkAtoms::strokeWidth, SVG_MARKERUNITS_STROKEWIDTH}, 46 {nsGkAtoms::userSpaceOnUse, SVG_MARKERUNITS_USERSPACEONUSE}, 47 {nullptr, 0}}; 48 49 SVGElement::EnumInfo SVGMarkerElement::sEnumInfo[1] = { 50 {nsGkAtoms::markerUnits, sUnitsMap, SVG_MARKERUNITS_STROKEWIDTH}}; 51 52 //---------------------------------------------------------------------- 53 // Implementation 54 55 SVGMarkerElement::SVGMarkerElement( 56 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) 57 : SVGMarkerElementBase(std::move(aNodeInfo)), mCoordCtx(nullptr) {} 58 59 //---------------------------------------------------------------------- 60 // nsINode methods 61 62 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGMarkerElement) 63 64 //---------------------------------------------------------------------- 65 66 already_AddRefed<SVGAnimatedRect> SVGMarkerElement::ViewBox() { 67 return mViewBox.ToSVGAnimatedRect(this); 68 } 69 70 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> 71 SVGMarkerElement::PreserveAspectRatio() { 72 return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this); 73 } 74 75 //---------------------------------------------------------------------- 76 77 already_AddRefed<DOMSVGAnimatedLength> SVGMarkerElement::RefX() { 78 return mLengthAttributes[REFX].ToDOMAnimatedLength(this); 79 } 80 81 already_AddRefed<DOMSVGAnimatedLength> SVGMarkerElement::RefY() { 82 return mLengthAttributes[REFY].ToDOMAnimatedLength(this); 83 } 84 85 already_AddRefed<DOMSVGAnimatedEnumeration> SVGMarkerElement::MarkerUnits() { 86 return mEnumAttributes[MARKERUNITS].ToDOMAnimatedEnum(this); 87 } 88 89 already_AddRefed<DOMSVGAnimatedLength> SVGMarkerElement::MarkerWidth() { 90 return mLengthAttributes[MARKERWIDTH].ToDOMAnimatedLength(this); 91 } 92 93 already_AddRefed<DOMSVGAnimatedLength> SVGMarkerElement::MarkerHeight() { 94 return mLengthAttributes[MARKERHEIGHT].ToDOMAnimatedLength(this); 95 } 96 97 already_AddRefed<DOMSVGAnimatedEnumeration> SVGMarkerElement::OrientType() { 98 return mOrient.ToDOMAnimatedEnum(this); 99 } 100 101 already_AddRefed<DOMSVGAnimatedAngle> SVGMarkerElement::OrientAngle() { 102 return mOrient.ToDOMAnimatedAngle(this); 103 } 104 105 void SVGMarkerElement::SetOrientToAuto() { 106 mOrient.SetBaseType(SVG_MARKER_ORIENT_AUTO, this, IgnoreErrors()); 107 } 108 109 void SVGMarkerElement::SetOrientToAngle(DOMSVGAngle& aAngle) { 110 nsAutoString angle; 111 aAngle.GetValueAsString(angle); 112 mOrient.SetBaseValueString(angle, this, true); 113 } 114 115 //---------------------------------------------------------------------- 116 // SVGElement methods 117 118 void SVGMarkerElement::SetParentCoordCtxProvider(SVGViewportElement* aContext) { 119 mCoordCtx = aContext; 120 mViewBoxToViewportTransform = nullptr; 121 } 122 123 /* virtual */ 124 bool SVGMarkerElement::HasValidDimensions() const { 125 return (!mLengthAttributes[MARKERWIDTH].IsExplicitlySet() || 126 mLengthAttributes[MARKERWIDTH].GetAnimValInSpecifiedUnits() > 0) && 127 (!mLengthAttributes[MARKERHEIGHT].IsExplicitlySet() || 128 mLengthAttributes[MARKERHEIGHT].GetAnimValInSpecifiedUnits() > 0); 129 } 130 131 SVGElement::LengthAttributesInfo SVGMarkerElement::GetLengthInfo() { 132 return LengthAttributesInfo(mLengthAttributes, sLengthInfo, 133 std::size(sLengthInfo)); 134 } 135 136 SVGElement::EnumAttributesInfo SVGMarkerElement::GetEnumInfo() { 137 return EnumAttributesInfo(mEnumAttributes, sEnumInfo, std::size(sEnumInfo)); 138 } 139 140 SVGAnimatedOrient* SVGMarkerElement::GetAnimatedOrient() { return &mOrient; } 141 142 SVGAnimatedViewBox* SVGMarkerElement::GetAnimatedViewBox() { return &mViewBox; } 143 144 SVGAnimatedPreserveAspectRatio* 145 SVGMarkerElement::GetAnimatedPreserveAspectRatio() { 146 return &mPreserveAspectRatio; 147 } 148 149 //---------------------------------------------------------------------- 150 // public helpers 151 152 gfx::Matrix SVGMarkerElement::GetMarkerTransform(float aStrokeWidth, 153 const SVGMark& aMark) { 154 float scale = 155 mEnumAttributes[MARKERUNITS].GetAnimValue() == SVG_MARKERUNITS_STROKEWIDTH 156 ? aStrokeWidth 157 : 1.0f; 158 159 float angle; 160 switch (mOrient.GetAnimType()) { 161 case SVG_MARKER_ORIENT_AUTO: 162 angle = aMark.angle; 163 break; 164 case SVG_MARKER_ORIENT_AUTO_START_REVERSE: 165 angle = aMark.angle + (aMark.type == SVGMark::eStart ? M_PI : 0.0f); 166 break; 167 default: // SVG_MARKER_ORIENT_ANGLE 168 angle = mOrient.GetAnimValue() * M_PI / 180.0f; 169 break; 170 } 171 172 return gfx::Matrix(cos(angle) * scale, sin(angle) * scale, 173 -sin(angle) * scale, cos(angle) * scale, aMark.x, aMark.y); 174 } 175 176 SVGViewBox SVGMarkerElement::GetViewBox() { 177 if (mViewBox.HasRect()) { 178 float zoom = UserSpaceMetrics::GetZoom(this); 179 return mViewBox.GetAnimValue() * zoom; 180 } 181 return SVGViewBox( 182 0, 0, mLengthAttributes[MARKERWIDTH].GetAnimValueWithZoom(mCoordCtx), 183 mLengthAttributes[MARKERHEIGHT].GetAnimValueWithZoom(mCoordCtx)); 184 } 185 186 gfx::Matrix SVGMarkerElement::GetViewBoxTransform() { 187 if (!mViewBoxToViewportTransform) { 188 float viewportWidth = 189 mLengthAttributes[MARKERWIDTH].GetAnimValueWithZoom(mCoordCtx); 190 float viewportHeight = 191 mLengthAttributes[MARKERHEIGHT].GetAnimValueWithZoom(mCoordCtx); 192 193 SVGViewBox viewbox = GetViewBox(); 194 195 MOZ_ASSERT(viewbox.width > 0.0f && viewbox.height > 0.0f, 196 "Rendering should be disabled"); 197 198 gfx::Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform( 199 viewportWidth, viewportHeight, viewbox.x, viewbox.y, viewbox.width, 200 viewbox.height, mPreserveAspectRatio); 201 202 float refX = mLengthAttributes[REFX].GetAnimValueWithZoom(mCoordCtx); 203 float refY = mLengthAttributes[REFY].GetAnimValueWithZoom(mCoordCtx); 204 205 gfx::Point ref = viewBoxTM.TransformPoint(gfx::Point(refX, refY)); 206 207 Matrix TM = viewBoxTM; 208 TM.PostTranslate(-ref.x, -ref.y); 209 210 mViewBoxToViewportTransform = MakeUnique<gfx::Matrix>(TM); 211 } 212 213 return *mViewBoxToViewportTransform; 214 } 215 216 } // namespace mozilla::dom