/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef DOM_SVG_SVGPATHDATA_H_ #define DOM_SVG_SVGPATHDATA_H_ #include "nsCOMPtr.h" #include "nsDebug.h" #include "nsIContent.h" #include "nsINode.h" #include "nsIWeakReferenceUtils.h" #include "mozilla/dom/SVGElement.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Types.h" #include "mozilla/MemoryReporting.h" #include "mozilla/RefPtr.h" #include "mozilla/ServoStyleConsts.h" #include "nsTArray.h" #include namespace mozilla { struct SVGMark; enum class StyleStrokeLinecap : uint8_t; namespace dom { class SVGPathElement; class SVGPathSegment; } // namespace dom class SVGPathData { friend class SVGAnimatedPathSegList; friend class SVGPathDataAndInfo; friend class SVGPathSegListSMILType; using DrawTarget = gfx::DrawTarget; using Path = gfx::Path; using PathBuilder = gfx::PathBuilder; using FillRule = gfx::FillRule; using Float = gfx::Float; using CapStyle = gfx::CapStyle; public: SVGPathData() = default; ~SVGPathData() = default; explicit SVGPathData(const nsACString& aString) { SetValueFromString(aString); } SVGPathData& operator=(const SVGPathData&) = default; SVGPathData(const SVGPathData&) = default; SVGPathData& operator=(SVGPathData&&) = default; SVGPathData(SVGPathData&&) = default; // Used by SMILCompositor to check if the cached base val is out of date bool operator==(const SVGPathData& rhs) const { return mData == rhs.mData; } // Only methods that don't make/permit modification to this list are public. // Only our friend classes can access methods that may change us. /// This may return an incomplete string on OOM, but that's acceptable. void GetValueAsString(nsACString& aValue) const; Span AsSpan() const { return mData._0.AsSpan(); } bool IsEmpty() const { return AsSpan().IsEmpty(); } const StyleSVGPathData& RawData() const { return mData; } static already_AddRefed GetPathSegmentAtLength( dom::SVGPathElement* aPathElement, Span aPath, float aDistance); void GetMarkerPositioningData(float aZoom, nsTArray* aMarks) const; static void GetMarkerPositioningData(Span aPath, float aZoom, nsTArray* aMarks); /** * Returns true, except on OOM, in which case returns false. */ bool GetDistancesFromOriginToEndsOfVisibleSegments( FallibleTArray* aOutput) const; /** * This is identical to the above one but accepts StylePathCommand. */ static bool GetDistancesFromOriginToEndsOfVisibleSegments( Span aPath, FallibleTArray* aOutput); /** * This returns a path without the extra little line segments that * ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps. * See the comment for that function for more info on that. */ already_AddRefed BuildPathForMeasuring(float aZoom) const; already_AddRefed BuildPath(PathBuilder* aBuilder, StyleStrokeLinecap aStrokeLineCap, Float aStrokeWidth, float aZoom) const; static already_AddRefed BuildPathForMeasuring( Span aPath, float aZoom); /** * This function tries to build the path from an array of GenericShapeCommand, * which is generated by cbindgen from Rust (see ServoStyleConsts.h). * Basically, this is a variant of the above BuildPath() functions. * Note: |StylePathCommand| doesn't accept percentage values, so its |aBasis| * is empty by default. */ static already_AddRefed BuildPath(Span aPath, PathBuilder* aBuilder, StyleStrokeLinecap aStrokeLineCap, Float aStrokeWidth, const CSSSize& aBasis = {}, const gfx::Point& aOffset = {}, float aZoomFactor = 1.0); static already_AddRefed BuildPath( Span aShape, PathBuilder* aBuilder, StyleStrokeLinecap aStrokeLineCap, Float aStrokeWidth, const CSSSize& aBasis, const gfx::Point& aOffset = gfx::Point(), float aZoomFactor = 1.0); // memory reporting methods size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; protected: nsresult SetValueFromString(const nsACString& aValue); void Clear() { mData = {}; } StyleSVGPathData& RawData() { return mData; } mozilla::StyleSVGPathData mData; }; /** * This SVGPathData subclass is for SVGPathSegListSMILType which needs to * have write access to the lists it works with. * * Instances of this class do not have DOM wrappers that need to be kept in * sync, so we can safely expose any protected base class methods required by * the SMIL code. */ class SVGPathDataAndInfo final : public SVGPathData { public: explicit SVGPathDataAndInfo(dom::SVGElement* aElement = nullptr) : mElement(do_GetWeakReference(static_cast(aElement))) {} void SetElement(dom::SVGElement* aElement) { mElement = do_GetWeakReference(static_cast(aElement)); } dom::SVGElement* Element() const { nsCOMPtr e = do_QueryReferent(mElement); return static_cast(e.get()); } // If you use this, you need to call SetElement manually. void CopyFrom(const SVGPathData& aOther) { mData = aOther.mData; } void CopyFrom(const SVGPathDataAndInfo& aOther) { CopyFrom(static_cast(aOther)); mElement = aOther.mElement; } /** * Returns true if this object is an "identity" value, from the perspective * of SMIL. In other words, returns true until the initial value set up in * SVGPathSegListSMILType::Init() has been changed with a SetElement() call. */ bool IsIdentity() const { if (!mElement) { MOZ_ASSERT(IsEmpty(), "target element propagation failure"); return true; } return false; } private: // We must keep a weak reference to our element because we may belong to a // cached baseVal SMILValue. See the comments starting at: // https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15 // See also https://bugzilla.mozilla.org/show_bug.cgi?id=653497 nsWeakPtr mElement; }; } // namespace mozilla #endif // DOM_SVG_SVGPATHDATA_H_