layout/base/FramePropertyTable.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifndef FRAMEPROPERTYTABLE_H_
michael@0 7 #define FRAMEPROPERTYTABLE_H_
michael@0 8
michael@0 9 #include "mozilla/MemoryReporting.h"
michael@0 10 #include "nsTArray.h"
michael@0 11 #include "nsTHashtable.h"
michael@0 12 #include "nsHashKeys.h"
michael@0 13
michael@0 14 class nsIFrame;
michael@0 15
michael@0 16 namespace mozilla {
michael@0 17
michael@0 18 struct FramePropertyDescriptor;
michael@0 19
michael@0 20 typedef void (*FramePropertyDestructor)(void* aPropertyValue);
michael@0 21 typedef void (*FramePropertyDestructorWithFrame)(nsIFrame* aFrame,
michael@0 22 void* aPropertyValue);
michael@0 23
michael@0 24 /**
michael@0 25 * A pointer to a FramePropertyDescriptor serves as a unique property ID.
michael@0 26 * The FramePropertyDescriptor stores metadata about the property.
michael@0 27 * Currently the only metadata is a destructor function. The destructor
michael@0 28 * function is called on property values when they are overwritten or
michael@0 29 * deleted.
michael@0 30 *
michael@0 31 * To use this class, declare a global (i.e., file, class or function-scope
michael@0 32 * static member) FramePropertyDescriptor and pass its address as
michael@0 33 * aProperty in the FramePropertyTable methods.
michael@0 34 */
michael@0 35 struct FramePropertyDescriptor {
michael@0 36 /**
michael@0 37 * mDestructor will be called if it's non-null.
michael@0 38 */
michael@0 39 FramePropertyDestructor mDestructor;
michael@0 40 /**
michael@0 41 * mDestructorWithFrame will be called if it's non-null and mDestructor
michael@0 42 * is null. WARNING: The frame passed to mDestructorWithFrame may
michael@0 43 * be a dangling frame pointer, if this is being called during
michael@0 44 * presshell teardown. Do not use it except to compare against
michael@0 45 * other frame pointers. No frame will have been allocated with
michael@0 46 * the same address yet.
michael@0 47 */
michael@0 48 FramePropertyDestructorWithFrame mDestructorWithFrame;
michael@0 49 /**
michael@0 50 * mDestructor and mDestructorWithFrame may both be null, in which case
michael@0 51 * no value destruction is a no-op.
michael@0 52 */
michael@0 53 };
michael@0 54
michael@0 55 /**
michael@0 56 * The FramePropertyTable is optimized for storing 0 or 1 properties on
michael@0 57 * a given frame. Storing very large numbers of properties on a single
michael@0 58 * frame will not be efficient.
michael@0 59 *
michael@0 60 * Property values are passed as void* but do not actually have to be
michael@0 61 * valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to
michael@0 62 * store int32_t values. Null/zero values can be stored and retrieved.
michael@0 63 * Of course, the destructor function (if any) must handle such values
michael@0 64 * correctly.
michael@0 65 */
michael@0 66 class FramePropertyTable {
michael@0 67 public:
michael@0 68 FramePropertyTable() : mLastFrame(nullptr), mLastEntry(nullptr)
michael@0 69 {
michael@0 70 }
michael@0 71 ~FramePropertyTable()
michael@0 72 {
michael@0 73 DeleteAll();
michael@0 74 }
michael@0 75
michael@0 76 /**
michael@0 77 * Set a property value on a frame. This requires one hashtable
michael@0 78 * lookup (using the frame as the key) and a linear search through
michael@0 79 * the properties of that frame. Any existing value for the property
michael@0 80 * is destroyed.
michael@0 81 */
michael@0 82 void Set(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty,
michael@0 83 void* aValue);
michael@0 84 /**
michael@0 85 * Get a property value for a frame. This requires one hashtable
michael@0 86 * lookup (using the frame as the key) and a linear search through
michael@0 87 * the properties of that frame. If the frame has no such property,
michael@0 88 * returns null.
michael@0 89 * @param aFoundResult if non-null, receives a value 'true' iff
michael@0 90 * the frame has a value for the property. This lets callers
michael@0 91 * disambiguate a null result, which can mean 'no such property' or
michael@0 92 * 'property value is null'.
michael@0 93 */
michael@0 94 void* Get(const nsIFrame* aFrame, const FramePropertyDescriptor* aProperty,
michael@0 95 bool* aFoundResult = nullptr);
michael@0 96 /**
michael@0 97 * Remove a property value for a frame. This requires one hashtable
michael@0 98 * lookup (using the frame as the key) and a linear search through
michael@0 99 * the properties of that frame. The old property value is returned
michael@0 100 * (and not destroyed). If the frame has no such property,
michael@0 101 * returns null.
michael@0 102 * @param aFoundResult if non-null, receives a value 'true' iff
michael@0 103 * the frame had a value for the property. This lets callers
michael@0 104 * disambiguate a null result, which can mean 'no such property' or
michael@0 105 * 'property value is null'.
michael@0 106 */
michael@0 107 void* Remove(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty,
michael@0 108 bool* aFoundResult = nullptr);
michael@0 109 /**
michael@0 110 * Remove and destroy a property value for a frame. This requires one
michael@0 111 * hashtable lookup (using the frame as the key) and a linear search
michael@0 112 * through the properties of that frame. If the frame has no such
michael@0 113 * property, nothing happens.
michael@0 114 */
michael@0 115 void Delete(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty);
michael@0 116 /**
michael@0 117 * Remove and destroy all property values for a frame. This requires one
michael@0 118 * hashtable lookup (using the frame as the key).
michael@0 119 */
michael@0 120 void DeleteAllFor(nsIFrame* aFrame);
michael@0 121 /**
michael@0 122 * Remove and destroy all property values for all frames.
michael@0 123 */
michael@0 124 void DeleteAll();
michael@0 125
michael@0 126 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
michael@0 127
michael@0 128 protected:
michael@0 129 /**
michael@0 130 * Stores a property descriptor/value pair. It can also be used to
michael@0 131 * store an nsTArray of PropertyValues.
michael@0 132 */
michael@0 133 struct PropertyValue {
michael@0 134 PropertyValue() : mProperty(nullptr), mValue(nullptr) {}
michael@0 135 PropertyValue(const FramePropertyDescriptor* aProperty, void* aValue)
michael@0 136 : mProperty(aProperty), mValue(aValue) {}
michael@0 137
michael@0 138 bool IsArray() { return !mProperty && mValue; }
michael@0 139 nsTArray<PropertyValue>* ToArray()
michael@0 140 {
michael@0 141 NS_ASSERTION(IsArray(), "Must be array");
michael@0 142 return reinterpret_cast<nsTArray<PropertyValue>*>(&mValue);
michael@0 143 }
michael@0 144
michael@0 145 void DestroyValueFor(nsIFrame* aFrame) {
michael@0 146 if (mProperty->mDestructor) {
michael@0 147 mProperty->mDestructor(mValue);
michael@0 148 } else if (mProperty->mDestructorWithFrame) {
michael@0 149 mProperty->mDestructorWithFrame(aFrame, mValue);
michael@0 150 }
michael@0 151 }
michael@0 152
michael@0 153 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
michael@0 154 size_t n = 0;
michael@0 155 // We don't need to measure mProperty because it always points to static
michael@0 156 // memory. As for mValue: if it's a single value we can't measure it,
michael@0 157 // because the type is opaque; if it's an array, we measure the array
michael@0 158 // storage, but we can't measure the individual values, again because
michael@0 159 // their types are opaque.
michael@0 160 if (IsArray()) {
michael@0 161 nsTArray<PropertyValue>* array = ToArray();
michael@0 162 n += array->SizeOfExcludingThis(aMallocSizeOf);
michael@0 163 }
michael@0 164 return n;
michael@0 165 }
michael@0 166
michael@0 167 const FramePropertyDescriptor* mProperty;
michael@0 168 void* mValue;
michael@0 169 };
michael@0 170
michael@0 171 /**
michael@0 172 * Used with an array of PropertyValues to allow lookups that compare
michael@0 173 * only on the FramePropertyDescriptor.
michael@0 174 */
michael@0 175 class PropertyComparator {
michael@0 176 public:
michael@0 177 bool Equals(const PropertyValue& a, const PropertyValue& b) const {
michael@0 178 return a.mProperty == b.mProperty;
michael@0 179 }
michael@0 180 bool Equals(const FramePropertyDescriptor* a, const PropertyValue& b) const {
michael@0 181 return a == b.mProperty;
michael@0 182 }
michael@0 183 bool Equals(const PropertyValue& a, const FramePropertyDescriptor* b) const {
michael@0 184 return a.mProperty == b;
michael@0 185 }
michael@0 186 };
michael@0 187
michael@0 188 /**
michael@0 189 * Our hashtable entry. The key is an nsIFrame*, the value is a
michael@0 190 * PropertyValue representing one or more property/value pairs.
michael@0 191 */
michael@0 192 class Entry : public nsPtrHashKey<nsIFrame>
michael@0 193 {
michael@0 194 public:
michael@0 195 Entry(KeyTypePointer aKey) : nsPtrHashKey<nsIFrame>(aKey) {}
michael@0 196 Entry(const Entry &toCopy) :
michael@0 197 nsPtrHashKey<nsIFrame>(toCopy), mProp(toCopy.mProp) {}
michael@0 198
michael@0 199 PropertyValue mProp;
michael@0 200 };
michael@0 201
michael@0 202 static void DeleteAllForEntry(Entry* aEntry);
michael@0 203 static PLDHashOperator DeleteEnumerator(Entry* aEntry, void* aArg);
michael@0 204
michael@0 205 static size_t SizeOfPropertyTableEntryExcludingThis(Entry* aEntry,
michael@0 206 mozilla::MallocSizeOf aMallocSizeOf, void *);
michael@0 207
michael@0 208 nsTHashtable<Entry> mEntries;
michael@0 209 nsIFrame* mLastFrame;
michael@0 210 Entry* mLastEntry;
michael@0 211 };
michael@0 212
michael@0 213 /**
michael@0 214 * This class encapsulates the properties of a frame.
michael@0 215 */
michael@0 216 class FrameProperties {
michael@0 217 public:
michael@0 218 FrameProperties(FramePropertyTable* aTable, nsIFrame* aFrame)
michael@0 219 : mTable(aTable), mFrame(aFrame) {}
michael@0 220 FrameProperties(FramePropertyTable* aTable, const nsIFrame* aFrame)
michael@0 221 : mTable(aTable), mFrame(const_cast<nsIFrame*>(aFrame)) {}
michael@0 222
michael@0 223 void Set(const FramePropertyDescriptor* aProperty, void* aValue) const
michael@0 224 {
michael@0 225 mTable->Set(mFrame, aProperty, aValue);
michael@0 226 }
michael@0 227 void* Get(const FramePropertyDescriptor* aProperty,
michael@0 228 bool* aFoundResult = nullptr) const
michael@0 229 {
michael@0 230 return mTable->Get(mFrame, aProperty, aFoundResult);
michael@0 231 }
michael@0 232 void* Remove(const FramePropertyDescriptor* aProperty,
michael@0 233 bool* aFoundResult = nullptr) const
michael@0 234 {
michael@0 235 return mTable->Remove(mFrame, aProperty, aFoundResult);
michael@0 236 }
michael@0 237 void Delete(const FramePropertyDescriptor* aProperty)
michael@0 238 {
michael@0 239 mTable->Delete(mFrame, aProperty);
michael@0 240 }
michael@0 241
michael@0 242 private:
michael@0 243 FramePropertyTable* mTable;
michael@0 244 nsIFrame* mFrame;
michael@0 245 };
michael@0 246
michael@0 247 }
michael@0 248
michael@0 249 #endif /* FRAMEPROPERTYTABLE_H_ */

mercurial