layout/style/nsCSSDataBlock.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 /*
michael@0 7 * compact representation of the property-value pairs within a CSS
michael@0 8 * declaration, and the code for expanding and compacting it
michael@0 9 */
michael@0 10
michael@0 11 #ifndef nsCSSDataBlock_h__
michael@0 12 #define nsCSSDataBlock_h__
michael@0 13
michael@0 14 #include "mozilla/MemoryReporting.h"
michael@0 15 #include "nsCSSProps.h"
michael@0 16 #include "nsCSSPropertySet.h"
michael@0 17 #include "nsCSSValue.h"
michael@0 18 #include "imgRequestProxy.h"
michael@0 19
michael@0 20 struct nsRuleData;
michael@0 21 class nsCSSExpandedDataBlock;
michael@0 22
michael@0 23 namespace mozilla {
michael@0 24 namespace css {
michael@0 25 class Declaration;
michael@0 26 }
michael@0 27 }
michael@0 28
michael@0 29 /**
michael@0 30 * An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of
michael@0 31 * property-value data for a CSS declaration block (which we misname a
michael@0 32 * |css::Declaration|). Mutation is accomplished through
michael@0 33 * |nsCSSExpandedDataBlock| or in some cases via direct slot access.
michael@0 34 */
michael@0 35 class nsCSSCompressedDataBlock {
michael@0 36 private:
michael@0 37 friend class nsCSSExpandedDataBlock;
michael@0 38
michael@0 39 // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock
michael@0 40 // (in |Compress|) can create compressed data blocks.
michael@0 41 nsCSSCompressedDataBlock(uint32_t aNumProps)
michael@0 42 : mStyleBits(0), mNumProps(aNumProps)
michael@0 43 {}
michael@0 44
michael@0 45 public:
michael@0 46 ~nsCSSCompressedDataBlock();
michael@0 47
michael@0 48 /**
michael@0 49 * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style
michael@0 50 * rule using this block for storage.
michael@0 51 */
michael@0 52 void MapRuleInfoInto(nsRuleData *aRuleData) const;
michael@0 53
michael@0 54 /**
michael@0 55 * Return the location at which the *value* for the property is
michael@0 56 * stored, or null if the block does not contain a value for the
michael@0 57 * property.
michael@0 58 *
michael@0 59 * Inefficient (by design).
michael@0 60 *
michael@0 61 * Must not be called for shorthands.
michael@0 62 */
michael@0 63 const nsCSSValue* ValueFor(nsCSSProperty aProperty) const;
michael@0 64
michael@0 65 /**
michael@0 66 * Attempt to replace the value for |aProperty| stored in this block
michael@0 67 * with the matching value stored in |aFromBlock|.
michael@0 68 * This method will fail (returning false) if |aProperty| is not
michael@0 69 * already in this block. It will set |aChanged| to true if it
michael@0 70 * actually made a change to the block, but regardless, if it
michael@0 71 * returns true, the value in |aFromBlock| was erased.
michael@0 72 */
michael@0 73 bool TryReplaceValue(nsCSSProperty aProperty,
michael@0 74 nsCSSExpandedDataBlock& aFromBlock,
michael@0 75 bool* aChanged);
michael@0 76
michael@0 77 /**
michael@0 78 * Clone this block, or return null on out-of-memory.
michael@0 79 */
michael@0 80 nsCSSCompressedDataBlock* Clone() const;
michael@0 81
michael@0 82 /**
michael@0 83 * Create a new nsCSSCompressedDataBlock holding no declarations.
michael@0 84 */
michael@0 85 static nsCSSCompressedDataBlock* CreateEmptyBlock();
michael@0 86
michael@0 87 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
michael@0 88
michael@0 89 bool HasDefaultBorderImageSlice() const;
michael@0 90 bool HasDefaultBorderImageWidth() const;
michael@0 91 bool HasDefaultBorderImageOutset() const;
michael@0 92 bool HasDefaultBorderImageRepeat() const;
michael@0 93
michael@0 94 private:
michael@0 95 void* operator new(size_t aBaseSize, uint32_t aNumProps) {
michael@0 96 NS_ABORT_IF_FALSE(aBaseSize == sizeof(nsCSSCompressedDataBlock),
michael@0 97 "unexpected size for nsCSSCompressedDataBlock");
michael@0 98 return ::operator new(aBaseSize + DataSize(aNumProps));
michael@0 99 }
michael@0 100
michael@0 101 public:
michael@0 102 // Ideally, |nsCSSProperty| would be |enum nsCSSProperty : int16_t|. But
michael@0 103 // not all of the compilers we use are modern enough to support small
michael@0 104 // enums. So we manually squeeze nsCSSProperty into 16 bits ourselves.
michael@0 105 // The static assertion below ensures it fits.
michael@0 106 typedef int16_t CompressedCSSProperty;
michael@0 107 static const size_t MaxCompressedCSSProperty = INT16_MAX;
michael@0 108
michael@0 109 private:
michael@0 110 static size_t DataSize(uint32_t aNumProps) {
michael@0 111 return size_t(aNumProps) *
michael@0 112 (sizeof(nsCSSValue) + sizeof(CompressedCSSProperty));
michael@0 113 }
michael@0 114
michael@0 115 int32_t mStyleBits; // the structs for which we have data, according to
michael@0 116 // |nsCachedStyleData::GetBitForSID|.
michael@0 117 uint32_t mNumProps;
michael@0 118 // nsCSSValue elements are stored after these fields, and
michael@0 119 // nsCSSProperty elements are stored -- each one compressed as a
michael@0 120 // CompressedCSSProperty -- after the nsCSSValue elements. Space for them
michael@0 121 // is allocated in |operator new| above. The static assertions following
michael@0 122 // this class make sure that the value and property elements are aligned
michael@0 123 // appropriately.
michael@0 124
michael@0 125 nsCSSValue* Values() const {
michael@0 126 return (nsCSSValue*)(this + 1);
michael@0 127 }
michael@0 128
michael@0 129 CompressedCSSProperty* CompressedProperties() const {
michael@0 130 return (CompressedCSSProperty*)(Values() + mNumProps);
michael@0 131 }
michael@0 132
michael@0 133 nsCSSValue* ValueAtIndex(uint32_t i) const {
michael@0 134 NS_ABORT_IF_FALSE(i < mNumProps, "value index out of range");
michael@0 135 return Values() + i;
michael@0 136 }
michael@0 137
michael@0 138 nsCSSProperty PropertyAtIndex(uint32_t i) const {
michael@0 139 NS_ABORT_IF_FALSE(i < mNumProps, "property index out of range");
michael@0 140 nsCSSProperty prop = (nsCSSProperty)CompressedProperties()[i];
michael@0 141 NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(prop), "out of range");
michael@0 142 return prop;
michael@0 143 }
michael@0 144
michael@0 145 void CopyValueToIndex(uint32_t i, nsCSSValue* aValue) {
michael@0 146 new (ValueAtIndex(i)) nsCSSValue(*aValue);
michael@0 147 }
michael@0 148
michael@0 149 void RawCopyValueToIndex(uint32_t i, nsCSSValue* aValue) {
michael@0 150 memcpy(ValueAtIndex(i), aValue, sizeof(nsCSSValue));
michael@0 151 }
michael@0 152
michael@0 153 void SetPropertyAtIndex(uint32_t i, nsCSSProperty aProperty) {
michael@0 154 NS_ABORT_IF_FALSE(i < mNumProps, "set property index out of range");
michael@0 155 CompressedProperties()[i] = (CompressedCSSProperty)aProperty;
michael@0 156 }
michael@0 157
michael@0 158 void SetNumPropsToZero() {
michael@0 159 mNumProps = 0;
michael@0 160 }
michael@0 161 };
michael@0 162
michael@0 163 // Make sure the values and properties are aligned appropriately. (These
michael@0 164 // assertions are stronger than necessary to keep them simple.)
michael@0 165 static_assert(sizeof(nsCSSCompressedDataBlock) == 8,
michael@0 166 "nsCSSCompressedDataBlock's size has changed");
michael@0 167 static_assert(NS_ALIGNMENT_OF(nsCSSValue) == 4 || NS_ALIGNMENT_OF(nsCSSValue) == 8,
michael@0 168 "nsCSSValue doesn't align with nsCSSCompressedDataBlock");
michael@0 169 static_assert(NS_ALIGNMENT_OF(nsCSSCompressedDataBlock::CompressedCSSProperty) == 2,
michael@0 170 "CompressedCSSProperty doesn't align with nsCSSValue");
michael@0 171
michael@0 172 // Make sure that sizeof(CompressedCSSProperty) is big enough.
michael@0 173 static_assert(eCSSProperty_COUNT_no_shorthands <=
michael@0 174 nsCSSCompressedDataBlock::MaxCompressedCSSProperty,
michael@0 175 "nsCSSProperty doesn't fit in StoredSizeOfCSSProperty");
michael@0 176
michael@0 177 class nsCSSExpandedDataBlock {
michael@0 178 friend class nsCSSCompressedDataBlock;
michael@0 179
michael@0 180 public:
michael@0 181 nsCSSExpandedDataBlock();
michael@0 182 ~nsCSSExpandedDataBlock();
michael@0 183
michael@0 184 private:
michael@0 185 /* Property storage may not be accessed directly; use AddLonghandProperty
michael@0 186 * and friends.
michael@0 187 */
michael@0 188 nsCSSValue mValues[eCSSProperty_COUNT_no_shorthands];
michael@0 189
michael@0 190 public:
michael@0 191 /**
michael@0 192 * Transfer all of the state from a pair of compressed data blocks
michael@0 193 * to this expanded block. This expanded block must be clear
michael@0 194 * beforehand.
michael@0 195 *
michael@0 196 * This method DELETES both of the compressed data blocks it is
michael@0 197 * passed. (This is necessary because ownership of sub-objects
michael@0 198 * is transferred to the expanded block.)
michael@0 199 */
michael@0 200 void Expand(nsCSSCompressedDataBlock *aNormalBlock,
michael@0 201 nsCSSCompressedDataBlock *aImportantBlock);
michael@0 202
michael@0 203 /**
michael@0 204 * Allocate new compressed blocks and transfer all of the state
michael@0 205 * from this expanded block to the new blocks, clearing this
michael@0 206 * expanded block. A normal block will always be allocated, but
michael@0 207 * an important block will only be allocated if there are
michael@0 208 * !important properties in the expanded block; otherwise
michael@0 209 * |*aImportantBlock| will be set to null.
michael@0 210 */
michael@0 211 void Compress(nsCSSCompressedDataBlock **aNormalBlock,
michael@0 212 nsCSSCompressedDataBlock **aImportantBlock);
michael@0 213
michael@0 214 /**
michael@0 215 * Copy a value into this expanded block. This does NOT destroy
michael@0 216 * the source value object. |aProperty| cannot be a shorthand.
michael@0 217 */
michael@0 218 void AddLonghandProperty(nsCSSProperty aProperty, const nsCSSValue& aValue);
michael@0 219
michael@0 220 /**
michael@0 221 * Clear the state of this expanded block.
michael@0 222 */
michael@0 223 void Clear();
michael@0 224
michael@0 225 /**
michael@0 226 * Clear the data for the given property (including the set and
michael@0 227 * important bits). Can be used with shorthand properties.
michael@0 228 */
michael@0 229 void ClearProperty(nsCSSProperty aPropID);
michael@0 230
michael@0 231 /**
michael@0 232 * Same as ClearProperty, but faster and cannot be used with shorthands.
michael@0 233 */
michael@0 234 void ClearLonghandProperty(nsCSSProperty aPropID);
michael@0 235
michael@0 236 /**
michael@0 237 * Transfer the state for |aPropID| (which may be a shorthand)
michael@0 238 * from |aFromBlock| to this block. The property being transferred
michael@0 239 * is !important if |aIsImportant| is true, and should replace an
michael@0 240 * existing !important property regardless of its own importance
michael@0 241 * if |aOverrideImportant| is true.
michael@0 242 *
michael@0 243 * Returns true if something changed, false otherwise. Calls
michael@0 244 * |ValueAppended| on |aDeclaration| if the property was not
michael@0 245 * previously set, or in any case if |aMustCallValueAppended| is true.
michael@0 246 */
michael@0 247 bool TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
michael@0 248 nsCSSProperty aPropID,
michael@0 249 bool aIsImportant,
michael@0 250 bool aOverrideImportant,
michael@0 251 bool aMustCallValueAppended,
michael@0 252 mozilla::css::Declaration* aDeclaration);
michael@0 253
michael@0 254 /**
michael@0 255 * Copies the values for aPropID into the specified aRuleData object.
michael@0 256 *
michael@0 257 * This is used for copying parsed-at-computed-value-time properties
michael@0 258 * that had variable references. aPropID must be a longhand property.
michael@0 259 */
michael@0 260 void MapRuleInfoInto(nsCSSProperty aPropID, nsRuleData* aRuleData) const;
michael@0 261
michael@0 262 void AssertInitialState() {
michael@0 263 #ifdef DEBUG
michael@0 264 DoAssertInitialState();
michael@0 265 #endif
michael@0 266 }
michael@0 267
michael@0 268 private:
michael@0 269 /**
michael@0 270 * Compute the number of properties that will be present in the
michael@0 271 * result of |Compress|.
michael@0 272 */
michael@0 273 void ComputeNumProps(uint32_t* aNumPropsNormal,
michael@0 274 uint32_t* aNumPropsImportant);
michael@0 275
michael@0 276 void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant);
michael@0 277
michael@0 278 /**
michael@0 279 * Worker for TransferFromBlock; cannot be used with shorthands.
michael@0 280 */
michael@0 281 bool DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
michael@0 282 nsCSSProperty aPropID,
michael@0 283 bool aIsImportant,
michael@0 284 bool aOverrideImportant,
michael@0 285 bool aMustCallValueAppended,
michael@0 286 mozilla::css::Declaration* aDeclaration);
michael@0 287
michael@0 288 #ifdef DEBUG
michael@0 289 void DoAssertInitialState();
michael@0 290 #endif
michael@0 291
michael@0 292 /*
michael@0 293 * mPropertiesSet stores a bit for every property that is present,
michael@0 294 * to optimize compression of blocks with small numbers of
michael@0 295 * properties (the norm) and to allow quickly checking whether a
michael@0 296 * property is set in this block.
michael@0 297 */
michael@0 298 nsCSSPropertySet mPropertiesSet;
michael@0 299 /*
michael@0 300 * mPropertiesImportant indicates which properties are '!important'.
michael@0 301 */
michael@0 302 nsCSSPropertySet mPropertiesImportant;
michael@0 303
michael@0 304 /*
michael@0 305 * Return the storage location within |this| of the value of the
michael@0 306 * property |aProperty|.
michael@0 307 */
michael@0 308 nsCSSValue* PropertyAt(nsCSSProperty aProperty) {
michael@0 309 NS_ABORT_IF_FALSE(0 <= aProperty &&
michael@0 310 aProperty < eCSSProperty_COUNT_no_shorthands,
michael@0 311 "property out of range");
michael@0 312 return &mValues[aProperty];
michael@0 313 }
michael@0 314 const nsCSSValue* PropertyAt(nsCSSProperty aProperty) const {
michael@0 315 NS_ABORT_IF_FALSE(0 <= aProperty &&
michael@0 316 aProperty < eCSSProperty_COUNT_no_shorthands,
michael@0 317 "property out of range");
michael@0 318 return &mValues[aProperty];
michael@0 319 }
michael@0 320
michael@0 321 void SetPropertyBit(nsCSSProperty aProperty) {
michael@0 322 mPropertiesSet.AddProperty(aProperty);
michael@0 323 }
michael@0 324
michael@0 325 void ClearPropertyBit(nsCSSProperty aProperty) {
michael@0 326 mPropertiesSet.RemoveProperty(aProperty);
michael@0 327 }
michael@0 328
michael@0 329 bool HasPropertyBit(nsCSSProperty aProperty) {
michael@0 330 return mPropertiesSet.HasProperty(aProperty);
michael@0 331 }
michael@0 332
michael@0 333 void SetImportantBit(nsCSSProperty aProperty) {
michael@0 334 mPropertiesImportant.AddProperty(aProperty);
michael@0 335 }
michael@0 336
michael@0 337 void ClearImportantBit(nsCSSProperty aProperty) {
michael@0 338 mPropertiesImportant.RemoveProperty(aProperty);
michael@0 339 }
michael@0 340
michael@0 341 bool HasImportantBit(nsCSSProperty aProperty) {
michael@0 342 return mPropertiesImportant.HasProperty(aProperty);
michael@0 343 }
michael@0 344
michael@0 345 void ClearSets() {
michael@0 346 mPropertiesSet.Empty();
michael@0 347 mPropertiesImportant.Empty();
michael@0 348 }
michael@0 349 };
michael@0 350
michael@0 351 #endif /* !defined(nsCSSDataBlock_h__) */

mercurial