SVGPolyElement.cpp (3960B)
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 "SVGPolyElement.h" 8 9 #include "DOMSVGPointList.h" 10 #include "SVGContentUtils.h" 11 #include "mozilla/dom/SVGAnimatedLength.h" 12 #include "mozilla/gfx/2D.h" 13 14 using namespace mozilla::gfx; 15 16 namespace mozilla::dom { 17 18 //---------------------------------------------------------------------- 19 // Implementation 20 21 SVGPolyElement::SVGPolyElement( 22 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) 23 : SVGPolyElementBase(std::move(aNodeInfo)) {} 24 25 already_AddRefed<DOMSVGPointList> SVGPolyElement::Points() { 26 return DOMSVGPointList::GetDOMWrapper(mPoints.GetBaseValKey(), this); 27 } 28 29 already_AddRefed<DOMSVGPointList> SVGPolyElement::AnimatedPoints() { 30 return DOMSVGPointList::GetDOMWrapper(mPoints.GetAnimValKey(), this); 31 } 32 33 //---------------------------------------------------------------------- 34 // SVGElement methods 35 36 /* virtual */ 37 bool SVGPolyElement::HasValidDimensions() const { 38 return !mPoints.GetAnimValue().IsEmpty(); 39 } 40 41 //---------------------------------------------------------------------- 42 // SVGGeometryElement methods 43 44 bool SVGPolyElement::AttributeDefinesGeometry(const nsAtom* aName) { 45 return aName == nsGkAtoms::points || aName == nsGkAtoms::pathLength; 46 } 47 48 void SVGPolyElement::GetMarkPoints(nsTArray<SVGMark>* aMarks) { 49 const SVGPointList& points = mPoints.GetAnimValue(); 50 51 if (points.IsEmpty()) { 52 return; 53 } 54 55 float zoom = UserSpaceMetrics::GetZoom(this); 56 57 float px = points[0].mX * zoom, py = points[0].mY * zoom, prevAngle = 0.0f; 58 if (!(std::isfinite(px) && std::isfinite(py))) { 59 return; 60 } 61 62 aMarks->AppendElement(SVGMark(px, py, 0, SVGMark::eStart)); 63 64 for (uint32_t i = 1; i < points.Length(); ++i) { 65 float x = points[i].mX * zoom; 66 float y = points[i].mY * zoom; 67 if (!(std::isfinite(x) && std::isfinite(y))) { 68 aMarks->Clear(); 69 return; 70 } 71 float angle = std::atan2(y - py, x - px); 72 73 // Vertex marker. 74 if (i == 1) { 75 aMarks->ElementAt(0).angle = angle; 76 } else { 77 aMarks->LastElement().angle = 78 SVGContentUtils::AngleBisect(prevAngle, angle); 79 } 80 81 aMarks->AppendElement(SVGMark(x, y, 0, SVGMark::eMid)); 82 83 prevAngle = angle; 84 px = x; 85 py = y; 86 } 87 88 aMarks->LastElement().angle = prevAngle; 89 aMarks->LastElement().type = SVGMark::eEnd; 90 } 91 92 bool SVGPolyElement::GetGeometryBounds(Rect* aBounds, 93 const StrokeOptions& aStrokeOptions, 94 const Matrix& aToBoundsSpace, 95 const Matrix* aToNonScalingStrokeSpace) { 96 const SVGPointList& points = mPoints.GetAnimValue(); 97 98 if (points.IsEmpty()) { 99 // Rendering of the element is disabled 100 aBounds->SetEmpty(); 101 return true; 102 } 103 104 if (aStrokeOptions.mLineWidth > 0 || aToNonScalingStrokeSpace) { 105 // We don't handle non-scaling-stroke or stroke-miterlimit etc. yet 106 return false; 107 } 108 109 float zoom = UserSpaceMetrics::GetZoom(this); 110 111 if (aToBoundsSpace.IsRectilinear()) { 112 // We can avoid transforming each point and just transform the result. 113 // Important for large point lists. 114 115 Rect bounds(Point(points[0]) * zoom, Size()); 116 for (uint32_t i = 1; i < points.Length(); ++i) { 117 bounds.ExpandToEnclose(Point(points[i]) * zoom); 118 } 119 *aBounds = aToBoundsSpace.TransformBounds(bounds); 120 } else { 121 *aBounds = 122 Rect(aToBoundsSpace.TransformPoint(Point(points[0]) * zoom), Size()); 123 for (uint32_t i = 1; i < points.Length(); ++i) { 124 aBounds->ExpandToEnclose( 125 aToBoundsSpace.TransformPoint(Point(points[i]) * zoom)); 126 } 127 } 128 return aBounds->IsFinite(); 129 } 130 } // namespace mozilla::dom