SVGEllipseElement.cpp (6487B)
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/SVGEllipseElement.h" 8 9 #include "ComputedStyle.h" 10 #include "SVGGeometryProperty.h" 11 #include "mozilla/dom/SVGEllipseElementBinding.h" 12 #include "mozilla/dom/SVGLengthBinding.h" 13 #include "mozilla/gfx/2D.h" 14 #include "mozilla/gfx/PathHelpers.h" 15 16 NS_IMPL_NS_NEW_SVG_ELEMENT(Ellipse) 17 18 using namespace mozilla::gfx; 19 20 namespace mozilla::dom { 21 22 JSObject* SVGEllipseElement::WrapNode(JSContext* aCx, 23 JS::Handle<JSObject*> aGivenProto) { 24 return SVGEllipseElement_Binding::Wrap(aCx, this, aGivenProto); 25 } 26 27 SVGElement::LengthInfo SVGEllipseElement::sLengthInfo[4] = { 28 {nsGkAtoms::cx, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, 29 SVGContentUtils::X}, 30 {nsGkAtoms::cy, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, 31 SVGContentUtils::Y}, 32 {nsGkAtoms::rx, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, 33 SVGContentUtils::X}, 34 {nsGkAtoms::ry, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, 35 SVGContentUtils::Y}, 36 }; 37 38 //---------------------------------------------------------------------- 39 // Implementation 40 41 SVGEllipseElement::SVGEllipseElement( 42 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) 43 : SVGEllipseElementBase(std::move(aNodeInfo)) {} 44 45 bool SVGEllipseElement::IsAttributeMapped(const nsAtom* aAttribute) const { 46 return IsInLengthInfo(aAttribute, sLengthInfo) || 47 SVGEllipseElementBase::IsAttributeMapped(aAttribute); 48 } 49 50 namespace SVGT = SVGGeometryProperty::Tags; 51 52 //---------------------------------------------------------------------- 53 // nsINode methods 54 55 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGEllipseElement) 56 57 //---------------------------------------------------------------------- 58 // nsIDOMSVGEllipseElement methods 59 60 already_AddRefed<DOMSVGAnimatedLength> SVGEllipseElement::Cx() { 61 return mLengthAttributes[CX].ToDOMAnimatedLength(this); 62 } 63 64 already_AddRefed<DOMSVGAnimatedLength> SVGEllipseElement::Cy() { 65 return mLengthAttributes[CY].ToDOMAnimatedLength(this); 66 } 67 68 already_AddRefed<DOMSVGAnimatedLength> SVGEllipseElement::Rx() { 69 return mLengthAttributes[RX].ToDOMAnimatedLength(this); 70 } 71 72 already_AddRefed<DOMSVGAnimatedLength> SVGEllipseElement::Ry() { 73 return mLengthAttributes[RY].ToDOMAnimatedLength(this); 74 } 75 76 //---------------------------------------------------------------------- 77 // SVGElement methods 78 79 /* virtual */ 80 bool SVGEllipseElement::HasValidDimensions() const { 81 float rx, ry; 82 83 if (SVGGeometryProperty::ResolveAll<SVGT::Rx, SVGT::Ry>(this, &rx, &ry)) { 84 return rx > 0 && ry > 0; 85 } 86 // This function might be called for an element in display:none subtree 87 // (e.g. SMIL animateMotion), we fall back to use SVG attributes. 88 bool hasRx = mLengthAttributes[RX].IsExplicitlySet(); 89 bool hasRy = mLengthAttributes[RY].IsExplicitlySet(); 90 if ((hasRx && mLengthAttributes[RX].GetAnimValInSpecifiedUnits() <= 0) || 91 (hasRy && mLengthAttributes[RY].GetAnimValInSpecifiedUnits() <= 0)) { 92 return false; 93 } 94 return hasRx || hasRy; 95 } 96 97 SVGElement::LengthAttributesInfo SVGEllipseElement::GetLengthInfo() { 98 return LengthAttributesInfo(mLengthAttributes, sLengthInfo, 99 std::size(sLengthInfo)); 100 } 101 102 //---------------------------------------------------------------------- 103 // SVGGeometryElement methods 104 105 bool SVGEllipseElement::GetGeometryBounds( 106 Rect* aBounds, const StrokeOptions& aStrokeOptions, 107 const Matrix& aToBoundsSpace, const Matrix* aToNonScalingStrokeSpace) { 108 float x, y, rx, ry; 109 110 DebugOnly<bool> ok = 111 SVGGeometryProperty::ResolveAll<SVGT::Cx, SVGT::Cy, SVGT::Rx, SVGT::Ry>( 112 this, &x, &y, &rx, &ry); 113 MOZ_ASSERT(ok, "SVGGeometryProperty::ResolveAll failed"); 114 115 if (rx <= 0.f || ry <= 0.f) { 116 // Rendering of the element is disabled 117 *aBounds = Rect(aToBoundsSpace.TransformPoint(Point(x, y)), Size()); 118 return true; 119 } 120 121 if (aToBoundsSpace.IsRectilinear()) { 122 // Optimize the case where we can treat the ellipse as a rectangle and 123 // still get tight bounds. 124 if (aStrokeOptions.mLineWidth > 0.f) { 125 if (aToNonScalingStrokeSpace) { 126 if (aToNonScalingStrokeSpace->IsRectilinear()) { 127 MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular()); 128 Rect userBounds(x - rx, y - ry, 2 * rx, 2 * ry); 129 SVGContentUtils::RectilinearGetStrokeBounds( 130 userBounds, aToBoundsSpace, *aToNonScalingStrokeSpace, 131 aStrokeOptions.mLineWidth, aBounds); 132 return true; 133 } 134 return false; 135 } 136 rx += aStrokeOptions.mLineWidth / 2.f; 137 ry += aStrokeOptions.mLineWidth / 2.f; 138 } 139 Rect rect(x - rx, y - ry, 2 * rx, 2 * ry); 140 *aBounds = aToBoundsSpace.TransformBounds(rect); 141 return true; 142 } 143 144 return false; 145 } 146 147 already_AddRefed<Path> SVGEllipseElement::BuildPath(PathBuilder* aBuilder) { 148 float x, y, rx, ry; 149 150 if (!SVGGeometryProperty::ResolveAll<SVGT::Cx, SVGT::Cy, SVGT::Rx, SVGT::Ry>( 151 this, &x, &y, &rx, &ry)) { 152 // This function might be called for element in display:none subtree 153 // (e.g. getTotalLength), we fall back to use SVG attributes. 154 GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr); 155 } 156 157 if (rx <= 0.0f || ry <= 0.0f) { 158 return nullptr; 159 } 160 161 EllipseToBezier(aBuilder, Point(x, y), Size(rx, ry)); 162 163 return aBuilder->Finish(); 164 } 165 166 bool SVGEllipseElement::IsLengthChangedViaCSS(const ComputedStyle& aNewStyle, 167 const ComputedStyle& aOldStyle) { 168 const auto& newSVGReset = *aNewStyle.StyleSVGReset(); 169 const auto& oldSVGReset = *aOldStyle.StyleSVGReset(); 170 return newSVGReset.mCx != oldSVGReset.mCx || 171 newSVGReset.mCy != oldSVGReset.mCy || 172 newSVGReset.mRx != oldSVGReset.mRx || 173 newSVGReset.mRy != oldSVGReset.mRy; 174 } 175 176 NonCustomCSSPropertyId SVGEllipseElement::GetCSSPropertyIdForAttrEnum( 177 uint8_t aAttrEnum) { 178 switch (aAttrEnum) { 179 case CX: 180 return eCSSProperty_cx; 181 case CY: 182 return eCSSProperty_cy; 183 case RX: 184 return eCSSProperty_rx; 185 case RY: 186 return eCSSProperty_ry; 187 default: 188 MOZ_ASSERT_UNREACHABLE("Unknown attr enum"); 189 return eCSSProperty_UNKNOWN; 190 } 191 } 192 193 } // namespace mozilla::dom