Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / style / nsRuleNode.cpp
blob2d41feb14ee46dbfc0e7c8564cc1760ad3b3abe1
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Original Author: David W. Hyatt (hyatt@netscape.com)
24 * Daniel Glazman <glazman@netscape.com>
25 * Roger B. Sidje <rbs@maths.uq.edu.au>
26 * Mats Palmgren <mats.palmgren@bredband.net>
27 * L. David Baron <dbaron@dbaron.org>
28 * Christian Biesinger <cbiesinger@web.de>
29 * Michael Ventnor <m.ventnor@gmail.com>
31 * Alternatively, the contents of this file may be used under the terms of
32 * either of the GNU General Public License Version 2 or later (the "GPL"),
33 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 * in which case the provisions of the GPL or the LGPL are applicable instead
35 * of those above. If you wish to allow use of your version of this file only
36 * under the terms of either the GPL or the LGPL, and not to allow others to
37 * use your version of this file under the terms of the MPL, indicate your
38 * decision by deleting the provisions above and replace them with the notice
39 * and other provisions required by the GPL or the LGPL. If you do not delete
40 * the provisions above, a recipient may use your version of this file under
41 * the terms of any one of the MPL, the GPL or the LGPL.
43 * ***** END LICENSE BLOCK ***** */
46 * a node in the lexicographic tree of rules that match an element,
47 * responsible for converting the rules' information into computed style
50 #include "nsRuleNode.h"
51 #include "nscore.h"
52 #include "nsIServiceManager.h"
53 #include "nsIDeviceContext.h"
54 #include "nsILookAndFeel.h"
55 #include "nsIPresShell.h"
56 #include "nsIThebesFontMetrics.h"
57 #include "gfxFont.h"
58 #include "nsStyleUtil.h"
59 #include "nsCSSPseudoElements.h"
60 #include "nsThemeConstants.h"
61 #include "nsITheme.h"
62 #include "pldhash.h"
63 #include "nsStyleContext.h"
64 #include "nsStyleSet.h"
65 #include "nsSize.h"
66 #include "imgIRequest.h"
67 #include "nsRuleData.h"
68 #include "nsILanguageAtomService.h"
69 #include "nsIStyleRule.h"
70 #include "nsBidiUtils.h"
71 #include "nsStyleStructInlines.h"
72 #include "nsStyleTransformMatrix.h"
73 #include "nsCSSKeywords.h"
74 #include "nsCSSProps.h"
77 * For storage of an |nsRuleNode|'s children in a PLDHashTable.
80 struct ChildrenHashEntry : public PLDHashEntryHdr {
81 // key is |mRuleNode->GetKey()|
82 nsRuleNode *mRuleNode;
85 /* static */ PLDHashNumber
86 nsRuleNode::ChildrenHashHashKey(PLDHashTable *aTable, const void *aKey)
88 const nsRuleNode::Key *key =
89 static_cast<const nsRuleNode::Key*>(aKey);
90 // Disagreement on importance and level for the same rule is extremely
91 // rare, so hash just on the rule.
92 return PL_DHashVoidPtrKeyStub(aTable, key->mRule);
95 /* static */ PRBool
96 nsRuleNode::ChildrenHashMatchEntry(PLDHashTable *aTable,
97 const PLDHashEntryHdr *aHdr,
98 const void *aKey)
100 const ChildrenHashEntry *entry =
101 static_cast<const ChildrenHashEntry*>(aHdr);
102 const nsRuleNode::Key *key =
103 static_cast<const nsRuleNode::Key*>(aKey);
104 return entry->mRuleNode->GetKey() == *key;
107 /* static */ PLDHashTableOps
108 nsRuleNode::ChildrenHashOps = {
109 // It's probably better to allocate the table itself using malloc and
110 // free rather than the pres shell's arena because the table doesn't
111 // grow very often and the pres shell's arena doesn't recycle very
112 // large size allocations.
113 PL_DHashAllocTable,
114 PL_DHashFreeTable,
115 ChildrenHashHashKey,
116 ChildrenHashMatchEntry,
117 PL_DHashMoveEntryStub,
118 PL_DHashClearEntryStub,
119 PL_DHashFinalizeStub,
120 NULL
124 // EnsureBlockDisplay:
125 // - if the display value (argument) is not a block-type
126 // then we set it to a valid block display value
127 // - For enforcing the floated/positioned element CSS2 rules
128 static void EnsureBlockDisplay(PRUint8& display)
130 // see if the display value is already a block
131 switch (display) {
132 case NS_STYLE_DISPLAY_NONE :
133 // never change display:none *ever*
134 case NS_STYLE_DISPLAY_TABLE :
135 case NS_STYLE_DISPLAY_BLOCK :
136 case NS_STYLE_DISPLAY_LIST_ITEM :
137 // do not muck with these at all - already blocks
138 // This is equivalent to nsStyleDisplay::IsBlockOutside. (XXX Maybe we
139 // should just call that?)
140 break;
142 case NS_STYLE_DISPLAY_INLINE_TABLE :
143 // make inline tables into tables
144 display = NS_STYLE_DISPLAY_TABLE;
145 break;
147 default :
148 // make it a block
149 display = NS_STYLE_DISPLAY_BLOCK;
153 // XXX This should really be done in the CSS parser.
154 static nsString& Unquote(nsString& aString)
156 PRUnichar start = aString.First();
157 PRUnichar end = aString.Last();
159 if ((start == end) &&
160 ((start == PRUnichar('\"')) ||
161 (start == PRUnichar('\'')))) {
162 PRInt32 length = aString.Length();
163 aString.Truncate(length - 1);
164 aString.Cut(0, 1);
166 return aString;
169 static nscoord CalcLengthWith(const nsCSSValue& aValue,
170 nscoord aFontSize,
171 const nsStyleFont* aStyleFont,
172 nsStyleContext* aStyleContext,
173 nsPresContext* aPresContext,
174 PRBool& aInherited)
176 NS_ASSERTION(aValue.IsLengthUnit(), "not a length unit");
177 NS_ASSERTION(aStyleFont || aStyleContext, "Must have style data");
178 NS_ASSERTION(aPresContext, "Must have prescontext");
180 if (aValue.IsFixedLengthUnit()) {
181 return aPresContext->TwipsToAppUnits(aValue.GetLengthTwips());
183 nsCSSUnit unit = aValue.GetUnit();
184 if (unit == eCSSUnit_Pixel) {
185 return nsPresContext::CSSPixelsToAppUnits(aValue.GetFloatValue());
187 // Common code for all units other than pixels:
188 aInherited = PR_TRUE;
189 if (!aStyleFont) {
190 aStyleFont = aStyleContext->GetStyleFont();
192 if (aFontSize == -1) {
193 // XXX Should this be aStyleFont->mSize instead to avoid taking minfontsize
194 // prefs into account?
195 aFontSize = aStyleFont->mFont.size;
197 switch (unit) {
198 case eCSSUnit_EM: {
199 return NSToCoordRoundWithClamp(aValue.GetFloatValue() * float(aFontSize));
200 // XXX scale against font metrics height instead?
202 case eCSSUnit_XHeight: {
203 nsFont font = aStyleFont->mFont;
204 font.size = aFontSize;
205 nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(font);
206 nscoord xHeight;
207 fm->GetXHeight(xHeight);
208 return NSToCoordRoundWithClamp(aValue.GetFloatValue() * float(xHeight));
210 case eCSSUnit_Char: {
211 nsFont font = aStyleFont->mFont;
212 font.size = aFontSize;
213 nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(font);
214 nsCOMPtr<nsIThebesFontMetrics> tfm(do_QueryInterface(fm));
215 gfxFloat zeroWidth = (tfm->GetThebesFontGroup()->GetFontAt(0)
216 ->GetMetrics().zeroOrAveCharWidth);
218 return NSToCoordRoundWithClamp(aValue.GetFloatValue() *
219 NS_ceil(aPresContext->AppUnitsPerDevPixel() *
220 zeroWidth));
222 default:
223 NS_NOTREACHED("unexpected unit");
224 break;
226 return 0;
229 /* static */ nscoord
230 nsRuleNode::CalcLength(const nsCSSValue& aValue,
231 nsStyleContext* aStyleContext,
232 nsPresContext* aPresContext,
233 PRBool& aInherited)
235 NS_ASSERTION(aStyleContext, "Must have style data");
237 return CalcLengthWith(aValue, -1, nsnull, aStyleContext, aPresContext, aInherited);
240 /* Inline helper function to redirect requests to CalcLength. */
241 static inline nscoord CalcLength(const nsCSSValue& aValue,
242 nsStyleContext* aStyleContext,
243 nsPresContext* aPresContext,
244 PRBool& aInherited)
246 return nsRuleNode::CalcLength(aValue, aStyleContext,
247 aPresContext, aInherited);
250 /* static */ nscoord
251 nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
252 const nsCSSValue& aValue)
254 nsStyleFont defaultFont(aPresContext);
255 PRBool inherited;
256 return CalcLengthWith(aValue, -1, &defaultFont, nsnull, aPresContext,
257 inherited);
260 #define SETCOORD_NORMAL 0x01 // N
261 #define SETCOORD_AUTO 0x02 // A
262 #define SETCOORD_INHERIT 0x04 // H
263 #define SETCOORD_PERCENT 0x08 // P
264 #define SETCOORD_FACTOR 0x10 // F
265 #define SETCOORD_LENGTH 0x20 // L
266 #define SETCOORD_INTEGER 0x40 // I
267 #define SETCOORD_ENUMERATED 0x80 // E
268 #define SETCOORD_NONE 0x100 // O
269 #define SETCOORD_INITIAL_ZERO 0x200
270 #define SETCOORD_INITIAL_AUTO 0x400
271 #define SETCOORD_INITIAL_NONE 0x800
272 #define SETCOORD_INITIAL_NORMAL 0x1000
273 #define SETCOORD_INITIAL_HALF 0x2000
275 #define SETCOORD_LP (SETCOORD_LENGTH | SETCOORD_PERCENT)
276 #define SETCOORD_LH (SETCOORD_LENGTH | SETCOORD_INHERIT)
277 #define SETCOORD_AH (SETCOORD_AUTO | SETCOORD_INHERIT)
278 #define SETCOORD_LAH (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
279 #define SETCOORD_LPH (SETCOORD_LP | SETCOORD_INHERIT)
280 #define SETCOORD_LPAH (SETCOORD_LP | SETCOORD_AH)
281 #define SETCOORD_LPEH (SETCOORD_LP | SETCOORD_ENUMERATED | SETCOORD_INHERIT)
282 #define SETCOORD_LPAEH (SETCOORD_LPAH | SETCOORD_ENUMERATED)
283 #define SETCOORD_LPOH (SETCOORD_LPH | SETCOORD_NONE)
284 #define SETCOORD_LPOEH (SETCOORD_LPOH | SETCOORD_ENUMERATED)
285 #define SETCOORD_LE (SETCOORD_LENGTH | SETCOORD_ENUMERATED)
286 #define SETCOORD_LEH (SETCOORD_LE | SETCOORD_INHERIT)
287 #define SETCOORD_IA (SETCOORD_INTEGER | SETCOORD_AUTO)
288 #define SETCOORD_LAE (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
290 // changes aCoord iff it returns PR_TRUE
291 static PRBool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
292 const nsStyleCoord& aParentCoord,
293 PRInt32 aMask, nsStyleContext* aStyleContext,
294 nsPresContext* aPresContext, PRBool& aInherited)
296 PRBool result = PR_TRUE;
297 if (aValue.GetUnit() == eCSSUnit_Null) {
298 result = PR_FALSE;
300 else if (((aMask & SETCOORD_LENGTH) != 0) &&
301 aValue.IsLengthUnit()) {
302 aCoord.SetCoordValue(CalcLength(aValue, aStyleContext, aPresContext, aInherited));
304 else if (((aMask & SETCOORD_PERCENT) != 0) &&
305 (aValue.GetUnit() == eCSSUnit_Percent)) {
306 aCoord.SetPercentValue(aValue.GetPercentValue());
308 else if (((aMask & SETCOORD_INTEGER) != 0) &&
309 (aValue.GetUnit() == eCSSUnit_Integer)) {
310 aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Integer);
312 else if (((aMask & SETCOORD_ENUMERATED) != 0) &&
313 (aValue.GetUnit() == eCSSUnit_Enumerated)) {
314 aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Enumerated);
316 else if (((aMask & SETCOORD_AUTO) != 0) &&
317 (aValue.GetUnit() == eCSSUnit_Auto)) {
318 aCoord.SetAutoValue();
320 else if (((aMask & SETCOORD_INHERIT) != 0) &&
321 (aValue.GetUnit() == eCSSUnit_Inherit)) {
322 aCoord = aParentCoord; // just inherit value from parent
323 aInherited = PR_TRUE;
325 else if (((aMask & SETCOORD_NORMAL) != 0) &&
326 (aValue.GetUnit() == eCSSUnit_Normal)) {
327 aCoord.SetNormalValue();
329 else if (((aMask & SETCOORD_NONE) != 0) &&
330 (aValue.GetUnit() == eCSSUnit_None)) {
331 aCoord.SetNoneValue();
333 else if (((aMask & SETCOORD_FACTOR) != 0) &&
334 (aValue.GetUnit() == eCSSUnit_Number)) {
335 aCoord.SetFactorValue(aValue.GetFloatValue());
337 else if (((aMask & SETCOORD_INITIAL_AUTO) != 0) &&
338 (aValue.GetUnit() == eCSSUnit_Initial)) {
339 aCoord.SetAutoValue();
341 else if (((aMask & SETCOORD_INITIAL_ZERO) != 0) &&
342 (aValue.GetUnit() == eCSSUnit_Initial)) {
343 aCoord.SetCoordValue(0);
345 else if (((aMask & SETCOORD_INITIAL_NONE) != 0) &&
346 (aValue.GetUnit() == eCSSUnit_Initial)) {
347 aCoord.SetNoneValue();
349 else if (((aMask & SETCOORD_INITIAL_NORMAL) != 0) &&
350 (aValue.GetUnit() == eCSSUnit_Initial)) {
351 aCoord.SetNormalValue();
353 else if (((aMask & SETCOORD_INITIAL_HALF) != 0) &&
354 (aValue.GetUnit() == eCSSUnit_Initial)) {
355 aCoord.SetPercentValue(0.5f);
357 else {
358 result = PR_FALSE; // didn't set anything
360 return result;
363 /* Given an enumerated value that represents a box position, converts it to
364 * a float representing the percentage of the box it corresponds to. For
365 * example, "center" becomes 0.5f.
367 * @param aEnumValue The enumerated value.
368 * @return The float percent it corresponds to.
370 static float GetFloatFromBoxPosition(PRInt32 aEnumValue)
372 switch (aEnumValue) {
373 case NS_STYLE_BG_POSITION_LEFT:
374 case NS_STYLE_BG_POSITION_TOP:
375 return 0.0f;
376 case NS_STYLE_BG_POSITION_RIGHT:
377 case NS_STYLE_BG_POSITION_BOTTOM:
378 return 1.0f;
379 default:
380 NS_NOTREACHED("unexpected value");
381 // fall through
382 case NS_STYLE_BG_POSITION_CENTER:
383 return 0.5f;
387 static PRBool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
388 nsPresContext* aPresContext, nsStyleContext *aContext,
389 nscolor& aResult, PRBool& aInherited)
391 PRBool result = PR_FALSE;
392 nsCSSUnit unit = aValue.GetUnit();
394 if (eCSSUnit_Color == unit) {
395 aResult = aValue.GetColorValue();
396 result = PR_TRUE;
398 else if (eCSSUnit_String == unit) {
399 nsAutoString value;
400 aValue.GetStringValue(value);
401 nscolor rgba;
402 if (NS_ColorNameToRGB(value, &rgba)) {
403 aResult = rgba;
404 result = PR_TRUE;
407 else if (eCSSUnit_EnumColor == unit) {
408 PRInt32 intValue = aValue.GetIntValue();
409 if (0 <= intValue) {
410 nsILookAndFeel* look = aPresContext->LookAndFeel();
411 nsILookAndFeel::nsColorID colorID = (nsILookAndFeel::nsColorID) intValue;
412 if (NS_SUCCEEDED(look->GetColor(colorID, aResult))) {
413 result = PR_TRUE;
416 else {
417 switch (intValue) {
418 case NS_COLOR_MOZ_HYPERLINKTEXT:
419 aResult = aPresContext->DefaultLinkColor();
420 break;
421 case NS_COLOR_MOZ_VISITEDHYPERLINKTEXT:
422 aResult = aPresContext->DefaultVisitedLinkColor();
423 break;
424 case NS_COLOR_MOZ_ACTIVEHYPERLINKTEXT:
425 aResult = aPresContext->DefaultActiveLinkColor();
426 break;
427 case NS_COLOR_CURRENTCOLOR:
428 // The data computed from this can't be shared in the rule tree
429 // because they could be used on a node with a different color
430 aInherited = PR_TRUE;
431 aResult = aContext->GetStyleColor()->mColor;
432 break;
433 default:
434 NS_NOTREACHED("Should never have an unknown negative colorID.");
435 break;
437 result = PR_TRUE;
440 else if (eCSSUnit_Inherit == unit) {
441 aResult = aParentColor;
442 result = PR_TRUE;
443 aInherited = PR_TRUE;
445 return result;
448 // flags for SetDiscrete - align values with SETCOORD_* constants
449 // where possible
451 #define SETDSC_NORMAL 0x01 // N
452 #define SETDSC_AUTO 0x02 // A
453 #define SETDSC_INTEGER 0x40 // I
454 #define SETDSC_ENUMERATED 0x80 // E
455 #define SETDSC_NONE 0x100 // O
456 #define SETDSC_SYSTEM_FONT 0x2000
458 // no caller cares whether aField was changed or not
459 template <typename FieldT,
460 typename T1, typename T2, typename T3, typename T4, typename T5>
461 static void
462 SetDiscrete(const nsCSSValue& aValue, FieldT & aField,
463 PRBool& aInherited, PRUint32 aMask,
464 FieldT aParentValue,
465 T1 aInitialValue,
466 T2 aAutoValue,
467 T3 aNoneValue,
468 T4 aNormalValue,
469 T5 aSystemFontValue)
471 switch (aValue.GetUnit()) {
472 case eCSSUnit_Null:
473 return;
475 // every caller of SetDiscrete provides inherit and initial
476 // alternatives, so we don't require them to say so in the mask
477 case eCSSUnit_Inherit:
478 aInherited = PR_TRUE;
479 aField = aParentValue;
480 return;
482 case eCSSUnit_Initial:
483 aField = aInitialValue;
484 return;
486 // every caller provides one or other of these alternatives,
487 // but they have to say which
488 case eCSSUnit_Enumerated:
489 if (aMask & SETDSC_ENUMERATED) {
490 aField = aValue.GetIntValue();
491 return;
493 break;
495 case eCSSUnit_Integer:
496 if (aMask & SETDSC_INTEGER) {
497 aField = aValue.GetIntValue();
498 return;
500 break;
502 // remaining possibilities in descending order of frequency of use
503 case eCSSUnit_Auto:
504 if (aMask & SETDSC_AUTO) {
505 aField = aAutoValue;
506 return;
508 break;
510 case eCSSUnit_None:
511 if (aMask & SETDSC_NONE) {
512 aField = aNoneValue;
513 return;
515 break;
517 case eCSSUnit_Normal:
518 if (aMask & SETDSC_NORMAL) {
519 aField = aNormalValue;
520 return;
522 break;
524 case eCSSUnit_System_Font:
525 if (aMask & SETDSC_SYSTEM_FONT) {
526 aField = aSystemFontValue;
527 return;
529 break;
531 default:
532 break;
535 NS_NOTREACHED("SetDiscrete: inappropriate unit");
538 // flags for SetFactor
539 #define SETFCT_POSITIVE 0x01 // assert value is >= 0.0f
540 #define SETFCT_OPACITY 0x02 // clamp value to [0.0f .. 1.0f]
541 #define SETFCT_NONE 0x04 // allow _None (uses aInitialValue).
543 static void
544 SetFactor(const nsCSSValue& aValue, float& aField, PRBool& aInherited,
545 float aParentValue, float aInitialValue, PRUint32 aFlags = 0)
547 switch (aValue.GetUnit()) {
548 case eCSSUnit_Null:
549 return;
551 case eCSSUnit_Number:
552 aField = aValue.GetFloatValue();
553 if (aFlags & SETFCT_POSITIVE) {
554 NS_ASSERTION(aField >= 0.0f, "negative value for positive-only property");
555 if (aField < 0.0f)
556 aField = 0.0f;
558 if (aFlags & SETFCT_OPACITY) {
559 if (aField < 0.0f)
560 aField = 0.0f;
561 if (aField > 1.0f)
562 aField = 1.0f;
564 return;
566 case eCSSUnit_Inherit:
567 aInherited = PR_TRUE;
568 aField = aParentValue;
569 return;
571 case eCSSUnit_Initial:
572 aField = aInitialValue;
573 return;
575 case eCSSUnit_None:
576 if (aFlags & SETFCT_NONE) {
577 aField = aInitialValue;
578 return;
580 break;
582 default:
583 break;
586 NS_NOTREACHED("SetFactor: inappropriate unit");
589 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
590 // (which comes from the presShell) to perform the allocation.
591 void*
592 nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
594 // Check the recycle list first.
595 return aPresContext->AllocateFromShell(sz);
598 /* static */ PLDHashOperator
599 nsRuleNode::EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
600 PRUint32 number, void *arg)
602 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
603 nsRuleNode ***destroyQueueTail = static_cast<nsRuleNode***>(arg);
604 **destroyQueueTail = entry->mRuleNode;
605 *destroyQueueTail = &entry->mRuleNode->mNextSibling;
606 return PL_DHASH_NEXT;
609 // Overridden to prevent the global delete from being called, since the memory
610 // came out of an nsIArena instead of the global delete operator's heap.
611 void
612 nsRuleNode::DestroyInternal(nsRuleNode ***aDestroyQueueTail)
614 nsRuleNode *destroyQueue, **destroyQueueTail;
615 if (aDestroyQueueTail) {
616 destroyQueueTail = *aDestroyQueueTail;
617 } else {
618 destroyQueue = nsnull;
619 destroyQueueTail = &destroyQueue;
622 if (ChildrenAreHashed()) {
623 PLDHashTable *children = ChildrenHash();
624 PL_DHashTableEnumerate(children, EnqueueRuleNodeChildren,
625 &destroyQueueTail);
626 *destroyQueueTail = nsnull; // ensure null-termination
627 PL_DHashTableDestroy(children);
628 } else if (HaveChildren()) {
629 *destroyQueueTail = ChildrenList();
630 do {
631 destroyQueueTail = &(*destroyQueueTail)->mNextSibling;
632 } while (*destroyQueueTail);
634 mChildren.asVoid = nsnull;
636 if (aDestroyQueueTail) {
637 // Our caller destroys the queue.
638 *aDestroyQueueTail = destroyQueueTail;
639 } else {
640 // We have to do destroy the queue. When we destroy each node, it
641 // will add its children to the queue.
642 while (destroyQueue) {
643 nsRuleNode *cur = destroyQueue;
644 destroyQueue = destroyQueue->mNextSibling;
645 if (!destroyQueue) {
646 NS_ASSERTION(destroyQueueTail == &cur->mNextSibling, "mangled list");
647 destroyQueueTail = &destroyQueue;
649 cur->DestroyInternal(&destroyQueueTail);
653 // Destroy ourselves.
654 this->~nsRuleNode();
656 // Don't let the memory be freed, since it will be recycled
657 // instead. Don't call the global operator delete.
658 mPresContext->FreeToShell(sizeof(nsRuleNode), this);
661 nsRuleNode* nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
663 return new (aPresContext)
664 nsRuleNode(aPresContext, nsnull, nsnull, 0xff, PR_FALSE);
667 nsILanguageAtomService* nsRuleNode::gLangService = nsnull;
669 nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
670 nsIStyleRule* aRule, PRUint8 aLevel,
671 PRBool aIsImportant)
672 : mPresContext(aContext),
673 mParent(aParent),
674 mRule(aRule),
675 mDependentBits((PRUint32(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
676 (aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
677 mNoneBits(0)
679 mChildren.asVoid = nsnull;
680 MOZ_COUNT_CTOR(nsRuleNode);
681 NS_IF_ADDREF(mRule);
683 NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
684 NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
687 nsRuleNode::~nsRuleNode()
689 MOZ_COUNT_DTOR(nsRuleNode);
690 if (mStyleData.mResetData || mStyleData.mInheritedData)
691 mStyleData.Destroy(0, mPresContext);
692 NS_IF_RELEASE(mRule);
695 nsRuleNode*
696 nsRuleNode::Transition(nsIStyleRule* aRule, PRUint8 aLevel,
697 PRPackedBool aIsImportantRule)
699 nsRuleNode* next = nsnull;
700 nsRuleNode::Key key(aRule, aLevel, aIsImportantRule);
702 if (HaveChildren() && !ChildrenAreHashed()) {
703 PRInt32 numKids = 0;
704 nsRuleNode* curr = ChildrenList();
705 while (curr && curr->GetKey() != key) {
706 curr = curr->mNextSibling;
707 ++numKids;
709 if (curr)
710 next = curr;
711 else if (numKids >= kMaxChildrenInList)
712 ConvertChildrenToHash();
715 if (ChildrenAreHashed()) {
716 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>
717 (PL_DHashTableOperate(ChildrenHash(), &key, PL_DHASH_ADD));
718 if (!entry) {
719 return nsnull;
721 if (entry->mRuleNode)
722 next = entry->mRuleNode;
723 else {
724 next = entry->mRuleNode = new (mPresContext)
725 nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
726 if (!next) {
727 PL_DHashTableRawRemove(ChildrenHash(), entry);
728 return nsnull;
731 } else if (!next) {
732 // Create the new entry in our list.
733 next = new (mPresContext)
734 nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
735 if (!next) {
736 return nsnull;
738 next->mNextSibling = ChildrenList();
739 SetChildrenList(next);
742 return next;
745 void
746 nsRuleNode::ConvertChildrenToHash()
748 NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
749 "must have a non-empty list of children");
750 PLDHashTable *hash = PL_NewDHashTable(&ChildrenHashOps, nsnull,
751 sizeof(ChildrenHashEntry),
752 kMaxChildrenInList * 4);
753 if (!hash)
754 return;
755 for (nsRuleNode* curr = ChildrenList(); curr; curr = curr->mNextSibling) {
756 // This will never fail because of the initial size we gave the table.
757 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(
758 PL_DHashTableOperate(hash, curr->mRule, PL_DHASH_ADD));
759 NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
760 entry->mRuleNode = curr;
762 SetChildrenHash(hash);
765 inline void
766 nsRuleNode::PropagateNoneBit(PRUint32 aBit, nsRuleNode* aHighestNode)
768 nsRuleNode* curr = this;
769 for (;;) {
770 NS_ASSERTION(!(curr->mNoneBits & aBit), "propagating too far");
771 curr->mNoneBits |= aBit;
772 if (curr == aHighestNode)
773 break;
774 curr = curr->mParent;
778 inline void
779 nsRuleNode::PropagateDependentBit(PRUint32 aBit, nsRuleNode* aHighestNode)
781 for (nsRuleNode* curr = this; curr != aHighestNode; curr = curr->mParent) {
782 if (curr->mDependentBits & aBit) {
783 #ifdef DEBUG
784 while (curr != aHighestNode) {
785 NS_ASSERTION(curr->mDependentBits & aBit, "bit not set");
786 curr = curr->mParent;
788 #endif
789 break;
792 curr->mDependentBits |= aBit;
797 * The following "Check" functions are used for determining what type of
798 * sharing can be used for the data on this rule node. MORE HERE...
801 /* the information for a property (or in some cases, a rect group of
802 properties) */
804 struct PropertyCheckData {
805 size_t offset;
806 // These duplicate the same data in nsCSSProps::kTypeTable and
807 // kFlagsTable, except that we have some extra entries for
808 // CSS_PROP_INCLUDE_NOT_CSS.
809 nsCSSType type;
810 PRUint32 flags;
814 * a callback function that that can revise the result of
815 * CheckSpecifiedProperties before finishing; aResult is the current
816 * result, and it returns the revised one.
818 typedef nsRuleNode::RuleDetail
819 (* CheckCallbackFn)(const nsRuleDataStruct& aData,
820 nsRuleNode::RuleDetail aResult);
822 /* the information for all the properties in a style struct */
823 struct StructCheckData {
824 const PropertyCheckData* props;
825 PRInt32 nprops;
826 CheckCallbackFn callback;
831 * @param aValue the value being examined
832 * @param aSpecifiedCount to be incremented by one if the value is specified
833 * @param aInherited to be incremented by one if the value is set to inherit
835 inline void
836 ExamineCSSValue(const nsCSSValue& aValue,
837 PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
839 if (aValue.GetUnit() != eCSSUnit_Null) {
840 ++aSpecifiedCount;
841 if (aValue.GetUnit() == eCSSUnit_Inherit) {
842 ++aInheritedCount;
847 static void
848 ExamineCSSValuePair(const nsCSSValuePair* aValuePair,
849 PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
851 NS_PRECONDITION(aValuePair, "Must have a value pair");
853 ExamineCSSValue(aValuePair->mXValue, aSpecifiedCount, aInheritedCount);
854 ExamineCSSValue(aValuePair->mYValue, aSpecifiedCount, aInheritedCount);
857 static void
858 ExamineCSSRect(const nsCSSRect* aRect,
859 PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
861 NS_PRECONDITION(aRect, "Must have a rect");
863 NS_FOR_CSS_SIDES(side) {
864 ExamineCSSValue(aRect->*(nsCSSRect::sides[side]),
865 aSpecifiedCount, aInheritedCount);
869 static nsRuleNode::RuleDetail
870 CheckFontCallback(const nsRuleDataStruct& aData,
871 nsRuleNode::RuleDetail aResult)
873 const nsRuleDataFont& fontData =
874 static_cast<const nsRuleDataFont&>(aData);
876 // em, ex, percent, 'larger', and 'smaller' values on font-size depend
877 // on the parent context's font-size
878 // Likewise, 'lighter' and 'bolder' values of 'font-weight' depend on
879 // the parent.
880 const nsCSSValue& size = fontData.mSize;
881 const nsCSSValue& weight = fontData.mWeight;
882 if ((size.IsRelativeLengthUnit() && size.GetUnit() != eCSSUnit_Pixel) ||
883 size.GetUnit() == eCSSUnit_Percent ||
884 (size.GetUnit() == eCSSUnit_Enumerated &&
885 (size.GetIntValue() == NS_STYLE_FONT_SIZE_SMALLER ||
886 size.GetIntValue() == NS_STYLE_FONT_SIZE_LARGER)) ||
887 #ifdef MOZ_MATHML
888 fontData.mScriptLevel.GetUnit() == eCSSUnit_Integer ||
889 #endif
890 (weight.GetUnit() == eCSSUnit_Enumerated &&
891 (weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_BOLDER ||
892 weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_LIGHTER))) {
893 NS_ASSERTION(aResult == nsRuleNode::eRulePartialReset ||
894 aResult == nsRuleNode::eRuleFullReset ||
895 aResult == nsRuleNode::eRulePartialMixed ||
896 aResult == nsRuleNode::eRuleFullMixed,
897 "we know we already have a reset-counted property");
898 // Promote reset to mixed since we have something that depends on
899 // the parent. But never promote to inherited since that could
900 // cause inheritance of the exact value.
901 if (aResult == nsRuleNode::eRulePartialReset)
902 aResult = nsRuleNode::eRulePartialMixed;
903 else if (aResult == nsRuleNode::eRuleFullReset)
904 aResult = nsRuleNode::eRuleFullMixed;
907 return aResult;
910 static nsRuleNode::RuleDetail
911 CheckColorCallback(const nsRuleDataStruct& aData,
912 nsRuleNode::RuleDetail aResult)
914 const nsRuleDataColor& colorData =
915 static_cast<const nsRuleDataColor&>(aData);
917 // currentColor values for color require inheritance
918 if (colorData.mColor.GetUnit() == eCSSUnit_EnumColor &&
919 colorData.mColor.GetIntValue() == NS_COLOR_CURRENTCOLOR) {
920 NS_ASSERTION(aResult == nsRuleNode::eRuleFullReset,
921 "we should already be counted as full-reset");
922 aResult = nsRuleNode::eRuleFullInherited;
925 return aResult;
929 // for nsCSSPropList.h, so we get information on things in the style
930 // structs but not nsCSS*
931 #define CSS_PROP_INCLUDE_NOT_CSS
933 #define CHECK_DATA_FOR_PROPERTY(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
934 { offsetof(nsRuleData##datastruct_, member_), type_, flags_ },
936 static const PropertyCheckData FontCheckProperties[] = {
937 #define CSS_PROP_FONT CHECK_DATA_FOR_PROPERTY
938 #include "nsCSSPropList.h"
939 #undef CSS_PROP_FONT
942 static const PropertyCheckData DisplayCheckProperties[] = {
943 #define CSS_PROP_DISPLAY CHECK_DATA_FOR_PROPERTY
944 #include "nsCSSPropList.h"
945 #undef CSS_PROP_DISPLAY
948 static const PropertyCheckData VisibilityCheckProperties[] = {
949 #define CSS_PROP_VISIBILITY CHECK_DATA_FOR_PROPERTY
950 #include "nsCSSPropList.h"
951 #undef CSS_PROP_VISIBILITY
954 static const PropertyCheckData MarginCheckProperties[] = {
955 #define CSS_PROP_MARGIN CHECK_DATA_FOR_PROPERTY
956 #include "nsCSSPropList.h"
957 #undef CSS_PROP_MARGIN
960 static const PropertyCheckData BorderCheckProperties[] = {
961 #define CSS_PROP_BORDER CHECK_DATA_FOR_PROPERTY
962 #include "nsCSSPropList.h"
963 #undef CSS_PROP_BORDER
966 static const PropertyCheckData PaddingCheckProperties[] = {
967 #define CSS_PROP_PADDING CHECK_DATA_FOR_PROPERTY
968 #include "nsCSSPropList.h"
969 #undef CSS_PROP_PADDING
972 static const PropertyCheckData OutlineCheckProperties[] = {
973 #define CSS_PROP_OUTLINE CHECK_DATA_FOR_PROPERTY
974 #include "nsCSSPropList.h"
975 #undef CSS_PROP_OUTLINE
978 static const PropertyCheckData ListCheckProperties[] = {
979 #define CSS_PROP_LIST CHECK_DATA_FOR_PROPERTY
980 #include "nsCSSPropList.h"
981 #undef CSS_PROP_LIST
984 static const PropertyCheckData ColorCheckProperties[] = {
985 #define CSS_PROP_COLOR CHECK_DATA_FOR_PROPERTY
986 #include "nsCSSPropList.h"
987 #undef CSS_PROP_COLOR
990 static const PropertyCheckData BackgroundCheckProperties[] = {
991 #define CSS_PROP_BACKGROUND CHECK_DATA_FOR_PROPERTY
992 #include "nsCSSPropList.h"
993 #undef CSS_PROP_BACKGROUND
996 static const PropertyCheckData PositionCheckProperties[] = {
997 #define CSS_PROP_POSITION CHECK_DATA_FOR_PROPERTY
998 #include "nsCSSPropList.h"
999 #undef CSS_PROP_POSITION
1002 static const PropertyCheckData TableCheckProperties[] = {
1003 #define CSS_PROP_TABLE CHECK_DATA_FOR_PROPERTY
1004 #include "nsCSSPropList.h"
1005 #undef CSS_PROP_TABLE
1008 static const PropertyCheckData TableBorderCheckProperties[] = {
1009 #define CSS_PROP_TABLEBORDER CHECK_DATA_FOR_PROPERTY
1010 #include "nsCSSPropList.h"
1011 #undef CSS_PROP_TABLEBORDER
1014 static const PropertyCheckData ContentCheckProperties[] = {
1015 #define CSS_PROP_CONTENT CHECK_DATA_FOR_PROPERTY
1016 #include "nsCSSPropList.h"
1017 #undef CSS_PROP_CONTENT
1020 static const PropertyCheckData QuotesCheckProperties[] = {
1021 #define CSS_PROP_QUOTES CHECK_DATA_FOR_PROPERTY
1022 #include "nsCSSPropList.h"
1023 #undef CSS_PROP_QUOTES
1026 static const PropertyCheckData TextCheckProperties[] = {
1027 #define CSS_PROP_TEXT CHECK_DATA_FOR_PROPERTY
1028 #include "nsCSSPropList.h"
1029 #undef CSS_PROP_TEXT
1032 static const PropertyCheckData TextResetCheckProperties[] = {
1033 #define CSS_PROP_TEXTRESET CHECK_DATA_FOR_PROPERTY
1034 #include "nsCSSPropList.h"
1035 #undef CSS_PROP_TEXTRESET
1038 static const PropertyCheckData UserInterfaceCheckProperties[] = {
1039 #define CSS_PROP_USERINTERFACE CHECK_DATA_FOR_PROPERTY
1040 #include "nsCSSPropList.h"
1041 #undef CSS_PROP_USERINTERFACE
1044 static const PropertyCheckData UIResetCheckProperties[] = {
1045 #define CSS_PROP_UIRESET CHECK_DATA_FOR_PROPERTY
1046 #include "nsCSSPropList.h"
1047 #undef CSS_PROP_UIRESET
1050 static const PropertyCheckData XULCheckProperties[] = {
1051 #define CSS_PROP_XUL CHECK_DATA_FOR_PROPERTY
1052 #include "nsCSSPropList.h"
1053 #undef CSS_PROP_XUL
1056 #ifdef MOZ_SVG
1057 static const PropertyCheckData SVGCheckProperties[] = {
1058 #define CSS_PROP_SVG CHECK_DATA_FOR_PROPERTY
1059 #include "nsCSSPropList.h"
1060 #undef CSS_PROP_SVG
1063 static const PropertyCheckData SVGResetCheckProperties[] = {
1064 #define CSS_PROP_SVGRESET CHECK_DATA_FOR_PROPERTY
1065 #include "nsCSSPropList.h"
1066 #undef CSS_PROP_SVGRESET
1068 #endif
1070 static const PropertyCheckData ColumnCheckProperties[] = {
1071 #define CSS_PROP_COLUMN CHECK_DATA_FOR_PROPERTY
1072 #include "nsCSSPropList.h"
1073 #undef CSS_PROP_COLUMN
1076 #undef CSS_PROP_INCLUDE_NOT_CSS
1077 #undef CHECK_DATA_FOR_PROPERTY
1079 static const StructCheckData gCheckProperties[] = {
1081 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
1082 {name##CheckProperties, \
1083 sizeof(name##CheckProperties)/sizeof(PropertyCheckData), \
1084 checkdata_cb},
1085 #include "nsStyleStructList.h"
1086 #undef STYLE_STRUCT
1087 {nsnull, 0, nsnull}
1093 // XXXldb Taking the address of a reference is evil.
1095 inline nsCSSValue&
1096 ValueAtOffset(nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1098 return * reinterpret_cast<nsCSSValue*>
1099 (reinterpret_cast<char*>(&aRuleDataStruct) + aOffset);
1102 inline const nsCSSValue&
1103 ValueAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1105 return * reinterpret_cast<const nsCSSValue*>
1106 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1109 inline nsCSSRect*
1110 RectAtOffset(nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1112 return reinterpret_cast<nsCSSRect*>
1113 (reinterpret_cast<char*>(&aRuleDataStruct) + aOffset);
1116 inline const nsCSSRect*
1117 RectAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1119 return reinterpret_cast<const nsCSSRect*>
1120 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1123 inline nsCSSValuePair*
1124 ValuePairAtOffset(nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1126 return reinterpret_cast<nsCSSValuePair*>
1127 (reinterpret_cast<char*>(&aRuleDataStruct) + aOffset);
1130 inline const nsCSSValuePair*
1131 ValuePairAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1133 return reinterpret_cast<const nsCSSValuePair*>
1134 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1137 inline nsCSSValueList*&
1138 ValueListAtOffset(nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1140 return * reinterpret_cast<nsCSSValueList**>
1141 (reinterpret_cast<char*>(&aRuleDataStruct) + aOffset);
1144 inline const nsCSSValueList*
1145 ValueListAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1147 return * reinterpret_cast<const nsCSSValueList*const*>
1148 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1151 inline nsCSSValuePairList*&
1152 ValuePairListAtOffset(nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1154 return * reinterpret_cast<nsCSSValuePairList**>
1155 (reinterpret_cast<char*>(&aRuleDataStruct) + aOffset);
1158 inline const nsCSSValuePairList*
1159 ValuePairListAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1161 return * reinterpret_cast<const nsCSSValuePairList*const*>
1162 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1165 #if defined(MOZ_MATHML) && defined(DEBUG)
1166 static PRBool
1167 AreAllMathMLPropertiesUndefined(const nsCSSFont& aRuleData)
1169 return aRuleData.mScriptLevel.GetUnit() == eCSSUnit_Null &&
1170 aRuleData.mScriptSizeMultiplier.GetUnit() == eCSSUnit_Null &&
1171 aRuleData.mScriptMinSize.GetUnit() == eCSSUnit_Null;
1173 #endif
1175 inline nsRuleNode::RuleDetail
1176 nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID,
1177 const nsRuleDataStruct& aRuleDataStruct)
1179 const StructCheckData *structData = gCheckProperties + aSID;
1181 // Build a count of the:
1182 PRUint32 total = 0, // total number of props in the struct
1183 specified = 0, // number that were specified for this node
1184 inherited = 0; // number that were 'inherit' (and not
1185 // eCSSUnit_Inherit) for this node
1187 for (const PropertyCheckData *prop = structData->props,
1188 *prop_end = prop + structData->nprops;
1189 prop != prop_end;
1190 ++prop)
1191 switch (prop->type) {
1193 case eCSSType_Value:
1194 ++total;
1195 ExamineCSSValue(ValueAtOffset(aRuleDataStruct, prop->offset),
1196 specified, inherited);
1197 break;
1199 case eCSSType_Rect:
1200 total += 4;
1201 ExamineCSSRect(RectAtOffset(aRuleDataStruct, prop->offset),
1202 specified, inherited);
1203 break;
1205 case eCSSType_ValuePair:
1206 total += 2;
1207 ExamineCSSValuePair(ValuePairAtOffset(aRuleDataStruct, prop->offset),
1208 specified, inherited);
1209 break;
1211 case eCSSType_ValueList:
1213 ++total;
1214 const nsCSSValueList* valueList =
1215 ValueListAtOffset(aRuleDataStruct, prop->offset);
1216 if (valueList) {
1217 ++specified;
1218 if (eCSSUnit_Inherit == valueList->mValue.GetUnit()) {
1219 ++inherited;
1223 break;
1225 case eCSSType_ValuePairList:
1227 ++total;
1228 const nsCSSValuePairList* valuePairList =
1229 ValuePairListAtOffset(aRuleDataStruct, prop->offset);
1230 if (valuePairList) {
1231 ++specified;
1232 if (eCSSUnit_Inherit == valuePairList->mXValue.GetUnit()) {
1233 ++inherited;
1237 break;
1239 default:
1240 NS_NOTREACHED("unknown type");
1241 break;
1245 #if 0
1246 printf("CheckSpecifiedProperties: SID=%d total=%d spec=%d inh=%d.\n",
1247 aSID, total, specified, inherited);
1248 #endif
1250 #ifdef MOZ_MATHML
1251 NS_ASSERTION(aSID != eStyleStruct_Font ||
1252 mPresContext->Document()->GetMathMLEnabled() ||
1253 AreAllMathMLPropertiesUndefined(static_cast<const nsCSSFont&>(aRuleDataStruct)),
1254 "MathML style property was defined even though MathML is disabled");
1255 #endif
1258 * Return the most specific information we can: prefer None or Full
1259 * over Partial, and Reset or Inherited over Mixed, since we can
1260 * optimize based on the edge cases and not the in-between cases.
1262 nsRuleNode::RuleDetail result;
1263 if (inherited == total)
1264 result = eRuleFullInherited;
1265 else if (specified == total
1266 #ifdef MOZ_MATHML
1267 // MathML defines 3 properties in Font that will never be set when
1268 // MathML is not in use. Therefore if all but three
1269 // properties have been set, and MathML is not enabled, we can treat
1270 // this as fully specified. Code in nsMathMLElementFactory will
1271 // rebuild the rule tree and style data when MathML is first enabled
1272 // (see nsMathMLElement::BindToTree).
1273 || (aSID == eStyleStruct_Font && specified + 3 == total &&
1274 !mPresContext->Document()->GetMathMLEnabled())
1275 #endif
1277 if (inherited == 0)
1278 result = eRuleFullReset;
1279 else
1280 result = eRuleFullMixed;
1281 } else if (specified == 0)
1282 result = eRuleNone;
1283 else if (specified == inherited)
1284 result = eRulePartialInherited;
1285 else if (inherited == 0)
1286 result = eRulePartialReset;
1287 else
1288 result = eRulePartialMixed;
1290 if (structData->callback) {
1291 result = (*structData->callback)(aRuleDataStruct, result);
1294 return result;
1297 const void*
1298 nsRuleNode::GetDisplayData(nsStyleContext* aContext)
1300 nsRuleDataDisplay displayData; // Declare a struct with null CSS values.
1301 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Display), mPresContext, aContext);
1302 ruleData.mDisplayData = &displayData;
1304 return WalkRuleTree(eStyleStruct_Display, aContext, &ruleData, &displayData);
1307 const void*
1308 nsRuleNode::GetVisibilityData(nsStyleContext* aContext)
1310 nsRuleDataDisplay displayData; // Declare a struct with null CSS values.
1311 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Visibility), mPresContext, aContext);
1312 ruleData.mDisplayData = &displayData;
1314 return WalkRuleTree(eStyleStruct_Visibility, aContext, &ruleData, &displayData);
1317 const void*
1318 nsRuleNode::GetTextData(nsStyleContext* aContext)
1320 nsRuleDataText textData; // Declare a struct with null CSS values.
1321 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Text), mPresContext, aContext);
1322 ruleData.mTextData = &textData;
1324 const void* res = WalkRuleTree(eStyleStruct_Text, aContext, &ruleData, &textData);
1325 textData.mTextShadow = nsnull; // We are sharing with some style rule. It really owns the data.
1326 return res;
1329 const void*
1330 nsRuleNode::GetTextResetData(nsStyleContext* aContext)
1332 nsRuleDataText textData; // Declare a struct with null CSS values.
1333 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(TextReset), mPresContext, aContext);
1334 ruleData.mTextData = &textData;
1336 return WalkRuleTree(eStyleStruct_TextReset, aContext, &ruleData, &textData);
1339 const void*
1340 nsRuleNode::GetUserInterfaceData(nsStyleContext* aContext)
1342 nsRuleDataUserInterface uiData; // Declare a struct with null CSS values.
1343 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(UserInterface), mPresContext, aContext);
1344 ruleData.mUserInterfaceData = &uiData;
1346 const void* res = WalkRuleTree(eStyleStruct_UserInterface, aContext, &ruleData, &uiData);
1347 uiData.mCursor = nsnull; // We are sharing with some style rule. It really owns the data.
1348 return res;
1351 const void*
1352 nsRuleNode::GetUIResetData(nsStyleContext* aContext)
1354 nsRuleDataUserInterface uiData; // Declare a struct with null CSS values.
1355 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(UIReset), mPresContext, aContext);
1356 ruleData.mUserInterfaceData = &uiData;
1358 const void* res = WalkRuleTree(eStyleStruct_UIReset, aContext, &ruleData, &uiData);
1359 return res;
1362 const void*
1363 nsRuleNode::GetFontData(nsStyleContext* aContext)
1365 nsRuleDataFont fontData; // Declare a struct with null CSS values.
1366 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), mPresContext, aContext);
1367 ruleData.mFontData = &fontData;
1369 return WalkRuleTree(eStyleStruct_Font, aContext, &ruleData, &fontData);
1372 const void*
1373 nsRuleNode::GetColorData(nsStyleContext* aContext)
1375 nsRuleDataColor colorData; // Declare a struct with null CSS values.
1376 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Color), mPresContext, aContext);
1377 ruleData.mColorData = &colorData;
1379 return WalkRuleTree(eStyleStruct_Color, aContext, &ruleData, &colorData);
1382 const void*
1383 nsRuleNode::GetBackgroundData(nsStyleContext* aContext)
1385 nsRuleDataColor colorData; // Declare a struct with null CSS values.
1386 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Background), mPresContext, aContext);
1387 ruleData.mColorData = &colorData;
1389 // If any members need to be set to null here, they must also be set to
1390 // null in HasAuthorSpecifiedRules (look at mBoxShadow in GetBorderData
1391 // and HasAuthorSpecifiedRules).
1393 return WalkRuleTree(eStyleStruct_Background, aContext, &ruleData, &colorData);
1396 const void*
1397 nsRuleNode::GetMarginData(nsStyleContext* aContext)
1399 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1400 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Margin), mPresContext, aContext);
1401 ruleData.mMarginData = &marginData;
1403 return WalkRuleTree(eStyleStruct_Margin, aContext, &ruleData, &marginData);
1406 const void*
1407 nsRuleNode::GetBorderData(nsStyleContext* aContext)
1409 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1410 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Border), mPresContext, aContext);
1411 ruleData.mMarginData = &marginData;
1413 const void* res = WalkRuleTree(eStyleStruct_Border, aContext, &ruleData, &marginData);
1414 // We are sharing with some style rule. It really owns the data.
1415 // This nulling must also happen in HasAuthorSpecifiedRules.
1416 marginData.mBoxShadow = nsnull;
1417 return res;
1420 const void*
1421 nsRuleNode::GetPaddingData(nsStyleContext* aContext)
1423 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1424 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Padding), mPresContext, aContext);
1425 ruleData.mMarginData = &marginData;
1427 // If any members need to be set to null here, they must also be set to
1428 // null in HasAuthorSpecifiedRules (look at mBoxShadow in GetBorderData
1429 // and HasAuthorSpecifiedRules).
1431 return WalkRuleTree(eStyleStruct_Padding, aContext, &ruleData, &marginData);
1434 const void*
1435 nsRuleNode::GetOutlineData(nsStyleContext* aContext)
1437 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1438 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Outline), mPresContext, aContext);
1439 ruleData.mMarginData = &marginData;
1441 return WalkRuleTree(eStyleStruct_Outline, aContext, &ruleData, &marginData);
1444 const void*
1445 nsRuleNode::GetListData(nsStyleContext* aContext)
1447 nsRuleDataList listData; // Declare a struct with null CSS values.
1448 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(List), mPresContext, aContext);
1449 ruleData.mListData = &listData;
1451 return WalkRuleTree(eStyleStruct_List, aContext, &ruleData, &listData);
1454 const void*
1455 nsRuleNode::GetPositionData(nsStyleContext* aContext)
1457 nsRuleDataPosition posData; // Declare a struct with null CSS values.
1458 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Position), mPresContext, aContext);
1459 ruleData.mPositionData = &posData;
1461 return WalkRuleTree(eStyleStruct_Position, aContext, &ruleData, &posData);
1464 const void*
1465 nsRuleNode::GetTableData(nsStyleContext* aContext)
1467 nsRuleDataTable tableData; // Declare a struct with null CSS values.
1468 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Table), mPresContext, aContext);
1469 ruleData.mTableData = &tableData;
1471 return WalkRuleTree(eStyleStruct_Table, aContext, &ruleData, &tableData);
1474 const void*
1475 nsRuleNode::GetTableBorderData(nsStyleContext* aContext)
1477 nsRuleDataTable tableData; // Declare a struct with null CSS values.
1478 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(TableBorder), mPresContext, aContext);
1479 ruleData.mTableData = &tableData;
1481 return WalkRuleTree(eStyleStruct_TableBorder, aContext, &ruleData, &tableData);
1484 const void*
1485 nsRuleNode::GetContentData(nsStyleContext* aContext)
1487 nsRuleDataContent contentData; // Declare a struct with null CSS values.
1488 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Content), mPresContext, aContext);
1489 ruleData.mContentData = &contentData;
1491 const void* res = WalkRuleTree(eStyleStruct_Content, aContext, &ruleData, &contentData);
1492 contentData.mCounterIncrement = contentData.mCounterReset = nsnull;
1493 contentData.mContent = nsnull; // We are sharing with some style rule. It really owns the data.
1494 return res;
1497 const void*
1498 nsRuleNode::GetQuotesData(nsStyleContext* aContext)
1500 nsRuleDataContent contentData; // Declare a struct with null CSS values.
1501 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Quotes), mPresContext, aContext);
1502 ruleData.mContentData = &contentData;
1504 const void* res = WalkRuleTree(eStyleStruct_Quotes, aContext, &ruleData, &contentData);
1505 contentData.mQuotes = nsnull; // We are sharing with some style rule. It really owns the data.
1506 return res;
1509 const void*
1510 nsRuleNode::GetXULData(nsStyleContext* aContext)
1512 nsRuleDataXUL xulData; // Declare a struct with null CSS values.
1513 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(XUL), mPresContext, aContext);
1514 ruleData.mXULData = &xulData;
1516 return WalkRuleTree(eStyleStruct_XUL, aContext, &ruleData, &xulData);
1519 const void*
1520 nsRuleNode::GetColumnData(nsStyleContext* aContext)
1522 nsRuleDataColumn columnData; // Declare a struct with null CSS values.
1523 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Column), mPresContext, aContext);
1524 ruleData.mColumnData = &columnData;
1526 return WalkRuleTree(eStyleStruct_Column, aContext, &ruleData, &columnData);
1529 #ifdef MOZ_SVG
1530 const void*
1531 nsRuleNode::GetSVGData(nsStyleContext* aContext)
1533 nsRuleDataSVG svgData; // Declare a struct with null CSS values.
1534 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(SVG), mPresContext, aContext);
1535 ruleData.mSVGData = &svgData;
1537 const void *res = WalkRuleTree(eStyleStruct_SVG, aContext, &ruleData, &svgData);
1538 svgData.mStrokeDasharray = nsnull; // We are sharing with some style rule. It really owns the data.
1539 return res;
1542 const void*
1543 nsRuleNode::GetSVGResetData(nsStyleContext* aContext)
1545 nsRuleDataSVG svgData; // Declare a struct with null CSS values.
1546 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(SVGReset), mPresContext, aContext);
1547 ruleData.mSVGData = &svgData;
1549 return WalkRuleTree(eStyleStruct_SVGReset, aContext, &ruleData, &svgData);
1551 #endif
1553 // If we need to restrict which properties apply to the style context,
1554 // return the bit to check in nsCSSProp's flags table. Otherwise,
1555 // return 0.
1556 inline PRUint32
1557 GetPseudoRestriction(nsStyleContext *aContext)
1559 // This needs to match nsStyleSet::WalkRestrictionRule.
1560 PRUint32 pseudoRestriction = 0;
1561 nsIAtom *pseudoType = aContext->GetPseudoType();
1562 if (pseudoType) {
1563 if (pseudoType == nsCSSPseudoElements::firstLetter) {
1564 pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LETTER;
1565 } else if (pseudoType == nsCSSPseudoElements::firstLine) {
1566 pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LINE;
1569 return pseudoRestriction;
1572 static void
1573 UnsetPropertiesWithoutFlags(const nsStyleStructID aSID,
1574 nsRuleDataStruct& aRuleDataStruct,
1575 PRUint32 aFlags)
1577 NS_ASSERTION(aFlags != 0, "aFlags must be nonzero");
1578 const StructCheckData *structData = gCheckProperties + aSID;
1580 for (const PropertyCheckData *prop = structData->props,
1581 *prop_end = prop + structData->nprops;
1582 prop != prop_end;
1583 ++prop) {
1584 if ((prop->flags & aFlags) == aFlags)
1585 // Don't unset the property.
1586 continue;
1588 switch (prop->type) {
1589 case eCSSType_Value:
1590 ValueAtOffset(aRuleDataStruct, prop->offset).Reset();
1591 break;
1592 case eCSSType_Rect:
1593 RectAtOffset(aRuleDataStruct, prop->offset)->Reset();
1594 break;
1595 case eCSSType_ValuePair:
1596 ValuePairAtOffset(aRuleDataStruct, prop->offset)->Reset();
1597 break;
1598 case eCSSType_ValueList:
1599 ValueListAtOffset(aRuleDataStruct, prop->offset) = nsnull;
1600 break;
1601 case eCSSType_ValuePairList:
1602 ValuePairListAtOffset(aRuleDataStruct, prop->offset) = nsnull;
1603 break;
1604 default:
1605 NS_NOTREACHED("unknown type");
1606 break;
1611 const void*
1612 nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
1613 nsStyleContext* aContext,
1614 nsRuleData* aRuleData,
1615 nsRuleDataStruct* aSpecificData)
1617 // We start at the most specific rule in the tree.
1618 void* startStruct = nsnull;
1620 nsRuleNode* ruleNode = this;
1621 nsRuleNode* highestNode = nsnull; // The highest node in the rule tree
1622 // that has the same properties
1623 // specified for struct |aSID| as
1624 // |this| does.
1625 nsRuleNode* rootNode = this; // After the loop below, this will be the
1626 // highest node that we've walked without
1627 // finding cached data on the rule tree.
1628 // If we don't find any cached data, it
1629 // will be the root. (XXX misnamed)
1630 RuleDetail detail = eRuleNone;
1631 PRUint32 bit = nsCachedStyleData::GetBitForSID(aSID);
1633 while (ruleNode) {
1634 // See if this rule node has cached the fact that the remaining
1635 // nodes along this path specify no data whatsoever.
1636 if (ruleNode->mNoneBits & bit)
1637 break;
1639 // If the dependent bit is set on a rule node for this struct, that
1640 // means its rule won't have any information to add, so skip it.
1641 // XXXldb I don't understand why we need to check |detail| here, but
1642 // we do.
1643 if (detail == eRuleNone)
1644 while (ruleNode->mDependentBits & bit) {
1645 NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nsnull,
1646 "dependent bit with cached data makes no sense");
1647 // Climb up to the next rule in the tree (a less specific rule).
1648 rootNode = ruleNode;
1649 ruleNode = ruleNode->mParent;
1650 NS_ASSERTION(!(ruleNode->mNoneBits & bit), "can't have both bits set");
1653 // Check for cached data after the inner loop above -- otherwise
1654 // we'll miss it.
1655 startStruct = ruleNode->mStyleData.GetStyleData(aSID);
1656 if (startStruct)
1657 break; // We found a rule with fully specified data. We don't
1658 // need to go up the tree any further, since the remainder
1659 // of this branch has already been computed.
1661 // Ask the rule to fill in the properties that it specifies.
1662 nsIStyleRule *rule = ruleNode->mRule;
1663 if (rule) {
1664 aRuleData->mLevel = ruleNode->GetLevel();
1665 aRuleData->mIsImportantRule = ruleNode->IsImportantRule();
1666 rule->MapRuleInfoInto(aRuleData);
1669 // Now we check to see how many properties have been specified by
1670 // the rules we've examined so far.
1671 RuleDetail oldDetail = detail;
1672 detail = CheckSpecifiedProperties(aSID, *aSpecificData);
1674 if (oldDetail == eRuleNone && detail != eRuleNone)
1675 highestNode = ruleNode;
1677 if (detail == eRuleFullReset ||
1678 detail == eRuleFullMixed ||
1679 detail == eRuleFullInherited)
1680 break; // We don't need to examine any more rules. All properties
1681 // have been fully specified.
1683 // Climb up to the next rule in the tree (a less specific rule).
1684 rootNode = ruleNode;
1685 ruleNode = ruleNode->mParent;
1688 // If needed, unset the properties that don't have a flag that allows
1689 // them to be set for this style context. (For example, only some
1690 // properties apply to :first-line and :first-letter.)
1691 PRUint32 pseudoRestriction = GetPseudoRestriction(aContext);
1692 if (pseudoRestriction) {
1693 UnsetPropertiesWithoutFlags(aSID, *aSpecificData, pseudoRestriction);
1695 // Recompute |detail| based on the restrictions we just applied.
1696 // We can adjust |detail| arbitrarily because of the restriction
1697 // rule added in nsStyleSet::WalkRestrictionRule.
1698 detail = CheckSpecifiedProperties(aSID, *aSpecificData);
1701 NS_ASSERTION(!startStruct || (detail != eRuleFullReset &&
1702 detail != eRuleFullMixed &&
1703 detail != eRuleFullInherited),
1704 "can't have start struct and be fully specified");
1706 PRBool isReset = nsCachedStyleData::IsReset(aSID);
1707 if (!highestNode)
1708 highestNode = rootNode;
1710 if (!aRuleData->mCanStoreInRuleTree)
1711 detail = eRulePartialMixed; // Treat as though some data is specified to avoid
1712 // the optimizations and force data computation.
1714 if (detail == eRuleNone && startStruct && !aRuleData->mPostResolveCallback) {
1715 // We specified absolutely no rule information, but a parent rule in the tree
1716 // specified all the rule information. We set a bit along the branch from our
1717 // node in the tree to the node that specified the data that tells nodes on that
1718 // branch that they never need to examine their rules for this particular struct type
1719 // ever again.
1720 PropagateDependentBit(bit, ruleNode);
1721 return startStruct;
1723 // FIXME Do we need to check for mPostResolveCallback?
1724 if ((!startStruct && !isReset &&
1725 (detail == eRuleNone || detail == eRulePartialInherited)) ||
1726 detail == eRuleFullInherited) {
1727 // We specified no non-inherited information and neither did any of
1728 // our parent rules.
1730 // We set a bit along the branch from the highest node (ruleNode)
1731 // down to our node (this) indicating that no non-inherited data was
1732 // specified. This bit is guaranteed to be set already on the path
1733 // from the highest node to the root node in the case where
1734 // (detail == eRuleNone), which is the most common case here.
1735 // We must check |!isReset| because the Compute*Data functions for
1736 // reset structs wouldn't handle none bits correctly.
1737 if (highestNode != this && !isReset)
1738 PropagateNoneBit(bit, highestNode);
1740 // All information must necessarily be inherited from our parent style context.
1741 // In the absence of any computed data in the rule tree and with
1742 // no rules specified that didn't have values of 'inherit', we should check our parent.
1743 nsStyleContext* parentContext = aContext->GetParent();
1744 if (isReset) {
1745 /* Reset structs don't inherit from first-line. */
1746 /* See similar code in COMPUTE_START_RESET */
1747 while (parentContext &&
1748 parentContext->GetPseudoType() == nsCSSPseudoElements::firstLine) {
1749 parentContext = parentContext->GetParent();
1752 if (parentContext) {
1753 // We have a parent, and so we should just inherit from the parent.
1754 // Set the inherit bits on our context. These bits tell the style context that
1755 // it never has to go back to the rule tree for data. Instead the style context tree
1756 // should be walked to find the data.
1757 const void* parentStruct = parentContext->GetStyleData(aSID);
1758 aContext->AddStyleBit(bit); // makes const_cast OK.
1759 aContext->SetStyle(aSID, const_cast<void*>(parentStruct));
1760 return parentStruct;
1762 else
1763 // We are the root. In the case of fonts, the default values just
1764 // come from the pres context.
1765 return SetDefaultOnRoot(aSID, aContext);
1768 // We need to compute the data from the information that the rules specified.
1769 const void* res;
1770 #define STYLE_STRUCT_TEST aSID
1771 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
1772 res = Compute##name##Data(startStruct, *aSpecificData, aContext, \
1773 highestNode, detail, !aRuleData->mCanStoreInRuleTree);
1774 #include "nsStyleStructList.h"
1775 #undef STYLE_STRUCT
1776 #undef STYLE_STRUCT_TEST
1778 // If we have a post-resolve callback, handle that now.
1779 if (aRuleData->mPostResolveCallback && (NS_LIKELY(res != nsnull)))
1780 (*aRuleData->mPostResolveCallback)(const_cast<void*>(res), aRuleData);
1782 // Now return the result.
1783 return res;
1786 const void*
1787 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
1789 switch (aSID) {
1790 case eStyleStruct_Font:
1792 nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
1793 if (NS_LIKELY(fontData != nsnull)) {
1794 nscoord minimumFontSize =
1795 mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
1797 if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
1798 fontData->mFont.size = PR_MAX(fontData->mSize, minimumFontSize);
1800 else {
1801 fontData->mFont.size = fontData->mSize;
1803 aContext->SetStyle(eStyleStruct_Font, fontData);
1805 return fontData;
1807 case eStyleStruct_Display:
1809 nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay();
1810 if (NS_LIKELY(disp != nsnull)) {
1811 aContext->SetStyle(eStyleStruct_Display, disp);
1813 return disp;
1815 case eStyleStruct_Visibility:
1817 nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
1818 if (NS_LIKELY(vis != nsnull)) {
1819 aContext->SetStyle(eStyleStruct_Visibility, vis);
1821 return vis;
1823 case eStyleStruct_Text:
1825 nsStyleText* text = new (mPresContext) nsStyleText();
1826 if (NS_LIKELY(text != nsnull)) {
1827 aContext->SetStyle(eStyleStruct_Text, text);
1829 return text;
1831 case eStyleStruct_TextReset:
1833 nsStyleTextReset* text = new (mPresContext) nsStyleTextReset();
1834 if (NS_LIKELY(text != nsnull)) {
1835 aContext->SetStyle(eStyleStruct_TextReset, text);
1837 return text;
1839 case eStyleStruct_Color:
1841 nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
1842 if (NS_LIKELY(color != nsnull)) {
1843 aContext->SetStyle(eStyleStruct_Color, color);
1845 return color;
1847 case eStyleStruct_Background:
1849 nsStyleBackground* bg = new (mPresContext) nsStyleBackground();
1850 if (NS_LIKELY(bg != nsnull)) {
1851 aContext->SetStyle(eStyleStruct_Background, bg);
1853 return bg;
1855 case eStyleStruct_Margin:
1857 nsStyleMargin* margin = new (mPresContext) nsStyleMargin();
1858 if (NS_LIKELY(margin != nsnull)) {
1859 aContext->SetStyle(eStyleStruct_Margin, margin);
1861 return margin;
1863 case eStyleStruct_Border:
1865 nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
1866 if (NS_LIKELY(border != nsnull)) {
1867 aContext->SetStyle(eStyleStruct_Border, border);
1869 return border;
1871 case eStyleStruct_Padding:
1873 nsStylePadding* padding = new (mPresContext) nsStylePadding();
1874 if (NS_LIKELY(padding != nsnull)) {
1875 aContext->SetStyle(eStyleStruct_Padding, padding);
1877 return padding;
1879 case eStyleStruct_Outline:
1881 nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
1882 if (NS_LIKELY(outline != nsnull)) {
1883 aContext->SetStyle(eStyleStruct_Outline, outline);
1885 return outline;
1887 case eStyleStruct_List:
1889 nsStyleList* list = new (mPresContext) nsStyleList();
1890 if (NS_LIKELY(list != nsnull)) {
1891 aContext->SetStyle(eStyleStruct_List, list);
1893 return list;
1895 case eStyleStruct_Position:
1897 nsStylePosition* pos = new (mPresContext) nsStylePosition();
1898 if (NS_LIKELY(pos != nsnull)) {
1899 aContext->SetStyle(eStyleStruct_Position, pos);
1901 return pos;
1903 case eStyleStruct_Table:
1905 nsStyleTable* table = new (mPresContext) nsStyleTable();
1906 if (NS_LIKELY(table != nsnull)) {
1907 aContext->SetStyle(eStyleStruct_Table, table);
1909 return table;
1911 case eStyleStruct_TableBorder:
1913 nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
1914 if (NS_LIKELY(table != nsnull)) {
1915 aContext->SetStyle(eStyleStruct_TableBorder, table);
1917 return table;
1919 case eStyleStruct_Content:
1921 nsStyleContent* content = new (mPresContext) nsStyleContent();
1922 if (NS_LIKELY(content != nsnull)) {
1923 aContext->SetStyle(eStyleStruct_Content, content);
1925 return content;
1927 case eStyleStruct_Quotes:
1929 nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes();
1930 if (NS_LIKELY(quotes != nsnull)) {
1931 aContext->SetStyle(eStyleStruct_Quotes, quotes);
1933 return quotes;
1935 case eStyleStruct_UserInterface:
1937 nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface();
1938 if (NS_LIKELY(ui != nsnull)) {
1939 aContext->SetStyle(eStyleStruct_UserInterface, ui);
1941 return ui;
1943 case eStyleStruct_UIReset:
1945 nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset();
1946 if (NS_LIKELY(ui != nsnull)) {
1947 aContext->SetStyle(eStyleStruct_UIReset, ui);
1949 return ui;
1952 case eStyleStruct_XUL:
1954 nsStyleXUL* xul = new (mPresContext) nsStyleXUL();
1955 if (NS_LIKELY(xul != nsnull)) {
1956 aContext->SetStyle(eStyleStruct_XUL, xul);
1958 return xul;
1961 case eStyleStruct_Column:
1963 nsStyleColumn* column = new (mPresContext) nsStyleColumn(mPresContext);
1964 if (NS_LIKELY(column != nsnull)) {
1965 aContext->SetStyle(eStyleStruct_Column, column);
1967 return column;
1970 #ifdef MOZ_SVG
1971 case eStyleStruct_SVG:
1973 nsStyleSVG* svg = new (mPresContext) nsStyleSVG();
1974 if (NS_LIKELY(svg != nsnull)) {
1975 aContext->SetStyle(eStyleStruct_SVG, svg);
1977 return svg;
1980 case eStyleStruct_SVGReset:
1982 nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset();
1983 if (NS_LIKELY(svgReset != nsnull)) {
1984 aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
1986 return svgReset;
1988 #endif
1989 default:
1991 * unhandled case: nsStyleStructID_Length.
1992 * last item of nsStyleStructID, to know its length.
1994 return nsnull;
1996 return nsnull;
2000 * This function handles cascading of *-left or *-right box properties
2001 * against *-start (which is L for LTR and R for RTL) or *-end (which is
2002 * R for LTR and L for RTL).
2004 * Cascading these properties correctly is hard because we need to
2005 * cascade two properties as one, but which two properties depends on a
2006 * third property ('direction'). We solve this by treating each of
2007 * these properties (say, 'margin-start') as a shorthand that sets a
2008 * property containing the value of the property specified
2009 * ('margin-start-value') and sets a pair of properties
2010 * ('margin-left-ltr-source' and 'margin-right-rtl-source') saying which
2011 * of the properties we use. Thus, when we want to compute the value of
2012 * 'margin-left' when 'direction' is 'ltr', we look at the value of
2013 * 'margin-left-ltr-source', which tells us whether to use the highest
2014 * 'margin-left' in the cascade or the highest 'margin-start'.
2016 * Finally, since we can compute the normal (*-left and *-right)
2017 * properties in a loop, this function works by modifying the data we
2018 * will use in that loop (which the caller must copy from the const
2019 * input).
2021 void
2022 nsRuleNode::AdjustLogicalBoxProp(nsStyleContext* aContext,
2023 const nsCSSValue& aLTRSource,
2024 const nsCSSValue& aRTLSource,
2025 const nsCSSValue& aLTRLogicalValue,
2026 const nsCSSValue& aRTLLogicalValue,
2027 PRUint8 aSide,
2028 nsCSSRect& aValueRect,
2029 PRBool& aInherited)
2031 PRBool LTRlogical = aLTRSource.GetUnit() == eCSSUnit_Enumerated &&
2032 aLTRSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
2033 PRBool RTLlogical = aRTLSource.GetUnit() == eCSSUnit_Enumerated &&
2034 aRTLSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
2035 if (LTRlogical || RTLlogical) {
2036 // We can't cache anything on the rule tree if we use any data from
2037 // the style context, since data cached in the rule tree could be
2038 // used with a style context with a different value.
2039 aInherited = PR_TRUE;
2040 PRUint8 dir = aContext->GetStyleVisibility()->mDirection;
2042 if (dir == NS_STYLE_DIRECTION_LTR) {
2043 if (LTRlogical)
2044 aValueRect.*(nsCSSRect::sides[aSide]) = aLTRLogicalValue;
2045 } else {
2046 if (RTLlogical)
2047 aValueRect.*(nsCSSRect::sides[aSide]) = aRTLLogicalValue;
2053 * Begin an nsRuleNode::Compute*Data function for an inherited struct.
2055 * @param type_ The nsStyle* type this function computes.
2056 * @param ctorargs_ The arguments used for the default nsStyle* constructor.
2057 * @param data_ Variable (declared here) holding the result of this
2058 * function.
2059 * @param parentdata_ Variable (declared here) holding the parent style
2060 * context's data for this struct.
2061 * @param rdtype_ The nsCSS* struct type used to compute this struct's data.
2062 * @param rdata_ Variable (declared here) holding the nsCSS* used here.
2064 #define COMPUTE_START_INHERITED(type_, ctorargs_, data_, parentdata_, rdtype_, rdata_) \
2065 NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
2066 "should not have bothered calling Compute*Data"); \
2068 nsStyleContext* parentContext = aContext->GetParent(); \
2070 const nsRuleData##rdtype_& rdata_ = \
2071 static_cast<const nsRuleData##rdtype_&>(aData); \
2072 nsStyle##type_* data_ = nsnull; \
2073 const nsStyle##type_* parentdata_ = nsnull; \
2074 PRBool inherited = aInherited; \
2076 /* If |inherited| might be false by the time we're done, we can't call */ \
2077 /* parentContext->GetStyle##type_() since it could recur into setting */ \
2078 /* the same struct on the same rule node, causing a leak. */ \
2079 if (parentContext && aRuleDetail != eRuleFullReset && \
2080 (!aStartStruct || (aRuleDetail != eRulePartialReset && \
2081 aRuleDetail != eRuleNone))) \
2082 parentdata_ = parentContext->GetStyle##type_(); \
2083 if (aStartStruct) \
2084 /* We only need to compute the delta between this computed data and */ \
2085 /* our computed data. */ \
2086 data_ = new (mPresContext) \
2087 nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
2088 else { \
2089 if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) { \
2090 /* No question. We will have to inherit. Go ahead and init */ \
2091 /* with inherited vals from parent. */ \
2092 inherited = PR_TRUE; \
2093 if (parentdata_) \
2094 data_ = new (mPresContext) nsStyle##type_(*parentdata_); \
2095 else \
2096 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2098 else \
2099 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2102 if (NS_UNLIKELY(!data_)) \
2103 return nsnull; /* Out Of Memory */ \
2104 if (!parentdata_) \
2105 parentdata_ = data_;
2108 * Begin an nsRuleNode::Compute*Data function for a reset struct.
2110 * @param type_ The nsStyle* type this function computes.
2111 * @param ctorargs_ The arguments used for the default nsStyle* constructor.
2112 * @param data_ Variable (declared here) holding the result of this
2113 * function.
2114 * @param parentdata_ Variable (declared here) holding the parent style
2115 * context's data for this struct.
2116 * @param rdtype_ The nsCSS* struct type used to compute this struct's data.
2117 * @param rdata_ Variable (declared here) holding the nsCSS* used here.
2119 #define COMPUTE_START_RESET(type_, ctorargs_, data_, parentdata_, rdtype_, rdata_) \
2120 NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
2121 "should not have bothered calling Compute*Data"); \
2123 nsStyleContext* parentContext = aContext->GetParent(); \
2124 /* Reset structs don't inherit from first-line */ \
2125 /* See similar code in WalkRuleTree */ \
2126 while (parentContext && \
2127 parentContext->GetPseudoType() == nsCSSPseudoElements::firstLine) { \
2128 parentContext = parentContext->GetParent(); \
2131 const nsRuleData##rdtype_& rdata_ = \
2132 static_cast<const nsRuleData##rdtype_&>(aData); \
2133 nsStyle##type_* data_; \
2134 if (aStartStruct) \
2135 /* We only need to compute the delta between this computed data and */ \
2136 /* our computed data. */ \
2137 data_ = new (mPresContext) \
2138 nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
2139 else \
2140 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2142 if (NS_UNLIKELY(!data_)) \
2143 return nsnull; /* Out Of Memory */ \
2145 /* If |inherited| might be false by the time we're done, we can't call */ \
2146 /* parentContext->GetStyle##type_() since it could recur into setting */ \
2147 /* the same struct on the same rule node, causing a leak. */ \
2148 const nsStyle##type_* parentdata_ = data_; \
2149 if (parentContext && \
2150 aRuleDetail != eRuleFullReset && \
2151 aRuleDetail != eRulePartialReset && \
2152 aRuleDetail != eRuleNone) \
2153 parentdata_ = parentContext->GetStyle##type_(); \
2154 PRBool inherited = aInherited;
2157 * Begin an nsRuleNode::Compute*Data function for an inherited struct.
2159 * @param type_ The nsStyle* type this function computes.
2160 * @param data_ Variable holding the result of this function.
2162 #define COMPUTE_END_INHERITED(type_, data_) \
2163 if (inherited) \
2164 /* We inherited, and therefore can't be cached in the rule node. We */ \
2165 /* have to be put right on the style context. */ \
2166 aContext->SetStyle(eStyleStruct_##type_, data_); \
2167 else { \
2168 /* We were fully specified and can therefore be cached right on the */ \
2169 /* rule node. */ \
2170 if (!aHighestNode->mStyleData.mInheritedData) { \
2171 aHighestNode->mStyleData.mInheritedData = \
2172 new (mPresContext) nsInheritedStyleData; \
2173 if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) { \
2174 data_->Destroy(mPresContext); \
2175 return nsnull; \
2178 aHighestNode->mStyleData.mInheritedData->m##type_##Data = data_; \
2179 /* Propagate the bit down. */ \
2180 PropagateDependentBit(NS_STYLE_INHERIT_BIT(type_), aHighestNode); \
2183 return data_;
2186 * Begin an nsRuleNode::Compute*Data function for a reset struct.
2188 * @param type_ The nsStyle* type this function computes.
2189 * @param data_ Variable holding the result of this function.
2191 #define COMPUTE_END_RESET(type_, data_) \
2192 if (inherited) \
2193 /* We inherited, and therefore can't be cached in the rule node. We */ \
2194 /* have to be put right on the style context. */ \
2195 aContext->SetStyle(eStyleStruct_##type_, data_); \
2196 else { \
2197 /* We were fully specified and can therefore be cached right on the */ \
2198 /* rule node. */ \
2199 if (!aHighestNode->mStyleData.mResetData) { \
2200 aHighestNode->mStyleData.mResetData = \
2201 new (mPresContext) nsResetStyleData; \
2202 if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) { \
2203 data_->Destroy(mPresContext); \
2204 return nsnull; \
2207 aHighestNode->mStyleData.mResetData->m##type_##Data = data_; \
2208 /* Propagate the bit down. */ \
2209 PropagateDependentBit(NS_STYLE_INHERIT_BIT(type_), aHighestNode); \
2212 return data_;
2214 #ifdef MOZ_MATHML
2215 // This function figures out how much scaling should be suppressed to
2216 // satisfy scriptminsize. This is our attempt to implement
2217 // http://www.w3.org/TR/MathML2/chapter3.html#id.3.3.4.2.2
2218 // This is called after mScriptLevel, mScriptMinSize and mScriptSizeMultiplier
2219 // have been set in aFont.
2221 // Here are the invariants we enforce:
2222 // 1) A decrease in size must not reduce the size below minscriptsize.
2223 // 2) An increase in size must not increase the size above the size we would
2224 // have if minscriptsize had not been applied anywhere.
2225 // 3) The scriptlevel-induced size change must between 1.0 and the parent's
2226 // scriptsizemultiplier^(new script level - old script level), as close to the
2227 // latter as possible subject to constraints 1 and 2.
2228 static nscoord
2229 ComputeScriptLevelSize(const nsStyleFont* aFont, const nsStyleFont* aParentFont,
2230 nsPresContext* aPresContext, nscoord* aUnconstrainedSize)
2232 PRInt32 scriptLevelChange =
2233 aFont->mScriptLevel - aParentFont->mScriptLevel;
2234 if (scriptLevelChange == 0) {
2235 *aUnconstrainedSize = aParentFont->mScriptUnconstrainedSize;
2236 // Constraint #3 says that we cannot change size, and #1 and #2 are always
2237 // satisfied with no change. It's important this be fast because it covers
2238 // all non-MathML content.
2239 return aParentFont->mSize;
2242 // Compute actual value of minScriptSize
2243 nscoord minScriptSize =
2244 nsStyleFont::ZoomText(aPresContext, aParentFont->mScriptMinSize);
2246 double scriptLevelScale =
2247 pow(aParentFont->mScriptSizeMultiplier, scriptLevelChange);
2248 // Compute the size we would have had if minscriptsize had never been
2249 // applied, also prevent overflow (bug 413274)
2250 *aUnconstrainedSize =
2251 NSToCoordRound(PR_MIN(aParentFont->mScriptUnconstrainedSize*scriptLevelScale,
2252 nscoord_MAX));
2253 // Compute the size we could get via scriptlevel change
2254 nscoord scriptLevelSize =
2255 NSToCoordRound(PR_MIN(aParentFont->mSize*scriptLevelScale,
2256 nscoord_MAX));
2257 if (scriptLevelScale <= 1.0) {
2258 if (aParentFont->mSize <= minScriptSize) {
2259 // We can't decrease the font size at all, so just stick to no change
2260 // (authors are allowed to explicitly set the font size smaller than
2261 // minscriptsize)
2262 return aParentFont->mSize;
2264 // We can decrease, so apply constraint #1
2265 return PR_MAX(minScriptSize, scriptLevelSize);
2266 } else {
2267 // scriptminsize can only make sizes larger than the unconstrained size
2268 NS_ASSERTION(*aUnconstrainedSize <= scriptLevelSize, "How can this ever happen?");
2269 // Apply constraint #2
2270 return PR_MIN(scriptLevelSize, PR_MAX(*aUnconstrainedSize, minScriptSize));
2273 #endif
2275 /* static */ void
2276 nsRuleNode::SetFontSize(nsPresContext* aPresContext,
2277 const nsRuleDataFont& aFontData,
2278 const nsStyleFont* aFont,
2279 const nsStyleFont* aParentFont,
2280 nscoord* aSize,
2281 const nsFont& aSystemFont,
2282 nscoord aParentSize,
2283 nscoord aScriptLevelAdjustedParentSize,
2284 PRBool aUsedStartStruct,
2285 PRBool& aInherited)
2287 PRBool zoom = PR_FALSE;
2288 PRInt32 baseSize = (PRInt32) aPresContext->
2289 GetDefaultFont(aFont->mGenericID)->size;
2290 if (eCSSUnit_Enumerated == aFontData.mSize.GetUnit()) {
2291 PRInt32 value = aFontData.mSize.GetIntValue();
2292 PRInt32 scaler = aPresContext->FontScaler();
2293 float scaleFactor = nsStyleUtil::GetScalingFactor(scaler);
2295 zoom = PR_TRUE;
2296 if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) &&
2297 (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
2298 *aSize = nsStyleUtil::CalcFontPointSize(value, baseSize,
2299 scaleFactor, aPresContext, eFontSize_CSS);
2301 else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
2302 // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
2303 *aSize = nsStyleUtil::CalcFontPointSize(value, baseSize,
2304 scaleFactor, aPresContext);
2306 else if (NS_STYLE_FONT_SIZE_LARGER == value ||
2307 NS_STYLE_FONT_SIZE_SMALLER == value) {
2308 aInherited = PR_TRUE;
2310 // Un-zoom so we use the tables correctly. We'll then rezoom due
2311 // to the |zoom = PR_TRUE| above.
2312 // Note that relative units here use the parent's size unadjusted
2313 // for scriptlevel changes. A scriptlevel change between us and the parent
2314 // is simply ignored.
2315 nscoord parentSize =
2316 nsStyleFont::UnZoomText(aPresContext, aParentSize);
2318 if (NS_STYLE_FONT_SIZE_LARGER == value) {
2319 *aSize = nsStyleUtil::FindNextLargerFontSize(parentSize,
2320 baseSize, scaleFactor, aPresContext, eFontSize_CSS);
2321 NS_ASSERTION(*aSize > parentSize,
2322 "FindNextLargerFontSize failed");
2324 else {
2325 *aSize = nsStyleUtil::FindNextSmallerFontSize(parentSize,
2326 baseSize, scaleFactor, aPresContext, eFontSize_CSS);
2327 NS_ASSERTION(*aSize < parentSize ||
2328 parentSize <= nsPresContext::CSSPixelsToAppUnits(1),
2329 "FindNextSmallerFontSize failed");
2331 } else {
2332 NS_NOTREACHED("unexpected value");
2335 else if (aFontData.mSize.IsLengthUnit()) {
2336 // Note that font-based length units use the parent's size unadjusted
2337 // for scriptlevel changes. A scriptlevel change between us and the parent
2338 // is simply ignored.
2339 *aSize = CalcLengthWith(aFontData.mSize, aParentSize, aParentFont, nsnull,
2340 aPresContext, aInherited);
2341 zoom = aFontData.mSize.IsFixedLengthUnit() ||
2342 aFontData.mSize.GetUnit() == eCSSUnit_Pixel;
2344 else if (eCSSUnit_Percent == aFontData.mSize.GetUnit()) {
2345 aInherited = PR_TRUE;
2346 // Note that % units use the parent's size unadjusted for scriptlevel
2347 // changes. A scriptlevel change between us and the parent is simply
2348 // ignored.
2349 *aSize = NSToCoordRound(aParentSize *
2350 aFontData.mSize.GetPercentValue());
2351 zoom = PR_FALSE;
2353 else if (eCSSUnit_System_Font == aFontData.mSize.GetUnit()) {
2354 // this becomes our cascading size
2355 *aSize = aSystemFont.size;
2356 zoom = PR_TRUE;
2358 else if (eCSSUnit_Inherit == aFontData.mSize.GetUnit()) {
2359 aInherited = PR_TRUE;
2360 // We apply scriptlevel change for this case, because the default is
2361 // to inherit and we don't want explicit "inherit" to differ from the
2362 // default.
2363 *aSize = aScriptLevelAdjustedParentSize;
2364 zoom = PR_FALSE;
2366 else if (eCSSUnit_Initial == aFontData.mSize.GetUnit()) {
2367 // The initial value is 'medium', which has magical sizing based on
2368 // the generic font family, so do that here too.
2369 *aSize = baseSize;
2370 zoom = PR_TRUE;
2371 } else {
2372 NS_ASSERTION(eCSSUnit_Null == aFontData.mSize.GetUnit(),
2373 "What kind of font-size value is this?");
2374 #ifdef MOZ_MATHML
2375 // if aUsedStartStruct is true, then every single property in the
2376 // font struct is being set all at once. This means scriptlevel is not
2377 // going to have any influence on the font size; there is no need to
2378 // do anything here.
2379 if (!aUsedStartStruct && aParentSize != aScriptLevelAdjustedParentSize) {
2380 // There was no rule affecting the size but the size has been
2381 // affected by the parent's size via scriptlevel change. So treat
2382 // this as inherited.
2383 aInherited = PR_TRUE;
2384 *aSize = aScriptLevelAdjustedParentSize;
2386 #endif
2389 // We want to zoom the cascaded size so that em-based measurements,
2390 // line-heights, etc., work.
2391 if (zoom) {
2392 *aSize = nsStyleFont::ZoomText(aPresContext, *aSize);
2396 static PRInt8 ClampTo8Bit(PRInt32 aValue) {
2397 if (aValue < -128)
2398 return -128;
2399 if (aValue > 127)
2400 return 127;
2401 return PRInt8(aValue);
2404 /* static */ void
2405 nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
2406 nscoord aMinFontSize,
2407 PRUint8 aGenericFontID, const nsRuleDataFont& aFontData,
2408 const nsStyleFont* aParentFont,
2409 nsStyleFont* aFont, PRBool aUsedStartStruct,
2410 PRBool& aInherited)
2412 const nsFont* defaultVariableFont =
2413 aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID);
2415 // -moz-system-font: enum (never inherit!)
2416 nsFont systemFont;
2417 if (eCSSUnit_Enumerated == aFontData.mSystemFont.GetUnit()) {
2418 nsSystemFontID sysID;
2419 switch (aFontData.mSystemFont.GetIntValue()) {
2420 case NS_STYLE_FONT_CAPTION: sysID = eSystemFont_Caption; break; // css2
2421 case NS_STYLE_FONT_ICON: sysID = eSystemFont_Icon; break;
2422 case NS_STYLE_FONT_MENU: sysID = eSystemFont_Menu; break;
2423 case NS_STYLE_FONT_MESSAGE_BOX: sysID = eSystemFont_MessageBox; break;
2424 case NS_STYLE_FONT_SMALL_CAPTION: sysID = eSystemFont_SmallCaption; break;
2425 case NS_STYLE_FONT_STATUS_BAR: sysID = eSystemFont_StatusBar; break;
2426 case NS_STYLE_FONT_WINDOW: sysID = eSystemFont_Window; break; // css3
2427 case NS_STYLE_FONT_DOCUMENT: sysID = eSystemFont_Document; break;
2428 case NS_STYLE_FONT_WORKSPACE: sysID = eSystemFont_Workspace; break;
2429 case NS_STYLE_FONT_DESKTOP: sysID = eSystemFont_Desktop; break;
2430 case NS_STYLE_FONT_INFO: sysID = eSystemFont_Info; break;
2431 case NS_STYLE_FONT_DIALOG: sysID = eSystemFont_Dialog; break;
2432 case NS_STYLE_FONT_BUTTON: sysID = eSystemFont_Button; break;
2433 case NS_STYLE_FONT_PULL_DOWN_MENU:sysID = eSystemFont_PullDownMenu; break;
2434 case NS_STYLE_FONT_LIST: sysID = eSystemFont_List; break;
2435 case NS_STYLE_FONT_FIELD: sysID = eSystemFont_Field; break;
2438 // GetSystemFont sets the font face but not necessarily the size
2439 // XXX Or at least it used to -- no longer true for thebes. Maybe
2440 // it should be again, though.
2441 systemFont.size = defaultVariableFont->size;
2443 if (NS_FAILED(aPresContext->DeviceContext()->GetSystemFont(sysID,
2444 &systemFont))) {
2445 systemFont.name = defaultVariableFont->name;
2448 // XXXldb All of this platform-specific stuff should be in the
2449 // nsIDeviceContext implementations, not here.
2451 #ifdef XP_WIN
2453 // As far as I can tell the system default fonts and sizes for
2454 // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
2455 // all pre-determined and cannot be changed by either the control panel
2456 // or programmtically.
2458 switch (sysID) {
2459 // Fields (text fields)
2460 // Button and Selects (listboxes/comboboxes)
2461 // We use whatever font is defined by the system. Which it appears
2462 // (and the assumption is) it is always a proportional font. Then we
2463 // always use 2 points smaller than what the browser has defined as
2464 // the default proportional font.
2465 case eSystemFont_Field:
2466 case eSystemFont_Button:
2467 case eSystemFont_List:
2468 // Assumption: system defined font is proportional
2469 systemFont.size =
2470 PR_MAX(defaultVariableFont->size - aPresContext->PointsToAppUnits(2), 0);
2471 break;
2473 #endif
2474 } else {
2475 // In case somebody explicitly used -moz-use-system-font.
2476 systemFont = *defaultVariableFont;
2480 // font-family: string list, enum, inherit
2481 NS_ASSERTION(eCSSUnit_Enumerated != aFontData.mFamily.GetUnit(),
2482 "system fonts should not be in mFamily anymore");
2483 if (eCSSUnit_String == aFontData.mFamily.GetUnit()) {
2484 // set the correct font if we are using DocumentFonts OR we are overriding for XUL
2485 // MJA: bug 31816
2486 if (aGenericFontID == kGenericFont_NONE) {
2487 // only bother appending fallback fonts if this isn't a fallback generic font itself
2488 if (!aFont->mFont.name.IsEmpty())
2489 aFont->mFont.name.Append((PRUnichar)',');
2490 // defaultVariableFont.name should always be "serif" or "sans-serif".
2491 aFont->mFont.name.Append(defaultVariableFont->name);
2493 aFont->mFont.familyNameQuirks =
2494 (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks &&
2495 aFontData.mFamilyFromHTML);
2496 aFont->mFont.systemFont = PR_FALSE;
2497 // Technically this is redundant with the code below, but it's good
2498 // to have since we'll still want it once we get rid of
2499 // SetGenericFont (bug 380915).
2500 aFont->mGenericID = aGenericFontID;
2502 else if (eCSSUnit_System_Font == aFontData.mFamily.GetUnit()) {
2503 aFont->mFont.name = systemFont.name;
2504 aFont->mFont.familyNameQuirks = PR_FALSE;
2505 aFont->mFont.systemFont = PR_TRUE;
2506 aFont->mGenericID = kGenericFont_NONE;
2508 else if (eCSSUnit_Inherit == aFontData.mFamily.GetUnit()) {
2509 aInherited = PR_TRUE;
2510 aFont->mFont.name = aParentFont->mFont.name;
2511 aFont->mFont.familyNameQuirks = aParentFont->mFont.familyNameQuirks;
2512 aFont->mFont.systemFont = aParentFont->mFont.systemFont;
2513 aFont->mGenericID = aParentFont->mGenericID;
2515 else if (eCSSUnit_Initial == aFontData.mFamily.GetUnit()) {
2516 aFont->mFont.name = defaultVariableFont->name;
2517 aFont->mFont.familyNameQuirks = PR_FALSE;
2518 aFont->mFont.systemFont = defaultVariableFont->systemFont;
2519 aFont->mGenericID = kGenericFont_NONE;
2522 // When we're in the loop in SetGenericFont, we must ensure that we
2523 // always keep aFont->mFlags set to the correct generic. But we have
2524 // to be careful not to touch it when we're called directly from
2525 // ComputeFontData, because we could have a start struct.
2526 if (aGenericFontID != kGenericFont_NONE) {
2527 aFont->mGenericID = aGenericFontID;
2530 // font-style: enum, normal, inherit, initial, -moz-system-font
2531 SetDiscrete(aFontData.mStyle, aFont->mFont.style, aInherited,
2532 SETDSC_ENUMERATED | SETDSC_NORMAL | SETDSC_SYSTEM_FONT,
2533 aParentFont->mFont.style,
2534 defaultVariableFont->style,
2535 0, 0,
2536 NS_STYLE_FONT_STYLE_NORMAL,
2537 systemFont.style);
2539 // font-variant: enum, normal, inherit, initial, -moz-system-font
2540 SetDiscrete(aFontData.mVariant, aFont->mFont.variant, aInherited,
2541 SETDSC_ENUMERATED | SETDSC_NORMAL | SETDSC_SYSTEM_FONT,
2542 aParentFont->mFont.variant,
2543 defaultVariableFont->variant,
2544 0, 0,
2545 NS_STYLE_FONT_VARIANT_NORMAL,
2546 systemFont.variant);
2548 // font-weight: int, enum, normal, inherit, initial, -moz-system-font
2549 // special handling for enum
2550 if (eCSSUnit_Enumerated == aFontData.mWeight.GetUnit()) {
2551 PRInt32 value = aFontData.mWeight.GetIntValue();
2552 switch (value) {
2553 case NS_STYLE_FONT_WEIGHT_NORMAL:
2554 case NS_STYLE_FONT_WEIGHT_BOLD:
2555 aFont->mFont.weight = value;
2556 break;
2557 case NS_STYLE_FONT_WEIGHT_BOLDER:
2558 case NS_STYLE_FONT_WEIGHT_LIGHTER:
2559 aInherited = PR_TRUE;
2560 aFont->mFont.weight = nsStyleUtil::ConstrainFontWeight(aParentFont->mFont.weight + value);
2561 break;
2563 } else
2564 SetDiscrete(aFontData.mWeight, aFont->mFont.weight, aInherited,
2565 SETDSC_INTEGER | SETDSC_NORMAL | SETDSC_SYSTEM_FONT,
2566 aParentFont->mFont.weight,
2567 defaultVariableFont->weight,
2568 0, 0,
2569 NS_STYLE_FONT_WEIGHT_NORMAL,
2570 systemFont.weight);
2572 #ifdef MOZ_MATHML
2573 // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
2574 // they're available for font-size computation.
2576 // -moz-script-min-size: length
2577 if (aFontData.mScriptMinSize.IsLengthUnit()) {
2578 // scriptminsize in font units (em, ex) has to be interpreted relative
2579 // to the parent font, or the size definitions are circular and we
2581 aFont->mScriptMinSize =
2582 CalcLengthWith(aFontData.mScriptMinSize, aParentFont->mSize, aParentFont, nsnull,
2583 aPresContext, aInherited);
2586 // -moz-script-size-multiplier: factor, inherit, initial
2587 SetFactor(aFontData.mScriptSizeMultiplier, aFont->mScriptSizeMultiplier,
2588 aInherited, aParentFont->mScriptSizeMultiplier,
2589 NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER,
2590 SETFCT_POSITIVE);
2592 // -moz-script-level: integer, number, inherit
2593 if (eCSSUnit_Integer == aFontData.mScriptLevel.GetUnit()) {
2594 // "relative"
2595 aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel + aFontData.mScriptLevel.GetIntValue());
2597 else if (eCSSUnit_Number == aFontData.mScriptLevel.GetUnit()) {
2598 // "absolute"
2599 aFont->mScriptLevel = ClampTo8Bit(PRInt32(aFontData.mScriptLevel.GetFloatValue()));
2601 else if (eCSSUnit_Inherit == aFontData.mScriptSizeMultiplier.GetUnit()) {
2602 aInherited = PR_TRUE;
2603 aFont->mScriptLevel = aParentFont->mScriptLevel;
2605 else if (eCSSUnit_Initial == aFontData.mScriptSizeMultiplier.GetUnit()) {
2606 aFont->mScriptLevel = 0;
2608 #endif
2610 // font-size: enum, length, percent, inherit
2611 nscoord scriptLevelAdjustedParentSize = aParentFont->mSize;
2612 #ifdef MOZ_MATHML
2613 nscoord scriptLevelAdjustedUnconstrainedParentSize;
2614 scriptLevelAdjustedParentSize =
2615 ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
2616 &scriptLevelAdjustedUnconstrainedParentSize);
2617 NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
2618 "If we have a start struct, we should have reset everything coming in here");
2619 #endif
2620 SetFontSize(aPresContext, aFontData, aFont, aParentFont, &aFont->mSize,
2621 systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
2622 aUsedStartStruct, aInherited);
2623 #ifdef MOZ_MATHML
2624 if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
2625 scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) {
2626 // Fast path: we have not been affected by scriptminsize so we don't
2627 // need to call SetFontSize again to compute the
2628 // scriptminsize-unconstrained size. This is OK even if we have a
2629 // start struct, because if we have a start struct then 'font-size'
2630 // was specified and so scriptminsize has no effect.
2631 aFont->mScriptUnconstrainedSize = aFont->mSize;
2632 } else {
2633 SetFontSize(aPresContext, aFontData, aFont, aParentFont,
2634 &aFont->mScriptUnconstrainedSize, systemFont,
2635 aParentFont->mScriptUnconstrainedSize,
2636 scriptLevelAdjustedUnconstrainedParentSize,
2637 aUsedStartStruct, aInherited);
2639 NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
2640 "scriptminsize should never be making things bigger");
2641 #endif
2643 // enforce the user' specified minimum font-size on the value that we expose
2644 // (but don't change font-size:0)
2645 if (0 < aFont->mSize && aFont->mSize < aMinFontSize)
2646 aFont->mFont.size = aMinFontSize;
2647 else
2648 aFont->mFont.size = aFont->mSize;
2650 // font-size-adjust: number, none, inherit, initial, -moz-system-font
2651 if (eCSSUnit_System_Font == aFontData.mSizeAdjust.GetUnit()) {
2652 aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
2653 } else
2654 SetFactor(aFontData.mSizeAdjust, aFont->mFont.sizeAdjust, aInherited,
2655 aParentFont->mFont.sizeAdjust, 0.0f, SETFCT_NONE);
2658 // SetGenericFont:
2659 // - backtrack to an ancestor with the same generic font name (possibly
2660 // up to the root where default values come from the presentation context)
2661 // - re-apply cascading rules from there without caching intermediate values
2662 /* static */ void
2663 nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
2664 nsStyleContext* aContext,
2665 PRUint8 aGenericFontID, nscoord aMinFontSize,
2666 nsStyleFont* aFont)
2668 // walk up the contexts until a context with the desired generic font
2669 nsAutoVoidArray contextPath;
2670 contextPath.AppendElement(aContext);
2671 nsStyleContext* higherContext = aContext->GetParent();
2672 while (higherContext) {
2673 if (higherContext->GetStyleFont()->mGenericID == aGenericFontID) {
2674 // done walking up the higher contexts
2675 break;
2677 contextPath.AppendElement(higherContext);
2678 higherContext = higherContext->GetParent();
2681 // re-apply the cascading rules, starting from the higher context
2683 // If we stopped earlier because we reached the root of the style tree,
2684 // we will start with the default generic font from the presentation
2685 // context. Otherwise we start with the higher context.
2686 const nsFont* defaultFont = aPresContext->GetDefaultFont(aGenericFontID);
2687 nsStyleFont parentFont(*defaultFont, aPresContext);
2688 if (higherContext) {
2689 const nsStyleFont* tmpFont = higherContext->GetStyleFont();
2690 parentFont = *tmpFont;
2692 *aFont = parentFont;
2694 PRBool dummy;
2695 PRUint32 fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
2697 for (PRInt32 i = contextPath.Count() - 1; i >= 0; --i) {
2698 nsStyleContext* context = (nsStyleContext*)contextPath[i];
2699 nsRuleDataFont fontData; // Declare a struct with null CSS values.
2700 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), aPresContext, context);
2701 ruleData.mFontData = &fontData;
2703 // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
2704 // Note that we *do* need to do this for our own data, since what is
2705 // in |fontData| in ComputeFontData is only for the rules below
2706 // aStartStruct.
2707 for (nsRuleNode* ruleNode = context->GetRuleNode(); ruleNode;
2708 ruleNode = ruleNode->GetParent()) {
2709 if (ruleNode->mNoneBits & fontBit)
2710 // no more font rules on this branch, get out
2711 break;
2713 nsIStyleRule *rule = ruleNode->GetRule();
2714 if (rule) {
2715 ruleData.mLevel = ruleNode->GetLevel();
2716 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
2717 rule->MapRuleInfoInto(&ruleData);
2721 // Compute the delta from the information that the rules specified
2723 // Avoid unnecessary operations in SetFont(). But we care if it's
2724 // the final value that we're computing.
2725 if (i != 0)
2726 fontData.mFamily.Reset();
2728 nsRuleNode::SetFont(aPresContext, context, aMinFontSize,
2729 aGenericFontID, fontData, &parentFont, aFont,
2730 PR_FALSE, dummy);
2732 // XXX Not sure if we need to do this here
2733 // If we have a post-resolve callback, handle that now.
2734 if (ruleData.mPostResolveCallback)
2735 (ruleData.mPostResolveCallback)(aFont, &ruleData);
2737 parentFont = *aFont;
2741 static PRBool ExtractGeneric(const nsString& aFamily, PRBool aGeneric,
2742 void *aData)
2744 nsAutoString *data = static_cast<nsAutoString*>(aData);
2746 if (aGeneric) {
2747 *data = aFamily;
2748 return PR_FALSE; // stop enumeration
2750 return PR_TRUE;
2753 const void*
2754 nsRuleNode::ComputeFontData(void* aStartStruct,
2755 const nsRuleDataStruct& aData,
2756 nsStyleContext* aContext,
2757 nsRuleNode* aHighestNode,
2758 const RuleDetail aRuleDetail, PRBool aInherited)
2760 COMPUTE_START_INHERITED(Font, (mPresContext), font, parentFont,
2761 Font, fontData)
2763 // NOTE: The |aRuleDetail| passed in is a little bit conservative due
2764 // to the -moz-system-font property. We really don't need to consider
2765 // it here in determining whether to cache in the rule tree. However,
2766 // we do need to consider it in WalkRuleTree when deciding whether to
2767 // walk further up the tree. So this means that when the font struct
2768 // is fully specified using *longhand* properties (excluding
2769 // -moz-system-font), we won't cache in the rule tree even though we
2770 // could. However, it's pretty unlikely authors will do that
2771 // (although there is a pretty good chance they'll fully specify it
2772 // using the 'font' shorthand).
2774 // See if there is a minimum font-size constraint to honor
2775 nscoord minimumFontSize =
2776 mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
2778 if (minimumFontSize < 0)
2779 minimumFontSize = 0;
2781 PRBool useDocumentFonts =
2782 mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
2784 // See if we are in the chrome
2785 // We only need to know this to determine if we have to use the
2786 // document fonts (overriding the useDocumentFonts flag), or to
2787 // determine if we have to override the minimum font-size constraint.
2788 if ((!useDocumentFonts || minimumFontSize > 0) && mPresContext->IsChrome()) {
2789 // if we are not using document fonts, but this is a XUL document,
2790 // then we use the document fonts anyway
2791 useDocumentFonts = PR_TRUE;
2792 minimumFontSize = 0;
2795 // Figure out if we are a generic font
2796 PRUint8 generic = kGenericFont_NONE;
2797 // XXXldb What if we would have had a string if we hadn't been doing
2798 // the optimization with a non-null aStartStruct?
2799 if (eCSSUnit_String == fontData.mFamily.GetUnit()) {
2800 fontData.mFamily.GetStringValue(font->mFont.name);
2801 // XXXldb Do we want to extract the generic for this if it's not only a
2802 // generic?
2803 nsFont::GetGenericID(font->mFont.name, &generic);
2805 // If we aren't allowed to use document fonts, then we are only entitled
2806 // to use the user's default variable-width font and fixed-width font
2807 if (!useDocumentFonts) {
2808 // Extract the generic from the specified font family...
2809 nsAutoString genericName;
2810 if (!font->mFont.EnumerateFamilies(ExtractGeneric, &genericName)) {
2811 // The specified font had a generic family.
2812 font->mFont.name = genericName;
2813 nsFont::GetGenericID(genericName, &generic);
2815 // ... and only use it if it's -moz-fixed or monospace
2816 if (generic != kGenericFont_moz_fixed &&
2817 generic != kGenericFont_monospace) {
2818 font->mFont.name.Truncate();
2819 generic = kGenericFont_NONE;
2821 } else {
2822 // The specified font did not have a generic family.
2823 font->mFont.name.Truncate();
2824 generic = kGenericFont_NONE;
2829 // Now compute our font struct
2830 if (generic == kGenericFont_NONE) {
2831 // continue the normal processing
2832 nsRuleNode::SetFont(mPresContext, aContext, minimumFontSize, generic,
2833 fontData, parentFont, font,
2834 aStartStruct != nsnull, inherited);
2836 else {
2837 // re-calculate the font as a generic font
2838 inherited = PR_TRUE;
2839 nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
2840 minimumFontSize, font);
2843 COMPUTE_END_INHERITED(Font, font)
2846 already_AddRefed<nsCSSShadowArray>
2847 nsRuleNode::GetShadowData(nsCSSValueList* aList,
2848 nsStyleContext* aContext,
2849 PRBool aUsesSpread,
2850 PRBool& inherited)
2852 PRUint32 arrayLength = 0;
2853 for (nsCSSValueList *list2 = aList; list2; list2 = list2->mNext)
2854 ++arrayLength;
2856 NS_ASSERTION(arrayLength > 0, "Non-null text-shadow list, yet we counted 0 items.");
2857 nsCSSShadowArray* shadowList = new(arrayLength) nsCSSShadowArray(arrayLength);
2859 if (!shadowList)
2860 return nsnull;
2862 nsStyleCoord tempCoord;
2863 PRBool unitOK;
2864 for (nsCSSShadowItem* item = shadowList->ShadowAt(0);
2865 aList;
2866 aList = aList->mNext, ++item) {
2867 nsCSSValue::Array *arr = aList->mValue.GetArrayValue();
2868 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
2869 unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(),
2870 SETCOORD_LENGTH, aContext, mPresContext, inherited);
2871 NS_ASSERTION(unitOK, "unexpected unit");
2872 item->mXOffset = tempCoord.GetCoordValue();
2874 unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(),
2875 SETCOORD_LENGTH, aContext, mPresContext, inherited);
2876 NS_ASSERTION(unitOK, "unexpected unit");
2877 item->mYOffset = tempCoord.GetCoordValue();
2879 // Blur radius is optional in the current box-shadow spec
2880 if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
2881 unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(),
2882 SETCOORD_LENGTH, aContext, mPresContext, inherited);
2883 NS_ASSERTION(unitOK, "unexpected unit");
2884 item->mRadius = tempCoord.GetCoordValue();
2885 } else {
2886 item->mRadius = 0;
2889 // Find the spread radius
2890 if (aUsesSpread && arr->Item(3).GetUnit() != eCSSUnit_Null) {
2891 unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(),
2892 SETCOORD_LENGTH, aContext, mPresContext, inherited);
2893 NS_ASSERTION(unitOK, "unexpected unit");
2894 item->mSpread = tempCoord.GetCoordValue();
2895 } else {
2896 item->mSpread = 0;
2899 if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
2900 item->mHasColor = PR_TRUE;
2901 // 2nd argument can be bogus since inherit is not a valid color
2902 unitOK = SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor,
2903 inherited);
2904 NS_ASSERTION(unitOK, "unexpected unit");
2908 NS_ADDREF(shadowList);
2909 return shadowList;
2912 const void*
2913 nsRuleNode::ComputeTextData(void* aStartStruct,
2914 const nsRuleDataStruct& aData,
2915 nsStyleContext* aContext,
2916 nsRuleNode* aHighestNode,
2917 const RuleDetail aRuleDetail, PRBool aInherited)
2919 COMPUTE_START_INHERITED(Text, (), text, parentText, Text, textData)
2921 // letter-spacing: normal, length, inherit
2922 SetCoord(textData.mLetterSpacing, text->mLetterSpacing, parentText->mLetterSpacing,
2923 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL,
2924 aContext, mPresContext, inherited);
2926 // text-shadow: none, list, inherit, initial
2927 nsCSSValueList* list = textData.mTextShadow;
2928 if (list) {
2929 text->mTextShadow = nsnull;
2931 // Don't need to handle none/initial explicitly: The above assignment
2932 // takes care of that
2933 if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
2934 inherited = PR_TRUE;
2935 text->mTextShadow = parentText->mTextShadow;
2936 } else if (eCSSUnit_Array == list->mValue.GetUnit()) {
2937 // List of arrays
2938 text->mTextShadow = GetShadowData(list, aContext, PR_FALSE, inherited);
2942 // line-height: normal, number, length, percent, inherit
2943 if (eCSSUnit_Percent == textData.mLineHeight.GetUnit()) {
2944 inherited = PR_TRUE;
2945 // Use |mFont.size| to pick up minimum font size.
2946 text->mLineHeight.SetCoordValue(
2947 nscoord(float(aContext->GetStyleFont()->mFont.size) *
2948 textData.mLineHeight.GetPercentValue()));
2950 else if (eCSSUnit_Initial == textData.mLineHeight.GetUnit() ||
2951 eCSSUnit_System_Font == textData.mLineHeight.GetUnit()) {
2952 text->mLineHeight.SetNormalValue();
2954 else {
2955 SetCoord(textData.mLineHeight, text->mLineHeight, parentText->mLineHeight,
2956 SETCOORD_LH | SETCOORD_FACTOR | SETCOORD_NORMAL,
2957 aContext, mPresContext, inherited);
2958 if (textData.mLineHeight.IsFixedLengthUnit() ||
2959 textData.mLineHeight.GetUnit() == eCSSUnit_Pixel) {
2960 nscoord lh = nsStyleFont::ZoomText(mPresContext,
2961 text->mLineHeight.GetCoordValue());
2962 nscoord minimumFontSize =
2963 mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
2965 if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
2966 // If we applied a minimum font size, scale the line height by
2967 // the same ratio. (If we *might* have applied a minimum font
2968 // size, we can't cache in the rule tree.)
2969 inherited = PR_TRUE;
2970 const nsStyleFont *font = aContext->GetStyleFont();
2971 if (font->mSize != 0) {
2972 lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
2973 } else {
2974 lh = minimumFontSize;
2977 text->mLineHeight.SetCoordValue(lh);
2982 // text-align: enum, string, inherit, initial
2983 if (eCSSUnit_String == textData.mTextAlign.GetUnit()) {
2984 NS_NOTYETIMPLEMENTED("align string");
2985 } else
2986 SetDiscrete(textData.mTextAlign, text->mTextAlign, inherited,
2987 SETDSC_ENUMERATED, parentText->mTextAlign,
2988 NS_STYLE_TEXT_ALIGN_DEFAULT,
2989 0, 0, 0, 0);
2991 // text-indent: length, percent, inherit, initial
2992 SetCoord(textData.mTextIndent, text->mTextIndent, parentText->mTextIndent,
2993 SETCOORD_LPH | SETCOORD_INITIAL_ZERO, aContext,
2994 mPresContext, inherited);
2996 // text-transform: enum, none, inherit, initial
2997 SetDiscrete(textData.mTextTransform, text->mTextTransform, inherited,
2998 SETDSC_ENUMERATED | SETDSC_NONE, parentText->mTextTransform,
2999 NS_STYLE_TEXT_TRANSFORM_NONE, 0,
3000 NS_STYLE_TEXT_TRANSFORM_NONE, 0, 0);
3002 // white-space: enum, normal, inherit, initial
3003 SetDiscrete(textData.mWhiteSpace, text->mWhiteSpace, inherited,
3004 SETDSC_ENUMERATED | SETDSC_NORMAL, parentText->mWhiteSpace,
3005 NS_STYLE_WHITESPACE_NORMAL, 0, 0,
3006 NS_STYLE_WHITESPACE_NORMAL, 0);
3008 // word-spacing: normal, length, inherit
3009 SetCoord(textData.mWordSpacing, text->mWordSpacing, parentText->mWordSpacing,
3010 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL,
3011 aContext, mPresContext, inherited);
3013 // word-wrap: enum, normal, inherit, initial
3014 SetDiscrete(textData.mWordWrap, text->mWordWrap, inherited,
3015 SETDSC_ENUMERATED | SETDSC_NORMAL, parentText->mWordWrap,
3016 NS_STYLE_WORDWRAP_NORMAL, 0, 0,
3017 NS_STYLE_WORDWRAP_NORMAL, 0);
3019 COMPUTE_END_INHERITED(Text, text)
3022 const void*
3023 nsRuleNode::ComputeTextResetData(void* aStartStruct,
3024 const nsRuleDataStruct& aData,
3025 nsStyleContext* aContext,
3026 nsRuleNode* aHighestNode,
3027 const RuleDetail aRuleDetail, PRBool aInherited)
3029 COMPUTE_START_RESET(TextReset, (), text, parentText, Text, textData)
3031 // vertical-align: enum, length, percent, inherit
3032 if (!SetCoord(textData.mVerticalAlign, text->mVerticalAlign,
3033 parentText->mVerticalAlign, SETCOORD_LPH | SETCOORD_ENUMERATED,
3034 aContext, mPresContext, inherited)) {
3035 if (eCSSUnit_Initial == textData.mVerticalAlign.GetUnit()) {
3036 text->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,
3037 eStyleUnit_Enumerated);
3041 // text-decoration: none, enum (bit field), inherit, initial
3042 if (eCSSUnit_Enumerated == textData.mDecoration.GetUnit()) {
3043 PRInt32 td = textData.mDecoration.GetIntValue();
3044 text->mTextDecoration = td;
3045 if (td & NS_STYLE_TEXT_DECORATION_PREF_ANCHORS) {
3046 PRBool underlineLinks =
3047 mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
3048 if (underlineLinks) {
3049 text->mTextDecoration |= NS_STYLE_TEXT_DECORATION_UNDERLINE;
3051 else {
3052 text->mTextDecoration &= ~NS_STYLE_TEXT_DECORATION_UNDERLINE;
3056 else
3057 SetDiscrete(textData.mDecoration, text->mTextDecoration, inherited,
3058 SETDSC_NONE,
3059 parentText->mTextDecoration,
3060 NS_STYLE_TEXT_DECORATION_NONE, 0,
3061 NS_STYLE_TEXT_DECORATION_NONE, 0, 0);
3063 // unicode-bidi: enum, normal, inherit, initial
3064 SetDiscrete(textData.mUnicodeBidi, text->mUnicodeBidi, inherited,
3065 SETDSC_ENUMERATED | SETDSC_NORMAL,
3066 parentText->mUnicodeBidi,
3067 NS_STYLE_UNICODE_BIDI_NORMAL, 0, 0,
3068 NS_STYLE_UNICODE_BIDI_NORMAL, 0);
3070 COMPUTE_END_RESET(TextReset, text)
3073 const void*
3074 nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
3075 const nsRuleDataStruct& aData,
3076 nsStyleContext* aContext,
3077 nsRuleNode* aHighestNode,
3078 const RuleDetail aRuleDetail,
3079 PRBool aInherited)
3081 COMPUTE_START_INHERITED(UserInterface, (), ui, parentUI,
3082 UserInterface, uiData)
3084 // cursor: enum, auto, url, inherit
3085 nsCSSValueList* list = uiData.mCursor;
3086 if (nsnull != list) {
3087 delete [] ui->mCursorArray;
3088 ui->mCursorArray = nsnull;
3089 ui->mCursorArrayLength = 0;
3091 if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
3092 inherited = PR_TRUE;
3093 ui->mCursor = parentUI->mCursor;
3094 ui->CopyCursorArrayFrom(*parentUI);
3096 else if (eCSSUnit_Initial == list->mValue.GetUnit()) {
3097 ui->mCursor = NS_STYLE_CURSOR_AUTO;
3099 else {
3100 // The parser will never create a list that is *all* URL values --
3101 // that's invalid.
3102 PRUint32 arrayLength = 0;
3103 nsCSSValueList* list2 = list;
3104 for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext)
3105 if (list->mValue.GetArrayValue()->Item(0).GetImageValue())
3106 ++arrayLength;
3108 if (arrayLength != 0) {
3109 ui->mCursorArray = new nsCursorImage[arrayLength];
3110 if (ui->mCursorArray) {
3111 ui->mCursorArrayLength = arrayLength;
3113 for (nsCursorImage *item = ui->mCursorArray;
3114 list2->mValue.GetUnit() == eCSSUnit_Array;
3115 list2 = list2->mNext) {
3116 nsCSSValue::Array *arr = list2->mValue.GetArrayValue();
3117 imgIRequest *req = arr->Item(0).GetImageValue();
3118 if (req) {
3119 item->mImage = req;
3120 if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
3121 item->mHaveHotspot = PR_TRUE;
3122 item->mHotspotX = arr->Item(1).GetFloatValue(),
3123 item->mHotspotY = arr->Item(2).GetFloatValue();
3125 ++item;
3131 NS_ASSERTION(list, "Must have non-array value at the end");
3132 NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated ||
3133 list->mValue.GetUnit() == eCSSUnit_Auto,
3134 "Unexpected fallback value at end of cursor list");
3136 if (eCSSUnit_Enumerated == list->mValue.GetUnit()) {
3137 ui->mCursor = list->mValue.GetIntValue();
3139 else if (eCSSUnit_Auto == list->mValue.GetUnit()) {
3140 ui->mCursor = NS_STYLE_CURSOR_AUTO;
3145 // user-input: auto, none, enum, inherit, initial
3146 SetDiscrete(uiData.mUserInput, ui->mUserInput, inherited,
3147 SETDSC_ENUMERATED | SETDSC_NONE | SETDSC_AUTO,
3148 parentUI->mUserInput,
3149 NS_STYLE_USER_INPUT_AUTO,
3150 NS_STYLE_USER_INPUT_AUTO,
3151 NS_STYLE_USER_INPUT_NONE,
3152 0, 0);
3154 // user-modify: enum, inherit, initial
3155 SetDiscrete(uiData.mUserModify, ui->mUserModify, inherited,
3156 SETDSC_ENUMERATED,
3157 parentUI->mUserModify,
3158 NS_STYLE_USER_MODIFY_READ_ONLY,
3159 0, 0, 0, 0);
3161 // user-focus: none, normal, enum, inherit, initial
3162 SetDiscrete(uiData.mUserFocus, ui->mUserFocus, inherited,
3163 SETDSC_ENUMERATED | SETDSC_NONE | SETDSC_NORMAL,
3164 parentUI->mUserFocus,
3165 NS_STYLE_USER_FOCUS_NONE,
3167 NS_STYLE_USER_FOCUS_NONE,
3168 NS_STYLE_USER_FOCUS_NORMAL,
3171 COMPUTE_END_INHERITED(UserInterface, ui)
3174 const void*
3175 nsRuleNode::ComputeUIResetData(void* aStartStruct,
3176 const nsRuleDataStruct& aData,
3177 nsStyleContext* aContext,
3178 nsRuleNode* aHighestNode,
3179 const RuleDetail aRuleDetail, PRBool aInherited)
3181 COMPUTE_START_RESET(UIReset, (), ui, parentUI, UserInterface, uiData)
3183 // user-select: auto, none, enum, inherit, initial
3184 SetDiscrete(uiData.mUserSelect, ui->mUserSelect, inherited,
3185 SETDSC_ENUMERATED | SETDSC_NONE | SETDSC_AUTO,
3186 parentUI->mUserSelect,
3187 NS_STYLE_USER_SELECT_AUTO,
3188 NS_STYLE_USER_SELECT_AUTO,
3189 NS_STYLE_USER_SELECT_NONE,
3190 0, 0);
3192 // ime-mode: auto, normal, enum, inherit, initial
3193 SetDiscrete(uiData.mIMEMode, ui->mIMEMode, inherited,
3194 SETDSC_ENUMERATED | SETDSC_NORMAL | SETDSC_AUTO,
3195 parentUI->mIMEMode,
3196 NS_STYLE_IME_MODE_AUTO,
3197 NS_STYLE_IME_MODE_AUTO,
3199 NS_STYLE_IME_MODE_NORMAL,
3202 // force-broken-image-icons: integer, inherit, initial
3203 SetDiscrete(uiData.mForceBrokenImageIcon, ui->mForceBrokenImageIcon,
3204 inherited,
3205 SETDSC_INTEGER,
3206 parentUI->mForceBrokenImageIcon,
3207 0, 0, 0, 0, 0);
3209 // -moz-window-shadow: enum, none, inherit, initial
3210 SetDiscrete(uiData.mWindowShadow, ui->mWindowShadow, inherited,
3211 SETDSC_ENUMERATED | SETDSC_NONE, parentUI->mWindowShadow,
3212 NS_STYLE_WINDOW_SHADOW_DEFAULT, 0,
3213 NS_STYLE_WINDOW_SHADOW_NONE, 0, 0);
3215 COMPUTE_END_RESET(UIReset, ui)
3218 /* Given a -moz-transform token stream, accumulates them into an
3219 * nsStyleTransformMatrix
3221 * @param aList The nsCSSValueList of arrays to read into transform functions.
3222 * @param aContext The style context to use for unit conversion.
3223 * @param aPresContext The presentation context to use for unit conversion
3224 * @param aInherited If the value is inherited, this is set to PR_TRUE.
3225 * @return An nsStyleTransformMatrix corresponding to the net transform.
3227 static nsStyleTransformMatrix ReadTransforms(const nsCSSValueList* aList,
3228 nsStyleContext* aContext,
3229 nsPresContext* aPresContext,
3230 PRBool &aInherited)
3232 nsStyleTransformMatrix result;
3234 for (const nsCSSValueList* curr = aList; curr != nsnull; curr = curr->mNext) {
3235 const nsCSSValue &currElem = curr->mValue;
3236 NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
3237 "Stream should consist solely of functions!");
3238 NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
3239 "Incoming function is too short!");
3241 /* Read in a single transform matrix, then accumulate it with the total. */
3242 nsStyleTransformMatrix currMatrix;
3243 currMatrix.SetToTransformFunction(currElem.GetArrayValue(), aContext,
3244 aPresContext, aInherited);
3245 result *= currMatrix;
3247 return result;
3250 const void*
3251 nsRuleNode::ComputeDisplayData(void* aStartStruct,
3252 const nsRuleDataStruct& aData,
3253 nsStyleContext* aContext,
3254 nsRuleNode* aHighestNode,
3255 const RuleDetail aRuleDetail, PRBool aInherited)
3257 COMPUTE_START_RESET(Display, (), display, parentDisplay,
3258 Display, displayData)
3260 // opacity: factor, inherit, initial
3261 SetFactor(displayData.mOpacity, display->mOpacity, inherited,
3262 parentDisplay->mOpacity, 1.0f, SETFCT_OPACITY);
3264 // display: enum, none, inherit, initial
3265 SetDiscrete(displayData.mDisplay, display->mDisplay, inherited,
3266 SETDSC_ENUMERATED | SETDSC_NONE, parentDisplay->mDisplay,
3267 NS_STYLE_DISPLAY_INLINE, 0,
3268 NS_STYLE_DISPLAY_NONE, 0, 0);
3270 // appearance: enum, none, inherit, initial
3271 SetDiscrete(displayData.mAppearance, display->mAppearance, inherited,
3272 SETDSC_ENUMERATED | SETDSC_NONE, parentDisplay->mAppearance,
3273 NS_THEME_NONE, 0,
3274 NS_THEME_NONE, 0, 0);
3276 // binding: url, none, inherit
3277 if (eCSSUnit_URL == displayData.mBinding.GetUnit()) {
3278 nsCSSValue::URL* url = displayData.mBinding.GetURLStructValue();
3279 NS_ASSERTION(url, "What's going on here?");
3281 if (NS_LIKELY(url->mURI)) {
3282 display->mBinding = url;
3283 } else {
3284 display->mBinding = nsnull;
3287 else if (eCSSUnit_None == displayData.mBinding.GetUnit() ||
3288 eCSSUnit_Initial == displayData.mBinding.GetUnit()) {
3289 display->mBinding = nsnull;
3291 else if (eCSSUnit_Inherit == displayData.mBinding.GetUnit()) {
3292 inherited = PR_TRUE;
3293 display->mBinding = parentDisplay->mBinding;
3296 // position: enum, inherit, initial
3297 SetDiscrete(displayData.mPosition, display->mPosition, inherited,
3298 SETDSC_ENUMERATED, parentDisplay->mPosition,
3299 NS_STYLE_POSITION_STATIC, 0, 0, 0, 0);
3301 // clear: enum, none, inherit, initial
3302 SetDiscrete(displayData.mClear, display->mBreakType, inherited,
3303 SETDSC_ENUMERATED | SETDSC_NONE, parentDisplay->mBreakType,
3304 NS_STYLE_CLEAR_NONE, 0,
3305 NS_STYLE_CLEAR_NONE, 0, 0);
3307 // temp fix for bug 24000
3308 // Map 'auto' and 'avoid' to PR_FALSE, and 'always', 'left', and
3309 // 'right' to PR_TRUE.
3310 // "A conforming user agent may interpret the values 'left' and
3311 // 'right' as 'always'." - CSS2.1, section 13.3.1
3312 if (eCSSUnit_Enumerated == displayData.mBreakBefore.GetUnit()) {
3313 display->mBreakBefore = (NS_STYLE_PAGE_BREAK_AVOID != displayData.mBreakBefore.GetIntValue());
3315 else if (eCSSUnit_Auto == displayData.mBreakBefore.GetUnit() ||
3316 eCSSUnit_Initial == displayData.mBreakBefore.GetUnit()) {
3317 display->mBreakBefore = PR_FALSE;
3319 else if (eCSSUnit_Inherit == displayData.mBreakBefore.GetUnit()) {
3320 inherited = PR_TRUE;
3321 display->mBreakBefore = parentDisplay->mBreakBefore;
3324 if (eCSSUnit_Enumerated == displayData.mBreakAfter.GetUnit()) {
3325 display->mBreakAfter = (NS_STYLE_PAGE_BREAK_AVOID != displayData.mBreakAfter.GetIntValue());
3327 else if (eCSSUnit_Auto == displayData.mBreakAfter.GetUnit() ||
3328 eCSSUnit_Initial == displayData.mBreakAfter.GetUnit()) {
3329 display->mBreakAfter = PR_FALSE;
3331 else if (eCSSUnit_Inherit == displayData.mBreakAfter.GetUnit()) {
3332 inherited = PR_TRUE;
3333 display->mBreakAfter = parentDisplay->mBreakAfter;
3335 // end temp fix
3337 // float: enum, none, inherit, initial
3338 SetDiscrete(displayData.mFloat, display->mFloats, inherited,
3339 SETDSC_ENUMERATED | SETDSC_NONE, parentDisplay->mFloats,
3340 NS_STYLE_FLOAT_NONE, 0,
3341 NS_STYLE_FLOAT_NONE, 0, 0);
3343 // overflow-x: enum, auto, inherit, initial
3344 SetDiscrete(displayData.mOverflowX, display->mOverflowX, inherited,
3345 SETDSC_ENUMERATED | SETDSC_AUTO,
3346 parentDisplay->mOverflowX,
3347 NS_STYLE_OVERFLOW_VISIBLE,
3348 NS_STYLE_OVERFLOW_AUTO,
3349 0, 0, 0);
3351 // overflow-y: enum, auto, inherit, initial
3352 SetDiscrete(displayData.mOverflowY, display->mOverflowY, inherited,
3353 SETDSC_ENUMERATED | SETDSC_AUTO,
3354 parentDisplay->mOverflowY,
3355 NS_STYLE_OVERFLOW_VISIBLE,
3356 NS_STYLE_OVERFLOW_AUTO,
3357 0, 0, 0);
3359 // CSS3 overflow-x and overflow-y require some fixup as well in some
3360 // cases. NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
3361 // meaningful only when used in both dimensions.
3362 if (display->mOverflowX != display->mOverflowY &&
3363 (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
3364 display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
3365 display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
3366 display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
3367 // We can't store in the rule tree since a more specific rule might
3368 // change these conditions.
3369 inherited = PR_TRUE;
3371 // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
3372 // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
3373 if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
3374 display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
3375 if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
3376 display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
3378 // If 'visible' is specified but doesn't match the other dimension, it
3379 // turns into 'auto'.
3380 if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
3381 display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
3382 if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
3383 display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
3386 // clip property: length, auto, inherit
3387 if (eCSSUnit_Inherit == displayData.mClip.mTop.GetUnit()) { // if one is inherit, they all are
3388 inherited = PR_TRUE;
3389 display->mClipFlags = parentDisplay->mClipFlags;
3390 display->mClip = parentDisplay->mClip;
3392 // if one is initial, they all are
3393 else if (eCSSUnit_Initial == displayData.mClip.mTop.GetUnit()) {
3394 display->mClipFlags = NS_STYLE_CLIP_AUTO;
3395 display->mClip.SetRect(0,0,0,0);
3397 else {
3398 PRBool fullAuto = PR_TRUE;
3400 display->mClipFlags = 0; // clear it
3402 if (eCSSUnit_Auto == displayData.mClip.mTop.GetUnit()) {
3403 display->mClip.y = 0;
3404 display->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
3406 else if (displayData.mClip.mTop.IsLengthUnit()) {
3407 display->mClip.y = CalcLength(displayData.mClip.mTop, aContext, mPresContext, inherited);
3408 fullAuto = PR_FALSE;
3410 if (eCSSUnit_Auto == displayData.mClip.mBottom.GetUnit()) {
3411 // Setting to NS_MAXSIZE for the 'auto' case ensures that
3412 // the clip rect is nonempty. It is important that mClip be
3413 // nonempty if the actual clip rect could be nonempty.
3414 display->mClip.height = NS_MAXSIZE;
3415 display->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
3417 else if (displayData.mClip.mBottom.IsLengthUnit()) {
3418 display->mClip.height = CalcLength(displayData.mClip.mBottom, aContext, mPresContext, inherited) -
3419 display->mClip.y;
3420 fullAuto = PR_FALSE;
3422 if (eCSSUnit_Auto == displayData.mClip.mLeft.GetUnit()) {
3423 display->mClip.x = 0;
3424 display->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
3426 else if (displayData.mClip.mLeft.IsLengthUnit()) {
3427 display->mClip.x = CalcLength(displayData.mClip.mLeft, aContext, mPresContext, inherited);
3428 fullAuto = PR_FALSE;
3430 if (eCSSUnit_Auto == displayData.mClip.mRight.GetUnit()) {
3431 // Setting to NS_MAXSIZE for the 'auto' case ensures that
3432 // the clip rect is nonempty. It is important that mClip be
3433 // nonempty if the actual clip rect could be nonempty.
3434 display->mClip.width = NS_MAXSIZE;
3435 display->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
3437 else if (displayData.mClip.mRight.IsLengthUnit()) {
3438 display->mClip.width = CalcLength(displayData.mClip.mRight, aContext, mPresContext, inherited) -
3439 display->mClip.x;
3440 fullAuto = PR_FALSE;
3442 display->mClipFlags &= ~NS_STYLE_CLIP_TYPE_MASK;
3443 if (fullAuto) {
3444 display->mClipFlags |= NS_STYLE_CLIP_AUTO;
3446 else {
3447 display->mClipFlags |= NS_STYLE_CLIP_RECT;
3451 if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
3452 // CSS2 9.7 specifies display type corrections dealing with 'float'
3453 // and 'position'. Since generated content can't be floated or
3454 // positioned, we can deal with it here.
3456 if (nsCSSPseudoElements::firstLetter == aContext->GetPseudoType()) {
3457 // a non-floating first-letter must be inline
3458 // XXX this fix can go away once bug 103189 is fixed correctly
3459 display->mDisplay = NS_STYLE_DISPLAY_INLINE;
3461 // We can't cache the data in the rule tree since if a more specific
3462 // rule has 'float: left' we'll end up with the wrong 'display'
3463 // property.
3464 inherited = PR_TRUE;
3467 if (display->IsAbsolutelyPositioned()) {
3468 // 1) if position is 'absolute' or 'fixed' then display must be
3469 // block-level and float must be 'none'
3471 // Backup original display value for calculation of a hypothetical
3472 // box (CSS2 10.6.4/10.6.5).
3473 // See nsHTMLReflowState::CalculateHypotheticalBox
3474 display->mOriginalDisplay = display->mDisplay;
3475 EnsureBlockDisplay(display->mDisplay);
3476 display->mFloats = NS_STYLE_FLOAT_NONE;
3478 // We can't cache the data in the rule tree since if a more specific
3479 // rule has 'position: static' we'll end up with problems with the
3480 // 'display' and 'float' properties.
3481 inherited = PR_TRUE;
3482 } else if (display->mFloats != NS_STYLE_FLOAT_NONE) {
3483 // 2) if float is not none, and display is not none, then we must
3484 // set a block-level 'display' type per CSS2.1 section 9.7.
3486 EnsureBlockDisplay(display->mDisplay);
3488 // We can't cache the data in the rule tree since if a more specific
3489 // rule has 'float: none' we'll end up with the wrong 'display'
3490 // property.
3491 inherited = PR_TRUE;
3496 /* Convert the nsCSSValueList into an nsTArray<nsTransformFunction *>. */
3497 const nsCSSValueList *head = displayData.mTransform;
3499 if (head != nsnull) {
3500 /* There is a chance that we will discover that
3501 * the transform property has been set to 'none,' 'initial,' or 'inherit.'
3502 * If so, process appropriately.
3505 /* If it's 'none,' indicate that there are no transforms. */
3506 if (head->mValue.GetUnit() == eCSSUnit_None)
3507 display->mTransformPresent = PR_FALSE;
3509 /* If we need to inherit, do so by making a full deep-copy. */
3510 else if (head->mValue.GetUnit() == eCSSUnit_Inherit) {
3511 display->mTransformPresent = parentDisplay->mTransformPresent;
3512 if (parentDisplay->mTransformPresent)
3513 display->mTransform = parentDisplay->mTransform;
3514 inherited = PR_TRUE;
3516 /* If it's 'initial', then we reset to empty. */
3517 else if (head->mValue.GetUnit() == eCSSUnit_Initial)
3518 display->mTransformPresent = PR_FALSE;
3520 /* Otherwise, we are looking at a list of CSS tokens. We'll read each of
3521 * them in as an array of nsTransformFunction objects, then will accumulate
3522 * them all together to form the final transform matrix.
3524 else {
3526 display->mTransform =
3527 ReadTransforms(head, aContext, mPresContext, inherited);
3529 /* Make sure to say that this data is valid! */
3530 display->mTransformPresent = PR_TRUE;
3534 /* Convert -moz-transform-origin. */
3535 if (displayData.mTransformOrigin.mXValue.GetUnit() != eCSSUnit_Null ||
3536 displayData.mTransformOrigin.mXValue.GetUnit() != eCSSUnit_Null) {
3538 /* If X coordinate is an enumerated type, handle it explicitly. */
3539 if (eCSSUnit_Enumerated == displayData.mTransformOrigin.mXValue.GetUnit())
3540 display->mTransformOrigin[0].SetPercentValue
3541 (GetFloatFromBoxPosition
3542 (displayData.mTransformOrigin.mXValue.GetIntValue()));
3543 else {
3544 /* Convert lengths, percents, and inherit. Default value is 50%. */
3545 #ifdef DEBUG
3546 PRBool result =
3547 #endif
3548 SetCoord(displayData.mTransformOrigin.mXValue,
3549 display->mTransformOrigin[0],
3550 parentDisplay->mTransformOrigin[0],
3551 SETCOORD_LPH | SETCOORD_INITIAL_HALF,
3552 aContext, mPresContext, aInherited);
3553 NS_ASSERTION(result, "Malformed -moz-transform-origin parse!");
3556 /* If Y coordinate is an enumerated type, handle it explicitly. */
3557 if (eCSSUnit_Enumerated == displayData.mTransformOrigin.mYValue.GetUnit())
3558 display->mTransformOrigin[1].SetPercentValue
3559 (GetFloatFromBoxPosition
3560 (displayData.mTransformOrigin.mYValue.GetIntValue()));
3561 else {
3562 /* Convert lengths, percents, initial, inherit. */
3563 #ifdef DEBUG
3564 PRBool result =
3565 #endif
3566 SetCoord(displayData.mTransformOrigin.mYValue,
3567 display->mTransformOrigin[1],
3568 parentDisplay->mTransformOrigin[1],
3569 SETCOORD_LPH | SETCOORD_INITIAL_HALF,
3570 aContext, mPresContext, aInherited);
3571 NS_ASSERTION(result, "Malformed -moz-transform-origin parse!");
3575 COMPUTE_END_RESET(Display, display)
3578 const void*
3579 nsRuleNode::ComputeVisibilityData(void* aStartStruct,
3580 const nsRuleDataStruct& aData,
3581 nsStyleContext* aContext,
3582 nsRuleNode* aHighestNode,
3583 const RuleDetail aRuleDetail, PRBool aInherited)
3585 COMPUTE_START_INHERITED(Visibility, (mPresContext),
3586 visibility, parentVisibility,
3587 Display, displayData)
3589 // direction: enum, inherit, initial
3590 SetDiscrete(displayData.mDirection, visibility->mDirection, inherited,
3591 SETDSC_ENUMERATED, parentVisibility->mDirection,
3592 (GET_BIDI_OPTION_DIRECTION(mPresContext->GetBidi())
3593 == IBMBIDI_TEXTDIRECTION_RTL)
3594 ? NS_STYLE_DIRECTION_RTL : NS_STYLE_DIRECTION_LTR,
3595 0, 0, 0, 0);
3597 // visibility: enum, inherit, initial
3598 SetDiscrete(displayData.mVisibility, visibility->mVisible, inherited,
3599 SETDSC_ENUMERATED, parentVisibility->mVisible,
3600 NS_STYLE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
3602 // lang: string, inherit
3603 // this is not a real CSS property, it is a html attribute mapped to CSS struture
3604 if (eCSSUnit_String == displayData.mLang.GetUnit()) {
3605 if (!gLangService) {
3606 CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService);
3609 if (gLangService) {
3610 nsAutoString lang;
3611 displayData.mLang.GetStringValue(lang);
3612 visibility->mLangGroup = gLangService->LookupLanguage(lang);
3616 COMPUTE_END_INHERITED(Visibility, visibility)
3619 const void*
3620 nsRuleNode::ComputeColorData(void* aStartStruct,
3621 const nsRuleDataStruct& aData,
3622 nsStyleContext* aContext,
3623 nsRuleNode* aHighestNode,
3624 const RuleDetail aRuleDetail, PRBool aInherited)
3626 COMPUTE_START_INHERITED(Color, (mPresContext), color, parentColor,
3627 Color, colorData)
3629 // color: color, string, inherit
3630 // Special case for currentColor. According to CSS3, setting color to 'currentColor'
3631 // should behave as if it is inherited
3632 if (colorData.mColor.GetUnit() == eCSSUnit_EnumColor &&
3633 colorData.mColor.GetIntValue() == NS_COLOR_CURRENTCOLOR) {
3634 color->mColor = parentColor->mColor;
3635 inherited = PR_TRUE;
3637 else if (colorData.mColor.GetUnit() == eCSSUnit_Initial) {
3638 color->mColor = mPresContext->DefaultColor();
3640 else {
3641 SetColor(colorData.mColor, parentColor->mColor, mPresContext, aContext, color->mColor,
3642 inherited);
3645 COMPUTE_END_INHERITED(Color, color)
3648 const void*
3649 nsRuleNode::ComputeBackgroundData(void* aStartStruct,
3650 const nsRuleDataStruct& aData,
3651 nsStyleContext* aContext,
3652 nsRuleNode* aHighestNode,
3653 const RuleDetail aRuleDetail,
3654 PRBool aInherited)
3656 COMPUTE_START_RESET(Background, (), bg, parentBG, Color, colorData)
3658 // save parentFlags in case bg == parentBG and we clobber them later
3659 PRUint8 parentFlags = parentBG->mBackgroundFlags;
3661 // background-color: color, string, inherit
3662 if (eCSSUnit_Initial == colorData.mBackColor.GetUnit()) {
3663 bg->mBackgroundColor = NS_RGBA(0, 0, 0, 0);
3664 } else if (!SetColor(colorData.mBackColor, parentBG->mBackgroundColor,
3665 mPresContext, aContext, bg->mBackgroundColor,
3666 inherited)) {
3667 NS_ASSERTION(eCSSUnit_Null == colorData.mBackColor.GetUnit(),
3668 "unexpected color unit");
3671 // background-image: url (stored as image), none, inherit
3672 if (eCSSUnit_Image == colorData.mBackImage.GetUnit()) {
3673 bg->mBackgroundImage = colorData.mBackImage.GetImageValue();
3675 else if (eCSSUnit_None == colorData.mBackImage.GetUnit() ||
3676 eCSSUnit_Initial == colorData.mBackImage.GetUnit()) {
3677 bg->mBackgroundImage = nsnull;
3679 else if (eCSSUnit_Inherit == colorData.mBackImage.GetUnit()) {
3680 inherited = PR_TRUE;
3681 bg->mBackgroundImage = parentBG->mBackgroundImage;
3684 if (bg->mBackgroundImage) {
3685 bg->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE;
3686 } else {
3687 bg->mBackgroundFlags |= NS_STYLE_BG_IMAGE_NONE;
3690 // background-repeat: enum, inherit, initial
3691 SetDiscrete(colorData.mBackRepeat, bg->mBackgroundRepeat, inherited,
3692 SETDSC_ENUMERATED, parentBG->mBackgroundRepeat,
3693 NS_STYLE_BG_REPEAT_XY, 0, 0, 0, 0);
3695 // background-attachment: enum, inherit, initial
3696 SetDiscrete(colorData.mBackAttachment, bg->mBackgroundAttachment, inherited,
3697 SETDSC_ENUMERATED, parentBG->mBackgroundAttachment,
3698 NS_STYLE_BG_ATTACHMENT_SCROLL, 0, 0, 0, 0);
3700 // background-clip: enum, inherit, initial
3701 SetDiscrete(colorData.mBackClip, bg->mBackgroundClip, inherited,
3702 SETDSC_ENUMERATED, parentBG->mBackgroundClip,
3703 NS_STYLE_BG_CLIP_BORDER, 0, 0, 0, 0);
3705 // background-inline-policy: enum, inherit, initial
3706 SetDiscrete(colorData.mBackInlinePolicy, bg->mBackgroundInlinePolicy,
3707 inherited, SETDSC_ENUMERATED,
3708 parentBG->mBackgroundInlinePolicy,
3709 NS_STYLE_BG_INLINE_POLICY_CONTINUOUS, 0, 0, 0, 0);
3711 // background-origin: enum, inherit, initial
3712 SetDiscrete(colorData.mBackOrigin, bg->mBackgroundOrigin, inherited,
3713 SETDSC_ENUMERATED, parentBG->mBackgroundOrigin,
3714 NS_STYLE_BG_ORIGIN_PADDING, 0, 0, 0, 0);
3716 // background-position: enum, length, percent (flags), inherit
3717 if (eCSSUnit_Percent == colorData.mBackPosition.mXValue.GetUnit()) {
3718 bg->mBackgroundXPosition.mFloat = colorData.mBackPosition.mXValue.GetPercentValue();
3719 bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PERCENT;
3720 bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH;
3722 else if (colorData.mBackPosition.mXValue.IsLengthUnit()) {
3723 bg->mBackgroundXPosition.mCoord = CalcLength(colorData.mBackPosition.mXValue,
3724 aContext, mPresContext, inherited);
3725 bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_LENGTH;
3726 bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_PERCENT;
3728 else if (eCSSUnit_Enumerated == colorData.mBackPosition.mXValue.GetUnit()) {
3729 bg->mBackgroundXPosition.mFloat =
3730 GetFloatFromBoxPosition(colorData.mBackPosition.mXValue.GetIntValue());
3732 bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PERCENT;
3733 bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH;
3735 else if (eCSSUnit_Inherit == colorData.mBackPosition.mXValue.GetUnit()) {
3736 inherited = PR_TRUE;
3737 bg->mBackgroundXPosition = parentBG->mBackgroundXPosition;
3738 bg->mBackgroundFlags &= ~(NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT);
3739 bg->mBackgroundFlags |= (parentFlags & (NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT));
3741 else if (eCSSUnit_Initial == colorData.mBackPosition.mXValue.GetUnit()) {
3742 bg->mBackgroundFlags &= ~(NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT);
3745 if (eCSSUnit_Percent == colorData.mBackPosition.mYValue.GetUnit()) {
3746 bg->mBackgroundYPosition.mFloat = colorData.mBackPosition.mYValue.GetPercentValue();
3747 bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PERCENT;
3748 bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
3750 else if (colorData.mBackPosition.mYValue.IsLengthUnit()) {
3751 bg->mBackgroundYPosition.mCoord = CalcLength(colorData.mBackPosition.mYValue,
3752 aContext, mPresContext, inherited);
3753 bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_LENGTH;
3754 bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_PERCENT;
3756 else if (eCSSUnit_Enumerated == colorData.mBackPosition.mYValue.GetUnit()) {
3757 bg->mBackgroundYPosition.mFloat =
3758 GetFloatFromBoxPosition(colorData.mBackPosition.mYValue.GetIntValue());
3760 bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PERCENT;
3761 bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
3763 else if (eCSSUnit_Inherit == colorData.mBackPosition.mYValue.GetUnit()) {
3764 inherited = PR_TRUE;
3765 bg->mBackgroundYPosition = parentBG->mBackgroundYPosition;
3766 bg->mBackgroundFlags &= ~(NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT);
3767 bg->mBackgroundFlags |= (parentFlags & (NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT));
3769 else if (eCSSUnit_Initial == colorData.mBackPosition.mYValue.GetUnit()) {
3770 bg->mBackgroundFlags &= ~(NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT);
3773 COMPUTE_END_RESET(Background, bg)
3776 const void*
3777 nsRuleNode::ComputeMarginData(void* aStartStruct,
3778 const nsRuleDataStruct& aData,
3779 nsStyleContext* aContext,
3780 nsRuleNode* aHighestNode,
3781 const RuleDetail aRuleDetail, PRBool aInherited)
3783 COMPUTE_START_RESET(Margin, (), margin, parentMargin, Margin, marginData)
3785 // margin: length, percent, auto, inherit
3786 nsStyleCoord coord;
3787 nsCSSRect ourMargin(marginData.mMargin);
3788 AdjustLogicalBoxProp(aContext,
3789 marginData.mMarginLeftLTRSource,
3790 marginData.mMarginLeftRTLSource,
3791 marginData.mMarginStart, marginData.mMarginEnd,
3792 NS_SIDE_LEFT, ourMargin, inherited);
3793 AdjustLogicalBoxProp(aContext,
3794 marginData.mMarginRightLTRSource,
3795 marginData.mMarginRightRTLSource,
3796 marginData.mMarginEnd, marginData.mMarginStart,
3797 NS_SIDE_RIGHT, ourMargin, inherited);
3798 NS_FOR_CSS_SIDES(side) {
3799 nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
3800 if (SetCoord(ourMargin.*(nsCSSRect::sides[side]),
3801 coord, parentCoord, SETCOORD_LPAH | SETCOORD_INITIAL_ZERO,
3802 aContext, mPresContext, inherited)) {
3803 margin->mMargin.Set(side, coord);
3807 margin->RecalcData();
3808 COMPUTE_END_RESET(Margin, margin)
3811 const void*
3812 nsRuleNode::ComputeBorderData(void* aStartStruct,
3813 const nsRuleDataStruct& aData,
3814 nsStyleContext* aContext,
3815 nsRuleNode* aHighestNode,
3816 const RuleDetail aRuleDetail, PRBool aInherited)
3818 COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder,
3819 Margin, marginData)
3821 // -moz-box-shadow: none, list, inherit, initial
3822 nsCSSValueList* list = marginData.mBoxShadow;
3823 if (list) {
3824 // This handles 'none' and 'initial'
3825 border->mBoxShadow = nsnull;
3827 if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
3828 inherited = PR_TRUE;
3829 border->mBoxShadow = parentBorder->mBoxShadow;
3830 } else if (eCSSUnit_Array == list->mValue.GetUnit()) {
3831 // List of arrays
3832 border->mBoxShadow = GetShadowData(list, aContext, PR_TRUE, inherited);
3836 // border-width, border-*-width: length, enum, inherit
3837 nsStyleCoord coord;
3838 nsCSSRect ourBorderWidth(marginData.mBorderWidth);
3839 AdjustLogicalBoxProp(aContext,
3840 marginData.mBorderLeftWidthLTRSource,
3841 marginData.mBorderLeftWidthRTLSource,
3842 marginData.mBorderStartWidth,
3843 marginData.mBorderEndWidth,
3844 NS_SIDE_LEFT, ourBorderWidth, inherited);
3845 AdjustLogicalBoxProp(aContext,
3846 marginData.mBorderRightWidthLTRSource,
3847 marginData.mBorderRightWidthRTLSource,
3848 marginData.mBorderEndWidth,
3849 marginData.mBorderStartWidth,
3850 NS_SIDE_RIGHT, ourBorderWidth, inherited);
3851 { // scope for compilers with broken |for| loop scoping
3852 NS_FOR_CSS_SIDES(side) {
3853 const nsCSSValue &value = ourBorderWidth.*(nsCSSRect::sides[side]);
3854 NS_ASSERTION(eCSSUnit_Percent != value.GetUnit(),
3855 "Percentage borders not implemented yet "
3856 "If implementing, make sure to fix all consumers of "
3857 "nsStyleBorder, the IsPercentageAwareChild method, "
3858 "the nsAbsoluteContainingBlock::FrameDependsOnContainer "
3859 "method, the "
3860 "nsLineLayout::IsPercentageAwareReplacedElement method "
3861 "and probably some other places");
3862 if (eCSSUnit_Enumerated == value.GetUnit()) {
3863 NS_ASSERTION(value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
3864 value.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
3865 value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
3866 "Unexpected enum value");
3867 border->SetBorderWidth(side,
3868 (mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
3870 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
3871 else if (SetCoord(value, coord, nsStyleCoord(), SETCOORD_LENGTH,
3872 aContext, mPresContext, inherited)) {
3873 NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
3874 border->SetBorderWidth(side, coord.GetCoordValue());
3876 else if (eCSSUnit_Inherit == value.GetUnit()) {
3877 inherited = PR_TRUE;
3878 border->SetBorderWidth(side,
3879 parentBorder->GetComputedBorder().side(side));
3881 else if (eCSSUnit_Initial == value.GetUnit()) {
3882 border->SetBorderWidth(side,
3883 (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
3885 else {
3886 NS_ASSERTION(eCSSUnit_Null == value.GetUnit(),
3887 "missing case handling border width");
3892 // border-style, border-*-style: enum, none, inherit
3893 nsCSSRect ourStyle(marginData.mBorderStyle);
3894 AdjustLogicalBoxProp(aContext,
3895 marginData.mBorderLeftStyleLTRSource,
3896 marginData.mBorderLeftStyleRTLSource,
3897 marginData.mBorderStartStyle, marginData.mBorderEndStyle,
3898 NS_SIDE_LEFT, ourStyle, inherited);
3899 AdjustLogicalBoxProp(aContext,
3900 marginData.mBorderRightStyleLTRSource,
3901 marginData.mBorderRightStyleRTLSource,
3902 marginData.mBorderEndStyle, marginData.mBorderStartStyle,
3903 NS_SIDE_RIGHT, ourStyle, inherited);
3904 { // scope for compilers with broken |for| loop scoping
3905 NS_FOR_CSS_SIDES(side) {
3906 const nsCSSValue &value = ourStyle.*(nsCSSRect::sides[side]);
3907 nsCSSUnit unit = value.GetUnit();
3908 if (eCSSUnit_Enumerated == unit) {
3909 border->SetBorderStyle(side, value.GetIntValue());
3911 else if (eCSSUnit_None == unit || eCSSUnit_Initial == unit) {
3912 border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
3914 else if (eCSSUnit_Inherit == unit) {
3915 inherited = PR_TRUE;
3916 border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
3921 // -moz-border-*-colors: color, string, enum
3922 nscolor borderColor;
3923 nscolor unused = NS_RGB(0,0,0);
3925 { // scope for compilers with broken |for| loop scoping
3926 NS_FOR_CSS_SIDES(side) {
3927 nsCSSValueList* list =
3928 marginData.mBorderColors.*(nsCSSValueListRect::sides[side]);
3929 // FIXME Bug 389404: Implement inherit and -moz-initial.
3930 if (list) {
3931 // Some composite border color information has been specified for this
3932 // border side.
3933 border->EnsureBorderColors();
3934 border->ClearBorderColors(side);
3935 while (list) {
3936 if (SetColor(list->mValue, unused, mPresContext,
3937 aContext, borderColor, inherited))
3938 border->AppendBorderColor(side, borderColor);
3939 list = list->mNext;
3945 // border-color, border-*-color: color, string, enum, inherit
3946 nsCSSRect ourBorderColor(marginData.mBorderColor);
3947 PRBool foreground;
3948 AdjustLogicalBoxProp(aContext,
3949 marginData.mBorderLeftColorLTRSource,
3950 marginData.mBorderLeftColorRTLSource,
3951 marginData.mBorderStartColor, marginData.mBorderEndColor,
3952 NS_SIDE_LEFT, ourBorderColor, inherited);
3953 AdjustLogicalBoxProp(aContext,
3954 marginData.mBorderRightColorLTRSource,
3955 marginData.mBorderRightColorRTLSource,
3956 marginData.mBorderEndColor, marginData.mBorderStartColor,
3957 NS_SIDE_RIGHT, ourBorderColor, inherited);
3958 { // scope for compilers with broken |for| loop scoping
3959 NS_FOR_CSS_SIDES(side) {
3960 const nsCSSValue &value = ourBorderColor.*(nsCSSRect::sides[side]);
3961 if (eCSSUnit_Inherit == value.GetUnit()) {
3962 if (parentContext) {
3963 inherited = PR_TRUE;
3964 parentBorder->GetBorderColor(side, borderColor, foreground);
3965 if (foreground) {
3966 // We want to inherit the color from the parent, not use the
3967 // color on the element where this chunk of style data will be
3968 // used. We can ensure that the data for the parent are fully
3969 // computed (unlike for the element where this will be used, for
3970 // which the color could be specified on a more specific rule).
3971 border->SetBorderColor(side, parentContext->GetStyleColor()->mColor);
3972 } else
3973 border->SetBorderColor(side, borderColor);
3974 } else {
3975 // We're the root
3976 border->SetBorderToForeground(side);
3979 else if (SetColor(value, unused, mPresContext, aContext, borderColor, inherited)) {
3980 border->SetBorderColor(side, borderColor);
3982 else if (eCSSUnit_Enumerated == value.GetUnit()) {
3983 switch (value.GetIntValue()) {
3984 case NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR:
3985 border->SetBorderToForeground(side);
3986 break;
3989 else if (eCSSUnit_Initial == value.GetUnit()) {
3990 border->SetBorderToForeground(side);
3995 // -moz-border-radius: length, percent, inherit
3997 const nsCSSCornerSizes& borderRadius = marginData.mBorderRadius;
3998 NS_FOR_CSS_HALF_CORNERS(corner) {
3999 nsStyleCoord parentCoord = parentBorder->mBorderRadius.Get(corner);
4000 if (SetCoord(borderRadius.GetHalfCorner(corner),
4001 coord, parentCoord, SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
4002 aContext, mPresContext, inherited))
4003 border->mBorderRadius.Set(corner, coord);
4007 // float-edge: enum, inherit, initial
4008 SetDiscrete(marginData.mFloatEdge, border->mFloatEdge, inherited,
4009 SETDSC_ENUMERATED, parentBorder->mFloatEdge,
4010 NS_STYLE_FLOAT_EDGE_CONTENT, 0, 0, 0, 0);
4012 // border-image
4013 if (eCSSUnit_Array == marginData.mBorderImage.GetUnit()) {
4014 nsCSSValue::Array *arr = marginData.mBorderImage.GetArrayValue();
4016 // the image
4017 if (eCSSUnit_Image == arr->Item(0).GetUnit()) {
4018 border->SetBorderImage(arr->Item(0).GetImageValue());
4021 // the numbers saying where to split the image
4022 NS_FOR_CSS_SIDES(side) {
4023 // an uninitialized parentCoord is ok because I'm not passing SETCOORD_INHERIT
4024 if (SetCoord(arr->Item(1 + side), coord, nsStyleCoord(),
4025 SETCOORD_FACTOR | SETCOORD_PERCENT, aContext,
4026 mPresContext, inherited)) {
4027 border->mBorderImageSplit.Set(side, coord);
4031 // possible replacement for border-width
4032 // if have one - have all four (see CSSParserImpl::ParseBorderImage())
4033 if (eCSSUnit_Null != arr->Item(5).GetUnit()) {
4034 NS_FOR_CSS_SIDES(side) {
4035 // an uninitialized parentCoord is ok because I'm not passing SETCOORD_INHERIT
4036 if (!SetCoord(arr->Item(5 + side), coord, nsStyleCoord(),
4037 SETCOORD_LENGTH, aContext, mPresContext, inherited)) {
4038 NS_NOTREACHED("SetCoord for border-width replacement from border-image failed");
4040 if (coord.GetUnit() == eStyleUnit_Coord) {
4041 border->SetBorderImageWidthOverride(side, coord.GetCoordValue());
4042 } else {
4043 NS_WARNING("a border-width replacement from border-image "
4044 "has a unit that's not eStyleUnit_Coord");
4045 border->SetBorderImageWidthOverride(side, 0);
4048 border->mHaveBorderImageWidth = PR_TRUE;
4049 } else {
4050 border->mHaveBorderImageWidth = PR_FALSE;
4053 // stretch/round/repeat keywords
4054 if (eCSSUnit_Null == arr->Item(9).GetUnit()) {
4055 // default, both horizontal and vertical are stretch
4056 border->mBorderImageHFill = NS_STYLE_BORDER_IMAGE_STRETCH;
4057 border->mBorderImageVFill = NS_STYLE_BORDER_IMAGE_STRETCH;
4058 } else {
4059 // have horizontal value
4060 border->mBorderImageHFill = arr->Item(9).GetIntValue();
4061 if (eCSSUnit_Null == arr->Item(10).GetUnit()) {
4062 // vertical same as horizontal
4063 border->mBorderImageVFill = border->mBorderImageHFill;
4064 } else {
4065 // have vertical value
4066 border->mBorderImageVFill = arr->Item(10).GetIntValue();
4069 } else if (eCSSUnit_None == marginData.mBorderImage.GetUnit() ||
4070 eCSSUnit_Initial == marginData.mBorderImage.GetUnit()) {
4071 border->mHaveBorderImageWidth = PR_FALSE;
4072 border->SetBorderImage(nsnull);
4073 } else if (eCSSUnit_Inherit == marginData.mBorderImage.GetUnit()) {
4074 NS_FOR_CSS_SIDES(side) {
4075 border->SetBorderImageWidthOverride(side, parentBorder->mBorderImageWidth.side(side));
4077 border->mBorderImageSplit = parentBorder->mBorderImageSplit;
4078 border->mBorderImageHFill = parentBorder->mBorderImageHFill;
4079 border->mBorderImageVFill = parentBorder->mBorderImageVFill;
4080 border->mHaveBorderImageWidth = parentBorder->mHaveBorderImageWidth;
4081 border->SetBorderImage(parentBorder->GetBorderImage());
4084 COMPUTE_END_RESET(Border, border)
4087 const void*
4088 nsRuleNode::ComputePaddingData(void* aStartStruct,
4089 const nsRuleDataStruct& aData,
4090 nsStyleContext* aContext,
4091 nsRuleNode* aHighestNode,
4092 const RuleDetail aRuleDetail, PRBool aInherited)
4094 COMPUTE_START_RESET(Padding, (), padding, parentPadding, Margin, marginData)
4096 // padding: length, percent, inherit
4097 nsStyleCoord coord;
4098 nsCSSRect ourPadding(marginData.mPadding);
4099 AdjustLogicalBoxProp(aContext,
4100 marginData.mPaddingLeftLTRSource,
4101 marginData.mPaddingLeftRTLSource,
4102 marginData.mPaddingStart, marginData.mPaddingEnd,
4103 NS_SIDE_LEFT, ourPadding, inherited);
4104 AdjustLogicalBoxProp(aContext,
4105 marginData.mPaddingRightLTRSource,
4106 marginData.mPaddingRightRTLSource,
4107 marginData.mPaddingEnd, marginData.mPaddingStart,
4108 NS_SIDE_RIGHT, ourPadding, inherited);
4109 NS_FOR_CSS_SIDES(side) {
4110 nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
4111 if (SetCoord(ourPadding.*(nsCSSRect::sides[side]),
4112 coord, parentCoord, SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
4113 aContext, mPresContext, inherited)) {
4114 padding->mPadding.Set(side, coord);
4118 padding->RecalcData();
4119 COMPUTE_END_RESET(Padding, padding)
4122 const void*
4123 nsRuleNode::ComputeOutlineData(void* aStartStruct,
4124 const nsRuleDataStruct& aData,
4125 nsStyleContext* aContext,
4126 nsRuleNode* aHighestNode,
4127 const RuleDetail aRuleDetail, PRBool aInherited)
4129 COMPUTE_START_RESET(Outline, (mPresContext), outline, parentOutline,
4130 Margin, marginData)
4132 // outline-width: length, enum, inherit
4133 if (eCSSUnit_Initial == marginData.mOutlineWidth.GetUnit()) {
4134 outline->mOutlineWidth =
4135 nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
4137 else {
4138 SetCoord(marginData.mOutlineWidth, outline->mOutlineWidth,
4139 parentOutline->mOutlineWidth, SETCOORD_LEH, aContext,
4140 mPresContext, inherited);
4143 // outline-offset: length, inherit
4144 nsStyleCoord tempCoord;
4145 if (SetCoord(marginData.mOutlineOffset, tempCoord,
4146 parentOutline->mOutlineOffset,
4147 SETCOORD_LH | SETCOORD_INITIAL_ZERO, aContext, mPresContext,
4148 inherited)) {
4149 outline->mOutlineOffset = tempCoord.GetCoordValue();
4150 } else {
4151 NS_ASSERTION(marginData.mOutlineOffset.GetUnit() == eCSSUnit_Null,
4152 "unexpected unit");
4155 // outline-color: color, string, enum, inherit
4156 nscolor outlineColor;
4157 nscolor unused = NS_RGB(0,0,0);
4158 if (eCSSUnit_Inherit == marginData.mOutlineColor.GetUnit()) {
4159 if (parentContext) {
4160 inherited = PR_TRUE;
4161 if (parentOutline->GetOutlineColor(outlineColor))
4162 outline->SetOutlineColor(outlineColor);
4163 else {
4164 #ifdef GFX_HAS_INVERT
4165 outline->SetOutlineInitialColor();
4166 #else
4167 // We want to inherit the color from the parent, not use the
4168 // color on the element where this chunk of style data will be
4169 // used. We can ensure that the data for the parent are fully
4170 // computed (unlike for the element where this will be used, for
4171 // which the color could be specified on a more specific rule).
4172 outline->SetOutlineColor(parentContext->GetStyleColor()->mColor);
4173 #endif
4175 } else {
4176 outline->SetOutlineInitialColor();
4179 else if (SetColor(marginData.mOutlineColor, unused, mPresContext, aContext, outlineColor, inherited))
4180 outline->SetOutlineColor(outlineColor);
4181 else if (eCSSUnit_Enumerated == marginData.mOutlineColor.GetUnit() ||
4182 eCSSUnit_Initial == marginData.mOutlineColor.GetUnit()) {
4183 outline->SetOutlineInitialColor();
4186 // -moz-outline-radius: length, percent, inherit
4188 nsStyleCoord coord;
4189 const nsCSSCornerSizes& outlineRadius = marginData.mOutlineRadius;
4190 NS_FOR_CSS_HALF_CORNERS(corner) {
4191 nsStyleCoord parentCoord = parentOutline->mOutlineRadius.Get(corner);
4192 if (SetCoord(outlineRadius.GetHalfCorner(corner),
4193 coord, parentCoord, SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
4194 aContext, mPresContext, inherited))
4195 outline->mOutlineRadius.Set(corner, coord);
4199 // outline-style: auto, enum, none, inherit, initial
4200 // cannot use SetDiscrete because of SetOutlineStyle
4201 if (eCSSUnit_Enumerated == marginData.mOutlineStyle.GetUnit())
4202 outline->SetOutlineStyle(marginData.mOutlineStyle.GetIntValue());
4203 else if (eCSSUnit_None == marginData.mOutlineStyle.GetUnit() ||
4204 eCSSUnit_Initial == marginData.mOutlineStyle.GetUnit())
4205 outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_NONE);
4206 else if (eCSSUnit_Auto == marginData.mOutlineStyle.GetUnit()) {
4207 outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_AUTO);
4208 } else if (eCSSUnit_Inherit == marginData.mOutlineStyle.GetUnit()) {
4209 inherited = PR_TRUE;
4210 outline->SetOutlineStyle(parentOutline->GetOutlineStyle());
4213 outline->RecalcData(mPresContext);
4214 COMPUTE_END_RESET(Outline, outline)
4217 const void*
4218 nsRuleNode::ComputeListData(void* aStartStruct,
4219 const nsRuleDataStruct& aData,
4220 nsStyleContext* aContext,
4221 nsRuleNode* aHighestNode,
4222 const RuleDetail aRuleDetail, PRBool aInherited)
4224 COMPUTE_START_INHERITED(List, (), list, parentList, List, listData)
4226 // list-style-type: enum, none, inherit, initial
4227 SetDiscrete(listData.mType, list->mListStyleType, inherited,
4228 SETDSC_ENUMERATED | SETDSC_NONE, parentList->mListStyleType,
4229 NS_STYLE_LIST_STYLE_DISC, 0,
4230 NS_STYLE_LIST_STYLE_NONE, 0, 0);
4232 // list-style-image: url, none, inherit
4233 if (eCSSUnit_Image == listData.mImage.GetUnit()) {
4234 list->mListStyleImage = listData.mImage.GetImageValue();
4236 else if (eCSSUnit_None == listData.mImage.GetUnit() ||
4237 eCSSUnit_Initial == listData.mImage.GetUnit()) {
4238 list->mListStyleImage = nsnull;
4240 else if (eCSSUnit_Inherit == listData.mImage.GetUnit()) {
4241 inherited = PR_TRUE;
4242 list->mListStyleImage = parentList->mListStyleImage;
4245 // list-style-position: enum, inherit, initial
4246 SetDiscrete(listData.mPosition, list->mListStylePosition, inherited,
4247 SETDSC_ENUMERATED, parentList->mListStylePosition,
4248 NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, 0, 0, 0, 0);
4250 // image region property: length, auto, inherit
4251 if (eCSSUnit_Inherit == listData.mImageRegion.mTop.GetUnit()) { // if one is inherit, they all are
4252 inherited = PR_TRUE;
4253 list->mImageRegion = parentList->mImageRegion;
4255 // if one is -moz-initial, they all are
4256 else if (eCSSUnit_Initial == listData.mImageRegion.mTop.GetUnit()) {
4257 list->mImageRegion.Empty();
4259 else {
4260 if (eCSSUnit_Auto == listData.mImageRegion.mTop.GetUnit())
4261 list->mImageRegion.y = 0;
4262 else if (listData.mImageRegion.mTop.IsLengthUnit())
4263 list->mImageRegion.y = CalcLength(listData.mImageRegion.mTop, aContext, mPresContext, inherited);
4265 if (eCSSUnit_Auto == listData.mImageRegion.mBottom.GetUnit())
4266 list->mImageRegion.height = 0;
4267 else if (listData.mImageRegion.mBottom.IsLengthUnit())
4268 list->mImageRegion.height = CalcLength(listData.mImageRegion.mBottom, aContext,
4269 mPresContext, inherited) - list->mImageRegion.y;
4271 if (eCSSUnit_Auto == listData.mImageRegion.mLeft.GetUnit())
4272 list->mImageRegion.x = 0;
4273 else if (listData.mImageRegion.mLeft.IsLengthUnit())
4274 list->mImageRegion.x = CalcLength(listData.mImageRegion.mLeft, aContext, mPresContext, inherited);
4276 if (eCSSUnit_Auto == listData.mImageRegion.mRight.GetUnit())
4277 list->mImageRegion.width = 0;
4278 else if (listData.mImageRegion.mRight.IsLengthUnit())
4279 list->mImageRegion.width = CalcLength(listData.mImageRegion.mRight, aContext, mPresContext, inherited) -
4280 list->mImageRegion.x;
4283 COMPUTE_END_INHERITED(List, list)
4286 const void*
4287 nsRuleNode::ComputePositionData(void* aStartStruct,
4288 const nsRuleDataStruct& aData,
4289 nsStyleContext* aContext,
4290 nsRuleNode* aHighestNode,
4291 const RuleDetail aRuleDetail, PRBool aInherited)
4293 COMPUTE_START_RESET(Position, (), pos, parentPos, Position, posData)
4295 // box offsets: length, percent, auto, inherit
4296 nsStyleCoord coord;
4297 NS_FOR_CSS_SIDES(side) {
4298 nsStyleCoord parentCoord = parentPos->mOffset.Get(side);
4299 if (SetCoord(posData.mOffset.*(nsCSSRect::sides[side]),
4300 coord, parentCoord, SETCOORD_LPAH | SETCOORD_INITIAL_AUTO,
4301 aContext, mPresContext, inherited)) {
4302 pos->mOffset.Set(side, coord);
4306 SetCoord(posData.mWidth, pos->mWidth, parentPos->mWidth,
4307 SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO, aContext,
4308 mPresContext, inherited);
4309 SetCoord(posData.mMinWidth, pos->mMinWidth, parentPos->mMinWidth,
4310 SETCOORD_LPEH | SETCOORD_INITIAL_ZERO, aContext,
4311 mPresContext, inherited);
4312 SetCoord(posData.mMaxWidth, pos->mMaxWidth, parentPos->mMaxWidth,
4313 SETCOORD_LPOEH | SETCOORD_INITIAL_NONE, aContext,
4314 mPresContext, inherited);
4316 SetCoord(posData.mHeight, pos->mHeight, parentPos->mHeight,
4317 SETCOORD_LPAH | SETCOORD_INITIAL_AUTO, aContext,
4318 mPresContext, inherited);
4319 SetCoord(posData.mMinHeight, pos->mMinHeight, parentPos->mMinHeight,
4320 SETCOORD_LPH | SETCOORD_INITIAL_ZERO, aContext,
4321 mPresContext, inherited);
4322 SetCoord(posData.mMaxHeight, pos->mMaxHeight, parentPos->mMaxHeight,
4323 SETCOORD_LPOH | SETCOORD_INITIAL_NONE, aContext,
4324 mPresContext, inherited);
4326 // box-sizing: enum, inherit, initial
4327 SetDiscrete(posData.mBoxSizing, pos->mBoxSizing, inherited,
4328 SETDSC_ENUMERATED, parentPos->mBoxSizing,
4329 NS_STYLE_BOX_SIZING_CONTENT, 0, 0, 0, 0);
4331 // z-index
4332 if (! SetCoord(posData.mZIndex, pos->mZIndex, parentPos->mZIndex,
4333 SETCOORD_IA | SETCOORD_INITIAL_AUTO, aContext,
4334 nsnull, inherited)) {
4335 if (eCSSUnit_Inherit == posData.mZIndex.GetUnit()) {
4336 // handle inherit, because it's ok to inherit 'auto' here
4337 inherited = PR_TRUE;
4338 pos->mZIndex = parentPos->mZIndex;
4342 COMPUTE_END_RESET(Position, pos)
4345 const void*
4346 nsRuleNode::ComputeTableData(void* aStartStruct,
4347 const nsRuleDataStruct& aData,
4348 nsStyleContext* aContext,
4349 nsRuleNode* aHighestNode,
4350 const RuleDetail aRuleDetail, PRBool aInherited)
4352 COMPUTE_START_RESET(Table, (), table, parentTable, Table, tableData)
4354 // table-layout: auto, enum, inherit, initial
4355 SetDiscrete(tableData.mLayout, table->mLayoutStrategy, inherited,
4356 SETDSC_ENUMERATED | SETDSC_AUTO,
4357 parentTable->mLayoutStrategy,
4358 NS_STYLE_TABLE_LAYOUT_AUTO,
4359 NS_STYLE_TABLE_LAYOUT_AUTO, 0, 0, 0);
4361 // rules: enum (not a real CSS prop)
4362 if (eCSSUnit_Enumerated == tableData.mRules.GetUnit())
4363 table->mRules = tableData.mRules.GetIntValue();
4365 // frame: enum (not a real CSS prop)
4366 if (eCSSUnit_Enumerated == tableData.mFrame.GetUnit())
4367 table->mFrame = tableData.mFrame.GetIntValue();
4369 // cols: enum, int (not a real CSS prop)
4370 if (eCSSUnit_Enumerated == tableData.mCols.GetUnit() ||
4371 eCSSUnit_Integer == tableData.mCols.GetUnit())
4372 table->mCols = tableData.mCols.GetIntValue();
4374 // span: pixels (not a real CSS prop)
4375 if (eCSSUnit_Enumerated == tableData.mSpan.GetUnit() ||
4376 eCSSUnit_Integer == tableData.mSpan.GetUnit())
4377 table->mSpan = tableData.mSpan.GetIntValue();
4379 COMPUTE_END_RESET(Table, table)
4382 const void*
4383 nsRuleNode::ComputeTableBorderData(void* aStartStruct,
4384 const nsRuleDataStruct& aData,
4385 nsStyleContext* aContext,
4386 nsRuleNode* aHighestNode,
4387 const RuleDetail aRuleDetail, PRBool aInherited)
4389 COMPUTE_START_INHERITED(TableBorder, (mPresContext), table, parentTable,
4390 Table, tableData)
4392 // border-collapse: enum, inherit, initial
4393 SetDiscrete(tableData.mBorderCollapse, table->mBorderCollapse, inherited,
4394 SETDSC_ENUMERATED, parentTable->mBorderCollapse,
4395 NS_STYLE_BORDER_SEPARATE, 0, 0, 0, 0);
4397 // border-spacing-x: length, inherit
4398 nsStyleCoord tempCoord;
4399 if (SetCoord(tableData.mBorderSpacing.mXValue, tempCoord,
4400 parentTable->mBorderSpacingX,
4401 SETCOORD_LH | SETCOORD_INITIAL_ZERO,
4402 aContext, mPresContext, inherited)) {
4403 table->mBorderSpacingX = tempCoord.GetCoordValue();
4404 } else {
4405 NS_ASSERTION(tableData.mBorderSpacing.mXValue.GetUnit() == eCSSUnit_Null,
4406 "unexpected unit");
4409 // border-spacing-y: length, inherit
4410 if (SetCoord(tableData.mBorderSpacing.mYValue, tempCoord,
4411 parentTable->mBorderSpacingY,
4412 SETCOORD_LH | SETCOORD_INITIAL_ZERO,
4413 aContext, mPresContext, inherited)) {
4414 table->mBorderSpacingY = tempCoord.GetCoordValue();
4415 } else {
4416 NS_ASSERTION(tableData.mBorderSpacing.mYValue.GetUnit() == eCSSUnit_Null,
4417 "unexpected unit");
4420 // caption-side: enum, inherit, initial
4421 SetDiscrete(tableData.mCaptionSide, table->mCaptionSide, inherited,
4422 SETDSC_ENUMERATED, parentTable->mCaptionSide,
4423 NS_STYLE_CAPTION_SIDE_TOP, 0, 0, 0, 0);
4425 // empty-cells: enum, inherit, initial
4426 SetDiscrete(tableData.mEmptyCells, table->mEmptyCells, inherited,
4427 SETDSC_ENUMERATED, parentTable->mEmptyCells,
4428 (mPresContext->CompatibilityMode() == eCompatibility_NavQuirks)
4429 ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
4430 : NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
4431 0, 0, 0, 0);
4433 COMPUTE_END_INHERITED(TableBorder, table)
4436 const void*
4437 nsRuleNode::ComputeContentData(void* aStartStruct,
4438 const nsRuleDataStruct& aData,
4439 nsStyleContext* aContext,
4440 nsRuleNode* aHighestNode,
4441 const RuleDetail aRuleDetail, PRBool aInherited)
4443 COMPUTE_START_RESET(Content, (), content, parentContent,
4444 Content, contentData)
4446 // content: [string, url, counter, attr, enum]+, normal, none, inherit
4447 PRUint32 count;
4448 nsAutoString buffer;
4449 nsCSSValueList* contentValue = contentData.mContent;
4450 if (contentValue) {
4451 if (eCSSUnit_Normal == contentValue->mValue.GetUnit() ||
4452 eCSSUnit_None == contentValue->mValue.GetUnit() ||
4453 eCSSUnit_Initial == contentValue->mValue.GetUnit()) {
4454 // "normal", "none", and "initial" all mean no content
4455 content->AllocateContents(0);
4457 else if (eCSSUnit_Inherit == contentValue->mValue.GetUnit()) {
4458 inherited = PR_TRUE;
4459 count = parentContent->ContentCount();
4460 if (NS_SUCCEEDED(content->AllocateContents(count))) {
4461 while (0 < count--) {
4462 content->ContentAt(count) = parentContent->ContentAt(count);
4466 else {
4467 count = 0;
4468 while (contentValue) {
4469 count++;
4470 contentValue = contentValue->mNext;
4472 if (NS_SUCCEEDED(content->AllocateContents(count))) {
4473 const nsAutoString nullStr;
4474 count = 0;
4475 contentValue = contentData.mContent;
4476 while (contentValue) {
4477 const nsCSSValue& value = contentValue->mValue;
4478 nsCSSUnit unit = value.GetUnit();
4479 nsStyleContentType type;
4480 nsStyleContentData &data = content->ContentAt(count++);
4481 switch (unit) {
4482 case eCSSUnit_String: type = eStyleContentType_String; break;
4483 case eCSSUnit_Image: type = eStyleContentType_Image; break;
4484 case eCSSUnit_Attr: type = eStyleContentType_Attr; break;
4485 case eCSSUnit_Counter: type = eStyleContentType_Counter; break;
4486 case eCSSUnit_Counters: type = eStyleContentType_Counters; break;
4487 case eCSSUnit_Enumerated:
4488 switch (value.GetIntValue()) {
4489 case NS_STYLE_CONTENT_OPEN_QUOTE:
4490 type = eStyleContentType_OpenQuote; break;
4491 case NS_STYLE_CONTENT_CLOSE_QUOTE:
4492 type = eStyleContentType_CloseQuote; break;
4493 case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
4494 type = eStyleContentType_NoOpenQuote; break;
4495 case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
4496 type = eStyleContentType_NoCloseQuote; break;
4497 case NS_STYLE_CONTENT_ALT_CONTENT:
4498 type = eStyleContentType_AltContent; break;
4499 default:
4500 NS_ERROR("bad content value");
4502 break;
4503 default:
4504 NS_ERROR("bad content type");
4506 data.mType = type;
4507 if (type == eStyleContentType_Image) {
4508 data.mContent.mImage = value.GetImageValue();
4509 NS_IF_ADDREF(data.mContent.mImage);
4511 else if (type <= eStyleContentType_Attr) {
4512 value.GetStringValue(buffer);
4513 Unquote(buffer);
4514 data.mContent.mString = NS_strdup(buffer.get());
4516 else if (type <= eStyleContentType_Counters) {
4517 data.mContent.mCounters = value.GetArrayValue();
4518 data.mContent.mCounters->AddRef();
4520 else {
4521 data.mContent.mString = nsnull;
4523 contentValue = contentValue->mNext;
4529 // counter-increment: [string [int]]+, none, inherit
4530 nsCSSValuePairList* ourIncrement = contentData.mCounterIncrement;
4531 if (ourIncrement) {
4532 if (eCSSUnit_None == ourIncrement->mXValue.GetUnit() ||
4533 eCSSUnit_Initial == ourIncrement->mXValue.GetUnit()) {
4534 content->AllocateCounterIncrements(0);
4536 else if (eCSSUnit_Inherit == ourIncrement->mXValue.GetUnit()) {
4537 inherited = PR_TRUE;
4538 count = parentContent->CounterIncrementCount();
4539 if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
4540 while (0 < count--) {
4541 const nsStyleCounterData *data =
4542 parentContent->GetCounterIncrementAt(count);
4543 content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
4547 else if (eCSSUnit_String == ourIncrement->mXValue.GetUnit()) {
4548 count = 0;
4549 while (ourIncrement) {
4550 count++;
4551 ourIncrement = ourIncrement->mNext;
4553 if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
4554 count = 0;
4555 ourIncrement = contentData.mCounterIncrement;
4556 while (ourIncrement) {
4557 PRInt32 increment;
4558 if (eCSSUnit_Integer == ourIncrement->mYValue.GetUnit()) {
4559 increment = ourIncrement->mYValue.GetIntValue();
4561 else {
4562 increment = 1;
4564 ourIncrement->mXValue.GetStringValue(buffer);
4565 content->SetCounterIncrementAt(count++, buffer, increment);
4566 ourIncrement = ourIncrement->mNext;
4572 // counter-reset: [string [int]]+, none, inherit
4573 nsCSSValuePairList* ourReset = contentData.mCounterReset;
4574 if (ourReset) {
4575 if (eCSSUnit_None == ourReset->mXValue.GetUnit() ||
4576 eCSSUnit_Initial == ourReset->mXValue.GetUnit()) {
4577 content->AllocateCounterResets(0);
4579 else if (eCSSUnit_Inherit == ourReset->mXValue.GetUnit()) {
4580 inherited = PR_TRUE;
4581 count = parentContent->CounterResetCount();
4582 if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
4583 while (0 < count--) {
4584 const nsStyleCounterData *data =
4585 parentContent->GetCounterResetAt(count);
4586 content->SetCounterResetAt(count, data->mCounter, data->mValue);
4590 else if (eCSSUnit_String == ourReset->mXValue.GetUnit()) {
4591 count = 0;
4592 while (ourReset) {
4593 count++;
4594 ourReset = ourReset->mNext;
4596 if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
4597 count = 0;
4598 ourReset = contentData.mCounterReset;
4599 while (ourReset) {
4600 PRInt32 reset;
4601 if (eCSSUnit_Integer == ourReset->mYValue.GetUnit()) {
4602 reset = ourReset->mYValue.GetIntValue();
4604 else {
4605 reset = 0;
4607 ourReset->mXValue.GetStringValue(buffer);
4608 content->SetCounterResetAt(count++, buffer, reset);
4609 ourReset = ourReset->mNext;
4615 // marker-offset: length, auto, inherit
4616 SetCoord(contentData.mMarkerOffset, content->mMarkerOffset, parentContent->mMarkerOffset,
4617 SETCOORD_LH | SETCOORD_AUTO | SETCOORD_INITIAL_AUTO, aContext,
4618 mPresContext, inherited);
4620 COMPUTE_END_RESET(Content, content)
4623 const void*
4624 nsRuleNode::ComputeQuotesData(void* aStartStruct,
4625 const nsRuleDataStruct& aData,
4626 nsStyleContext* aContext,
4627 nsRuleNode* aHighestNode,
4628 const RuleDetail aRuleDetail, PRBool aInherited)
4630 COMPUTE_START_INHERITED(Quotes, (), quotes, parentQuotes,
4631 Content, contentData)
4633 // quotes: inherit, initial, none, [string string]+
4634 nsCSSValuePairList* ourQuotes = contentData.mQuotes;
4635 if (ourQuotes) {
4636 if (eCSSUnit_Inherit == ourQuotes->mXValue.GetUnit()) {
4637 inherited = PR_TRUE;
4638 quotes->CopyFrom(*parentQuotes);
4640 else if (eCSSUnit_Initial == ourQuotes->mXValue.GetUnit()) {
4641 quotes->SetInitial();
4643 else if (eCSSUnit_None == ourQuotes->mXValue.GetUnit()) {
4644 quotes->AllocateQuotes(0);
4646 else if (eCSSUnit_String == ourQuotes->mXValue.GetUnit()) {
4647 nsAutoString buffer;
4648 nsAutoString closeBuffer;
4649 PRUint32 count = 0;
4651 while (ourQuotes) {
4652 count++;
4653 ourQuotes = ourQuotes->mNext;
4655 if (NS_SUCCEEDED(quotes->AllocateQuotes(count))) {
4656 count = 0;
4657 ourQuotes = contentData.mQuotes;
4658 while (ourQuotes) {
4659 ourQuotes->mXValue.GetStringValue(buffer);
4660 ourQuotes->mYValue.GetStringValue(closeBuffer);
4661 Unquote(buffer);
4662 Unquote(closeBuffer);
4663 quotes->SetQuotesAt(count++, buffer, closeBuffer);
4664 ourQuotes = ourQuotes->mNext;
4670 COMPUTE_END_INHERITED(Quotes, quotes)
4673 const void*
4674 nsRuleNode::ComputeXULData(void* aStartStruct,
4675 const nsRuleDataStruct& aData,
4676 nsStyleContext* aContext,
4677 nsRuleNode* aHighestNode,
4678 const RuleDetail aRuleDetail, PRBool aInherited)
4680 COMPUTE_START_RESET(XUL, (), xul, parentXUL, XUL, xulData)
4682 // box-align: enum, inherit, initial
4683 SetDiscrete(xulData.mBoxAlign, xul->mBoxAlign, inherited,
4684 SETDSC_ENUMERATED, parentXUL->mBoxAlign,
4685 NS_STYLE_BOX_ALIGN_STRETCH, 0, 0, 0, 0);
4687 // box-direction: enum, inherit, initial
4688 SetDiscrete(xulData.mBoxDirection, xul->mBoxDirection, inherited,
4689 SETDSC_ENUMERATED, parentXUL->mBoxDirection,
4690 NS_STYLE_BOX_DIRECTION_NORMAL, 0, 0, 0, 0);
4692 // box-flex: factor, inherit
4693 SetFactor(xulData.mBoxFlex, xul->mBoxFlex, inherited,
4694 parentXUL->mBoxFlex, 0.0f);
4696 // box-orient: enum, inherit, initial
4697 SetDiscrete(xulData.mBoxOrient, xul->mBoxOrient, inherited,
4698 SETDSC_ENUMERATED, parentXUL->mBoxOrient,
4699 NS_STYLE_BOX_ORIENT_HORIZONTAL, 0, 0, 0, 0);
4701 // box-pack: enum, inherit, initial
4702 SetDiscrete(xulData.mBoxPack, xul->mBoxPack, inherited,
4703 SETDSC_ENUMERATED, parentXUL->mBoxPack,
4704 NS_STYLE_BOX_PACK_START, 0, 0, 0, 0);
4706 // box-ordinal-group: integer, inherit, initial
4707 SetDiscrete(xulData.mBoxOrdinal, xul->mBoxOrdinal, inherited,
4708 SETDSC_INTEGER, parentXUL->mBoxOrdinal, 1,
4709 0, 0, 0, 0);
4711 if (eCSSUnit_Inherit == xulData.mStackSizing.GetUnit()) {
4712 inherited = PR_TRUE;
4713 xul->mStretchStack = parentXUL->mStretchStack;
4714 } else if (eCSSUnit_Initial == xulData.mStackSizing.GetUnit()) {
4715 xul->mStretchStack = PR_TRUE;
4716 } else if (eCSSUnit_Enumerated == xulData.mStackSizing.GetUnit()) {
4717 xul->mStretchStack = xulData.mStackSizing.GetIntValue() ==
4718 NS_STYLE_STACK_SIZING_STRETCH_TO_FIT;
4721 COMPUTE_END_RESET(XUL, xul)
4724 const void*
4725 nsRuleNode::ComputeColumnData(void* aStartStruct,
4726 const nsRuleDataStruct& aData,
4727 nsStyleContext* aContext,
4728 nsRuleNode* aHighestNode,
4729 const RuleDetail aRuleDetail, PRBool aInherited)
4731 COMPUTE_START_RESET(Column, (mPresContext), column, parent, Column, columnData)
4733 // column-width: length, auto, inherit
4734 SetCoord(columnData.mColumnWidth,
4735 column->mColumnWidth, parent->mColumnWidth,
4736 SETCOORD_LAH | SETCOORD_INITIAL_AUTO,
4737 aContext, mPresContext, inherited);
4739 // column-gap: length, percentage, inherit, normal
4740 SetCoord(columnData.mColumnGap,
4741 column->mColumnGap, parent->mColumnGap,
4742 SETCOORD_LPH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL,
4743 aContext, mPresContext, inherited);
4745 // column-count: auto, integer, inherit
4746 if (eCSSUnit_Auto == columnData.mColumnCount.GetUnit() ||
4747 eCSSUnit_Initial == columnData.mColumnCount.GetUnit()) {
4748 column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
4749 } else if (eCSSUnit_Integer == columnData.mColumnCount.GetUnit()) {
4750 column->mColumnCount = columnData.mColumnCount.GetIntValue();
4751 // Max 1000 columns - wallpaper for bug 345583.
4752 column->mColumnCount = PR_MIN(column->mColumnCount, 1000);
4753 } else if (eCSSUnit_Inherit == columnData.mColumnCount.GetUnit()) {
4754 inherited = PR_TRUE;
4755 column->mColumnCount = parent->mColumnCount;
4758 // column-rule-width: length, enum, inherit
4759 const nsCSSValue& widthValue = columnData.mColumnRuleWidth;
4760 if (eCSSUnit_Initial == widthValue.GetUnit()) {
4761 column->SetColumnRuleWidth(
4762 (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
4764 else if (eCSSUnit_Enumerated == widthValue.GetUnit()) {
4765 NS_ASSERTION(widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
4766 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
4767 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
4768 "Unexpected enum value");
4769 column->SetColumnRuleWidth(
4770 (mPresContext->GetBorderWidthTable())[widthValue.GetIntValue()]);
4772 else if (eCSSUnit_Inherit == widthValue.GetUnit()) {
4773 column->SetColumnRuleWidth(parent->GetComputedColumnRuleWidth());
4774 inherited = PR_TRUE;
4776 else if (widthValue.IsLengthUnit()) {
4777 column->SetColumnRuleWidth(CalcLength(widthValue, aContext,
4778 mPresContext, inherited));
4781 // column-rule-style: enum, none, inherit
4782 const nsCSSValue& styleValue = columnData.mColumnRuleStyle;
4783 if (eCSSUnit_Enumerated == styleValue.GetUnit()) {
4784 column->mColumnRuleStyle = styleValue.GetIntValue();
4786 else if (eCSSUnit_None == styleValue.GetUnit() ||
4787 eCSSUnit_Initial == styleValue.GetUnit()) {
4788 column->mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
4790 else if (eCSSUnit_Inherit == styleValue.GetUnit()) {
4791 inherited = PR_TRUE;
4792 column->mColumnRuleStyle = parent->mColumnRuleStyle;
4795 // column-rule-color: color, inherit
4796 const nsCSSValue& colorValue = columnData.mColumnRuleColor;
4797 if (eCSSUnit_Inherit == colorValue.GetUnit()) {
4798 inherited = PR_TRUE;
4799 column->mColumnRuleColorIsForeground = PR_FALSE;
4800 if (parent->mColumnRuleColorIsForeground) {
4801 column->mColumnRuleColor = parentContext->GetStyleColor()->mColor;
4802 } else {
4803 column->mColumnRuleColor = parent->mColumnRuleColor;
4806 else if (eCSSUnit_Initial == colorValue.GetUnit()) {
4807 column->mColumnRuleColorIsForeground = PR_TRUE;
4809 else if (SetColor(colorValue, 0, mPresContext, aContext, column->mColumnRuleColor, inherited)) {
4810 column->mColumnRuleColorIsForeground = PR_FALSE;
4813 COMPUTE_END_RESET(Column, column)
4816 #ifdef MOZ_SVG
4817 static void
4818 SetSVGPaint(const nsCSSValuePair& aValue, const nsStyleSVGPaint& parentPaint,
4819 nsPresContext* aPresContext, nsStyleContext *aContext,
4820 nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
4821 PRBool& aInherited)
4823 nscolor color;
4825 if (aValue.mXValue.GetUnit() == eCSSUnit_Inherit) {
4826 aResult = parentPaint;
4827 aInherited = PR_TRUE;
4828 } else if (aValue.mXValue.GetUnit() == eCSSUnit_None) {
4829 aResult.SetType(eStyleSVGPaintType_None);
4830 } else if (aValue.mXValue.GetUnit() == eCSSUnit_Initial) {
4831 aResult.SetType(aInitialPaintType);
4832 aResult.mPaint.mColor = NS_RGB(0, 0, 0);
4833 aResult.mFallbackColor = NS_RGB(0, 0, 0);
4834 } else if (aValue.mXValue.GetUnit() == eCSSUnit_URL) {
4835 aResult.SetType(eStyleSVGPaintType_Server);
4836 aResult.mPaint.mPaintServer = aValue.mXValue.GetURLValue();
4837 NS_IF_ADDREF(aResult.mPaint.mPaintServer);
4838 if (aValue.mYValue.GetUnit() == eCSSUnit_None) {
4839 aResult.mFallbackColor = NS_RGBA(0, 0, 0, 0);
4840 } else {
4841 NS_ASSERTION(aValue.mYValue.GetUnit() != eCSSUnit_Inherit, "cannot inherit fallback colour");
4842 SetColor(aValue.mYValue, NS_RGB(0, 0, 0), aPresContext, aContext, aResult.mFallbackColor, aInherited);
4844 } else if (SetColor(aValue.mXValue, parentPaint.mPaint.mColor, aPresContext, aContext, color, aInherited)) {
4845 aResult.SetType(eStyleSVGPaintType_Color);
4846 aResult.mPaint.mColor = color;
4850 const void*
4851 nsRuleNode::ComputeSVGData(void* aStartStruct,
4852 const nsRuleDataStruct& aData,
4853 nsStyleContext* aContext,
4854 nsRuleNode* aHighestNode,
4855 const RuleDetail aRuleDetail, PRBool aInherited)
4857 COMPUTE_START_INHERITED(SVG, (), svg, parentSVG, SVG, SVGData)
4859 // clip-rule: enum, inherit, initial
4860 SetDiscrete(SVGData.mClipRule, svg->mClipRule, inherited,
4861 SETDSC_ENUMERATED, parentSVG->mClipRule,
4862 NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
4864 // color-interpolation: enum, auto, inherit, initial
4865 SetDiscrete(SVGData.mColorInterpolation, svg->mColorInterpolation, inherited,
4866 SETDSC_ENUMERATED | SETDSC_AUTO,
4867 parentSVG->mColorInterpolation,
4868 NS_STYLE_COLOR_INTERPOLATION_SRGB,
4869 NS_STYLE_COLOR_INTERPOLATION_AUTO, 0, 0, 0);
4871 // color-interpolation-filters: enum, auto, inherit, initial
4872 SetDiscrete(SVGData.mColorInterpolationFilters,
4873 svg->mColorInterpolationFilters, inherited,
4874 SETDSC_ENUMERATED | SETDSC_AUTO,
4875 parentSVG->mColorInterpolationFilters,
4876 NS_STYLE_COLOR_INTERPOLATION_LINEARRGB,
4877 NS_STYLE_COLOR_INTERPOLATION_AUTO, 0, 0, 0);
4879 // fill:
4880 SetSVGPaint(SVGData.mFill, parentSVG->mFill, mPresContext, aContext,
4881 svg->mFill, eStyleSVGPaintType_Color, inherited);
4883 // fill-opacity: factor, inherit, initial
4884 SetFactor(SVGData.mFillOpacity, svg->mFillOpacity, inherited,
4885 parentSVG->mFillOpacity, 1.0f, SETFCT_OPACITY);
4887 // fill-rule: enum, inherit, initial
4888 SetDiscrete(SVGData.mFillRule, svg->mFillRule, inherited,
4889 SETDSC_ENUMERATED, parentSVG->mFillRule,
4890 NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
4892 // marker-end: url, none, inherit
4893 if (eCSSUnit_URL == SVGData.mMarkerEnd.GetUnit()) {
4894 svg->mMarkerEnd = SVGData.mMarkerEnd.GetURLValue();
4895 } else if (eCSSUnit_None == SVGData.mMarkerEnd.GetUnit() ||
4896 eCSSUnit_Initial == SVGData.mMarkerEnd.GetUnit()) {
4897 svg->mMarkerEnd = nsnull;
4898 } else if (eCSSUnit_Inherit == SVGData.mMarkerEnd.GetUnit()) {
4899 inherited = PR_TRUE;
4900 svg->mMarkerEnd = parentSVG->mMarkerEnd;
4903 // marker-mid: url, none, inherit
4904 if (eCSSUnit_URL == SVGData.mMarkerMid.GetUnit()) {
4905 svg->mMarkerMid = SVGData.mMarkerMid.GetURLValue();
4906 } else if (eCSSUnit_None == SVGData.mMarkerMid.GetUnit() ||
4907 eCSSUnit_Initial == SVGData.mMarkerMid.GetUnit()) {
4908 svg->mMarkerMid = nsnull;
4909 } else if (eCSSUnit_Inherit == SVGData.mMarkerMid.GetUnit()) {
4910 inherited = PR_TRUE;
4911 svg->mMarkerMid = parentSVG->mMarkerMid;
4914 // marker-start: url, none, inherit
4915 if (eCSSUnit_URL == SVGData.mMarkerStart.GetUnit()) {
4916 svg->mMarkerStart = SVGData.mMarkerStart.GetURLValue();
4917 } else if (eCSSUnit_None == SVGData.mMarkerStart.GetUnit() ||
4918 eCSSUnit_Initial == SVGData.mMarkerStart.GetUnit()) {
4919 svg->mMarkerStart = nsnull;
4920 } else if (eCSSUnit_Inherit == SVGData.mMarkerStart.GetUnit()) {
4921 inherited = PR_TRUE;
4922 svg->mMarkerStart = parentSVG->mMarkerStart;
4925 // pointer-events: enum, none, inherit, initial
4926 SetDiscrete(SVGData.mPointerEvents, svg->mPointerEvents, inherited,
4927 SETDSC_ENUMERATED | SETDSC_NONE, parentSVG->mPointerEvents,
4928 NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED, 0,
4929 NS_STYLE_POINTER_EVENTS_NONE, 0, 0);
4931 // shape-rendering: enum, auto, inherit
4932 SetDiscrete(SVGData.mShapeRendering, svg->mShapeRendering, inherited,
4933 SETDSC_ENUMERATED | SETDSC_AUTO,
4934 parentSVG->mShapeRendering,
4935 NS_STYLE_SHAPE_RENDERING_AUTO,
4936 NS_STYLE_SHAPE_RENDERING_AUTO, 0, 0, 0);
4938 // stroke:
4939 SetSVGPaint(SVGData.mStroke, parentSVG->mStroke, mPresContext, aContext,
4940 svg->mStroke, eStyleSVGPaintType_None, inherited);
4942 // stroke-dasharray: <dasharray>, none, inherit
4943 nsCSSValueList *list = SVGData.mStrokeDasharray;
4944 if (list) {
4945 if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
4946 // only do the copy if weren't already set up by the copy constructor
4947 // FIXME Bug 389408: This is broken when aStartStruct is non-null!
4948 if (!svg->mStrokeDasharray) {
4949 inherited = PR_TRUE;
4950 svg->mStrokeDasharrayLength = parentSVG->mStrokeDasharrayLength;
4951 if (svg->mStrokeDasharrayLength) {
4952 svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
4953 if (svg->mStrokeDasharray)
4954 memcpy(svg->mStrokeDasharray,
4955 parentSVG->mStrokeDasharray,
4956 svg->mStrokeDasharrayLength * sizeof(nsStyleCoord));
4957 else
4958 svg->mStrokeDasharrayLength = 0;
4961 } else {
4962 delete [] svg->mStrokeDasharray;
4963 svg->mStrokeDasharray = nsnull;
4964 svg->mStrokeDasharrayLength = 0;
4966 if (eCSSUnit_Initial != list->mValue.GetUnit() &&
4967 eCSSUnit_None != list->mValue.GetUnit()) {
4968 // count number of values
4969 nsCSSValueList *value = SVGData.mStrokeDasharray;
4970 while (nsnull != value) {
4971 ++svg->mStrokeDasharrayLength;
4972 value = value->mNext;
4975 NS_ASSERTION(svg->mStrokeDasharrayLength != 0, "no dasharray items");
4977 svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
4979 if (svg->mStrokeDasharray) {
4980 value = SVGData.mStrokeDasharray;
4981 PRUint32 i = 0;
4982 while (nsnull != value) {
4983 SetCoord(value->mValue,
4984 svg->mStrokeDasharray[i++], nsnull,
4985 SETCOORD_LP | SETCOORD_FACTOR,
4986 aContext, mPresContext, inherited);
4987 value = value->mNext;
4989 } else
4990 svg->mStrokeDasharrayLength = 0;
4995 // stroke-dashoffset: <dashoffset>, inherit
4996 SetCoord(SVGData.mStrokeDashoffset,
4997 svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
4998 SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_INITIAL_ZERO,
4999 aContext, mPresContext, inherited);
5001 // stroke-linecap: enum, inherit, initial
5002 SetDiscrete(SVGData.mStrokeLinecap, svg->mStrokeLinecap, inherited,
5003 SETDSC_ENUMERATED, parentSVG->mStrokeLinecap,
5004 NS_STYLE_STROKE_LINECAP_BUTT, 0, 0, 0, 0);
5006 // stroke-linejoin: enum, inherit, initial
5007 SetDiscrete(SVGData.mStrokeLinejoin, svg->mStrokeLinejoin, inherited,
5008 SETDSC_ENUMERATED, parentSVG->mStrokeLinejoin,
5009 NS_STYLE_STROKE_LINEJOIN_MITER, 0, 0, 0, 0);
5011 // stroke-miterlimit: <miterlimit>, inherit
5012 SetFactor(SVGData.mStrokeMiterlimit, svg->mStrokeMiterlimit, inherited,
5013 parentSVG->mStrokeMiterlimit, 4.0f);
5015 // stroke-opacity:
5016 SetFactor(SVGData.mStrokeOpacity, svg->mStrokeOpacity, inherited,
5017 parentSVG->mStrokeOpacity, 1.0f, SETFCT_OPACITY);
5019 // stroke-width:
5020 if (eCSSUnit_Initial == SVGData.mStrokeWidth.GetUnit()) {
5021 svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
5022 } else {
5023 SetCoord(SVGData.mStrokeWidth,
5024 svg->mStrokeWidth, parentSVG->mStrokeWidth,
5025 SETCOORD_LPH | SETCOORD_FACTOR,
5026 aContext, mPresContext, inherited);
5029 // text-anchor: enum, inherit, initial
5030 SetDiscrete(SVGData.mTextAnchor, svg->mTextAnchor, inherited,
5031 SETDSC_ENUMERATED, parentSVG->mTextAnchor,
5032 NS_STYLE_TEXT_ANCHOR_START, 0, 0, 0, 0);
5034 // text-rendering: enum, auto, inherit, initial
5035 SetDiscrete(SVGData.mTextRendering, svg->mTextRendering, inherited,
5036 SETDSC_ENUMERATED | SETDSC_AUTO,
5037 parentSVG->mTextRendering,
5038 NS_STYLE_TEXT_RENDERING_AUTO,
5039 NS_STYLE_TEXT_RENDERING_AUTO, 0, 0, 0);
5041 COMPUTE_END_INHERITED(SVG, svg)
5044 const void*
5045 nsRuleNode::ComputeSVGResetData(void* aStartStruct,
5046 const nsRuleDataStruct& aData,
5047 nsStyleContext* aContext,
5048 nsRuleNode* aHighestNode,
5049 const RuleDetail aRuleDetail, PRBool aInherited)
5051 COMPUTE_START_RESET(SVGReset, (), svgReset, parentSVGReset, SVG, SVGData)
5053 // stop-color:
5054 if (eCSSUnit_Initial == SVGData.mStopColor.GetUnit()) {
5055 svgReset->mStopColor = NS_RGB(0, 0, 0);
5056 } else {
5057 SetColor(SVGData.mStopColor, parentSVGReset->mStopColor,
5058 mPresContext, aContext, svgReset->mStopColor, inherited);
5061 // flood-color:
5062 if (eCSSUnit_Initial == SVGData.mFloodColor.GetUnit()) {
5063 svgReset->mFloodColor = NS_RGB(0, 0, 0);
5064 } else {
5065 SetColor(SVGData.mFloodColor, parentSVGReset->mFloodColor,
5066 mPresContext, aContext, svgReset->mFloodColor, inherited);
5069 // lighting-color:
5070 if (eCSSUnit_Initial == SVGData.mLightingColor.GetUnit()) {
5071 svgReset->mLightingColor = NS_RGB(255, 255, 255);
5072 } else {
5073 SetColor(SVGData.mLightingColor, parentSVGReset->mLightingColor,
5074 mPresContext, aContext, svgReset->mLightingColor, inherited);
5077 // clip-path: url, none, inherit
5078 if (eCSSUnit_URL == SVGData.mClipPath.GetUnit()) {
5079 svgReset->mClipPath = SVGData.mClipPath.GetURLValue();
5080 } else if (eCSSUnit_None == SVGData.mClipPath.GetUnit() ||
5081 eCSSUnit_Initial == SVGData.mClipPath.GetUnit()) {
5082 svgReset->mClipPath = nsnull;
5083 } else if (eCSSUnit_Inherit == SVGData.mClipPath.GetUnit()) {
5084 inherited = PR_TRUE;
5085 svgReset->mClipPath = parentSVGReset->mClipPath;
5088 // stop-opacity:
5089 SetFactor(SVGData.mStopOpacity, svgReset->mStopOpacity, inherited,
5090 parentSVGReset->mStopOpacity, 1.0f, SETFCT_OPACITY);
5092 // flood-opacity:
5093 SetFactor(SVGData.mFloodOpacity, svgReset->mFloodOpacity, inherited,
5094 parentSVGReset->mFloodOpacity, 1.0f, SETFCT_OPACITY);
5096 // dominant-baseline: enum, auto, inherit, initial
5097 SetDiscrete(SVGData.mDominantBaseline, svgReset->mDominantBaseline,
5098 inherited,
5099 SETDSC_ENUMERATED | SETDSC_AUTO,
5100 parentSVGReset->mDominantBaseline,
5101 NS_STYLE_DOMINANT_BASELINE_AUTO,
5102 NS_STYLE_DOMINANT_BASELINE_AUTO, 0, 0, 0);
5104 // filter: url, none, inherit
5105 if (eCSSUnit_URL == SVGData.mFilter.GetUnit()) {
5106 svgReset->mFilter = SVGData.mFilter.GetURLValue();
5107 } else if (eCSSUnit_None == SVGData.mFilter.GetUnit() ||
5108 eCSSUnit_Initial == SVGData.mFilter.GetUnit()) {
5109 svgReset->mFilter = nsnull;
5110 } else if (eCSSUnit_Inherit == SVGData.mFilter.GetUnit()) {
5111 inherited = PR_TRUE;
5112 svgReset->mFilter = parentSVGReset->mFilter;
5115 // mask: url, none, inherit
5116 if (eCSSUnit_URL == SVGData.mMask.GetUnit()) {
5117 svgReset->mMask = SVGData.mMask.GetURLValue();
5118 } else if (eCSSUnit_None == SVGData.mMask.GetUnit() ||
5119 eCSSUnit_Initial == SVGData.mMask.GetUnit()) {
5120 svgReset->mMask = nsnull;
5121 } else if (eCSSUnit_Inherit == SVGData.mMask.GetUnit()) {
5122 inherited = PR_TRUE;
5123 svgReset->mMask = parentSVGReset->mMask;
5126 COMPUTE_END_RESET(SVGReset, svgReset)
5128 #endif
5130 inline const void*
5131 nsRuleNode::GetParentData(const nsStyleStructID aSID)
5133 NS_PRECONDITION(mDependentBits & nsCachedStyleData::GetBitForSID(aSID),
5134 "should be called when node depends on parent data");
5135 NS_ASSERTION(mStyleData.GetStyleData(aSID) == nsnull,
5136 "both struct and dependent bits present");
5137 // Walk up the rule tree from this rule node (towards less specific
5138 // rules).
5139 PRUint32 bit = nsCachedStyleData::GetBitForSID(aSID);
5140 nsRuleNode *ruleNode = mParent;
5141 while (ruleNode->mDependentBits & bit) {
5142 NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nsnull,
5143 "both struct and dependent bits present");
5144 ruleNode = ruleNode->mParent;
5147 return ruleNode->mStyleData.GetStyleData(aSID);
5150 #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
5151 inline const nsStyle##name_ * \
5152 nsRuleNode::GetParent##name_() \
5154 NS_PRECONDITION(mDependentBits & \
5155 nsCachedStyleData::GetBitForSID(eStyleStruct_##name_), \
5156 "should be called when node depends on parent data"); \
5157 NS_ASSERTION(mStyleData.GetStyle##name_() == nsnull, \
5158 "both struct and dependent bits present"); \
5159 /* Walk up the rule tree from this rule node (towards less specific */ \
5160 /* rules). */ \
5161 PRUint32 bit = nsCachedStyleData::GetBitForSID(eStyleStruct_##name_); \
5162 nsRuleNode *ruleNode = mParent; \
5163 while (ruleNode->mDependentBits & bit) { \
5164 NS_ASSERTION(ruleNode->mStyleData.GetStyle##name_() == nsnull, \
5165 "both struct and dependent bits present"); \
5166 ruleNode = ruleNode->mParent; \
5169 return ruleNode->mStyleData.GetStyle##name_(); \
5171 #include "nsStyleStructList.h"
5172 #undef STYLE_STRUCT
5174 const void*
5175 nsRuleNode::GetStyleData(nsStyleStructID aSID,
5176 nsStyleContext* aContext,
5177 PRBool aComputeData)
5179 const void *data;
5180 if (mDependentBits & nsCachedStyleData::GetBitForSID(aSID)) {
5181 // We depend on an ancestor for this struct since the cached struct
5182 // it has is also appropriate for this rule node. Just go up the
5183 // rule tree and return the first cached struct we find.
5184 data = GetParentData(aSID);
5185 NS_ASSERTION(data, "dependent bits set but no cached struct present");
5186 return data;
5189 data = mStyleData.GetStyleData(aSID);
5190 if (NS_LIKELY(data != nsnull))
5191 return data; // We have a fully specified struct. Just return it.
5193 if (NS_UNLIKELY(!aComputeData))
5194 return nsnull;
5196 // Nothing is cached. We'll have to delve further and examine our rules.
5197 #define STYLE_STRUCT_TEST aSID
5198 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
5199 data = Get##name##Data(aContext);
5200 #include "nsStyleStructList.h"
5201 #undef STYLE_STRUCT
5202 #undef STYLE_STRUCT_TEST
5204 if (NS_LIKELY(data != nsnull))
5205 return data;
5207 NS_NOTREACHED("could not create style struct");
5208 // To ensure that |GetStyleData| never returns null (even when we're
5209 // out of memory), we'll get the style set and get a copy of the
5210 // default values for the given style struct from the set. Note that
5211 // this works fine even if |this| is a rule node that has been
5212 // destroyed (leftover from a previous rule tree) but is somehow still
5213 // used.
5214 return mPresContext->PresShell()->StyleSet()->
5215 DefaultStyleData()->GetStyleData(aSID);
5218 // See comments above in GetStyleData for an explanation of what the
5219 // code below does.
5220 #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
5221 const nsStyle##name_* \
5222 nsRuleNode::GetStyle##name_(nsStyleContext* aContext, PRBool aComputeData) \
5224 const nsStyle##name_ *data; \
5225 if (mDependentBits & \
5226 nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)) { \
5227 data = GetParent##name_(); \
5228 NS_ASSERTION(data, "dependent bits set but no cached struct present"); \
5229 return data; \
5232 data = mStyleData.GetStyle##name_(); \
5233 if (NS_LIKELY(data != nsnull)) \
5234 return data; \
5236 if (NS_UNLIKELY(!aComputeData)) \
5237 return nsnull; \
5239 data = \
5240 static_cast<const nsStyle##name_ *>(Get##name_##Data(aContext)); \
5242 if (NS_LIKELY(data != nsnull)) \
5243 return data; \
5245 NS_NOTREACHED("could not create style struct"); \
5246 return \
5247 static_cast<const nsStyle##name_ *>( \
5248 mPresContext->PresShell()->StyleSet()-> \
5249 DefaultStyleData()->GetStyleData(eStyleStruct_##name_)); \
5251 #include "nsStyleStructList.h"
5252 #undef STYLE_STRUCT
5254 void
5255 nsRuleNode::Mark()
5257 for (nsRuleNode *node = this;
5258 node && !(node->mDependentBits & NS_RULE_NODE_GC_MARK);
5259 node = node->mParent)
5260 node->mDependentBits |= NS_RULE_NODE_GC_MARK;
5263 static PLDHashOperator
5264 SweepRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
5265 PRUint32 number, void *arg)
5267 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
5268 if (entry->mRuleNode->Sweep())
5269 return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
5270 return PL_DHASH_NEXT;
5273 PRBool
5274 nsRuleNode::Sweep()
5276 // If we're not marked, then we have to delete ourself.
5277 // However, we never allow the root node to GC itself, because nsStyleSet
5278 // wants to hold onto the root node and not worry about re-creating a
5279 // rule walker if the root node is deleted.
5280 if (!(mDependentBits & NS_RULE_NODE_GC_MARK) && !IsRoot()) {
5281 Destroy();
5282 return PR_TRUE;
5285 // Clear our mark, for the next time around.
5286 mDependentBits &= ~NS_RULE_NODE_GC_MARK;
5288 // Call sweep on the children, since some may not be marked, and
5289 // remove any deleted children from the child lists.
5290 if (HaveChildren()) {
5291 if (ChildrenAreHashed()) {
5292 PLDHashTable *children = ChildrenHash();
5293 PL_DHashTableEnumerate(children, SweepRuleNodeChildren, nsnull);
5294 } else {
5295 for (nsRuleNode **children = ChildrenListPtr(); *children; ) {
5296 nsRuleNode *next = (*children)->mNextSibling;
5297 if ((*children)->Sweep()) {
5298 // This rule node was destroyed, so implicitly advance by
5299 // making *children point to the next entry.
5300 *children = next;
5301 } else {
5302 // Advance.
5303 children = &(*children)->mNextSibling;
5308 return PR_FALSE;
5311 /* static */ PRBool
5312 nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
5313 PRUint32 ruleTypeMask)
5315 nsRuleDataColor colorData;
5316 nsRuleDataMargin marginData;
5317 PRUint32 nValues = 0;
5319 PRUint32 inheritBits = 0;
5320 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND)
5321 inheritBits |= NS_STYLE_INHERIT_BIT(Background);
5323 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER)
5324 inheritBits |= NS_STYLE_INHERIT_BIT(Border);
5326 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING)
5327 inheritBits |= NS_STYLE_INHERIT_BIT(Padding);
5329 /* We're relying on the use of |aStyleContext| not mutating it! */
5330 nsRuleData ruleData(inheritBits,
5331 aStyleContext->PresContext(), aStyleContext);
5332 ruleData.mColorData = &colorData;
5333 ruleData.mMarginData = &marginData;
5335 nsCSSValue* backgroundValues[] = {
5336 &colorData.mBackColor,
5337 &colorData.mBackImage
5340 nsCSSValue* borderValues[] = {
5341 &marginData.mBorderColor.mTop,
5342 &marginData.mBorderStyle.mTop,
5343 &marginData.mBorderWidth.mTop,
5344 &marginData.mBorderColor.mRight,
5345 &marginData.mBorderStyle.mRight,
5346 &marginData.mBorderWidth.mRight,
5347 &marginData.mBorderColor.mBottom,
5348 &marginData.mBorderStyle.mBottom,
5349 &marginData.mBorderWidth.mBottom,
5350 &marginData.mBorderColor.mLeft,
5351 &marginData.mBorderStyle.mLeft,
5352 &marginData.mBorderWidth.mLeft
5353 // XXX add &marginData.mBorder{Start,End}{Width,Color,Style}
5356 nsCSSValue* paddingValues[] = {
5357 &marginData.mPadding.mTop,
5358 &marginData.mPadding.mRight,
5359 &marginData.mPadding.mBottom,
5360 &marginData.mPadding.mLeft,
5361 &marginData.mPaddingStart,
5362 &marginData.mPaddingEnd
5365 nsCSSValue* values[NS_ARRAY_LENGTH(backgroundValues) +
5366 NS_ARRAY_LENGTH(borderValues) +
5367 NS_ARRAY_LENGTH(paddingValues)];
5369 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
5370 memcpy(&values[nValues], backgroundValues, NS_ARRAY_LENGTH(backgroundValues) * sizeof(nsCSSValue*));
5371 nValues += NS_ARRAY_LENGTH(backgroundValues);
5374 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
5375 memcpy(&values[nValues], borderValues, NS_ARRAY_LENGTH(borderValues) * sizeof(nsCSSValue*));
5376 nValues += NS_ARRAY_LENGTH(borderValues);
5379 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
5380 memcpy(&values[nValues], paddingValues, NS_ARRAY_LENGTH(paddingValues) * sizeof(nsCSSValue*));
5381 nValues += NS_ARRAY_LENGTH(paddingValues);
5384 nsStyleContext* styleContext = aStyleContext;
5386 // We need to be careful not to count styles covered up by user-important or
5387 // UA-important declarations. But we do want to catch explicit inherit
5388 // styling in those and check our parent style context to see whether we have
5389 // user styling for those properties. Note that we don't care here about
5390 // inheritance due to lack of a specified value, since all the properties we
5391 // care about are reset properties.
5392 PRBool haveExplicitUAInherit;
5393 do {
5394 haveExplicitUAInherit = PR_FALSE;
5395 for (nsRuleNode* ruleNode = styleContext->GetRuleNode(); ruleNode;
5396 ruleNode = ruleNode->GetParent()) {
5397 nsIStyleRule *rule = ruleNode->GetRule();
5398 if (rule) {
5399 ruleData.mLevel = ruleNode->GetLevel();
5400 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
5401 rule->MapRuleInfoInto(&ruleData);
5402 // Do the same nulling out as in GetBorderData, GetBackgroundData
5403 // or GetPaddingData.
5404 // We are sharing with some style rule. It really owns the data.
5405 marginData.mBoxShadow = nsnull;
5407 if (ruleData.mLevel == nsStyleSet::eAgentSheet ||
5408 ruleData.mLevel == nsStyleSet::eUserSheet) {
5409 // This is a rule whose effect we want to ignore, so if any of
5410 // the properties we care about were set, set them to the dummy
5411 // value that they'll never otherwise get.
5412 for (PRUint32 i = 0; i < nValues; ++i) {
5413 nsCSSUnit unit = values[i]->GetUnit();
5414 if (unit != eCSSUnit_Null &&
5415 unit != eCSSUnit_Dummy &&
5416 unit != eCSSUnit_DummyInherit) {
5417 if (unit == eCSSUnit_Inherit) {
5418 haveExplicitUAInherit = PR_TRUE;
5419 values[i]->SetDummyInheritValue();
5420 } else {
5421 values[i]->SetDummyValue();
5425 } else {
5426 // If any of the values we care about was set by the above rule,
5427 // we have author style.
5428 for (PRUint32 i = 0; i < nValues; ++i)
5429 if (values[i]->GetUnit() != eCSSUnit_Null &&
5430 values[i]->GetUnit() != eCSSUnit_Dummy && // see above
5431 values[i]->GetUnit() != eCSSUnit_DummyInherit)
5432 return PR_TRUE;
5437 if (haveExplicitUAInherit) {
5438 // reset all the eCSSUnit_Null values to eCSSUnit_Dummy (since they're
5439 // not styled by the author, or by anyone else), and then reset all the
5440 // eCSSUnit_DummyInherit values to eCSSUnit_Null (so we will be able to
5441 // detect them being styled by the author) and move up to our parent
5442 // style context.
5443 for (PRUint32 i = 0; i < nValues; ++i)
5444 if (values[i]->GetUnit() == eCSSUnit_Null)
5445 values[i]->SetDummyValue();
5446 for (PRUint32 i = 0; i < nValues; ++i)
5447 if (values[i]->GetUnit() == eCSSUnit_DummyInherit)
5448 values[i]->Reset();
5449 styleContext = styleContext->GetParent();
5451 } while (haveExplicitUAInherit && styleContext);
5453 return PR_FALSE;