Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / layout / style / nsCSSDataBlock.cpp
blob4f9ccd7f3ea99007dc5ad5a4291640cb1a5ff412
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
13 * License.
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.
21 * Contributor(s):
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;
68 nsCSSValue value;
71 struct CDBRectStorage {
72 nsCSSProperty property;
73 nsCSSRect value;
77 struct CDBValuePairStorage {
78 nsCSSProperty property;
79 nsCSSValuePair value;
82 struct CDBPointerStorage {
83 nsCSSProperty property;
84 void *value;
87 enum {
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
102 * result.
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);
165 static PRBool
166 ShouldIgnoreColors(nsRuleData *aRuleData)
168 return aRuleData->mLevel != nsStyleSet::eAgentSheet &&
169 aRuleData->mLevel != nsStyleSet::eUserSheet &&
170 !aRuleData->mPresContext->UseDocumentColors();
173 nsresult
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))
181 return NS_OK;
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,
188 "out of range");
189 if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) &
190 aRuleData->mSIDs) {
191 void *prop =
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) {
202 val->StartImageLoad(
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());
214 *target = *val;
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())
245 > 0) ||
246 (u == eCSSUnit_String &&
247 !nsGkAtoms::transparent->
248 Equals(target->GetStringValue(buf))) ||
249 (u == eCSSUnit_EnumColor)) {
250 target->SetColorValue(aRuleData->
251 mPresContext->
252 DefaultBackgroundColor());
254 } else {
255 // Ignore 'color', 'border-*-color', and
256 // 'background-image'
257 *target = nsCSSValue();
262 cursor += CDBValueStorage_advance;
263 } break;
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;
278 } break;
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;
290 } break;
292 case eCSSType_ValueList:
293 if (iProp == eCSSProperty_content) {
294 for (nsCSSValueList* l = ValueListAtCursor(cursor);
295 l; l = l->mNext)
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);
301 l; l = l->mNext)
302 if (l->mValue.GetUnit() == eCSSUnit_Array) {
303 // Don't try to restart loads we've already
304 // started
305 nsCSSValue& val =
306 l->mValue.GetArrayValue()->Item(0);
307 if (val.GetUnit() == eCSSUnit_URL)
308 val.StartImageLoad(
309 aRuleData->mPresContext->Document());
312 // fall through
313 case eCSSType_ValuePairList: {
314 void** target = static_cast<void**>(prop);
315 if (!*target) {
316 void* val = PointerAtCursor(cursor);
317 NS_ASSERTION(val, "oops");
318 *target = val;
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)) {
325 *target = nsnull;
329 cursor += CDBPointerStorage_advance;
330 } break;
332 } else {
333 switch (nsCSSProps::kTypeTable[iProp]) {
334 case eCSSType_Value: {
335 cursor += CDBValueStorage_advance;
336 } break;
338 case eCSSType_Rect: {
339 cursor += CDBRectStorage_advance;
340 } break;
342 case eCSSType_ValuePair: {
343 cursor += CDBValuePairStorage_advance;
344 } break;
346 case eCSSType_ValueList:
347 case eCSSType_ValuePairList: {
348 cursor += CDBPointerStorage_advance;
349 } break;
353 NS_ASSERTION(cursor == cursor_end, "inconsistent data");
355 return NS_OK;
358 const void*
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]) &
366 mStyleBits))
367 return nsnull;
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,
374 "out of range");
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;
395 } break;
397 case eCSSType_Rect: {
398 cursor += CDBRectStorage_advance;
399 } break;
401 case eCSSType_ValuePair: {
402 cursor += CDBValuePairStorage_advance;
403 } break;
405 case eCSSType_ValueList:
406 case eCSSType_ValuePairList: {
407 cursor += CDBPointerStorage_advance;
408 } break;
411 NS_ASSERTION(cursor == cursor_end, "inconsistent data");
413 return nsnull;
416 nsCSSCompressedDataBlock*
417 nsCSSCompressedDataBlock::Clone() const
419 const char *cursor = Block(), *cursor_end = BlockEnd();
420 char *result_cursor;
422 nsCSSCompressedDataBlock *result =
423 new(cursor_end - cursor) nsCSSCompressedDataBlock();
424 if (!result)
425 return nsnull;
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,
431 "out of range");
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;
442 } break;
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;
451 } break;
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;
461 } break;
463 case eCSSType_ValueList:
464 case eCSSType_ValuePairList: {
465 void *copy;
466 NS_ASSERTION(PointerAtCursor(cursor), "oops");
467 switch (nsCSSProps::kTypeTable[iProp]) {
468 default:
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();
474 break;
475 case eCSSType_ValuePairList:
476 copy = ValuePairListAtCursor(cursor)->Clone();
477 break;
479 if (!copy) {
480 result->mBlockEnd = result_cursor;
481 result->Destroy();
482 return nsnull;
484 PointerAtCursor(result_cursor) = copy;
485 cursor += CDBPointerStorage_advance;
486 result_cursor += CDBPointerStorage_advance;
487 } break;
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");
495 return result;
498 void
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,
506 "out of range");
508 switch (nsCSSProps::kTypeTable[iProp]) {
509 case eCSSType_Value: {
510 const nsCSSValue* val = ValueAtCursor(cursor);
511 NS_ASSERTION(val->GetUnit() != eCSSUnit_Null, "oops");
512 val->~nsCSSValue();
513 cursor += CDBValueStorage_advance;
514 } break;
516 case eCSSType_Rect: {
517 const nsCSSRect* val = RectAtCursor(cursor);
518 NS_ASSERTION(val->HasValue(), "oops");
519 val->~nsCSSRect();
520 cursor += CDBRectStorage_advance;
521 } break;
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;
529 } break;
531 case eCSSType_ValueList: {
532 nsCSSValueList* val = ValueListAtCursor(cursor);
533 NS_ASSERTION(val, "oops");
534 delete val;
535 cursor += CDBPointerStorage_advance;
536 } break;
538 case eCSSType_ValuePairList: {
539 nsCSSValuePairList* val = ValuePairListAtCursor(cursor);
540 NS_ASSERTION(val, "oops");
541 delete val;
542 cursor += CDBPointerStorage_advance;
543 } break;
546 NS_ASSERTION(cursor == cursor_end, "inconsistent data");
547 delete this;
550 /* static */ nsCSSCompressedDataBlock*
551 nsCSSCompressedDataBlock::CreateEmptyBlock()
553 nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock();
554 if (!result)
555 return nsnull;
556 result->mBlockEnd = result->Block();
557 return result;
560 /*****************************************************************************/
562 nsCSSExpandedDataBlock::nsCSSExpandedDataBlock()
564 ClearSets();
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_), \
577 size_t(-1), \
578 size_t(-1) },
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"
584 #undef CSS_PROP
585 #undef CSS_PROP_BACKENDONLY
588 void
589 nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock,
590 PRBool aImportant)
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,
605 "out of range");
606 NS_ASSERTION(!HasPropertyBit(iProp),
607 "compressed block has property multiple times");
608 SetPropertyBit(iProp);
609 if (aImportant)
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
621 dest->~nsCSSValue();
622 #endif
623 memcpy(dest, val, sizeof(nsCSSValue));
624 cursor += CDBValueStorage_advance;
625 } break;
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
634 dest->~nsCSSRect();
635 #endif
636 memcpy(dest, val, sizeof(nsCSSRect));
637 cursor += CDBRectStorage_advance;
638 } break;
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();
650 #endif
651 memcpy(dest, val, sizeof(nsCSSValuePair));
652 cursor += CDBValuePairStorage_advance;
653 } break;
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");
661 *dest = val;
662 cursor += CDBPointerStorage_advance;
663 } break;
666 NS_ASSERTION(cursor == cursor_end, "inconsistent data");
668 delete aBlock;
671 void
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)
692 continue;
693 for (PRInt32 iLow = 0; iLow < kPropertiesSetChunkSize; ++iLow) {
694 if ((mPropertiesSet[iHigh] & (1 << iLow)) == 0)
695 continue;
696 nsCSSProperty iProp =
697 nsCSSProperty(iHigh * kPropertiesSetChunkSize + iLow);
698 NS_ASSERTION(0 <= iProp && iProp < eCSSProperty_COUNT_no_shorthands,
699 "out of range");
700 #ifdef DEBUG
701 void *prop = PropertyAt(iProp);
702 #endif
703 PRUint32 increment = 0;
704 switch (nsCSSProps::kTypeTable[iProp]) {
705 case eCSSType_Value: {
706 #ifdef DEBUG
707 nsCSSValue* val = static_cast<nsCSSValue*>(prop);
708 NS_ASSERTION(val->GetUnit() != eCSSUnit_Null,
709 "null value while computing size");
710 #endif
711 increment = CDBValueStorage_advance;
712 } break;
714 case eCSSType_Rect: {
715 #ifdef DEBUG
716 nsCSSRect* val = static_cast<nsCSSRect*>(prop);
717 NS_ASSERTION(val->HasValue(),
718 "Valueless rect while computing size");
719 #endif
720 increment = CDBRectStorage_advance;
721 } break;
723 case eCSSType_ValuePair: {
724 #ifdef DEBUG
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");
729 #endif
730 increment = CDBValuePairStorage_advance;
731 } break;
733 case eCSSType_ValueList:
734 case eCSSType_ValuePairList: {
735 #ifdef DEBUG
736 void* val = *static_cast<void**>(prop);
737 NS_ASSERTION(val, "Null pointer while computing size");
738 #endif
739 increment = CDBPointerStorage_advance;
740 } break;
742 if ((mPropertiesImportant[iHigh] & (1 << iLow)) == 0)
743 result.normal += increment;
744 else
745 result.important += increment;
748 return result;
751 void
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;
764 return;
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;
774 return;
776 cursor_important = result_important->Block();
777 } else {
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)
788 continue;
789 for (PRInt32 iLow = 0; iLow < kPropertiesSetChunkSize; ++iLow) {
790 if ((mPropertiesSet[iHigh] & (1 << iLow)) == 0)
791 continue;
792 nsCSSProperty iProp =
793 nsCSSProperty(iHigh * kPropertiesSetChunkSize + iLow);
794 NS_ASSERTION(0 <= iProp && iProp < eCSSProperty_COUNT_no_shorthands,
795 "out of range");
796 void *prop = PropertyAt(iProp);
797 PRBool important =
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;
813 } break;
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;
825 } break;
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;
838 } break;
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;
848 val = nsnull;
849 cursor += CDBPointerStorage_advance;
850 } break;
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");
866 ClearSets();
867 AssertInitialState();
868 *aNormalBlock = result_normal;
869 *aImportantBlock = result_important;
872 void
873 nsCSSExpandedDataBlock::Clear()
875 for (PRUint32 iHigh = 0; iHigh < NS_ARRAY_LENGTH(mPropertiesSet); ++iHigh) {
876 if (mPropertiesSet[iHigh] == 0)
877 continue;
878 for (PRInt32 iLow = 0; iLow < kPropertiesSetChunkSize; ++iLow) {
879 if ((mPropertiesSet[iHigh] & (1 << iLow)) == 0)
880 continue;
881 nsCSSProperty iProp =
882 nsCSSProperty(iHigh * kPropertiesSetChunkSize + iLow);
883 ClearProperty(iProp);
887 AssertInitialState();
890 void
891 nsCSSExpandedDataBlock::ClearProperty(nsCSSProperty aPropID)
893 NS_ASSERTION(0 <= aPropID && aPropID < eCSSProperty_COUNT_no_shorthands,
894 "out of range");
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);
903 val->Reset();
904 } break;
906 case eCSSType_Rect: {
907 nsCSSRect* val = static_cast<nsCSSRect*>(prop);
908 val->Reset();
909 } break;
911 case eCSSType_ValuePair: {
912 nsCSSValuePair* val = static_cast<nsCSSValuePair*>(prop);
913 val->mXValue.Reset();
914 val->mYValue.Reset();
915 } break;
917 case eCSSType_ValueList: {
918 nsCSSValueList*& val = *static_cast<nsCSSValueList**>(prop);
919 if (val) {
920 delete val;
921 val = nsnull;
923 } break;
925 case eCSSType_ValuePairList: {
926 nsCSSValuePairList*& val =
927 *static_cast<nsCSSValuePairList**>(prop);
928 if (val) {
929 delete val;
930 val = nsnull;
932 } break;
936 #ifdef DEBUG
937 void
938 nsCSSExpandedDataBlock::DoAssertInitialState()
940 PRUint32 i;
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");
955 } break;
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");
967 } break;
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");
975 } break;
977 case eCSSType_ValueList: {
978 nsCSSValueList* val = *static_cast<nsCSSValueList**>(prop);
979 NS_ASSERTION(val == nsnull, "not initial state");
980 } break;
982 case eCSSType_ValuePairList: {
983 nsCSSValuePairList* val =
984 *static_cast<nsCSSValuePairList**>(prop);
985 NS_ASSERTION(val == nsnull, "not initial state");
986 } break;
990 #endif