LCOV - code coverage report
Current view: top level - layout/base - FrameProperties.h (source / functions) Hit Total Coverage
Test: output.info Lines: 105 110 95.5 %
Date: 2017-07-14 16:53:18 Functions: 119 321 37.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #ifndef FRAMEPROPERTIES_H_
       7             : #define FRAMEPROPERTIES_H_
       8             : 
       9             : #include "mozilla/DebugOnly.h"
      10             : #include "mozilla/MemoryReporting.h"
      11             : #include "mozilla/TypeTraits.h"
      12             : #include "mozilla/Unused.h"
      13             : #include "nsTArray.h"
      14             : #include "nsThreadUtils.h"
      15             : 
      16             : class nsIFrame;
      17             : 
      18             : namespace mozilla {
      19             : 
      20             : struct FramePropertyDescriptorUntyped
      21             : {
      22             :   /**
      23             :    * mDestructor will be called if it's non-null.
      24             :    */
      25             :   typedef void UntypedDestructor(void* aPropertyValue);
      26             :   UntypedDestructor* mDestructor;
      27             :   /**
      28             :    * mDestructorWithFrame will be called if it's non-null and mDestructor
      29             :    * is null. WARNING: The frame passed to mDestructorWithFrame may
      30             :    * be a dangling frame pointer, if this is being called during
      31             :    * presshell teardown. Do not use it except to compare against
      32             :    * other frame pointers. No frame will have been allocated with
      33             :    * the same address yet.
      34             :    */
      35             :   typedef void UntypedDestructorWithFrame(const nsIFrame* aFrame,
      36             :                                           void* aPropertyValue);
      37             :   UntypedDestructorWithFrame* mDestructorWithFrame;
      38             :   /**
      39             :    * mDestructor and mDestructorWithFrame may both be null, in which case
      40             :    * no value destruction is a no-op.
      41             :    */
      42             : 
      43             : protected:
      44             :   /**
      45             :    * At most one destructor should be passed in. In general, you should
      46             :    * just use the static function FramePropertyDescriptor::New* below
      47             :    * instead of using this constructor directly.
      48             :    */
      49             :   constexpr FramePropertyDescriptorUntyped(
      50             :     UntypedDestructor* aDtor, UntypedDestructorWithFrame* aDtorWithFrame)
      51             :     : mDestructor(aDtor)
      52             :     , mDestructorWithFrame(aDtorWithFrame)
      53             :   {}
      54             : };
      55             : 
      56             : /**
      57             :  * A pointer to a FramePropertyDescriptor serves as a unique property ID.
      58             :  * The FramePropertyDescriptor stores metadata about the property.
      59             :  * Currently the only metadata is a destructor function. The destructor
      60             :  * function is called on property values when they are overwritten or
      61             :  * deleted.
      62             :  *
      63             :  * To use this class, declare a global (i.e., file, class or function-scope
      64             :  * static member) FramePropertyDescriptor and pass its address as
      65             :  * aProperty in the FrameProperties methods.
      66             :  */
      67             : template<typename T>
      68             : struct FramePropertyDescriptor : public FramePropertyDescriptorUntyped
      69             : {
      70             :   typedef void Destructor(T* aPropertyValue);
      71             :   typedef void DestructorWithFrame(const nsIFrame* aaFrame,
      72             :                                    T* aPropertyValue);
      73             : 
      74             :   template<Destructor Dtor>
      75             :   static constexpr const FramePropertyDescriptor<T> NewWithDestructor()
      76             :   {
      77             :     return { Destruct<Dtor>, nullptr };
      78             :   }
      79             : 
      80             :   template<DestructorWithFrame Dtor>
      81             :   static constexpr
      82             :   const FramePropertyDescriptor<T> NewWithDestructorWithFrame()
      83             :   {
      84             :     return { nullptr, DestructWithFrame<Dtor> };
      85             :   }
      86             : 
      87             :   static constexpr const FramePropertyDescriptor<T> NewWithoutDestructor()
      88             :   {
      89             :     return { nullptr, nullptr };
      90             :   }
      91             : 
      92             : private:
      93             :   constexpr FramePropertyDescriptor(
      94             :     UntypedDestructor* aDtor, UntypedDestructorWithFrame* aDtorWithFrame)
      95             :     : FramePropertyDescriptorUntyped(aDtor, aDtorWithFrame)
      96             :   {}
      97             : 
      98             :   template<Destructor Dtor>
      99         180 :   static void Destruct(void* aPropertyValue)
     100             :   {
     101         180 :     Dtor(static_cast<T*>(aPropertyValue));
     102         180 :   }
     103             : 
     104             :   template<DestructorWithFrame Dtor>
     105             :   static void DestructWithFrame(const nsIFrame* aFrame, void* aPropertyValue)
     106             :   {
     107             :     Dtor(aFrame, static_cast<T*>(aPropertyValue));
     108             :   }
     109             : };
     110             : 
     111             : // SmallValueHolder<T> is a placeholder intended to be used as template
     112             : // argument of FramePropertyDescriptor for types which can fit into the
     113             : // size of a pointer directly. This class should never be defined, so
     114             : // that we won't use it for unexpected purpose by mistake.
     115             : template<typename T>
     116             : class SmallValueHolder;
     117             : 
     118             : namespace detail {
     119             : 
     120             : template<typename T>
     121             : struct FramePropertyTypeHelper
     122             : {
     123             :   typedef T* Type;
     124             : };
     125             : template<typename T>
     126             : struct FramePropertyTypeHelper<SmallValueHolder<T>>
     127             : {
     128             :   typedef T Type;
     129             : };
     130             : 
     131             : }
     132             : 
     133             : /**
     134             :  * The FrameProperties class is optimized for storing 0 or 1 properties on
     135             :  * a given frame. Storing very large numbers of properties on a single
     136             :  * frame will not be efficient.
     137             :  *
     138             :  * Property values are passed as void* but do not actually have to be
     139             :  * valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to
     140             :  * store int32_t values. Null/zero values can be stored and retrieved.
     141             :  * Of course, the destructor function (if any) must handle such values
     142             :  * correctly.
     143             :  */
     144             : class FrameProperties
     145             : {
     146             : public:
     147             :   template<typename T>
     148             :   using Descriptor = const FramePropertyDescriptor<T>*;
     149             :   using UntypedDescriptor = const FramePropertyDescriptorUntyped*;
     150             : 
     151             :   template<typename T>
     152             :   using PropertyType = typename detail::FramePropertyTypeHelper<T>::Type;
     153             : 
     154         666 :   explicit FrameProperties()
     155         666 :   {
     156         666 :   }
     157             : 
     158         126 :   ~FrameProperties()
     159         126 :   {
     160         126 :     MOZ_ASSERT(mProperties.Length() == 0, "forgot to delete properties");
     161         126 :   }
     162             : 
     163             :   /**
     164             :    * Return true if we have no properties, otherwise return false.
     165             :    */
     166          76 :   bool IsEmpty() const { return mProperties.IsEmpty(); }
     167             : 
     168             :   /**
     169             :    * Set a property value. This requires a linear search through
     170             :    * the properties of the frame. Any existing value for the property
     171             :    * is destroyed.
     172             :    */
     173             :   template<typename T>
     174         469 :   void Set(Descriptor<T> aProperty, PropertyType<T> aValue,
     175             :            const nsIFrame* aFrame)
     176             :   {
     177         469 :     void* ptr = ReinterpretHelper<T>::ToPointer(aValue);
     178         469 :     SetInternal(aProperty, ptr, aFrame);
     179         469 :   }
     180             : 
     181             :   /**
     182             :    * Add a property value; the descriptor MUST NOT already be present.
     183             :    */
     184             :   template<typename T>
     185         126 :   void Add(Descriptor<T> aProperty, PropertyType<T> aValue)
     186             :   {
     187         126 :     MOZ_ASSERT(!Has(aProperty), "duplicate frame property");
     188         126 :     void* ptr = ReinterpretHelper<T>::ToPointer(aValue);
     189         126 :     AddInternal(aProperty, ptr);
     190         126 :   }
     191             : 
     192             :   /**
     193             :    * @return true if @aProperty is set. This requires a linear search through the
     194             :    * properties of the frame.
     195             :    *
     196             :    * In most cases, this shouldn't be used outside of assertions, because if
     197             :    * you're doing a lookup anyway it would be far more efficient to call Get()
     198             :    * or Remove() and check the aFoundResult outparam to find out whether the
     199             :    * property is set. Legitimate non-assertion uses include:
     200             :    *
     201             :    *   - Checking if a frame property is set in cases where that's all we want
     202             :    *     to know (i.e., we don't intend to read the actual value or remove the
     203             :    *     property).
     204             :    *
     205             :    *   - Calling Has() before Set() in cases where we don't want to overwrite
     206             :    *     an existing value for the frame property.
     207             :    *
     208             :    * The HasSkippingBitCheck variant doesn't test NS_FRAME_HAS_PROPERTIES
     209             :    * on aFrame, so it is safe to call after aFrame has been destroyed as
     210             :    * long as, since that destruction happened, it isn't possible for a
     211             :    * new frame to have been created and the same property added.
     212             :    */
     213             :   template<typename T>
     214         126 :   bool Has(Descriptor<T> aProperty) const
     215             :   {
     216             :     return mProperties.IndexOf(aProperty, 0, PropertyComparator())
     217         126 :            != nsTArray<PropertyValue>::NoIndex;
     218             :   }
     219             : 
     220             :   /**
     221             :    * Get a property value. This requires a linear search through
     222             :    * the properties of the frame. If the frame has no such property,
     223             :    * returns zero-filled result, which means null for pointers and
     224             :    * zero for integers and floating point types.
     225             :    * @param aFoundResult if non-null, receives a value 'true' iff
     226             :    * the frame has a value for the property. This lets callers
     227             :    * disambiguate a null result, which can mean 'no such property' or
     228             :    * 'property value is null'.
     229             :    */
     230             :   template<typename T>
     231       10004 :   PropertyType<T> Get(Descriptor<T> aProperty,
     232             :                       bool* aFoundResult = nullptr) const
     233             :   {
     234       10004 :     void* ptr = GetInternal(aProperty, aFoundResult);
     235       10004 :     return ReinterpretHelper<T>::FromPointer(ptr);
     236             :   }
     237             : 
     238             :   /**
     239             :    * Remove a property value. This requires a linear search through
     240             :    * the properties of the frame. The old property value is returned
     241             :    * (and not destroyed). If the frame has no such property,
     242             :    * returns zero-filled result, which means null for pointers and
     243             :    * zero for integers and floating point types.
     244             :    * @param aFoundResult if non-null, receives a value 'true' iff
     245             :    * the frame had a value for the property. This lets callers
     246             :    * disambiguate a null result, which can mean 'no such property' or
     247             :    * 'property value is null'.
     248             :    */
     249             :   template<typename T>
     250         108 :   PropertyType<T> Remove(Descriptor<T> aProperty,
     251             :                          bool* aFoundResult = nullptr)
     252             :   {
     253         108 :     void* ptr = RemoveInternal(aProperty, aFoundResult);
     254         108 :     return ReinterpretHelper<T>::FromPointer(ptr);
     255             :   }
     256             : 
     257             :   /**
     258             :    * Remove and destroy a property value. This requires a linear search
     259             :    * through the properties of the frame. If the frame has no such
     260             :    * property, nothing happens.
     261             :    */
     262             :   template<typename T>
     263       12412 :   void Delete(Descriptor<T> aProperty, const nsIFrame* aFrame)
     264             :   {
     265       12412 :     DeleteInternal(aProperty, aFrame);
     266       12412 :   }
     267             : 
     268             :   /**
     269             :    * Call @aFunction for each property or until @aFunction returns false.
     270             :    */
     271             :   template<class F>
     272        4844 :   void ForEach(F aFunction) const
     273             :   {
     274             : #ifdef DEBUG
     275        4844 :     size_t len = mProperties.Length();
     276             : #endif
     277        7198 :     for (const auto& prop : mProperties) {
     278        2354 :       bool shouldContinue = aFunction(prop.mProperty, prop.mValue);
     279        2354 :       MOZ_ASSERT(len == mProperties.Length(),
     280             :                  "frame property list was modified by ForEach callback!");
     281        2354 :       if (!shouldContinue) {
     282           0 :         return;
     283             :       }
     284             :     }
     285             :   }
     286             : 
     287             :   /**
     288             :    * Remove and destroy all property values for the frame.
     289             :    */
     290         252 :   void DeleteAll(const nsIFrame* aFrame) {
     291         504 :     mozilla::DebugOnly<size_t> len = mProperties.Length();
     292         290 :     for (auto& prop : mProperties) {
     293          38 :       prop.DestroyValueFor(aFrame);
     294          38 :       MOZ_ASSERT(mProperties.Length() == len);
     295             :     }
     296         252 :     mProperties.Clear();
     297         252 :   }
     298             : 
     299         124 :   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
     300             :     // We currently report only the shallow size of the mProperties array.
     301             :     // As for the PropertyValue entries: we don't need to measure the mProperty
     302             :     // field of because it always points to static memory, and we can't measure
     303             :     // mValue because the type is opaque.
     304             :     // XXX Can we do better, e.g. with a method on the descriptor?
     305         124 :     return mProperties.ShallowSizeOfExcludingThis(aMallocSizeOf);
     306             :   }
     307             : 
     308             : private:
     309             :   // Prevent copying of FrameProperties; we should always return/pass around
     310             :   // references to it, not copies!
     311             :   FrameProperties(const FrameProperties&) = delete;
     312             :   FrameProperties& operator=(const FrameProperties&) = delete;
     313             : 
     314             :   inline void
     315             :   SetInternal(UntypedDescriptor aProperty, void* aValue,
     316             :               const nsIFrame* aFrame);
     317             : 
     318             :   inline void
     319             :   AddInternal(UntypedDescriptor aProperty, void* aValue);
     320             : 
     321             :   inline void*
     322             :   GetInternal(UntypedDescriptor aProperty, bool* aFoundResult) const;
     323             : 
     324             :   inline void*
     325             :   RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult);
     326             : 
     327             :   inline void
     328             :   DeleteInternal(UntypedDescriptor aProperty, const nsIFrame* aFrame);
     329             : 
     330             :   template<typename T>
     331             :   struct ReinterpretHelper
     332             :   {
     333             :     static_assert(sizeof(PropertyType<T>) <= sizeof(void*),
     334             :                   "size of the value must never be larger than a pointer");
     335             : 
     336         595 :     static void* ToPointer(PropertyType<T> aValue)
     337             :     {
     338         595 :       void* ptr = nullptr;
     339         595 :       memcpy(&ptr, &aValue, sizeof(aValue));
     340         595 :       return ptr;
     341             :     }
     342             : 
     343       10112 :     static PropertyType<T> FromPointer(void* aPtr)
     344             :     {
     345             :       PropertyType<T> value;
     346       10112 :       memcpy(&value, &aPtr, sizeof(value));
     347       10112 :       return value;
     348             :     }
     349             :   };
     350             : 
     351             :   template<typename T>
     352             :   struct ReinterpretHelper<T*>
     353             :   {
     354             :     static void* ToPointer(T* aValue)
     355             :     {
     356             :       return static_cast<void*>(aValue);
     357             :     }
     358             : 
     359             :     static T* FromPointer(void* aPtr)
     360             :     {
     361             :       return static_cast<T*>(aPtr);
     362             :     }
     363             :   };
     364             : 
     365             :   /**
     366             :    * Stores a property descriptor/value pair.
     367             :    */
     368             :   struct PropertyValue {
     369             :     PropertyValue() : mProperty(nullptr), mValue(nullptr) {}
     370         486 :     PropertyValue(UntypedDescriptor aProperty, void* aValue)
     371         486 :       : mProperty(aProperty), mValue(aValue) {}
     372             : 
     373         272 :     void DestroyValueFor(const nsIFrame* aFrame) {
     374         272 :       if (mProperty->mDestructor) {
     375         180 :         mProperty->mDestructor(mValue);
     376          92 :       } else if (mProperty->mDestructorWithFrame) {
     377           0 :         mProperty->mDestructorWithFrame(aFrame, mValue);
     378             :       }
     379         272 :     }
     380             : 
     381             :     UntypedDescriptor mProperty;
     382             :     void* mValue;
     383             :   };
     384             : 
     385             :   /**
     386             :    * Used with an array of PropertyValues to allow lookups that compare
     387             :    * only on the FramePropertyDescriptor.
     388             :    */
     389             :   class PropertyComparator {
     390             :   public:
     391             :     bool Equals(const PropertyValue& a, const PropertyValue& b) const {
     392             :       return a.mProperty == b.mProperty;
     393             :     }
     394             :     bool Equals(UntypedDescriptor a, const PropertyValue& b) const {
     395             :       return a == b.mProperty;
     396             :     }
     397       16568 :     bool Equals(const PropertyValue& a, UntypedDescriptor b) const {
     398       16568 :       return a.mProperty == b;
     399             :     }
     400             :   };
     401             : 
     402             :   nsTArray<PropertyValue> mProperties;
     403             : };
     404             : 
     405             : 
     406             : inline void*
     407       10004 : FrameProperties::GetInternal(UntypedDescriptor aProperty,
     408             :                              bool* aFoundResult) const
     409             : {
     410       10004 :   MOZ_ASSERT(aProperty, "Null property?");
     411             : 
     412       10004 :   auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator());
     413       10004 :   if (index == nsTArray<PropertyValue>::NoIndex) {
     414        4672 :     if (aFoundResult) {
     415        1304 :       *aFoundResult = false;
     416             :     }
     417        4672 :     return nullptr;
     418             :   }
     419             : 
     420        5332 :   if (aFoundResult) {
     421           0 :     *aFoundResult = true;
     422             :   }
     423        5332 :   return mProperties.ElementAt(index).mValue;
     424             : }
     425             : 
     426             : inline void
     427         469 : FrameProperties::SetInternal(UntypedDescriptor aProperty, void* aValue,
     428             :                              const nsIFrame* aFrame)
     429             : {
     430         469 :   MOZ_ASSERT(NS_IsMainThread());
     431         469 :   MOZ_ASSERT(aProperty, "Null property?");
     432             : 
     433         469 :   auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator());
     434         469 :   if (index != nsTArray<PropertyValue>::NoIndex) {
     435         109 :     PropertyValue* pv = &mProperties.ElementAt(index);
     436         109 :     pv->DestroyValueFor(aFrame);
     437         109 :     pv->mValue = aValue;
     438         109 :     return;
     439             :   }
     440             : 
     441         360 :   mProperties.AppendElement(PropertyValue(aProperty, aValue));
     442             : }
     443             : 
     444             : inline void
     445         126 : FrameProperties::AddInternal(UntypedDescriptor aProperty, void* aValue)
     446             : {
     447         126 :   MOZ_ASSERT(NS_IsMainThread());
     448         126 :   MOZ_ASSERT(aProperty, "Null property?");
     449             : 
     450         126 :   mProperties.AppendElement(PropertyValue(aProperty, aValue));
     451         126 : }
     452             : 
     453             : inline void*
     454         108 : FrameProperties::RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult)
     455             : {
     456         108 :   MOZ_ASSERT(NS_IsMainThread());
     457         108 :   MOZ_ASSERT(aProperty, "Null property?");
     458             : 
     459         108 :   auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator());
     460         108 :   if (index == nsTArray<PropertyValue>::NoIndex) {
     461         107 :     if (aFoundResult) {
     462           0 :       *aFoundResult = false;
     463             :     }
     464         107 :     return nullptr;
     465             :   }
     466             : 
     467           1 :   if (aFoundResult) {
     468           0 :     *aFoundResult = true;
     469             :   }
     470             : 
     471           1 :   void* result = mProperties.ElementAt(index).mValue;
     472           1 :   mProperties.RemoveElementAt(index);
     473             : 
     474           1 :   return result;
     475             : }
     476             : 
     477             : inline void
     478       12412 : FrameProperties::DeleteInternal(UntypedDescriptor aProperty,
     479             :                                 const nsIFrame* aFrame)
     480             : {
     481       12412 :   MOZ_ASSERT(NS_IsMainThread());
     482       12412 :   MOZ_ASSERT(aProperty, "Null property?");
     483             : 
     484       12412 :   auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator());
     485       12412 :   if (index != nsTArray<PropertyValue>::NoIndex) {
     486         125 :     mProperties.ElementAt(index).DestroyValueFor(aFrame);
     487         125 :     mProperties.RemoveElementAt(index);
     488             :   }
     489       12412 : }
     490             : 
     491             : } // namespace mozilla
     492             : 
     493             : #endif /* FRAMEPROPERTIES_H_ */

Generated by: LCOV version 1.13