SVGPathData.h (6912B)
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 #ifndef DOM_SVG_SVGPATHDATA_H_ 8 #define DOM_SVG_SVGPATHDATA_H_ 9 10 #include <string.h> 11 12 #include "mozilla/MemoryReporting.h" 13 #include "mozilla/ServoStyleConsts.h" 14 #include "mozilla/dom/SVGElement.h" 15 #include "mozilla/gfx/2D.h" 16 #include "mozilla/gfx/Types.h" 17 #include "nsCOMPtr.h" 18 #include "nsDebug.h" 19 #include "nsIContent.h" 20 #include "nsINode.h" 21 #include "nsIWeakReferenceUtils.h" 22 #include "nsTArray.h" 23 24 namespace mozilla { 25 26 struct SVGMark; 27 enum class StyleStrokeLinecap : uint8_t; 28 namespace dom { 29 class SVGPathElement; 30 class SVGPathSegment; 31 } // namespace dom 32 33 class SVGPathData { 34 friend class SVGAnimatedPathSegList; 35 friend class SVGPathDataAndInfo; 36 friend class SVGPathSegListSMILType; 37 38 using DrawTarget = gfx::DrawTarget; 39 using Path = gfx::Path; 40 using PathBuilder = gfx::PathBuilder; 41 using FillRule = gfx::FillRule; 42 using Float = gfx::Float; 43 using CapStyle = gfx::CapStyle; 44 45 public: 46 SVGPathData() = default; 47 ~SVGPathData() = default; 48 49 explicit SVGPathData(const nsACString& aString) { 50 SetValueFromString(aString); 51 } 52 53 SVGPathData& operator=(const SVGPathData&) = default; 54 SVGPathData(const SVGPathData&) = default; 55 SVGPathData& operator=(SVGPathData&&) = default; 56 SVGPathData(SVGPathData&&) = default; 57 58 // Used by SMILCompositor to check if the cached base val is out of date 59 bool operator==(const SVGPathData& rhs) const { return mData == rhs.mData; } 60 61 // Only methods that don't make/permit modification to this list are public. 62 // Only our friend classes can access methods that may change us. 63 64 /// This may return an incomplete string on OOM, but that's acceptable. 65 void GetValueAsString(nsACString& aValue) const; 66 67 Span<const StylePathCommand> AsSpan() const { return mData._0.AsSpan(); } 68 bool IsEmpty() const { return AsSpan().IsEmpty(); } 69 70 const StyleSVGPathData& RawData() const { return mData; } 71 72 static already_AddRefed<dom::SVGPathSegment> GetPathSegmentAtLength( 73 dom::SVGPathElement* aPathElement, Span<const StylePathCommand> aPath, 74 float aDistance); 75 76 void GetMarkerPositioningData(float aZoom, nsTArray<SVGMark>* aMarks) const; 77 78 static void GetMarkerPositioningData(Span<const StylePathCommand> aPath, 79 float aZoom, nsTArray<SVGMark>* aMarks); 80 /** 81 * Returns true, except on OOM, in which case returns false. 82 */ 83 bool GetDistancesFromOriginToEndsOfVisibleSegments( 84 FallibleTArray<double>* aOutput) const; 85 86 /** 87 * This is identical to the above one but accepts StylePathCommand. 88 */ 89 static bool GetDistancesFromOriginToEndsOfVisibleSegments( 90 Span<const StylePathCommand> aPath, FallibleTArray<double>* aOutput); 91 92 /** 93 * This returns a path without the extra little line segments that 94 * ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps. 95 * See the comment for that function for more info on that. 96 */ 97 already_AddRefed<Path> BuildPathForMeasuring(float aZoom) const; 98 99 already_AddRefed<Path> BuildPath(PathBuilder* aBuilder, 100 StyleStrokeLinecap aStrokeLineCap, 101 Float aStrokeWidth, float aZoom) const; 102 103 static already_AddRefed<Path> BuildPathForMeasuring( 104 Span<const StylePathCommand> aPath, float aZoom); 105 106 /** 107 * This function tries to build the path from an array of GenericShapeCommand, 108 * which is generated by cbindgen from Rust (see ServoStyleConsts.h). 109 * Basically, this is a variant of the above BuildPath() functions. 110 * Note: |StylePathCommand| doesn't accept percentage values, so its |aBasis| 111 * is empty by default. 112 */ 113 static already_AddRefed<Path> BuildPath(Span<const StylePathCommand> aPath, 114 PathBuilder* aBuilder, 115 StyleStrokeLinecap aStrokeLineCap, 116 Float aStrokeWidth, 117 const CSSSize& aBasis = {}, 118 const gfx::Point& aOffset = {}, 119 float aZoomFactor = 1.0); 120 static already_AddRefed<Path> BuildPath( 121 Span<const StyleShapeCommand> aShape, PathBuilder* aBuilder, 122 StyleStrokeLinecap aStrokeLineCap, Float aStrokeWidth, 123 const CSSSize& aBasis, const gfx::Point& aOffset = gfx::Point(), 124 float aZoomFactor = 1.0); 125 126 // memory reporting methods 127 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 128 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 129 130 protected: 131 nsresult SetValueFromString(const nsACString& aValue); 132 133 void Clear() { mData = {}; } 134 135 StyleSVGPathData& RawData() { return mData; } 136 137 mozilla::StyleSVGPathData mData; 138 }; 139 140 /** 141 * This SVGPathData subclass is for SVGPathSegListSMILType which needs to 142 * have write access to the lists it works with. 143 * 144 * Instances of this class do not have DOM wrappers that need to be kept in 145 * sync, so we can safely expose any protected base class methods required by 146 * the SMIL code. 147 */ 148 class SVGPathDataAndInfo final : public SVGPathData { 149 public: 150 explicit SVGPathDataAndInfo(dom::SVGElement* aElement = nullptr) 151 : mElement(do_GetWeakReference(static_cast<nsINode*>(aElement))) {} 152 153 void SetElement(dom::SVGElement* aElement) { 154 mElement = do_GetWeakReference(static_cast<nsINode*>(aElement)); 155 } 156 157 dom::SVGElement* Element() const { 158 nsCOMPtr<nsIContent> e = do_QueryReferent(mElement); 159 return static_cast<dom::SVGElement*>(e.get()); 160 } 161 162 // If you use this, you need to call SetElement manually. 163 void CopyFrom(const SVGPathData& aOther) { mData = aOther.mData; } 164 void CopyFrom(const SVGPathDataAndInfo& aOther) { 165 CopyFrom(static_cast<const SVGPathData&>(aOther)); 166 mElement = aOther.mElement; 167 } 168 169 /** 170 * Returns true if this object is an "identity" value, from the perspective 171 * of SMIL. In other words, returns true until the initial value set up in 172 * SVGPathSegListSMILType::InitValue() has been changed with a SetElement() 173 * call. 174 */ 175 bool IsIdentity() const { 176 if (!mElement) { 177 MOZ_ASSERT(IsEmpty(), "target element propagation failure"); 178 return true; 179 } 180 return false; 181 } 182 183 private: 184 // We must keep a weak reference to our element because we may belong to a 185 // cached baseVal SMILValue. See the comments starting at: 186 // https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15 187 // See also https://bugzilla.mozilla.org/show_bug.cgi?id=653497 188 nsWeakPtr mElement; 189 }; 190 191 } // namespace mozilla 192 193 #endif // DOM_SVG_SVGPATHDATA_H_