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
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/
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
15 * The Original Code is nsCSSDataBlock.cpp.
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.
22 * L. David Baron <dbaron@dbaron.org> (original author)
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.
36 * ***** END LICENSE BLOCK ***** */
39 * compact representation of the property-value pairs within a CSS
40 * declaration, and the code for expanding and compacting it
43 #include "nsCSSDataBlock.h"
44 #include "nsCSSProps.h"
45 #include "nsRuleData.h"
46 #include "nsRuleNode.h"
47 #include "nsStyleSet.h"
50 * nsCSSCompressedDataBlock holds property-value pairs corresponding to
51 * CSS declaration blocks. The value is stored in one of the five CSS
52 * data types: nsCSSValue, nsCSSRect, nsCSSValueList, nsCSSValuePair,
53 * and nsCSSValuePairList, which each correspond to a value of the
54 * nsCSSType enumeration.
56 * The storage strategy uses the CDB*Storage structs below to help
57 * ensure that all the types remain properly aligned. nsCSSValue's
58 * alignment requirements cannot be weaker than any others, since it
59 * contains a pointer and an enumeration.
61 * The simple types, nsCSSValue and nsCSSRect have the nsCSSValue or
62 * nsCSSRect objects stored in the block. The list types have only a
63 * pointer to the first element in the list stored in the block.
66 struct CDBValueStorage
{
67 nsCSSProperty property
;
71 struct CDBRectStorage
{
72 nsCSSProperty property
;
77 struct CDBValuePairStorage
{
78 nsCSSProperty property
;
82 struct CDBPointerStorage
{
83 nsCSSProperty property
;
88 CDBValueStorage_advance
= sizeof(CDBValueStorage
),
89 CDBRectStorage_advance
= sizeof(CDBRectStorage
),
90 CDBValuePairStorage_advance
= sizeof(CDBValuePairStorage
),
91 // round up using the closest estimate we can get of the alignment
92 // requirements of nsCSSValue:
93 CDBPointerStorage_advance
= PR_ROUNDUP(sizeof(CDBPointerStorage
),
94 sizeof(CDBValueStorage
) - sizeof(nsCSSValue
))
98 * Define a bunch of utility functions for getting the property or any
99 * of the value types when the cursor is at the beginning of the storage
100 * for the property-value pair. The versions taking a non-const cursor
101 * argument return a reference so that the caller can assign into the
105 inline nsCSSProperty
& PropertyAtCursor(char *aCursor
) {
106 return *reinterpret_cast<nsCSSProperty
*>(aCursor
);
109 inline nsCSSProperty
PropertyAtCursor(const char *aCursor
) {
110 return *reinterpret_cast<const nsCSSProperty
*>(aCursor
);
113 inline nsCSSValue
* ValueAtCursor(char *aCursor
) {
114 return & reinterpret_cast<CDBValueStorage
*>(aCursor
)->value
;
117 inline const nsCSSValue
* ValueAtCursor(const char *aCursor
) {
118 return & reinterpret_cast<const CDBValueStorage
*>(aCursor
)->value
;
121 inline nsCSSRect
* RectAtCursor(char *aCursor
) {
122 return & reinterpret_cast<CDBRectStorage
*>(aCursor
)->value
;
125 inline const nsCSSRect
* RectAtCursor(const char *aCursor
) {
126 return & reinterpret_cast<const CDBRectStorage
*>(aCursor
)->value
;
129 inline nsCSSValuePair
* ValuePairAtCursor(char *aCursor
) {
130 return & reinterpret_cast<CDBValuePairStorage
*>(aCursor
)->value
;
133 inline const nsCSSValuePair
* ValuePairAtCursor(const char *aCursor
) {
134 return & reinterpret_cast<const CDBValuePairStorage
*>(aCursor
)->value
;
137 inline void*& PointerAtCursor(char *aCursor
) {
138 return reinterpret_cast<CDBPointerStorage
*>(aCursor
)->value
;
141 inline void* PointerAtCursor(const char *aCursor
) {
142 return reinterpret_cast<const CDBPointerStorage
*>(aCursor
)->value
;
145 inline nsCSSValueList
*& ValueListAtCursor(char *aCursor
) {
146 return * reinterpret_cast<nsCSSValueList
**>
147 (& reinterpret_cast<CDBPointerStorage
*>(aCursor
)->value
);
150 inline nsCSSValueList
* ValueListAtCursor(const char *aCursor
) {
151 return static_cast<nsCSSValueList
*>
152 (reinterpret_cast<const CDBPointerStorage
*>(aCursor
)->value
);
155 inline nsCSSValuePairList
*& ValuePairListAtCursor(char *aCursor
) {
156 return * reinterpret_cast<nsCSSValuePairList
**>
157 (& reinterpret_cast<CDBPointerStorage
*>(aCursor
)->value
);
160 inline nsCSSValuePairList
* ValuePairListAtCursor(const char *aCursor
) {
161 return static_cast<nsCSSValuePairList
*>
162 (reinterpret_cast<const CDBPointerStorage
*>(aCursor
)->value
);
166 ShouldIgnoreColors(nsRuleData
*aRuleData
)
168 return aRuleData
->mLevel
!= nsStyleSet::eAgentSheet
&&
169 aRuleData
->mLevel
!= nsStyleSet::eUserSheet
&&
170 !aRuleData
->mPresContext
->UseDocumentColors();
174 nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData
*aRuleData
) const
176 // If we have no data for these structs, then return immediately.
177 // This optimization should make us return most of the time, so we
178 // have to worry much less (although still some) about the speed of
179 // the rest of the function.
180 if (!(aRuleData
->mSIDs
& mStyleBits
))
183 const char* cursor
= Block();
184 const char* cursor_end
= BlockEnd();
185 while (cursor
< cursor_end
) {
186 nsCSSProperty iProp
= PropertyAtCursor(cursor
);
187 NS_ASSERTION(0 <= iProp
&& iProp
< eCSSProperty_COUNT_no_shorthands
,
189 if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable
[iProp
]) &
192 nsCSSExpandedDataBlock::RuleDataPropertyAt(aRuleData
, iProp
);
193 switch (nsCSSProps::kTypeTable
[iProp
]) {
194 case eCSSType_Value
: {
195 nsCSSValue
* target
= static_cast<nsCSSValue
*>(prop
);
196 if (target
->GetUnit() == eCSSUnit_Null
) {
197 const nsCSSValue
*val
= ValueAtCursor(cursor
);
198 NS_ASSERTION(val
->GetUnit() != eCSSUnit_Null
, "oops");
199 if (iProp
== eCSSProperty_background_image
||
200 iProp
== eCSSProperty_list_style_image
) {
201 if (val
->GetUnit() == eCSSUnit_URL
) {
203 aRuleData
->mPresContext
->Document());
205 } else if (iProp
== eCSSProperty_border_image
) {
206 if (val
->GetUnit() == eCSSUnit_Array
) {
207 nsCSSValue::Array
*array
= val
->GetArrayValue();
208 if (array
->Item(0).GetUnit() == eCSSUnit_URL
) {
209 array
->Item(0).StartImageLoad(
210 aRuleData
->mPresContext
->Document());
215 if (iProp
== eCSSProperty_font_family
) {
216 // XXX Are there other things like this?
217 aRuleData
->mFontData
->mFamilyFromHTML
= PR_FALSE
;
219 else if (iProp
== eCSSProperty_color
||
220 iProp
== eCSSProperty_background_color
||
221 iProp
== eCSSProperty_background_image
||
222 iProp
== eCSSProperty_border_top_color
||
223 iProp
== eCSSProperty_border_right_color_value
||
224 iProp
== eCSSProperty_border_right_color_ltr_source
||
225 iProp
== eCSSProperty_border_right_color_rtl_source
||
226 iProp
== eCSSProperty_border_bottom_color
||
227 iProp
== eCSSProperty_border_left_color_value
||
228 iProp
== eCSSProperty_border_left_color_ltr_source
||
229 iProp
== eCSSProperty_border_left_color_rtl_source
||
230 iProp
== eCSSProperty__moz_column_rule_color
||
231 iProp
== eCSSProperty_outline_color
) {
232 if (ShouldIgnoreColors(aRuleData
)) {
233 if (iProp
== eCSSProperty_background_color
) {
234 // Force non-'transparent' background
235 // colors to the user's default.
236 // We have the value in the form it was
237 // specified at this point, so we have to
238 // look for both the keyword 'transparent'
239 // and its equivalent in rgba notation.
240 nsCSSUnit u
= target
->GetUnit();
241 nsDependentString buf
;
243 if ((u
== eCSSUnit_Color
&&
244 NS_GET_A(target
->GetColorValue())
246 (u
== eCSSUnit_String
&&
247 !nsGkAtoms::transparent
->
248 Equals(target
->GetStringValue(buf
))) ||
249 (u
== eCSSUnit_EnumColor
)) {
250 target
->SetColorValue(aRuleData
->
252 DefaultBackgroundColor());
255 // Ignore 'color', 'border-*-color', and
256 // 'background-image'
257 *target
= nsCSSValue();
262 cursor
+= CDBValueStorage_advance
;
265 case eCSSType_Rect
: {
266 const nsCSSRect
* val
= RectAtCursor(cursor
);
267 NS_ASSERTION(val
->HasValue(), "oops");
268 nsCSSRect
* target
= static_cast<nsCSSRect
*>(prop
);
269 if (target
->mTop
.GetUnit() == eCSSUnit_Null
)
270 target
->mTop
= val
->mTop
;
271 if (target
->mRight
.GetUnit() == eCSSUnit_Null
)
272 target
->mRight
= val
->mRight
;
273 if (target
->mBottom
.GetUnit() == eCSSUnit_Null
)
274 target
->mBottom
= val
->mBottom
;
275 if (target
->mLeft
.GetUnit() == eCSSUnit_Null
)
276 target
->mLeft
= val
->mLeft
;
277 cursor
+= CDBRectStorage_advance
;
280 case eCSSType_ValuePair
: {
281 const nsCSSValuePair
* val
= ValuePairAtCursor(cursor
);
282 NS_ASSERTION(val
->mXValue
.GetUnit() != eCSSUnit_Null
||
283 val
->mYValue
.GetUnit() != eCSSUnit_Null
, "oops");
284 nsCSSValuePair
* target
= static_cast<nsCSSValuePair
*>(prop
);
285 if (target
->mXValue
.GetUnit() == eCSSUnit_Null
)
286 target
->mXValue
= val
->mXValue
;
287 if (target
->mYValue
.GetUnit() == eCSSUnit_Null
)
288 target
->mYValue
= val
->mYValue
;
289 cursor
+= CDBValuePairStorage_advance
;
292 case eCSSType_ValueList
:
293 if (iProp
== eCSSProperty_content
) {
294 for (nsCSSValueList
* l
= ValueListAtCursor(cursor
);
296 if (l
->mValue
.GetUnit() == eCSSUnit_URL
)
297 l
->mValue
.StartImageLoad(
298 aRuleData
->mPresContext
->Document());
299 } else if (iProp
== eCSSProperty_cursor
) {
300 for (nsCSSValueList
* l
= ValueListAtCursor(cursor
);
302 if (l
->mValue
.GetUnit() == eCSSUnit_Array
) {
303 // Don't try to restart loads we've already
306 l
->mValue
.GetArrayValue()->Item(0);
307 if (val
.GetUnit() == eCSSUnit_URL
)
309 aRuleData
->mPresContext
->Document());
313 case eCSSType_ValuePairList
: {
314 void** target
= static_cast<void**>(prop
);
316 void* val
= PointerAtCursor(cursor
);
317 NS_ASSERTION(val
, "oops");
320 if (iProp
== eCSSProperty_border_top_colors
||
321 iProp
== eCSSProperty_border_right_colors
||
322 iProp
== eCSSProperty_border_bottom_colors
||
323 iProp
== eCSSProperty_border_left_colors
) {
324 if (ShouldIgnoreColors(aRuleData
)) {
329 cursor
+= CDBPointerStorage_advance
;
333 switch (nsCSSProps::kTypeTable
[iProp
]) {
334 case eCSSType_Value
: {
335 cursor
+= CDBValueStorage_advance
;
338 case eCSSType_Rect
: {
339 cursor
+= CDBRectStorage_advance
;
342 case eCSSType_ValuePair
: {
343 cursor
+= CDBValuePairStorage_advance
;
346 case eCSSType_ValueList
:
347 case eCSSType_ValuePairList
: {
348 cursor
+= CDBPointerStorage_advance
;
353 NS_ASSERTION(cursor
== cursor_end
, "inconsistent data");
359 nsCSSCompressedDataBlock::StorageFor(nsCSSProperty aProperty
) const
361 // If we have no data for this struct, then return immediately.
362 // This optimization should make us return most of the time, so we
363 // have to worry much less (although still some) about the speed of
364 // the rest of the function.
365 if (!(nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable
[aProperty
]) &
369 const char* cursor
= Block();
370 const char* cursor_end
= BlockEnd();
371 while (cursor
< cursor_end
) {
372 nsCSSProperty iProp
= PropertyAtCursor(cursor
);
373 NS_ASSERTION(0 <= iProp
&& iProp
< eCSSProperty_COUNT_no_shorthands
,
375 if (iProp
== aProperty
) {
376 switch (nsCSSProps::kTypeTable
[iProp
]) {
377 case eCSSType_Value
: {
378 return ValueAtCursor(cursor
);
380 case eCSSType_Rect
: {
381 return RectAtCursor(cursor
);
383 case eCSSType_ValuePair
: {
384 return ValuePairAtCursor(cursor
);
386 case eCSSType_ValueList
:
387 case eCSSType_ValuePairList
: {
388 return &PointerAtCursor(const_cast<char*>(cursor
));
392 switch (nsCSSProps::kTypeTable
[iProp
]) {
393 case eCSSType_Value
: {
394 cursor
+= CDBValueStorage_advance
;
397 case eCSSType_Rect
: {
398 cursor
+= CDBRectStorage_advance
;
401 case eCSSType_ValuePair
: {
402 cursor
+= CDBValuePairStorage_advance
;
405 case eCSSType_ValueList
:
406 case eCSSType_ValuePairList
: {
407 cursor
+= CDBPointerStorage_advance
;
411 NS_ASSERTION(cursor
== cursor_end
, "inconsistent data");
416 nsCSSCompressedDataBlock
*
417 nsCSSCompressedDataBlock::Clone() const
419 const char *cursor
= Block(), *cursor_end
= BlockEnd();
422 nsCSSCompressedDataBlock
*result
=
423 new(cursor_end
- cursor
) nsCSSCompressedDataBlock();
426 result_cursor
= result
->Block();
428 while (cursor
< cursor_end
) {
429 nsCSSProperty iProp
= PropertyAtCursor(cursor
);
430 NS_ASSERTION(0 <= iProp
&& iProp
< eCSSProperty_COUNT_no_shorthands
,
432 PropertyAtCursor(result_cursor
) = iProp
;
434 switch (nsCSSProps::kTypeTable
[iProp
]) {
435 case eCSSType_Value
: {
436 const nsCSSValue
* val
= ValueAtCursor(cursor
);
437 NS_ASSERTION(val
->GetUnit() != eCSSUnit_Null
, "oops");
438 nsCSSValue
*result_val
= ValueAtCursor(result_cursor
);
439 new (result_val
) nsCSSValue(*val
);
440 cursor
+= CDBValueStorage_advance
;
441 result_cursor
+= CDBValueStorage_advance
;
444 case eCSSType_Rect
: {
445 const nsCSSRect
* val
= RectAtCursor(cursor
);
446 NS_ASSERTION(val
->HasValue(), "oops");
447 nsCSSRect
* result_val
= RectAtCursor(result_cursor
);
448 new (result_val
) nsCSSRect(*val
);
449 cursor
+= CDBRectStorage_advance
;
450 result_cursor
+= CDBRectStorage_advance
;
453 case eCSSType_ValuePair
: {
454 const nsCSSValuePair
* val
= ValuePairAtCursor(cursor
);
455 NS_ASSERTION(val
->mXValue
.GetUnit() != eCSSUnit_Null
||
456 val
->mYValue
.GetUnit() != eCSSUnit_Null
, "oops");
457 nsCSSValuePair
* result_val
= ValuePairAtCursor(result_cursor
);
458 new (result_val
) nsCSSValuePair(*val
);
459 cursor
+= CDBValuePairStorage_advance
;
460 result_cursor
+= CDBValuePairStorage_advance
;
463 case eCSSType_ValueList
:
464 case eCSSType_ValuePairList
: {
466 NS_ASSERTION(PointerAtCursor(cursor
), "oops");
467 switch (nsCSSProps::kTypeTable
[iProp
]) {
469 NS_NOTREACHED("unreachable");
470 // fall through to keep gcc's uninitialized
471 // variable warning quiet
472 case eCSSType_ValueList
:
473 copy
= ValueListAtCursor(cursor
)->Clone();
475 case eCSSType_ValuePairList
:
476 copy
= ValuePairListAtCursor(cursor
)->Clone();
480 result
->mBlockEnd
= result_cursor
;
484 PointerAtCursor(result_cursor
) = copy
;
485 cursor
+= CDBPointerStorage_advance
;
486 result_cursor
+= CDBPointerStorage_advance
;
490 NS_ASSERTION(cursor
== cursor_end
, "inconsistent data");
492 result
->mBlockEnd
= result_cursor
;
493 result
->mStyleBits
= mStyleBits
;
494 NS_ASSERTION(result
->DataSize() == DataSize(), "wrong size");
499 nsCSSCompressedDataBlock::Destroy()
501 const char* cursor
= Block();
502 const char* cursor_end
= BlockEnd();
503 while (cursor
< cursor_end
) {
504 nsCSSProperty iProp
= PropertyAtCursor(cursor
);
505 NS_ASSERTION(0 <= iProp
&& iProp
< eCSSProperty_COUNT_no_shorthands
,
508 switch (nsCSSProps::kTypeTable
[iProp
]) {
509 case eCSSType_Value
: {
510 const nsCSSValue
* val
= ValueAtCursor(cursor
);
511 NS_ASSERTION(val
->GetUnit() != eCSSUnit_Null
, "oops");
513 cursor
+= CDBValueStorage_advance
;
516 case eCSSType_Rect
: {
517 const nsCSSRect
* val
= RectAtCursor(cursor
);
518 NS_ASSERTION(val
->HasValue(), "oops");
520 cursor
+= CDBRectStorage_advance
;
523 case eCSSType_ValuePair
: {
524 const nsCSSValuePair
* val
= ValuePairAtCursor(cursor
);
525 NS_ASSERTION(val
->mXValue
.GetUnit() != eCSSUnit_Null
||
526 val
->mYValue
.GetUnit() != eCSSUnit_Null
, "oops");
527 val
->~nsCSSValuePair();
528 cursor
+= CDBValuePairStorage_advance
;
531 case eCSSType_ValueList
: {
532 nsCSSValueList
* val
= ValueListAtCursor(cursor
);
533 NS_ASSERTION(val
, "oops");
535 cursor
+= CDBPointerStorage_advance
;
538 case eCSSType_ValuePairList
: {
539 nsCSSValuePairList
* val
= ValuePairListAtCursor(cursor
);
540 NS_ASSERTION(val
, "oops");
542 cursor
+= CDBPointerStorage_advance
;
546 NS_ASSERTION(cursor
== cursor_end
, "inconsistent data");
550 /* static */ nsCSSCompressedDataBlock
*
551 nsCSSCompressedDataBlock::CreateEmptyBlock()
553 nsCSSCompressedDataBlock
*result
= new(0) nsCSSCompressedDataBlock();
556 result
->mBlockEnd
= result
->Block();
560 /*****************************************************************************/
562 nsCSSExpandedDataBlock::nsCSSExpandedDataBlock()
565 AssertInitialState();
568 nsCSSExpandedDataBlock::~nsCSSExpandedDataBlock()
570 AssertInitialState();
573 const nsCSSExpandedDataBlock::PropertyOffsetInfo
574 nsCSSExpandedDataBlock::kOffsetTable
[eCSSProperty_COUNT_no_shorthands
] = {
575 #define CSS_PROP_BACKENDONLY(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
576 { offsetof(nsCSSExpandedDataBlock, m##datastruct_.member_), \
579 #define CSS_PROP(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
580 { offsetof(nsCSSExpandedDataBlock, m##datastruct_.member_), \
581 offsetof(nsRuleData, m##datastruct_##Data), \
582 offsetof(nsRuleData##datastruct_, member_) },
583 #include "nsCSSPropList.h"
585 #undef CSS_PROP_BACKENDONLY
589 nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock
*aBlock
,
592 NS_PRECONDITION(aBlock
, "unexpected null block");
595 * Save needless copying and allocation by copying the memory
596 * corresponding to the stored data in the compressed block, and
597 * then, to avoid destructors, deleting the compressed block by
598 * calling |delete| instead of using its |Destroy| method.
600 const char* cursor
= aBlock
->Block();
601 const char* cursor_end
= aBlock
->BlockEnd();
602 while (cursor
< cursor_end
) {
603 nsCSSProperty iProp
= PropertyAtCursor(cursor
);
604 NS_ASSERTION(0 <= iProp
&& iProp
< eCSSProperty_COUNT_no_shorthands
,
606 NS_ASSERTION(!HasPropertyBit(iProp
),
607 "compressed block has property multiple times");
608 SetPropertyBit(iProp
);
610 SetImportantBit(iProp
);
611 void *prop
= PropertyAt(iProp
);
613 switch (nsCSSProps::kTypeTable
[iProp
]) {
614 case eCSSType_Value
: {
615 const nsCSSValue
* val
= ValueAtCursor(cursor
);
616 nsCSSValue
* dest
= static_cast<nsCSSValue
*>(prop
);
617 NS_ASSERTION(val
->GetUnit() != eCSSUnit_Null
, "oops");
618 NS_ASSERTION(dest
->GetUnit() == eCSSUnit_Null
,
619 "expanding into non-empty block");
620 #ifdef NS_BUILD_REFCNT_LOGGING
623 memcpy(dest
, val
, sizeof(nsCSSValue
));
624 cursor
+= CDBValueStorage_advance
;
627 case eCSSType_Rect
: {
628 const nsCSSRect
* val
= RectAtCursor(cursor
);
629 nsCSSRect
* dest
= static_cast<nsCSSRect
*>(prop
);
630 NS_ASSERTION(val
->HasValue(), "oops");
631 NS_ASSERTION(!dest
->HasValue(),
632 "expanding into non-empty block");
633 #ifdef NS_BUILD_REFCNT_LOGGING
636 memcpy(dest
, val
, sizeof(nsCSSRect
));
637 cursor
+= CDBRectStorage_advance
;
640 case eCSSType_ValuePair
: {
641 const nsCSSValuePair
* val
= ValuePairAtCursor(cursor
);
642 nsCSSValuePair
* dest
= static_cast<nsCSSValuePair
*>(prop
);
643 NS_ASSERTION(val
->mXValue
.GetUnit() != eCSSUnit_Null
||
644 val
->mYValue
.GetUnit() != eCSSUnit_Null
, "oops");
645 NS_ASSERTION(dest
->mXValue
.GetUnit() == eCSSUnit_Null
&&
646 dest
->mYValue
.GetUnit() == eCSSUnit_Null
,
647 "expanding into non-empty block");
648 #ifdef NS_BUILD_REFCNT_LOGGING
649 dest
->~nsCSSValuePair();
651 memcpy(dest
, val
, sizeof(nsCSSValuePair
));
652 cursor
+= CDBValuePairStorage_advance
;
655 case eCSSType_ValueList
:
656 case eCSSType_ValuePairList
: {
657 void* val
= PointerAtCursor(cursor
);
658 void** dest
= static_cast<void**>(prop
);
659 NS_ASSERTION(val
, "oops");
660 NS_ASSERTION(!*dest
, "expanding into non-empty block");
662 cursor
+= CDBPointerStorage_advance
;
666 NS_ASSERTION(cursor
== cursor_end
, "inconsistent data");
672 nsCSSExpandedDataBlock::Expand(nsCSSCompressedDataBlock
**aNormalBlock
,
673 nsCSSCompressedDataBlock
**aImportantBlock
)
675 NS_PRECONDITION(*aNormalBlock
, "unexpected null block");
676 AssertInitialState();
678 DoExpand(*aNormalBlock
, PR_FALSE
);
679 *aNormalBlock
= nsnull
;
680 if (*aImportantBlock
) {
681 DoExpand(*aImportantBlock
, PR_TRUE
);
682 *aImportantBlock
= nsnull
;
686 nsCSSExpandedDataBlock::ComputeSizeResult
687 nsCSSExpandedDataBlock::ComputeSize()
689 ComputeSizeResult result
= {0, 0};
690 for (PRUint32 iHigh
= 0; iHigh
< NS_ARRAY_LENGTH(mPropertiesSet
); ++iHigh
) {
691 if (mPropertiesSet
[iHigh
] == 0)
693 for (PRInt32 iLow
= 0; iLow
< kPropertiesSetChunkSize
; ++iLow
) {
694 if ((mPropertiesSet
[iHigh
] & (1 << iLow
)) == 0)
696 nsCSSProperty iProp
=
697 nsCSSProperty(iHigh
* kPropertiesSetChunkSize
+ iLow
);
698 NS_ASSERTION(0 <= iProp
&& iProp
< eCSSProperty_COUNT_no_shorthands
,
701 void *prop
= PropertyAt(iProp
);
703 PRUint32 increment
= 0;
704 switch (nsCSSProps::kTypeTable
[iProp
]) {
705 case eCSSType_Value
: {
707 nsCSSValue
* val
= static_cast<nsCSSValue
*>(prop
);
708 NS_ASSERTION(val
->GetUnit() != eCSSUnit_Null
,
709 "null value while computing size");
711 increment
= CDBValueStorage_advance
;
714 case eCSSType_Rect
: {
716 nsCSSRect
* val
= static_cast<nsCSSRect
*>(prop
);
717 NS_ASSERTION(val
->HasValue(),
718 "Valueless rect while computing size");
720 increment
= CDBRectStorage_advance
;
723 case eCSSType_ValuePair
: {
725 nsCSSValuePair
* val
= static_cast<nsCSSValuePair
*>(prop
);
726 NS_ASSERTION(val
->mXValue
.GetUnit() != eCSSUnit_Null
||
727 val
->mYValue
.GetUnit() != eCSSUnit_Null
,
728 "Valueless pair while computing size");
730 increment
= CDBValuePairStorage_advance
;
733 case eCSSType_ValueList
:
734 case eCSSType_ValuePairList
: {
736 void* val
= *static_cast<void**>(prop
);
737 NS_ASSERTION(val
, "Null pointer while computing size");
739 increment
= CDBPointerStorage_advance
;
742 if ((mPropertiesImportant
[iHigh
] & (1 << iLow
)) == 0)
743 result
.normal
+= increment
;
745 result
.important
+= increment
;
752 nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock
**aNormalBlock
,
753 nsCSSCompressedDataBlock
**aImportantBlock
)
755 nsCSSCompressedDataBlock
*result_normal
, *result_important
;
756 char *cursor_normal
, *cursor_important
;
758 ComputeSizeResult size
= ComputeSize();
760 result_normal
= new(size
.normal
) nsCSSCompressedDataBlock();
761 if (!result_normal
) {
762 *aNormalBlock
= nsnull
;
763 *aImportantBlock
= nsnull
;
766 cursor_normal
= result_normal
->Block();
768 if (size
.important
!= 0) {
769 result_important
= new(size
.important
) nsCSSCompressedDataBlock();
770 if (!result_important
) {
771 delete result_normal
;
772 *aNormalBlock
= nsnull
;
773 *aImportantBlock
= nsnull
;
776 cursor_important
= result_important
->Block();
778 result_important
= nsnull
;
782 * Save needless copying and allocation by copying the memory
783 * corresponding to the stored data in the expanded block, and then
784 * clearing the data in the expanded block.
786 for (PRUint32 iHigh
= 0; iHigh
< NS_ARRAY_LENGTH(mPropertiesSet
); ++iHigh
) {
787 if (mPropertiesSet
[iHigh
] == 0)
789 for (PRInt32 iLow
= 0; iLow
< kPropertiesSetChunkSize
; ++iLow
) {
790 if ((mPropertiesSet
[iHigh
] & (1 << iLow
)) == 0)
792 nsCSSProperty iProp
=
793 nsCSSProperty(iHigh
* kPropertiesSetChunkSize
+ iLow
);
794 NS_ASSERTION(0 <= iProp
&& iProp
< eCSSProperty_COUNT_no_shorthands
,
796 void *prop
= PropertyAt(iProp
);
798 (mPropertiesImportant
[iHigh
] & (1 << iLow
)) != 0;
799 char *&cursor
= important
? cursor_important
: cursor_normal
;
800 nsCSSCompressedDataBlock
*result
=
801 important
? result_important
: result_normal
;
802 switch (nsCSSProps::kTypeTable
[iProp
]) {
803 case eCSSType_Value
: {
804 nsCSSValue
* val
= static_cast<nsCSSValue
*>(prop
);
805 NS_ASSERTION(val
->GetUnit() != eCSSUnit_Null
,
806 "Null value while compressing");
807 CDBValueStorage
*storage
=
808 reinterpret_cast<CDBValueStorage
*>(cursor
);
809 storage
->property
= iProp
;
810 memcpy(&storage
->value
, val
, sizeof(nsCSSValue
));
811 new (val
) nsCSSValue();
812 cursor
+= CDBValueStorage_advance
;
815 case eCSSType_Rect
: {
816 nsCSSRect
* val
= static_cast<nsCSSRect
*>(prop
);
817 NS_ASSERTION(val
->HasValue(),
818 "Valueless rect while compressing");
819 CDBRectStorage
*storage
=
820 reinterpret_cast<CDBRectStorage
*>(cursor
);
821 storage
->property
= iProp
;
822 memcpy(&storage
->value
, val
, sizeof(nsCSSRect
));
823 new (val
) nsCSSRect();
824 cursor
+= CDBRectStorage_advance
;
827 case eCSSType_ValuePair
: {
828 nsCSSValuePair
* val
= static_cast<nsCSSValuePair
*>(prop
);
829 NS_ASSERTION(val
->mXValue
.GetUnit() != eCSSUnit_Null
||
830 val
->mYValue
.GetUnit() != eCSSUnit_Null
,
831 "Valueless pair while compressing");
832 CDBValuePairStorage
*storage
=
833 reinterpret_cast<CDBValuePairStorage
*>(cursor
);
834 storage
->property
= iProp
;
835 memcpy(&storage
->value
, val
, sizeof(nsCSSValuePair
));
836 new (val
) nsCSSValuePair();
837 cursor
+= CDBValuePairStorage_advance
;
840 case eCSSType_ValueList
:
841 case eCSSType_ValuePairList
: {
842 void*& val
= *static_cast<void**>(prop
);
843 NS_ASSERTION(val
, "Null pointer while compressing");
844 CDBPointerStorage
*storage
=
845 reinterpret_cast<CDBPointerStorage
*>(cursor
);
846 storage
->property
= iProp
;
847 storage
->value
= val
;
849 cursor
+= CDBPointerStorage_advance
;
852 result
->mStyleBits
|=
853 nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable
[iProp
]);
857 result_normal
->mBlockEnd
= cursor_normal
;
858 NS_ASSERTION(result_normal
->DataSize() == ptrdiff_t(size
.normal
),
859 "size miscalculation");
860 if (result_important
) {
861 result_important
->mBlockEnd
= cursor_important
;
862 NS_ASSERTION(result_important
->DataSize() == ptrdiff_t(size
.important
),
863 "size miscalculation");
867 AssertInitialState();
868 *aNormalBlock
= result_normal
;
869 *aImportantBlock
= result_important
;
873 nsCSSExpandedDataBlock::Clear()
875 for (PRUint32 iHigh
= 0; iHigh
< NS_ARRAY_LENGTH(mPropertiesSet
); ++iHigh
) {
876 if (mPropertiesSet
[iHigh
] == 0)
878 for (PRInt32 iLow
= 0; iLow
< kPropertiesSetChunkSize
; ++iLow
) {
879 if ((mPropertiesSet
[iHigh
] & (1 << iLow
)) == 0)
881 nsCSSProperty iProp
=
882 nsCSSProperty(iHigh
* kPropertiesSetChunkSize
+ iLow
);
883 ClearProperty(iProp
);
887 AssertInitialState();
891 nsCSSExpandedDataBlock::ClearProperty(nsCSSProperty aPropID
)
893 NS_ASSERTION(0 <= aPropID
&& aPropID
< eCSSProperty_COUNT_no_shorthands
,
896 ClearPropertyBit(aPropID
);
897 ClearImportantBit(aPropID
);
899 void *prop
= PropertyAt(aPropID
);
900 switch (nsCSSProps::kTypeTable
[aPropID
]) {
901 case eCSSType_Value
: {
902 nsCSSValue
* val
= static_cast<nsCSSValue
*>(prop
);
906 case eCSSType_Rect
: {
907 nsCSSRect
* val
= static_cast<nsCSSRect
*>(prop
);
911 case eCSSType_ValuePair
: {
912 nsCSSValuePair
* val
= static_cast<nsCSSValuePair
*>(prop
);
913 val
->mXValue
.Reset();
914 val
->mYValue
.Reset();
917 case eCSSType_ValueList
: {
918 nsCSSValueList
*& val
= *static_cast<nsCSSValueList
**>(prop
);
925 case eCSSType_ValuePairList
: {
926 nsCSSValuePairList
*& val
=
927 *static_cast<nsCSSValuePairList
**>(prop
);
938 nsCSSExpandedDataBlock::DoAssertInitialState()
941 for (i
= 0; i
< NS_ARRAY_LENGTH(mPropertiesSet
); ++i
) {
942 NS_ASSERTION(mPropertiesSet
[i
] == 0, "not initial state");
944 for (i
= 0; i
< NS_ARRAY_LENGTH(mPropertiesImportant
); ++i
) {
945 NS_ASSERTION(mPropertiesImportant
[i
] == 0, "not initial state");
948 for (i
= 0; i
< eCSSProperty_COUNT_no_shorthands
; ++i
) {
949 void *prop
= PropertyAt(nsCSSProperty(i
));
950 switch (nsCSSProps::kTypeTable
[i
]) {
951 case eCSSType_Value
: {
952 nsCSSValue
* val
= static_cast<nsCSSValue
*>(prop
);
953 NS_ASSERTION(val
->GetUnit() == eCSSUnit_Null
,
954 "not initial state");
957 case eCSSType_Rect
: {
958 nsCSSRect
* val
= static_cast<nsCSSRect
*>(prop
);
959 NS_ASSERTION(val
->mTop
.GetUnit() == eCSSUnit_Null
,
960 "not initial state");
961 NS_ASSERTION(val
->mRight
.GetUnit() == eCSSUnit_Null
,
962 "not initial state");
963 NS_ASSERTION(val
->mBottom
.GetUnit() == eCSSUnit_Null
,
964 "not initial state");
965 NS_ASSERTION(val
->mLeft
.GetUnit() == eCSSUnit_Null
,
966 "not initial state");
969 case eCSSType_ValuePair
: {
970 nsCSSValuePair
* val
= static_cast<nsCSSValuePair
*>(prop
);
971 NS_ASSERTION(val
->mXValue
.GetUnit() == eCSSUnit_Null
,
972 "not initial state");
973 NS_ASSERTION(val
->mYValue
.GetUnit() == eCSSUnit_Null
,
974 "not initial state");
977 case eCSSType_ValueList
: {
978 nsCSSValueList
* val
= *static_cast<nsCSSValueList
**>(prop
);
979 NS_ASSERTION(val
== nsnull
, "not initial state");
982 case eCSSType_ValuePairList
: {
983 nsCSSValuePairList
* val
=
984 *static_cast<nsCSSValuePairList
**>(prop
);
985 NS_ASSERTION(val
== nsnull
, "not initial state");