1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/FramePropertyTable.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,249 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef FRAMEPROPERTYTABLE_H_ 1.10 +#define FRAMEPROPERTYTABLE_H_ 1.11 + 1.12 +#include "mozilla/MemoryReporting.h" 1.13 +#include "nsTArray.h" 1.14 +#include "nsTHashtable.h" 1.15 +#include "nsHashKeys.h" 1.16 + 1.17 +class nsIFrame; 1.18 + 1.19 +namespace mozilla { 1.20 + 1.21 +struct FramePropertyDescriptor; 1.22 + 1.23 +typedef void (*FramePropertyDestructor)(void* aPropertyValue); 1.24 +typedef void (*FramePropertyDestructorWithFrame)(nsIFrame* aFrame, 1.25 + void* aPropertyValue); 1.26 + 1.27 +/** 1.28 + * A pointer to a FramePropertyDescriptor serves as a unique property ID. 1.29 + * The FramePropertyDescriptor stores metadata about the property. 1.30 + * Currently the only metadata is a destructor function. The destructor 1.31 + * function is called on property values when they are overwritten or 1.32 + * deleted. 1.33 + * 1.34 + * To use this class, declare a global (i.e., file, class or function-scope 1.35 + * static member) FramePropertyDescriptor and pass its address as 1.36 + * aProperty in the FramePropertyTable methods. 1.37 + */ 1.38 +struct FramePropertyDescriptor { 1.39 + /** 1.40 + * mDestructor will be called if it's non-null. 1.41 + */ 1.42 + FramePropertyDestructor mDestructor; 1.43 + /** 1.44 + * mDestructorWithFrame will be called if it's non-null and mDestructor 1.45 + * is null. WARNING: The frame passed to mDestructorWithFrame may 1.46 + * be a dangling frame pointer, if this is being called during 1.47 + * presshell teardown. Do not use it except to compare against 1.48 + * other frame pointers. No frame will have been allocated with 1.49 + * the same address yet. 1.50 + */ 1.51 + FramePropertyDestructorWithFrame mDestructorWithFrame; 1.52 + /** 1.53 + * mDestructor and mDestructorWithFrame may both be null, in which case 1.54 + * no value destruction is a no-op. 1.55 + */ 1.56 +}; 1.57 + 1.58 +/** 1.59 + * The FramePropertyTable is optimized for storing 0 or 1 properties on 1.60 + * a given frame. Storing very large numbers of properties on a single 1.61 + * frame will not be efficient. 1.62 + * 1.63 + * Property values are passed as void* but do not actually have to be 1.64 + * valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to 1.65 + * store int32_t values. Null/zero values can be stored and retrieved. 1.66 + * Of course, the destructor function (if any) must handle such values 1.67 + * correctly. 1.68 + */ 1.69 +class FramePropertyTable { 1.70 +public: 1.71 + FramePropertyTable() : mLastFrame(nullptr), mLastEntry(nullptr) 1.72 + { 1.73 + } 1.74 + ~FramePropertyTable() 1.75 + { 1.76 + DeleteAll(); 1.77 + } 1.78 + 1.79 + /** 1.80 + * Set a property value on a frame. This requires one hashtable 1.81 + * lookup (using the frame as the key) and a linear search through 1.82 + * the properties of that frame. Any existing value for the property 1.83 + * is destroyed. 1.84 + */ 1.85 + void Set(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty, 1.86 + void* aValue); 1.87 + /** 1.88 + * Get a property value for a frame. This requires one hashtable 1.89 + * lookup (using the frame as the key) and a linear search through 1.90 + * the properties of that frame. If the frame has no such property, 1.91 + * returns null. 1.92 + * @param aFoundResult if non-null, receives a value 'true' iff 1.93 + * the frame has a value for the property. This lets callers 1.94 + * disambiguate a null result, which can mean 'no such property' or 1.95 + * 'property value is null'. 1.96 + */ 1.97 + void* Get(const nsIFrame* aFrame, const FramePropertyDescriptor* aProperty, 1.98 + bool* aFoundResult = nullptr); 1.99 + /** 1.100 + * Remove a property value for a frame. This requires one hashtable 1.101 + * lookup (using the frame as the key) and a linear search through 1.102 + * the properties of that frame. The old property value is returned 1.103 + * (and not destroyed). If the frame has no such property, 1.104 + * returns null. 1.105 + * @param aFoundResult if non-null, receives a value 'true' iff 1.106 + * the frame had a value for the property. This lets callers 1.107 + * disambiguate a null result, which can mean 'no such property' or 1.108 + * 'property value is null'. 1.109 + */ 1.110 + void* Remove(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty, 1.111 + bool* aFoundResult = nullptr); 1.112 + /** 1.113 + * Remove and destroy a property value for a frame. This requires one 1.114 + * hashtable lookup (using the frame as the key) and a linear search 1.115 + * through the properties of that frame. If the frame has no such 1.116 + * property, nothing happens. 1.117 + */ 1.118 + void Delete(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty); 1.119 + /** 1.120 + * Remove and destroy all property values for a frame. This requires one 1.121 + * hashtable lookup (using the frame as the key). 1.122 + */ 1.123 + void DeleteAllFor(nsIFrame* aFrame); 1.124 + /** 1.125 + * Remove and destroy all property values for all frames. 1.126 + */ 1.127 + void DeleteAll(); 1.128 + 1.129 + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 1.130 + 1.131 +protected: 1.132 + /** 1.133 + * Stores a property descriptor/value pair. It can also be used to 1.134 + * store an nsTArray of PropertyValues. 1.135 + */ 1.136 + struct PropertyValue { 1.137 + PropertyValue() : mProperty(nullptr), mValue(nullptr) {} 1.138 + PropertyValue(const FramePropertyDescriptor* aProperty, void* aValue) 1.139 + : mProperty(aProperty), mValue(aValue) {} 1.140 + 1.141 + bool IsArray() { return !mProperty && mValue; } 1.142 + nsTArray<PropertyValue>* ToArray() 1.143 + { 1.144 + NS_ASSERTION(IsArray(), "Must be array"); 1.145 + return reinterpret_cast<nsTArray<PropertyValue>*>(&mValue); 1.146 + } 1.147 + 1.148 + void DestroyValueFor(nsIFrame* aFrame) { 1.149 + if (mProperty->mDestructor) { 1.150 + mProperty->mDestructor(mValue); 1.151 + } else if (mProperty->mDestructorWithFrame) { 1.152 + mProperty->mDestructorWithFrame(aFrame, mValue); 1.153 + } 1.154 + } 1.155 + 1.156 + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) { 1.157 + size_t n = 0; 1.158 + // We don't need to measure mProperty because it always points to static 1.159 + // memory. As for mValue: if it's a single value we can't measure it, 1.160 + // because the type is opaque; if it's an array, we measure the array 1.161 + // storage, but we can't measure the individual values, again because 1.162 + // their types are opaque. 1.163 + if (IsArray()) { 1.164 + nsTArray<PropertyValue>* array = ToArray(); 1.165 + n += array->SizeOfExcludingThis(aMallocSizeOf); 1.166 + } 1.167 + return n; 1.168 + } 1.169 + 1.170 + const FramePropertyDescriptor* mProperty; 1.171 + void* mValue; 1.172 + }; 1.173 + 1.174 + /** 1.175 + * Used with an array of PropertyValues to allow lookups that compare 1.176 + * only on the FramePropertyDescriptor. 1.177 + */ 1.178 + class PropertyComparator { 1.179 + public: 1.180 + bool Equals(const PropertyValue& a, const PropertyValue& b) const { 1.181 + return a.mProperty == b.mProperty; 1.182 + } 1.183 + bool Equals(const FramePropertyDescriptor* a, const PropertyValue& b) const { 1.184 + return a == b.mProperty; 1.185 + } 1.186 + bool Equals(const PropertyValue& a, const FramePropertyDescriptor* b) const { 1.187 + return a.mProperty == b; 1.188 + } 1.189 + }; 1.190 + 1.191 + /** 1.192 + * Our hashtable entry. The key is an nsIFrame*, the value is a 1.193 + * PropertyValue representing one or more property/value pairs. 1.194 + */ 1.195 + class Entry : public nsPtrHashKey<nsIFrame> 1.196 + { 1.197 + public: 1.198 + Entry(KeyTypePointer aKey) : nsPtrHashKey<nsIFrame>(aKey) {} 1.199 + Entry(const Entry &toCopy) : 1.200 + nsPtrHashKey<nsIFrame>(toCopy), mProp(toCopy.mProp) {} 1.201 + 1.202 + PropertyValue mProp; 1.203 + }; 1.204 + 1.205 + static void DeleteAllForEntry(Entry* aEntry); 1.206 + static PLDHashOperator DeleteEnumerator(Entry* aEntry, void* aArg); 1.207 + 1.208 + static size_t SizeOfPropertyTableEntryExcludingThis(Entry* aEntry, 1.209 + mozilla::MallocSizeOf aMallocSizeOf, void *); 1.210 + 1.211 + nsTHashtable<Entry> mEntries; 1.212 + nsIFrame* mLastFrame; 1.213 + Entry* mLastEntry; 1.214 +}; 1.215 + 1.216 +/** 1.217 + * This class encapsulates the properties of a frame. 1.218 + */ 1.219 +class FrameProperties { 1.220 +public: 1.221 + FrameProperties(FramePropertyTable* aTable, nsIFrame* aFrame) 1.222 + : mTable(aTable), mFrame(aFrame) {} 1.223 + FrameProperties(FramePropertyTable* aTable, const nsIFrame* aFrame) 1.224 + : mTable(aTable), mFrame(const_cast<nsIFrame*>(aFrame)) {} 1.225 + 1.226 + void Set(const FramePropertyDescriptor* aProperty, void* aValue) const 1.227 + { 1.228 + mTable->Set(mFrame, aProperty, aValue); 1.229 + } 1.230 + void* Get(const FramePropertyDescriptor* aProperty, 1.231 + bool* aFoundResult = nullptr) const 1.232 + { 1.233 + return mTable->Get(mFrame, aProperty, aFoundResult); 1.234 + } 1.235 + void* Remove(const FramePropertyDescriptor* aProperty, 1.236 + bool* aFoundResult = nullptr) const 1.237 + { 1.238 + return mTable->Remove(mFrame, aProperty, aFoundResult); 1.239 + } 1.240 + void Delete(const FramePropertyDescriptor* aProperty) 1.241 + { 1.242 + mTable->Delete(mFrame, aProperty); 1.243 + } 1.244 + 1.245 +private: 1.246 + FramePropertyTable* mTable; 1.247 + nsIFrame* mFrame; 1.248 +}; 1.249 + 1.250 +} 1.251 + 1.252 +#endif /* FRAMEPROPERTYTABLE_H_ */