LCOV - code coverage report
Current view: top level - dom/svg - SVGPathData.h (source / functions) Hit Total Coverage
Test: output.info Lines: 7 37 18.9 %
Date: 2017-07-14 16:53:18 Functions: 4 17 23.5 %
Legend: Lines: hit not hit

          Line data    Source code
       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 MOZILLA_SVGPATHDATA_H__
       8             : #define MOZILLA_SVGPATHDATA_H__
       9             : 
      10             : #include "nsCOMPtr.h"
      11             : #include "nsDebug.h"
      12             : #include "nsIContent.h"
      13             : #include "nsINode.h"
      14             : #include "nsIWeakReferenceUtils.h"
      15             : #include "mozilla/gfx/2D.h"
      16             : #include "mozilla/gfx/Types.h"
      17             : #include "mozilla/MemoryReporting.h"
      18             : #include "mozilla/RefPtr.h"
      19             : #include "nsSVGElement.h"
      20             : #include "nsTArray.h"
      21             : 
      22             : #include <string.h>
      23             : 
      24             : class nsSVGPathDataParser; // IWYU pragma: keep
      25             : 
      26             : struct nsSVGMark;
      27             : 
      28             : namespace mozilla {
      29             : 
      30             : /**
      31             :  * ATTENTION! WARNING! WATCH OUT!!
      32             :  *
      33             :  * Consumers that modify objects of this type absolutely MUST keep the DOM
      34             :  * wrappers for those lists (if any) in sync!! That's why this class is so
      35             :  * locked down.
      36             :  *
      37             :  * The DOM wrapper class for this class is DOMSVGPathSegList.
      38             :  *
      39             :  * This class is not called |class SVGPathSegList| for one very good reason;
      40             :  * this class does not provide a list of "SVGPathSeg" items, it provides an
      41             :  * array of floats into which path segments are encoded. See the paragraphs
      42             :  * that follow for why. Note that the Length() method returns the number of
      43             :  * floats in our array, not the number of encoded segments, and the index
      44             :  * operator indexes floats in the array, not segments. If this class were
      45             :  * called SVGPathSegList the names of these methods would be very misleading.
      46             :  *
      47             :  * The reason this class is designed in this way is because there are many
      48             :  * different types of path segment, each taking a different numbers of
      49             :  * arguments. We want to store the segments in an nsTArray to avoid individual
      50             :  * allocations for each item, but the different size of segments means we can't
      51             :  * have one single segment type for the nsTArray (not without using a space
      52             :  * wasteful union or something similar). Since the internal code does not need
      53             :  * to index into the list (the DOM wrapper does, but it handles that itself)
      54             :  * the obvious solution is to have the items in this class take up variable
      55             :  * width and have the internal code iterate over these lists rather than index
      56             :  * into them.
      57             :  *
      58             :  * Implementing indexing to segments with O(1) performance would require us to
      59             :  * allocate and maintain a separate segment index table (keeping that table in
      60             :  * sync when items are inserted or removed from the list). So long as the
      61             :  * internal code doesn't require indexing to segments, we can avoid that
      62             :  * overhead and additional complexity.
      63             :  *
      64             :  * Segment encoding: the first float in the encoding of a segment contains the
      65             :  * segment's type. The segment's type is encoded to/decoded from this float
      66             :  * using the static methods SVGPathSegUtils::EncodeType(uint32_t)/
      67             :  * SVGPathSegUtils::DecodeType(float). If the path segment type in question
      68             :  * takes any arguments then these follow the first float, and are in the same
      69             :  * order as they are given in a <path> element's 'd' attribute (NOT in the
      70             :  * order of the createSVGPathSegXxx() methods' arguments from the SVG DOM
      71             :  * interface SVGPathElement, which are different...grr). Consumers can use
      72             :  * SVGPathSegUtils::ArgCountForType(type) to determine how many arguments
      73             :  * there are (if any), and thus where the current encoded segment ends, and
      74             :  * where the next segment (if any) begins.
      75             :  */
      76             : class SVGPathData
      77             : {
      78             :   friend class SVGAnimatedPathSegList;
      79             :   friend class DOMSVGPathSegList;
      80             :   friend class DOMSVGPathSeg;
      81             :   friend class ::nsSVGPathDataParser;
      82             :   // nsSVGPathDataParser will not keep wrappers in sync, so consumers
      83             :   // are responsible for that!
      84             : 
      85             :   typedef gfx::DrawTarget DrawTarget;
      86             :   typedef gfx::Path Path;
      87             :   typedef gfx::PathBuilder PathBuilder;
      88             :   typedef gfx::FillRule FillRule;
      89             :   typedef gfx::Float Float;
      90             :   typedef gfx::CapStyle CapStyle;
      91             : 
      92             : public:
      93             :   typedef const float* const_iterator;
      94             : 
      95          88 :   SVGPathData(){}
      96          44 :   ~SVGPathData(){}
      97             : 
      98             :   // Only methods that don't make/permit modification to this list are public.
      99             :   // Only our friend classes can access methods that may change us.
     100             : 
     101             :   /// This may return an incomplete string on OOM, but that's acceptable.
     102             :   void GetValueAsString(nsAString& aValue) const;
     103             : 
     104          14 :   bool IsEmpty() const {
     105          14 :     return mData.IsEmpty();
     106             :   }
     107             : 
     108             : #ifdef DEBUG
     109             :   /**
     110             :    * This method iterates over the encoded segment data and counts the number
     111             :    * of segments we currently have.
     112             :    */
     113             :   uint32_t CountItems() const;
     114             : #endif
     115             : 
     116             :   /**
     117             :    * Returns the number of *floats* in the encoding array, and NOT the number
     118             :    * of segments encoded in this object. (For that, see CountItems() above.)
     119             :    */
     120           0 :   uint32_t Length() const {
     121           0 :     return mData.Length();
     122             :   }
     123             : 
     124             :   const float& operator[](uint32_t aIndex) const {
     125             :     return mData[aIndex];
     126             :   }
     127             : 
     128             :   // Used by nsSMILCompositor to check if the cached base val is out of date
     129           0 :   bool operator==(const SVGPathData& rhs) const {
     130             :     // We use memcmp so that we don't need to worry that the data encoded in
     131             :     // the first float may have the same bit pattern as a NaN.
     132           0 :     return mData.Length() == rhs.mData.Length() &&
     133           0 :            memcmp(mData.Elements(), rhs.mData.Elements(),
     134           0 :                   mData.Length() * sizeof(float)) == 0;
     135             :   }
     136             : 
     137             :   bool SetCapacity(uint32_t aSize) {
     138             :     return mData.SetCapacity(aSize, fallible);
     139             :   }
     140             : 
     141             :   void Compact() {
     142             :     mData.Compact();
     143             :   }
     144             : 
     145             : 
     146             :   float GetPathLength() const;
     147             : 
     148             :   uint32_t GetPathSegAtLength(float aLength) const;
     149             : 
     150             :   void GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const;
     151             : 
     152             :   /**
     153             :    * Returns true, except on OOM, in which case returns false.
     154             :    */
     155             :   bool GetSegmentLengths(nsTArray<double> *aLengths) const;
     156             : 
     157             :   /**
     158             :    * Returns true, except on OOM, in which case returns false.
     159             :    */
     160             :   bool GetDistancesFromOriginToEndsOfVisibleSegments(FallibleTArray<double> *aArray) const;
     161             : 
     162             :   /**
     163             :    * This returns a path without the extra little line segments that
     164             :    * ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
     165             :    * See the comment for that function for more info on that.
     166             :    */
     167             :   already_AddRefed<Path> BuildPathForMeasuring() const;
     168             : 
     169             :   already_AddRefed<Path> BuildPath(PathBuilder* aBuilder,
     170             :                                uint8_t aCapStyle,
     171             :                                Float aStrokeWidth) const;
     172             : 
     173           0 :   const_iterator begin() const { return mData.Elements(); }
     174           0 :   const_iterator end() const { return mData.Elements() + mData.Length(); }
     175             : 
     176             :   // memory reporting methods
     177             :   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
     178             :   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
     179             : 
     180             :   // Access to methods that can modify objects of this type is deliberately
     181             :   // limited. This is to reduce the chances of someone modifying objects of
     182             :   // this type without taking the necessary steps to keep DOM wrappers in sync.
     183             :   // If you need wider access to these methods, consider adding a method to
     184             :   // SVGAnimatedPathSegList and having that class act as an intermediary so it
     185             :   // can take care of keeping DOM wrappers in sync.
     186             : 
     187             : protected:
     188             :   typedef float* iterator;
     189             : 
     190             :   /**
     191             :    * This may fail on OOM if the internal capacity needs to be increased, in
     192             :    * which case the list will be left unmodified.
     193             :    */
     194             :   nsresult CopyFrom(const SVGPathData& rhs);
     195             : 
     196             :   float& operator[](uint32_t aIndex) {
     197             :     return mData[aIndex];
     198             :   }
     199             : 
     200             :   /**
     201             :    * This may fail (return false) on OOM if the internal capacity is being
     202             :    * increased, in which case the list will be left unmodified.
     203             :    */
     204           0 :   bool SetLength(uint32_t aLength) {
     205           0 :     return mData.SetLength(aLength, fallible);
     206             :   }
     207             : 
     208             :   nsresult SetValueFromString(const nsAString& aValue);
     209             : 
     210          44 :   void Clear() {
     211          44 :     mData.Clear();
     212          44 :   }
     213             : 
     214             :   // Our DOM wrappers have direct access to our mData, so they directly
     215             :   // manipulate it rather than us implementing:
     216             :   //
     217             :   // * InsertItem(uint32_t aDataIndex, uint32_t aType, const float *aArgs);
     218             :   // * ReplaceItem(uint32_t aDataIndex, uint32_t aType, const float *aArgs);
     219             :   // * RemoveItem(uint32_t aDataIndex);
     220             :   // * bool AppendItem(uint32_t aType, const float *aArgs);
     221             : 
     222             :   nsresult AppendSeg(uint32_t aType, ...); // variable number of float args
     223             : 
     224           0 :   iterator begin() { return mData.Elements(); }
     225           0 :   iterator end() { return mData.Elements() + mData.Length(); }
     226             : 
     227             :   FallibleTArray<float> mData;
     228             : };
     229             : 
     230             : 
     231             : /**
     232             :  * This SVGPathData subclass is for SVGPathSegListSMILType which needs to
     233             :  * have write access to the lists it works with.
     234             :  *
     235             :  * Instances of this class do not have DOM wrappers that need to be kept in
     236             :  * sync, so we can safely expose any protected base class methods required by
     237             :  * the SMIL code.
     238             :  */
     239           0 : class SVGPathDataAndInfo final : public SVGPathData
     240             : {
     241             : public:
     242           0 :   explicit SVGPathDataAndInfo(nsSVGElement *aElement = nullptr)
     243           0 :     : mElement(do_GetWeakReference(static_cast<nsINode*>(aElement)))
     244           0 :   {}
     245             : 
     246           0 :   void SetElement(nsSVGElement *aElement) {
     247           0 :     mElement = do_GetWeakReference(static_cast<nsINode*>(aElement));
     248           0 :   }
     249             : 
     250           0 :   nsSVGElement* Element() const {
     251           0 :     nsCOMPtr<nsIContent> e = do_QueryReferent(mElement);
     252           0 :     return static_cast<nsSVGElement*>(e.get());
     253             :   }
     254             : 
     255           0 :   nsresult CopyFrom(const SVGPathDataAndInfo& rhs) {
     256           0 :     mElement = rhs.mElement;
     257           0 :     return SVGPathData::CopyFrom(rhs);
     258             :   }
     259             : 
     260             :   /**
     261             :    * Returns true if this object is an "identity" value, from the perspective
     262             :    * of SMIL. In other words, returns true until the initial value set up in
     263             :    * SVGPathSegListSMILType::Init() has been changed with a SetElement() call.
     264             :    */
     265           0 :   bool IsIdentity() const {
     266           0 :     if (!mElement) {
     267           0 :       MOZ_ASSERT(IsEmpty(), "target element propagation failure");
     268           0 :       return true;
     269             :     }
     270           0 :     return false;
     271             :   }
     272             : 
     273             :   /**
     274             :    * Exposed so that SVGPathData baseVals can be copied to
     275             :    * SVGPathDataAndInfo objects. Note that callers should also call
     276             :    * SetElement() when using this method!
     277             :    */
     278             :   using SVGPathData::CopyFrom;
     279             : 
     280             :   // Exposed since SVGPathData objects can be modified.
     281             :   using SVGPathData::iterator;
     282             :   using SVGPathData::operator[];
     283             :   using SVGPathData::SetLength;
     284             :   using SVGPathData::begin;
     285             :   using SVGPathData::end;
     286             : 
     287             : private:
     288             :   // We must keep a weak reference to our element because we may belong to a
     289             :   // cached baseVal nsSMILValue. See the comments starting at:
     290             :   // https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15
     291             :   // See also https://bugzilla.mozilla.org/show_bug.cgi?id=653497
     292             :   nsWeakPtr mElement;
     293             : };
     294             : 
     295             : } // namespace mozilla
     296             : 
     297             : #endif // MOZILLA_SVGPATHDATA_H__

Generated by: LCOV version 1.13