Bug 461267, bump version to 3.0.5pre/1.9.0.5pre, p=joduinn, r=nthomas
[mozilla-1.9.git] / layout / style / nsRuleNode.cpp
blob2c5c2095b29e164a5ab65b0d4c52ce4b09b586ea
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>
29 * Alternatively, the contents of this file may be used under the terms of
30 * either of the GNU General Public License Version 2 or later (the "GPL"),
31 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
44 * a node in the lexicographic tree of rules that match an element,
45 * responsible for converting the rules' information into computed style
48 #include "nsRuleNode.h"
49 #include "nscore.h"
50 #include "nsIServiceManager.h"
51 #include "nsIDeviceContext.h"
52 #include "nsILookAndFeel.h"
53 #include "nsIPresShell.h"
54 #include "nsIFontMetrics.h"
55 #include "nsStyleUtil.h"
56 #include "nsCSSPseudoElements.h"
57 #include "nsThemeConstants.h"
58 #include "nsITheme.h"
59 #include "pldhash.h"
60 #include "nsStyleContext.h"
61 #include "nsStyleSet.h"
62 #include "nsSize.h"
63 #include "imgIRequest.h"
64 #include "nsRuleData.h"
65 #include "nsILanguageAtomService.h"
66 #include "nsIStyleRule.h"
67 #include "nsBidiUtils.h"
70 * For storage of an |nsRuleNode|'s children in a linked list.
72 struct nsRuleList {
73 nsRuleNode* mRuleNode;
74 nsRuleList* mNext;
76 public:
77 nsRuleList(nsRuleNode* aNode, nsRuleList* aNext= nsnull) {
78 MOZ_COUNT_CTOR(nsRuleList);
79 mRuleNode = aNode;
80 mNext = aNext;
83 ~nsRuleList() {
84 MOZ_COUNT_DTOR(nsRuleList);
85 mRuleNode->Destroy();
86 if (mNext)
87 mNext->Destroy(mNext->mRuleNode->mPresContext);
90 void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
91 return aContext->AllocateFromShell(sz);
93 void operator delete(void* aPtr) {} // Does nothing. The arena will free us up when the rule tree
94 // dies.
96 void Destroy(nsPresContext* aContext) {
97 this->~nsRuleList();
98 aContext->FreeToShell(sizeof(nsRuleList), this);
101 // Destroy this node, but not its rule node or the rest of the list.
102 nsRuleList* DestroySelf(nsPresContext* aContext) {
103 nsRuleList *next = mNext;
104 MOZ_COUNT_DTOR(nsRuleList); // hack
105 aContext->FreeToShell(sizeof(nsRuleList), this);
106 return next;
111 * For storage of an |nsRuleNode|'s children in a PLDHashTable.
114 struct ChildrenHashEntry : public PLDHashEntryHdr {
115 // key is |mRuleNode->GetKey()|
116 nsRuleNode *mRuleNode;
119 /* static */ PR_CALLBACK PLDHashNumber
120 nsRuleNode::ChildrenHashHashKey(PLDHashTable *aTable, const void *aKey)
122 const nsRuleNode::Key *key =
123 static_cast<const nsRuleNode::Key*>(aKey);
124 // Disagreement on importance and level for the same rule is extremely
125 // rare, so hash just on the rule.
126 return PL_DHashVoidPtrKeyStub(aTable, key->mRule);
129 /* static */ PR_CALLBACK PRBool
130 nsRuleNode::ChildrenHashMatchEntry(PLDHashTable *aTable,
131 const PLDHashEntryHdr *aHdr,
132 const void *aKey)
134 const ChildrenHashEntry *entry =
135 static_cast<const ChildrenHashEntry*>(aHdr);
136 const nsRuleNode::Key *key =
137 static_cast<const nsRuleNode::Key*>(aKey);
138 return entry->mRuleNode->GetKey() == *key;
141 /* static */ PLDHashTableOps
142 nsRuleNode::ChildrenHashOps = {
143 // It's probably better to allocate the table itself using malloc and
144 // free rather than the pres shell's arena because the table doesn't
145 // grow very often and the pres shell's arena doesn't recycle very
146 // large size allocations.
147 PL_DHashAllocTable,
148 PL_DHashFreeTable,
149 ChildrenHashHashKey,
150 ChildrenHashMatchEntry,
151 PL_DHashMoveEntryStub,
152 PL_DHashClearEntryStub,
153 PL_DHashFinalizeStub,
154 NULL
158 // EnsureBlockDisplay:
159 // - if the display value (argument) is not a block-type
160 // then we set it to a valid block display value
161 // - For enforcing the floated/positioned element CSS2 rules
162 static void EnsureBlockDisplay(PRUint8& display)
164 // see if the display value is already a block
165 switch (display) {
166 case NS_STYLE_DISPLAY_NONE :
167 // never change display:none *ever*
168 case NS_STYLE_DISPLAY_TABLE :
169 case NS_STYLE_DISPLAY_BLOCK :
170 case NS_STYLE_DISPLAY_LIST_ITEM :
171 // do not muck with these at all - already blocks
172 // This is equivalent to nsStyleDisplay::IsBlockOutside. (XXX Maybe we
173 // should just call that?)
174 break;
176 case NS_STYLE_DISPLAY_INLINE_TABLE :
177 // make inline tables into tables
178 display = NS_STYLE_DISPLAY_TABLE;
179 break;
181 default :
182 // make it a block
183 display = NS_STYLE_DISPLAY_BLOCK;
187 // XXX This should really be done in the CSS parser.
188 static nsString& Unquote(nsString& aString)
190 PRUnichar start = aString.First();
191 PRUnichar end = aString.Last();
193 if ((start == end) &&
194 ((start == PRUnichar('\"')) ||
195 (start == PRUnichar('\'')))) {
196 PRInt32 length = aString.Length();
197 aString.Truncate(length - 1);
198 aString.Cut(0, 1);
200 return aString;
203 static nscoord CalcLengthWith(const nsCSSValue& aValue,
204 nscoord aFontSize,
205 const nsStyleFont* aStyleFont,
206 nsStyleContext* aStyleContext,
207 nsPresContext* aPresContext,
208 PRBool& aInherited)
210 NS_ASSERTION(aValue.IsLengthUnit(), "not a length unit");
211 NS_ASSERTION(aStyleFont || aStyleContext, "Must have style data");
212 NS_ASSERTION(aPresContext, "Must have prescontext");
214 if (aValue.IsFixedLengthUnit()) {
215 return aPresContext->TwipsToAppUnits(aValue.GetLengthTwips());
217 nsCSSUnit unit = aValue.GetUnit();
218 if (unit == eCSSUnit_Pixel) {
219 return nsPresContext::CSSPixelsToAppUnits(aValue.GetFloatValue());
221 // Common code for all units other than pixels:
222 aInherited = PR_TRUE;
223 if (!aStyleFont) {
224 aStyleFont = aStyleContext->GetStyleFont();
226 if (aFontSize == -1) {
227 // XXX Should this be aStyleFont->mSize instead to avoid taking minfontsize
228 // prefs into account?
229 aFontSize = aStyleFont->mFont.size;
231 switch (unit) {
232 case eCSSUnit_EM:
233 case eCSSUnit_Char: {
234 return NSToCoordRound(aValue.GetFloatValue() * float(aFontSize));
235 // XXX scale against font metrics height instead?
237 case eCSSUnit_EN: {
238 return NSToCoordRound((aValue.GetFloatValue() * float(aFontSize)) / 2.0f);
240 case eCSSUnit_XHeight: {
241 nsFont font = aStyleFont->mFont;
242 font.size = aFontSize;
243 nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(font);
244 nscoord xHeight;
245 fm->GetXHeight(xHeight);
246 return NSToCoordRound(aValue.GetFloatValue() * float(xHeight));
248 case eCSSUnit_CapHeight: {
249 NS_NOTYETIMPLEMENTED("cap height unit");
250 nscoord capHeight = ((aFontSize / 3) * 2); // XXX HACK!
251 return NSToCoordRound(aValue.GetFloatValue() * float(capHeight));
253 default:
254 NS_NOTREACHED("unexpected unit");
255 break;
257 return 0;
260 static nscoord CalcLength(const nsCSSValue& aValue,
261 nsStyleContext* aStyleContext,
262 nsPresContext* aPresContext,
263 PRBool& aInherited)
265 NS_ASSERTION(aStyleContext, "Must have style data");
267 return CalcLengthWith(aValue, -1, nsnull, aStyleContext, aPresContext, aInherited);
270 #define SETCOORD_NORMAL 0x01 // N
271 #define SETCOORD_AUTO 0x02 // A
272 #define SETCOORD_INHERIT 0x04 // H
273 #define SETCOORD_PERCENT 0x08 // P
274 #define SETCOORD_FACTOR 0x10 // F
275 #define SETCOORD_LENGTH 0x20 // L
276 #define SETCOORD_INTEGER 0x40 // I
277 #define SETCOORD_ENUMERATED 0x80 // E
278 #define SETCOORD_NONE 0x100 // O
279 #define SETCOORD_INITIAL_ZERO 0x200
280 #define SETCOORD_INITIAL_AUTO 0x400
281 #define SETCOORD_INITIAL_NONE 0x800
282 #define SETCOORD_INITIAL_NORMAL 0x1000
284 #define SETCOORD_LP (SETCOORD_LENGTH | SETCOORD_PERCENT)
285 #define SETCOORD_LH (SETCOORD_LENGTH | SETCOORD_INHERIT)
286 #define SETCOORD_AH (SETCOORD_AUTO | SETCOORD_INHERIT)
287 #define SETCOORD_LAH (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
288 #define SETCOORD_LPH (SETCOORD_LP | SETCOORD_INHERIT)
289 #define SETCOORD_LPAH (SETCOORD_LP | SETCOORD_AH)
290 #define SETCOORD_LPEH (SETCOORD_LP | SETCOORD_ENUMERATED | SETCOORD_INHERIT)
291 #define SETCOORD_LPAEH (SETCOORD_LPAH | SETCOORD_ENUMERATED)
292 #define SETCOORD_LPOH (SETCOORD_LPH | SETCOORD_NONE)
293 #define SETCOORD_LPOEH (SETCOORD_LPOH | SETCOORD_ENUMERATED)
294 #define SETCOORD_LE (SETCOORD_LENGTH | SETCOORD_ENUMERATED)
295 #define SETCOORD_LEH (SETCOORD_LE | SETCOORD_INHERIT)
296 #define SETCOORD_IA (SETCOORD_INTEGER | SETCOORD_AUTO)
297 #define SETCOORD_LAE (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
299 // changes aCoord iff it returns PR_TRUE
300 static PRBool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
301 const nsStyleCoord& aParentCoord,
302 PRInt32 aMask, nsStyleContext* aStyleContext,
303 nsPresContext* aPresContext, PRBool& aInherited)
305 PRBool result = PR_TRUE;
306 if (aValue.GetUnit() == eCSSUnit_Null) {
307 result = PR_FALSE;
309 else if (((aMask & SETCOORD_LENGTH) != 0) &&
310 (aValue.GetUnit() == eCSSUnit_Char)) {
311 aCoord.SetIntValue(NSToIntFloor(aValue.GetFloatValue()), eStyleUnit_Chars);
313 else if (((aMask & SETCOORD_LENGTH) != 0) &&
314 aValue.IsLengthUnit()) {
315 aCoord.SetCoordValue(CalcLength(aValue, aStyleContext, aPresContext, aInherited));
317 else if (((aMask & SETCOORD_PERCENT) != 0) &&
318 (aValue.GetUnit() == eCSSUnit_Percent)) {
319 aCoord.SetPercentValue(aValue.GetPercentValue());
321 else if (((aMask & SETCOORD_INTEGER) != 0) &&
322 (aValue.GetUnit() == eCSSUnit_Integer)) {
323 aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Integer);
325 else if (((aMask & SETCOORD_ENUMERATED) != 0) &&
326 (aValue.GetUnit() == eCSSUnit_Enumerated)) {
327 aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Enumerated);
329 else if (((aMask & SETCOORD_AUTO) != 0) &&
330 (aValue.GetUnit() == eCSSUnit_Auto)) {
331 aCoord.SetAutoValue();
333 else if (((aMask & SETCOORD_INHERIT) != 0) &&
334 (aValue.GetUnit() == eCSSUnit_Inherit)) {
335 aCoord = aParentCoord; // just inherit value from parent
336 aInherited = PR_TRUE;
338 else if (((aMask & SETCOORD_NORMAL) != 0) &&
339 (aValue.GetUnit() == eCSSUnit_Normal)) {
340 aCoord.SetNormalValue();
342 else if (((aMask & SETCOORD_NONE) != 0) &&
343 (aValue.GetUnit() == eCSSUnit_None)) {
344 aCoord.SetNoneValue();
346 else if (((aMask & SETCOORD_FACTOR) != 0) &&
347 (aValue.GetUnit() == eCSSUnit_Number)) {
348 aCoord.SetFactorValue(aValue.GetFloatValue());
350 else if (((aMask & SETCOORD_INITIAL_AUTO) != 0) &&
351 (aValue.GetUnit() == eCSSUnit_Initial)) {
352 aCoord.SetAutoValue();
354 else if (((aMask & SETCOORD_INITIAL_ZERO) != 0) &&
355 (aValue.GetUnit() == eCSSUnit_Initial)) {
356 aCoord.SetCoordValue(0);
358 else if (((aMask & SETCOORD_INITIAL_NONE) != 0) &&
359 (aValue.GetUnit() == eCSSUnit_Initial)) {
360 aCoord.SetNoneValue();
362 else if (((aMask & SETCOORD_INITIAL_NORMAL) != 0) &&
363 (aValue.GetUnit() == eCSSUnit_Initial)) {
364 aCoord.SetNormalValue();
366 else {
367 result = PR_FALSE; // didn't set anything
369 return result;
372 static PRBool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
373 nsPresContext* aPresContext, nsStyleContext *aContext,
374 nscolor& aResult, PRBool& aInherited)
376 PRBool result = PR_FALSE;
377 nsCSSUnit unit = aValue.GetUnit();
379 if (eCSSUnit_Color == unit) {
380 aResult = aValue.GetColorValue();
381 result = PR_TRUE;
383 else if (eCSSUnit_String == unit) {
384 nsAutoString value;
385 aValue.GetStringValue(value);
386 nscolor rgba;
387 if (NS_ColorNameToRGB(value, &rgba)) {
388 aResult = rgba;
389 result = PR_TRUE;
392 else if (eCSSUnit_EnumColor == unit) {
393 PRInt32 intValue = aValue.GetIntValue();
394 if (0 <= intValue) {
395 nsILookAndFeel* look = aPresContext->LookAndFeel();
396 nsILookAndFeel::nsColorID colorID = (nsILookAndFeel::nsColorID) intValue;
397 if (NS_SUCCEEDED(look->GetColor(colorID, aResult))) {
398 result = PR_TRUE;
401 else {
402 switch (intValue) {
403 case NS_COLOR_MOZ_HYPERLINKTEXT:
404 aResult = aPresContext->DefaultLinkColor();
405 break;
406 case NS_COLOR_MOZ_VISITEDHYPERLINKTEXT:
407 aResult = aPresContext->DefaultVisitedLinkColor();
408 break;
409 case NS_COLOR_MOZ_ACTIVEHYPERLINKTEXT:
410 aResult = aPresContext->DefaultActiveLinkColor();
411 break;
412 case NS_COLOR_CURRENTCOLOR:
413 // The data computed from this can't be shared in the rule tree
414 // because they could be used on a node with a different color
415 aInherited = PR_TRUE;
416 aResult = aContext->GetStyleColor()->mColor;
417 break;
418 default:
419 NS_NOTREACHED("Should never have an unknown negative colorID.");
420 break;
422 result = PR_TRUE;
425 else if (eCSSUnit_Inherit == unit) {
426 aResult = aParentColor;
427 result = PR_TRUE;
428 aInherited = PR_TRUE;
430 return result;
433 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
434 // (which comes from the presShell) to perform the allocation.
435 void*
436 nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
438 // Check the recycle list first.
439 return aPresContext->AllocateFromShell(sz);
442 // Overridden to prevent the global delete from being called, since the memory
443 // came out of an nsIArena instead of the global delete operator's heap.
444 void
445 nsRuleNode::Destroy()
447 // Destroy ourselves.
448 this->~nsRuleNode();
450 // Don't let the memory be freed, since it will be recycled
451 // instead. Don't call the global operator delete.
452 mPresContext->FreeToShell(sizeof(nsRuleNode), this);
455 nsRuleNode* nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
457 return new (aPresContext)
458 nsRuleNode(aPresContext, nsnull, nsnull, 0xff, PR_FALSE);
461 nsILanguageAtomService* nsRuleNode::gLangService = nsnull;
463 nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
464 nsIStyleRule* aRule, PRUint8 aLevel,
465 PRBool aIsImportant)
466 : mPresContext(aContext),
467 mParent(aParent),
468 mRule(aRule),
469 mChildrenTaggedPtr(nsnull),
470 mDependentBits((PRUint32(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
471 (aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
472 mNoneBits(0)
474 MOZ_COUNT_CTOR(nsRuleNode);
475 NS_IF_ADDREF(mRule);
477 NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
478 NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
481 PR_STATIC_CALLBACK(PLDHashOperator)
482 DeleteRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
483 PRUint32 number, void *arg)
485 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
486 entry->mRuleNode->Destroy();
487 return PL_DHASH_NEXT;
490 nsRuleNode::~nsRuleNode()
492 MOZ_COUNT_DTOR(nsRuleNode);
493 if (mStyleData.mResetData || mStyleData.mInheritedData)
494 mStyleData.Destroy(0, mPresContext);
495 if (ChildrenAreHashed()) {
496 PLDHashTable *children = ChildrenHash();
497 PL_DHashTableEnumerate(children, DeleteRuleNodeChildren, nsnull);
498 PL_DHashTableDestroy(children);
499 } else if (HaveChildren())
500 ChildrenList()->Destroy(mPresContext);
501 NS_IF_RELEASE(mRule);
504 nsRuleNode*
505 nsRuleNode::Transition(nsIStyleRule* aRule, PRUint8 aLevel,
506 PRPackedBool aIsImportantRule)
508 nsRuleNode* next = nsnull;
509 nsRuleNode::Key key(aRule, aLevel, aIsImportantRule);
511 if (HaveChildren() && !ChildrenAreHashed()) {
512 PRInt32 numKids = 0;
513 nsRuleList* curr = ChildrenList();
514 while (curr && curr->mRuleNode->GetKey() != key) {
515 curr = curr->mNext;
516 ++numKids;
518 if (curr)
519 next = curr->mRuleNode;
520 else if (numKids >= kMaxChildrenInList)
521 ConvertChildrenToHash();
524 if (ChildrenAreHashed()) {
525 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>
526 (PL_DHashTableOperate(ChildrenHash(), &key, PL_DHASH_ADD));
527 if (!entry) {
528 return nsnull;
530 if (entry->mRuleNode)
531 next = entry->mRuleNode;
532 else {
533 next = entry->mRuleNode = new (mPresContext)
534 nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
535 if (!next) {
536 PL_DHashTableRawRemove(ChildrenHash(), entry);
537 return nsnull;
540 } else if (!next) {
541 // Create the new entry in our list.
542 next = new (mPresContext)
543 nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
544 if (!next) {
545 return nsnull;
547 nsRuleList* newChildrenList = new (mPresContext) nsRuleList(next, ChildrenList());
548 if (NS_UNLIKELY(!newChildrenList)) {
549 next->Destroy();
550 return nsnull;
552 SetChildrenList(newChildrenList);
555 return next;
558 void
559 nsRuleNode::ConvertChildrenToHash()
561 NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
562 "must have a non-empty list of children");
563 PLDHashTable *hash = PL_NewDHashTable(&ChildrenHashOps, nsnull,
564 sizeof(ChildrenHashEntry),
565 kMaxChildrenInList * 4);
566 if (!hash)
567 return;
568 for (nsRuleList* curr = ChildrenList(); curr;
569 curr = curr->DestroySelf(mPresContext)) {
570 // This will never fail because of the initial size we gave the table.
571 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>
572 (PL_DHashTableOperate(hash, curr->mRuleNode->mRule, PL_DHASH_ADD));
573 NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
574 entry->mRuleNode = curr->mRuleNode;
576 SetChildrenHash(hash);
579 inline void
580 nsRuleNode::PropagateNoneBit(PRUint32 aBit, nsRuleNode* aHighestNode)
582 nsRuleNode* curr = this;
583 for (;;) {
584 NS_ASSERTION(!(curr->mNoneBits & aBit), "propagating too far");
585 curr->mNoneBits |= aBit;
586 if (curr == aHighestNode)
587 break;
588 curr = curr->mParent;
592 inline void
593 nsRuleNode::PropagateDependentBit(PRUint32 aBit, nsRuleNode* aHighestNode)
595 for (nsRuleNode* curr = this; curr != aHighestNode; curr = curr->mParent) {
596 if (curr->mDependentBits & aBit) {
597 #ifdef DEBUG
598 while (curr != aHighestNode) {
599 NS_ASSERTION(curr->mDependentBits & aBit, "bit not set");
600 curr = curr->mParent;
602 #endif
603 break;
606 curr->mDependentBits |= aBit;
611 * The following "Check" functions are used for determining what type of
612 * sharing can be used for the data on this rule node. MORE HERE...
615 /* the information for a property (or in some cases, a rect group of
616 properties) */
618 struct PropertyCheckData {
619 size_t offset;
620 nsCSSType type;
624 * a callback function that that can revise the result of
625 * CheckSpecifiedProperties before finishing; aResult is the current
626 * result, and it returns the revised one.
628 typedef nsRuleNode::RuleDetail
629 (* PR_CALLBACK CheckCallbackFn)(const nsRuleDataStruct& aData,
630 nsRuleNode::RuleDetail aResult);
632 /* the information for all the properties in a style struct */
633 struct StructCheckData {
634 const PropertyCheckData* props;
635 PRInt32 nprops;
636 CheckCallbackFn callback;
641 * @param aValue the value being examined
642 * @param aSpecifiedCount to be incremented by one if the value is specified
643 * @param aInherited to be incremented by one if the value is set to inherit
645 inline void
646 ExamineCSSValue(const nsCSSValue& aValue,
647 PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
649 if (aValue.GetUnit() != eCSSUnit_Null) {
650 ++aSpecifiedCount;
651 if (aValue.GetUnit() == eCSSUnit_Inherit) {
652 ++aInheritedCount;
657 static void
658 ExamineCSSValuePair(const nsCSSValuePair* aValuePair,
659 PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
661 NS_PRECONDITION(aValuePair, "Must have a value pair");
663 ExamineCSSValue(aValuePair->mXValue, aSpecifiedCount, aInheritedCount);
664 ExamineCSSValue(aValuePair->mYValue, aSpecifiedCount, aInheritedCount);
667 static void
668 ExamineCSSRect(const nsCSSRect* aRect,
669 PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
671 NS_PRECONDITION(aRect, "Must have a rect");
673 NS_FOR_CSS_SIDES(side) {
674 ExamineCSSValue(aRect->*(nsCSSRect::sides[side]),
675 aSpecifiedCount, aInheritedCount);
679 PR_STATIC_CALLBACK(nsRuleNode::RuleDetail)
680 CheckFontCallback(const nsRuleDataStruct& aData,
681 nsRuleNode::RuleDetail aResult)
683 const nsRuleDataFont& fontData =
684 static_cast<const nsRuleDataFont&>(aData);
686 // em, ex, percent, 'larger', and 'smaller' values on font-size depend
687 // on the parent context's font-size
688 // Likewise, 'lighter' and 'bolder' values of 'font-weight' depend on
689 // the parent.
690 const nsCSSValue& size = fontData.mSize;
691 const nsCSSValue& weight = fontData.mWeight;
692 if ((size.IsRelativeLengthUnit() && size.GetUnit() != eCSSUnit_Pixel) ||
693 size.GetUnit() == eCSSUnit_Percent ||
694 (size.GetUnit() == eCSSUnit_Enumerated &&
695 (size.GetIntValue() == NS_STYLE_FONT_SIZE_SMALLER ||
696 size.GetIntValue() == NS_STYLE_FONT_SIZE_LARGER)) ||
697 #ifdef MOZ_MATHML
698 fontData.mScriptLevel.GetUnit() == eCSSUnit_Integer ||
699 #endif
700 (weight.GetUnit() == eCSSUnit_Enumerated &&
701 (weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_BOLDER ||
702 weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_LIGHTER))) {
703 NS_ASSERTION(aResult == nsRuleNode::eRulePartialReset ||
704 aResult == nsRuleNode::eRuleFullReset ||
705 aResult == nsRuleNode::eRulePartialMixed ||
706 aResult == nsRuleNode::eRuleFullMixed,
707 "we know we already have a reset-counted property");
708 // Promote reset to mixed since we have something that depends on
709 // the parent. But never promote to inherited since that could
710 // cause inheritance of the exact value.
711 if (aResult == nsRuleNode::eRulePartialReset)
712 aResult = nsRuleNode::eRulePartialMixed;
713 else if (aResult == nsRuleNode::eRuleFullReset)
714 aResult = nsRuleNode::eRuleFullMixed;
717 return aResult;
720 PR_STATIC_CALLBACK(nsRuleNode::RuleDetail)
721 CheckColorCallback(const nsRuleDataStruct& aData,
722 nsRuleNode::RuleDetail aResult)
724 const nsRuleDataColor& colorData =
725 static_cast<const nsRuleDataColor&>(aData);
727 // currentColor values for color require inheritance
728 if (colorData.mColor.GetUnit() == eCSSUnit_EnumColor &&
729 colorData.mColor.GetIntValue() == NS_COLOR_CURRENTCOLOR) {
730 NS_ASSERTION(aResult == nsRuleNode::eRuleFullReset,
731 "we should already be counted as full-reset");
732 aResult = nsRuleNode::eRuleFullInherited;
735 return aResult;
739 // for nsCSSPropList.h, so we get information on things in the style
740 // structs but not nsCSS*
741 #define CSS_PROP_INCLUDE_NOT_CSS
743 static const PropertyCheckData FontCheckProperties[] = {
744 #define CSS_PROP_FONT(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
745 { offsetof(nsRuleData##datastruct_, member_), type_ },
746 #include "nsCSSPropList.h"
747 #undef CSS_PROP_FONT
750 static const PropertyCheckData DisplayCheckProperties[] = {
751 #define CSS_PROP_DISPLAY(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
752 { offsetof(nsRuleData##datastruct_, member_), type_ },
753 #include "nsCSSPropList.h"
754 #undef CSS_PROP_DISPLAY
757 static const PropertyCheckData VisibilityCheckProperties[] = {
758 #define CSS_PROP_VISIBILITY(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
759 { offsetof(nsRuleData##datastruct_, member_), type_ },
760 #include "nsCSSPropList.h"
761 #undef CSS_PROP_VISIBILITY
764 static const PropertyCheckData MarginCheckProperties[] = {
765 #define CSS_PROP_MARGIN(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
766 { offsetof(nsRuleData##datastruct_, member_), type_ },
767 #include "nsCSSPropList.h"
768 #undef CSS_PROP_MARGIN
771 static const PropertyCheckData BorderCheckProperties[] = {
772 #define CSS_PROP_BORDER(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
773 { offsetof(nsRuleData##datastruct_, member_), type_ },
774 #include "nsCSSPropList.h"
775 #undef CSS_PROP_BORDER
778 static const PropertyCheckData PaddingCheckProperties[] = {
779 #define CSS_PROP_PADDING(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
780 { offsetof(nsRuleData##datastruct_, member_), type_ },
781 #include "nsCSSPropList.h"
782 #undef CSS_PROP_PADDING
785 static const PropertyCheckData OutlineCheckProperties[] = {
786 #define CSS_PROP_OUTLINE(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
787 { offsetof(nsRuleData##datastruct_, member_), type_ },
788 #include "nsCSSPropList.h"
789 #undef CSS_PROP_OUTLINE
792 static const PropertyCheckData ListCheckProperties[] = {
793 #define CSS_PROP_LIST(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
794 { offsetof(nsRuleData##datastruct_, member_), type_ },
795 #include "nsCSSPropList.h"
796 #undef CSS_PROP_LIST
799 static const PropertyCheckData ColorCheckProperties[] = {
800 #define CSS_PROP_COLOR(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
801 { offsetof(nsRuleData##datastruct_, member_), type_ },
802 #include "nsCSSPropList.h"
803 #undef CSS_PROP_COLOR
806 static const PropertyCheckData BackgroundCheckProperties[] = {
807 #define CSS_PROP_BACKGROUND(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
808 { offsetof(nsRuleData##datastruct_, member_), type_ },
809 #include "nsCSSPropList.h"
810 #undef CSS_PROP_BACKGROUND
813 static const PropertyCheckData PositionCheckProperties[] = {
814 #define CSS_PROP_POSITION(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
815 { offsetof(nsRuleData##datastruct_, member_), type_ },
816 #include "nsCSSPropList.h"
817 #undef CSS_PROP_POSITION
820 static const PropertyCheckData TableCheckProperties[] = {
821 #define CSS_PROP_TABLE(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
822 { offsetof(nsRuleData##datastruct_, member_), type_ },
823 #include "nsCSSPropList.h"
824 #undef CSS_PROP_TABLE
827 static const PropertyCheckData TableBorderCheckProperties[] = {
828 #define CSS_PROP_TABLEBORDER(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
829 { offsetof(nsRuleData##datastruct_, member_), type_ },
830 #include "nsCSSPropList.h"
831 #undef CSS_PROP_TABLEBORDER
834 static const PropertyCheckData ContentCheckProperties[] = {
835 #define CSS_PROP_CONTENT(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
836 { offsetof(nsRuleData##datastruct_, member_), type_ },
837 #include "nsCSSPropList.h"
838 #undef CSS_PROP_CONTENT
841 static const PropertyCheckData QuotesCheckProperties[] = {
842 #define CSS_PROP_QUOTES(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
843 { offsetof(nsRuleData##datastruct_, member_), type_ },
844 #include "nsCSSPropList.h"
845 #undef CSS_PROP_QUOTES
848 static const PropertyCheckData TextCheckProperties[] = {
849 #define CSS_PROP_TEXT(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
850 { offsetof(nsRuleData##datastruct_, member_), type_ },
851 #include "nsCSSPropList.h"
852 #undef CSS_PROP_TEXT
855 static const PropertyCheckData TextResetCheckProperties[] = {
856 #define CSS_PROP_TEXTRESET(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
857 { offsetof(nsRuleData##datastruct_, member_), type_ },
858 #include "nsCSSPropList.h"
859 #undef CSS_PROP_TEXTRESET
862 static const PropertyCheckData UserInterfaceCheckProperties[] = {
863 #define CSS_PROP_USERINTERFACE(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
864 { offsetof(nsRuleData##datastruct_, member_), type_ },
865 #include "nsCSSPropList.h"
866 #undef CSS_PROP_USERINTERFACE
869 static const PropertyCheckData UIResetCheckProperties[] = {
870 #define CSS_PROP_UIRESET(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
871 { offsetof(nsRuleData##datastruct_, member_), type_ },
872 #include "nsCSSPropList.h"
873 #undef CSS_PROP_UIRESET
876 static const PropertyCheckData XULCheckProperties[] = {
877 #define CSS_PROP_XUL(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
878 { offsetof(nsRuleData##datastruct_, member_), type_ },
879 #include "nsCSSPropList.h"
880 #undef CSS_PROP_XUL
883 #ifdef MOZ_SVG
884 static const PropertyCheckData SVGCheckProperties[] = {
885 #define CSS_PROP_SVG(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
886 { offsetof(nsRuleData##datastruct_, member_), type_ },
887 #include "nsCSSPropList.h"
888 #undef CSS_PROP_SVG
891 static const PropertyCheckData SVGResetCheckProperties[] = {
892 #define CSS_PROP_SVGRESET(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
893 { offsetof(nsRuleData##datastruct_, member_), type_ },
894 #include "nsCSSPropList.h"
895 #undef CSS_PROP_SVGRESET
897 #endif
899 static const PropertyCheckData ColumnCheckProperties[] = {
900 #define CSS_PROP_COLUMN(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
901 { offsetof(nsRuleData##datastruct_, member_), type_ },
902 #include "nsCSSPropList.h"
903 #undef CSS_PROP_COLUMN
906 #undef CSS_PROP_INCLUDE_NOT_CSS
908 static const StructCheckData gCheckProperties[] = {
910 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
911 {name##CheckProperties, \
912 sizeof(name##CheckProperties)/sizeof(PropertyCheckData), \
913 checkdata_cb},
914 #include "nsStyleStructList.h"
915 #undef STYLE_STRUCT
916 {nsnull, 0, nsnull}
922 // XXXldb Taking the address of a reference is evil.
924 inline const nsCSSValue&
925 ValueAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
927 return * reinterpret_cast<const nsCSSValue*>
928 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
931 inline const nsCSSRect*
932 RectAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
934 return reinterpret_cast<const nsCSSRect*>
935 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
938 inline const nsCSSValuePair*
939 ValuePairAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
941 return reinterpret_cast<const nsCSSValuePair*>
942 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
945 inline const nsCSSValueList*
946 ValueListAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
948 return * reinterpret_cast<const nsCSSValueList*const*>
949 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
952 inline const nsCSSValueList**
953 ValueListArrayAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
955 return * reinterpret_cast<const nsCSSValueList**const*>
956 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
959 inline const nsCSSCounterData*
960 CounterDataAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
962 return * reinterpret_cast<const nsCSSCounterData*const*>
963 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
966 inline const nsCSSQuotes*
967 QuotesAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
969 return * reinterpret_cast<const nsCSSQuotes*const*>
970 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
973 #if defined(MOZ_MATHML) && defined(DEBUG)
974 static PRBool
975 AreAllMathMLPropertiesUndefined(const nsCSSFont& aRuleData)
977 return aRuleData.mScriptLevel.GetUnit() == eCSSUnit_Null &&
978 aRuleData.mScriptSizeMultiplier.GetUnit() == eCSSUnit_Null &&
979 aRuleData.mScriptMinSize.GetUnit() == eCSSUnit_Null;
981 #endif
983 inline nsRuleNode::RuleDetail
984 nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID,
985 const nsRuleDataStruct& aRuleDataStruct)
987 const StructCheckData *structData = gCheckProperties + aSID;
989 // Build a count of the:
990 PRUint32 total = 0, // total number of props in the struct
991 specified = 0, // number that were specified for this node
992 inherited = 0; // number that were 'inherit' (and not
993 // eCSSUnit_Inherit) for this node
995 for (const PropertyCheckData *prop = structData->props,
996 *prop_end = prop + structData->nprops;
997 prop != prop_end;
998 ++prop)
999 switch (prop->type) {
1001 case eCSSType_Value:
1002 ++total;
1003 ExamineCSSValue(ValueAtOffset(aRuleDataStruct, prop->offset),
1004 specified, inherited);
1005 break;
1007 case eCSSType_Rect:
1008 total += 4;
1009 ExamineCSSRect(RectAtOffset(aRuleDataStruct, prop->offset),
1010 specified, inherited);
1011 break;
1013 case eCSSType_ValuePair:
1014 total += 2;
1015 ExamineCSSValuePair(ValuePairAtOffset(aRuleDataStruct, prop->offset),
1016 specified, inherited);
1017 break;
1019 case eCSSType_ValueList:
1021 ++total;
1022 const nsCSSValueList* valueList =
1023 ValueListAtOffset(aRuleDataStruct, prop->offset);
1024 if (valueList) {
1025 ++specified;
1026 if (eCSSUnit_Inherit == valueList->mValue.GetUnit()) {
1027 ++inherited;
1031 break;
1033 case eCSSType_CounterData:
1035 ++total;
1036 const nsCSSCounterData* counterData =
1037 CounterDataAtOffset(aRuleDataStruct, prop->offset);
1038 if (counterData) {
1039 ++specified;
1040 if (eCSSUnit_Inherit == counterData->mCounter.GetUnit()) {
1041 ++inherited;
1045 break;
1047 case eCSSType_Quotes:
1049 ++total;
1050 const nsCSSQuotes* quotes =
1051 QuotesAtOffset(aRuleDataStruct, prop->offset);
1052 if (quotes) {
1053 ++specified;
1054 if (eCSSUnit_Inherit == quotes->mOpen.GetUnit()) {
1055 ++inherited;
1059 break;
1061 default:
1062 NS_NOTREACHED("unknown type");
1063 break;
1067 #if 0
1068 printf("CheckSpecifiedProperties: SID=%d total=%d spec=%d inh=%d.\n",
1069 aSID, total, specified, inherited);
1070 #endif
1072 #ifdef MOZ_MATHML
1073 NS_ASSERTION(aSID != eStyleStruct_Font ||
1074 mPresContext->Document()->GetMathMLEnabled() ||
1075 AreAllMathMLPropertiesUndefined(static_cast<const nsCSSFont&>(aRuleDataStruct)),
1076 "MathML style property was defined even though MathML is disabled");
1077 #endif
1080 * Return the most specific information we can: prefer None or Full
1081 * over Partial, and Reset or Inherited over Mixed, since we can
1082 * optimize based on the edge cases and not the in-between cases.
1084 nsRuleNode::RuleDetail result;
1085 if (inherited == total)
1086 result = eRuleFullInherited;
1087 else if (specified == total
1088 #ifdef MOZ_MATHML
1089 // MathML defines 3 properties in Font that will never be set when
1090 // MathML is not in use. Therefore if all but three
1091 // properties have been set, and MathML is not enabled, we can treat
1092 // this as fully specified. Code in nsMathMLElementFactory will
1093 // rebuild the rule tree and style data when MathML is first enabled
1094 // (see nsMathMLElement::BindToTree).
1095 || (aSID == eStyleStruct_Font && specified + 3 == total &&
1096 !mPresContext->Document()->GetMathMLEnabled())
1097 #endif
1099 if (inherited == 0)
1100 result = eRuleFullReset;
1101 else
1102 result = eRuleFullMixed;
1103 } else if (specified == 0)
1104 result = eRuleNone;
1105 else if (specified == inherited)
1106 result = eRulePartialInherited;
1107 else if (inherited == 0)
1108 result = eRulePartialReset;
1109 else
1110 result = eRulePartialMixed;
1112 if (structData->callback) {
1113 result = (*structData->callback)(aRuleDataStruct, result);
1116 return result;
1119 const void*
1120 nsRuleNode::GetDisplayData(nsStyleContext* aContext)
1122 nsRuleDataDisplay displayData; // Declare a struct with null CSS values.
1123 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Display), mPresContext, aContext);
1124 ruleData.mDisplayData = &displayData;
1126 return WalkRuleTree(eStyleStruct_Display, aContext, &ruleData, &displayData);
1129 const void*
1130 nsRuleNode::GetVisibilityData(nsStyleContext* aContext)
1132 nsRuleDataDisplay displayData; // Declare a struct with null CSS values.
1133 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Visibility), mPresContext, aContext);
1134 ruleData.mDisplayData = &displayData;
1136 return WalkRuleTree(eStyleStruct_Visibility, aContext, &ruleData, &displayData);
1139 const void*
1140 nsRuleNode::GetTextData(nsStyleContext* aContext)
1142 nsRuleDataText textData; // Declare a struct with null CSS values.
1143 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Text), mPresContext, aContext);
1144 ruleData.mTextData = &textData;
1146 return WalkRuleTree(eStyleStruct_Text, aContext, &ruleData, &textData);
1149 const void*
1150 nsRuleNode::GetTextResetData(nsStyleContext* aContext)
1152 nsRuleDataText textData; // Declare a struct with null CSS values.
1153 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(TextReset), mPresContext, aContext);
1154 ruleData.mTextData = &textData;
1156 const void* res = WalkRuleTree(eStyleStruct_TextReset, aContext, &ruleData, &textData);
1157 textData.mTextShadow = nsnull; // We are sharing with some style rule. It really owns the data.
1158 return res;
1161 const void*
1162 nsRuleNode::GetUserInterfaceData(nsStyleContext* aContext)
1164 nsRuleDataUserInterface uiData; // Declare a struct with null CSS values.
1165 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(UserInterface), mPresContext, aContext);
1166 ruleData.mUserInterfaceData = &uiData;
1168 const void* res = WalkRuleTree(eStyleStruct_UserInterface, aContext, &ruleData, &uiData);
1169 uiData.mCursor = nsnull; // We are sharing with some style rule. It really owns the data.
1170 return res;
1173 const void*
1174 nsRuleNode::GetUIResetData(nsStyleContext* aContext)
1176 nsRuleDataUserInterface uiData; // Declare a struct with null CSS values.
1177 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(UIReset), mPresContext, aContext);
1178 ruleData.mUserInterfaceData = &uiData;
1180 const void* res = WalkRuleTree(eStyleStruct_UIReset, aContext, &ruleData, &uiData);
1181 return res;
1184 const void*
1185 nsRuleNode::GetFontData(nsStyleContext* aContext)
1187 nsRuleDataFont fontData; // Declare a struct with null CSS values.
1188 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), mPresContext, aContext);
1189 ruleData.mFontData = &fontData;
1191 return WalkRuleTree(eStyleStruct_Font, aContext, &ruleData, &fontData);
1194 const void*
1195 nsRuleNode::GetColorData(nsStyleContext* aContext)
1197 nsRuleDataColor colorData; // Declare a struct with null CSS values.
1198 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Color), mPresContext, aContext);
1199 ruleData.mColorData = &colorData;
1201 return WalkRuleTree(eStyleStruct_Color, aContext, &ruleData, &colorData);
1204 const void*
1205 nsRuleNode::GetBackgroundData(nsStyleContext* aContext)
1207 nsRuleDataColor colorData; // Declare a struct with null CSS values.
1208 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Background), mPresContext, aContext);
1209 ruleData.mColorData = &colorData;
1211 return WalkRuleTree(eStyleStruct_Background, aContext, &ruleData, &colorData);
1214 const void*
1215 nsRuleNode::GetMarginData(nsStyleContext* aContext)
1217 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1218 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Margin), mPresContext, aContext);
1219 ruleData.mMarginData = &marginData;
1221 return WalkRuleTree(eStyleStruct_Margin, aContext, &ruleData, &marginData);
1224 const void*
1225 nsRuleNode::GetBorderData(nsStyleContext* aContext)
1227 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1228 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Border), mPresContext, aContext);
1229 ruleData.mMarginData = &marginData;
1231 return WalkRuleTree(eStyleStruct_Border, aContext, &ruleData, &marginData);
1234 const void*
1235 nsRuleNode::GetPaddingData(nsStyleContext* aContext)
1237 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1238 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Padding), mPresContext, aContext);
1239 ruleData.mMarginData = &marginData;
1241 return WalkRuleTree(eStyleStruct_Padding, aContext, &ruleData, &marginData);
1244 const void*
1245 nsRuleNode::GetOutlineData(nsStyleContext* aContext)
1247 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1248 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Outline), mPresContext, aContext);
1249 ruleData.mMarginData = &marginData;
1251 return WalkRuleTree(eStyleStruct_Outline, aContext, &ruleData, &marginData);
1254 const void*
1255 nsRuleNode::GetListData(nsStyleContext* aContext)
1257 nsRuleDataList listData; // Declare a struct with null CSS values.
1258 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(List), mPresContext, aContext);
1259 ruleData.mListData = &listData;
1261 return WalkRuleTree(eStyleStruct_List, aContext, &ruleData, &listData);
1264 const void*
1265 nsRuleNode::GetPositionData(nsStyleContext* aContext)
1267 nsRuleDataPosition posData; // Declare a struct with null CSS values.
1268 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Position), mPresContext, aContext);
1269 ruleData.mPositionData = &posData;
1271 return WalkRuleTree(eStyleStruct_Position, aContext, &ruleData, &posData);
1274 const void*
1275 nsRuleNode::GetTableData(nsStyleContext* aContext)
1277 nsRuleDataTable tableData; // Declare a struct with null CSS values.
1278 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Table), mPresContext, aContext);
1279 ruleData.mTableData = &tableData;
1281 return WalkRuleTree(eStyleStruct_Table, aContext, &ruleData, &tableData);
1284 const void*
1285 nsRuleNode::GetTableBorderData(nsStyleContext* aContext)
1287 nsRuleDataTable tableData; // Declare a struct with null CSS values.
1288 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(TableBorder), mPresContext, aContext);
1289 ruleData.mTableData = &tableData;
1291 return WalkRuleTree(eStyleStruct_TableBorder, aContext, &ruleData, &tableData);
1294 const void*
1295 nsRuleNode::GetContentData(nsStyleContext* aContext)
1297 nsRuleDataContent contentData; // Declare a struct with null CSS values.
1298 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Content), mPresContext, aContext);
1299 ruleData.mContentData = &contentData;
1301 const void* res = WalkRuleTree(eStyleStruct_Content, aContext, &ruleData, &contentData);
1302 contentData.mCounterIncrement = contentData.mCounterReset = nsnull;
1303 contentData.mContent = nsnull; // We are sharing with some style rule. It really owns the data.
1304 return res;
1307 const void*
1308 nsRuleNode::GetQuotesData(nsStyleContext* aContext)
1310 nsRuleDataContent contentData; // Declare a struct with null CSS values.
1311 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Quotes), mPresContext, aContext);
1312 ruleData.mContentData = &contentData;
1314 const void* res = WalkRuleTree(eStyleStruct_Quotes, aContext, &ruleData, &contentData);
1315 contentData.mQuotes = nsnull; // We are sharing with some style rule. It really owns the data.
1316 return res;
1319 const void*
1320 nsRuleNode::GetXULData(nsStyleContext* aContext)
1322 nsRuleDataXUL xulData; // Declare a struct with null CSS values.
1323 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(XUL), mPresContext, aContext);
1324 ruleData.mXULData = &xulData;
1326 return WalkRuleTree(eStyleStruct_XUL, aContext, &ruleData, &xulData);
1329 const void*
1330 nsRuleNode::GetColumnData(nsStyleContext* aContext)
1332 nsRuleDataColumn columnData; // Declare a struct with null CSS values.
1333 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Column), mPresContext, aContext);
1334 ruleData.mColumnData = &columnData;
1336 return WalkRuleTree(eStyleStruct_Column, aContext, &ruleData, &columnData);
1339 #ifdef MOZ_SVG
1340 const void*
1341 nsRuleNode::GetSVGData(nsStyleContext* aContext)
1343 nsRuleDataSVG svgData; // Declare a struct with null CSS values.
1344 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(SVG), mPresContext, aContext);
1345 ruleData.mSVGData = &svgData;
1347 const void *res = WalkRuleTree(eStyleStruct_SVG, aContext, &ruleData, &svgData);
1348 svgData.mStrokeDasharray = nsnull; // We are sharing with some style rule. It really owns the data.
1349 return res;
1352 const void*
1353 nsRuleNode::GetSVGResetData(nsStyleContext* aContext)
1355 nsRuleDataSVG svgData; // Declare a struct with null CSS values.
1356 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(SVGReset), mPresContext, aContext);
1357 ruleData.mSVGData = &svgData;
1359 return WalkRuleTree(eStyleStruct_SVGReset, aContext, &ruleData, &svgData);
1361 #endif
1363 const void*
1364 nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
1365 nsStyleContext* aContext,
1366 nsRuleData* aRuleData,
1367 nsRuleDataStruct* aSpecificData)
1369 // We start at the most specific rule in the tree.
1370 void* startStruct = nsnull;
1372 nsRuleNode* ruleNode = this;
1373 nsRuleNode* highestNode = nsnull; // The highest node in the rule tree
1374 // that has the same properties
1375 // specified for struct |aSID| as
1376 // |this| does.
1377 nsRuleNode* rootNode = this; // After the loop below, this will be the
1378 // highest node that we've walked without
1379 // finding cached data on the rule tree.
1380 // If we don't find any cached data, it
1381 // will be the root. (XXX misnamed)
1382 RuleDetail detail = eRuleNone;
1383 PRUint32 bit = nsCachedStyleData::GetBitForSID(aSID);
1385 while (ruleNode) {
1386 // See if this rule node has cached the fact that the remaining
1387 // nodes along this path specify no data whatsoever.
1388 if (ruleNode->mNoneBits & bit)
1389 break;
1391 // If the dependent bit is set on a rule node for this struct, that
1392 // means its rule won't have any information to add, so skip it.
1393 // XXXldb I don't understand why we need to check |detail| here, but
1394 // we do.
1395 if (detail == eRuleNone)
1396 while (ruleNode->mDependentBits & bit) {
1397 NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nsnull,
1398 "dependent bit with cached data makes no sense");
1399 // Climb up to the next rule in the tree (a less specific rule).
1400 rootNode = ruleNode;
1401 ruleNode = ruleNode->mParent;
1402 NS_ASSERTION(!(ruleNode->mNoneBits & bit), "can't have both bits set");
1405 // Check for cached data after the inner loop above -- otherwise
1406 // we'll miss it.
1407 startStruct = ruleNode->mStyleData.GetStyleData(aSID);
1408 if (startStruct)
1409 break; // We found a rule with fully specified data. We don't
1410 // need to go up the tree any further, since the remainder
1411 // of this branch has already been computed.
1413 // Ask the rule to fill in the properties that it specifies.
1414 nsIStyleRule *rule = ruleNode->mRule;
1415 if (rule) {
1416 aRuleData->mLevel = ruleNode->GetLevel();
1417 aRuleData->mIsImportantRule = ruleNode->IsImportantRule();
1418 rule->MapRuleInfoInto(aRuleData);
1421 // Now we check to see how many properties have been specified by
1422 // the rules we've examined so far.
1423 RuleDetail oldDetail = detail;
1424 detail = CheckSpecifiedProperties(aSID, *aSpecificData);
1426 if (oldDetail == eRuleNone && detail != eRuleNone)
1427 highestNode = ruleNode;
1429 if (detail == eRuleFullReset ||
1430 detail == eRuleFullMixed ||
1431 detail == eRuleFullInherited)
1432 break; // We don't need to examine any more rules. All properties
1433 // have been fully specified.
1435 // Climb up to the next rule in the tree (a less specific rule).
1436 rootNode = ruleNode;
1437 ruleNode = ruleNode->mParent;
1440 NS_ASSERTION(!startStruct || (detail != eRuleFullReset &&
1441 detail != eRuleFullMixed &&
1442 detail != eRuleFullInherited),
1443 "can't have start struct and be fully specified");
1445 PRBool isReset = nsCachedStyleData::IsReset(aSID);
1446 if (!highestNode)
1447 highestNode = rootNode;
1449 if (!aRuleData->mCanStoreInRuleTree)
1450 detail = eRulePartialMixed; // Treat as though some data is specified to avoid
1451 // the optimizations and force data computation.
1453 if (detail == eRuleNone && startStruct && !aRuleData->mPostResolveCallback) {
1454 // We specified absolutely no rule information, but a parent rule in the tree
1455 // specified all the rule information. We set a bit along the branch from our
1456 // node in the tree to the node that specified the data that tells nodes on that
1457 // branch that they never need to examine their rules for this particular struct type
1458 // ever again.
1459 PropagateDependentBit(bit, ruleNode);
1460 return startStruct;
1462 // FIXME Do we need to check for mPostResolveCallback?
1463 if ((!startStruct && !isReset &&
1464 (detail == eRuleNone || detail == eRulePartialInherited)) ||
1465 detail == eRuleFullInherited) {
1466 // We specified no non-inherited information and neither did any of
1467 // our parent rules.
1469 // We set a bit along the branch from the highest node (ruleNode)
1470 // down to our node (this) indicating that no non-inherited data was
1471 // specified. This bit is guaranteed to be set already on the path
1472 // from the highest node to the root node in the case where
1473 // (detail == eRuleNone), which is the most common case here.
1474 // We must check |!isReset| because the Compute*Data functions for
1475 // reset structs wouldn't handle none bits correctly.
1476 if (highestNode != this && !isReset)
1477 PropagateNoneBit(bit, highestNode);
1479 // All information must necessarily be inherited from our parent style context.
1480 // In the absence of any computed data in the rule tree and with
1481 // no rules specified that didn't have values of 'inherit', we should check our parent.
1482 nsStyleContext* parentContext = aContext->GetParent();
1483 if (parentContext) {
1484 // We have a parent, and so we should just inherit from the parent.
1485 // Set the inherit bits on our context. These bits tell the style context that
1486 // it never has to go back to the rule tree for data. Instead the style context tree
1487 // should be walked to find the data.
1488 const void* parentStruct = parentContext->GetStyleData(aSID);
1489 aContext->AddStyleBit(bit); // makes const_cast OK.
1490 aContext->SetStyle(aSID, const_cast<void*>(parentStruct));
1491 return parentStruct;
1493 else
1494 // We are the root. In the case of fonts, the default values just
1495 // come from the pres context.
1496 return SetDefaultOnRoot(aSID, aContext);
1499 // We need to compute the data from the information that the rules specified.
1500 const void* res;
1501 #define STYLE_STRUCT_TEST aSID
1502 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
1503 res = Compute##name##Data(startStruct, *aSpecificData, aContext, \
1504 highestNode, detail, !aRuleData->mCanStoreInRuleTree);
1505 #include "nsStyleStructList.h"
1506 #undef STYLE_STRUCT
1507 #undef STYLE_STRUCT_TEST
1509 // If we have a post-resolve callback, handle that now.
1510 if (aRuleData->mPostResolveCallback && (NS_LIKELY(res != nsnull)))
1511 (*aRuleData->mPostResolveCallback)(const_cast<void*>(res), aRuleData);
1513 // Now return the result.
1514 return res;
1517 const void*
1518 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
1520 switch (aSID) {
1521 case eStyleStruct_Font:
1523 nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
1524 if (NS_LIKELY(fontData != nsnull)) {
1525 nscoord minimumFontSize =
1526 mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
1528 if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
1529 fontData->mFont.size = PR_MAX(fontData->mSize, minimumFontSize);
1531 else {
1532 fontData->mFont.size = fontData->mSize;
1534 aContext->SetStyle(eStyleStruct_Font, fontData);
1536 return fontData;
1538 case eStyleStruct_Display:
1540 nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay();
1541 if (NS_LIKELY(disp != nsnull)) {
1542 aContext->SetStyle(eStyleStruct_Display, disp);
1544 return disp;
1546 case eStyleStruct_Visibility:
1548 nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
1549 if (NS_LIKELY(vis != nsnull)) {
1550 aContext->SetStyle(eStyleStruct_Visibility, vis);
1552 return vis;
1554 case eStyleStruct_Text:
1556 nsStyleText* text = new (mPresContext) nsStyleText();
1557 if (NS_LIKELY(text != nsnull)) {
1558 aContext->SetStyle(eStyleStruct_Text, text);
1560 return text;
1562 case eStyleStruct_TextReset:
1564 nsStyleTextReset* text = new (mPresContext) nsStyleTextReset();
1565 if (NS_LIKELY(text != nsnull)) {
1566 aContext->SetStyle(eStyleStruct_TextReset, text);
1568 return text;
1570 case eStyleStruct_Color:
1572 nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
1573 if (NS_LIKELY(color != nsnull)) {
1574 aContext->SetStyle(eStyleStruct_Color, color);
1576 return color;
1578 case eStyleStruct_Background:
1580 nsStyleBackground* bg = new (mPresContext) nsStyleBackground(mPresContext);
1581 if (NS_LIKELY(bg != nsnull)) {
1582 aContext->SetStyle(eStyleStruct_Background, bg);
1584 return bg;
1586 case eStyleStruct_Margin:
1588 nsStyleMargin* margin = new (mPresContext) nsStyleMargin();
1589 if (NS_LIKELY(margin != nsnull)) {
1590 aContext->SetStyle(eStyleStruct_Margin, margin);
1592 return margin;
1594 case eStyleStruct_Border:
1596 nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
1597 if (NS_LIKELY(border != nsnull)) {
1598 aContext->SetStyle(eStyleStruct_Border, border);
1600 return border;
1602 case eStyleStruct_Padding:
1604 nsStylePadding* padding = new (mPresContext) nsStylePadding();
1605 if (NS_LIKELY(padding != nsnull)) {
1606 aContext->SetStyle(eStyleStruct_Padding, padding);
1608 return padding;
1610 case eStyleStruct_Outline:
1612 nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
1613 if (NS_LIKELY(outline != nsnull)) {
1614 aContext->SetStyle(eStyleStruct_Outline, outline);
1616 return outline;
1618 case eStyleStruct_List:
1620 nsStyleList* list = new (mPresContext) nsStyleList();
1621 if (NS_LIKELY(list != nsnull)) {
1622 aContext->SetStyle(eStyleStruct_List, list);
1624 return list;
1626 case eStyleStruct_Position:
1628 nsStylePosition* pos = new (mPresContext) nsStylePosition();
1629 if (NS_LIKELY(pos != nsnull)) {
1630 aContext->SetStyle(eStyleStruct_Position, pos);
1632 return pos;
1634 case eStyleStruct_Table:
1636 nsStyleTable* table = new (mPresContext) nsStyleTable();
1637 if (NS_LIKELY(table != nsnull)) {
1638 aContext->SetStyle(eStyleStruct_Table, table);
1640 return table;
1642 case eStyleStruct_TableBorder:
1644 nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
1645 if (NS_LIKELY(table != nsnull)) {
1646 aContext->SetStyle(eStyleStruct_TableBorder, table);
1648 return table;
1650 case eStyleStruct_Content:
1652 nsStyleContent* content = new (mPresContext) nsStyleContent();
1653 if (NS_LIKELY(content != nsnull)) {
1654 aContext->SetStyle(eStyleStruct_Content, content);
1656 return content;
1658 case eStyleStruct_Quotes:
1660 nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes();
1661 if (NS_LIKELY(quotes != nsnull)) {
1662 aContext->SetStyle(eStyleStruct_Quotes, quotes);
1664 return quotes;
1666 case eStyleStruct_UserInterface:
1668 nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface();
1669 if (NS_LIKELY(ui != nsnull)) {
1670 aContext->SetStyle(eStyleStruct_UserInterface, ui);
1672 return ui;
1674 case eStyleStruct_UIReset:
1676 nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset();
1677 if (NS_LIKELY(ui != nsnull)) {
1678 aContext->SetStyle(eStyleStruct_UIReset, ui);
1680 return ui;
1683 case eStyleStruct_XUL:
1685 nsStyleXUL* xul = new (mPresContext) nsStyleXUL();
1686 if (NS_LIKELY(xul != nsnull)) {
1687 aContext->SetStyle(eStyleStruct_XUL, xul);
1689 return xul;
1692 case eStyleStruct_Column:
1694 nsStyleColumn* column = new (mPresContext) nsStyleColumn();
1695 if (NS_LIKELY(column != nsnull)) {
1696 aContext->SetStyle(eStyleStruct_Column, column);
1698 return column;
1701 #ifdef MOZ_SVG
1702 case eStyleStruct_SVG:
1704 nsStyleSVG* svg = new (mPresContext) nsStyleSVG();
1705 if (NS_LIKELY(svg != nsnull)) {
1706 aContext->SetStyle(eStyleStruct_SVG, svg);
1708 return svg;
1711 case eStyleStruct_SVGReset:
1713 nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset();
1714 if (NS_LIKELY(svgReset != nsnull)) {
1715 aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
1717 return svgReset;
1719 #endif
1721 return nsnull;
1725 * This function handles cascading of *-left or *-right box properties
1726 * against *-start (which is L for LTR and R for RTL) or *-end (which is
1727 * R for LTR and L for RTL).
1729 * Cascading these properties correctly is hard because we need to
1730 * cascade two properties as one, but which two properties depends on a
1731 * third property ('direction'). We solve this by treating each of
1732 * these properties (say, 'margin-start') as a shorthand that sets a
1733 * property containing the value of the property specified
1734 * ('margin-start-value') and sets a pair of properties
1735 * ('margin-left-ltr-source' and 'margin-right-rtl-source') saying which
1736 * of the properties we use. Thus, when we want to compute the value of
1737 * 'margin-left' when 'direction' is 'ltr', we look at the value of
1738 * 'margin-left-ltr-source', which tells us whether to use the highest
1739 * 'margin-left' in the cascade or the highest 'margin-start'.
1741 * Finally, since we can compute the normal (*-left and *-right)
1742 * properties in a loop, this function works by modifying the data we
1743 * will use in that loop (which the caller must copy from the const
1744 * input).
1746 void
1747 nsRuleNode::AdjustLogicalBoxProp(nsStyleContext* aContext,
1748 const nsCSSValue& aLTRSource,
1749 const nsCSSValue& aRTLSource,
1750 const nsCSSValue& aLTRLogicalValue,
1751 const nsCSSValue& aRTLLogicalValue,
1752 PRUint8 aSide,
1753 nsCSSRect& aValueRect,
1754 PRBool& aInherited)
1756 PRBool LTRlogical = aLTRSource.GetUnit() == eCSSUnit_Enumerated &&
1757 aLTRSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
1758 PRBool RTLlogical = aRTLSource.GetUnit() == eCSSUnit_Enumerated &&
1759 aRTLSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
1760 if (LTRlogical || RTLlogical) {
1761 // We can't cache anything on the rule tree if we use any data from
1762 // the style context, since data cached in the rule tree could be
1763 // used with a style context with a different value.
1764 aInherited = PR_TRUE;
1765 PRUint8 dir = aContext->GetStyleVisibility()->mDirection;
1767 if (dir == NS_STYLE_DIRECTION_LTR) {
1768 if (LTRlogical)
1769 aValueRect.*(nsCSSRect::sides[aSide]) = aLTRLogicalValue;
1770 } else {
1771 if (RTLlogical)
1772 aValueRect.*(nsCSSRect::sides[aSide]) = aRTLLogicalValue;
1778 * Begin an nsRuleNode::Compute*Data function for an inherited struct.
1780 * @param type_ The nsStyle* type this function computes.
1781 * @param ctorargs_ The arguments used for the default nsStyle* constructor.
1782 * @param data_ Variable (declared here) holding the result of this
1783 * function.
1784 * @param parentdata_ Variable (declared here) holding the parent style
1785 * context's data for this struct.
1786 * @param rdtype_ The nsCSS* struct type used to compute this struct's data.
1787 * @param rdata_ Variable (declared here) holding the nsCSS* used here.
1789 #define COMPUTE_START_INHERITED(type_, ctorargs_, data_, parentdata_, rdtype_, rdata_) \
1790 NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
1791 "should not have bothered calling Compute*Data"); \
1793 nsStyleContext* parentContext = aContext->GetParent(); \
1795 const nsRuleData##rdtype_& rdata_ = \
1796 static_cast<const nsRuleData##rdtype_&>(aData); \
1797 nsStyle##type_* data_ = nsnull; \
1798 const nsStyle##type_* parentdata_ = nsnull; \
1799 PRBool inherited = aInherited; \
1801 /* If |inherited| might be false by the time we're done, we can't call */ \
1802 /* parentContext->GetStyle##type_() since it could recur into setting */ \
1803 /* the same struct on the same rule node, causing a leak. */ \
1804 if (parentContext && aRuleDetail != eRuleFullReset && \
1805 (!aStartStruct || (aRuleDetail != eRulePartialReset && \
1806 aRuleDetail != eRuleNone))) \
1807 parentdata_ = parentContext->GetStyle##type_(); \
1808 if (aStartStruct) \
1809 /* We only need to compute the delta between this computed data and */ \
1810 /* our computed data. */ \
1811 data_ = new (mPresContext) \
1812 nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
1813 else { \
1814 if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) { \
1815 /* No question. We will have to inherit. Go ahead and init */ \
1816 /* with inherited vals from parent. */ \
1817 inherited = PR_TRUE; \
1818 if (parentdata_) \
1819 data_ = new (mPresContext) nsStyle##type_(*parentdata_); \
1820 else \
1821 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
1823 else \
1824 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
1827 if (NS_UNLIKELY(!data_)) \
1828 return nsnull; /* Out Of Memory */ \
1829 if (!parentdata_) \
1830 parentdata_ = data_;
1833 * Begin an nsRuleNode::Compute*Data function for a reset struct.
1835 * @param type_ The nsStyle* type this function computes.
1836 * @param ctorargs_ The arguments used for the default nsStyle* constructor.
1837 * @param data_ Variable (declared here) holding the result of this
1838 * function.
1839 * @param parentdata_ Variable (declared here) holding the parent style
1840 * context's data for this struct.
1841 * @param rdtype_ The nsCSS* struct type used to compute this struct's data.
1842 * @param rdata_ Variable (declared here) holding the nsCSS* used here.
1844 #define COMPUTE_START_RESET(type_, ctorargs_, data_, parentdata_, rdtype_, rdata_) \
1845 NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
1846 "should not have bothered calling Compute*Data"); \
1848 nsStyleContext* parentContext = aContext->GetParent(); \
1849 if (parentContext && \
1850 parentContext->GetPseudoType() == nsCSSPseudoElements::firstLine) { \
1851 /* Reset structs don't inherit from first-line */ \
1852 parentContext = parentContext->GetParent(); \
1855 const nsRuleData##rdtype_& rdata_ = \
1856 static_cast<const nsRuleData##rdtype_&>(aData); \
1857 nsStyle##type_* data_; \
1858 if (aStartStruct) \
1859 /* We only need to compute the delta between this computed data and */ \
1860 /* our computed data. */ \
1861 data_ = new (mPresContext) \
1862 nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
1863 else \
1864 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
1866 if (NS_UNLIKELY(!data_)) \
1867 return nsnull; /* Out Of Memory */ \
1869 /* If |inherited| might be false by the time we're done, we can't call */ \
1870 /* parentContext->GetStyle##type_() since it could recur into setting */ \
1871 /* the same struct on the same rule node, causing a leak. */ \
1872 const nsStyle##type_* parentdata_ = data_; \
1873 if (parentContext && \
1874 aRuleDetail != eRuleFullReset && \
1875 aRuleDetail != eRulePartialReset && \
1876 aRuleDetail != eRuleNone) \
1877 parentdata_ = parentContext->GetStyle##type_(); \
1878 PRBool inherited = aInherited;
1881 * Begin an nsRuleNode::Compute*Data function for an inherited struct.
1883 * @param type_ The nsStyle* type this function computes.
1884 * @param data_ Variable holding the result of this function.
1886 #define COMPUTE_END_INHERITED(type_, data_) \
1887 if (inherited) \
1888 /* We inherited, and therefore can't be cached in the rule node. We */ \
1889 /* have to be put right on the style context. */ \
1890 aContext->SetStyle(eStyleStruct_##type_, data_); \
1891 else { \
1892 /* We were fully specified and can therefore be cached right on the */ \
1893 /* rule node. */ \
1894 if (!aHighestNode->mStyleData.mInheritedData) { \
1895 aHighestNode->mStyleData.mInheritedData = \
1896 new (mPresContext) nsInheritedStyleData; \
1897 if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) { \
1898 data_->Destroy(mPresContext); \
1899 return nsnull; \
1902 aHighestNode->mStyleData.mInheritedData->m##type_##Data = data_; \
1903 /* Propagate the bit down. */ \
1904 PropagateDependentBit(NS_STYLE_INHERIT_BIT(type_), aHighestNode); \
1907 return data_;
1910 * Begin an nsRuleNode::Compute*Data function for a reset struct.
1912 * @param type_ The nsStyle* type this function computes.
1913 * @param data_ Variable holding the result of this function.
1915 #define COMPUTE_END_RESET(type_, data_) \
1916 if (inherited) \
1917 /* We inherited, and therefore can't be cached in the rule node. We */ \
1918 /* have to be put right on the style context. */ \
1919 aContext->SetStyle(eStyleStruct_##type_, data_); \
1920 else { \
1921 /* We were fully specified and can therefore be cached right on the */ \
1922 /* rule node. */ \
1923 if (!aHighestNode->mStyleData.mResetData) { \
1924 aHighestNode->mStyleData.mResetData = \
1925 new (mPresContext) nsResetStyleData; \
1926 if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) { \
1927 data_->Destroy(mPresContext); \
1928 return nsnull; \
1931 aHighestNode->mStyleData.mResetData->m##type_##Data = data_; \
1932 /* Propagate the bit down. */ \
1933 PropagateDependentBit(NS_STYLE_INHERIT_BIT(type_), aHighestNode); \
1936 return data_;
1938 #ifdef MOZ_MATHML
1939 // This function figures out how much scaling should be suppressed to
1940 // satisfy scriptminsize. This is our attempt to implement
1941 // http://www.w3.org/TR/MathML2/chapter3.html#id.3.3.4.2.2
1942 // This is called after mScriptLevel, mScriptMinSize and mScriptSizeMultiplier
1943 // have been set in aFont.
1945 // Here are the invariants we enforce:
1946 // 1) A decrease in size must not reduce the size below minscriptsize.
1947 // 2) An increase in size must not increase the size above the size we would
1948 // have if minscriptsize had not been applied anywhere.
1949 // 3) The scriptlevel-induced size change must between 1.0 and the parent's
1950 // scriptsizemultiplier^(new script level - old script level), as close to the
1951 // latter as possible subject to constraints 1 and 2.
1952 static nscoord
1953 ComputeScriptLevelSize(const nsStyleFont* aFont, const nsStyleFont* aParentFont,
1954 nsPresContext* aPresContext, nscoord* aUnconstrainedSize)
1956 PRInt32 scriptLevelChange =
1957 aFont->mScriptLevel - aParentFont->mScriptLevel;
1958 if (scriptLevelChange == 0) {
1959 *aUnconstrainedSize = aParentFont->mScriptUnconstrainedSize;
1960 // Constraint #3 says that we cannot change size, and #1 and #2 are always
1961 // satisfied with no change. It's important this be fast because it covers
1962 // all non-MathML content.
1963 return aParentFont->mSize;
1966 // Compute actual value of minScriptSize
1967 nscoord minScriptSize =
1968 nsStyleFont::ZoomText(aPresContext, aParentFont->mScriptMinSize);
1970 double scriptLevelScale =
1971 pow(aParentFont->mScriptSizeMultiplier, scriptLevelChange);
1972 // Compute the size we would have had if minscriptsize had never been
1973 // applied, also prevent overflow (bug 413274)
1974 *aUnconstrainedSize =
1975 NSToCoordRound(PR_MIN(aParentFont->mScriptUnconstrainedSize*scriptLevelScale,
1976 nscoord_MAX));
1977 // Compute the size we could get via scriptlevel change
1978 nscoord scriptLevelSize =
1979 NSToCoordRound(PR_MIN(aParentFont->mSize*scriptLevelScale,
1980 nscoord_MAX));
1981 if (scriptLevelScale <= 1.0) {
1982 if (aParentFont->mSize <= minScriptSize) {
1983 // We can't decrease the font size at all, so just stick to no change
1984 // (authors are allowed to explicitly set the font size smaller than
1985 // minscriptsize)
1986 return aParentFont->mSize;
1988 // We can decrease, so apply constraint #1
1989 return PR_MAX(minScriptSize, scriptLevelSize);
1990 } else {
1991 // scriptminsize can only make sizes larger than the unconstrained size
1992 NS_ASSERTION(*aUnconstrainedSize <= scriptLevelSize, "How can this ever happen?");
1993 // Apply constraint #2
1994 return PR_MIN(scriptLevelSize, PR_MAX(*aUnconstrainedSize, minScriptSize));
1997 #endif
1999 /* static */ void
2000 nsRuleNode::SetFontSize(nsPresContext* aPresContext,
2001 const nsRuleDataFont& aFontData,
2002 const nsStyleFont* aFont,
2003 const nsStyleFont* aParentFont,
2004 nscoord* aSize,
2005 const nsFont& aSystemFont,
2006 nscoord aParentSize,
2007 nscoord aScriptLevelAdjustedParentSize,
2008 PRBool aUsedStartStruct,
2009 PRBool& aInherited)
2011 PRBool zoom = PR_FALSE;
2012 PRInt32 baseSize = (PRInt32) aPresContext->
2013 GetDefaultFont(aFont->mFlags & NS_STYLE_FONT_FACE_MASK)->size;
2014 if (eCSSUnit_Enumerated == aFontData.mSize.GetUnit()) {
2015 PRInt32 value = aFontData.mSize.GetIntValue();
2016 PRInt32 scaler = aPresContext->FontScaler();
2017 float scaleFactor = nsStyleUtil::GetScalingFactor(scaler);
2019 zoom = PR_TRUE;
2020 if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) &&
2021 (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
2022 *aSize = nsStyleUtil::CalcFontPointSize(value, baseSize,
2023 scaleFactor, aPresContext, eFontSize_CSS);
2025 else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
2026 // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
2027 *aSize = nsStyleUtil::CalcFontPointSize(value, baseSize,
2028 scaleFactor, aPresContext);
2030 else if (NS_STYLE_FONT_SIZE_LARGER == value ||
2031 NS_STYLE_FONT_SIZE_SMALLER == value) {
2032 aInherited = PR_TRUE;
2034 // Un-zoom so we use the tables correctly. We'll then rezoom due
2035 // to the |zoom = PR_TRUE| above.
2036 // Note that relative units here use the parent's size unadjusted
2037 // for scriptlevel changes. A scriptlevel change between us and the parent
2038 // is simply ignored.
2039 nscoord parentSize =
2040 nsStyleFont::UnZoomText(aPresContext, aParentSize);
2042 if (NS_STYLE_FONT_SIZE_LARGER == value) {
2043 *aSize = nsStyleUtil::FindNextLargerFontSize(parentSize,
2044 baseSize, scaleFactor, aPresContext, eFontSize_CSS);
2045 NS_ASSERTION(*aSize > parentSize,
2046 "FindNextLargerFontSize failed");
2048 else {
2049 *aSize = nsStyleUtil::FindNextSmallerFontSize(parentSize,
2050 baseSize, scaleFactor, aPresContext, eFontSize_CSS);
2051 NS_ASSERTION(*aSize < parentSize ||
2052 parentSize <= nsPresContext::CSSPixelsToAppUnits(1),
2053 "FindNextSmallerFontSize failed");
2055 } else {
2056 NS_NOTREACHED("unexpected value");
2059 else if (aFontData.mSize.IsLengthUnit()) {
2060 // Note that font-based length units use the parent's size unadjusted
2061 // for scriptlevel changes. A scriptlevel change between us and the parent
2062 // is simply ignored.
2063 *aSize = CalcLengthWith(aFontData.mSize, aParentSize, aParentFont, nsnull,
2064 aPresContext, aInherited);
2065 zoom = aFontData.mSize.IsFixedLengthUnit() ||
2066 aFontData.mSize.GetUnit() == eCSSUnit_Pixel;
2068 else if (eCSSUnit_Percent == aFontData.mSize.GetUnit()) {
2069 aInherited = PR_TRUE;
2070 // Note that % units use the parent's size unadjusted for scriptlevel
2071 // changes. A scriptlevel change between us and the parent is simply
2072 // ignored.
2073 *aSize = NSToCoordRound(aParentSize *
2074 aFontData.mSize.GetPercentValue());
2075 zoom = PR_FALSE;
2077 else if (eCSSUnit_System_Font == aFontData.mSize.GetUnit()) {
2078 // this becomes our cascading size
2079 *aSize = aSystemFont.size;
2080 zoom = PR_TRUE;
2082 else if (eCSSUnit_Inherit == aFontData.mSize.GetUnit()) {
2083 aInherited = PR_TRUE;
2084 // We apply scriptlevel change for this case, because the default is
2085 // to inherit and we don't want explicit "inherit" to differ from the
2086 // default.
2087 *aSize = aScriptLevelAdjustedParentSize;
2088 zoom = PR_FALSE;
2090 else if (eCSSUnit_Initial == aFontData.mSize.GetUnit()) {
2091 // The initial value is 'medium', which has magical sizing based on
2092 // the generic font family, so do that here too.
2093 *aSize = baseSize;
2094 zoom = PR_TRUE;
2095 } else {
2096 NS_ASSERTION(eCSSUnit_Null == aFontData.mSize.GetUnit(),
2097 "What kind of font-size value is this?");
2098 #ifdef MOZ_MATHML
2099 // if aUsedStartStruct is true, then every single property in the
2100 // font struct is being set all at once. This means scriptlevel is not
2101 // going to have any influence on the font size; there is no need to
2102 // do anything here.
2103 if (!aUsedStartStruct && aParentSize != aScriptLevelAdjustedParentSize) {
2104 // There was no rule affecting the size but the size has been
2105 // affected by the parent's size via scriptlevel change. So treat
2106 // this as inherited.
2107 aInherited = PR_TRUE;
2108 *aSize = aScriptLevelAdjustedParentSize;
2110 #endif
2113 // We want to zoom the cascaded size so that em-based measurements,
2114 // line-heights, etc., work.
2115 if (zoom) {
2116 *aSize = nsStyleFont::ZoomText(aPresContext, *aSize);
2120 static PRInt8 ClampTo8Bit(PRInt32 aValue) {
2121 if (aValue < -128)
2122 return -128;
2123 if (aValue > 127)
2124 return 127;
2125 return PRInt8(aValue);
2128 /* static */ void
2129 nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
2130 nscoord aMinFontSize,
2131 PRUint8 aGenericFontID, const nsRuleDataFont& aFontData,
2132 const nsStyleFont* aParentFont,
2133 nsStyleFont* aFont, PRBool aUsedStartStruct,
2134 PRBool& aInherited)
2136 const nsFont* defaultVariableFont =
2137 aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID);
2139 // -moz-system-font: enum (never inherit!)
2140 nsFont systemFont;
2141 if (eCSSUnit_Enumerated == aFontData.mSystemFont.GetUnit()) {
2142 nsSystemFontID sysID;
2143 switch (aFontData.mSystemFont.GetIntValue()) {
2144 case NS_STYLE_FONT_CAPTION: sysID = eSystemFont_Caption; break; // css2
2145 case NS_STYLE_FONT_ICON: sysID = eSystemFont_Icon; break;
2146 case NS_STYLE_FONT_MENU: sysID = eSystemFont_Menu; break;
2147 case NS_STYLE_FONT_MESSAGE_BOX: sysID = eSystemFont_MessageBox; break;
2148 case NS_STYLE_FONT_SMALL_CAPTION: sysID = eSystemFont_SmallCaption; break;
2149 case NS_STYLE_FONT_STATUS_BAR: sysID = eSystemFont_StatusBar; break;
2150 case NS_STYLE_FONT_WINDOW: sysID = eSystemFont_Window; break; // css3
2151 case NS_STYLE_FONT_DOCUMENT: sysID = eSystemFont_Document; break;
2152 case NS_STYLE_FONT_WORKSPACE: sysID = eSystemFont_Workspace; break;
2153 case NS_STYLE_FONT_DESKTOP: sysID = eSystemFont_Desktop; break;
2154 case NS_STYLE_FONT_INFO: sysID = eSystemFont_Info; break;
2155 case NS_STYLE_FONT_DIALOG: sysID = eSystemFont_Dialog; break;
2156 case NS_STYLE_FONT_BUTTON: sysID = eSystemFont_Button; break;
2157 case NS_STYLE_FONT_PULL_DOWN_MENU:sysID = eSystemFont_PullDownMenu; break;
2158 case NS_STYLE_FONT_LIST: sysID = eSystemFont_List; break;
2159 case NS_STYLE_FONT_FIELD: sysID = eSystemFont_Field; break;
2162 // GetSystemFont sets the font face but not necessarily the size
2163 // XXX Or at least it used to -- no longer true for thebes. Maybe
2164 // it should be again, though.
2165 systemFont.size = defaultVariableFont->size;
2167 if (NS_FAILED(aPresContext->DeviceContext()->GetSystemFont(sysID,
2168 &systemFont))) {
2169 systemFont.name = defaultVariableFont->name;
2172 // XXXldb All of this platform-specific stuff should be in the
2173 // nsIDeviceContext implementations, not here.
2175 #ifdef XP_WIN
2177 // As far as I can tell the system default fonts and sizes for
2178 // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
2179 // all pre-determined and cannot be changed by either the control panel
2180 // or programmtically.
2182 switch (sysID) {
2183 // Fields (text fields)
2184 // Button and Selects (listboxes/comboboxes)
2185 // We use whatever font is defined by the system. Which it appears
2186 // (and the assumption is) it is always a proportional font. Then we
2187 // always use 2 points smaller than what the browser has defined as
2188 // the default proportional font.
2189 case eSystemFont_Field:
2190 case eSystemFont_Button:
2191 case eSystemFont_List:
2192 // Assumption: system defined font is proportional
2193 systemFont.size =
2194 PR_MAX(defaultVariableFont->size - aPresContext->PointsToAppUnits(2), 0);
2195 break;
2197 #endif
2198 } else {
2199 // In case somebody explicitly used -moz-use-system-font.
2200 systemFont = *defaultVariableFont;
2204 // font-family: string list, enum, inherit
2205 NS_ASSERTION(eCSSUnit_Enumerated != aFontData.mFamily.GetUnit(),
2206 "system fonts should not be in mFamily anymore");
2207 if (eCSSUnit_String == aFontData.mFamily.GetUnit()) {
2208 // set the correct font if we are using DocumentFonts OR we are overriding for XUL
2209 // MJA: bug 31816
2210 if (aGenericFontID == kGenericFont_NONE) {
2211 // only bother appending fallback fonts if this isn't a fallback generic font itself
2212 if (!aFont->mFont.name.IsEmpty())
2213 aFont->mFont.name.Append((PRUnichar)',');
2214 // defaultVariableFont.name should always be "serif" or "sans-serif".
2215 aFont->mFont.name.Append(defaultVariableFont->name);
2217 aFont->mFont.familyNameQuirks =
2218 (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks &&
2219 aFontData.mFamilyFromHTML);
2220 aFont->mFont.systemFont = PR_FALSE;
2221 aFont->mFlags &= ~NS_STYLE_FONT_FACE_MASK;
2222 // Technically this is redundant with the code below, but it's good
2223 // to have since we'll still want it once we get rid of
2224 // SetGenericFont (bug 380915).
2225 aFont->mFlags |= aGenericFontID;
2227 else if (eCSSUnit_System_Font == aFontData.mFamily.GetUnit()) {
2228 aFont->mFont.name = systemFont.name;
2229 aFont->mFont.familyNameQuirks = PR_FALSE;
2230 aFont->mFont.systemFont = PR_TRUE;
2231 aFont->mFlags &= ~NS_STYLE_FONT_FACE_MASK;
2233 else if (eCSSUnit_Inherit == aFontData.mFamily.GetUnit()) {
2234 aInherited = PR_TRUE;
2235 aFont->mFont.name = aParentFont->mFont.name;
2236 aFont->mFont.familyNameQuirks = aParentFont->mFont.familyNameQuirks;
2237 aFont->mFont.systemFont = aParentFont->mFont.systemFont;
2238 aFont->mFlags &= ~NS_STYLE_FONT_FACE_MASK;
2239 aFont->mFlags |= (aParentFont->mFlags & NS_STYLE_FONT_FACE_MASK);
2241 else if (eCSSUnit_Initial == aFontData.mFamily.GetUnit()) {
2242 aFont->mFont.name = defaultVariableFont->name;
2243 aFont->mFont.familyNameQuirks = PR_FALSE;
2244 aFont->mFont.systemFont = defaultVariableFont->systemFont;
2245 aFont->mFlags &= ~NS_STYLE_FONT_FACE_MASK;
2248 // When we're in the loop in SetGenericFont, we must ensure that we
2249 // always keep aFont->mFlags set to the correct generic. But we have
2250 // to be careful not to touch it when we're called directly from
2251 // ComputeFontData, because we could have a start struct.
2252 if (aGenericFontID != kGenericFont_NONE) {
2253 aFont->mFlags &= ~NS_STYLE_FONT_FACE_MASK;
2254 aFont->mFlags |= aGenericFontID;
2257 // font-style: enum, normal, inherit
2258 if (eCSSUnit_Enumerated == aFontData.mStyle.GetUnit()) {
2259 aFont->mFont.style = aFontData.mStyle.GetIntValue();
2261 else if (eCSSUnit_Normal == aFontData.mStyle.GetUnit()) {
2262 aFont->mFont.style = NS_STYLE_FONT_STYLE_NORMAL;
2264 else if (eCSSUnit_System_Font == aFontData.mStyle.GetUnit()) {
2265 aFont->mFont.style = systemFont.style;
2267 else if (eCSSUnit_Inherit == aFontData.mStyle.GetUnit()) {
2268 aInherited = PR_TRUE;
2269 aFont->mFont.style = aParentFont->mFont.style;
2271 else if (eCSSUnit_Initial == aFontData.mStyle.GetUnit()) {
2272 aFont->mFont.style = defaultVariableFont->style;
2275 // font-variant: enum, normal, inherit
2276 if (eCSSUnit_Enumerated == aFontData.mVariant.GetUnit()) {
2277 aFont->mFont.variant = aFontData.mVariant.GetIntValue();
2279 else if (eCSSUnit_Normal == aFontData.mVariant.GetUnit()) {
2280 aFont->mFont.variant = NS_STYLE_FONT_VARIANT_NORMAL;
2282 else if (eCSSUnit_System_Font == aFontData.mVariant.GetUnit()) {
2283 aFont->mFont.variant = systemFont.variant;
2285 else if (eCSSUnit_Inherit == aFontData.mVariant.GetUnit()) {
2286 aInherited = PR_TRUE;
2287 aFont->mFont.variant = aParentFont->mFont.variant;
2289 else if (eCSSUnit_Initial == aFontData.mVariant.GetUnit()) {
2290 aFont->mFont.variant = defaultVariableFont->variant;
2293 // font-weight: int, enum, normal, inherit
2294 if (eCSSUnit_Integer == aFontData.mWeight.GetUnit()) {
2295 aFont->mFont.weight = aFontData.mWeight.GetIntValue();
2297 else if (eCSSUnit_Enumerated == aFontData.mWeight.GetUnit()) {
2298 PRInt32 value = aFontData.mWeight.GetIntValue();
2299 switch (value) {
2300 case NS_STYLE_FONT_WEIGHT_NORMAL:
2301 case NS_STYLE_FONT_WEIGHT_BOLD:
2302 aFont->mFont.weight = value;
2303 break;
2304 case NS_STYLE_FONT_WEIGHT_BOLDER:
2305 case NS_STYLE_FONT_WEIGHT_LIGHTER:
2306 aInherited = PR_TRUE;
2307 aFont->mFont.weight = nsStyleUtil::ConstrainFontWeight(aParentFont->mFont.weight + value);
2308 break;
2311 else if (eCSSUnit_Normal == aFontData.mWeight.GetUnit()) {
2312 aFont->mFont.weight = NS_STYLE_FONT_WEIGHT_NORMAL;
2314 else if (eCSSUnit_System_Font == aFontData.mWeight.GetUnit()) {
2315 aFont->mFont.weight = systemFont.weight;
2317 else if (eCSSUnit_Inherit == aFontData.mWeight.GetUnit()) {
2318 aInherited = PR_TRUE;
2319 aFont->mFont.weight = aParentFont->mFont.weight;
2321 else if (eCSSUnit_Initial == aFontData.mWeight.GetUnit()) {
2322 aFont->mFont.weight = defaultVariableFont->weight;
2325 #ifdef MOZ_MATHML
2326 // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
2327 // they're available for font-size computation.
2329 // -moz-script-min-size: length
2330 if (aFontData.mScriptMinSize.IsLengthUnit()) {
2331 // scriptminsize in font units (em, ex) has to be interpreted relative
2332 // to the parent font, or the size definitions are circular and we
2334 aFont->mScriptMinSize =
2335 CalcLengthWith(aFontData.mScriptMinSize, aParentFont->mSize, aParentFont, nsnull,
2336 aPresContext, aInherited);
2339 // -moz-script-size-multiplier: factor, inherit
2340 if (eCSSUnit_Number == aFontData.mScriptSizeMultiplier.GetUnit()) {
2341 aFont->mScriptSizeMultiplier = aFontData.mScriptSizeMultiplier.GetFloatValue();
2342 NS_ASSERTION(aFont->mScriptSizeMultiplier >= 0.0f, "Cannot have negative script size multiplier");
2344 else if (eCSSUnit_Inherit == aFontData.mScriptSizeMultiplier.GetUnit()) {
2345 aInherited = PR_TRUE;
2346 aFont->mScriptSizeMultiplier = aParentFont->mScriptSizeMultiplier;
2348 else if (eCSSUnit_Initial == aFontData.mScriptSizeMultiplier.GetUnit()) {
2349 aFont->mScriptSizeMultiplier = NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER;
2352 // -moz-script-level: integer, number, inherit
2353 if (eCSSUnit_Integer == aFontData.mScriptLevel.GetUnit()) {
2354 // "relative"
2355 aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel + aFontData.mScriptLevel.GetIntValue());
2357 else if (eCSSUnit_Number == aFontData.mScriptLevel.GetUnit()) {
2358 // "absolute"
2359 aFont->mScriptLevel = ClampTo8Bit(PRInt32(aFontData.mScriptLevel.GetFloatValue()));
2361 else if (eCSSUnit_Inherit == aFontData.mScriptSizeMultiplier.GetUnit()) {
2362 aInherited = PR_TRUE;
2363 aFont->mScriptLevel = aParentFont->mScriptLevel;
2365 else if (eCSSUnit_Initial == aFontData.mScriptSizeMultiplier.GetUnit()) {
2366 aFont->mScriptLevel = 0;
2368 #endif
2370 // font-size: enum, length, percent, inherit
2371 nscoord scriptLevelAdjustedParentSize = aParentFont->mSize;
2372 #ifdef MOZ_MATHML
2373 nscoord scriptLevelAdjustedUnconstrainedParentSize;
2374 scriptLevelAdjustedParentSize =
2375 ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
2376 &scriptLevelAdjustedUnconstrainedParentSize);
2377 NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
2378 "If we have a start struct, we should have reset everything coming in here");
2379 #endif
2380 SetFontSize(aPresContext, aFontData, aFont, aParentFont, &aFont->mSize,
2381 systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
2382 aUsedStartStruct, aInherited);
2383 #ifdef MOZ_MATHML
2384 if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
2385 scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) {
2386 // Fast path: we have not been affected by scriptminsize so we don't
2387 // need to call SetFontSize again to compute the
2388 // scriptminsize-unconstrained size. This is OK even if we have a
2389 // start struct, because if we have a start struct then 'font-size'
2390 // was specified and so scriptminsize has no effect.
2391 aFont->mScriptUnconstrainedSize = aFont->mSize;
2392 } else {
2393 SetFontSize(aPresContext, aFontData, aFont, aParentFont,
2394 &aFont->mScriptUnconstrainedSize, systemFont,
2395 aParentFont->mScriptUnconstrainedSize,
2396 scriptLevelAdjustedUnconstrainedParentSize,
2397 aUsedStartStruct, aInherited);
2399 NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
2400 "scriptminsize should never be making things bigger");
2401 #endif
2403 // enforce the user' specified minimum font-size on the value that we expose
2404 // (but don't change font-size:0)
2405 if (0 < aFont->mSize && aFont->mSize < aMinFontSize)
2406 aFont->mFont.size = aMinFontSize;
2407 else
2408 aFont->mFont.size = aFont->mSize;
2410 // font-size-adjust: number, none, inherit
2411 if (eCSSUnit_Number == aFontData.mSizeAdjust.GetUnit()) {
2412 aFont->mFont.sizeAdjust = aFontData.mSizeAdjust.GetFloatValue();
2414 else if (eCSSUnit_None == aFontData.mSizeAdjust.GetUnit()) {
2415 aFont->mFont.sizeAdjust = 0.0f;
2417 else if (eCSSUnit_System_Font == aFontData.mSizeAdjust.GetUnit()) {
2418 aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
2420 else if (eCSSUnit_Inherit == aFontData.mSizeAdjust.GetUnit()) {
2421 aInherited = PR_TRUE;
2422 aFont->mFont.sizeAdjust = aParentFont->mFont.sizeAdjust;
2424 else if (eCSSUnit_Initial == aFontData.mSizeAdjust.GetUnit()) {
2425 aFont->mFont.sizeAdjust = 0.0f;
2429 // SetGenericFont:
2430 // - backtrack to an ancestor with the same generic font name (possibly
2431 // up to the root where default values come from the presentation context)
2432 // - re-apply cascading rules from there without caching intermediate values
2433 /* static */ void
2434 nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
2435 nsStyleContext* aContext,
2436 PRUint8 aGenericFontID, nscoord aMinFontSize,
2437 nsStyleFont* aFont)
2439 // walk up the contexts until a context with the desired generic font
2440 nsAutoVoidArray contextPath;
2441 contextPath.AppendElement(aContext);
2442 nsStyleContext* higherContext = aContext->GetParent();
2443 while (higherContext) {
2444 if (higherContext->GetStyleFont()->mFlags & aGenericFontID) {
2445 // done walking up the higher contexts
2446 break;
2448 contextPath.AppendElement(higherContext);
2449 higherContext = higherContext->GetParent();
2452 // re-apply the cascading rules, starting from the higher context
2454 // If we stopped earlier because we reached the root of the style tree,
2455 // we will start with the default generic font from the presentation
2456 // context. Otherwise we start with the higher context.
2457 const nsFont* defaultFont = aPresContext->GetDefaultFont(aGenericFontID);
2458 nsStyleFont parentFont(*defaultFont, aPresContext);
2459 if (higherContext) {
2460 const nsStyleFont* tmpFont = higherContext->GetStyleFont();
2461 parentFont = *tmpFont;
2463 *aFont = parentFont;
2465 PRBool dummy;
2466 PRUint32 fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
2468 for (PRInt32 i = contextPath.Count() - 1; i >= 0; --i) {
2469 nsStyleContext* context = (nsStyleContext*)contextPath[i];
2470 nsRuleDataFont fontData; // Declare a struct with null CSS values.
2471 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), aPresContext, context);
2472 ruleData.mFontData = &fontData;
2474 // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
2475 // Note that we *do* need to do this for our own data, since what is
2476 // in |fontData| in ComputeFontData is only for the rules below
2477 // aStartStruct.
2478 for (nsRuleNode* ruleNode = context->GetRuleNode(); ruleNode;
2479 ruleNode = ruleNode->GetParent()) {
2480 if (ruleNode->mNoneBits & fontBit)
2481 // no more font rules on this branch, get out
2482 break;
2484 nsIStyleRule *rule = ruleNode->GetRule();
2485 if (rule) {
2486 ruleData.mLevel = ruleNode->GetLevel();
2487 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
2488 rule->MapRuleInfoInto(&ruleData);
2492 // Compute the delta from the information that the rules specified
2494 // Avoid unnecessary operations in SetFont(). But we care if it's
2495 // the final value that we're computing.
2496 if (i != 0)
2497 fontData.mFamily.Reset();
2499 nsRuleNode::SetFont(aPresContext, context, aMinFontSize,
2500 aGenericFontID, fontData, &parentFont, aFont,
2501 PR_FALSE, dummy);
2503 // XXX Not sure if we need to do this here
2504 // If we have a post-resolve callback, handle that now.
2505 if (ruleData.mPostResolveCallback)
2506 (ruleData.mPostResolveCallback)(aFont, &ruleData);
2508 parentFont = *aFont;
2512 static PRBool ExtractGeneric(const nsString& aFamily, PRBool aGeneric,
2513 void *aData)
2515 nsAutoString *data = static_cast<nsAutoString*>(aData);
2517 if (aGeneric) {
2518 *data = aFamily;
2519 return PR_FALSE; // stop enumeration
2521 return PR_TRUE;
2524 const void*
2525 nsRuleNode::ComputeFontData(void* aStartStruct,
2526 const nsRuleDataStruct& aData,
2527 nsStyleContext* aContext,
2528 nsRuleNode* aHighestNode,
2529 const RuleDetail aRuleDetail, PRBool aInherited)
2531 COMPUTE_START_INHERITED(Font, (mPresContext), font, parentFont,
2532 Font, fontData)
2534 // NOTE: The |aRuleDetail| passed in is a little bit conservative due
2535 // to the -moz-system-font property. We really don't need to consider
2536 // it here in determining whether to cache in the rule tree. However,
2537 // we do need to consider it in WalkRuleTree when deciding whether to
2538 // walk further up the tree. So this means that when the font struct
2539 // is fully specified using *longhand* properties (excluding
2540 // -moz-system-font), we won't cache in the rule tree even though we
2541 // could. However, it's pretty unlikely authors will do that
2542 // (although there is a pretty good chance they'll fully specify it
2543 // using the 'font' shorthand).
2545 // See if there is a minimum font-size constraint to honor
2546 nscoord minimumFontSize =
2547 mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
2549 if (minimumFontSize < 0)
2550 minimumFontSize = 0;
2552 PRBool useDocumentFonts =
2553 mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
2555 // See if we are in the chrome
2556 // We only need to know this to determine if we have to use the
2557 // document fonts (overriding the useDocumentFonts flag), or to
2558 // determine if we have to override the minimum font-size constraint.
2559 if ((!useDocumentFonts || minimumFontSize > 0) && mPresContext->IsChrome()) {
2560 // if we are not using document fonts, but this is a XUL document,
2561 // then we use the document fonts anyway
2562 useDocumentFonts = PR_TRUE;
2563 minimumFontSize = 0;
2566 // Figure out if we are a generic font
2567 PRUint8 generic = kGenericFont_NONE;
2568 // XXXldb What if we would have had a string if we hadn't been doing
2569 // the optimization with a non-null aStartStruct?
2570 if (eCSSUnit_String == fontData.mFamily.GetUnit()) {
2571 fontData.mFamily.GetStringValue(font->mFont.name);
2572 // XXXldb Do we want to extract the generic for this if it's not only a
2573 // generic?
2574 nsFont::GetGenericID(font->mFont.name, &generic);
2576 // If we aren't allowed to use document fonts, then we are only entitled
2577 // to use the user's default variable-width font and fixed-width font
2578 if (!useDocumentFonts) {
2579 // Extract the generic from the specified font family...
2580 nsAutoString genericName;
2581 if (!font->mFont.EnumerateFamilies(ExtractGeneric, &genericName)) {
2582 // The specified font had a generic family.
2583 font->mFont.name = genericName;
2584 nsFont::GetGenericID(genericName, &generic);
2586 // ... and only use it if it's -moz-fixed or monospace
2587 if (generic != kGenericFont_moz_fixed &&
2588 generic != kGenericFont_monospace) {
2589 font->mFont.name.Truncate();
2590 generic = kGenericFont_NONE;
2592 } else {
2593 // The specified font did not have a generic family.
2594 font->mFont.name.Truncate();
2595 generic = kGenericFont_NONE;
2600 // Now compute our font struct
2601 if (generic == kGenericFont_NONE) {
2602 // continue the normal processing
2603 nsRuleNode::SetFont(mPresContext, aContext, minimumFontSize, generic,
2604 fontData, parentFont, font,
2605 aStartStruct != nsnull, inherited);
2607 else {
2608 // re-calculate the font as a generic font
2609 inherited = PR_TRUE;
2610 nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
2611 minimumFontSize, font);
2614 COMPUTE_END_INHERITED(Font, font)
2617 const void*
2618 nsRuleNode::ComputeTextData(void* aStartStruct,
2619 const nsRuleDataStruct& aData,
2620 nsStyleContext* aContext,
2621 nsRuleNode* aHighestNode,
2622 const RuleDetail aRuleDetail, PRBool aInherited)
2624 COMPUTE_START_INHERITED(Text, (), text, parentText, Text, textData)
2626 // letter-spacing: normal, length, inherit
2627 SetCoord(textData.mLetterSpacing, text->mLetterSpacing, parentText->mLetterSpacing,
2628 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL,
2629 aContext, mPresContext, inherited);
2631 // line-height: normal, number, length, percent, inherit
2632 if (eCSSUnit_Percent == textData.mLineHeight.GetUnit()) {
2633 inherited = PR_TRUE;
2634 // Use |mFont.size| to pick up minimum font size.
2635 text->mLineHeight.SetCoordValue(
2636 nscoord(float(aContext->GetStyleFont()->mFont.size) *
2637 textData.mLineHeight.GetPercentValue()));
2639 else if (eCSSUnit_Initial == textData.mLineHeight.GetUnit() ||
2640 eCSSUnit_System_Font == textData.mLineHeight.GetUnit()) {
2641 text->mLineHeight.SetNormalValue();
2643 else {
2644 SetCoord(textData.mLineHeight, text->mLineHeight, parentText->mLineHeight,
2645 SETCOORD_LH | SETCOORD_FACTOR | SETCOORD_NORMAL,
2646 aContext, mPresContext, inherited);
2647 if (textData.mLineHeight.IsFixedLengthUnit() ||
2648 textData.mLineHeight.GetUnit() == eCSSUnit_Pixel) {
2649 nscoord lh = nsStyleFont::ZoomText(mPresContext,
2650 text->mLineHeight.GetCoordValue());
2651 nscoord minimumFontSize =
2652 mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
2654 if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
2655 // If we applied a minimum font size, scale the line height by
2656 // the same ratio. (If we *might* have applied a minimum font
2657 // size, we can't cache in the rule tree.)
2658 inherited = PR_TRUE;
2659 const nsStyleFont *font = aContext->GetStyleFont();
2660 if (font->mSize != 0) {
2661 lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
2662 } else {
2663 lh = minimumFontSize;
2666 text->mLineHeight.SetCoordValue(lh);
2671 // text-align: enum, string, inherit
2672 if (eCSSUnit_Enumerated == textData.mTextAlign.GetUnit()) {
2673 text->mTextAlign = textData.mTextAlign.GetIntValue();
2675 else if (eCSSUnit_String == textData.mTextAlign.GetUnit()) {
2676 NS_NOTYETIMPLEMENTED("align string");
2678 else if (eCSSUnit_Inherit == textData.mTextAlign.GetUnit()) {
2679 inherited = PR_TRUE;
2680 text->mTextAlign = parentText->mTextAlign;
2682 else if (eCSSUnit_Initial == textData.mTextAlign.GetUnit())
2683 text->mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
2685 // text-indent: length, percent, inherit
2686 SetCoord(textData.mTextIndent, text->mTextIndent, parentText->mTextIndent,
2687 SETCOORD_LPH | SETCOORD_INITIAL_ZERO, aContext,
2688 mPresContext, inherited);
2690 // text-transform: enum, none, inherit
2691 if (eCSSUnit_Enumerated == textData.mTextTransform.GetUnit()) {
2692 text->mTextTransform = textData.mTextTransform.GetIntValue();
2694 else if (eCSSUnit_None == textData.mTextTransform.GetUnit() ||
2695 eCSSUnit_Initial == textData.mTextTransform.GetUnit()) {
2696 text->mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE;
2698 else if (eCSSUnit_Inherit == textData.mTextTransform.GetUnit()) {
2699 inherited = PR_TRUE;
2700 text->mTextTransform = parentText->mTextTransform;
2703 // white-space: enum, normal, inherit
2704 if (eCSSUnit_Enumerated == textData.mWhiteSpace.GetUnit()) {
2705 text->mWhiteSpace = textData.mWhiteSpace.GetIntValue();
2707 else if (eCSSUnit_Normal == textData.mWhiteSpace.GetUnit() ||
2708 eCSSUnit_Initial == textData.mWhiteSpace.GetUnit()) {
2709 text->mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL;
2711 else if (eCSSUnit_Inherit == textData.mWhiteSpace.GetUnit()) {
2712 inherited = PR_TRUE;
2713 text->mWhiteSpace = parentText->mWhiteSpace;
2716 // word-spacing: normal, length, inherit
2717 SetCoord(textData.mWordSpacing, text->mWordSpacing, parentText->mWordSpacing,
2718 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL,
2719 aContext, mPresContext, inherited);
2721 COMPUTE_END_INHERITED(Text, text)
2724 const void*
2725 nsRuleNode::ComputeTextResetData(void* aStartStruct,
2726 const nsRuleDataStruct& aData,
2727 nsStyleContext* aContext,
2728 nsRuleNode* aHighestNode,
2729 const RuleDetail aRuleDetail, PRBool aInherited)
2731 COMPUTE_START_RESET(TextReset, (), text, parentText, Text, textData)
2733 // vertical-align: enum, length, percent, inherit
2734 if (!SetCoord(textData.mVerticalAlign, text->mVerticalAlign,
2735 parentText->mVerticalAlign, SETCOORD_LPH | SETCOORD_ENUMERATED,
2736 aContext, mPresContext, inherited)) {
2737 if (eCSSUnit_Initial == textData.mVerticalAlign.GetUnit()) {
2738 text->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,
2739 eStyleUnit_Enumerated);
2743 // text-decoration: none, enum (bit field), inherit
2744 if (eCSSUnit_Enumerated == textData.mDecoration.GetUnit()) {
2745 PRInt32 td = textData.mDecoration.GetIntValue();
2746 text->mTextDecoration = td;
2747 if (td & NS_STYLE_TEXT_DECORATION_PREF_ANCHORS) {
2748 PRBool underlineLinks =
2749 mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
2750 if (underlineLinks) {
2751 text->mTextDecoration |= NS_STYLE_TEXT_DECORATION_UNDERLINE;
2753 else {
2754 text->mTextDecoration &= ~NS_STYLE_TEXT_DECORATION_UNDERLINE;
2758 else if (eCSSUnit_None == textData.mDecoration.GetUnit() ||
2759 eCSSUnit_Initial == textData.mDecoration.GetUnit()) {
2760 text->mTextDecoration = NS_STYLE_TEXT_DECORATION_NONE;
2762 else if (eCSSUnit_Inherit == textData.mDecoration.GetUnit()) {
2763 inherited = PR_TRUE;
2764 text->mTextDecoration = parentText->mTextDecoration;
2767 // unicode-bidi: enum, normal, inherit
2768 if (eCSSUnit_Normal == textData.mUnicodeBidi.GetUnit() ||
2769 eCSSUnit_Initial == textData.mUnicodeBidi.GetUnit()) {
2770 text->mUnicodeBidi = NS_STYLE_UNICODE_BIDI_NORMAL;
2772 else if (eCSSUnit_Enumerated == textData.mUnicodeBidi.GetUnit() ) {
2773 text->mUnicodeBidi = textData.mUnicodeBidi.GetIntValue();
2775 else if (eCSSUnit_Inherit == textData.mUnicodeBidi.GetUnit() ) {
2776 inherited = PR_TRUE;
2777 text->mUnicodeBidi = parentText->mUnicodeBidi;
2780 COMPUTE_END_RESET(TextReset, text)
2783 const void*
2784 nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
2785 const nsRuleDataStruct& aData,
2786 nsStyleContext* aContext,
2787 nsRuleNode* aHighestNode,
2788 const RuleDetail aRuleDetail,
2789 PRBool aInherited)
2791 COMPUTE_START_INHERITED(UserInterface, (), ui, parentUI,
2792 UserInterface, uiData)
2794 // cursor: enum, auto, url, inherit
2795 nsCSSValueList* list = uiData.mCursor;
2796 if (nsnull != list) {
2797 delete [] ui->mCursorArray;
2798 ui->mCursorArray = nsnull;
2799 ui->mCursorArrayLength = 0;
2801 if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
2802 inherited = PR_TRUE;
2803 ui->mCursor = parentUI->mCursor;
2804 ui->CopyCursorArrayFrom(*parentUI);
2806 else if (eCSSUnit_Initial == list->mValue.GetUnit()) {
2807 ui->mCursor = NS_STYLE_CURSOR_AUTO;
2809 else {
2810 // The parser will never create a list that is *all* URL values --
2811 // that's invalid.
2812 PRUint32 arrayLength = 0;
2813 nsCSSValueList* list2 = list;
2814 for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext)
2815 if (list->mValue.GetArrayValue()->Item(0).GetImageValue())
2816 ++arrayLength;
2818 if (arrayLength != 0) {
2819 ui->mCursorArray = new nsCursorImage[arrayLength];
2820 if (ui->mCursorArray) {
2821 ui->mCursorArrayLength = arrayLength;
2823 for (nsCursorImage *item = ui->mCursorArray;
2824 list2->mValue.GetUnit() == eCSSUnit_Array;
2825 list2 = list2->mNext) {
2826 nsCSSValue::Array *arr = list2->mValue.GetArrayValue();
2827 imgIRequest *req = arr->Item(0).GetImageValue();
2828 if (req) {
2829 item->mImage = req;
2830 if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
2831 item->mHaveHotspot = PR_TRUE;
2832 item->mHotspotX = arr->Item(1).GetFloatValue(),
2833 item->mHotspotY = arr->Item(2).GetFloatValue();
2835 ++item;
2841 NS_ASSERTION(list, "Must have non-array value at the end");
2842 NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated ||
2843 list->mValue.GetUnit() == eCSSUnit_Auto,
2844 "Unexpected fallback value at end of cursor list");
2846 if (eCSSUnit_Enumerated == list->mValue.GetUnit()) {
2847 ui->mCursor = list->mValue.GetIntValue();
2849 else if (eCSSUnit_Auto == list->mValue.GetUnit()) {
2850 ui->mCursor = NS_STYLE_CURSOR_AUTO;
2855 // user-input: auto, none, enum, inherit
2856 if (eCSSUnit_Enumerated == uiData.mUserInput.GetUnit()) {
2857 ui->mUserInput = uiData.mUserInput.GetIntValue();
2859 else if (eCSSUnit_Auto == uiData.mUserInput.GetUnit() ||
2860 eCSSUnit_Initial == uiData.mUserInput.GetUnit()) {
2861 ui->mUserInput = NS_STYLE_USER_INPUT_AUTO;
2863 else if (eCSSUnit_None == uiData.mUserInput.GetUnit()) {
2864 ui->mUserInput = NS_STYLE_USER_INPUT_NONE;
2866 else if (eCSSUnit_Inherit == uiData.mUserInput.GetUnit()) {
2867 inherited = PR_TRUE;
2868 ui->mUserInput = parentUI->mUserInput;
2871 // user-modify: enum, inherit
2872 if (eCSSUnit_Enumerated == uiData.mUserModify.GetUnit()) {
2873 ui->mUserModify = uiData.mUserModify.GetIntValue();
2875 else if (eCSSUnit_Inherit == uiData.mUserModify.GetUnit()) {
2876 inherited = PR_TRUE;
2877 ui->mUserModify = parentUI->mUserModify;
2879 else if (eCSSUnit_Initial == uiData.mUserModify.GetUnit()) {
2880 ui->mUserModify = NS_STYLE_USER_MODIFY_READ_ONLY;
2883 // user-focus: none, normal, enum, inherit
2884 if (eCSSUnit_Enumerated == uiData.mUserFocus.GetUnit()) {
2885 ui->mUserFocus = uiData.mUserFocus.GetIntValue();
2887 else if (eCSSUnit_None == uiData.mUserFocus.GetUnit() ||
2888 eCSSUnit_Initial == uiData.mUserFocus.GetUnit()) {
2889 ui->mUserFocus = NS_STYLE_USER_FOCUS_NONE;
2891 else if (eCSSUnit_Normal == uiData.mUserFocus.GetUnit()) {
2892 ui->mUserFocus = NS_STYLE_USER_FOCUS_NORMAL;
2894 else if (eCSSUnit_Inherit == uiData.mUserFocus.GetUnit()) {
2895 inherited = PR_TRUE;
2896 ui->mUserFocus = parentUI->mUserFocus;
2899 COMPUTE_END_INHERITED(UserInterface, ui)
2902 const void*
2903 nsRuleNode::ComputeUIResetData(void* aStartStruct,
2904 const nsRuleDataStruct& aData,
2905 nsStyleContext* aContext,
2906 nsRuleNode* aHighestNode,
2907 const RuleDetail aRuleDetail, PRBool aInherited)
2909 COMPUTE_START_RESET(UIReset, (), ui, parentUI, UserInterface, uiData)
2911 // user-select: none, enum, inherit
2912 if (eCSSUnit_Enumerated == uiData.mUserSelect.GetUnit()) {
2913 ui->mUserSelect = uiData.mUserSelect.GetIntValue();
2915 else if (eCSSUnit_None == uiData.mUserSelect.GetUnit()) {
2916 ui->mUserSelect = NS_STYLE_USER_SELECT_NONE;
2918 else if (eCSSUnit_Inherit == uiData.mUserSelect.GetUnit()) {
2919 inherited = PR_TRUE;
2920 ui->mUserSelect = parentUI->mUserSelect;
2922 else if (eCSSUnit_Initial == uiData.mUserSelect.GetUnit()) {
2923 // FIXME There's no other way to specify this value!
2924 ui->mUserSelect = NS_STYLE_USER_SELECT_AUTO;
2927 // ime-mode: auto, normal, enum, inherit
2928 if (eCSSUnit_Auto == uiData.mIMEMode.GetUnit() ||
2929 eCSSUnit_Initial == uiData.mIMEMode.GetUnit()) {
2930 ui->mIMEMode = NS_STYLE_IME_MODE_AUTO;
2932 else if (eCSSUnit_Normal == uiData.mIMEMode.GetUnit()) {
2933 ui->mIMEMode = NS_STYLE_IME_MODE_NORMAL;
2935 else if (eCSSUnit_Enumerated == uiData.mIMEMode.GetUnit()) {
2936 ui->mIMEMode = uiData.mIMEMode.GetIntValue();
2938 else if (eCSSUnit_Inherit == uiData.mIMEMode.GetUnit()) {
2939 inherited = PR_TRUE;
2940 ui->mIMEMode = parentUI->mIMEMode;
2943 // force-broken-image-icons: integer
2944 if (eCSSUnit_Integer == uiData.mForceBrokenImageIcon.GetUnit()) {
2945 ui->mForceBrokenImageIcon = uiData.mForceBrokenImageIcon.GetIntValue();
2946 } else if (eCSSUnit_Inherit == uiData.mForceBrokenImageIcon.GetUnit()) {
2947 inherited = PR_TRUE;
2948 ui->mForceBrokenImageIcon = parentUI->mForceBrokenImageIcon;
2949 } else if (eCSSUnit_Initial == uiData.mForceBrokenImageIcon.GetUnit()) {
2950 ui->mForceBrokenImageIcon = 0;
2952 COMPUTE_END_RESET(UIReset, ui)
2955 const void*
2956 nsRuleNode::ComputeDisplayData(void* aStartStruct,
2957 const nsRuleDataStruct& aData,
2958 nsStyleContext* aContext,
2959 nsRuleNode* aHighestNode,
2960 const RuleDetail aRuleDetail, PRBool aInherited)
2962 COMPUTE_START_RESET(Display, (), display, parentDisplay,
2963 Display, displayData)
2964 nsIAtom* pseudoTag = aContext->GetPseudoType();
2965 PRBool generatedContent = (pseudoTag == nsCSSPseudoElements::before ||
2966 pseudoTag == nsCSSPseudoElements::after);
2967 NS_ASSERTION(!generatedContent || parentContext,
2968 "Must have parent context for generated content");
2969 if (parentDisplay == display && generatedContent)
2970 parentDisplay = parentContext->GetStyleDisplay();
2972 // opacity: factor, inherit
2973 if (eCSSUnit_Number == displayData.mOpacity.GetUnit()) {
2974 display->mOpacity = displayData.mOpacity.GetFloatValue();
2975 if (display->mOpacity > 1.0f)
2976 display->mOpacity = 1.0f;
2977 if (display->mOpacity < 0.0f)
2978 display->mOpacity = 0.0f;
2980 else if (eCSSUnit_Inherit == displayData.mOpacity.GetUnit()) {
2981 inherited = PR_TRUE;
2982 display->mOpacity = parentDisplay->mOpacity;
2984 else if (eCSSUnit_Initial == displayData.mOpacity.GetUnit()) {
2985 display->mOpacity = 1.0f;
2988 // display: enum, none, inherit
2989 if (eCSSUnit_Enumerated == displayData.mDisplay.GetUnit()) {
2990 display->mDisplay = displayData.mDisplay.GetIntValue();
2992 else if (eCSSUnit_None == displayData.mDisplay.GetUnit()) {
2993 display->mDisplay = NS_STYLE_DISPLAY_NONE;
2995 else if (eCSSUnit_Inherit == displayData.mDisplay.GetUnit()) {
2996 inherited = PR_TRUE;
2997 display->mDisplay = parentDisplay->mDisplay;
2999 else if (eCSSUnit_Initial == displayData.mDisplay.GetUnit()) {
3000 display->mDisplay = NS_STYLE_DISPLAY_INLINE;
3003 // appearance: enum, none, inherit
3004 if (eCSSUnit_Enumerated == displayData.mAppearance.GetUnit()) {
3005 display->mAppearance = displayData.mAppearance.GetIntValue();
3007 else if (eCSSUnit_None == displayData.mAppearance.GetUnit() ||
3008 eCSSUnit_Initial == displayData.mAppearance.GetUnit()) {
3009 display->mAppearance = NS_THEME_NONE;
3011 else if (eCSSUnit_Inherit == displayData.mAppearance.GetUnit()) {
3012 inherited = PR_TRUE;
3013 display->mAppearance = parentDisplay->mAppearance;
3016 // binding: url, none, inherit
3017 if (eCSSUnit_URL == displayData.mBinding.GetUnit()) {
3018 nsCSSValue::URL* url = displayData.mBinding.GetURLStructValue();
3019 NS_ASSERTION(url, "What's going on here?");
3021 if (NS_LIKELY(url->mURI)) {
3022 display->mBinding = url;
3023 } else {
3024 display->mBinding = nsnull;
3027 else if (eCSSUnit_None == displayData.mBinding.GetUnit() ||
3028 eCSSUnit_Initial == displayData.mBinding.GetUnit()) {
3029 display->mBinding = nsnull;
3031 else if (eCSSUnit_Inherit == displayData.mBinding.GetUnit()) {
3032 inherited = PR_TRUE;
3033 display->mBinding = parentDisplay->mBinding;
3036 // position: enum, inherit
3037 if (eCSSUnit_Enumerated == displayData.mPosition.GetUnit()) {
3038 display->mPosition = displayData.mPosition.GetIntValue();
3040 else if (eCSSUnit_Inherit == displayData.mPosition.GetUnit()) {
3041 inherited = PR_TRUE;
3042 display->mPosition = parentDisplay->mPosition;
3044 else if (eCSSUnit_Initial == displayData.mPosition.GetUnit()) {
3045 display->mPosition = NS_STYLE_POSITION_STATIC;
3048 // clear: enum, none, inherit
3049 if (eCSSUnit_Enumerated == displayData.mClear.GetUnit()) {
3050 display->mBreakType = displayData.mClear.GetIntValue();
3052 else if (eCSSUnit_None == displayData.mClear.GetUnit() ||
3053 eCSSUnit_Initial == displayData.mClear.GetUnit()) {
3054 display->mBreakType = NS_STYLE_CLEAR_NONE;
3056 else if (eCSSUnit_Inherit == displayData.mClear.GetUnit()) {
3057 inherited = PR_TRUE;
3058 display->mBreakType = parentDisplay->mBreakType;
3061 // temp fix for bug 24000
3062 // Map 'auto' and 'avoid' to PR_FALSE, and 'always', 'left', and
3063 // 'right' to PR_TRUE.
3064 // "A conforming user agent may interpret the values 'left' and
3065 // 'right' as 'always'." - CSS2.1, section 13.3.1
3066 if (eCSSUnit_Enumerated == displayData.mBreakBefore.GetUnit()) {
3067 display->mBreakBefore = (NS_STYLE_PAGE_BREAK_AVOID != displayData.mBreakBefore.GetIntValue());
3069 else if (eCSSUnit_Auto == displayData.mBreakBefore.GetUnit() ||
3070 eCSSUnit_Initial == displayData.mBreakBefore.GetUnit()) {
3071 display->mBreakBefore = PR_FALSE;
3073 else if (eCSSUnit_Inherit == displayData.mBreakBefore.GetUnit()) {
3074 inherited = PR_TRUE;
3075 display->mBreakBefore = parentDisplay->mBreakBefore;
3078 if (eCSSUnit_Enumerated == displayData.mBreakAfter.GetUnit()) {
3079 display->mBreakAfter = (NS_STYLE_PAGE_BREAK_AVOID != displayData.mBreakAfter.GetIntValue());
3081 else if (eCSSUnit_Auto == displayData.mBreakAfter.GetUnit() ||
3082 eCSSUnit_Initial == displayData.mBreakAfter.GetUnit()) {
3083 display->mBreakAfter = PR_FALSE;
3085 else if (eCSSUnit_Inherit == displayData.mBreakAfter.GetUnit()) {
3086 inherited = PR_TRUE;
3087 display->mBreakAfter = parentDisplay->mBreakAfter;
3089 // end temp fix
3091 // float: enum, none, inherit
3092 if (eCSSUnit_Enumerated == displayData.mFloat.GetUnit()) {
3093 display->mFloats = displayData.mFloat.GetIntValue();
3095 else if (eCSSUnit_None == displayData.mFloat.GetUnit() ||
3096 eCSSUnit_Initial == displayData.mFloat.GetUnit()) {
3097 display->mFloats = NS_STYLE_FLOAT_NONE;
3099 else if (eCSSUnit_Inherit == displayData.mFloat.GetUnit()) {
3100 inherited = PR_TRUE;
3101 display->mFloats = parentDisplay->mFloats;
3104 // overflow-x: enum, auto, inherit
3105 if (eCSSUnit_Enumerated == displayData.mOverflowX.GetUnit()) {
3106 display->mOverflowX = displayData.mOverflowX.GetIntValue();
3108 else if (eCSSUnit_Auto == displayData.mOverflowX.GetUnit()) {
3109 display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
3111 else if (eCSSUnit_Inherit == displayData.mOverflowX.GetUnit()) {
3112 inherited = PR_TRUE;
3113 display->mOverflowX = parentDisplay->mOverflowX;
3115 else if (eCSSUnit_Initial == displayData.mOverflowX.GetUnit()) {
3116 display->mOverflowX = NS_STYLE_OVERFLOW_VISIBLE;
3119 // overflow-y: enum, auto, inherit
3120 if (eCSSUnit_Enumerated == displayData.mOverflowY.GetUnit()) {
3121 display->mOverflowY = displayData.mOverflowY.GetIntValue();
3123 else if (eCSSUnit_Auto == displayData.mOverflowY.GetUnit()) {
3124 display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
3126 else if (eCSSUnit_Inherit == displayData.mOverflowY.GetUnit()) {
3127 inherited = PR_TRUE;
3128 display->mOverflowY = parentDisplay->mOverflowY;
3130 else if (eCSSUnit_Initial == displayData.mOverflowY.GetUnit()) {
3131 display->mOverflowY = NS_STYLE_OVERFLOW_VISIBLE;
3134 // CSS3 overflow-x and overflow-y require some fixup as well in some
3135 // cases. NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
3136 // meaningful only when used in both dimensions.
3137 if (display->mOverflowX != display->mOverflowY &&
3138 (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
3139 display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
3140 display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
3141 display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
3142 // We can't store in the rule tree since a more specific rule might
3143 // change these conditions.
3144 inherited = PR_TRUE;
3146 // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
3147 // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
3148 if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
3149 display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
3150 if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
3151 display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
3153 // If 'visible' is specified but doesn't match the other dimension, it
3154 // turns into 'auto'.
3155 if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
3156 display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
3157 if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
3158 display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
3161 // clip property: length, auto, inherit
3162 if (eCSSUnit_Inherit == displayData.mClip.mTop.GetUnit()) { // if one is inherit, they all are
3163 inherited = PR_TRUE;
3164 display->mClipFlags = parentDisplay->mClipFlags;
3165 display->mClip = parentDisplay->mClip;
3167 // if one is initial, they all are
3168 else if (eCSSUnit_Initial == displayData.mClip.mTop.GetUnit()) {
3169 display->mClipFlags = NS_STYLE_CLIP_AUTO;
3170 display->mClip.SetRect(0,0,0,0);
3172 else {
3173 PRBool fullAuto = PR_TRUE;
3175 display->mClipFlags = 0; // clear it
3177 if (eCSSUnit_Auto == displayData.mClip.mTop.GetUnit()) {
3178 display->mClip.y = 0;
3179 display->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
3181 else if (displayData.mClip.mTop.IsLengthUnit()) {
3182 display->mClip.y = CalcLength(displayData.mClip.mTop, aContext, mPresContext, inherited);
3183 fullAuto = PR_FALSE;
3185 if (eCSSUnit_Auto == displayData.mClip.mBottom.GetUnit()) {
3186 // Setting to NS_MAXSIZE for the 'auto' case ensures that
3187 // the clip rect is nonempty. It is important that mClip be
3188 // nonempty if the actual clip rect could be nonempty.
3189 display->mClip.height = NS_MAXSIZE;
3190 display->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
3192 else if (displayData.mClip.mBottom.IsLengthUnit()) {
3193 display->mClip.height = CalcLength(displayData.mClip.mBottom, aContext, mPresContext, inherited) -
3194 display->mClip.y;
3195 fullAuto = PR_FALSE;
3197 if (eCSSUnit_Auto == displayData.mClip.mLeft.GetUnit()) {
3198 display->mClip.x = 0;
3199 display->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
3201 else if (displayData.mClip.mLeft.IsLengthUnit()) {
3202 display->mClip.x = CalcLength(displayData.mClip.mLeft, aContext, mPresContext, inherited);
3203 fullAuto = PR_FALSE;
3205 if (eCSSUnit_Auto == displayData.mClip.mRight.GetUnit()) {
3206 // Setting to NS_MAXSIZE for the 'auto' case ensures that
3207 // the clip rect is nonempty. It is important that mClip be
3208 // nonempty if the actual clip rect could be nonempty.
3209 display->mClip.width = NS_MAXSIZE;
3210 display->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
3212 else if (displayData.mClip.mRight.IsLengthUnit()) {
3213 display->mClip.width = CalcLength(displayData.mClip.mRight, aContext, mPresContext, inherited) -
3214 display->mClip.x;
3215 fullAuto = PR_FALSE;
3217 display->mClipFlags &= ~NS_STYLE_CLIP_TYPE_MASK;
3218 if (fullAuto) {
3219 display->mClipFlags |= NS_STYLE_CLIP_AUTO;
3221 else {
3222 display->mClipFlags |= NS_STYLE_CLIP_RECT;
3226 // CSS2 specified fixups:
3227 if (generatedContent) {
3228 // According to CSS2 section 12.1, :before and :after
3229 // pseudo-elements must not be positioned or floated (CSS2 12.1) and
3230 // must be limited to certain display types (depending on the
3231 // display type of the element to which they are attached).
3232 // XXX These restrictions are no longer present in CSS2.1. We
3233 // should ensure that we support removing them before doing so,
3234 // though.
3235 // XXXbz For example, the calls to WipeContainingBlock in the
3236 // frame constructor will need to be changedif we allow
3237 // block-level generated content inside inlines.
3239 if (display->mPosition != NS_STYLE_POSITION_STATIC)
3240 display->mPosition = NS_STYLE_POSITION_STATIC;
3241 if (display->mFloats != NS_STYLE_FLOAT_NONE)
3242 display->mFloats = NS_STYLE_FLOAT_NONE;
3244 PRUint8 displayValue = display->mDisplay;
3245 if (displayValue != NS_STYLE_DISPLAY_NONE &&
3246 displayValue != NS_STYLE_DISPLAY_INLINE &&
3247 displayValue != NS_STYLE_DISPLAY_INLINE_BLOCK) {
3248 inherited = PR_TRUE;
3249 if (parentDisplay->IsBlockOutside() ||
3250 parentDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_BLOCK ||
3251 parentDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL ||
3252 parentDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION) {
3253 // If the subject of the selector is a block-level element,
3254 // allowed values are 'none', 'inline', 'block', and 'marker'.
3255 // If the value of the 'display' has any other value, the
3256 // pseudo-element will behave as if the value were 'block'.
3257 if (displayValue != NS_STYLE_DISPLAY_BLOCK &&
3258 displayValue != NS_STYLE_DISPLAY_MARKER)
3259 display->mDisplay = NS_STYLE_DISPLAY_BLOCK;
3260 } else {
3261 // If the subject of the selector is an inline-level element,
3262 // allowed values are 'none' and 'inline'. If the value of the
3263 // 'display' has any other value, the pseudo-element will behave
3264 // as if the value were 'inline'.
3265 display->mDisplay = NS_STYLE_DISPLAY_INLINE;
3269 else if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
3270 // CSS2 9.7 specifies display type corrections dealing with 'float'
3271 // and 'position'. Since generated content can't be floated or
3272 // positioned, we can deal with it here.
3274 if (nsCSSPseudoElements::firstLetter == pseudoTag) {
3275 // a non-floating first-letter must be inline
3276 // XXX this fix can go away once bug 103189 is fixed correctly
3277 display->mDisplay = NS_STYLE_DISPLAY_INLINE;
3279 // We can't cache the data in the rule tree since if a more specific
3280 // rule has 'float: left' we'll end up with the wrong 'display'
3281 // property.
3282 inherited = PR_TRUE;
3285 if (display->IsAbsolutelyPositioned()) {
3286 // 1) if position is 'absolute' or 'fixed' then display must be
3287 // block-level and float must be 'none'
3289 // Backup original display value for calculation of a hypothetical
3290 // box (CSS2 10.6.4/10.6.5).
3291 // See nsHTMLReflowState::CalculateHypotheticalBox
3292 display->mOriginalDisplay = display->mDisplay;
3293 EnsureBlockDisplay(display->mDisplay);
3294 display->mFloats = NS_STYLE_FLOAT_NONE;
3296 // We can't cache the data in the rule tree since if a more specific
3297 // rule has 'position: static' we'll end up with problems with the
3298 // 'display' and 'float' properties.
3299 inherited = PR_TRUE;
3300 } else if (display->mFloats != NS_STYLE_FLOAT_NONE) {
3301 // 2) if float is not none, and display is not none, then we must
3302 // set a block-level 'display' type per CSS2.1 section 9.7.
3304 EnsureBlockDisplay(display->mDisplay);
3306 // We can't cache the data in the rule tree since if a more specific
3307 // rule has 'float: none' we'll end up with the wrong 'display'
3308 // property.
3309 inherited = PR_TRUE;
3314 COMPUTE_END_RESET(Display, display)
3317 const void*
3318 nsRuleNode::ComputeVisibilityData(void* aStartStruct,
3319 const nsRuleDataStruct& aData,
3320 nsStyleContext* aContext,
3321 nsRuleNode* aHighestNode,
3322 const RuleDetail aRuleDetail, PRBool aInherited)
3324 COMPUTE_START_INHERITED(Visibility, (mPresContext),
3325 visibility, parentVisibility,
3326 Display, displayData)
3328 // direction: enum, inherit
3329 if (eCSSUnit_Enumerated == displayData.mDirection.GetUnit()) {
3330 visibility->mDirection = displayData.mDirection.GetIntValue();
3331 if (NS_STYLE_DIRECTION_RTL == visibility->mDirection)
3332 mPresContext->SetBidiEnabled();
3334 else if (eCSSUnit_Inherit == displayData.mDirection.GetUnit()) {
3335 inherited = PR_TRUE;
3336 visibility->mDirection = parentVisibility->mDirection;
3338 else if (eCSSUnit_Initial == displayData.mDirection.GetUnit()) {
3339 PRUint32 bidiOptions = mPresContext->GetBidi();
3340 if (GET_BIDI_OPTION_DIRECTION(bidiOptions) == IBMBIDI_TEXTDIRECTION_RTL)
3341 visibility->mDirection = NS_STYLE_DIRECTION_RTL;
3342 else
3343 visibility->mDirection = NS_STYLE_DIRECTION_LTR;
3346 // visibility: enum, inherit
3347 if (eCSSUnit_Enumerated == displayData.mVisibility.GetUnit()) {
3348 visibility->mVisible = displayData.mVisibility.GetIntValue();
3350 else if (eCSSUnit_Inherit == displayData.mVisibility.GetUnit()) {
3351 inherited = PR_TRUE;
3352 visibility->mVisible = parentVisibility->mVisible;
3354 else if (eCSSUnit_Initial == displayData.mVisibility.GetUnit()) {
3355 visibility->mVisible = NS_STYLE_VISIBILITY_VISIBLE;
3358 // lang: string, inherit
3359 // this is not a real CSS property, it is a html attribute mapped to CSS struture
3360 if (eCSSUnit_String == displayData.mLang.GetUnit()) {
3361 if (!gLangService) {
3362 CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService);
3365 if (gLangService) {
3366 nsAutoString lang;
3367 displayData.mLang.GetStringValue(lang);
3368 visibility->mLangGroup = gLangService->LookupLanguage(lang);
3372 COMPUTE_END_INHERITED(Visibility, visibility)
3375 const void*
3376 nsRuleNode::ComputeColorData(void* aStartStruct,
3377 const nsRuleDataStruct& aData,
3378 nsStyleContext* aContext,
3379 nsRuleNode* aHighestNode,
3380 const RuleDetail aRuleDetail, PRBool aInherited)
3382 COMPUTE_START_INHERITED(Color, (mPresContext), color, parentColor,
3383 Color, colorData)
3385 // color: color, string, inherit
3386 // Special case for currentColor. According to CSS3, setting color to 'currentColor'
3387 // should behave as if it is inherited
3388 if (colorData.mColor.GetUnit() == eCSSUnit_EnumColor &&
3389 colorData.mColor.GetIntValue() == NS_COLOR_CURRENTCOLOR) {
3390 color->mColor = parentColor->mColor;
3391 inherited = PR_TRUE;
3393 else if (colorData.mColor.GetUnit() == eCSSUnit_Initial) {
3394 color->mColor = mPresContext->DefaultColor();
3396 else {
3397 SetColor(colorData.mColor, parentColor->mColor, mPresContext, aContext, color->mColor,
3398 inherited);
3401 COMPUTE_END_INHERITED(Color, color)
3404 const void*
3405 nsRuleNode::ComputeBackgroundData(void* aStartStruct,
3406 const nsRuleDataStruct& aData,
3407 nsStyleContext* aContext,
3408 nsRuleNode* aHighestNode,
3409 const RuleDetail aRuleDetail, PRBool aInherited)
3411 COMPUTE_START_RESET(Background, (mPresContext), bg, parentBG,
3412 Color, colorData)
3414 // save parentFlags in case bg == parentBG and we clobber them later
3415 PRUint8 parentFlags = parentBG->mBackgroundFlags;
3417 // background-color: color, string, enum (flags), inherit
3418 if (eCSSUnit_Inherit == colorData.mBackColor.GetUnit()) { // do inherit first, so SetColor doesn't do it
3419 bg->mBackgroundColor = parentBG->mBackgroundColor;
3420 bg->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT;
3421 bg->mBackgroundFlags |= (parentFlags & NS_STYLE_BG_COLOR_TRANSPARENT);
3422 inherited = PR_TRUE;
3424 else if (SetColor(colorData.mBackColor, parentBG->mBackgroundColor,
3425 mPresContext, aContext, bg->mBackgroundColor, inherited)) {
3426 bg->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT;
3428 else if (eCSSUnit_Enumerated == colorData.mBackColor.GetUnit() ||
3429 eCSSUnit_Initial == colorData.mBackColor.GetUnit()) {
3430 bg->mBackgroundFlags |= NS_STYLE_BG_COLOR_TRANSPARENT;
3433 // background-image: url (stored as image), none, inherit
3434 if (eCSSUnit_Image == colorData.mBackImage.GetUnit()) {
3435 bg->mBackgroundImage = colorData.mBackImage.GetImageValue();
3437 else if (eCSSUnit_None == colorData.mBackImage.GetUnit() ||
3438 eCSSUnit_Initial == colorData.mBackImage.GetUnit()) {
3439 bg->mBackgroundImage = nsnull;
3441 else if (eCSSUnit_Inherit == colorData.mBackImage.GetUnit()) {
3442 inherited = PR_TRUE;
3443 bg->mBackgroundImage = parentBG->mBackgroundImage;
3446 if (bg->mBackgroundImage) {
3447 bg->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE;
3448 } else {
3449 bg->mBackgroundFlags |= NS_STYLE_BG_IMAGE_NONE;
3452 // background-repeat: enum, inherit
3453 if (eCSSUnit_Enumerated == colorData.mBackRepeat.GetUnit()) {
3454 bg->mBackgroundRepeat = colorData.mBackRepeat.GetIntValue();
3456 else if (eCSSUnit_Inherit == colorData.mBackRepeat.GetUnit()) {
3457 inherited = PR_TRUE;
3458 bg->mBackgroundRepeat = parentBG->mBackgroundRepeat;
3460 else if (eCSSUnit_Initial == colorData.mBackRepeat.GetUnit()) {
3461 bg->mBackgroundRepeat = NS_STYLE_BG_REPEAT_XY;
3464 // background-attachment: enum, inherit
3465 if (eCSSUnit_Enumerated == colorData.mBackAttachment.GetUnit()) {
3466 bg->mBackgroundAttachment = colorData.mBackAttachment.GetIntValue();
3468 else if (eCSSUnit_Inherit == colorData.mBackAttachment.GetUnit()) {
3469 inherited = PR_TRUE;
3470 bg->mBackgroundAttachment = parentBG->mBackgroundAttachment;
3472 else if (eCSSUnit_Initial == colorData.mBackAttachment.GetUnit()) {
3473 bg->mBackgroundAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL;
3476 // background-clip: enum, inherit, initial
3477 if (eCSSUnit_Enumerated == colorData.mBackClip.GetUnit()) {
3478 bg->mBackgroundClip = colorData.mBackClip.GetIntValue();
3480 else if (eCSSUnit_Inherit == colorData.mBackClip.GetUnit()) {
3481 bg->mBackgroundClip = parentBG->mBackgroundClip;
3483 else if (eCSSUnit_Initial == colorData.mBackClip.GetUnit()) {
3484 bg->mBackgroundClip = NS_STYLE_BG_CLIP_BORDER;
3487 // background-inline-policy: enum, inherit, initial
3488 if (eCSSUnit_Enumerated == colorData.mBackInlinePolicy.GetUnit()) {
3489 bg->mBackgroundInlinePolicy = colorData.mBackInlinePolicy.GetIntValue();
3491 else if (eCSSUnit_Inherit == colorData.mBackInlinePolicy.GetUnit()) {
3492 bg->mBackgroundInlinePolicy = parentBG->mBackgroundInlinePolicy;
3494 else if (eCSSUnit_Initial == colorData.mBackInlinePolicy.GetUnit()) {
3495 bg->mBackgroundInlinePolicy = NS_STYLE_BG_INLINE_POLICY_CONTINUOUS;
3498 // background-origin: enum, inherit, initial
3499 if (eCSSUnit_Enumerated == colorData.mBackOrigin.GetUnit()) {
3500 bg->mBackgroundOrigin = colorData.mBackOrigin.GetIntValue();
3502 else if (eCSSUnit_Inherit == colorData.mBackOrigin.GetUnit()) {
3503 bg->mBackgroundOrigin = parentBG->mBackgroundOrigin;
3505 else if (eCSSUnit_Initial == colorData.mBackOrigin.GetUnit()) {
3506 bg->mBackgroundOrigin = NS_STYLE_BG_ORIGIN_PADDING;
3509 // background-position: enum, length, percent (flags), inherit
3510 if (eCSSUnit_Percent == colorData.mBackPosition.mXValue.GetUnit()) {
3511 bg->mBackgroundXPosition.mFloat = colorData.mBackPosition.mXValue.GetPercentValue();
3512 bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PERCENT;
3513 bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH;
3515 else if (colorData.mBackPosition.mXValue.IsLengthUnit()) {
3516 bg->mBackgroundXPosition.mCoord = CalcLength(colorData.mBackPosition.mXValue,
3517 aContext, mPresContext, inherited);
3518 bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_LENGTH;
3519 bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_PERCENT;
3521 else if (eCSSUnit_Enumerated == colorData.mBackPosition.mXValue.GetUnit()) {
3522 switch (colorData.mBackPosition.mXValue.GetIntValue()) {
3523 case NS_STYLE_BG_POSITION_LEFT:
3524 bg->mBackgroundXPosition.mFloat = 0.0f;
3525 break;
3526 case NS_STYLE_BG_POSITION_RIGHT:
3527 bg->mBackgroundXPosition.mFloat = 1.0f;
3528 break;
3529 default:
3530 NS_NOTREACHED("unexpected value");
3531 // fall through
3532 case NS_STYLE_BG_POSITION_CENTER:
3533 bg->mBackgroundXPosition.mFloat = 0.5f;
3534 break;
3536 bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PERCENT;
3537 bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH;
3539 else if (eCSSUnit_Inherit == colorData.mBackPosition.mXValue.GetUnit()) {
3540 inherited = PR_TRUE;
3541 bg->mBackgroundXPosition = parentBG->mBackgroundXPosition;
3542 bg->mBackgroundFlags &= ~(NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT);
3543 bg->mBackgroundFlags |= (parentFlags & (NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT));
3545 else if (eCSSUnit_Initial == colorData.mBackPosition.mXValue.GetUnit()) {
3546 bg->mBackgroundFlags &= ~(NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT);
3549 if (eCSSUnit_Percent == colorData.mBackPosition.mYValue.GetUnit()) {
3550 bg->mBackgroundYPosition.mFloat = colorData.mBackPosition.mYValue.GetPercentValue();
3551 bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PERCENT;
3552 bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
3554 else if (colorData.mBackPosition.mYValue.IsLengthUnit()) {
3555 bg->mBackgroundYPosition.mCoord = CalcLength(colorData.mBackPosition.mYValue,
3556 aContext, mPresContext, inherited);
3557 bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_LENGTH;
3558 bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_PERCENT;
3560 else if (eCSSUnit_Enumerated == colorData.mBackPosition.mYValue.GetUnit()) {
3561 switch (colorData.mBackPosition.mYValue.GetIntValue()) {
3562 case NS_STYLE_BG_POSITION_TOP:
3563 bg->mBackgroundYPosition.mFloat = 0.0f;
3564 break;
3565 case NS_STYLE_BG_POSITION_BOTTOM:
3566 bg->mBackgroundYPosition.mFloat = 1.0f;
3567 break;
3568 default:
3569 NS_NOTREACHED("unexpected value");
3570 // fall through
3571 case NS_STYLE_BG_POSITION_CENTER:
3572 bg->mBackgroundYPosition.mFloat = 0.5f;
3573 break;
3575 bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PERCENT;
3576 bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
3578 else if (eCSSUnit_Inherit == colorData.mBackPosition.mYValue.GetUnit()) {
3579 inherited = PR_TRUE;
3580 bg->mBackgroundYPosition = parentBG->mBackgroundYPosition;
3581 bg->mBackgroundFlags &= ~(NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT);
3582 bg->mBackgroundFlags |= (parentFlags & (NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT));
3584 else if (eCSSUnit_Initial == colorData.mBackPosition.mYValue.GetUnit()) {
3585 bg->mBackgroundFlags &= ~(NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT);
3588 COMPUTE_END_RESET(Background, bg)
3591 const void*
3592 nsRuleNode::ComputeMarginData(void* aStartStruct,
3593 const nsRuleDataStruct& aData,
3594 nsStyleContext* aContext,
3595 nsRuleNode* aHighestNode,
3596 const RuleDetail aRuleDetail, PRBool aInherited)
3598 COMPUTE_START_RESET(Margin, (), margin, parentMargin, Margin, marginData)
3600 // margin: length, percent, auto, inherit
3601 nsStyleCoord coord;
3602 nsCSSRect ourMargin(marginData.mMargin);
3603 AdjustLogicalBoxProp(aContext,
3604 marginData.mMarginLeftLTRSource,
3605 marginData.mMarginLeftRTLSource,
3606 marginData.mMarginStart, marginData.mMarginEnd,
3607 NS_SIDE_LEFT, ourMargin, inherited);
3608 AdjustLogicalBoxProp(aContext,
3609 marginData.mMarginRightLTRSource,
3610 marginData.mMarginRightRTLSource,
3611 marginData.mMarginEnd, marginData.mMarginStart,
3612 NS_SIDE_RIGHT, ourMargin, inherited);
3613 NS_FOR_CSS_SIDES(side) {
3614 nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
3615 if (SetCoord(ourMargin.*(nsCSSRect::sides[side]),
3616 coord, parentCoord, SETCOORD_LPAH | SETCOORD_INITIAL_ZERO,
3617 aContext, mPresContext, inherited)) {
3618 margin->mMargin.Set(side, coord);
3622 margin->RecalcData();
3623 COMPUTE_END_RESET(Margin, margin)
3626 const void*
3627 nsRuleNode::ComputeBorderData(void* aStartStruct,
3628 const nsRuleDataStruct& aData,
3629 nsStyleContext* aContext,
3630 nsRuleNode* aHighestNode,
3631 const RuleDetail aRuleDetail, PRBool aInherited)
3633 COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder,
3634 Margin, marginData)
3636 // border-width, border-*-width: length, enum, inherit
3637 nsStyleCoord coord;
3638 nsCSSRect ourBorderWidth(marginData.mBorderWidth);
3639 AdjustLogicalBoxProp(aContext,
3640 marginData.mBorderLeftWidthLTRSource,
3641 marginData.mBorderLeftWidthRTLSource,
3642 marginData.mBorderStartWidth,
3643 marginData.mBorderEndWidth,
3644 NS_SIDE_LEFT, ourBorderWidth, inherited);
3645 AdjustLogicalBoxProp(aContext,
3646 marginData.mBorderRightWidthLTRSource,
3647 marginData.mBorderRightWidthRTLSource,
3648 marginData.mBorderEndWidth,
3649 marginData.mBorderStartWidth,
3650 NS_SIDE_RIGHT, ourBorderWidth, inherited);
3651 { // scope for compilers with broken |for| loop scoping
3652 NS_FOR_CSS_SIDES(side) {
3653 const nsCSSValue &value = ourBorderWidth.*(nsCSSRect::sides[side]);
3654 NS_ASSERTION(eCSSUnit_Percent != value.GetUnit(),
3655 "Percentage borders not implemented yet "
3656 "If implementing, make sure to fix all consumers of "
3657 "nsStyleBorder, the IsPercentageAwareChild method, "
3658 "the nsAbsoluteContainingBlock::FrameDependsOnContainer "
3659 "method, the "
3660 "nsLineLayout::IsPercentageAwareReplacedElement method "
3661 "and probably some other places");
3662 if (eCSSUnit_Enumerated == value.GetUnit()) {
3663 NS_ASSERTION(value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
3664 value.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
3665 value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
3666 "Unexpected enum value");
3667 border->SetBorderWidth(side,
3668 (mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
3670 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
3671 else if (SetCoord(value, coord, nsStyleCoord(), SETCOORD_LENGTH,
3672 aContext, mPresContext, inherited)) {
3673 if (coord.GetUnit() == eStyleUnit_Coord) {
3674 border->SetBorderWidth(side, coord.GetCoordValue());
3676 #ifdef DEBUG
3677 else {
3678 NS_ASSERTION(coord.GetUnit() == eStyleUnit_Chars, "unexpected unit");
3679 NS_WARNING("Border set in chars; we don't handle that");
3681 #endif
3683 else if (eCSSUnit_Inherit == value.GetUnit()) {
3684 inherited = PR_TRUE;
3685 border->SetBorderWidth(side, parentBorder->GetBorderWidth(side));
3687 else if (eCSSUnit_Initial == value.GetUnit()) {
3688 border->SetBorderWidth(side,
3689 (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
3694 // border-style, border-*-style: enum, none, inherit
3695 nsCSSRect ourStyle(marginData.mBorderStyle);
3696 AdjustLogicalBoxProp(aContext,
3697 marginData.mBorderLeftStyleLTRSource,
3698 marginData.mBorderLeftStyleRTLSource,
3699 marginData.mBorderStartStyle, marginData.mBorderEndStyle,
3700 NS_SIDE_LEFT, ourStyle, inherited);
3701 AdjustLogicalBoxProp(aContext,
3702 marginData.mBorderRightStyleLTRSource,
3703 marginData.mBorderRightStyleRTLSource,
3704 marginData.mBorderEndStyle, marginData.mBorderStartStyle,
3705 NS_SIDE_RIGHT, ourStyle, inherited);
3706 { // scope for compilers with broken |for| loop scoping
3707 NS_FOR_CSS_SIDES(side) {
3708 const nsCSSValue &value = ourStyle.*(nsCSSRect::sides[side]);
3709 nsCSSUnit unit = value.GetUnit();
3710 if (eCSSUnit_Enumerated == unit) {
3711 border->SetBorderStyle(side, value.GetIntValue());
3713 else if (eCSSUnit_None == unit || eCSSUnit_Initial == unit) {
3714 border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
3716 else if (eCSSUnit_Inherit == unit) {
3717 inherited = PR_TRUE;
3718 border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
3723 // -moz-border-*-colors: color, string, enum
3724 nscolor borderColor;
3725 nscolor unused = NS_RGB(0,0,0);
3727 { // scope for compilers with broken |for| loop scoping
3728 NS_FOR_CSS_SIDES(side) {
3729 nsCSSValueList* list =
3730 marginData.mBorderColors.*(nsCSSValueListRect::sides[side]);
3731 // FIXME Bug 389404: Implement inherit and -moz-initial.
3732 if (list) {
3733 // Some composite border color information has been specified for this
3734 // border side.
3735 border->EnsureBorderColors();
3736 border->ClearBorderColors(side);
3737 while (list) {
3738 if (SetColor(list->mValue, unused, mPresContext, aContext, borderColor, inherited))
3739 border->AppendBorderColor(side, borderColor, PR_FALSE);
3740 else if (eCSSUnit_Enumerated == list->mValue.GetUnit() &&
3741 NS_STYLE_COLOR_TRANSPARENT == list->mValue.GetIntValue())
3742 border->AppendBorderColor(side, nsnull, PR_TRUE);
3743 list = list->mNext;
3749 // border-color, border-*-color: color, string, enum, inherit
3750 nsCSSRect ourBorderColor(marginData.mBorderColor);
3751 PRBool transparent;
3752 PRBool foreground;
3753 AdjustLogicalBoxProp(aContext,
3754 marginData.mBorderLeftColorLTRSource,
3755 marginData.mBorderLeftColorRTLSource,
3756 marginData.mBorderStartColor, marginData.mBorderEndColor,
3757 NS_SIDE_LEFT, ourBorderColor, inherited);
3758 AdjustLogicalBoxProp(aContext,
3759 marginData.mBorderRightColorLTRSource,
3760 marginData.mBorderRightColorRTLSource,
3761 marginData.mBorderEndColor, marginData.mBorderStartColor,
3762 NS_SIDE_RIGHT, ourBorderColor, inherited);
3763 { // scope for compilers with broken |for| loop scoping
3764 NS_FOR_CSS_SIDES(side) {
3765 const nsCSSValue &value = ourBorderColor.*(nsCSSRect::sides[side]);
3766 if (eCSSUnit_Inherit == value.GetUnit()) {
3767 if (parentContext) {
3768 inherited = PR_TRUE;
3769 parentBorder->GetBorderColor(side, borderColor,
3770 transparent, foreground);
3771 if (transparent)
3772 border->SetBorderTransparent(side);
3773 else if (foreground) {
3774 // We want to inherit the color from the parent, not use the
3775 // color on the element where this chunk of style data will be
3776 // used. We can ensure that the data for the parent are fully
3777 // computed (unlike for the element where this will be used, for
3778 // which the color could be specified on a more specific rule).
3779 border->SetBorderColor(side, parentContext->GetStyleColor()->mColor);
3780 } else
3781 border->SetBorderColor(side, borderColor);
3782 } else {
3783 // We're the root
3784 border->SetBorderToForeground(side);
3787 else if (SetColor(value, unused, mPresContext, aContext, borderColor, inherited)) {
3788 border->SetBorderColor(side, borderColor);
3790 else if (eCSSUnit_Enumerated == value.GetUnit()) {
3791 switch (value.GetIntValue()) {
3792 case NS_STYLE_COLOR_TRANSPARENT:
3793 border->SetBorderTransparent(side);
3794 break;
3795 case NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR:
3796 border->SetBorderToForeground(side);
3797 break;
3800 else if (eCSSUnit_Initial == value.GetUnit()) {
3801 border->SetBorderToForeground(side);
3806 // -moz-border-radius: length, percent, inherit
3807 { // scope for compilers with broken |for| loop scoping
3808 NS_FOR_CSS_SIDES(side) {
3809 nsStyleCoord parentCoord = parentBorder->mBorderRadius.Get(side);
3810 if (SetCoord(marginData.mBorderRadius.*(nsCSSRect::sides[side]), coord,
3811 parentCoord, SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
3812 aContext, mPresContext, inherited))
3813 border->mBorderRadius.Set(side, coord);
3817 // float-edge: enum, inherit
3818 if (eCSSUnit_Enumerated == marginData.mFloatEdge.GetUnit())
3819 border->mFloatEdge = marginData.mFloatEdge.GetIntValue();
3820 else if (eCSSUnit_Inherit == marginData.mFloatEdge.GetUnit()) {
3821 inherited = PR_TRUE;
3822 border->mFloatEdge = parentBorder->mFloatEdge;
3824 else if (eCSSUnit_Initial == marginData.mFloatEdge.GetUnit()) {
3825 border->mFloatEdge = NS_STYLE_FLOAT_EDGE_CONTENT;
3828 COMPUTE_END_RESET(Border, border)
3831 const void*
3832 nsRuleNode::ComputePaddingData(void* aStartStruct,
3833 const nsRuleDataStruct& aData,
3834 nsStyleContext* aContext,
3835 nsRuleNode* aHighestNode,
3836 const RuleDetail aRuleDetail, PRBool aInherited)
3838 COMPUTE_START_RESET(Padding, (), padding, parentPadding, Margin, marginData)
3840 // padding: length, percent, inherit
3841 nsStyleCoord coord;
3842 nsCSSRect ourPadding(marginData.mPadding);
3843 AdjustLogicalBoxProp(aContext,
3844 marginData.mPaddingLeftLTRSource,
3845 marginData.mPaddingLeftRTLSource,
3846 marginData.mPaddingStart, marginData.mPaddingEnd,
3847 NS_SIDE_LEFT, ourPadding, inherited);
3848 AdjustLogicalBoxProp(aContext,
3849 marginData.mPaddingRightLTRSource,
3850 marginData.mPaddingRightRTLSource,
3851 marginData.mPaddingEnd, marginData.mPaddingStart,
3852 NS_SIDE_RIGHT, ourPadding, inherited);
3853 NS_FOR_CSS_SIDES(side) {
3854 nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
3855 if (SetCoord(ourPadding.*(nsCSSRect::sides[side]),
3856 coord, parentCoord, SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
3857 aContext, mPresContext, inherited)) {
3858 padding->mPadding.Set(side, coord);
3862 padding->RecalcData();
3863 COMPUTE_END_RESET(Padding, padding)
3866 const void*
3867 nsRuleNode::ComputeOutlineData(void* aStartStruct,
3868 const nsRuleDataStruct& aData,
3869 nsStyleContext* aContext,
3870 nsRuleNode* aHighestNode,
3871 const RuleDetail aRuleDetail, PRBool aInherited)
3873 COMPUTE_START_RESET(Outline, (mPresContext), outline, parentOutline,
3874 Margin, marginData)
3876 // outline-width: length, enum, inherit
3877 if (eCSSUnit_Initial == marginData.mOutlineWidth.GetUnit()) {
3878 outline->mOutlineWidth =
3879 nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
3881 else {
3882 SetCoord(marginData.mOutlineWidth, outline->mOutlineWidth,
3883 parentOutline->mOutlineWidth, SETCOORD_LEH, aContext,
3884 mPresContext, inherited);
3887 // outline-offset: length, inherit
3888 SetCoord(marginData.mOutlineOffset, outline->mOutlineOffset, parentOutline->mOutlineOffset,
3889 SETCOORD_LH | SETCOORD_INITIAL_ZERO, aContext, mPresContext,
3890 inherited);
3893 // outline-color: color, string, enum, inherit
3894 nscolor outlineColor;
3895 nscolor unused = NS_RGB(0,0,0);
3896 if (eCSSUnit_Inherit == marginData.mOutlineColor.GetUnit()) {
3897 if (parentContext) {
3898 inherited = PR_TRUE;
3899 if (parentOutline->GetOutlineColor(outlineColor))
3900 outline->SetOutlineColor(outlineColor);
3901 else {
3902 #ifdef GFX_HAS_INVERT
3903 outline->SetOutlineInitialColor();
3904 #else
3905 // We want to inherit the color from the parent, not use the
3906 // color on the element where this chunk of style data will be
3907 // used. We can ensure that the data for the parent are fully
3908 // computed (unlike for the element where this will be used, for
3909 // which the color could be specified on a more specific rule).
3910 outline->SetOutlineColor(parentContext->GetStyleColor()->mColor);
3911 #endif
3913 } else {
3914 outline->SetOutlineInitialColor();
3917 else if (SetColor(marginData.mOutlineColor, unused, mPresContext, aContext, outlineColor, inherited))
3918 outline->SetOutlineColor(outlineColor);
3919 else if (eCSSUnit_Enumerated == marginData.mOutlineColor.GetUnit() ||
3920 eCSSUnit_Initial == marginData.mOutlineColor.GetUnit()) {
3921 outline->SetOutlineInitialColor();
3924 // -moz-outline-radius: length, percent, inherit
3925 nsStyleCoord coord;
3926 { // scope for compilers with broken |for| loop scoping
3927 NS_FOR_CSS_SIDES(side) {
3928 nsStyleCoord parentCoord = parentOutline->mOutlineRadius.Get(side);
3929 if (SetCoord(marginData.mOutlineRadius.*(nsCSSRect::sides[side]), coord,
3930 parentCoord, SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
3931 aContext, mPresContext, inherited))
3932 outline->mOutlineRadius.Set(side, coord);
3936 // outline-style: auto, enum, none, inherit
3937 if (eCSSUnit_Enumerated == marginData.mOutlineStyle.GetUnit())
3938 outline->SetOutlineStyle(marginData.mOutlineStyle.GetIntValue());
3939 else if (eCSSUnit_None == marginData.mOutlineStyle.GetUnit() ||
3940 eCSSUnit_Initial == marginData.mOutlineStyle.GetUnit())
3941 outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_NONE);
3942 else if (eCSSUnit_Auto == marginData.mOutlineStyle.GetUnit()) {
3943 outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_AUTO);
3944 } else if (eCSSUnit_Inherit == marginData.mOutlineStyle.GetUnit()) {
3945 inherited = PR_TRUE;
3946 outline->SetOutlineStyle(parentOutline->GetOutlineStyle());
3949 outline->RecalcData(mPresContext);
3950 COMPUTE_END_RESET(Outline, outline)
3953 const void*
3954 nsRuleNode::ComputeListData(void* aStartStruct,
3955 const nsRuleDataStruct& aData,
3956 nsStyleContext* aContext,
3957 nsRuleNode* aHighestNode,
3958 const RuleDetail aRuleDetail, PRBool aInherited)
3960 COMPUTE_START_INHERITED(List, (), list, parentList, List, listData)
3962 // list-style-type: enum, none, inherit
3963 if (eCSSUnit_Enumerated == listData.mType.GetUnit()) {
3964 list->mListStyleType = listData.mType.GetIntValue();
3966 else if (eCSSUnit_None == listData.mType.GetUnit()) {
3967 list->mListStyleType = NS_STYLE_LIST_STYLE_NONE;
3969 else if (eCSSUnit_Inherit == listData.mType.GetUnit()) {
3970 inherited = PR_TRUE;
3971 list->mListStyleType = parentList->mListStyleType;
3973 else if (eCSSUnit_Initial == listData.mType.GetUnit()) {
3974 list->mListStyleType = NS_STYLE_LIST_STYLE_DISC;
3977 // list-style-image: url, none, inherit
3978 if (eCSSUnit_Image == listData.mImage.GetUnit()) {
3979 list->mListStyleImage = listData.mImage.GetImageValue();
3981 else if (eCSSUnit_None == listData.mImage.GetUnit() ||
3982 eCSSUnit_Initial == listData.mImage.GetUnit()) {
3983 list->mListStyleImage = nsnull;
3985 else if (eCSSUnit_Inherit == listData.mImage.GetUnit()) {
3986 inherited = PR_TRUE;
3987 list->mListStyleImage = parentList->mListStyleImage;
3990 // list-style-position: enum, inherit
3991 if (eCSSUnit_Enumerated == listData.mPosition.GetUnit()) {
3992 list->mListStylePosition = listData.mPosition.GetIntValue();
3994 else if (eCSSUnit_Inherit == listData.mPosition.GetUnit()) {
3995 inherited = PR_TRUE;
3996 list->mListStylePosition = parentList->mListStylePosition;
3998 else if (eCSSUnit_Initial == listData.mPosition.GetUnit()) {
3999 list->mListStylePosition = NS_STYLE_LIST_STYLE_POSITION_OUTSIDE;
4002 // image region property: length, auto, inherit
4003 if (eCSSUnit_Inherit == listData.mImageRegion.mTop.GetUnit()) { // if one is inherit, they all are
4004 inherited = PR_TRUE;
4005 list->mImageRegion = parentList->mImageRegion;
4007 // if one is -moz-initial, they all are
4008 else if (eCSSUnit_Initial == listData.mImageRegion.mTop.GetUnit()) {
4009 list->mImageRegion.Empty();
4011 else {
4012 if (eCSSUnit_Auto == listData.mImageRegion.mTop.GetUnit())
4013 list->mImageRegion.y = 0;
4014 else if (listData.mImageRegion.mTop.IsLengthUnit())
4015 list->mImageRegion.y = CalcLength(listData.mImageRegion.mTop, aContext, mPresContext, inherited);
4017 if (eCSSUnit_Auto == listData.mImageRegion.mBottom.GetUnit())
4018 list->mImageRegion.height = 0;
4019 else if (listData.mImageRegion.mBottom.IsLengthUnit())
4020 list->mImageRegion.height = CalcLength(listData.mImageRegion.mBottom, aContext,
4021 mPresContext, inherited) - list->mImageRegion.y;
4023 if (eCSSUnit_Auto == listData.mImageRegion.mLeft.GetUnit())
4024 list->mImageRegion.x = 0;
4025 else if (listData.mImageRegion.mLeft.IsLengthUnit())
4026 list->mImageRegion.x = CalcLength(listData.mImageRegion.mLeft, aContext, mPresContext, inherited);
4028 if (eCSSUnit_Auto == listData.mImageRegion.mRight.GetUnit())
4029 list->mImageRegion.width = 0;
4030 else if (listData.mImageRegion.mRight.IsLengthUnit())
4031 list->mImageRegion.width = CalcLength(listData.mImageRegion.mRight, aContext, mPresContext, inherited) -
4032 list->mImageRegion.x;
4035 COMPUTE_END_INHERITED(List, list)
4038 const void*
4039 nsRuleNode::ComputePositionData(void* aStartStruct,
4040 const nsRuleDataStruct& aData,
4041 nsStyleContext* aContext,
4042 nsRuleNode* aHighestNode,
4043 const RuleDetail aRuleDetail, PRBool aInherited)
4045 COMPUTE_START_RESET(Position, (), pos, parentPos, Position, posData)
4047 // box offsets: length, percent, auto, inherit
4048 nsStyleCoord coord;
4049 NS_FOR_CSS_SIDES(side) {
4050 nsStyleCoord parentCoord = parentPos->mOffset.Get(side);
4051 if (SetCoord(posData.mOffset.*(nsCSSRect::sides[side]),
4052 coord, parentCoord, SETCOORD_LPAH | SETCOORD_INITIAL_AUTO,
4053 aContext, mPresContext, inherited)) {
4054 pos->mOffset.Set(side, coord);
4058 SetCoord(posData.mWidth, pos->mWidth, parentPos->mWidth,
4059 SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO, aContext,
4060 mPresContext, inherited);
4061 SetCoord(posData.mMinWidth, pos->mMinWidth, parentPos->mMinWidth,
4062 SETCOORD_LPEH | SETCOORD_INITIAL_ZERO, aContext,
4063 mPresContext, inherited);
4064 SetCoord(posData.mMaxWidth, pos->mMaxWidth, parentPos->mMaxWidth,
4065 SETCOORD_LPOEH | SETCOORD_INITIAL_NONE, aContext,
4066 mPresContext, inherited);
4068 SetCoord(posData.mHeight, pos->mHeight, parentPos->mHeight,
4069 SETCOORD_LPAH | SETCOORD_INITIAL_AUTO, aContext,
4070 mPresContext, inherited);
4071 SetCoord(posData.mMinHeight, pos->mMinHeight, parentPos->mMinHeight,
4072 SETCOORD_LPH | SETCOORD_INITIAL_ZERO, aContext,
4073 mPresContext, inherited);
4074 SetCoord(posData.mMaxHeight, pos->mMaxHeight, parentPos->mMaxHeight,
4075 SETCOORD_LPOH | SETCOORD_INITIAL_NONE, aContext,
4076 mPresContext, inherited);
4078 // box-sizing: enum, inherit
4079 if (eCSSUnit_Enumerated == posData.mBoxSizing.GetUnit()) {
4080 pos->mBoxSizing = posData.mBoxSizing.GetIntValue();
4082 else if (eCSSUnit_Inherit == posData.mBoxSizing.GetUnit()) {
4083 inherited = PR_TRUE;
4084 pos->mBoxSizing = parentPos->mBoxSizing;
4086 else if (eCSSUnit_Initial == posData.mBoxSizing.GetUnit()) {
4087 pos->mBoxSizing = NS_STYLE_BOX_SIZING_CONTENT;
4090 // z-index
4091 if (! SetCoord(posData.mZIndex, pos->mZIndex, parentPos->mZIndex,
4092 SETCOORD_IA | SETCOORD_INITIAL_AUTO, aContext,
4093 nsnull, inherited)) {
4094 if (eCSSUnit_Inherit == posData.mZIndex.GetUnit()) {
4095 // handle inherit, because it's ok to inherit 'auto' here
4096 inherited = PR_TRUE;
4097 pos->mZIndex = parentPos->mZIndex;
4101 COMPUTE_END_RESET(Position, pos)
4104 const void*
4105 nsRuleNode::ComputeTableData(void* aStartStruct,
4106 const nsRuleDataStruct& aData,
4107 nsStyleContext* aContext,
4108 nsRuleNode* aHighestNode,
4109 const RuleDetail aRuleDetail, PRBool aInherited)
4111 COMPUTE_START_RESET(Table, (), table, parentTable, Table, tableData)
4113 // table-layout: auto, enum, inherit
4114 if (eCSSUnit_Enumerated == tableData.mLayout.GetUnit())
4115 table->mLayoutStrategy = tableData.mLayout.GetIntValue();
4116 else if (eCSSUnit_Auto == tableData.mLayout.GetUnit() ||
4117 eCSSUnit_Initial == tableData.mLayout.GetUnit())
4118 table->mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO;
4119 else if (eCSSUnit_Inherit == tableData.mLayout.GetUnit()) {
4120 inherited = PR_TRUE;
4121 table->mLayoutStrategy = parentTable->mLayoutStrategy;
4124 // rules: enum (not a real CSS prop)
4125 if (eCSSUnit_Enumerated == tableData.mRules.GetUnit())
4126 table->mRules = tableData.mRules.GetIntValue();
4128 // frame: enum (not a real CSS prop)
4129 if (eCSSUnit_Enumerated == tableData.mFrame.GetUnit())
4130 table->mFrame = tableData.mFrame.GetIntValue();
4132 // cols: enum, int (not a real CSS prop)
4133 if (eCSSUnit_Enumerated == tableData.mCols.GetUnit() ||
4134 eCSSUnit_Integer == tableData.mCols.GetUnit())
4135 table->mCols = tableData.mCols.GetIntValue();
4137 // span: pixels (not a real CSS prop)
4138 if (eCSSUnit_Enumerated == tableData.mSpan.GetUnit() ||
4139 eCSSUnit_Integer == tableData.mSpan.GetUnit())
4140 table->mSpan = tableData.mSpan.GetIntValue();
4142 COMPUTE_END_RESET(Table, table)
4145 const void*
4146 nsRuleNode::ComputeTableBorderData(void* aStartStruct,
4147 const nsRuleDataStruct& aData,
4148 nsStyleContext* aContext,
4149 nsRuleNode* aHighestNode,
4150 const RuleDetail aRuleDetail, PRBool aInherited)
4152 COMPUTE_START_INHERITED(TableBorder, (mPresContext), table, parentTable,
4153 Table, tableData)
4155 // border-collapse: enum, inherit
4156 if (eCSSUnit_Enumerated == tableData.mBorderCollapse.GetUnit()) {
4157 table->mBorderCollapse = tableData.mBorderCollapse.GetIntValue();
4159 else if (eCSSUnit_Inherit == tableData.mBorderCollapse.GetUnit()) {
4160 inherited = PR_TRUE;
4161 table->mBorderCollapse = parentTable->mBorderCollapse;
4163 else if (eCSSUnit_Initial == tableData.mBorderCollapse.GetUnit()) {
4164 table->mBorderCollapse = NS_STYLE_BORDER_SEPARATE;
4167 // border-spacing-x: length, inherit
4168 SetCoord(tableData.mBorderSpacing.mXValue, table->mBorderSpacingX,
4169 parentTable->mBorderSpacingX, SETCOORD_LH | SETCOORD_INITIAL_ZERO,
4170 aContext, mPresContext, inherited);
4171 // border-spacing-y: length, inherit
4172 SetCoord(tableData.mBorderSpacing.mYValue, table->mBorderSpacingY,
4173 parentTable->mBorderSpacingY, SETCOORD_LH | SETCOORD_INITIAL_ZERO,
4174 aContext, mPresContext, inherited);
4176 // caption-side: enum, inherit
4177 if (eCSSUnit_Enumerated == tableData.mCaptionSide.GetUnit()) {
4178 table->mCaptionSide = tableData.mCaptionSide.GetIntValue();
4180 else if (eCSSUnit_Inherit == tableData.mCaptionSide.GetUnit()) {
4181 inherited = PR_TRUE;
4182 table->mCaptionSide = parentTable->mCaptionSide;
4184 else if (eCSSUnit_Initial == tableData.mCaptionSide.GetUnit()) {
4185 table->mCaptionSide = NS_STYLE_CAPTION_SIDE_TOP;
4188 // empty-cells: enum, inherit
4189 if (eCSSUnit_Enumerated == tableData.mEmptyCells.GetUnit()) {
4190 table->mEmptyCells = tableData.mEmptyCells.GetIntValue();
4192 else if (eCSSUnit_Inherit == tableData.mEmptyCells.GetUnit()) {
4193 inherited = PR_TRUE;
4194 table->mEmptyCells = parentTable->mEmptyCells;
4196 else if (eCSSUnit_Initial == tableData.mEmptyCells.GetUnit()) {
4197 table->mEmptyCells =
4198 (mPresContext->CompatibilityMode() == eCompatibility_NavQuirks)
4199 ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
4200 : NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
4204 COMPUTE_END_INHERITED(TableBorder, table)
4207 const void*
4208 nsRuleNode::ComputeContentData(void* aStartStruct,
4209 const nsRuleDataStruct& aData,
4210 nsStyleContext* aContext,
4211 nsRuleNode* aHighestNode,
4212 const RuleDetail aRuleDetail, PRBool aInherited)
4214 COMPUTE_START_RESET(Content, (), content, parentContent,
4215 Content, contentData)
4217 // content: [string, url, counter, attr, enum]+, normal, none, inherit
4218 PRUint32 count;
4219 nsAutoString buffer;
4220 nsCSSValueList* contentValue = contentData.mContent;
4221 if (contentValue) {
4222 if (eCSSUnit_Normal == contentValue->mValue.GetUnit() ||
4223 eCSSUnit_None == contentValue->mValue.GetUnit() ||
4224 eCSSUnit_Initial == contentValue->mValue.GetUnit()) {
4225 // "normal", "none", and "initial" all mean no content
4226 content->AllocateContents(0);
4228 else if (eCSSUnit_Inherit == contentValue->mValue.GetUnit()) {
4229 inherited = PR_TRUE;
4230 count = parentContent->ContentCount();
4231 if (NS_SUCCEEDED(content->AllocateContents(count))) {
4232 while (0 < count--) {
4233 content->ContentAt(count) = parentContent->ContentAt(count);
4237 else {
4238 count = 0;
4239 while (contentValue) {
4240 count++;
4241 contentValue = contentValue->mNext;
4243 if (NS_SUCCEEDED(content->AllocateContents(count))) {
4244 const nsAutoString nullStr;
4245 count = 0;
4246 contentValue = contentData.mContent;
4247 while (contentValue) {
4248 const nsCSSValue& value = contentValue->mValue;
4249 nsCSSUnit unit = value.GetUnit();
4250 nsStyleContentType type;
4251 nsStyleContentData &data = content->ContentAt(count++);
4252 switch (unit) {
4253 case eCSSUnit_String: type = eStyleContentType_String; break;
4254 case eCSSUnit_Image: type = eStyleContentType_Image; break;
4255 case eCSSUnit_Attr: type = eStyleContentType_Attr; break;
4256 case eCSSUnit_Counter: type = eStyleContentType_Counter; break;
4257 case eCSSUnit_Counters: type = eStyleContentType_Counters; break;
4258 case eCSSUnit_Enumerated:
4259 switch (value.GetIntValue()) {
4260 case NS_STYLE_CONTENT_OPEN_QUOTE:
4261 type = eStyleContentType_OpenQuote; break;
4262 case NS_STYLE_CONTENT_CLOSE_QUOTE:
4263 type = eStyleContentType_CloseQuote; break;
4264 case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
4265 type = eStyleContentType_NoOpenQuote; break;
4266 case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
4267 type = eStyleContentType_NoCloseQuote; break;
4268 case NS_STYLE_CONTENT_ALT_CONTENT:
4269 type = eStyleContentType_AltContent; break;
4270 default:
4271 NS_ERROR("bad content value");
4273 break;
4274 default:
4275 NS_ERROR("bad content type");
4277 data.mType = type;
4278 if (type == eStyleContentType_Image) {
4279 data.mContent.mImage = value.GetImageValue();
4280 NS_IF_ADDREF(data.mContent.mImage);
4282 else if (type <= eStyleContentType_Attr) {
4283 value.GetStringValue(buffer);
4284 Unquote(buffer);
4285 data.mContent.mString = NS_strdup(buffer.get());
4287 else if (type <= eStyleContentType_Counters) {
4288 data.mContent.mCounters = value.GetArrayValue();
4289 data.mContent.mCounters->AddRef();
4291 else {
4292 data.mContent.mString = nsnull;
4294 contentValue = contentValue->mNext;
4300 // counter-increment: [string [int]]+, none, inherit
4301 nsCSSCounterData* ourIncrement = contentData.mCounterIncrement;
4302 if (ourIncrement) {
4303 if (eCSSUnit_None == ourIncrement->mCounter.GetUnit() ||
4304 eCSSUnit_Initial == ourIncrement->mCounter.GetUnit()) {
4305 content->AllocateCounterIncrements(0);
4307 else if (eCSSUnit_Inherit == ourIncrement->mCounter.GetUnit()) {
4308 inherited = PR_TRUE;
4309 count = parentContent->CounterIncrementCount();
4310 if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
4311 while (0 < count--) {
4312 const nsStyleCounterData *data =
4313 parentContent->GetCounterIncrementAt(count);
4314 content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
4318 else if (eCSSUnit_String == ourIncrement->mCounter.GetUnit()) {
4319 count = 0;
4320 while (ourIncrement) {
4321 count++;
4322 ourIncrement = ourIncrement->mNext;
4324 if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
4325 count = 0;
4326 ourIncrement = contentData.mCounterIncrement;
4327 while (ourIncrement) {
4328 PRInt32 increment;
4329 if (eCSSUnit_Integer == ourIncrement->mValue.GetUnit()) {
4330 increment = ourIncrement->mValue.GetIntValue();
4332 else {
4333 increment = 1;
4335 ourIncrement->mCounter.GetStringValue(buffer);
4336 content->SetCounterIncrementAt(count++, buffer, increment);
4337 ourIncrement = ourIncrement->mNext;
4343 // counter-reset: [string [int]]+, none, inherit
4344 nsCSSCounterData* ourReset = contentData.mCounterReset;
4345 if (ourReset) {
4346 if (eCSSUnit_None == ourReset->mCounter.GetUnit() ||
4347 eCSSUnit_Initial == ourReset->mCounter.GetUnit()) {
4348 content->AllocateCounterResets(0);
4350 else if (eCSSUnit_Inherit == ourReset->mCounter.GetUnit()) {
4351 inherited = PR_TRUE;
4352 count = parentContent->CounterResetCount();
4353 if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
4354 while (0 < count--) {
4355 const nsStyleCounterData *data =
4356 parentContent->GetCounterResetAt(count);
4357 content->SetCounterResetAt(count, data->mCounter, data->mValue);
4361 else if (eCSSUnit_String == ourReset->mCounter.GetUnit()) {
4362 count = 0;
4363 while (ourReset) {
4364 count++;
4365 ourReset = ourReset->mNext;
4367 if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
4368 count = 0;
4369 ourReset = contentData.mCounterReset;
4370 while (ourReset) {
4371 PRInt32 reset;
4372 if (eCSSUnit_Integer == ourReset->mValue.GetUnit()) {
4373 reset = ourReset->mValue.GetIntValue();
4375 else {
4376 reset = 0;
4378 ourReset->mCounter.GetStringValue(buffer);
4379 content->SetCounterResetAt(count++, buffer, reset);
4380 ourReset = ourReset->mNext;
4386 // marker-offset: length, auto, inherit
4387 SetCoord(contentData.mMarkerOffset, content->mMarkerOffset, parentContent->mMarkerOffset,
4388 SETCOORD_LH | SETCOORD_AUTO | SETCOORD_INITIAL_AUTO, aContext,
4389 mPresContext, inherited);
4391 COMPUTE_END_RESET(Content, content)
4394 const void*
4395 nsRuleNode::ComputeQuotesData(void* aStartStruct,
4396 const nsRuleDataStruct& aData,
4397 nsStyleContext* aContext,
4398 nsRuleNode* aHighestNode,
4399 const RuleDetail aRuleDetail, PRBool aInherited)
4401 COMPUTE_START_INHERITED(Quotes, (), quotes, parentQuotes,
4402 Content, contentData)
4404 // quotes: [string string]+, none, inherit
4405 PRUint32 count;
4406 nsAutoString buffer;
4407 nsCSSQuotes* ourQuotes = contentData.mQuotes;
4408 if (ourQuotes) {
4409 nsAutoString closeBuffer;
4410 // FIXME Bug 389406: Implement eCSSUnit_Initial (correctly, unlike
4411 // style structs), and remove the "initial" value from ua.css.
4412 if (eCSSUnit_Inherit == ourQuotes->mOpen.GetUnit()) {
4413 inherited = PR_TRUE;
4414 count = parentQuotes->QuotesCount();
4415 if (NS_SUCCEEDED(quotes->AllocateQuotes(count))) {
4416 while (0 < count--) {
4417 parentQuotes->GetQuotesAt(count, buffer, closeBuffer);
4418 quotes->SetQuotesAt(count, buffer, closeBuffer);
4422 else if (eCSSUnit_None == ourQuotes->mOpen.GetUnit()) {
4423 quotes->AllocateQuotes(0);
4425 else if (eCSSUnit_String == ourQuotes->mOpen.GetUnit()) {
4426 count = 0;
4427 while (ourQuotes) {
4428 count++;
4429 ourQuotes = ourQuotes->mNext;
4431 if (NS_SUCCEEDED(quotes->AllocateQuotes(count))) {
4432 count = 0;
4433 ourQuotes = contentData.mQuotes;
4434 while (ourQuotes) {
4435 ourQuotes->mOpen.GetStringValue(buffer);
4436 ourQuotes->mClose.GetStringValue(closeBuffer);
4437 Unquote(buffer);
4438 Unquote(closeBuffer);
4439 quotes->SetQuotesAt(count++, buffer, closeBuffer);
4440 ourQuotes = ourQuotes->mNext;
4446 COMPUTE_END_INHERITED(Quotes, quotes)
4449 const void*
4450 nsRuleNode::ComputeXULData(void* aStartStruct,
4451 const nsRuleDataStruct& aData,
4452 nsStyleContext* aContext,
4453 nsRuleNode* aHighestNode,
4454 const RuleDetail aRuleDetail, PRBool aInherited)
4456 COMPUTE_START_RESET(XUL, (), xul, parentXUL, XUL, xulData)
4458 // box-align: enum, inherit
4459 if (eCSSUnit_Enumerated == xulData.mBoxAlign.GetUnit()) {
4460 xul->mBoxAlign = xulData.mBoxAlign.GetIntValue();
4462 else if (eCSSUnit_Inherit == xulData.mBoxAlign.GetUnit()) {
4463 inherited = PR_TRUE;
4464 xul->mBoxAlign = parentXUL->mBoxAlign;
4466 else if (eCSSUnit_Initial == xulData.mBoxAlign.GetUnit()) {
4467 xul->mBoxAlign = NS_STYLE_BOX_ALIGN_STRETCH;
4470 // box-direction: enum, inherit
4471 if (eCSSUnit_Enumerated == xulData.mBoxDirection.GetUnit()) {
4472 xul->mBoxDirection = xulData.mBoxDirection.GetIntValue();
4474 else if (eCSSUnit_Inherit == xulData.mBoxDirection.GetUnit()) {
4475 inherited = PR_TRUE;
4476 xul->mBoxDirection = parentXUL->mBoxDirection;
4478 else if (eCSSUnit_Initial == xulData.mBoxDirection.GetUnit()) {
4479 xul->mBoxDirection = NS_STYLE_BOX_DIRECTION_NORMAL;
4482 // box-flex: factor, inherit
4483 if (eCSSUnit_Number == xulData.mBoxFlex.GetUnit()) {
4484 xul->mBoxFlex = xulData.mBoxFlex.GetFloatValue();
4486 else if (eCSSUnit_Inherit == xulData.mBoxFlex.GetUnit()) {
4487 inherited = PR_TRUE;
4488 xul->mBoxFlex = parentXUL->mBoxFlex;
4490 else if (eCSSUnit_Initial == xulData.mBoxFlex.GetUnit()) {
4491 xul->mBoxFlex = 0.0f;
4494 // box-orient: enum, inherit
4495 if (eCSSUnit_Enumerated == xulData.mBoxOrient.GetUnit()) {
4496 xul->mBoxOrient = xulData.mBoxOrient.GetIntValue();
4498 else if (eCSSUnit_Inherit == xulData.mBoxOrient.GetUnit()) {
4499 inherited = PR_TRUE;
4500 xul->mBoxOrient = parentXUL->mBoxOrient;
4502 else if (eCSSUnit_Initial == xulData.mBoxOrient.GetUnit()) {
4503 xul->mBoxOrient = NS_STYLE_BOX_ORIENT_HORIZONTAL;
4506 // box-pack: enum, inherit
4507 if (eCSSUnit_Enumerated == xulData.mBoxPack.GetUnit()) {
4508 xul->mBoxPack = xulData.mBoxPack.GetIntValue();
4510 else if (eCSSUnit_Inherit == xulData.mBoxPack.GetUnit()) {
4511 inherited = PR_TRUE;
4512 xul->mBoxPack = parentXUL->mBoxPack;
4514 else if (eCSSUnit_Initial == xulData.mBoxPack.GetUnit()) {
4515 xul->mBoxPack = NS_STYLE_BOX_PACK_START;
4518 // box-ordinal-group: integer
4519 if (eCSSUnit_Integer == xulData.mBoxOrdinal.GetUnit()) {
4520 xul->mBoxOrdinal = xulData.mBoxOrdinal.GetIntValue();
4521 } else if (eCSSUnit_Inherit == xulData.mBoxOrdinal.GetUnit()) {
4522 inherited = PR_TRUE;
4523 xul->mBoxOrdinal = parentXUL->mBoxOrdinal;
4524 } else if (eCSSUnit_Initial == xulData.mBoxOrdinal.GetUnit()) {
4525 xul->mBoxOrdinal = 1;
4528 COMPUTE_END_RESET(XUL, xul)
4531 const void*
4532 nsRuleNode::ComputeColumnData(void* aStartStruct,
4533 const nsRuleDataStruct& aData,
4534 nsStyleContext* aContext,
4535 nsRuleNode* aHighestNode,
4536 const RuleDetail aRuleDetail, PRBool aInherited)
4538 COMPUTE_START_RESET(Column, (), column, parent, Column, columnData)
4540 // column-width: length, auto, inherit
4541 SetCoord(columnData.mColumnWidth,
4542 column->mColumnWidth, parent->mColumnWidth,
4543 SETCOORD_LAH | SETCOORD_INITIAL_AUTO,
4544 aContext, mPresContext, inherited);
4546 // column-gap: length, percentage, inherit, normal
4547 SetCoord(columnData.mColumnGap,
4548 column->mColumnGap, parent->mColumnGap,
4549 SETCOORD_LPH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL,
4550 aContext, mPresContext, inherited);
4552 // column-count: auto, integer, inherit
4553 if (eCSSUnit_Auto == columnData.mColumnCount.GetUnit() ||
4554 eCSSUnit_Initial == columnData.mColumnCount.GetUnit()) {
4555 column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
4556 } else if (eCSSUnit_Integer == columnData.mColumnCount.GetUnit()) {
4557 column->mColumnCount = columnData.mColumnCount.GetIntValue();
4558 // Max 1000 columns - wallpaper for bug 345583.
4559 column->mColumnCount = PR_MIN(column->mColumnCount, 1000);
4560 } else if (eCSSUnit_Inherit == columnData.mColumnCount.GetUnit()) {
4561 inherited = PR_TRUE;
4562 column->mColumnCount = parent->mColumnCount;
4565 COMPUTE_END_RESET(Column, column)
4568 #ifdef MOZ_SVG
4569 static void
4570 SetSVGPaint(const nsCSSValuePair& aValue, const nsStyleSVGPaint& parentPaint,
4571 nsPresContext* aPresContext, nsStyleContext *aContext,
4572 nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
4573 PRBool& aInherited)
4575 nscolor color;
4577 if (aValue.mXValue.GetUnit() == eCSSUnit_Inherit) {
4578 aResult = parentPaint;
4579 aInherited = PR_TRUE;
4580 } else if (aValue.mXValue.GetUnit() == eCSSUnit_None) {
4581 aResult.SetType(eStyleSVGPaintType_None);
4582 } else if (aValue.mXValue.GetUnit() == eCSSUnit_Initial) {
4583 aResult.SetType(aInitialPaintType);
4584 aResult.mPaint.mColor = NS_RGB(0, 0, 0);
4585 aResult.mFallbackColor = NS_RGB(0, 0, 0);
4586 } else if (aValue.mXValue.GetUnit() == eCSSUnit_URL) {
4587 aResult.SetType(eStyleSVGPaintType_Server);
4588 aResult.mPaint.mPaintServer = aValue.mXValue.GetURLValue();
4589 NS_IF_ADDREF(aResult.mPaint.mPaintServer);
4590 if (aValue.mYValue.GetUnit() == eCSSUnit_None) {
4591 aResult.mFallbackColor = NS_RGBA(0, 0, 0, 0);
4592 } else {
4593 NS_ASSERTION(aValue.mYValue.GetUnit() != eCSSUnit_Inherit, "cannot inherit fallback colour");
4594 SetColor(aValue.mYValue, NS_RGB(0, 0, 0), aPresContext, aContext, aResult.mFallbackColor, aInherited);
4596 } else if (SetColor(aValue.mXValue, parentPaint.mPaint.mColor, aPresContext, aContext, color, aInherited)) {
4597 aResult.SetType(eStyleSVGPaintType_Color);
4598 aResult.mPaint.mColor = color;
4602 static void
4603 SetSVGOpacity(const nsCSSValue& aValue, float parentOpacity, float& opacity, PRBool& aInherited)
4605 if (aValue.GetUnit() == eCSSUnit_Inherit) {
4606 opacity = parentOpacity;
4607 aInherited = PR_TRUE;
4609 else if (aValue.GetUnit() == eCSSUnit_Number) {
4610 opacity = aValue.GetFloatValue();
4611 opacity = PR_MAX(opacity, 0.0f);
4612 opacity = PR_MIN(opacity, 1.0f);
4614 else if (aValue.GetUnit() == eCSSUnit_Initial) {
4615 opacity = 1.0f;
4619 const void*
4620 nsRuleNode::ComputeSVGData(void* aStartStruct,
4621 const nsRuleDataStruct& aData,
4622 nsStyleContext* aContext,
4623 nsRuleNode* aHighestNode,
4624 const RuleDetail aRuleDetail, PRBool aInherited)
4626 COMPUTE_START_INHERITED(SVG, (), svg, parentSVG, SVG, SVGData)
4628 // clip-rule: enum, inherit
4629 if (eCSSUnit_Enumerated == SVGData.mClipRule.GetUnit()) {
4630 svg->mClipRule = SVGData.mClipRule.GetIntValue();
4632 else if (eCSSUnit_Inherit == SVGData.mClipRule.GetUnit()) {
4633 inherited = PR_TRUE;
4634 svg->mClipRule = parentSVG->mClipRule;
4636 else if (eCSSUnit_Initial == SVGData.mClipRule.GetUnit()) {
4637 svg->mClipRule = NS_STYLE_FILL_RULE_NONZERO;
4640 // color-interpolation: auto, sRGB, linearRGB, inherit
4641 if (eCSSUnit_Enumerated == SVGData.mColorInterpolation.GetUnit()) {
4642 svg->mColorInterpolation = SVGData.mColorInterpolation.GetIntValue();
4644 else if (eCSSUnit_Auto == SVGData.mColorInterpolation.GetUnit()) {
4645 svg->mColorInterpolation = NS_STYLE_COLOR_INTERPOLATION_AUTO;
4647 else if (eCSSUnit_Inherit == SVGData.mColorInterpolation.GetUnit()) {
4648 inherited = PR_TRUE;
4649 svg->mColorInterpolation = parentSVG->mColorInterpolation;
4651 else if (eCSSUnit_Initial == SVGData.mColorInterpolation.GetUnit()) {
4652 svg->mColorInterpolation = NS_STYLE_COLOR_INTERPOLATION_SRGB;
4655 // color-interpolation-filters: auto, sRGB, linearRGB, inherit
4656 if (eCSSUnit_Enumerated == SVGData.mColorInterpolationFilters.GetUnit()) {
4657 svg->mColorInterpolationFilters = SVGData.mColorInterpolationFilters.GetIntValue();
4659 else if (eCSSUnit_Auto == SVGData.mColorInterpolationFilters.GetUnit()) {
4660 svg->mColorInterpolationFilters = NS_STYLE_COLOR_INTERPOLATION_AUTO;
4662 else if (eCSSUnit_Inherit == SVGData.mColorInterpolationFilters.GetUnit()) {
4663 inherited = PR_TRUE;
4664 svg->mColorInterpolationFilters = parentSVG->mColorInterpolationFilters;
4666 else if (eCSSUnit_Initial == SVGData.mColorInterpolationFilters.GetUnit()) {
4667 svg->mColorInterpolationFilters = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB;
4670 // fill:
4671 SetSVGPaint(SVGData.mFill, parentSVG->mFill, mPresContext, aContext,
4672 svg->mFill, eStyleSVGPaintType_Color, inherited);
4674 // fill-opacity:
4675 SetSVGOpacity(SVGData.mFillOpacity, parentSVG->mFillOpacity,
4676 svg->mFillOpacity, inherited);
4678 // fill-rule: enum, inherit
4679 if (eCSSUnit_Enumerated == SVGData.mFillRule.GetUnit()) {
4680 svg->mFillRule = SVGData.mFillRule.GetIntValue();
4682 else if (eCSSUnit_Inherit == SVGData.mFillRule.GetUnit()) {
4683 inherited = PR_TRUE;
4684 svg->mFillRule = parentSVG->mFillRule;
4686 else if (eCSSUnit_Initial == SVGData.mFillRule.GetUnit()) {
4687 svg->mFillRule = NS_STYLE_FILL_RULE_NONZERO;
4690 // marker-end: url, none, inherit
4691 if (eCSSUnit_URL == SVGData.mMarkerEnd.GetUnit()) {
4692 svg->mMarkerEnd = SVGData.mMarkerEnd.GetURLValue();
4693 } else if (eCSSUnit_None == SVGData.mMarkerEnd.GetUnit() ||
4694 eCSSUnit_Initial == SVGData.mMarkerEnd.GetUnit()) {
4695 svg->mMarkerEnd = nsnull;
4696 } else if (eCSSUnit_Inherit == SVGData.mMarkerEnd.GetUnit()) {
4697 inherited = PR_TRUE;
4698 svg->mMarkerEnd = parentSVG->mMarkerEnd;
4701 // marker-mid: url, none, inherit
4702 if (eCSSUnit_URL == SVGData.mMarkerMid.GetUnit()) {
4703 svg->mMarkerMid = SVGData.mMarkerMid.GetURLValue();
4704 } else if (eCSSUnit_None == SVGData.mMarkerMid.GetUnit() ||
4705 eCSSUnit_Initial == SVGData.mMarkerMid.GetUnit()) {
4706 svg->mMarkerMid = nsnull;
4707 } else if (eCSSUnit_Inherit == SVGData.mMarkerMid.GetUnit()) {
4708 inherited = PR_TRUE;
4709 svg->mMarkerMid = parentSVG->mMarkerMid;
4712 // marker-start: url, none, inherit
4713 if (eCSSUnit_URL == SVGData.mMarkerStart.GetUnit()) {
4714 svg->mMarkerStart = SVGData.mMarkerStart.GetURLValue();
4715 } else if (eCSSUnit_None == SVGData.mMarkerStart.GetUnit() ||
4716 eCSSUnit_Initial == SVGData.mMarkerStart.GetUnit()) {
4717 svg->mMarkerStart = nsnull;
4718 } else if (eCSSUnit_Inherit == SVGData.mMarkerStart.GetUnit()) {
4719 inherited = PR_TRUE;
4720 svg->mMarkerStart = parentSVG->mMarkerStart;
4723 // pointer-events: enum, inherit
4724 if (eCSSUnit_Enumerated == SVGData.mPointerEvents.GetUnit()) {
4725 svg->mPointerEvents = SVGData.mPointerEvents.GetIntValue();
4726 } else if (eCSSUnit_None == SVGData.mPointerEvents.GetUnit()) {
4727 svg->mPointerEvents = NS_STYLE_POINTER_EVENTS_NONE;
4728 } else if (eCSSUnit_Inherit == SVGData.mPointerEvents.GetUnit()) {
4729 inherited = PR_TRUE;
4730 svg->mPointerEvents = parentSVG->mPointerEvents;
4731 } else if (eCSSUnit_Initial == SVGData.mPointerEvents.GetUnit()) {
4732 svg->mPointerEvents = NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED;
4735 // shape-rendering: enum, auto, inherit
4736 if (eCSSUnit_Enumerated == SVGData.mShapeRendering.GetUnit()) {
4737 svg->mShapeRendering = SVGData.mShapeRendering.GetIntValue();
4739 else if (eCSSUnit_Auto == SVGData.mShapeRendering.GetUnit() ||
4740 eCSSUnit_Initial == SVGData.mShapeRendering.GetUnit()) {
4741 svg->mShapeRendering = NS_STYLE_SHAPE_RENDERING_AUTO;
4743 else if (eCSSUnit_Inherit == SVGData.mShapeRendering.GetUnit()) {
4744 inherited = PR_TRUE;
4745 svg->mShapeRendering = parentSVG->mShapeRendering;
4748 // stroke:
4749 SetSVGPaint(SVGData.mStroke, parentSVG->mStroke, mPresContext, aContext,
4750 svg->mStroke, eStyleSVGPaintType_None, inherited);
4752 // stroke-dasharray: <dasharray>, none, inherit
4753 nsCSSValueList *list = SVGData.mStrokeDasharray;
4754 if (list) {
4755 if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
4756 // only do the copy if weren't already set up by the copy constructor
4757 // FIXME Bug 389408: This is broken when aStartStruct is non-null!
4758 if (!svg->mStrokeDasharray) {
4759 inherited = PR_TRUE;
4760 svg->mStrokeDasharrayLength = parentSVG->mStrokeDasharrayLength;
4761 if (svg->mStrokeDasharrayLength) {
4762 svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
4763 if (svg->mStrokeDasharray)
4764 memcpy(svg->mStrokeDasharray,
4765 parentSVG->mStrokeDasharray,
4766 svg->mStrokeDasharrayLength * sizeof(nsStyleCoord));
4767 else
4768 svg->mStrokeDasharrayLength = 0;
4771 } else {
4772 delete [] svg->mStrokeDasharray;
4773 svg->mStrokeDasharray = nsnull;
4774 svg->mStrokeDasharrayLength = 0;
4776 if (eCSSUnit_Initial != list->mValue.GetUnit() &&
4777 eCSSUnit_None != list->mValue.GetUnit()) {
4778 // count number of values
4779 nsCSSValueList *value = SVGData.mStrokeDasharray;
4780 while (nsnull != value) {
4781 ++svg->mStrokeDasharrayLength;
4782 value = value->mNext;
4785 NS_ASSERTION(svg->mStrokeDasharrayLength != 0, "no dasharray items");
4787 svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
4789 if (svg->mStrokeDasharray) {
4790 value = SVGData.mStrokeDasharray;
4791 PRUint32 i = 0;
4792 while (nsnull != value) {
4793 SetCoord(value->mValue,
4794 svg->mStrokeDasharray[i++], nsnull,
4795 SETCOORD_LP | SETCOORD_FACTOR,
4796 aContext, mPresContext, inherited);
4797 value = value->mNext;
4799 } else
4800 svg->mStrokeDasharrayLength = 0;
4805 // stroke-dashoffset: <dashoffset>, inherit
4806 SetCoord(SVGData.mStrokeDashoffset,
4807 svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
4808 SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_INITIAL_ZERO,
4809 aContext, mPresContext, inherited);
4811 // stroke-linecap: enum, inherit
4812 if (eCSSUnit_Enumerated == SVGData.mStrokeLinecap.GetUnit()) {
4813 svg->mStrokeLinecap = SVGData.mStrokeLinecap.GetIntValue();
4815 else if (eCSSUnit_Inherit == SVGData.mStrokeLinecap.GetUnit()) {
4816 inherited = PR_TRUE;
4817 svg->mStrokeLinecap = parentSVG->mStrokeLinecap;
4819 else if (eCSSUnit_Initial == SVGData.mStrokeLinecap.GetUnit()) {
4820 svg->mStrokeLinecap = NS_STYLE_STROKE_LINECAP_BUTT;
4823 // stroke-linejoin: enum, inherit
4824 if (eCSSUnit_Enumerated == SVGData.mStrokeLinejoin.GetUnit()) {
4825 svg->mStrokeLinejoin = SVGData.mStrokeLinejoin.GetIntValue();
4827 else if (eCSSUnit_Inherit == SVGData.mStrokeLinejoin.GetUnit()) {
4828 inherited = PR_TRUE;
4829 svg->mStrokeLinejoin = parentSVG->mStrokeLinejoin;
4831 else if (eCSSUnit_Initial == SVGData.mStrokeLinejoin.GetUnit()) {
4832 svg->mStrokeLinejoin = NS_STYLE_STROKE_LINEJOIN_MITER;
4835 // stroke-miterlimit: <miterlimit>, inherit
4836 if (eCSSUnit_Number == SVGData.mStrokeMiterlimit.GetUnit()) {
4837 svg->mStrokeMiterlimit = SVGData.mStrokeMiterlimit.GetFloatValue();
4839 else if (eCSSUnit_Inherit == SVGData.mStrokeMiterlimit.GetUnit()) {
4840 svg->mStrokeMiterlimit = parentSVG->mStrokeMiterlimit;
4841 inherited = PR_TRUE;
4843 else if (eCSSUnit_Initial == SVGData.mStrokeMiterlimit.GetUnit()) {
4844 svg->mStrokeMiterlimit = 4.0f;
4847 // stroke-opacity:
4848 SetSVGOpacity(SVGData.mStrokeOpacity, parentSVG->mStrokeOpacity,
4849 svg->mStrokeOpacity, inherited);
4851 // stroke-width:
4852 if (eCSSUnit_Initial == SVGData.mStrokeWidth.GetUnit()) {
4853 svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
4854 } else {
4855 SetCoord(SVGData.mStrokeWidth,
4856 svg->mStrokeWidth, parentSVG->mStrokeWidth,
4857 SETCOORD_LPH | SETCOORD_FACTOR,
4858 aContext, mPresContext, inherited);
4861 // text-anchor: enum, inherit
4862 if (eCSSUnit_Enumerated == SVGData.mTextAnchor.GetUnit()) {
4863 svg->mTextAnchor = SVGData.mTextAnchor.GetIntValue();
4865 else if (eCSSUnit_Inherit == SVGData.mTextAnchor.GetUnit()) {
4866 inherited = PR_TRUE;
4867 svg->mTextAnchor = parentSVG->mTextAnchor;
4869 else if (eCSSUnit_Initial == SVGData.mTextAnchor.GetUnit()) {
4870 svg->mTextAnchor = NS_STYLE_TEXT_ANCHOR_START;
4873 // text-rendering: enum, auto, inherit
4874 if (eCSSUnit_Enumerated == SVGData.mTextRendering.GetUnit()) {
4875 svg->mTextRendering = SVGData.mTextRendering.GetIntValue();
4877 else if (eCSSUnit_Auto == SVGData.mTextRendering.GetUnit() ||
4878 eCSSUnit_Initial == SVGData.mTextRendering.GetUnit()) {
4879 svg->mTextRendering = NS_STYLE_TEXT_RENDERING_AUTO;
4881 else if (eCSSUnit_Inherit == SVGData.mTextRendering.GetUnit()) {
4882 inherited = PR_TRUE;
4883 svg->mTextRendering = parentSVG->mTextRendering;
4886 COMPUTE_END_INHERITED(SVG, svg)
4889 const void*
4890 nsRuleNode::ComputeSVGResetData(void* aStartStruct,
4891 const nsRuleDataStruct& aData,
4892 nsStyleContext* aContext,
4893 nsRuleNode* aHighestNode,
4894 const RuleDetail aRuleDetail, PRBool aInherited)
4896 COMPUTE_START_RESET(SVGReset, (), svgReset, parentSVGReset, SVG, SVGData)
4898 // stop-color:
4899 if (eCSSUnit_Initial == SVGData.mStopColor.GetUnit()) {
4900 svgReset->mStopColor = NS_RGB(0, 0, 0);
4901 } else {
4902 SetColor(SVGData.mStopColor, parentSVGReset->mStopColor,
4903 mPresContext, aContext, svgReset->mStopColor, inherited);
4906 // flood-color:
4907 if (eCSSUnit_Initial == SVGData.mFloodColor.GetUnit()) {
4908 svgReset->mFloodColor = NS_RGB(0, 0, 0);
4909 } else {
4910 SetColor(SVGData.mFloodColor, parentSVGReset->mFloodColor,
4911 mPresContext, aContext, svgReset->mFloodColor, inherited);
4914 // lighting-color:
4915 if (eCSSUnit_Initial == SVGData.mLightingColor.GetUnit()) {
4916 svgReset->mLightingColor = NS_RGB(255, 255, 255);
4917 } else {
4918 SetColor(SVGData.mLightingColor, parentSVGReset->mLightingColor,
4919 mPresContext, aContext, svgReset->mLightingColor, inherited);
4922 // clip-path: url, none, inherit
4923 if (eCSSUnit_URL == SVGData.mClipPath.GetUnit()) {
4924 svgReset->mClipPath = SVGData.mClipPath.GetURLValue();
4925 } else if (eCSSUnit_None == SVGData.mClipPath.GetUnit() ||
4926 eCSSUnit_Initial == SVGData.mClipPath.GetUnit()) {
4927 svgReset->mClipPath = nsnull;
4928 } else if (eCSSUnit_Inherit == SVGData.mClipPath.GetUnit()) {
4929 inherited = PR_TRUE;
4930 svgReset->mClipPath = parentSVGReset->mClipPath;
4933 // stop-opacity:
4934 SetSVGOpacity(SVGData.mStopOpacity, parentSVGReset->mStopOpacity,
4935 svgReset->mStopOpacity, inherited);
4937 // flood-opacity:
4938 SetSVGOpacity(SVGData.mFloodOpacity, parentSVGReset->mFloodOpacity,
4939 svgReset->mFloodOpacity, inherited);
4941 // dominant-baseline: enum, auto, inherit
4942 if (eCSSUnit_Enumerated == SVGData.mDominantBaseline.GetUnit()) {
4943 svgReset->mDominantBaseline = SVGData.mDominantBaseline.GetIntValue();
4945 else if (eCSSUnit_Auto == SVGData.mDominantBaseline.GetUnit() ||
4946 eCSSUnit_Initial == SVGData.mDominantBaseline.GetUnit()) {
4947 svgReset->mDominantBaseline = NS_STYLE_DOMINANT_BASELINE_AUTO;
4949 else if (eCSSUnit_Inherit == SVGData.mDominantBaseline.GetUnit()) {
4950 inherited = PR_TRUE;
4951 svgReset->mDominantBaseline = parentSVGReset->mDominantBaseline;
4954 // filter: url, none, inherit
4955 if (eCSSUnit_URL == SVGData.mFilter.GetUnit()) {
4956 svgReset->mFilter = SVGData.mFilter.GetURLValue();
4957 } else if (eCSSUnit_None == SVGData.mFilter.GetUnit() ||
4958 eCSSUnit_Initial == SVGData.mFilter.GetUnit()) {
4959 svgReset->mFilter = nsnull;
4960 } else if (eCSSUnit_Inherit == SVGData.mFilter.GetUnit()) {
4961 inherited = PR_TRUE;
4962 svgReset->mFilter = parentSVGReset->mFilter;
4965 // mask: url, none, inherit
4966 if (eCSSUnit_URL == SVGData.mMask.GetUnit()) {
4967 svgReset->mMask = SVGData.mMask.GetURLValue();
4968 } else if (eCSSUnit_None == SVGData.mMask.GetUnit() ||
4969 eCSSUnit_Initial == SVGData.mMask.GetUnit()) {
4970 svgReset->mMask = nsnull;
4971 } else if (eCSSUnit_Inherit == SVGData.mMask.GetUnit()) {
4972 inherited = PR_TRUE;
4973 svgReset->mMask = parentSVGReset->mMask;
4976 COMPUTE_END_RESET(SVGReset, svgReset)
4978 #endif
4980 inline const void*
4981 nsRuleNode::GetParentData(const nsStyleStructID aSID)
4983 NS_PRECONDITION(mDependentBits & nsCachedStyleData::GetBitForSID(aSID),
4984 "should be called when node depends on parent data");
4985 NS_ASSERTION(mStyleData.GetStyleData(aSID) == nsnull,
4986 "both struct and dependent bits present");
4987 // Walk up the rule tree from this rule node (towards less specific
4988 // rules).
4989 PRUint32 bit = nsCachedStyleData::GetBitForSID(aSID);
4990 nsRuleNode *ruleNode = mParent;
4991 while (ruleNode->mDependentBits & bit) {
4992 NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nsnull,
4993 "both struct and dependent bits present");
4994 ruleNode = ruleNode->mParent;
4997 return ruleNode->mStyleData.GetStyleData(aSID);
5000 #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
5001 inline const nsStyle##name_ * \
5002 nsRuleNode::GetParent##name_() \
5004 NS_PRECONDITION(mDependentBits & \
5005 nsCachedStyleData::GetBitForSID(eStyleStruct_##name_), \
5006 "should be called when node depends on parent data"); \
5007 NS_ASSERTION(mStyleData.GetStyle##name_() == nsnull, \
5008 "both struct and dependent bits present"); \
5009 /* Walk up the rule tree from this rule node (towards less specific */ \
5010 /* rules). */ \
5011 PRUint32 bit = nsCachedStyleData::GetBitForSID(eStyleStruct_##name_); \
5012 nsRuleNode *ruleNode = mParent; \
5013 while (ruleNode->mDependentBits & bit) { \
5014 NS_ASSERTION(ruleNode->mStyleData.GetStyle##name_() == nsnull, \
5015 "both struct and dependent bits present"); \
5016 ruleNode = ruleNode->mParent; \
5019 return ruleNode->mStyleData.GetStyle##name_(); \
5021 #include "nsStyleStructList.h"
5022 #undef STYLE_STRUCT
5024 const void*
5025 nsRuleNode::GetStyleData(nsStyleStructID aSID,
5026 nsStyleContext* aContext,
5027 PRBool aComputeData)
5029 const void *data;
5030 if (mDependentBits & nsCachedStyleData::GetBitForSID(aSID)) {
5031 // We depend on an ancestor for this struct since the cached struct
5032 // it has is also appropriate for this rule node. Just go up the
5033 // rule tree and return the first cached struct we find.
5034 data = GetParentData(aSID);
5035 NS_ASSERTION(data, "dependent bits set but no cached struct present");
5036 return data;
5039 data = mStyleData.GetStyleData(aSID);
5040 if (NS_LIKELY(data != nsnull))
5041 return data; // We have a fully specified struct. Just return it.
5043 if (NS_UNLIKELY(!aComputeData))
5044 return nsnull;
5046 // Nothing is cached. We'll have to delve further and examine our rules.
5047 #define STYLE_STRUCT_TEST aSID
5048 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
5049 data = Get##name##Data(aContext);
5050 #include "nsStyleStructList.h"
5051 #undef STYLE_STRUCT
5052 #undef STYLE_STRUCT_TEST
5054 if (NS_LIKELY(data != nsnull))
5055 return data;
5057 NS_NOTREACHED("could not create style struct");
5058 // To ensure that |GetStyleData| never returns null (even when we're
5059 // out of memory), we'll get the style set and get a copy of the
5060 // default values for the given style struct from the set. Note that
5061 // this works fine even if |this| is a rule node that has been
5062 // destroyed (leftover from a previous rule tree) but is somehow still
5063 // used.
5064 return mPresContext->PresShell()->StyleSet()->
5065 DefaultStyleData()->GetStyleData(aSID);
5068 // See comments above in GetStyleData for an explanation of what the
5069 // code below does.
5070 #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
5071 const nsStyle##name_* \
5072 nsRuleNode::GetStyle##name_(nsStyleContext* aContext, PRBool aComputeData) \
5074 const nsStyle##name_ *data; \
5075 if (mDependentBits & \
5076 nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)) { \
5077 data = GetParent##name_(); \
5078 NS_ASSERTION(data, "dependent bits set but no cached struct present"); \
5079 return data; \
5082 data = mStyleData.GetStyle##name_(); \
5083 if (NS_LIKELY(data != nsnull)) \
5084 return data; \
5086 if (NS_UNLIKELY(!aComputeData)) \
5087 return nsnull; \
5089 data = \
5090 static_cast<const nsStyle##name_ *>(Get##name_##Data(aContext)); \
5092 if (NS_LIKELY(data != nsnull)) \
5093 return data; \
5095 NS_NOTREACHED("could not create style struct"); \
5096 return \
5097 static_cast<const nsStyle##name_ *>( \
5098 mPresContext->PresShell()->StyleSet()-> \
5099 DefaultStyleData()->GetStyleData(eStyleStruct_##name_)); \
5101 #include "nsStyleStructList.h"
5102 #undef STYLE_STRUCT
5104 void
5105 nsRuleNode::Mark()
5107 for (nsRuleNode *node = this;
5108 node && !(node->mDependentBits & NS_RULE_NODE_GC_MARK);
5109 node = node->mParent)
5110 node->mDependentBits |= NS_RULE_NODE_GC_MARK;
5113 PR_STATIC_CALLBACK(PLDHashOperator)
5114 SweepRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
5115 PRUint32 number, void *arg)
5117 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
5118 if (entry->mRuleNode->Sweep())
5119 return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
5120 return PL_DHASH_NEXT;
5123 PRBool
5124 nsRuleNode::Sweep()
5126 // If we're not marked, then we have to delete ourself.
5127 // However, we never allow the root node to GC itself, because nsStyleSet
5128 // wants to hold onto the root node and not worry about re-creating a
5129 // rule walker if the root node is deleted.
5130 if (!(mDependentBits & NS_RULE_NODE_GC_MARK) && !IsRoot()) {
5131 Destroy();
5132 return PR_TRUE;
5135 // Clear our mark, for the next time around.
5136 mDependentBits &= ~NS_RULE_NODE_GC_MARK;
5138 // Call sweep on the children, since some may not be marked, and
5139 // remove any deleted children from the child lists.
5140 if (HaveChildren()) {
5141 if (ChildrenAreHashed()) {
5142 PLDHashTable *children = ChildrenHash();
5143 PL_DHashTableEnumerate(children, SweepRuleNodeChildren, nsnull);
5144 } else {
5145 for (nsRuleList **children = ChildrenListPtr(); *children; ) {
5146 if ((*children)->mRuleNode->Sweep()) {
5147 // This rule node was destroyed, so remove this entry, and
5148 // implicitly advance by making *children point to the next
5149 // entry.
5150 *children = (*children)->DestroySelf(mPresContext);
5151 } else {
5152 // Advance.
5153 children = &(*children)->mNext;
5158 return PR_FALSE;
5161 /* static */ PRBool
5162 nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
5163 PRUint32 ruleTypeMask)
5165 nsRuleDataColor colorData;
5166 nsRuleDataMargin marginData;
5167 PRUint32 nValues = 0;
5169 PRUint32 inheritBits = 0;
5170 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND)
5171 inheritBits |= NS_STYLE_INHERIT_BIT(Background);
5173 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER)
5174 inheritBits |= NS_STYLE_INHERIT_BIT(Border);
5176 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING)
5177 inheritBits |= NS_STYLE_INHERIT_BIT(Padding);
5179 /* We're relying on the use of |aStyleContext| not mutating it! */
5180 nsRuleData ruleData(inheritBits,
5181 aStyleContext->PresContext(), aStyleContext);
5182 ruleData.mColorData = &colorData;
5183 ruleData.mMarginData = &marginData;
5185 nsCSSValue* backgroundValues[] = {
5186 &colorData.mBackColor,
5187 &colorData.mBackImage
5190 nsCSSValue* borderValues[] = {
5191 &marginData.mBorderColor.mTop,
5192 &marginData.mBorderStyle.mTop,
5193 &marginData.mBorderWidth.mTop,
5194 &marginData.mBorderColor.mRight,
5195 &marginData.mBorderStyle.mRight,
5196 &marginData.mBorderWidth.mRight,
5197 &marginData.mBorderColor.mBottom,
5198 &marginData.mBorderStyle.mBottom,
5199 &marginData.mBorderWidth.mBottom,
5200 &marginData.mBorderColor.mLeft,
5201 &marginData.mBorderStyle.mLeft,
5202 &marginData.mBorderWidth.mLeft
5203 // XXX add &marginData.mBorder{Start,End}{Width,Color,Style}
5206 nsCSSValue* paddingValues[] = {
5207 &marginData.mPadding.mTop,
5208 &marginData.mPadding.mRight,
5209 &marginData.mPadding.mBottom,
5210 &marginData.mPadding.mLeft,
5211 &marginData.mPaddingStart,
5212 &marginData.mPaddingEnd
5215 nsCSSValue* values[NS_ARRAY_LENGTH(backgroundValues) +
5216 NS_ARRAY_LENGTH(borderValues) +
5217 NS_ARRAY_LENGTH(paddingValues)];
5219 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
5220 memcpy(&values[nValues], backgroundValues, NS_ARRAY_LENGTH(backgroundValues) * sizeof(nsCSSValue*));
5221 nValues += NS_ARRAY_LENGTH(backgroundValues);
5224 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
5225 memcpy(&values[nValues], borderValues, NS_ARRAY_LENGTH(borderValues) * sizeof(nsCSSValue*));
5226 nValues += NS_ARRAY_LENGTH(borderValues);
5229 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
5230 memcpy(&values[nValues], paddingValues, NS_ARRAY_LENGTH(paddingValues) * sizeof(nsCSSValue*));
5231 nValues += NS_ARRAY_LENGTH(paddingValues);
5234 // We need to be careful not to count styles covered up by
5235 // user-important or UA-important declarations.
5236 for (nsRuleNode* ruleNode = aStyleContext->GetRuleNode(); ruleNode;
5237 ruleNode = ruleNode->GetParent()) {
5238 nsIStyleRule *rule = ruleNode->GetRule();
5239 if (rule) {
5240 ruleData.mLevel = ruleNode->GetLevel();
5241 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
5242 rule->MapRuleInfoInto(&ruleData);
5243 if (ruleData.mLevel == nsStyleSet::eAgentSheet ||
5244 ruleData.mLevel == nsStyleSet::eUserSheet) {
5245 // This is a rule whose effect we want to ignore, so if any of
5246 // the properties we care about were set, set them to the dummy
5247 // value that they'll never otherwise get.
5248 for (PRUint32 i = 0; i < nValues; ++i)
5249 if (values[i]->GetUnit() != eCSSUnit_Null)
5250 values[i]->SetDummyValue();
5251 } else {
5252 // If any of the values we care about was set by the above rule,
5253 // we have author style.
5254 for (PRUint32 i = 0; i < nValues; ++i)
5255 if (values[i]->GetUnit() != eCSSUnit_Null &&
5256 values[i]->GetUnit() != eCSSUnit_Dummy) // see above
5257 return PR_TRUE;
5262 return PR_FALSE;