LCOV - code coverage report
Current view: top level - dom/svg - DOMSVGAnimatedLengthList.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 7 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 8 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_DOMSVGANIMATEDLENGTHLIST_H__
       8             : #define MOZILLA_DOMSVGANIMATEDLENGTHLIST_H__
       9             : 
      10             : #include "nsCOMPtr.h"
      11             : #include "nsCycleCollectionParticipant.h"
      12             : #include "nsSVGElement.h"
      13             : #include "mozilla/Attributes.h"
      14             : 
      15             : namespace mozilla {
      16             : 
      17             : class SVGAnimatedLengthList;
      18             : class SVGLengthList;
      19             : class DOMSVGLengthList;
      20             : 
      21             : /**
      22             :  * Class DOMSVGAnimatedLengthList
      23             :  *
      24             :  * This class is used to create the DOM tearoff objects that wrap internal
      25             :  * SVGAnimatedLengthList objects. We have this internal-DOM split because DOM
      26             :  * classes are relatively heavy-weight objects with non-optimal interfaces for
      27             :  * internal code, and they're relatively infrequently used. Having separate
      28             :  * internal and DOM classes does add complexity - especially for lists where
      29             :  * the internal list and DOM lists (and their items) need to be kept in sync -
      30             :  * but it keeps the internal classes light and fast, and in 99% of cases
      31             :  * they're all that's used. DOM wrappers are only instantiated when script
      32             :  * demands it.
      33             :  *
      34             :  * Ownership model:
      35             :  *
      36             :  * The diagram below shows the ownership model between the various DOM objects
      37             :  * in the tree of DOM objects that correspond to an SVG length list attribute.
      38             :  * The angled brackets ">" and "<" denote a reference from one object to
      39             :  * another, where the "!" character denotes a strong reference, and the "~"
      40             :  * character denotes a weak reference.
      41             :  *
      42             :  *      .----<!----.                .----<!----.        .----<!----.
      43             :  *      |          |                |          |        |          |
      44             :  *   element ~> DOMSVGAnimatedLengthList ~> DOMSVGLengthList ~> DOMSVGLength
      45             :  *
      46             :  * Rationale:
      47             :  *
      48             :  * The following three paragraphs explain the main three requirements that must
      49             :  * be met by any design. These are followed by an explanation of the rationale
      50             :  * behind our particular design.
      51             :  *
      52             :  * 1: DOMSVGAnimatedLengthList, DOMSVGLengthLists and DOMSVGLength get to their
      53             :  * internal counterparts via their element, and they use their element to send
      54             :  * out appropriate notifications when they change. Because of this, having
      55             :  * their element disappear out from under them would be very bad. To keep their
      56             :  * element alive at least as long as themselves, each of these classes must
      57             :  * contain a _strong_ reference (directly or indirectly) to their element.
      58             :  *
      59             :  * 2: Another central requirement of any design is the SVG specification's
      60             :  * requirement that script must always be given the exact same objects each
      61             :  * time it accesses a given object in a DOM object tree corresponding to an SVG
      62             :  * length list attribute. In practice "always" actually means "whenever script
      63             :  * has kept a references to a DOM object it previously accessed", since a
      64             :  * script will only be able to detect any difference in object identity if it
      65             :  * has a previous reference to compare against.
      66             :  *
      67             :  * 3: The wiggle room in the "same object" requirement leads us to a third
      68             :  * (self imposed) requirement: if script no longer has a reference to a given
      69             :  * DOM object from an object tree corresponding to an SVG length list
      70             :  * attribute, and if that object doesn't currently have any descendants, then
      71             :  * that object should be released to free up memory.
      72             :  *
      73             :  * To help in understanding our current design, consider this BROKEN design:
      74             :  *
      75             :  *      .-------------------------------<!-------------------------.
      76             :  *      |--------------------<!----------------.                   |
      77             :  *      |----<!----.                           |                   |
      78             :  *      |          |                           |                   |
      79             :  *   element ~> DOMSVGAnimatedLengthList !> DOMSVGLengthList !> DOMSVGLength
      80             :  *
      81             :  * Having all the objects keep a reference directly to their element like this
      82             :  * would reduce the number of dereferences that they need to make to get their
      83             :  * internal counterpart. Hovewer, this design does not meet the "same object"
      84             :  * requirement of the SVG specification. If script keeps a reference to a
      85             :  * DOMSVGLength or DOMSVGLengthList object, but not to that object's
      86             :  * DOMSVGAnimatedLengthList, then the DOMSVGAnimatedLengthList may be garbage
      87             :  * collected. We'd then have no way to return the same DOMSVGLength /
      88             :  * DOMSVGLengthList object that the script has a reference to if the script
      89             :  * went looking for it via the DOMSVGAnimatedLengthList property on the
      90             :  * element - we'd end up creating a fresh DOMSVGAnimatedLengthList, with no
      91             :  * knowlegde of the existing DOMSVGLengthList or DOMSVGLength object.
      92             :  *
      93             :  * The way we solve this problem is by making sure that parent objects cannot
      94             :  * die until all their children are dead by having child objects hold a strong
      95             :  * reference to their parent object. Note that this design means that the child
      96             :  * objects hold a strong reference to their element too, albeit indirectly via
      97             :  * the strong reference to their parent object:
      98             :  *
      99             :  *      .----<!----.                .----<!----.        .----<!----.
     100             :  *      |          |                |          |        |          |
     101             :  *   element ~> DOMSVGAnimatedLengthList ~> DOMSVGLengthList ~> DOMSVGLength
     102             :  *
     103             :  * One drawback of this design is that objects must look up their parent
     104             :  * chain to find their element, but that overhead is relatively small.
     105             :  */
     106             : class DOMSVGAnimatedLengthList final : public nsWrapperCache
     107             : {
     108             :   friend class DOMSVGLengthList;
     109             : 
     110             : public:
     111           0 :   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMSVGAnimatedLengthList)
     112           0 :   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMSVGAnimatedLengthList)
     113             : 
     114             :   /**
     115             :    * Factory method to create and return a DOMSVGAnimatedLengthList wrapper
     116             :    * for a given internal SVGAnimatedLengthList object. The factory takes care
     117             :    * of caching the object that it returns so that the same object can be
     118             :    * returned for the given SVGAnimatedLengthList each time it is requested.
     119             :    * The cached object is only removed from the cache when it is destroyed due
     120             :    * to there being no more references to it or to any of its descendant
     121             :    * objects. If that happens, any subsequent call requesting the DOM wrapper
     122             :    * for the SVGAnimatedLengthList will naturally result in a new
     123             :    * DOMSVGAnimatedLengthList being returned.
     124             :    */
     125             :   static already_AddRefed<DOMSVGAnimatedLengthList>
     126             :     GetDOMWrapper(SVGAnimatedLengthList *aList,
     127             :                   nsSVGElement *aElement,
     128             :                   uint8_t aAttrEnum,
     129             :                   uint8_t aAxis);
     130             : 
     131             :   /**
     132             :    * This method returns the DOMSVGAnimatedLengthList wrapper for an internal
     133             :    * SVGAnimatedLengthList object if it currently has a wrapper. If it does
     134             :    * not, then nullptr is returned.
     135             :    */
     136             :   static DOMSVGAnimatedLengthList*
     137             :     GetDOMWrapperIfExists(SVGAnimatedLengthList *aList);
     138             : 
     139             :   /**
     140             :    * Called by internal code to notify us when we need to sync the length of
     141             :    * our baseVal DOM list with its internal list. This is called just prior to
     142             :    * the length of the internal baseVal list being changed so that any DOM list
     143             :    * items that need to be removed from the DOM list can first get their values
     144             :    * from their internal counterpart.
     145             :    *
     146             :    * The only time this method could fail is on OOM when trying to increase the
     147             :    * length of the DOM list. If that happens then this method simply clears the
     148             :    * list and returns. Callers just proceed as normal, and we simply accept
     149             :    * that the DOM list will be empty (until successfully set to a new value).
     150             :    */
     151             :   void InternalBaseValListWillChangeTo(const SVGLengthList& aNewValue);
     152             :   void InternalAnimValListWillChangeTo(const SVGLengthList& aNewValue);
     153             : 
     154             :   /**
     155             :    * Returns true if our attribute is animating (in which case our animVal is
     156             :    * not simply a mirror of our baseVal).
     157             :    */
     158             :   bool IsAnimating() const;
     159             : 
     160             :   // WebIDL
     161           0 :   nsSVGElement* GetParentObject() const { return mElement; }
     162             :   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
     163             :   // These aren't weak refs because mBaseVal and mAnimVal are weak
     164             :   already_AddRefed<DOMSVGLengthList> BaseVal();
     165             :   already_AddRefed<DOMSVGLengthList> AnimVal();
     166             : 
     167             : private:
     168             : 
     169             :   /**
     170             :    * Only our static GetDOMWrapper() factory method may create objects of our
     171             :    * type.
     172             :    */
     173           0 :   DOMSVGAnimatedLengthList(nsSVGElement *aElement, uint8_t aAttrEnum, uint8_t aAxis)
     174           0 :     : mBaseVal(nullptr)
     175             :     , mAnimVal(nullptr)
     176             :     , mElement(aElement)
     177             :     , mAttrEnum(aAttrEnum)
     178           0 :     , mAxis(aAxis)
     179             :   {
     180           0 :   }
     181             : 
     182             :   ~DOMSVGAnimatedLengthList();
     183             : 
     184             :   /// Get a reference to this DOM wrapper object's internal counterpart.
     185             :   SVGAnimatedLengthList& InternalAList();
     186             :   const SVGAnimatedLengthList& InternalAList() const;
     187             : 
     188             :   // Weak refs to our DOMSVGLengthList baseVal/animVal objects. These objects
     189             :   // are friends and take care of clearing these pointers when they die, making
     190             :   // these true weak references.
     191             :   DOMSVGLengthList *mBaseVal;
     192             :   DOMSVGLengthList *mAnimVal;
     193             : 
     194             :   // Strong ref to our element to keep it alive. We hold this not only for
     195             :   // ourself, but also for our base/animVal and all of their items.
     196             :   RefPtr<nsSVGElement> mElement;
     197             : 
     198             :   uint8_t mAttrEnum;
     199             :   uint8_t mAxis;
     200             : };
     201             : 
     202             : } // namespace mozilla
     203             : 
     204             : #endif // MOZILLA_DOMSVGANIMATEDLENGTHLIST_H__

Generated by: LCOV version 1.13