1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is nsCSSDataBlock.h.
16 : *
17 : * The Initial Developer of the Original Code is L. David Baron.
18 : * Portions created by the Initial Developer are Copyright (C) 2003
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * L. David Baron <dbaron@dbaron.org> (original author)
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : * compact representation of the property-value pairs within a CSS
40 : * declaration, and the code for expanding and compacting it
41 : */
42 :
43 : #ifndef nsCSSDataBlock_h__
44 : #define nsCSSDataBlock_h__
45 :
46 : #include "nsCSSProps.h"
47 : #include "nsCSSPropertySet.h"
48 :
49 : struct nsRuleData;
50 : class nsCSSExpandedDataBlock;
51 :
52 : namespace mozilla {
53 : namespace css {
54 : class Declaration;
55 : }
56 : }
57 :
58 : /*
59 : * nsCSSCompressedDataBlock holds property-value pairs corresponding
60 : * to CSS declaration blocks. Each pair is stored in a CDBValueStorage
61 : * object; these objects form an array at the end of the data block.
62 : */
63 : struct CDBValueStorage {
64 : nsCSSProperty property;
65 : nsCSSValue value;
66 : };
67 :
68 : /**
69 : * An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of
70 : * property-value data for a CSS declaration block (which we misname a
71 : * |css::Declaration|). Mutation is accomplished through
72 : * |nsCSSExpandedDataBlock| or in some cases via direct slot access.
73 : */
74 : class nsCSSCompressedDataBlock {
75 : private:
76 : friend class nsCSSExpandedDataBlock;
77 :
78 : // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock
79 : // (in |Compress|) can create compressed data blocks.
80 0 : nsCSSCompressedDataBlock() : mStyleBits(0) {}
81 :
82 : public:
83 : ~nsCSSCompressedDataBlock();
84 :
85 : /**
86 : * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style
87 : * rule using this block for storage.
88 : */
89 : void MapRuleInfoInto(nsRuleData *aRuleData) const;
90 :
91 : /**
92 : * Return the location at which the *value* for the property is
93 : * stored, or null if the block does not contain a value for the
94 : * property.
95 : *
96 : * Inefficient (by design).
97 : *
98 : * Must not be called for shorthands.
99 : */
100 : const nsCSSValue* ValueFor(nsCSSProperty aProperty) const;
101 :
102 : /**
103 : * Attempt to replace the value for |aProperty| stored in this block
104 : * with the matching value stored in |aFromBlock|.
105 : * This method will fail (returning false) if |aProperty| is not
106 : * already in this block. It will set |aChanged| to true if it
107 : * actually made a change to the block, but regardless, if it
108 : * returns true, the value in |aFromBlock| was erased.
109 : */
110 : bool TryReplaceValue(nsCSSProperty aProperty,
111 : nsCSSExpandedDataBlock& aFromBlock,
112 : bool* aChanged);
113 :
114 : /**
115 : * Clone this block, or return null on out-of-memory.
116 : */
117 : nsCSSCompressedDataBlock* Clone() const;
118 :
119 : /**
120 : * Create a new nsCSSCompressedDataBlock holding no declarations.
121 : */
122 : static nsCSSCompressedDataBlock* CreateEmptyBlock();
123 :
124 : size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
125 :
126 : private:
127 0 : void* operator new(size_t aBaseSize, size_t aDataSize) {
128 0 : NS_ABORT_IF_FALSE(aBaseSize == sizeof(nsCSSCompressedDataBlock),
129 : "unexpected size for nsCSSCompressedDataBlock");
130 0 : return ::operator new(aBaseSize + aDataSize);
131 : }
132 :
133 : /**
134 : * Delete all the data stored in this block, and the block itself.
135 : */
136 : void Destroy();
137 :
138 : PRInt32 mStyleBits; // the structs for which we have data, according to
139 : // |nsCachedStyleData::GetBitForSID|.
140 : PRUint32 mDataSize;
141 : // CDBValueStorage elements are stored after these fields. Space for them
142 : // is allocated in |operator new| above. The static assertions following
143 : // this class make sure that the CDBValueStorage elements are aligned
144 : // appropriately.
145 :
146 0 : char* Block() { return (char*)this + sizeof(*this); }
147 0 : char* BlockEnd() { return Block() + mDataSize; }
148 0 : const char* Block() const { return (char*)this + sizeof(*this); }
149 0 : const char* BlockEnd() const { return Block() + mDataSize; }
150 0 : void SetBlockEnd(char *blockEnd) {
151 : /*
152 : * Note: if we ever change nsCSSDeclaration to store the declarations
153 : * in order and also store repeated declarations of the same property,
154 : * then we need to worry about checking for integer overflow here.
155 : */
156 0 : NS_ABORT_IF_FALSE(size_t(blockEnd - Block()) <= size_t(PR_UINT32_MAX),
157 : "overflow of mDataSize");
158 0 : mDataSize = PRUint32(blockEnd - Block());
159 0 : }
160 0 : ptrdiff_t DataSize() const { return mDataSize; }
161 : };
162 :
163 : /* Make sure the CDBValueStorage elements are aligned appropriately. */
164 : MOZ_STATIC_ASSERT(sizeof(nsCSSCompressedDataBlock) == 8,
165 : "nsCSSCompressedDataBlock's size has changed");
166 : MOZ_STATIC_ASSERT(NS_ALIGNMENT_OF(CDBValueStorage) <= 8,
167 : "CDBValueStorage needs too much alignment");
168 :
169 : class nsCSSExpandedDataBlock {
170 : friend class nsCSSCompressedDataBlock;
171 :
172 : public:
173 : nsCSSExpandedDataBlock();
174 : ~nsCSSExpandedDataBlock();
175 :
176 : private:
177 : /* Property storage may not be accessed directly; use AddLonghandProperty
178 : * and friends.
179 : */
180 : nsCSSValue mValues[eCSSProperty_COUNT_no_shorthands];
181 :
182 : public:
183 : /**
184 : * Transfer all of the state from a pair of compressed data blocks
185 : * to this expanded block. This expanded block must be clear
186 : * beforehand.
187 : *
188 : * This method DELETES both of the compressed data blocks it is
189 : * passed. (This is necessary because ownership of sub-objects
190 : * is transferred to the expanded block.)
191 : */
192 : void Expand(nsCSSCompressedDataBlock *aNormalBlock,
193 : nsCSSCompressedDataBlock *aImportantBlock);
194 :
195 : /**
196 : * Allocate new compressed blocks and transfer all of the state
197 : * from this expanded block to the new blocks, clearing this
198 : * expanded block. A normal block will always be allocated, but
199 : * an important block will only be allocated if there are
200 : * !important properties in the expanded block; otherwise
201 : * |*aImportantBlock| will be set to null.
202 : */
203 : void Compress(nsCSSCompressedDataBlock **aNormalBlock,
204 : nsCSSCompressedDataBlock **aImportantBlock);
205 :
206 : /**
207 : * Copy a value into this expanded block. This does NOT destroy
208 : * the source value object. |aProperty| cannot be a shorthand.
209 : */
210 : void AddLonghandProperty(nsCSSProperty aProperty, const nsCSSValue& aValue);
211 :
212 : /**
213 : * Clear the state of this expanded block.
214 : */
215 : void Clear();
216 :
217 : /**
218 : * Clear the data for the given property (including the set and
219 : * important bits). Can be used with shorthand properties.
220 : */
221 : void ClearProperty(nsCSSProperty aPropID);
222 :
223 : /**
224 : * Same as ClearProperty, but faster and cannot be used with shorthands.
225 : */
226 : void ClearLonghandProperty(nsCSSProperty aPropID);
227 :
228 : /**
229 : * Transfer the state for |aPropID| (which may be a shorthand)
230 : * from |aFromBlock| to this block. The property being transferred
231 : * is !important if |aIsImportant| is true, and should replace an
232 : * existing !important property regardless of its own importance
233 : * if |aOverrideImportant| is true.
234 : *
235 : * Returns true if something changed, false otherwise. Calls
236 : * |ValueAppended| on |aDeclaration| if the property was not
237 : * previously set, or in any case if |aMustCallValueAppended| is true.
238 : */
239 : bool TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
240 : nsCSSProperty aPropID,
241 : bool aIsImportant,
242 : bool aOverrideImportant,
243 : bool aMustCallValueAppended,
244 : mozilla::css::Declaration* aDeclaration);
245 :
246 72 : void AssertInitialState() {
247 : #ifdef DEBUG
248 72 : DoAssertInitialState();
249 : #endif
250 72 : }
251 :
252 : private:
253 : /**
254 : * Compute the size that will be occupied by the result of
255 : * |Compress|.
256 : */
257 : struct ComputeSizeResult {
258 : PRUint32 normal, important;
259 : };
260 : ComputeSizeResult ComputeSize();
261 :
262 : void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant);
263 :
264 : /**
265 : * Worker for TransferFromBlock; cannot be used with shorthands.
266 : */
267 : bool DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
268 : nsCSSProperty aPropID,
269 : bool aIsImportant,
270 : bool aOverrideImportant,
271 : bool aMustCallValueAppended,
272 : mozilla::css::Declaration* aDeclaration);
273 :
274 : #ifdef DEBUG
275 : void DoAssertInitialState();
276 : #endif
277 :
278 : /*
279 : * mPropertiesSet stores a bit for every property that is present,
280 : * to optimize compression of blocks with small numbers of
281 : * properties (the norm) and to allow quickly checking whether a
282 : * property is set in this block.
283 : */
284 : nsCSSPropertySet mPropertiesSet;
285 : /*
286 : * mPropertiesImportant indicates which properties are '!important'.
287 : */
288 : nsCSSPropertySet mPropertiesImportant;
289 :
290 : /*
291 : * Return the storage location within |this| of the value of the
292 : * property |aProperty|.
293 : */
294 16848 : nsCSSValue* PropertyAt(nsCSSProperty aProperty) {
295 16848 : NS_ABORT_IF_FALSE(0 <= aProperty &&
296 : aProperty < eCSSProperty_COUNT_no_shorthands,
297 : "property out of range");
298 16848 : return &mValues[aProperty];
299 : }
300 :
301 0 : void SetPropertyBit(nsCSSProperty aProperty) {
302 0 : mPropertiesSet.AddProperty(aProperty);
303 0 : }
304 :
305 0 : void ClearPropertyBit(nsCSSProperty aProperty) {
306 0 : mPropertiesSet.RemoveProperty(aProperty);
307 0 : }
308 :
309 0 : bool HasPropertyBit(nsCSSProperty aProperty) {
310 0 : return mPropertiesSet.HasProperty(aProperty);
311 : }
312 :
313 0 : void SetImportantBit(nsCSSProperty aProperty) {
314 0 : mPropertiesImportant.AddProperty(aProperty);
315 0 : }
316 :
317 0 : void ClearImportantBit(nsCSSProperty aProperty) {
318 0 : mPropertiesImportant.RemoveProperty(aProperty);
319 0 : }
320 :
321 0 : bool HasImportantBit(nsCSSProperty aProperty) {
322 0 : return mPropertiesImportant.HasProperty(aProperty);
323 : }
324 :
325 0 : void ClearSets() {
326 0 : mPropertiesSet.Empty();
327 0 : mPropertiesImportant.Empty();
328 0 : }
329 : };
330 :
331 : #endif /* !defined(nsCSSDataBlock_h__) */
|