LCOV - code coverage report
Current view: top level - dom/svg - SVGLengthList.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 82 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 31 0.0 %
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_SVGLENGTHLIST_H__
       8             : #define MOZILLA_SVGLENGTHLIST_H__
       9             : 
      10             : #include "nsCOMPtr.h"
      11             : #include "nsDebug.h"
      12             : #include "nsIContent.h"
      13             : #include "nsINode.h"
      14             : #include "nsIWeakReferenceUtils.h"
      15             : #include "nsSVGElement.h"
      16             : #include "nsTArray.h"
      17             : #include "SVGLength.h"
      18             : 
      19             : namespace mozilla {
      20             : 
      21             : /**
      22             :  * ATTENTION! WARNING! WATCH OUT!!
      23             :  *
      24             :  * Consumers that modify objects of this type absolutely MUST keep the DOM
      25             :  * wrappers for those lists (if any) in sync!! That's why this class is so
      26             :  * locked down.
      27             :  *
      28             :  * The DOM wrapper class for this class is DOMSVGLengthList.
      29             :  */
      30             : class SVGLengthList
      31             : {
      32             :   friend class SVGAnimatedLengthList;
      33             :   friend class DOMSVGLengthList;
      34             :   friend class DOMSVGLength;
      35             : 
      36             : public:
      37             : 
      38           0 :   SVGLengthList(){}
      39           0 :   ~SVGLengthList(){}
      40             : 
      41             :   // Only methods that don't make/permit modification to this list are public.
      42             :   // Only our friend classes can access methods that may change us.
      43             : 
      44             :   /// This may return an incomplete string on OOM, but that's acceptable.
      45             :   void GetValueAsString(nsAString& aValue) const;
      46             : 
      47           0 :   bool IsEmpty() const {
      48           0 :     return mLengths.IsEmpty();
      49             :   }
      50             : 
      51           0 :   uint32_t Length() const {
      52           0 :     return mLengths.Length();
      53             :   }
      54             : 
      55           0 :   const SVGLength& operator[](uint32_t aIndex) const {
      56           0 :     return mLengths[aIndex];
      57             :   }
      58             : 
      59             :   bool operator==(const SVGLengthList& rhs) const;
      60             : 
      61           0 :   bool SetCapacity(uint32_t size) {
      62           0 :     return mLengths.SetCapacity(size, fallible);
      63             :   }
      64             : 
      65             :   void Compact() {
      66             :     mLengths.Compact();
      67             :   }
      68             : 
      69             :   // Access to methods that can modify objects of this type is deliberately
      70             :   // limited. This is to reduce the chances of someone modifying objects of
      71             :   // this type without taking the necessary steps to keep DOM wrappers in sync.
      72             :   // If you need wider access to these methods, consider adding a method to
      73             :   // SVGAnimatedLengthList and having that class act as an intermediary so it
      74             :   // can take care of keeping DOM wrappers in sync.
      75             : 
      76             : protected:
      77             : 
      78             :   /**
      79             :    * This may fail on OOM if the internal capacity needs to be increased, in
      80             :    * which case the list will be left unmodified.
      81             :    */
      82             :   nsresult CopyFrom(const SVGLengthList& rhs);
      83             : 
      84           0 :   SVGLength& operator[](uint32_t aIndex) {
      85           0 :     return mLengths[aIndex];
      86             :   }
      87             : 
      88             :   /**
      89             :    * This may fail (return false) on OOM if the internal capacity is being
      90             :    * increased, in which case the list will be left unmodified.
      91             :    */
      92           0 :   bool SetLength(uint32_t aNumberOfItems) {
      93           0 :     return mLengths.SetLength(aNumberOfItems, fallible);
      94             :   }
      95             : 
      96             : private:
      97             : 
      98             :   // Marking the following private only serves to show which methods are only
      99             :   // used by our friend classes (as opposed to our subclasses) - it doesn't
     100             :   // really provide additional safety.
     101             : 
     102             :   nsresult SetValueFromString(const nsAString& aValue);
     103             : 
     104           0 :   void Clear() {
     105           0 :     mLengths.Clear();
     106           0 :   }
     107             : 
     108           0 :   bool InsertItem(uint32_t aIndex, const SVGLength &aLength) {
     109           0 :     if (aIndex >= mLengths.Length()) aIndex = mLengths.Length();
     110           0 :     return !!mLengths.InsertElementAt(aIndex, aLength, fallible);
     111             :   }
     112             : 
     113             :   void ReplaceItem(uint32_t aIndex, const SVGLength &aLength) {
     114             :     MOZ_ASSERT(aIndex < mLengths.Length(),
     115             :                "DOM wrapper caller should have raised INDEX_SIZE_ERR");
     116             :     mLengths[aIndex] = aLength;
     117             :   }
     118             : 
     119           0 :   void RemoveItem(uint32_t aIndex) {
     120           0 :     MOZ_ASSERT(aIndex < mLengths.Length(),
     121             :                "DOM wrapper caller should have raised INDEX_SIZE_ERR");
     122           0 :     mLengths.RemoveElementAt(aIndex);
     123           0 :   }
     124             : 
     125           0 :   bool AppendItem(SVGLength aLength) {
     126           0 :     return !!mLengths.AppendElement(aLength, fallible);
     127             :   }
     128             : 
     129             : protected:
     130             : 
     131             :   /* Rationale for using nsTArray<SVGLength> and not nsTArray<SVGLength, 1>:
     132             :    *
     133             :    * It might seem like we should use AutoTArray<SVGLength, 1> instead of
     134             :    * nsTArray<SVGLength>. That would preallocate space for one SVGLength and
     135             :    * avoid an extra memory allocation call in the common case of the 'x'
     136             :    * and 'y' attributes each containing a single length (and the 'dx' and 'dy'
     137             :    * attributes being empty). However, consider this:
     138             :    *
     139             :    * An empty nsTArray uses sizeof(Header*). An AutoTArray<class E,
     140             :    * uint32_t N> on the other hand uses sizeof(Header*) +
     141             :    * (2 * sizeof(uint32_t)) + (N * sizeof(E)), which for one SVGLength is
     142             :    * sizeof(Header*) + 16 bytes.
     143             :    *
     144             :    * Now consider that for text elements we have four length list attributes
     145             :    * (x, y, dx, dy), each of which can have a baseVal and an animVal list. If
     146             :    * we were to go the AutoTArray<SVGLength, 1> route for each of these, we'd
     147             :    * end up using at least 160 bytes for these four attributes alone, even
     148             :    * though we only need storage for two SVGLengths (16 bytes) in the common
     149             :    * case!!
     150             :    *
     151             :    * A compromise might be to template SVGLengthList to allow
     152             :    * SVGAnimatedLengthList to preallocate space for an SVGLength for the
     153             :    * baseVal lists only, and that would cut the space used by the four
     154             :    * attributes to 96 bytes. Taking that even further and templating
     155             :    * SVGAnimatedLengthList too in order to only use nsTArray for 'dx' and 'dy'
     156             :    * would reduce the storage further to 64 bytes. Having different types makes
     157             :    * things more complicated for code that needs to look at the lists though.
     158             :    * In fact it also makes things more complicated when it comes to storing the
     159             :    * lists.
     160             :    *
     161             :    * It may be worth considering using nsAttrValue for length lists instead of
     162             :    * storing them directly on the element.
     163             :    */
     164             :   FallibleTArray<SVGLength> mLengths;
     165             : };
     166             : 
     167             : 
     168             : /**
     169             :  * This SVGLengthList subclass is for SVGLengthListSMILType which needs to know
     170             :  * which element and attribute a length list belongs to so that it can convert
     171             :  * between unit types if necessary.
     172             :  */
     173           0 : class SVGLengthListAndInfo : public SVGLengthList
     174             : {
     175             : public:
     176             : 
     177           0 :   SVGLengthListAndInfo()
     178           0 :     : mElement(nullptr)
     179             :     , mAxis(0)
     180           0 :     , mCanZeroPadList(false)
     181           0 :   {}
     182             : 
     183             :   SVGLengthListAndInfo(nsSVGElement *aElement, uint8_t aAxis, bool aCanZeroPadList)
     184             :     : mElement(do_GetWeakReference(static_cast<nsINode*>(aElement)))
     185             :     , mAxis(aAxis)
     186             :     , mCanZeroPadList(aCanZeroPadList)
     187             :   {}
     188             : 
     189           0 :   void SetInfo(nsSVGElement *aElement, uint8_t aAxis, bool aCanZeroPadList) {
     190           0 :     mElement = do_GetWeakReference(static_cast<nsINode*>(aElement));
     191           0 :     mAxis = aAxis;
     192           0 :     mCanZeroPadList = aCanZeroPadList;
     193           0 :   }
     194             : 
     195           0 :   nsSVGElement* Element() const {
     196           0 :     nsCOMPtr<nsIContent> e = do_QueryReferent(mElement);
     197           0 :     return static_cast<nsSVGElement*>(e.get());
     198             :   }
     199             : 
     200             :   /**
     201             :    * Returns true if this object is an "identity" value, from the perspective
     202             :    * of SMIL. In other words, returns true until the initial value set up in
     203             :    * SVGLengthListSMILType::Init() has been changed with a SetInfo() call.
     204             :    */
     205           0 :   bool IsIdentity() const {
     206           0 :     if (!mElement) {
     207           0 :       MOZ_ASSERT(IsEmpty(), "target element propagation failure");
     208           0 :       return true;
     209             :     }
     210           0 :     return false;
     211             :   }
     212             : 
     213           0 :   uint8_t Axis() const {
     214           0 :     MOZ_ASSERT(mElement, "Axis() isn't valid");
     215           0 :     return mAxis;
     216             :   }
     217             : 
     218             :   /**
     219             :    * The value returned by this function depends on which attribute this object
     220             :    * is for. If appending a list of zeros to the attribute's list would have no
     221             :    * effect on rendering (e.g. the attributes 'dx' and 'dy' on <text>), then
     222             :    * this method will return true. If appending a list of zeros to the
     223             :    * attribute's list could *change* rendering (e.g. the attributes 'x' and 'y'
     224             :    * on <text>), then this method will return false.
     225             :    *
     226             :    * The reason that this method exists is because the SMIL code needs to know
     227             :    * what to do when it's asked to animate between lists of different length.
     228             :    * If this method returns true, then it can zero pad the short list before
     229             :    * carrying out its operations. However, in the case of the 'x' and 'y'
     230             :    * attributes on <text>, zero would mean "zero in the current coordinate
     231             :    * system", whereas we would want to pad shorter lists with the coordinates
     232             :    * at which glyphs would otherwise lie, which is almost certainly not zero!
     233             :    * Animating from/to zeros in this case would produce terrible results.
     234             :    *
     235             :    * Currently SVGLengthListSMILType simply disallows (drops) animation between
     236             :    * lists of different length if it can't zero pad a list. This is to avoid
     237             :    * having some authors create content that depends on undesirable behaviour
     238             :    * (which would make it difficult for us to fix the behavior in future). At
     239             :    * some point it would be nice to implement a callback to allow this code to
     240             :    * determine padding values for lists that can't be zero padded. See
     241             :    * https://bugzilla.mozilla.org/show_bug.cgi?id=573431
     242             :    */
     243           0 :   bool CanZeroPadList() const {
     244             :     //NS_ASSERTION(mElement, "CanZeroPadList() isn't valid");
     245           0 :     return mCanZeroPadList;
     246             :   }
     247             : 
     248             :   // For the SMIL code. See comment in SVGLengthListSMILType::Add().
     249           0 :   void SetCanZeroPadList(bool aCanZeroPadList) {
     250           0 :     mCanZeroPadList = aCanZeroPadList;
     251           0 :   }
     252             : 
     253           0 :   nsresult CopyFrom(const SVGLengthListAndInfo& rhs) {
     254           0 :     mElement = rhs.mElement;
     255           0 :     mAxis = rhs.mAxis;
     256           0 :     mCanZeroPadList = rhs.mCanZeroPadList;
     257           0 :     return SVGLengthList::CopyFrom(rhs);
     258             :   }
     259             : 
     260             :   // Instances of this special subclass do not have DOM wrappers that we need
     261             :   // to worry about keeping in sync, so it's safe to expose any hidden base
     262             :   // class methods required by the SMIL code, as we do below.
     263             : 
     264             :   /**
     265             :    * Exposed so that SVGLengthList baseVals can be copied to
     266             :    * SVGLengthListAndInfo objects. Note that callers should also call
     267             :    * SetInfo() when using this method!
     268             :    */
     269           0 :   nsresult CopyFrom(const SVGLengthList& rhs) {
     270           0 :     return SVGLengthList::CopyFrom(rhs);
     271             :   }
     272           0 :   const SVGLength& operator[](uint32_t aIndex) const {
     273           0 :     return SVGLengthList::operator[](aIndex);
     274             :   }
     275           0 :   SVGLength& operator[](uint32_t aIndex) {
     276           0 :     return SVGLengthList::operator[](aIndex);
     277             :   }
     278           0 :   bool SetLength(uint32_t aNumberOfItems) {
     279           0 :     return SVGLengthList::SetLength(aNumberOfItems);
     280             :   }
     281             : 
     282             : private:
     283             :   // We must keep a weak reference to our element because we may belong to a
     284             :   // cached baseVal nsSMILValue. See the comments starting at:
     285             :   // https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15
     286             :   // See also https://bugzilla.mozilla.org/show_bug.cgi?id=653497
     287             :   nsWeakPtr mElement;
     288             :   uint8_t mAxis;
     289             :   bool mCanZeroPadList;
     290             : };
     291             : 
     292             : 
     293             : /**
     294             :  * This class wraps SVGLengthList objects to allow frame consumers to process
     295             :  * SVGLengthList objects as if they were simply a list of float values in user
     296             :  * units. When consumers request the value at a given index, this class
     297             :  * dynamically converts the corresponding SVGLength from its actual unit and
     298             :  * returns its value in user units.
     299             :  *
     300             :  * Consumers should check that the user unit values returned are finite. Even
     301             :  * if the consumer can guarantee the list's element has a valid viewport
     302             :  * ancestor to resolve percentage units against, and a valid presContext and
     303             :  * styleContext to resolve absolute and em/ex units against, unit conversions
     304             :  * could still overflow. In that case the value returned will be
     305             :  * numeric_limits<float>::quiet_NaN().
     306             :  */
     307             : class MOZ_STACK_CLASS SVGUserUnitList
     308             : {
     309             : public:
     310             : 
     311           0 :   SVGUserUnitList()
     312           0 :     : mList(nullptr)
     313           0 :   {}
     314             : 
     315           0 :   void Init(const SVGLengthList *aList, nsSVGElement *aElement, uint8_t aAxis) {
     316           0 :     mList = aList;
     317           0 :     mElement = aElement;
     318           0 :     mAxis = aAxis;
     319           0 :   }
     320             : 
     321             :   void Clear() {
     322             :     mList = nullptr;
     323             :   }
     324             : 
     325           0 :   bool IsEmpty() const {
     326           0 :     return !mList || mList->IsEmpty();
     327             :   }
     328             : 
     329           0 :   uint32_t Length() const {
     330           0 :     return mList ? mList->Length() : 0;
     331             :   }
     332             : 
     333             :   /// This may return a non-finite value
     334           0 :   float operator[](uint32_t aIndex) const {
     335           0 :     return (*mList)[aIndex].GetValueInUserUnits(mElement, mAxis);
     336             :   }
     337             : 
     338           0 :   bool HasPercentageValueAt(uint32_t aIndex) const {
     339           0 :     const SVGLength& length = (*mList)[aIndex];
     340           0 :     return length.GetUnit() == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE;
     341             :   }
     342             : 
     343             : private:
     344             :   const SVGLengthList *mList;
     345             :   nsSVGElement *mElement;
     346             :   uint8_t mAxis;
     347             : };
     348             : 
     349             : } // namespace mozilla
     350             : 
     351             : #endif // MOZILLA_SVGLENGTHLIST_H__

Generated by: LCOV version 1.13