Bug 458861. Validate TrueType headers before activating downloaded font. r=roc, sr...
[wine-gecko.git] / layout / style / nsRuleNode.cpp
blobc202b701688a2fb470582cbb14770c69ef7af54a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Original Author: David W. Hyatt (hyatt@netscape.com)
24 * Daniel Glazman <glazman@netscape.com>
25 * Roger B. Sidje <rbs@maths.uq.edu.au>
26 * Mats Palmgren <mats.palmgren@bredband.net>
27 * L. David Baron <dbaron@dbaron.org>
28 * Christian Biesinger <cbiesinger@web.de>
29 * Michael Ventnor <m.ventnor@gmail.com>
31 * Alternatively, the contents of this file may be used under the terms of
32 * either of the GNU General Public License Version 2 or later (the "GPL"),
33 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 * in which case the provisions of the GPL or the LGPL are applicable instead
35 * of those above. If you wish to allow use of your version of this file only
36 * under the terms of either the GPL or the LGPL, and not to allow others to
37 * use your version of this file under the terms of the MPL, indicate your
38 * decision by deleting the provisions above and replace them with the notice
39 * and other provisions required by the GPL or the LGPL. If you do not delete
40 * the provisions above, a recipient may use your version of this file under
41 * the terms of any one of the MPL, the GPL or the LGPL.
43 * ***** END LICENSE BLOCK ***** */
46 * a node in the lexicographic tree of rules that match an element,
47 * responsible for converting the rules' information into computed style
50 #include "nsRuleNode.h"
51 #include "nscore.h"
52 #include "nsIServiceManager.h"
53 #include "nsIDeviceContext.h"
54 #include "nsILookAndFeel.h"
55 #include "nsIPresShell.h"
56 #include "nsIThebesFontMetrics.h"
57 #include "gfxFont.h"
58 #include "nsStyleUtil.h"
59 #include "nsCSSPseudoElements.h"
60 #include "nsThemeConstants.h"
61 #include "nsITheme.h"
62 #include "pldhash.h"
63 #include "nsStyleContext.h"
64 #include "nsStyleSet.h"
65 #include "nsSize.h"
66 #include "imgIRequest.h"
67 #include "nsRuleData.h"
68 #include "nsILanguageAtomService.h"
69 #include "nsIStyleRule.h"
70 #include "nsBidiUtils.h"
71 #include "nsStyleStructInlines.h"
72 #include "nsStyleTransformMatrix.h"
73 #include "nsCSSKeywords.h"
76 * For storage of an |nsRuleNode|'s children in a PLDHashTable.
79 struct ChildrenHashEntry : public PLDHashEntryHdr {
80 // key is |mRuleNode->GetKey()|
81 nsRuleNode *mRuleNode;
84 /* static */ PLDHashNumber
85 nsRuleNode::ChildrenHashHashKey(PLDHashTable *aTable, const void *aKey)
87 const nsRuleNode::Key *key =
88 static_cast<const nsRuleNode::Key*>(aKey);
89 // Disagreement on importance and level for the same rule is extremely
90 // rare, so hash just on the rule.
91 return PL_DHashVoidPtrKeyStub(aTable, key->mRule);
94 /* static */ PRBool
95 nsRuleNode::ChildrenHashMatchEntry(PLDHashTable *aTable,
96 const PLDHashEntryHdr *aHdr,
97 const void *aKey)
99 const ChildrenHashEntry *entry =
100 static_cast<const ChildrenHashEntry*>(aHdr);
101 const nsRuleNode::Key *key =
102 static_cast<const nsRuleNode::Key*>(aKey);
103 return entry->mRuleNode->GetKey() == *key;
106 /* static */ PLDHashTableOps
107 nsRuleNode::ChildrenHashOps = {
108 // It's probably better to allocate the table itself using malloc and
109 // free rather than the pres shell's arena because the table doesn't
110 // grow very often and the pres shell's arena doesn't recycle very
111 // large size allocations.
112 PL_DHashAllocTable,
113 PL_DHashFreeTable,
114 ChildrenHashHashKey,
115 ChildrenHashMatchEntry,
116 PL_DHashMoveEntryStub,
117 PL_DHashClearEntryStub,
118 PL_DHashFinalizeStub,
119 NULL
123 // EnsureBlockDisplay:
124 // - if the display value (argument) is not a block-type
125 // then we set it to a valid block display value
126 // - For enforcing the floated/positioned element CSS2 rules
127 static void EnsureBlockDisplay(PRUint8& display)
129 // see if the display value is already a block
130 switch (display) {
131 case NS_STYLE_DISPLAY_NONE :
132 // never change display:none *ever*
133 case NS_STYLE_DISPLAY_TABLE :
134 case NS_STYLE_DISPLAY_BLOCK :
135 case NS_STYLE_DISPLAY_LIST_ITEM :
136 // do not muck with these at all - already blocks
137 // This is equivalent to nsStyleDisplay::IsBlockOutside. (XXX Maybe we
138 // should just call that?)
139 break;
141 case NS_STYLE_DISPLAY_INLINE_TABLE :
142 // make inline tables into tables
143 display = NS_STYLE_DISPLAY_TABLE;
144 break;
146 default :
147 // make it a block
148 display = NS_STYLE_DISPLAY_BLOCK;
152 // XXX This should really be done in the CSS parser.
153 static nsString& Unquote(nsString& aString)
155 PRUnichar start = aString.First();
156 PRUnichar end = aString.Last();
158 if ((start == end) &&
159 ((start == PRUnichar('\"')) ||
160 (start == PRUnichar('\'')))) {
161 PRInt32 length = aString.Length();
162 aString.Truncate(length - 1);
163 aString.Cut(0, 1);
165 return aString;
168 static nscoord CalcLengthWith(const nsCSSValue& aValue,
169 nscoord aFontSize,
170 const nsStyleFont* aStyleFont,
171 nsStyleContext* aStyleContext,
172 nsPresContext* aPresContext,
173 PRBool& aInherited)
175 NS_ASSERTION(aValue.IsLengthUnit(), "not a length unit");
176 NS_ASSERTION(aStyleFont || aStyleContext, "Must have style data");
177 NS_ASSERTION(aPresContext, "Must have prescontext");
179 if (aValue.IsFixedLengthUnit()) {
180 return aPresContext->TwipsToAppUnits(aValue.GetLengthTwips());
182 nsCSSUnit unit = aValue.GetUnit();
183 if (unit == eCSSUnit_Pixel) {
184 return nsPresContext::CSSPixelsToAppUnits(aValue.GetFloatValue());
186 // Common code for all units other than pixels:
187 aInherited = PR_TRUE;
188 if (!aStyleFont) {
189 aStyleFont = aStyleContext->GetStyleFont();
191 if (aFontSize == -1) {
192 // XXX Should this be aStyleFont->mSize instead to avoid taking minfontsize
193 // prefs into account?
194 aFontSize = aStyleFont->mFont.size;
196 switch (unit) {
197 case eCSSUnit_EM: {
198 return NSToCoordRound(aValue.GetFloatValue() * float(aFontSize));
199 // XXX scale against font metrics height instead?
201 case eCSSUnit_EN: {
202 return NSToCoordRound((aValue.GetFloatValue() * float(aFontSize)) / 2.0f);
204 case eCSSUnit_XHeight: {
205 nsFont font = aStyleFont->mFont;
206 font.size = aFontSize;
207 nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(font);
208 nscoord xHeight;
209 fm->GetXHeight(xHeight);
210 return NSToCoordRound(aValue.GetFloatValue() * float(xHeight));
212 case eCSSUnit_CapHeight: {
213 NS_NOTYETIMPLEMENTED("cap height unit");
214 nscoord capHeight = ((aFontSize / 3) * 2); // XXX HACK!
215 return NSToCoordRound(aValue.GetFloatValue() * float(capHeight));
217 case eCSSUnit_Char: {
218 nsFont font = aStyleFont->mFont;
219 font.size = aFontSize;
220 nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(font);
221 nsCOMPtr<nsIThebesFontMetrics> tfm(do_QueryInterface(fm));
222 gfxFloat zeroWidth = (tfm->GetThebesFontGroup()->GetFontAt(0)
223 ->GetMetrics().zeroOrAveCharWidth);
225 return NSToCoordRound(aValue.GetFloatValue() *
226 NS_ceil(aPresContext->AppUnitsPerDevPixel() *
227 zeroWidth));
229 default:
230 NS_NOTREACHED("unexpected unit");
231 break;
233 return 0;
236 /* static */ nscoord
237 nsRuleNode::CalcLength(const nsCSSValue& aValue,
238 nsStyleContext* aStyleContext,
239 nsPresContext* aPresContext,
240 PRBool& aInherited)
242 NS_ASSERTION(aStyleContext, "Must have style data");
244 return CalcLengthWith(aValue, -1, nsnull, aStyleContext, aPresContext, aInherited);
247 /* Inline helper function to redirect requests to CalcLength. */
248 static inline nscoord CalcLength(const nsCSSValue& aValue,
249 nsStyleContext* aStyleContext,
250 nsPresContext* aPresContext,
251 PRBool& aInherited)
253 return nsRuleNode::CalcLength(aValue, aStyleContext,
254 aPresContext, aInherited);
257 /* static */ nscoord
258 nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
259 const nsCSSValue& aValue)
261 nsStyleFont defaultFont(aPresContext);
262 PRBool inherited;
263 return CalcLengthWith(aValue, -1, &defaultFont, nsnull, aPresContext,
264 inherited);
267 #define SETCOORD_NORMAL 0x01 // N
268 #define SETCOORD_AUTO 0x02 // A
269 #define SETCOORD_INHERIT 0x04 // H
270 #define SETCOORD_PERCENT 0x08 // P
271 #define SETCOORD_FACTOR 0x10 // F
272 #define SETCOORD_LENGTH 0x20 // L
273 #define SETCOORD_INTEGER 0x40 // I
274 #define SETCOORD_ENUMERATED 0x80 // E
275 #define SETCOORD_NONE 0x100 // O
276 #define SETCOORD_INITIAL_ZERO 0x200
277 #define SETCOORD_INITIAL_AUTO 0x400
278 #define SETCOORD_INITIAL_NONE 0x800
279 #define SETCOORD_INITIAL_NORMAL 0x1000
280 #define SETCOORD_INITIAL_HALF 0x2000
282 #define SETCOORD_LP (SETCOORD_LENGTH | SETCOORD_PERCENT)
283 #define SETCOORD_LH (SETCOORD_LENGTH | SETCOORD_INHERIT)
284 #define SETCOORD_AH (SETCOORD_AUTO | SETCOORD_INHERIT)
285 #define SETCOORD_LAH (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
286 #define SETCOORD_LPH (SETCOORD_LP | SETCOORD_INHERIT)
287 #define SETCOORD_LPAH (SETCOORD_LP | SETCOORD_AH)
288 #define SETCOORD_LPEH (SETCOORD_LP | SETCOORD_ENUMERATED | SETCOORD_INHERIT)
289 #define SETCOORD_LPAEH (SETCOORD_LPAH | SETCOORD_ENUMERATED)
290 #define SETCOORD_LPOH (SETCOORD_LPH | SETCOORD_NONE)
291 #define SETCOORD_LPOEH (SETCOORD_LPOH | SETCOORD_ENUMERATED)
292 #define SETCOORD_LE (SETCOORD_LENGTH | SETCOORD_ENUMERATED)
293 #define SETCOORD_LEH (SETCOORD_LE | SETCOORD_INHERIT)
294 #define SETCOORD_IA (SETCOORD_INTEGER | SETCOORD_AUTO)
295 #define SETCOORD_LAE (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
297 // changes aCoord iff it returns PR_TRUE
298 static PRBool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
299 const nsStyleCoord& aParentCoord,
300 PRInt32 aMask, nsStyleContext* aStyleContext,
301 nsPresContext* aPresContext, PRBool& aInherited)
303 PRBool result = PR_TRUE;
304 if (aValue.GetUnit() == eCSSUnit_Null) {
305 result = PR_FALSE;
307 else if (((aMask & SETCOORD_LENGTH) != 0) &&
308 aValue.IsLengthUnit()) {
309 aCoord.SetCoordValue(CalcLength(aValue, aStyleContext, aPresContext, aInherited));
311 else if (((aMask & SETCOORD_PERCENT) != 0) &&
312 (aValue.GetUnit() == eCSSUnit_Percent)) {
313 aCoord.SetPercentValue(aValue.GetPercentValue());
315 else if (((aMask & SETCOORD_INTEGER) != 0) &&
316 (aValue.GetUnit() == eCSSUnit_Integer)) {
317 aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Integer);
319 else if (((aMask & SETCOORD_ENUMERATED) != 0) &&
320 (aValue.GetUnit() == eCSSUnit_Enumerated)) {
321 aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Enumerated);
323 else if (((aMask & SETCOORD_AUTO) != 0) &&
324 (aValue.GetUnit() == eCSSUnit_Auto)) {
325 aCoord.SetAutoValue();
327 else if (((aMask & SETCOORD_INHERIT) != 0) &&
328 (aValue.GetUnit() == eCSSUnit_Inherit)) {
329 aCoord = aParentCoord; // just inherit value from parent
330 aInherited = PR_TRUE;
332 else if (((aMask & SETCOORD_NORMAL) != 0) &&
333 (aValue.GetUnit() == eCSSUnit_Normal)) {
334 aCoord.SetNormalValue();
336 else if (((aMask & SETCOORD_NONE) != 0) &&
337 (aValue.GetUnit() == eCSSUnit_None)) {
338 aCoord.SetNoneValue();
340 else if (((aMask & SETCOORD_FACTOR) != 0) &&
341 (aValue.GetUnit() == eCSSUnit_Number)) {
342 aCoord.SetFactorValue(aValue.GetFloatValue());
344 else if (((aMask & SETCOORD_INITIAL_AUTO) != 0) &&
345 (aValue.GetUnit() == eCSSUnit_Initial)) {
346 aCoord.SetAutoValue();
348 else if (((aMask & SETCOORD_INITIAL_ZERO) != 0) &&
349 (aValue.GetUnit() == eCSSUnit_Initial)) {
350 aCoord.SetCoordValue(0);
352 else if (((aMask & SETCOORD_INITIAL_NONE) != 0) &&
353 (aValue.GetUnit() == eCSSUnit_Initial)) {
354 aCoord.SetNoneValue();
356 else if (((aMask & SETCOORD_INITIAL_NORMAL) != 0) &&
357 (aValue.GetUnit() == eCSSUnit_Initial)) {
358 aCoord.SetNormalValue();
360 else if (((aMask & SETCOORD_INITIAL_HALF) != 0) &&
361 (aValue.GetUnit() == eCSSUnit_Initial)) {
362 aCoord.SetPercentValue(0.5f);
364 else {
365 result = PR_FALSE; // didn't set anything
367 return result;
370 /* Given an enumerated value that represents a box position, converts it to
371 * a float representing the percentage of the box it corresponds to. For
372 * example, "center" becomes 0.5f.
374 * @param aEnumValue The enumerated value.
375 * @return The float percent it corresponds to.
377 static float GetFloatFromBoxPosition(PRInt32 aEnumValue)
379 switch (aEnumValue) {
380 case NS_STYLE_BG_POSITION_LEFT:
381 case NS_STYLE_BG_POSITION_TOP:
382 return 0.0f;
383 case NS_STYLE_BG_POSITION_RIGHT:
384 case NS_STYLE_BG_POSITION_BOTTOM:
385 return 1.0f;
386 default:
387 NS_NOTREACHED("unexpected value");
388 // fall through
389 case NS_STYLE_BG_POSITION_CENTER:
390 return 0.5f;
394 static PRBool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
395 nsPresContext* aPresContext, nsStyleContext *aContext,
396 nscolor& aResult, PRBool& aInherited)
398 PRBool result = PR_FALSE;
399 nsCSSUnit unit = aValue.GetUnit();
401 if (eCSSUnit_Color == unit) {
402 aResult = aValue.GetColorValue();
403 result = PR_TRUE;
405 else if (eCSSUnit_String == unit) {
406 nsAutoString value;
407 aValue.GetStringValue(value);
408 nscolor rgba;
409 if (NS_ColorNameToRGB(value, &rgba)) {
410 aResult = rgba;
411 result = PR_TRUE;
414 else if (eCSSUnit_EnumColor == unit) {
415 PRInt32 intValue = aValue.GetIntValue();
416 if (0 <= intValue) {
417 nsILookAndFeel* look = aPresContext->LookAndFeel();
418 nsILookAndFeel::nsColorID colorID = (nsILookAndFeel::nsColorID) intValue;
419 if (NS_SUCCEEDED(look->GetColor(colorID, aResult))) {
420 result = PR_TRUE;
423 else {
424 switch (intValue) {
425 case NS_COLOR_MOZ_HYPERLINKTEXT:
426 aResult = aPresContext->DefaultLinkColor();
427 break;
428 case NS_COLOR_MOZ_VISITEDHYPERLINKTEXT:
429 aResult = aPresContext->DefaultVisitedLinkColor();
430 break;
431 case NS_COLOR_MOZ_ACTIVEHYPERLINKTEXT:
432 aResult = aPresContext->DefaultActiveLinkColor();
433 break;
434 case NS_COLOR_CURRENTCOLOR:
435 // The data computed from this can't be shared in the rule tree
436 // because they could be used on a node with a different color
437 aInherited = PR_TRUE;
438 aResult = aContext->GetStyleColor()->mColor;
439 break;
440 default:
441 NS_NOTREACHED("Should never have an unknown negative colorID.");
442 break;
444 result = PR_TRUE;
447 else if (eCSSUnit_Inherit == unit) {
448 aResult = aParentColor;
449 result = PR_TRUE;
450 aInherited = PR_TRUE;
452 return result;
455 // flags for SetDiscrete - align values with SETCOORD_* constants
456 // where possible
458 #define SETDSC_NORMAL 0x01 // N
459 #define SETDSC_AUTO 0x02 // A
460 #define SETDSC_INTEGER 0x40 // I
461 #define SETDSC_ENUMERATED 0x80 // E
462 #define SETDSC_NONE 0x100 // O
463 #define SETDSC_SYSTEM_FONT 0x2000
465 // no caller cares whether aField was changed or not
466 template <typename FieldT,
467 typename T1, typename T2, typename T3, typename T4, typename T5>
468 static void
469 SetDiscrete(const nsCSSValue& aValue, FieldT & aField,
470 PRBool& aInherited, PRUint32 aMask,
471 FieldT aParentValue,
472 T1 aInitialValue,
473 T2 aAutoValue,
474 T3 aNoneValue,
475 T4 aNormalValue,
476 T5 aSystemFontValue)
478 switch (aValue.GetUnit()) {
479 case eCSSUnit_Null:
480 return;
482 // every caller of SetDiscrete provides inherit and initial
483 // alternatives, so we don't require them to say so in the mask
484 case eCSSUnit_Inherit:
485 aInherited = PR_TRUE;
486 aField = aParentValue;
487 return;
489 case eCSSUnit_Initial:
490 aField = aInitialValue;
491 return;
493 // every caller provides one or other of these alternatives,
494 // but they have to say which
495 case eCSSUnit_Enumerated:
496 if (aMask & SETDSC_ENUMERATED) {
497 aField = aValue.GetIntValue();
498 return;
500 break;
502 case eCSSUnit_Integer:
503 if (aMask & SETDSC_INTEGER) {
504 aField = aValue.GetIntValue();
505 return;
507 break;
509 // remaining possibilities in descending order of frequency of use
510 case eCSSUnit_Auto:
511 if (aMask & SETDSC_AUTO) {
512 aField = aAutoValue;
513 return;
515 break;
517 case eCSSUnit_None:
518 if (aMask & SETDSC_NONE) {
519 aField = aNoneValue;
520 return;
522 break;
524 case eCSSUnit_Normal:
525 if (aMask & SETDSC_NORMAL) {
526 aField = aNormalValue;
527 return;
529 break;
531 case eCSSUnit_System_Font:
532 if (aMask & SETDSC_SYSTEM_FONT) {
533 aField = aSystemFontValue;
534 return;
536 break;
538 default:
539 break;
542 NS_NOTREACHED("SetDiscrete: inappropriate unit");
545 // flags for SetFactor
546 #define SETFCT_POSITIVE 0x01 // assert value is >= 0.0f
547 #define SETFCT_OPACITY 0x02 // clamp value to [0.0f .. 1.0f]
548 #define SETFCT_NONE 0x04 // allow _None (uses aInitialValue).
550 static void
551 SetFactor(const nsCSSValue& aValue, float& aField, PRBool& aInherited,
552 float aParentValue, float aInitialValue, PRUint32 aFlags = 0)
554 switch (aValue.GetUnit()) {
555 case eCSSUnit_Null:
556 return;
558 case eCSSUnit_Number:
559 aField = aValue.GetFloatValue();
560 if (aFlags & SETFCT_POSITIVE) {
561 NS_ASSERTION(aField >= 0.0f, "negative value for positive-only property");
562 if (aField < 0.0f)
563 aField = 0.0f;
565 if (aFlags & SETFCT_OPACITY) {
566 if (aField < 0.0f)
567 aField = 0.0f;
568 if (aField > 1.0f)
569 aField = 1.0f;
571 return;
573 case eCSSUnit_Inherit:
574 aInherited = PR_TRUE;
575 aField = aParentValue;
576 return;
578 case eCSSUnit_Initial:
579 aField = aInitialValue;
580 return;
582 case eCSSUnit_None:
583 if (aFlags & SETFCT_NONE) {
584 aField = aInitialValue;
585 return;
587 break;
589 default:
590 break;
593 NS_NOTREACHED("SetFactor: inappropriate unit");
596 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
597 // (which comes from the presShell) to perform the allocation.
598 void*
599 nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
601 // Check the recycle list first.
602 return aPresContext->AllocateFromShell(sz);
605 /* static */ PLDHashOperator
606 nsRuleNode::EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
607 PRUint32 number, void *arg)
609 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
610 nsRuleNode ***destroyQueueTail = static_cast<nsRuleNode***>(arg);
611 **destroyQueueTail = entry->mRuleNode;
612 *destroyQueueTail = &entry->mRuleNode->mNextSibling;
613 return PL_DHASH_NEXT;
616 // Overridden to prevent the global delete from being called, since the memory
617 // came out of an nsIArena instead of the global delete operator's heap.
618 void
619 nsRuleNode::DestroyInternal(nsRuleNode ***aDestroyQueueTail)
621 nsRuleNode *destroyQueue, **destroyQueueTail;
622 if (aDestroyQueueTail) {
623 destroyQueueTail = *aDestroyQueueTail;
624 } else {
625 destroyQueue = nsnull;
626 destroyQueueTail = &destroyQueue;
629 if (ChildrenAreHashed()) {
630 PLDHashTable *children = ChildrenHash();
631 PL_DHashTableEnumerate(children, EnqueueRuleNodeChildren,
632 &destroyQueueTail);
633 *destroyQueueTail = nsnull; // ensure null-termination
634 PL_DHashTableDestroy(children);
635 } else if (HaveChildren()) {
636 *destroyQueueTail = ChildrenList();
637 do {
638 destroyQueueTail = &(*destroyQueueTail)->mNextSibling;
639 } while (*destroyQueueTail);
641 mChildren.asVoid = nsnull;
643 if (aDestroyQueueTail) {
644 // Our caller destroys the queue.
645 *aDestroyQueueTail = destroyQueueTail;
646 } else {
647 // We have to do destroy the queue. When we destroy each node, it
648 // will add its children to the queue.
649 while (destroyQueue) {
650 nsRuleNode *cur = destroyQueue;
651 destroyQueue = destroyQueue->mNextSibling;
652 if (!destroyQueue) {
653 NS_ASSERTION(destroyQueueTail == &cur->mNextSibling, "mangled list");
654 destroyQueueTail = &destroyQueue;
656 cur->DestroyInternal(&destroyQueueTail);
660 // Destroy ourselves.
661 this->~nsRuleNode();
663 // Don't let the memory be freed, since it will be recycled
664 // instead. Don't call the global operator delete.
665 mPresContext->FreeToShell(sizeof(nsRuleNode), this);
668 nsRuleNode* nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
670 return new (aPresContext)
671 nsRuleNode(aPresContext, nsnull, nsnull, 0xff, PR_FALSE);
674 nsILanguageAtomService* nsRuleNode::gLangService = nsnull;
676 nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
677 nsIStyleRule* aRule, PRUint8 aLevel,
678 PRBool aIsImportant)
679 : mPresContext(aContext),
680 mParent(aParent),
681 mRule(aRule),
682 mDependentBits((PRUint32(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
683 (aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
684 mNoneBits(0)
686 mChildren.asVoid = nsnull;
687 MOZ_COUNT_CTOR(nsRuleNode);
688 NS_IF_ADDREF(mRule);
690 NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
691 NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
694 nsRuleNode::~nsRuleNode()
696 MOZ_COUNT_DTOR(nsRuleNode);
697 if (mStyleData.mResetData || mStyleData.mInheritedData)
698 mStyleData.Destroy(0, mPresContext);
699 NS_IF_RELEASE(mRule);
702 nsRuleNode*
703 nsRuleNode::Transition(nsIStyleRule* aRule, PRUint8 aLevel,
704 PRPackedBool aIsImportantRule)
706 nsRuleNode* next = nsnull;
707 nsRuleNode::Key key(aRule, aLevel, aIsImportantRule);
709 if (HaveChildren() && !ChildrenAreHashed()) {
710 PRInt32 numKids = 0;
711 nsRuleNode* curr = ChildrenList();
712 while (curr && curr->GetKey() != key) {
713 curr = curr->mNextSibling;
714 ++numKids;
716 if (curr)
717 next = curr;
718 else if (numKids >= kMaxChildrenInList)
719 ConvertChildrenToHash();
722 if (ChildrenAreHashed()) {
723 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>
724 (PL_DHashTableOperate(ChildrenHash(), &key, PL_DHASH_ADD));
725 if (!entry) {
726 return nsnull;
728 if (entry->mRuleNode)
729 next = entry->mRuleNode;
730 else {
731 next = entry->mRuleNode = new (mPresContext)
732 nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
733 if (!next) {
734 PL_DHashTableRawRemove(ChildrenHash(), entry);
735 return nsnull;
738 } else if (!next) {
739 // Create the new entry in our list.
740 next = new (mPresContext)
741 nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
742 if (!next) {
743 return nsnull;
745 next->mNextSibling = ChildrenList();
746 SetChildrenList(next);
749 return next;
752 void
753 nsRuleNode::ConvertChildrenToHash()
755 NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
756 "must have a non-empty list of children");
757 PLDHashTable *hash = PL_NewDHashTable(&ChildrenHashOps, nsnull,
758 sizeof(ChildrenHashEntry),
759 kMaxChildrenInList * 4);
760 if (!hash)
761 return;
762 for (nsRuleNode* curr = ChildrenList(); curr; curr = curr->mNextSibling) {
763 // This will never fail because of the initial size we gave the table.
764 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(
765 PL_DHashTableOperate(hash, curr->mRule, PL_DHASH_ADD));
766 NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
767 entry->mRuleNode = curr;
769 SetChildrenHash(hash);
772 inline void
773 nsRuleNode::PropagateNoneBit(PRUint32 aBit, nsRuleNode* aHighestNode)
775 nsRuleNode* curr = this;
776 for (;;) {
777 NS_ASSERTION(!(curr->mNoneBits & aBit), "propagating too far");
778 curr->mNoneBits |= aBit;
779 if (curr == aHighestNode)
780 break;
781 curr = curr->mParent;
785 inline void
786 nsRuleNode::PropagateDependentBit(PRUint32 aBit, nsRuleNode* aHighestNode)
788 for (nsRuleNode* curr = this; curr != aHighestNode; curr = curr->mParent) {
789 if (curr->mDependentBits & aBit) {
790 #ifdef DEBUG
791 while (curr != aHighestNode) {
792 NS_ASSERTION(curr->mDependentBits & aBit, "bit not set");
793 curr = curr->mParent;
795 #endif
796 break;
799 curr->mDependentBits |= aBit;
804 * The following "Check" functions are used for determining what type of
805 * sharing can be used for the data on this rule node. MORE HERE...
808 /* the information for a property (or in some cases, a rect group of
809 properties) */
811 struct PropertyCheckData {
812 size_t offset;
813 nsCSSType type;
817 * a callback function that that can revise the result of
818 * CheckSpecifiedProperties before finishing; aResult is the current
819 * result, and it returns the revised one.
821 typedef nsRuleNode::RuleDetail
822 (* CheckCallbackFn)(const nsRuleDataStruct& aData,
823 nsRuleNode::RuleDetail aResult);
825 /* the information for all the properties in a style struct */
826 struct StructCheckData {
827 const PropertyCheckData* props;
828 PRInt32 nprops;
829 CheckCallbackFn callback;
834 * @param aValue the value being examined
835 * @param aSpecifiedCount to be incremented by one if the value is specified
836 * @param aInherited to be incremented by one if the value is set to inherit
838 inline void
839 ExamineCSSValue(const nsCSSValue& aValue,
840 PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
842 if (aValue.GetUnit() != eCSSUnit_Null) {
843 ++aSpecifiedCount;
844 if (aValue.GetUnit() == eCSSUnit_Inherit) {
845 ++aInheritedCount;
850 static void
851 ExamineCSSValuePair(const nsCSSValuePair* aValuePair,
852 PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
854 NS_PRECONDITION(aValuePair, "Must have a value pair");
856 ExamineCSSValue(aValuePair->mXValue, aSpecifiedCount, aInheritedCount);
857 ExamineCSSValue(aValuePair->mYValue, aSpecifiedCount, aInheritedCount);
860 static void
861 ExamineCSSRect(const nsCSSRect* aRect,
862 PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
864 NS_PRECONDITION(aRect, "Must have a rect");
866 NS_FOR_CSS_SIDES(side) {
867 ExamineCSSValue(aRect->*(nsCSSRect::sides[side]),
868 aSpecifiedCount, aInheritedCount);
872 static nsRuleNode::RuleDetail
873 CheckFontCallback(const nsRuleDataStruct& aData,
874 nsRuleNode::RuleDetail aResult)
876 const nsRuleDataFont& fontData =
877 static_cast<const nsRuleDataFont&>(aData);
879 // em, ex, percent, 'larger', and 'smaller' values on font-size depend
880 // on the parent context's font-size
881 // Likewise, 'lighter' and 'bolder' values of 'font-weight' depend on
882 // the parent.
883 const nsCSSValue& size = fontData.mSize;
884 const nsCSSValue& weight = fontData.mWeight;
885 if ((size.IsRelativeLengthUnit() && size.GetUnit() != eCSSUnit_Pixel) ||
886 size.GetUnit() == eCSSUnit_Percent ||
887 (size.GetUnit() == eCSSUnit_Enumerated &&
888 (size.GetIntValue() == NS_STYLE_FONT_SIZE_SMALLER ||
889 size.GetIntValue() == NS_STYLE_FONT_SIZE_LARGER)) ||
890 #ifdef MOZ_MATHML
891 fontData.mScriptLevel.GetUnit() == eCSSUnit_Integer ||
892 #endif
893 (weight.GetUnit() == eCSSUnit_Enumerated &&
894 (weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_BOLDER ||
895 weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_LIGHTER))) {
896 NS_ASSERTION(aResult == nsRuleNode::eRulePartialReset ||
897 aResult == nsRuleNode::eRuleFullReset ||
898 aResult == nsRuleNode::eRulePartialMixed ||
899 aResult == nsRuleNode::eRuleFullMixed,
900 "we know we already have a reset-counted property");
901 // Promote reset to mixed since we have something that depends on
902 // the parent. But never promote to inherited since that could
903 // cause inheritance of the exact value.
904 if (aResult == nsRuleNode::eRulePartialReset)
905 aResult = nsRuleNode::eRulePartialMixed;
906 else if (aResult == nsRuleNode::eRuleFullReset)
907 aResult = nsRuleNode::eRuleFullMixed;
910 return aResult;
913 static nsRuleNode::RuleDetail
914 CheckColorCallback(const nsRuleDataStruct& aData,
915 nsRuleNode::RuleDetail aResult)
917 const nsRuleDataColor& colorData =
918 static_cast<const nsRuleDataColor&>(aData);
920 // currentColor values for color require inheritance
921 if (colorData.mColor.GetUnit() == eCSSUnit_EnumColor &&
922 colorData.mColor.GetIntValue() == NS_COLOR_CURRENTCOLOR) {
923 NS_ASSERTION(aResult == nsRuleNode::eRuleFullReset,
924 "we should already be counted as full-reset");
925 aResult = nsRuleNode::eRuleFullInherited;
928 return aResult;
932 // for nsCSSPropList.h, so we get information on things in the style
933 // structs but not nsCSS*
934 #define CSS_PROP_INCLUDE_NOT_CSS
936 static const PropertyCheckData FontCheckProperties[] = {
937 #define CSS_PROP_FONT(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
938 { offsetof(nsRuleData##datastruct_, member_), type_ },
939 #include "nsCSSPropList.h"
940 #undef CSS_PROP_FONT
943 static const PropertyCheckData DisplayCheckProperties[] = {
944 #define CSS_PROP_DISPLAY(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
945 { offsetof(nsRuleData##datastruct_, member_), type_ },
946 #include "nsCSSPropList.h"
947 #undef CSS_PROP_DISPLAY
950 static const PropertyCheckData VisibilityCheckProperties[] = {
951 #define CSS_PROP_VISIBILITY(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
952 { offsetof(nsRuleData##datastruct_, member_), type_ },
953 #include "nsCSSPropList.h"
954 #undef CSS_PROP_VISIBILITY
957 static const PropertyCheckData MarginCheckProperties[] = {
958 #define CSS_PROP_MARGIN(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
959 { offsetof(nsRuleData##datastruct_, member_), type_ },
960 #include "nsCSSPropList.h"
961 #undef CSS_PROP_MARGIN
964 static const PropertyCheckData BorderCheckProperties[] = {
965 #define CSS_PROP_BORDER(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
966 { offsetof(nsRuleData##datastruct_, member_), type_ },
967 #include "nsCSSPropList.h"
968 #undef CSS_PROP_BORDER
971 static const PropertyCheckData PaddingCheckProperties[] = {
972 #define CSS_PROP_PADDING(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
973 { offsetof(nsRuleData##datastruct_, member_), type_ },
974 #include "nsCSSPropList.h"
975 #undef CSS_PROP_PADDING
978 static const PropertyCheckData OutlineCheckProperties[] = {
979 #define CSS_PROP_OUTLINE(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
980 { offsetof(nsRuleData##datastruct_, member_), type_ },
981 #include "nsCSSPropList.h"
982 #undef CSS_PROP_OUTLINE
985 static const PropertyCheckData ListCheckProperties[] = {
986 #define CSS_PROP_LIST(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
987 { offsetof(nsRuleData##datastruct_, member_), type_ },
988 #include "nsCSSPropList.h"
989 #undef CSS_PROP_LIST
992 static const PropertyCheckData ColorCheckProperties[] = {
993 #define CSS_PROP_COLOR(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
994 { offsetof(nsRuleData##datastruct_, member_), type_ },
995 #include "nsCSSPropList.h"
996 #undef CSS_PROP_COLOR
999 static const PropertyCheckData BackgroundCheckProperties[] = {
1000 #define CSS_PROP_BACKGROUND(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1001 { offsetof(nsRuleData##datastruct_, member_), type_ },
1002 #include "nsCSSPropList.h"
1003 #undef CSS_PROP_BACKGROUND
1006 static const PropertyCheckData PositionCheckProperties[] = {
1007 #define CSS_PROP_POSITION(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1008 { offsetof(nsRuleData##datastruct_, member_), type_ },
1009 #include "nsCSSPropList.h"
1010 #undef CSS_PROP_POSITION
1013 static const PropertyCheckData TableCheckProperties[] = {
1014 #define CSS_PROP_TABLE(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1015 { offsetof(nsRuleData##datastruct_, member_), type_ },
1016 #include "nsCSSPropList.h"
1017 #undef CSS_PROP_TABLE
1020 static const PropertyCheckData TableBorderCheckProperties[] = {
1021 #define CSS_PROP_TABLEBORDER(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1022 { offsetof(nsRuleData##datastruct_, member_), type_ },
1023 #include "nsCSSPropList.h"
1024 #undef CSS_PROP_TABLEBORDER
1027 static const PropertyCheckData ContentCheckProperties[] = {
1028 #define CSS_PROP_CONTENT(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1029 { offsetof(nsRuleData##datastruct_, member_), type_ },
1030 #include "nsCSSPropList.h"
1031 #undef CSS_PROP_CONTENT
1034 static const PropertyCheckData QuotesCheckProperties[] = {
1035 #define CSS_PROP_QUOTES(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1036 { offsetof(nsRuleData##datastruct_, member_), type_ },
1037 #include "nsCSSPropList.h"
1038 #undef CSS_PROP_QUOTES
1041 static const PropertyCheckData TextCheckProperties[] = {
1042 #define CSS_PROP_TEXT(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1043 { offsetof(nsRuleData##datastruct_, member_), type_ },
1044 #include "nsCSSPropList.h"
1045 #undef CSS_PROP_TEXT
1048 static const PropertyCheckData TextResetCheckProperties[] = {
1049 #define CSS_PROP_TEXTRESET(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1050 { offsetof(nsRuleData##datastruct_, member_), type_ },
1051 #include "nsCSSPropList.h"
1052 #undef CSS_PROP_TEXTRESET
1055 static const PropertyCheckData UserInterfaceCheckProperties[] = {
1056 #define CSS_PROP_USERINTERFACE(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1057 { offsetof(nsRuleData##datastruct_, member_), type_ },
1058 #include "nsCSSPropList.h"
1059 #undef CSS_PROP_USERINTERFACE
1062 static const PropertyCheckData UIResetCheckProperties[] = {
1063 #define CSS_PROP_UIRESET(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1064 { offsetof(nsRuleData##datastruct_, member_), type_ },
1065 #include "nsCSSPropList.h"
1066 #undef CSS_PROP_UIRESET
1069 static const PropertyCheckData XULCheckProperties[] = {
1070 #define CSS_PROP_XUL(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1071 { offsetof(nsRuleData##datastruct_, member_), type_ },
1072 #include "nsCSSPropList.h"
1073 #undef CSS_PROP_XUL
1076 #ifdef MOZ_SVG
1077 static const PropertyCheckData SVGCheckProperties[] = {
1078 #define CSS_PROP_SVG(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1079 { offsetof(nsRuleData##datastruct_, member_), type_ },
1080 #include "nsCSSPropList.h"
1081 #undef CSS_PROP_SVG
1084 static const PropertyCheckData SVGResetCheckProperties[] = {
1085 #define CSS_PROP_SVGRESET(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1086 { offsetof(nsRuleData##datastruct_, member_), type_ },
1087 #include "nsCSSPropList.h"
1088 #undef CSS_PROP_SVGRESET
1090 #endif
1092 static const PropertyCheckData ColumnCheckProperties[] = {
1093 #define CSS_PROP_COLUMN(name_, id_, method_, flags_, datastruct_, member_, type_, kwtable_) \
1094 { offsetof(nsRuleData##datastruct_, member_), type_ },
1095 #include "nsCSSPropList.h"
1096 #undef CSS_PROP_COLUMN
1099 #undef CSS_PROP_INCLUDE_NOT_CSS
1101 static const StructCheckData gCheckProperties[] = {
1103 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
1104 {name##CheckProperties, \
1105 sizeof(name##CheckProperties)/sizeof(PropertyCheckData), \
1106 checkdata_cb},
1107 #include "nsStyleStructList.h"
1108 #undef STYLE_STRUCT
1109 {nsnull, 0, nsnull}
1115 // XXXldb Taking the address of a reference is evil.
1117 inline const nsCSSValue&
1118 ValueAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1120 return * reinterpret_cast<const nsCSSValue*>
1121 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1124 inline const nsCSSRect*
1125 RectAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1127 return reinterpret_cast<const nsCSSRect*>
1128 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1131 inline const nsCSSValuePair*
1132 ValuePairAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1134 return reinterpret_cast<const nsCSSValuePair*>
1135 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1138 inline const nsCSSValueList*
1139 ValueListAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1141 return * reinterpret_cast<const nsCSSValueList*const*>
1142 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1145 inline const nsCSSValueList**
1146 ValueListArrayAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1148 return * reinterpret_cast<const nsCSSValueList**const*>
1149 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1152 inline const nsCSSValuePairList*
1153 ValuePairListAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
1155 return * reinterpret_cast<const nsCSSValuePairList*const*>
1156 (reinterpret_cast<const char*>(&aRuleDataStruct) + aOffset);
1159 #if defined(MOZ_MATHML) && defined(DEBUG)
1160 static PRBool
1161 AreAllMathMLPropertiesUndefined(const nsCSSFont& aRuleData)
1163 return aRuleData.mScriptLevel.GetUnit() == eCSSUnit_Null &&
1164 aRuleData.mScriptSizeMultiplier.GetUnit() == eCSSUnit_Null &&
1165 aRuleData.mScriptMinSize.GetUnit() == eCSSUnit_Null;
1167 #endif
1169 inline nsRuleNode::RuleDetail
1170 nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID,
1171 const nsRuleDataStruct& aRuleDataStruct)
1173 const StructCheckData *structData = gCheckProperties + aSID;
1175 // Build a count of the:
1176 PRUint32 total = 0, // total number of props in the struct
1177 specified = 0, // number that were specified for this node
1178 inherited = 0; // number that were 'inherit' (and not
1179 // eCSSUnit_Inherit) for this node
1181 for (const PropertyCheckData *prop = structData->props,
1182 *prop_end = prop + structData->nprops;
1183 prop != prop_end;
1184 ++prop)
1185 switch (prop->type) {
1187 case eCSSType_Value:
1188 ++total;
1189 ExamineCSSValue(ValueAtOffset(aRuleDataStruct, prop->offset),
1190 specified, inherited);
1191 break;
1193 case eCSSType_Rect:
1194 total += 4;
1195 ExamineCSSRect(RectAtOffset(aRuleDataStruct, prop->offset),
1196 specified, inherited);
1197 break;
1199 case eCSSType_ValuePair:
1200 total += 2;
1201 ExamineCSSValuePair(ValuePairAtOffset(aRuleDataStruct, prop->offset),
1202 specified, inherited);
1203 break;
1205 case eCSSType_ValueList:
1207 ++total;
1208 const nsCSSValueList* valueList =
1209 ValueListAtOffset(aRuleDataStruct, prop->offset);
1210 if (valueList) {
1211 ++specified;
1212 if (eCSSUnit_Inherit == valueList->mValue.GetUnit()) {
1213 ++inherited;
1217 break;
1219 case eCSSType_ValuePairList:
1221 ++total;
1222 const nsCSSValuePairList* quotes =
1223 ValuePairListAtOffset(aRuleDataStruct, prop->offset);
1224 if (quotes) {
1225 ++specified;
1226 if (eCSSUnit_Inherit == quotes->mXValue.GetUnit()) {
1227 ++inherited;
1231 break;
1233 default:
1234 NS_NOTREACHED("unknown type");
1235 break;
1239 #if 0
1240 printf("CheckSpecifiedProperties: SID=%d total=%d spec=%d inh=%d.\n",
1241 aSID, total, specified, inherited);
1242 #endif
1244 #ifdef MOZ_MATHML
1245 NS_ASSERTION(aSID != eStyleStruct_Font ||
1246 mPresContext->Document()->GetMathMLEnabled() ||
1247 AreAllMathMLPropertiesUndefined(static_cast<const nsCSSFont&>(aRuleDataStruct)),
1248 "MathML style property was defined even though MathML is disabled");
1249 #endif
1252 * Return the most specific information we can: prefer None or Full
1253 * over Partial, and Reset or Inherited over Mixed, since we can
1254 * optimize based on the edge cases and not the in-between cases.
1256 nsRuleNode::RuleDetail result;
1257 if (inherited == total)
1258 result = eRuleFullInherited;
1259 else if (specified == total
1260 #ifdef MOZ_MATHML
1261 // MathML defines 3 properties in Font that will never be set when
1262 // MathML is not in use. Therefore if all but three
1263 // properties have been set, and MathML is not enabled, we can treat
1264 // this as fully specified. Code in nsMathMLElementFactory will
1265 // rebuild the rule tree and style data when MathML is first enabled
1266 // (see nsMathMLElement::BindToTree).
1267 || (aSID == eStyleStruct_Font && specified + 3 == total &&
1268 !mPresContext->Document()->GetMathMLEnabled())
1269 #endif
1271 if (inherited == 0)
1272 result = eRuleFullReset;
1273 else
1274 result = eRuleFullMixed;
1275 } else if (specified == 0)
1276 result = eRuleNone;
1277 else if (specified == inherited)
1278 result = eRulePartialInherited;
1279 else if (inherited == 0)
1280 result = eRulePartialReset;
1281 else
1282 result = eRulePartialMixed;
1284 if (structData->callback) {
1285 result = (*structData->callback)(aRuleDataStruct, result);
1288 return result;
1291 const void*
1292 nsRuleNode::GetDisplayData(nsStyleContext* aContext)
1294 nsRuleDataDisplay displayData; // Declare a struct with null CSS values.
1295 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Display), mPresContext, aContext);
1296 ruleData.mDisplayData = &displayData;
1298 return WalkRuleTree(eStyleStruct_Display, aContext, &ruleData, &displayData);
1301 const void*
1302 nsRuleNode::GetVisibilityData(nsStyleContext* aContext)
1304 nsRuleDataDisplay displayData; // Declare a struct with null CSS values.
1305 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Visibility), mPresContext, aContext);
1306 ruleData.mDisplayData = &displayData;
1308 return WalkRuleTree(eStyleStruct_Visibility, aContext, &ruleData, &displayData);
1311 const void*
1312 nsRuleNode::GetTextData(nsStyleContext* aContext)
1314 nsRuleDataText textData; // Declare a struct with null CSS values.
1315 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Text), mPresContext, aContext);
1316 ruleData.mTextData = &textData;
1318 const void* res = WalkRuleTree(eStyleStruct_Text, aContext, &ruleData, &textData);
1319 textData.mTextShadow = nsnull; // We are sharing with some style rule. It really owns the data.
1320 return res;
1323 const void*
1324 nsRuleNode::GetTextResetData(nsStyleContext* aContext)
1326 nsRuleDataText textData; // Declare a struct with null CSS values.
1327 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(TextReset), mPresContext, aContext);
1328 ruleData.mTextData = &textData;
1330 return WalkRuleTree(eStyleStruct_TextReset, aContext, &ruleData, &textData);
1333 const void*
1334 nsRuleNode::GetUserInterfaceData(nsStyleContext* aContext)
1336 nsRuleDataUserInterface uiData; // Declare a struct with null CSS values.
1337 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(UserInterface), mPresContext, aContext);
1338 ruleData.mUserInterfaceData = &uiData;
1340 const void* res = WalkRuleTree(eStyleStruct_UserInterface, aContext, &ruleData, &uiData);
1341 uiData.mCursor = nsnull; // We are sharing with some style rule. It really owns the data.
1342 return res;
1345 const void*
1346 nsRuleNode::GetUIResetData(nsStyleContext* aContext)
1348 nsRuleDataUserInterface uiData; // Declare a struct with null CSS values.
1349 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(UIReset), mPresContext, aContext);
1350 ruleData.mUserInterfaceData = &uiData;
1352 const void* res = WalkRuleTree(eStyleStruct_UIReset, aContext, &ruleData, &uiData);
1353 return res;
1356 const void*
1357 nsRuleNode::GetFontData(nsStyleContext* aContext)
1359 nsRuleDataFont fontData; // Declare a struct with null CSS values.
1360 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), mPresContext, aContext);
1361 ruleData.mFontData = &fontData;
1363 return WalkRuleTree(eStyleStruct_Font, aContext, &ruleData, &fontData);
1366 const void*
1367 nsRuleNode::GetColorData(nsStyleContext* aContext)
1369 nsRuleDataColor colorData; // Declare a struct with null CSS values.
1370 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Color), mPresContext, aContext);
1371 ruleData.mColorData = &colorData;
1373 return WalkRuleTree(eStyleStruct_Color, aContext, &ruleData, &colorData);
1376 const void*
1377 nsRuleNode::GetBackgroundData(nsStyleContext* aContext)
1379 nsRuleDataColor colorData; // Declare a struct with null CSS values.
1380 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Background), mPresContext, aContext);
1381 ruleData.mColorData = &colorData;
1383 // If any members need to be set to null here, they must also be set to
1384 // null in HasAuthorSpecifiedRules (look at mBoxShadow in GetBorderData
1385 // and HasAuthorSpecifiedRules).
1387 return WalkRuleTree(eStyleStruct_Background, aContext, &ruleData, &colorData);
1390 const void*
1391 nsRuleNode::GetMarginData(nsStyleContext* aContext)
1393 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1394 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Margin), mPresContext, aContext);
1395 ruleData.mMarginData = &marginData;
1397 return WalkRuleTree(eStyleStruct_Margin, aContext, &ruleData, &marginData);
1400 const void*
1401 nsRuleNode::GetBorderData(nsStyleContext* aContext)
1403 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1404 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Border), mPresContext, aContext);
1405 ruleData.mMarginData = &marginData;
1407 const void* res = WalkRuleTree(eStyleStruct_Border, aContext, &ruleData, &marginData);
1408 // We are sharing with some style rule. It really owns the data.
1409 // This nulling must also happen in HasAuthorSpecifiedRules.
1410 marginData.mBoxShadow = nsnull;
1411 return res;
1414 const void*
1415 nsRuleNode::GetPaddingData(nsStyleContext* aContext)
1417 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1418 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Padding), mPresContext, aContext);
1419 ruleData.mMarginData = &marginData;
1421 // If any members need to be set to null here, they must also be set to
1422 // null in HasAuthorSpecifiedRules (look at mBoxShadow in GetBorderData
1423 // and HasAuthorSpecifiedRules).
1425 return WalkRuleTree(eStyleStruct_Padding, aContext, &ruleData, &marginData);
1428 const void*
1429 nsRuleNode::GetOutlineData(nsStyleContext* aContext)
1431 nsRuleDataMargin marginData; // Declare a struct with null CSS values.
1432 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Outline), mPresContext, aContext);
1433 ruleData.mMarginData = &marginData;
1435 return WalkRuleTree(eStyleStruct_Outline, aContext, &ruleData, &marginData);
1438 const void*
1439 nsRuleNode::GetListData(nsStyleContext* aContext)
1441 nsRuleDataList listData; // Declare a struct with null CSS values.
1442 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(List), mPresContext, aContext);
1443 ruleData.mListData = &listData;
1445 return WalkRuleTree(eStyleStruct_List, aContext, &ruleData, &listData);
1448 const void*
1449 nsRuleNode::GetPositionData(nsStyleContext* aContext)
1451 nsRuleDataPosition posData; // Declare a struct with null CSS values.
1452 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Position), mPresContext, aContext);
1453 ruleData.mPositionData = &posData;
1455 return WalkRuleTree(eStyleStruct_Position, aContext, &ruleData, &posData);
1458 const void*
1459 nsRuleNode::GetTableData(nsStyleContext* aContext)
1461 nsRuleDataTable tableData; // Declare a struct with null CSS values.
1462 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Table), mPresContext, aContext);
1463 ruleData.mTableData = &tableData;
1465 return WalkRuleTree(eStyleStruct_Table, aContext, &ruleData, &tableData);
1468 const void*
1469 nsRuleNode::GetTableBorderData(nsStyleContext* aContext)
1471 nsRuleDataTable tableData; // Declare a struct with null CSS values.
1472 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(TableBorder), mPresContext, aContext);
1473 ruleData.mTableData = &tableData;
1475 return WalkRuleTree(eStyleStruct_TableBorder, aContext, &ruleData, &tableData);
1478 const void*
1479 nsRuleNode::GetContentData(nsStyleContext* aContext)
1481 nsRuleDataContent contentData; // Declare a struct with null CSS values.
1482 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Content), mPresContext, aContext);
1483 ruleData.mContentData = &contentData;
1485 const void* res = WalkRuleTree(eStyleStruct_Content, aContext, &ruleData, &contentData);
1486 contentData.mCounterIncrement = contentData.mCounterReset = nsnull;
1487 contentData.mContent = nsnull; // We are sharing with some style rule. It really owns the data.
1488 return res;
1491 const void*
1492 nsRuleNode::GetQuotesData(nsStyleContext* aContext)
1494 nsRuleDataContent contentData; // Declare a struct with null CSS values.
1495 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Quotes), mPresContext, aContext);
1496 ruleData.mContentData = &contentData;
1498 const void* res = WalkRuleTree(eStyleStruct_Quotes, aContext, &ruleData, &contentData);
1499 contentData.mQuotes = nsnull; // We are sharing with some style rule. It really owns the data.
1500 return res;
1503 const void*
1504 nsRuleNode::GetXULData(nsStyleContext* aContext)
1506 nsRuleDataXUL xulData; // Declare a struct with null CSS values.
1507 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(XUL), mPresContext, aContext);
1508 ruleData.mXULData = &xulData;
1510 return WalkRuleTree(eStyleStruct_XUL, aContext, &ruleData, &xulData);
1513 const void*
1514 nsRuleNode::GetColumnData(nsStyleContext* aContext)
1516 nsRuleDataColumn columnData; // Declare a struct with null CSS values.
1517 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Column), mPresContext, aContext);
1518 ruleData.mColumnData = &columnData;
1520 return WalkRuleTree(eStyleStruct_Column, aContext, &ruleData, &columnData);
1523 #ifdef MOZ_SVG
1524 const void*
1525 nsRuleNode::GetSVGData(nsStyleContext* aContext)
1527 nsRuleDataSVG svgData; // Declare a struct with null CSS values.
1528 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(SVG), mPresContext, aContext);
1529 ruleData.mSVGData = &svgData;
1531 const void *res = WalkRuleTree(eStyleStruct_SVG, aContext, &ruleData, &svgData);
1532 svgData.mStrokeDasharray = nsnull; // We are sharing with some style rule. It really owns the data.
1533 return res;
1536 const void*
1537 nsRuleNode::GetSVGResetData(nsStyleContext* aContext)
1539 nsRuleDataSVG svgData; // Declare a struct with null CSS values.
1540 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(SVGReset), mPresContext, aContext);
1541 ruleData.mSVGData = &svgData;
1543 return WalkRuleTree(eStyleStruct_SVGReset, aContext, &ruleData, &svgData);
1545 #endif
1547 const void*
1548 nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
1549 nsStyleContext* aContext,
1550 nsRuleData* aRuleData,
1551 nsRuleDataStruct* aSpecificData)
1553 // We start at the most specific rule in the tree.
1554 void* startStruct = nsnull;
1556 nsRuleNode* ruleNode = this;
1557 nsRuleNode* highestNode = nsnull; // The highest node in the rule tree
1558 // that has the same properties
1559 // specified for struct |aSID| as
1560 // |this| does.
1561 nsRuleNode* rootNode = this; // After the loop below, this will be the
1562 // highest node that we've walked without
1563 // finding cached data on the rule tree.
1564 // If we don't find any cached data, it
1565 // will be the root. (XXX misnamed)
1566 RuleDetail detail = eRuleNone;
1567 PRUint32 bit = nsCachedStyleData::GetBitForSID(aSID);
1569 while (ruleNode) {
1570 // See if this rule node has cached the fact that the remaining
1571 // nodes along this path specify no data whatsoever.
1572 if (ruleNode->mNoneBits & bit)
1573 break;
1575 // If the dependent bit is set on a rule node for this struct, that
1576 // means its rule won't have any information to add, so skip it.
1577 // XXXldb I don't understand why we need to check |detail| here, but
1578 // we do.
1579 if (detail == eRuleNone)
1580 while (ruleNode->mDependentBits & bit) {
1581 NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nsnull,
1582 "dependent bit with cached data makes no sense");
1583 // Climb up to the next rule in the tree (a less specific rule).
1584 rootNode = ruleNode;
1585 ruleNode = ruleNode->mParent;
1586 NS_ASSERTION(!(ruleNode->mNoneBits & bit), "can't have both bits set");
1589 // Check for cached data after the inner loop above -- otherwise
1590 // we'll miss it.
1591 startStruct = ruleNode->mStyleData.GetStyleData(aSID);
1592 if (startStruct)
1593 break; // We found a rule with fully specified data. We don't
1594 // need to go up the tree any further, since the remainder
1595 // of this branch has already been computed.
1597 // Ask the rule to fill in the properties that it specifies.
1598 nsIStyleRule *rule = ruleNode->mRule;
1599 if (rule) {
1600 aRuleData->mLevel = ruleNode->GetLevel();
1601 aRuleData->mIsImportantRule = ruleNode->IsImportantRule();
1602 rule->MapRuleInfoInto(aRuleData);
1605 // Now we check to see how many properties have been specified by
1606 // the rules we've examined so far.
1607 RuleDetail oldDetail = detail;
1608 detail = CheckSpecifiedProperties(aSID, *aSpecificData);
1610 if (oldDetail == eRuleNone && detail != eRuleNone)
1611 highestNode = ruleNode;
1613 if (detail == eRuleFullReset ||
1614 detail == eRuleFullMixed ||
1615 detail == eRuleFullInherited)
1616 break; // We don't need to examine any more rules. All properties
1617 // have been fully specified.
1619 // Climb up to the next rule in the tree (a less specific rule).
1620 rootNode = ruleNode;
1621 ruleNode = ruleNode->mParent;
1624 NS_ASSERTION(!startStruct || (detail != eRuleFullReset &&
1625 detail != eRuleFullMixed &&
1626 detail != eRuleFullInherited),
1627 "can't have start struct and be fully specified");
1629 PRBool isReset = nsCachedStyleData::IsReset(aSID);
1630 if (!highestNode)
1631 highestNode = rootNode;
1633 if (!aRuleData->mCanStoreInRuleTree)
1634 detail = eRulePartialMixed; // Treat as though some data is specified to avoid
1635 // the optimizations and force data computation.
1637 if (detail == eRuleNone && startStruct && !aRuleData->mPostResolveCallback) {
1638 // We specified absolutely no rule information, but a parent rule in the tree
1639 // specified all the rule information. We set a bit along the branch from our
1640 // node in the tree to the node that specified the data that tells nodes on that
1641 // branch that they never need to examine their rules for this particular struct type
1642 // ever again.
1643 PropagateDependentBit(bit, ruleNode);
1644 return startStruct;
1646 // FIXME Do we need to check for mPostResolveCallback?
1647 if ((!startStruct && !isReset &&
1648 (detail == eRuleNone || detail == eRulePartialInherited)) ||
1649 detail == eRuleFullInherited) {
1650 // We specified no non-inherited information and neither did any of
1651 // our parent rules.
1653 // We set a bit along the branch from the highest node (ruleNode)
1654 // down to our node (this) indicating that no non-inherited data was
1655 // specified. This bit is guaranteed to be set already on the path
1656 // from the highest node to the root node in the case where
1657 // (detail == eRuleNone), which is the most common case here.
1658 // We must check |!isReset| because the Compute*Data functions for
1659 // reset structs wouldn't handle none bits correctly.
1660 if (highestNode != this && !isReset)
1661 PropagateNoneBit(bit, highestNode);
1663 // All information must necessarily be inherited from our parent style context.
1664 // In the absence of any computed data in the rule tree and with
1665 // no rules specified that didn't have values of 'inherit', we should check our parent.
1666 nsStyleContext* parentContext = aContext->GetParent();
1667 if (isReset) {
1668 /* Reset structs don't inherit from first-line. */
1669 /* See similar code in COMPUTE_START_RESET */
1670 while (parentContext &&
1671 parentContext->GetPseudoType() == nsCSSPseudoElements::firstLine) {
1672 parentContext = parentContext->GetParent();
1675 if (parentContext) {
1676 // We have a parent, and so we should just inherit from the parent.
1677 // Set the inherit bits on our context. These bits tell the style context that
1678 // it never has to go back to the rule tree for data. Instead the style context tree
1679 // should be walked to find the data.
1680 const void* parentStruct = parentContext->GetStyleData(aSID);
1681 aContext->AddStyleBit(bit); // makes const_cast OK.
1682 aContext->SetStyle(aSID, const_cast<void*>(parentStruct));
1683 return parentStruct;
1685 else
1686 // We are the root. In the case of fonts, the default values just
1687 // come from the pres context.
1688 return SetDefaultOnRoot(aSID, aContext);
1691 // We need to compute the data from the information that the rules specified.
1692 const void* res;
1693 #define STYLE_STRUCT_TEST aSID
1694 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
1695 res = Compute##name##Data(startStruct, *aSpecificData, aContext, \
1696 highestNode, detail, !aRuleData->mCanStoreInRuleTree);
1697 #include "nsStyleStructList.h"
1698 #undef STYLE_STRUCT
1699 #undef STYLE_STRUCT_TEST
1701 // If we have a post-resolve callback, handle that now.
1702 if (aRuleData->mPostResolveCallback && (NS_LIKELY(res != nsnull)))
1703 (*aRuleData->mPostResolveCallback)(const_cast<void*>(res), aRuleData);
1705 // Now return the result.
1706 return res;
1709 const void*
1710 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
1712 switch (aSID) {
1713 case eStyleStruct_Font:
1715 nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
1716 if (NS_LIKELY(fontData != nsnull)) {
1717 nscoord minimumFontSize =
1718 mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
1720 if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
1721 fontData->mFont.size = PR_MAX(fontData->mSize, minimumFontSize);
1723 else {
1724 fontData->mFont.size = fontData->mSize;
1726 aContext->SetStyle(eStyleStruct_Font, fontData);
1728 return fontData;
1730 case eStyleStruct_Display:
1732 nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay();
1733 if (NS_LIKELY(disp != nsnull)) {
1734 aContext->SetStyle(eStyleStruct_Display, disp);
1736 return disp;
1738 case eStyleStruct_Visibility:
1740 nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
1741 if (NS_LIKELY(vis != nsnull)) {
1742 aContext->SetStyle(eStyleStruct_Visibility, vis);
1744 return vis;
1746 case eStyleStruct_Text:
1748 nsStyleText* text = new (mPresContext) nsStyleText();
1749 if (NS_LIKELY(text != nsnull)) {
1750 aContext->SetStyle(eStyleStruct_Text, text);
1752 return text;
1754 case eStyleStruct_TextReset:
1756 nsStyleTextReset* text = new (mPresContext) nsStyleTextReset();
1757 if (NS_LIKELY(text != nsnull)) {
1758 aContext->SetStyle(eStyleStruct_TextReset, text);
1760 return text;
1762 case eStyleStruct_Color:
1764 nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
1765 if (NS_LIKELY(color != nsnull)) {
1766 aContext->SetStyle(eStyleStruct_Color, color);
1768 return color;
1770 case eStyleStruct_Background:
1772 nsStyleBackground* bg = new (mPresContext) nsStyleBackground();
1773 if (NS_LIKELY(bg != nsnull)) {
1774 aContext->SetStyle(eStyleStruct_Background, bg);
1776 return bg;
1778 case eStyleStruct_Margin:
1780 nsStyleMargin* margin = new (mPresContext) nsStyleMargin();
1781 if (NS_LIKELY(margin != nsnull)) {
1782 aContext->SetStyle(eStyleStruct_Margin, margin);
1784 return margin;
1786 case eStyleStruct_Border:
1788 nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
1789 if (NS_LIKELY(border != nsnull)) {
1790 aContext->SetStyle(eStyleStruct_Border, border);
1792 return border;
1794 case eStyleStruct_Padding:
1796 nsStylePadding* padding = new (mPresContext) nsStylePadding();
1797 if (NS_LIKELY(padding != nsnull)) {
1798 aContext->SetStyle(eStyleStruct_Padding, padding);
1800 return padding;
1802 case eStyleStruct_Outline:
1804 nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
1805 if (NS_LIKELY(outline != nsnull)) {
1806 aContext->SetStyle(eStyleStruct_Outline, outline);
1808 return outline;
1810 case eStyleStruct_List:
1812 nsStyleList* list = new (mPresContext) nsStyleList();
1813 if (NS_LIKELY(list != nsnull)) {
1814 aContext->SetStyle(eStyleStruct_List, list);
1816 return list;
1818 case eStyleStruct_Position:
1820 nsStylePosition* pos = new (mPresContext) nsStylePosition();
1821 if (NS_LIKELY(pos != nsnull)) {
1822 aContext->SetStyle(eStyleStruct_Position, pos);
1824 return pos;
1826 case eStyleStruct_Table:
1828 nsStyleTable* table = new (mPresContext) nsStyleTable();
1829 if (NS_LIKELY(table != nsnull)) {
1830 aContext->SetStyle(eStyleStruct_Table, table);
1832 return table;
1834 case eStyleStruct_TableBorder:
1836 nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
1837 if (NS_LIKELY(table != nsnull)) {
1838 aContext->SetStyle(eStyleStruct_TableBorder, table);
1840 return table;
1842 case eStyleStruct_Content:
1844 nsStyleContent* content = new (mPresContext) nsStyleContent();
1845 if (NS_LIKELY(content != nsnull)) {
1846 aContext->SetStyle(eStyleStruct_Content, content);
1848 return content;
1850 case eStyleStruct_Quotes:
1852 nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes();
1853 if (NS_LIKELY(quotes != nsnull)) {
1854 aContext->SetStyle(eStyleStruct_Quotes, quotes);
1856 return quotes;
1858 case eStyleStruct_UserInterface:
1860 nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface();
1861 if (NS_LIKELY(ui != nsnull)) {
1862 aContext->SetStyle(eStyleStruct_UserInterface, ui);
1864 return ui;
1866 case eStyleStruct_UIReset:
1868 nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset();
1869 if (NS_LIKELY(ui != nsnull)) {
1870 aContext->SetStyle(eStyleStruct_UIReset, ui);
1872 return ui;
1875 case eStyleStruct_XUL:
1877 nsStyleXUL* xul = new (mPresContext) nsStyleXUL();
1878 if (NS_LIKELY(xul != nsnull)) {
1879 aContext->SetStyle(eStyleStruct_XUL, xul);
1881 return xul;
1884 case eStyleStruct_Column:
1886 nsStyleColumn* column = new (mPresContext) nsStyleColumn(mPresContext);
1887 if (NS_LIKELY(column != nsnull)) {
1888 aContext->SetStyle(eStyleStruct_Column, column);
1890 return column;
1893 #ifdef MOZ_SVG
1894 case eStyleStruct_SVG:
1896 nsStyleSVG* svg = new (mPresContext) nsStyleSVG();
1897 if (NS_LIKELY(svg != nsnull)) {
1898 aContext->SetStyle(eStyleStruct_SVG, svg);
1900 return svg;
1903 case eStyleStruct_SVGReset:
1905 nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset();
1906 if (NS_LIKELY(svgReset != nsnull)) {
1907 aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
1909 return svgReset;
1911 #endif
1912 default:
1914 * unhandled case: nsStyleStructID_Length.
1915 * last item of nsStyleStructID, to know its length.
1917 return nsnull;
1919 return nsnull;
1923 * This function handles cascading of *-left or *-right box properties
1924 * against *-start (which is L for LTR and R for RTL) or *-end (which is
1925 * R for LTR and L for RTL).
1927 * Cascading these properties correctly is hard because we need to
1928 * cascade two properties as one, but which two properties depends on a
1929 * third property ('direction'). We solve this by treating each of
1930 * these properties (say, 'margin-start') as a shorthand that sets a
1931 * property containing the value of the property specified
1932 * ('margin-start-value') and sets a pair of properties
1933 * ('margin-left-ltr-source' and 'margin-right-rtl-source') saying which
1934 * of the properties we use. Thus, when we want to compute the value of
1935 * 'margin-left' when 'direction' is 'ltr', we look at the value of
1936 * 'margin-left-ltr-source', which tells us whether to use the highest
1937 * 'margin-left' in the cascade or the highest 'margin-start'.
1939 * Finally, since we can compute the normal (*-left and *-right)
1940 * properties in a loop, this function works by modifying the data we
1941 * will use in that loop (which the caller must copy from the const
1942 * input).
1944 void
1945 nsRuleNode::AdjustLogicalBoxProp(nsStyleContext* aContext,
1946 const nsCSSValue& aLTRSource,
1947 const nsCSSValue& aRTLSource,
1948 const nsCSSValue& aLTRLogicalValue,
1949 const nsCSSValue& aRTLLogicalValue,
1950 PRUint8 aSide,
1951 nsCSSRect& aValueRect,
1952 PRBool& aInherited)
1954 PRBool LTRlogical = aLTRSource.GetUnit() == eCSSUnit_Enumerated &&
1955 aLTRSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
1956 PRBool RTLlogical = aRTLSource.GetUnit() == eCSSUnit_Enumerated &&
1957 aRTLSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
1958 if (LTRlogical || RTLlogical) {
1959 // We can't cache anything on the rule tree if we use any data from
1960 // the style context, since data cached in the rule tree could be
1961 // used with a style context with a different value.
1962 aInherited = PR_TRUE;
1963 PRUint8 dir = aContext->GetStyleVisibility()->mDirection;
1965 if (dir == NS_STYLE_DIRECTION_LTR) {
1966 if (LTRlogical)
1967 aValueRect.*(nsCSSRect::sides[aSide]) = aLTRLogicalValue;
1968 } else {
1969 if (RTLlogical)
1970 aValueRect.*(nsCSSRect::sides[aSide]) = aRTLLogicalValue;
1976 * Begin an nsRuleNode::Compute*Data function for an inherited struct.
1978 * @param type_ The nsStyle* type this function computes.
1979 * @param ctorargs_ The arguments used for the default nsStyle* constructor.
1980 * @param data_ Variable (declared here) holding the result of this
1981 * function.
1982 * @param parentdata_ Variable (declared here) holding the parent style
1983 * context's data for this struct.
1984 * @param rdtype_ The nsCSS* struct type used to compute this struct's data.
1985 * @param rdata_ Variable (declared here) holding the nsCSS* used here.
1987 #define COMPUTE_START_INHERITED(type_, ctorargs_, data_, parentdata_, rdtype_, rdata_) \
1988 NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
1989 "should not have bothered calling Compute*Data"); \
1991 nsStyleContext* parentContext = aContext->GetParent(); \
1993 const nsRuleData##rdtype_& rdata_ = \
1994 static_cast<const nsRuleData##rdtype_&>(aData); \
1995 nsStyle##type_* data_ = nsnull; \
1996 const nsStyle##type_* parentdata_ = nsnull; \
1997 PRBool inherited = aInherited; \
1999 /* If |inherited| might be false by the time we're done, we can't call */ \
2000 /* parentContext->GetStyle##type_() since it could recur into setting */ \
2001 /* the same struct on the same rule node, causing a leak. */ \
2002 if (parentContext && aRuleDetail != eRuleFullReset && \
2003 (!aStartStruct || (aRuleDetail != eRulePartialReset && \
2004 aRuleDetail != eRuleNone))) \
2005 parentdata_ = parentContext->GetStyle##type_(); \
2006 if (aStartStruct) \
2007 /* We only need to compute the delta between this computed data and */ \
2008 /* our computed data. */ \
2009 data_ = new (mPresContext) \
2010 nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
2011 else { \
2012 if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) { \
2013 /* No question. We will have to inherit. Go ahead and init */ \
2014 /* with inherited vals from parent. */ \
2015 inherited = PR_TRUE; \
2016 if (parentdata_) \
2017 data_ = new (mPresContext) nsStyle##type_(*parentdata_); \
2018 else \
2019 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2021 else \
2022 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2025 if (NS_UNLIKELY(!data_)) \
2026 return nsnull; /* Out Of Memory */ \
2027 if (!parentdata_) \
2028 parentdata_ = data_;
2031 * Begin an nsRuleNode::Compute*Data function for a reset struct.
2033 * @param type_ The nsStyle* type this function computes.
2034 * @param ctorargs_ The arguments used for the default nsStyle* constructor.
2035 * @param data_ Variable (declared here) holding the result of this
2036 * function.
2037 * @param parentdata_ Variable (declared here) holding the parent style
2038 * context's data for this struct.
2039 * @param rdtype_ The nsCSS* struct type used to compute this struct's data.
2040 * @param rdata_ Variable (declared here) holding the nsCSS* used here.
2042 #define COMPUTE_START_RESET(type_, ctorargs_, data_, parentdata_, rdtype_, rdata_) \
2043 NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
2044 "should not have bothered calling Compute*Data"); \
2046 nsStyleContext* parentContext = aContext->GetParent(); \
2047 /* Reset structs don't inherit from first-line */ \
2048 /* See similar code in WalkRuleTree */ \
2049 while (parentContext && \
2050 parentContext->GetPseudoType() == nsCSSPseudoElements::firstLine) { \
2051 parentContext = parentContext->GetParent(); \
2054 const nsRuleData##rdtype_& rdata_ = \
2055 static_cast<const nsRuleData##rdtype_&>(aData); \
2056 nsStyle##type_* data_; \
2057 if (aStartStruct) \
2058 /* We only need to compute the delta between this computed data and */ \
2059 /* our computed data. */ \
2060 data_ = new (mPresContext) \
2061 nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
2062 else \
2063 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2065 if (NS_UNLIKELY(!data_)) \
2066 return nsnull; /* Out Of Memory */ \
2068 /* If |inherited| might be false by the time we're done, we can't call */ \
2069 /* parentContext->GetStyle##type_() since it could recur into setting */ \
2070 /* the same struct on the same rule node, causing a leak. */ \
2071 const nsStyle##type_* parentdata_ = data_; \
2072 if (parentContext && \
2073 aRuleDetail != eRuleFullReset && \
2074 aRuleDetail != eRulePartialReset && \
2075 aRuleDetail != eRuleNone) \
2076 parentdata_ = parentContext->GetStyle##type_(); \
2077 PRBool inherited = aInherited;
2080 * Begin an nsRuleNode::Compute*Data function for an inherited struct.
2082 * @param type_ The nsStyle* type this function computes.
2083 * @param data_ Variable holding the result of this function.
2085 #define COMPUTE_END_INHERITED(type_, data_) \
2086 if (inherited) \
2087 /* We inherited, and therefore can't be cached in the rule node. We */ \
2088 /* have to be put right on the style context. */ \
2089 aContext->SetStyle(eStyleStruct_##type_, data_); \
2090 else { \
2091 /* We were fully specified and can therefore be cached right on the */ \
2092 /* rule node. */ \
2093 if (!aHighestNode->mStyleData.mInheritedData) { \
2094 aHighestNode->mStyleData.mInheritedData = \
2095 new (mPresContext) nsInheritedStyleData; \
2096 if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) { \
2097 data_->Destroy(mPresContext); \
2098 return nsnull; \
2101 aHighestNode->mStyleData.mInheritedData->m##type_##Data = data_; \
2102 /* Propagate the bit down. */ \
2103 PropagateDependentBit(NS_STYLE_INHERIT_BIT(type_), aHighestNode); \
2106 return data_;
2109 * Begin an nsRuleNode::Compute*Data function for a reset struct.
2111 * @param type_ The nsStyle* type this function computes.
2112 * @param data_ Variable holding the result of this function.
2114 #define COMPUTE_END_RESET(type_, data_) \
2115 if (inherited) \
2116 /* We inherited, and therefore can't be cached in the rule node. We */ \
2117 /* have to be put right on the style context. */ \
2118 aContext->SetStyle(eStyleStruct_##type_, data_); \
2119 else { \
2120 /* We were fully specified and can therefore be cached right on the */ \
2121 /* rule node. */ \
2122 if (!aHighestNode->mStyleData.mResetData) { \
2123 aHighestNode->mStyleData.mResetData = \
2124 new (mPresContext) nsResetStyleData; \
2125 if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) { \
2126 data_->Destroy(mPresContext); \
2127 return nsnull; \
2130 aHighestNode->mStyleData.mResetData->m##type_##Data = data_; \
2131 /* Propagate the bit down. */ \
2132 PropagateDependentBit(NS_STYLE_INHERIT_BIT(type_), aHighestNode); \
2135 return data_;
2137 #ifdef MOZ_MATHML
2138 // This function figures out how much scaling should be suppressed to
2139 // satisfy scriptminsize. This is our attempt to implement
2140 // http://www.w3.org/TR/MathML2/chapter3.html#id.3.3.4.2.2
2141 // This is called after mScriptLevel, mScriptMinSize and mScriptSizeMultiplier
2142 // have been set in aFont.
2144 // Here are the invariants we enforce:
2145 // 1) A decrease in size must not reduce the size below minscriptsize.
2146 // 2) An increase in size must not increase the size above the size we would
2147 // have if minscriptsize had not been applied anywhere.
2148 // 3) The scriptlevel-induced size change must between 1.0 and the parent's
2149 // scriptsizemultiplier^(new script level - old script level), as close to the
2150 // latter as possible subject to constraints 1 and 2.
2151 static nscoord
2152 ComputeScriptLevelSize(const nsStyleFont* aFont, const nsStyleFont* aParentFont,
2153 nsPresContext* aPresContext, nscoord* aUnconstrainedSize)
2155 PRInt32 scriptLevelChange =
2156 aFont->mScriptLevel - aParentFont->mScriptLevel;
2157 if (scriptLevelChange == 0) {
2158 *aUnconstrainedSize = aParentFont->mScriptUnconstrainedSize;
2159 // Constraint #3 says that we cannot change size, and #1 and #2 are always
2160 // satisfied with no change. It's important this be fast because it covers
2161 // all non-MathML content.
2162 return aParentFont->mSize;
2165 // Compute actual value of minScriptSize
2166 nscoord minScriptSize =
2167 nsStyleFont::ZoomText(aPresContext, aParentFont->mScriptMinSize);
2169 double scriptLevelScale =
2170 pow(aParentFont->mScriptSizeMultiplier, scriptLevelChange);
2171 // Compute the size we would have had if minscriptsize had never been
2172 // applied, also prevent overflow (bug 413274)
2173 *aUnconstrainedSize =
2174 NSToCoordRound(PR_MIN(aParentFont->mScriptUnconstrainedSize*scriptLevelScale,
2175 nscoord_MAX));
2176 // Compute the size we could get via scriptlevel change
2177 nscoord scriptLevelSize =
2178 NSToCoordRound(PR_MIN(aParentFont->mSize*scriptLevelScale,
2179 nscoord_MAX));
2180 if (scriptLevelScale <= 1.0) {
2181 if (aParentFont->mSize <= minScriptSize) {
2182 // We can't decrease the font size at all, so just stick to no change
2183 // (authors are allowed to explicitly set the font size smaller than
2184 // minscriptsize)
2185 return aParentFont->mSize;
2187 // We can decrease, so apply constraint #1
2188 return PR_MAX(minScriptSize, scriptLevelSize);
2189 } else {
2190 // scriptminsize can only make sizes larger than the unconstrained size
2191 NS_ASSERTION(*aUnconstrainedSize <= scriptLevelSize, "How can this ever happen?");
2192 // Apply constraint #2
2193 return PR_MIN(scriptLevelSize, PR_MAX(*aUnconstrainedSize, minScriptSize));
2196 #endif
2198 /* static */ void
2199 nsRuleNode::SetFontSize(nsPresContext* aPresContext,
2200 const nsRuleDataFont& aFontData,
2201 const nsStyleFont* aFont,
2202 const nsStyleFont* aParentFont,
2203 nscoord* aSize,
2204 const nsFont& aSystemFont,
2205 nscoord aParentSize,
2206 nscoord aScriptLevelAdjustedParentSize,
2207 PRBool aUsedStartStruct,
2208 PRBool& aInherited)
2210 PRBool zoom = PR_FALSE;
2211 PRInt32 baseSize = (PRInt32) aPresContext->
2212 GetDefaultFont(aFont->mGenericID)->size;
2213 if (eCSSUnit_Enumerated == aFontData.mSize.GetUnit()) {
2214 PRInt32 value = aFontData.mSize.GetIntValue();
2215 PRInt32 scaler = aPresContext->FontScaler();
2216 float scaleFactor = nsStyleUtil::GetScalingFactor(scaler);
2218 zoom = PR_TRUE;
2219 if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) &&
2220 (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
2221 *aSize = nsStyleUtil::CalcFontPointSize(value, baseSize,
2222 scaleFactor, aPresContext, eFontSize_CSS);
2224 else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
2225 // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
2226 *aSize = nsStyleUtil::CalcFontPointSize(value, baseSize,
2227 scaleFactor, aPresContext);
2229 else if (NS_STYLE_FONT_SIZE_LARGER == value ||
2230 NS_STYLE_FONT_SIZE_SMALLER == value) {
2231 aInherited = PR_TRUE;
2233 // Un-zoom so we use the tables correctly. We'll then rezoom due
2234 // to the |zoom = PR_TRUE| above.
2235 // Note that relative units here use the parent's size unadjusted
2236 // for scriptlevel changes. A scriptlevel change between us and the parent
2237 // is simply ignored.
2238 nscoord parentSize =
2239 nsStyleFont::UnZoomText(aPresContext, aParentSize);
2241 if (NS_STYLE_FONT_SIZE_LARGER == value) {
2242 *aSize = nsStyleUtil::FindNextLargerFontSize(parentSize,
2243 baseSize, scaleFactor, aPresContext, eFontSize_CSS);
2244 NS_ASSERTION(*aSize > parentSize,
2245 "FindNextLargerFontSize failed");
2247 else {
2248 *aSize = nsStyleUtil::FindNextSmallerFontSize(parentSize,
2249 baseSize, scaleFactor, aPresContext, eFontSize_CSS);
2250 NS_ASSERTION(*aSize < parentSize ||
2251 parentSize <= nsPresContext::CSSPixelsToAppUnits(1),
2252 "FindNextSmallerFontSize failed");
2254 } else {
2255 NS_NOTREACHED("unexpected value");
2258 else if (aFontData.mSize.IsLengthUnit()) {
2259 // Note that font-based length units use the parent's size unadjusted
2260 // for scriptlevel changes. A scriptlevel change between us and the parent
2261 // is simply ignored.
2262 *aSize = CalcLengthWith(aFontData.mSize, aParentSize, aParentFont, nsnull,
2263 aPresContext, aInherited);
2264 zoom = aFontData.mSize.IsFixedLengthUnit() ||
2265 aFontData.mSize.GetUnit() == eCSSUnit_Pixel;
2267 else if (eCSSUnit_Percent == aFontData.mSize.GetUnit()) {
2268 aInherited = PR_TRUE;
2269 // Note that % units use the parent's size unadjusted for scriptlevel
2270 // changes. A scriptlevel change between us and the parent is simply
2271 // ignored.
2272 *aSize = NSToCoordRound(aParentSize *
2273 aFontData.mSize.GetPercentValue());
2274 zoom = PR_FALSE;
2276 else if (eCSSUnit_System_Font == aFontData.mSize.GetUnit()) {
2277 // this becomes our cascading size
2278 *aSize = aSystemFont.size;
2279 zoom = PR_TRUE;
2281 else if (eCSSUnit_Inherit == aFontData.mSize.GetUnit()) {
2282 aInherited = PR_TRUE;
2283 // We apply scriptlevel change for this case, because the default is
2284 // to inherit and we don't want explicit "inherit" to differ from the
2285 // default.
2286 *aSize = aScriptLevelAdjustedParentSize;
2287 zoom = PR_FALSE;
2289 else if (eCSSUnit_Initial == aFontData.mSize.GetUnit()) {
2290 // The initial value is 'medium', which has magical sizing based on
2291 // the generic font family, so do that here too.
2292 *aSize = baseSize;
2293 zoom = PR_TRUE;
2294 } else {
2295 NS_ASSERTION(eCSSUnit_Null == aFontData.mSize.GetUnit(),
2296 "What kind of font-size value is this?");
2297 #ifdef MOZ_MATHML
2298 // if aUsedStartStruct is true, then every single property in the
2299 // font struct is being set all at once. This means scriptlevel is not
2300 // going to have any influence on the font size; there is no need to
2301 // do anything here.
2302 if (!aUsedStartStruct && aParentSize != aScriptLevelAdjustedParentSize) {
2303 // There was no rule affecting the size but the size has been
2304 // affected by the parent's size via scriptlevel change. So treat
2305 // this as inherited.
2306 aInherited = PR_TRUE;
2307 *aSize = aScriptLevelAdjustedParentSize;
2309 #endif
2312 // We want to zoom the cascaded size so that em-based measurements,
2313 // line-heights, etc., work.
2314 if (zoom) {
2315 *aSize = nsStyleFont::ZoomText(aPresContext, *aSize);
2319 static PRInt8 ClampTo8Bit(PRInt32 aValue) {
2320 if (aValue < -128)
2321 return -128;
2322 if (aValue > 127)
2323 return 127;
2324 return PRInt8(aValue);
2327 /* static */ void
2328 nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
2329 nscoord aMinFontSize,
2330 PRUint8 aGenericFontID, const nsRuleDataFont& aFontData,
2331 const nsStyleFont* aParentFont,
2332 nsStyleFont* aFont, PRBool aUsedStartStruct,
2333 PRBool& aInherited)
2335 const nsFont* defaultVariableFont =
2336 aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID);
2338 // -moz-system-font: enum (never inherit!)
2339 nsFont systemFont;
2340 if (eCSSUnit_Enumerated == aFontData.mSystemFont.GetUnit()) {
2341 nsSystemFontID sysID;
2342 switch (aFontData.mSystemFont.GetIntValue()) {
2343 case NS_STYLE_FONT_CAPTION: sysID = eSystemFont_Caption; break; // css2
2344 case NS_STYLE_FONT_ICON: sysID = eSystemFont_Icon; break;
2345 case NS_STYLE_FONT_MENU: sysID = eSystemFont_Menu; break;
2346 case NS_STYLE_FONT_MESSAGE_BOX: sysID = eSystemFont_MessageBox; break;
2347 case NS_STYLE_FONT_SMALL_CAPTION: sysID = eSystemFont_SmallCaption; break;
2348 case NS_STYLE_FONT_STATUS_BAR: sysID = eSystemFont_StatusBar; break;
2349 case NS_STYLE_FONT_WINDOW: sysID = eSystemFont_Window; break; // css3
2350 case NS_STYLE_FONT_DOCUMENT: sysID = eSystemFont_Document; break;
2351 case NS_STYLE_FONT_WORKSPACE: sysID = eSystemFont_Workspace; break;
2352 case NS_STYLE_FONT_DESKTOP: sysID = eSystemFont_Desktop; break;
2353 case NS_STYLE_FONT_INFO: sysID = eSystemFont_Info; break;
2354 case NS_STYLE_FONT_DIALOG: sysID = eSystemFont_Dialog; break;
2355 case NS_STYLE_FONT_BUTTON: sysID = eSystemFont_Button; break;
2356 case NS_STYLE_FONT_PULL_DOWN_MENU:sysID = eSystemFont_PullDownMenu; break;
2357 case NS_STYLE_FONT_LIST: sysID = eSystemFont_List; break;
2358 case NS_STYLE_FONT_FIELD: sysID = eSystemFont_Field; break;
2361 // GetSystemFont sets the font face but not necessarily the size
2362 // XXX Or at least it used to -- no longer true for thebes. Maybe
2363 // it should be again, though.
2364 systemFont.size = defaultVariableFont->size;
2366 if (NS_FAILED(aPresContext->DeviceContext()->GetSystemFont(sysID,
2367 &systemFont))) {
2368 systemFont.name = defaultVariableFont->name;
2371 // XXXldb All of this platform-specific stuff should be in the
2372 // nsIDeviceContext implementations, not here.
2374 #ifdef XP_WIN
2376 // As far as I can tell the system default fonts and sizes for
2377 // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
2378 // all pre-determined and cannot be changed by either the control panel
2379 // or programmtically.
2381 switch (sysID) {
2382 // Fields (text fields)
2383 // Button and Selects (listboxes/comboboxes)
2384 // We use whatever font is defined by the system. Which it appears
2385 // (and the assumption is) it is always a proportional font. Then we
2386 // always use 2 points smaller than what the browser has defined as
2387 // the default proportional font.
2388 case eSystemFont_Field:
2389 case eSystemFont_Button:
2390 case eSystemFont_List:
2391 // Assumption: system defined font is proportional
2392 systemFont.size =
2393 PR_MAX(defaultVariableFont->size - aPresContext->PointsToAppUnits(2), 0);
2394 break;
2396 #endif
2397 } else {
2398 // In case somebody explicitly used -moz-use-system-font.
2399 systemFont = *defaultVariableFont;
2403 // font-family: string list, enum, inherit
2404 NS_ASSERTION(eCSSUnit_Enumerated != aFontData.mFamily.GetUnit(),
2405 "system fonts should not be in mFamily anymore");
2406 if (eCSSUnit_String == aFontData.mFamily.GetUnit()) {
2407 // set the correct font if we are using DocumentFonts OR we are overriding for XUL
2408 // MJA: bug 31816
2409 if (aGenericFontID == kGenericFont_NONE) {
2410 // only bother appending fallback fonts if this isn't a fallback generic font itself
2411 if (!aFont->mFont.name.IsEmpty())
2412 aFont->mFont.name.Append((PRUnichar)',');
2413 // defaultVariableFont.name should always be "serif" or "sans-serif".
2414 aFont->mFont.name.Append(defaultVariableFont->name);
2416 aFont->mFont.familyNameQuirks =
2417 (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks &&
2418 aFontData.mFamilyFromHTML);
2419 aFont->mFont.systemFont = PR_FALSE;
2420 // Technically this is redundant with the code below, but it's good
2421 // to have since we'll still want it once we get rid of
2422 // SetGenericFont (bug 380915).
2423 aFont->mGenericID = aGenericFontID;
2425 else if (eCSSUnit_System_Font == aFontData.mFamily.GetUnit()) {
2426 aFont->mFont.name = systemFont.name;
2427 aFont->mFont.familyNameQuirks = PR_FALSE;
2428 aFont->mFont.systemFont = PR_TRUE;
2429 aFont->mGenericID = kGenericFont_NONE;
2431 else if (eCSSUnit_Inherit == aFontData.mFamily.GetUnit()) {
2432 aInherited = PR_TRUE;
2433 aFont->mFont.name = aParentFont->mFont.name;
2434 aFont->mFont.familyNameQuirks = aParentFont->mFont.familyNameQuirks;
2435 aFont->mFont.systemFont = aParentFont->mFont.systemFont;
2436 aFont->mGenericID = aParentFont->mGenericID;
2438 else if (eCSSUnit_Initial == aFontData.mFamily.GetUnit()) {
2439 aFont->mFont.name = defaultVariableFont->name;
2440 aFont->mFont.familyNameQuirks = PR_FALSE;
2441 aFont->mFont.systemFont = defaultVariableFont->systemFont;
2442 aFont->mGenericID = kGenericFont_NONE;
2445 // When we're in the loop in SetGenericFont, we must ensure that we
2446 // always keep aFont->mFlags set to the correct generic. But we have
2447 // to be careful not to touch it when we're called directly from
2448 // ComputeFontData, because we could have a start struct.
2449 if (aGenericFontID != kGenericFont_NONE) {
2450 aFont->mGenericID = aGenericFontID;
2453 // font-style: enum, normal, inherit, initial, -moz-system-font
2454 SetDiscrete(aFontData.mStyle, aFont->mFont.style, aInherited,
2455 SETDSC_ENUMERATED | SETDSC_NORMAL | SETDSC_SYSTEM_FONT,
2456 aParentFont->mFont.style,
2457 defaultVariableFont->style,
2458 0, 0,
2459 NS_STYLE_FONT_STYLE_NORMAL,
2460 systemFont.style);
2462 // font-variant: enum, normal, inherit, initial, -moz-system-font
2463 SetDiscrete(aFontData.mVariant, aFont->mFont.variant, aInherited,
2464 SETDSC_ENUMERATED | SETDSC_NORMAL | SETDSC_SYSTEM_FONT,
2465 aParentFont->mFont.variant,
2466 defaultVariableFont->variant,
2467 0, 0,
2468 NS_STYLE_FONT_VARIANT_NORMAL,
2469 systemFont.variant);
2471 // font-weight: int, enum, normal, inherit, initial, -moz-system-font
2472 // special handling for enum
2473 if (eCSSUnit_Enumerated == aFontData.mWeight.GetUnit()) {
2474 PRInt32 value = aFontData.mWeight.GetIntValue();
2475 switch (value) {
2476 case NS_STYLE_FONT_WEIGHT_NORMAL:
2477 case NS_STYLE_FONT_WEIGHT_BOLD:
2478 aFont->mFont.weight = value;
2479 break;
2480 case NS_STYLE_FONT_WEIGHT_BOLDER:
2481 case NS_STYLE_FONT_WEIGHT_LIGHTER:
2482 aInherited = PR_TRUE;
2483 aFont->mFont.weight = nsStyleUtil::ConstrainFontWeight(aParentFont->mFont.weight + value);
2484 break;
2486 } else
2487 SetDiscrete(aFontData.mWeight, aFont->mFont.weight, aInherited,
2488 SETDSC_INTEGER | SETDSC_NORMAL | SETDSC_SYSTEM_FONT,
2489 aParentFont->mFont.weight,
2490 defaultVariableFont->weight,
2491 0, 0,
2492 NS_STYLE_FONT_WEIGHT_NORMAL,
2493 systemFont.weight);
2495 #ifdef MOZ_MATHML
2496 // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
2497 // they're available for font-size computation.
2499 // -moz-script-min-size: length
2500 if (aFontData.mScriptMinSize.IsLengthUnit()) {
2501 // scriptminsize in font units (em, ex) has to be interpreted relative
2502 // to the parent font, or the size definitions are circular and we
2504 aFont->mScriptMinSize =
2505 CalcLengthWith(aFontData.mScriptMinSize, aParentFont->mSize, aParentFont, nsnull,
2506 aPresContext, aInherited);
2509 // -moz-script-size-multiplier: factor, inherit, initial
2510 SetFactor(aFontData.mScriptSizeMultiplier, aFont->mScriptSizeMultiplier,
2511 aInherited, aParentFont->mScriptSizeMultiplier,
2512 NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER,
2513 SETFCT_POSITIVE);
2515 // -moz-script-level: integer, number, inherit
2516 if (eCSSUnit_Integer == aFontData.mScriptLevel.GetUnit()) {
2517 // "relative"
2518 aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel + aFontData.mScriptLevel.GetIntValue());
2520 else if (eCSSUnit_Number == aFontData.mScriptLevel.GetUnit()) {
2521 // "absolute"
2522 aFont->mScriptLevel = ClampTo8Bit(PRInt32(aFontData.mScriptLevel.GetFloatValue()));
2524 else if (eCSSUnit_Inherit == aFontData.mScriptSizeMultiplier.GetUnit()) {
2525 aInherited = PR_TRUE;
2526 aFont->mScriptLevel = aParentFont->mScriptLevel;
2528 else if (eCSSUnit_Initial == aFontData.mScriptSizeMultiplier.GetUnit()) {
2529 aFont->mScriptLevel = 0;
2531 #endif
2533 // font-size: enum, length, percent, inherit
2534 nscoord scriptLevelAdjustedParentSize = aParentFont->mSize;
2535 #ifdef MOZ_MATHML
2536 nscoord scriptLevelAdjustedUnconstrainedParentSize;
2537 scriptLevelAdjustedParentSize =
2538 ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
2539 &scriptLevelAdjustedUnconstrainedParentSize);
2540 NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
2541 "If we have a start struct, we should have reset everything coming in here");
2542 #endif
2543 SetFontSize(aPresContext, aFontData, aFont, aParentFont, &aFont->mSize,
2544 systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
2545 aUsedStartStruct, aInherited);
2546 #ifdef MOZ_MATHML
2547 if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
2548 scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) {
2549 // Fast path: we have not been affected by scriptminsize so we don't
2550 // need to call SetFontSize again to compute the
2551 // scriptminsize-unconstrained size. This is OK even if we have a
2552 // start struct, because if we have a start struct then 'font-size'
2553 // was specified and so scriptminsize has no effect.
2554 aFont->mScriptUnconstrainedSize = aFont->mSize;
2555 } else {
2556 SetFontSize(aPresContext, aFontData, aFont, aParentFont,
2557 &aFont->mScriptUnconstrainedSize, systemFont,
2558 aParentFont->mScriptUnconstrainedSize,
2559 scriptLevelAdjustedUnconstrainedParentSize,
2560 aUsedStartStruct, aInherited);
2562 NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
2563 "scriptminsize should never be making things bigger");
2564 #endif
2566 // enforce the user' specified minimum font-size on the value that we expose
2567 // (but don't change font-size:0)
2568 if (0 < aFont->mSize && aFont->mSize < aMinFontSize)
2569 aFont->mFont.size = aMinFontSize;
2570 else
2571 aFont->mFont.size = aFont->mSize;
2573 // font-size-adjust: number, none, inherit, initial, -moz-system-font
2574 if (eCSSUnit_System_Font == aFontData.mSizeAdjust.GetUnit()) {
2575 aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
2576 } else
2577 SetFactor(aFontData.mSizeAdjust, aFont->mFont.sizeAdjust, aInherited,
2578 aParentFont->mFont.sizeAdjust, 0.0f, SETFCT_NONE);
2581 // SetGenericFont:
2582 // - backtrack to an ancestor with the same generic font name (possibly
2583 // up to the root where default values come from the presentation context)
2584 // - re-apply cascading rules from there without caching intermediate values
2585 /* static */ void
2586 nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
2587 nsStyleContext* aContext,
2588 PRUint8 aGenericFontID, nscoord aMinFontSize,
2589 nsStyleFont* aFont)
2591 // walk up the contexts until a context with the desired generic font
2592 nsAutoVoidArray contextPath;
2593 contextPath.AppendElement(aContext);
2594 nsStyleContext* higherContext = aContext->GetParent();
2595 while (higherContext) {
2596 if (higherContext->GetStyleFont()->mGenericID == aGenericFontID) {
2597 // done walking up the higher contexts
2598 break;
2600 contextPath.AppendElement(higherContext);
2601 higherContext = higherContext->GetParent();
2604 // re-apply the cascading rules, starting from the higher context
2606 // If we stopped earlier because we reached the root of the style tree,
2607 // we will start with the default generic font from the presentation
2608 // context. Otherwise we start with the higher context.
2609 const nsFont* defaultFont = aPresContext->GetDefaultFont(aGenericFontID);
2610 nsStyleFont parentFont(*defaultFont, aPresContext);
2611 if (higherContext) {
2612 const nsStyleFont* tmpFont = higherContext->GetStyleFont();
2613 parentFont = *tmpFont;
2615 *aFont = parentFont;
2617 PRBool dummy;
2618 PRUint32 fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
2620 for (PRInt32 i = contextPath.Count() - 1; i >= 0; --i) {
2621 nsStyleContext* context = (nsStyleContext*)contextPath[i];
2622 nsRuleDataFont fontData; // Declare a struct with null CSS values.
2623 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), aPresContext, context);
2624 ruleData.mFontData = &fontData;
2626 // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
2627 // Note that we *do* need to do this for our own data, since what is
2628 // in |fontData| in ComputeFontData is only for the rules below
2629 // aStartStruct.
2630 for (nsRuleNode* ruleNode = context->GetRuleNode(); ruleNode;
2631 ruleNode = ruleNode->GetParent()) {
2632 if (ruleNode->mNoneBits & fontBit)
2633 // no more font rules on this branch, get out
2634 break;
2636 nsIStyleRule *rule = ruleNode->GetRule();
2637 if (rule) {
2638 ruleData.mLevel = ruleNode->GetLevel();
2639 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
2640 rule->MapRuleInfoInto(&ruleData);
2644 // Compute the delta from the information that the rules specified
2646 // Avoid unnecessary operations in SetFont(). But we care if it's
2647 // the final value that we're computing.
2648 if (i != 0)
2649 fontData.mFamily.Reset();
2651 nsRuleNode::SetFont(aPresContext, context, aMinFontSize,
2652 aGenericFontID, fontData, &parentFont, aFont,
2653 PR_FALSE, dummy);
2655 // XXX Not sure if we need to do this here
2656 // If we have a post-resolve callback, handle that now.
2657 if (ruleData.mPostResolveCallback)
2658 (ruleData.mPostResolveCallback)(aFont, &ruleData);
2660 parentFont = *aFont;
2664 static PRBool ExtractGeneric(const nsString& aFamily, PRBool aGeneric,
2665 void *aData)
2667 nsAutoString *data = static_cast<nsAutoString*>(aData);
2669 if (aGeneric) {
2670 *data = aFamily;
2671 return PR_FALSE; // stop enumeration
2673 return PR_TRUE;
2676 const void*
2677 nsRuleNode::ComputeFontData(void* aStartStruct,
2678 const nsRuleDataStruct& aData,
2679 nsStyleContext* aContext,
2680 nsRuleNode* aHighestNode,
2681 const RuleDetail aRuleDetail, PRBool aInherited)
2683 COMPUTE_START_INHERITED(Font, (mPresContext), font, parentFont,
2684 Font, fontData)
2686 // NOTE: The |aRuleDetail| passed in is a little bit conservative due
2687 // to the -moz-system-font property. We really don't need to consider
2688 // it here in determining whether to cache in the rule tree. However,
2689 // we do need to consider it in WalkRuleTree when deciding whether to
2690 // walk further up the tree. So this means that when the font struct
2691 // is fully specified using *longhand* properties (excluding
2692 // -moz-system-font), we won't cache in the rule tree even though we
2693 // could. However, it's pretty unlikely authors will do that
2694 // (although there is a pretty good chance they'll fully specify it
2695 // using the 'font' shorthand).
2697 // See if there is a minimum font-size constraint to honor
2698 nscoord minimumFontSize =
2699 mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
2701 if (minimumFontSize < 0)
2702 minimumFontSize = 0;
2704 PRBool useDocumentFonts =
2705 mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
2707 // See if we are in the chrome
2708 // We only need to know this to determine if we have to use the
2709 // document fonts (overriding the useDocumentFonts flag), or to
2710 // determine if we have to override the minimum font-size constraint.
2711 if ((!useDocumentFonts || minimumFontSize > 0) && mPresContext->IsChrome()) {
2712 // if we are not using document fonts, but this is a XUL document,
2713 // then we use the document fonts anyway
2714 useDocumentFonts = PR_TRUE;
2715 minimumFontSize = 0;
2718 // Figure out if we are a generic font
2719 PRUint8 generic = kGenericFont_NONE;
2720 // XXXldb What if we would have had a string if we hadn't been doing
2721 // the optimization with a non-null aStartStruct?
2722 if (eCSSUnit_String == fontData.mFamily.GetUnit()) {
2723 fontData.mFamily.GetStringValue(font->mFont.name);
2724 // XXXldb Do we want to extract the generic for this if it's not only a
2725 // generic?
2726 nsFont::GetGenericID(font->mFont.name, &generic);
2728 // If we aren't allowed to use document fonts, then we are only entitled
2729 // to use the user's default variable-width font and fixed-width font
2730 if (!useDocumentFonts) {
2731 // Extract the generic from the specified font family...
2732 nsAutoString genericName;
2733 if (!font->mFont.EnumerateFamilies(ExtractGeneric, &genericName)) {
2734 // The specified font had a generic family.
2735 font->mFont.name = genericName;
2736 nsFont::GetGenericID(genericName, &generic);
2738 // ... and only use it if it's -moz-fixed or monospace
2739 if (generic != kGenericFont_moz_fixed &&
2740 generic != kGenericFont_monospace) {
2741 font->mFont.name.Truncate();
2742 generic = kGenericFont_NONE;
2744 } else {
2745 // The specified font did not have a generic family.
2746 font->mFont.name.Truncate();
2747 generic = kGenericFont_NONE;
2752 // Now compute our font struct
2753 if (generic == kGenericFont_NONE) {
2754 // continue the normal processing
2755 nsRuleNode::SetFont(mPresContext, aContext, minimumFontSize, generic,
2756 fontData, parentFont, font,
2757 aStartStruct != nsnull, inherited);
2759 else {
2760 // re-calculate the font as a generic font
2761 inherited = PR_TRUE;
2762 nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
2763 minimumFontSize, font);
2766 COMPUTE_END_INHERITED(Font, font)
2769 already_AddRefed<nsCSSShadowArray>
2770 nsRuleNode::GetShadowData(nsCSSValueList* aList,
2771 nsStyleContext* aContext,
2772 PRBool aUsesSpread,
2773 PRBool& inherited)
2775 PRUint32 arrayLength = 0;
2776 for (nsCSSValueList *list2 = aList; list2; list2 = list2->mNext)
2777 ++arrayLength;
2779 NS_ASSERTION(arrayLength > 0, "Non-null text-shadow list, yet we counted 0 items.");
2780 nsCSSShadowArray* shadowList = new(arrayLength) nsCSSShadowArray(arrayLength);
2782 if (!shadowList)
2783 return nsnull;
2785 nsStyleCoord tempCoord;
2786 PRBool unitOK;
2787 for (nsCSSShadowItem* item = shadowList->ShadowAt(0);
2788 aList;
2789 aList = aList->mNext, ++item) {
2790 nsCSSValue::Array *arr = aList->mValue.GetArrayValue();
2791 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
2792 unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(),
2793 SETCOORD_LENGTH, aContext, mPresContext, inherited);
2794 NS_ASSERTION(unitOK, "unexpected unit");
2795 item->mXOffset = tempCoord.GetCoordValue();
2797 unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(),
2798 SETCOORD_LENGTH, aContext, mPresContext, inherited);
2799 NS_ASSERTION(unitOK, "unexpected unit");
2800 item->mYOffset = tempCoord.GetCoordValue();
2802 // Blur radius is optional in the current box-shadow spec
2803 if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
2804 unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(),
2805 SETCOORD_LENGTH, aContext, mPresContext, inherited);
2806 NS_ASSERTION(unitOK, "unexpected unit");
2807 item->mRadius = tempCoord.GetCoordValue();
2808 } else {
2809 item->mRadius = 0;
2812 // Find the spread radius
2813 if (aUsesSpread && arr->Item(3).GetUnit() != eCSSUnit_Null) {
2814 unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(),
2815 SETCOORD_LENGTH, aContext, mPresContext, inherited);
2816 NS_ASSERTION(unitOK, "unexpected unit");
2817 item->mSpread = tempCoord.GetCoordValue();
2818 } else {
2819 item->mSpread = 0;
2822 if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
2823 item->mHasColor = PR_TRUE;
2824 // 2nd argument can be bogus since inherit is not a valid color
2825 unitOK = SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor,
2826 inherited);
2827 NS_ASSERTION(unitOK, "unexpected unit");
2831 NS_ADDREF(shadowList);
2832 return shadowList;
2835 const void*
2836 nsRuleNode::ComputeTextData(void* aStartStruct,
2837 const nsRuleDataStruct& aData,
2838 nsStyleContext* aContext,
2839 nsRuleNode* aHighestNode,
2840 const RuleDetail aRuleDetail, PRBool aInherited)
2842 COMPUTE_START_INHERITED(Text, (), text, parentText, Text, textData)
2844 // letter-spacing: normal, length, inherit
2845 SetCoord(textData.mLetterSpacing, text->mLetterSpacing, parentText->mLetterSpacing,
2846 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL,
2847 aContext, mPresContext, inherited);
2849 // text-shadow: none, list, inherit, initial
2850 nsCSSValueList* list = textData.mTextShadow;
2851 if (list) {
2852 text->mTextShadow = nsnull;
2854 // Don't need to handle none/initial explicitly: The above assignment
2855 // takes care of that
2856 if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
2857 inherited = PR_TRUE;
2858 text->mTextShadow = parentText->mTextShadow;
2859 } else if (eCSSUnit_Array == list->mValue.GetUnit()) {
2860 // List of arrays
2861 text->mTextShadow = GetShadowData(list, aContext, PR_FALSE, inherited);
2865 // line-height: normal, number, length, percent, inherit
2866 if (eCSSUnit_Percent == textData.mLineHeight.GetUnit()) {
2867 inherited = PR_TRUE;
2868 // Use |mFont.size| to pick up minimum font size.
2869 text->mLineHeight.SetCoordValue(
2870 nscoord(float(aContext->GetStyleFont()->mFont.size) *
2871 textData.mLineHeight.GetPercentValue()));
2873 else if (eCSSUnit_Initial == textData.mLineHeight.GetUnit() ||
2874 eCSSUnit_System_Font == textData.mLineHeight.GetUnit()) {
2875 text->mLineHeight.SetNormalValue();
2877 else {
2878 SetCoord(textData.mLineHeight, text->mLineHeight, parentText->mLineHeight,
2879 SETCOORD_LH | SETCOORD_FACTOR | SETCOORD_NORMAL,
2880 aContext, mPresContext, inherited);
2881 if (textData.mLineHeight.IsFixedLengthUnit() ||
2882 textData.mLineHeight.GetUnit() == eCSSUnit_Pixel) {
2883 nscoord lh = nsStyleFont::ZoomText(mPresContext,
2884 text->mLineHeight.GetCoordValue());
2885 nscoord minimumFontSize =
2886 mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
2888 if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
2889 // If we applied a minimum font size, scale the line height by
2890 // the same ratio. (If we *might* have applied a minimum font
2891 // size, we can't cache in the rule tree.)
2892 inherited = PR_TRUE;
2893 const nsStyleFont *font = aContext->GetStyleFont();
2894 if (font->mSize != 0) {
2895 lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
2896 } else {
2897 lh = minimumFontSize;
2900 text->mLineHeight.SetCoordValue(lh);
2905 // text-align: enum, string, inherit, initial
2906 if (eCSSUnit_String == textData.mTextAlign.GetUnit()) {
2907 NS_NOTYETIMPLEMENTED("align string");
2908 } else
2909 SetDiscrete(textData.mTextAlign, text->mTextAlign, inherited,
2910 SETDSC_ENUMERATED, parentText->mTextAlign,
2911 NS_STYLE_TEXT_ALIGN_DEFAULT,
2912 0, 0, 0, 0);
2914 // text-indent: length, percent, inherit, initial
2915 SetCoord(textData.mTextIndent, text->mTextIndent, parentText->mTextIndent,
2916 SETCOORD_LPH | SETCOORD_INITIAL_ZERO, aContext,
2917 mPresContext, inherited);
2919 // text-transform: enum, none, inherit, initial
2920 SetDiscrete(textData.mTextTransform, text->mTextTransform, inherited,
2921 SETDSC_ENUMERATED | SETDSC_NONE, parentText->mTextTransform,
2922 NS_STYLE_TEXT_TRANSFORM_NONE, 0,
2923 NS_STYLE_TEXT_TRANSFORM_NONE, 0, 0);
2925 // white-space: enum, normal, inherit, initial
2926 SetDiscrete(textData.mWhiteSpace, text->mWhiteSpace, inherited,
2927 SETDSC_ENUMERATED | SETDSC_NORMAL, parentText->mWhiteSpace,
2928 NS_STYLE_WHITESPACE_NORMAL, 0, 0,
2929 NS_STYLE_WHITESPACE_NORMAL, 0);
2931 // word-spacing: normal, length, inherit
2932 SetCoord(textData.mWordSpacing, text->mWordSpacing, parentText->mWordSpacing,
2933 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL,
2934 aContext, mPresContext, inherited);
2936 // word-wrap: enum, normal, inherit, initial
2937 SetDiscrete(textData.mWordWrap, text->mWordWrap, inherited,
2938 SETDSC_ENUMERATED | SETDSC_NORMAL, parentText->mWordWrap,
2939 NS_STYLE_WORDWRAP_NORMAL, 0, 0,
2940 NS_STYLE_WORDWRAP_NORMAL, 0);
2942 COMPUTE_END_INHERITED(Text, text)
2945 const void*
2946 nsRuleNode::ComputeTextResetData(void* aStartStruct,
2947 const nsRuleDataStruct& aData,
2948 nsStyleContext* aContext,
2949 nsRuleNode* aHighestNode,
2950 const RuleDetail aRuleDetail, PRBool aInherited)
2952 COMPUTE_START_RESET(TextReset, (), text, parentText, Text, textData)
2954 // vertical-align: enum, length, percent, inherit
2955 if (!SetCoord(textData.mVerticalAlign, text->mVerticalAlign,
2956 parentText->mVerticalAlign, SETCOORD_LPH | SETCOORD_ENUMERATED,
2957 aContext, mPresContext, inherited)) {
2958 if (eCSSUnit_Initial == textData.mVerticalAlign.GetUnit()) {
2959 text->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,
2960 eStyleUnit_Enumerated);
2964 // text-decoration: none, enum (bit field), inherit, initial
2965 if (eCSSUnit_Enumerated == textData.mDecoration.GetUnit()) {
2966 PRInt32 td = textData.mDecoration.GetIntValue();
2967 text->mTextDecoration = td;
2968 if (td & NS_STYLE_TEXT_DECORATION_PREF_ANCHORS) {
2969 PRBool underlineLinks =
2970 mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
2971 if (underlineLinks) {
2972 text->mTextDecoration |= NS_STYLE_TEXT_DECORATION_UNDERLINE;
2974 else {
2975 text->mTextDecoration &= ~NS_STYLE_TEXT_DECORATION_UNDERLINE;
2979 else
2980 SetDiscrete(textData.mDecoration, text->mTextDecoration, inherited,
2981 SETDSC_NONE,
2982 parentText->mTextDecoration,
2983 NS_STYLE_TEXT_DECORATION_NONE, 0,
2984 NS_STYLE_TEXT_DECORATION_NONE, 0, 0);
2986 // unicode-bidi: enum, normal, inherit, initial
2987 SetDiscrete(textData.mUnicodeBidi, text->mUnicodeBidi, inherited,
2988 SETDSC_ENUMERATED | SETDSC_NORMAL,
2989 parentText->mUnicodeBidi,
2990 NS_STYLE_UNICODE_BIDI_NORMAL, 0, 0,
2991 NS_STYLE_UNICODE_BIDI_NORMAL, 0);
2993 COMPUTE_END_RESET(TextReset, text)
2996 const void*
2997 nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
2998 const nsRuleDataStruct& aData,
2999 nsStyleContext* aContext,
3000 nsRuleNode* aHighestNode,
3001 const RuleDetail aRuleDetail,
3002 PRBool aInherited)
3004 COMPUTE_START_INHERITED(UserInterface, (), ui, parentUI,
3005 UserInterface, uiData)
3007 // cursor: enum, auto, url, inherit
3008 nsCSSValueList* list = uiData.mCursor;
3009 if (nsnull != list) {
3010 delete [] ui->mCursorArray;
3011 ui->mCursorArray = nsnull;
3012 ui->mCursorArrayLength = 0;
3014 if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
3015 inherited = PR_TRUE;
3016 ui->mCursor = parentUI->mCursor;
3017 ui->CopyCursorArrayFrom(*parentUI);
3019 else if (eCSSUnit_Initial == list->mValue.GetUnit()) {
3020 ui->mCursor = NS_STYLE_CURSOR_AUTO;
3022 else {
3023 // The parser will never create a list that is *all* URL values --
3024 // that's invalid.
3025 PRUint32 arrayLength = 0;
3026 nsCSSValueList* list2 = list;
3027 for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext)
3028 if (list->mValue.GetArrayValue()->Item(0).GetImageValue())
3029 ++arrayLength;
3031 if (arrayLength != 0) {
3032 ui->mCursorArray = new nsCursorImage[arrayLength];
3033 if (ui->mCursorArray) {
3034 ui->mCursorArrayLength = arrayLength;
3036 for (nsCursorImage *item = ui->mCursorArray;
3037 list2->mValue.GetUnit() == eCSSUnit_Array;
3038 list2 = list2->mNext) {
3039 nsCSSValue::Array *arr = list2->mValue.GetArrayValue();
3040 imgIRequest *req = arr->Item(0).GetImageValue();
3041 if (req) {
3042 item->mImage = req;
3043 if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
3044 item->mHaveHotspot = PR_TRUE;
3045 item->mHotspotX = arr->Item(1).GetFloatValue(),
3046 item->mHotspotY = arr->Item(2).GetFloatValue();
3048 ++item;
3054 NS_ASSERTION(list, "Must have non-array value at the end");
3055 NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated ||
3056 list->mValue.GetUnit() == eCSSUnit_Auto,
3057 "Unexpected fallback value at end of cursor list");
3059 if (eCSSUnit_Enumerated == list->mValue.GetUnit()) {
3060 ui->mCursor = list->mValue.GetIntValue();
3062 else if (eCSSUnit_Auto == list->mValue.GetUnit()) {
3063 ui->mCursor = NS_STYLE_CURSOR_AUTO;
3068 // user-input: auto, none, enum, inherit, initial
3069 SetDiscrete(uiData.mUserInput, ui->mUserInput, inherited,
3070 SETDSC_ENUMERATED | SETDSC_NONE | SETDSC_AUTO,
3071 parentUI->mUserInput,
3072 NS_STYLE_USER_INPUT_AUTO,
3073 NS_STYLE_USER_INPUT_AUTO,
3074 NS_STYLE_USER_INPUT_NONE,
3075 0, 0);
3077 // user-modify: enum, inherit, initial
3078 SetDiscrete(uiData.mUserModify, ui->mUserModify, inherited,
3079 SETDSC_ENUMERATED,
3080 parentUI->mUserModify,
3081 NS_STYLE_USER_MODIFY_READ_ONLY,
3082 0, 0, 0, 0);
3084 // user-focus: none, normal, enum, inherit, initial
3085 SetDiscrete(uiData.mUserFocus, ui->mUserFocus, inherited,
3086 SETDSC_ENUMERATED | SETDSC_NONE | SETDSC_NORMAL,
3087 parentUI->mUserFocus,
3088 NS_STYLE_USER_FOCUS_NONE,
3090 NS_STYLE_USER_FOCUS_NONE,
3091 NS_STYLE_USER_FOCUS_NORMAL,
3094 COMPUTE_END_INHERITED(UserInterface, ui)
3097 const void*
3098 nsRuleNode::ComputeUIResetData(void* aStartStruct,
3099 const nsRuleDataStruct& aData,
3100 nsStyleContext* aContext,
3101 nsRuleNode* aHighestNode,
3102 const RuleDetail aRuleDetail, PRBool aInherited)
3104 COMPUTE_START_RESET(UIReset, (), ui, parentUI, UserInterface, uiData)
3106 // user-select: auto, none, enum, inherit, initial
3107 SetDiscrete(uiData.mUserSelect, ui->mUserSelect, inherited,
3108 SETDSC_ENUMERATED | SETDSC_NONE | SETDSC_AUTO,
3109 parentUI->mUserSelect,
3110 NS_STYLE_USER_SELECT_AUTO,
3111 NS_STYLE_USER_SELECT_AUTO,
3112 NS_STYLE_USER_SELECT_NONE,
3113 0, 0);
3115 // ime-mode: auto, normal, enum, inherit, initial
3116 SetDiscrete(uiData.mIMEMode, ui->mIMEMode, inherited,
3117 SETDSC_ENUMERATED | SETDSC_NORMAL | SETDSC_AUTO,
3118 parentUI->mIMEMode,
3119 NS_STYLE_IME_MODE_AUTO,
3120 NS_STYLE_IME_MODE_AUTO,
3122 NS_STYLE_IME_MODE_NORMAL,
3125 // force-broken-image-icons: integer, inherit, initial
3126 SetDiscrete(uiData.mForceBrokenImageIcon, ui->mForceBrokenImageIcon,
3127 inherited,
3128 SETDSC_INTEGER,
3129 parentUI->mForceBrokenImageIcon,
3130 0, 0, 0, 0, 0);
3132 // -moz-window-shadow: enum, none, inherit, initial
3133 SetDiscrete(uiData.mWindowShadow, ui->mWindowShadow, inherited,
3134 SETDSC_ENUMERATED | SETDSC_NONE, parentUI->mWindowShadow,
3135 NS_STYLE_WINDOW_SHADOW_DEFAULT, 0,
3136 NS_STYLE_WINDOW_SHADOW_NONE, 0, 0);
3138 COMPUTE_END_RESET(UIReset, ui)
3141 /* Given a -moz-transform token stream, accumulates them into an
3142 * nsStyleTransformMatrix
3144 * @param aList The nsCSSValueList of arrays to read into transform functions.
3145 * @param aContext The style context to use for unit conversion.
3146 * @param aPresContext The presentation context to use for unit conversion
3147 * @param aInherited If the value is inherited, this is set to PR_TRUE.
3148 * @return An nsStyleTransformMatrix corresponding to the net transform.
3150 static nsStyleTransformMatrix ReadTransforms(const nsCSSValueList* aList,
3151 nsStyleContext* aContext,
3152 nsPresContext* aPresContext,
3153 PRBool &aInherited)
3155 nsStyleTransformMatrix result;
3157 for (const nsCSSValueList* curr = aList; curr != nsnull; curr = curr->mNext) {
3158 const nsCSSValue &currElem = curr->mValue;
3159 NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
3160 "Stream should consist solely of functions!");
3161 NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
3162 "Incoming function is too short!");
3164 /* Read in a single transform matrix, then accumulate it with the total. */
3165 nsStyleTransformMatrix currMatrix;
3166 currMatrix.SetToTransformFunction(currElem.GetArrayValue(), aContext,
3167 aPresContext, aInherited);
3168 result *= currMatrix;
3170 return result;
3173 const void*
3174 nsRuleNode::ComputeDisplayData(void* aStartStruct,
3175 const nsRuleDataStruct& aData,
3176 nsStyleContext* aContext,
3177 nsRuleNode* aHighestNode,
3178 const RuleDetail aRuleDetail, PRBool aInherited)
3180 COMPUTE_START_RESET(Display, (), display, parentDisplay,
3181 Display, displayData)
3183 // opacity: factor, inherit, initial
3184 SetFactor(displayData.mOpacity, display->mOpacity, inherited,
3185 parentDisplay->mOpacity, 1.0f, SETFCT_OPACITY);
3187 // display: enum, none, inherit, initial
3188 SetDiscrete(displayData.mDisplay, display->mDisplay, inherited,
3189 SETDSC_ENUMERATED | SETDSC_NONE, parentDisplay->mDisplay,
3190 NS_STYLE_DISPLAY_INLINE, 0,
3191 NS_STYLE_DISPLAY_NONE, 0, 0);
3193 // appearance: enum, none, inherit, initial
3194 SetDiscrete(displayData.mAppearance, display->mAppearance, inherited,
3195 SETDSC_ENUMERATED | SETDSC_NONE, parentDisplay->mAppearance,
3196 NS_THEME_NONE, 0,
3197 NS_THEME_NONE, 0, 0);
3199 // binding: url, none, inherit
3200 if (eCSSUnit_URL == displayData.mBinding.GetUnit()) {
3201 nsCSSValue::URL* url = displayData.mBinding.GetURLStructValue();
3202 NS_ASSERTION(url, "What's going on here?");
3204 if (NS_LIKELY(url->mURI)) {
3205 display->mBinding = url;
3206 } else {
3207 display->mBinding = nsnull;
3210 else if (eCSSUnit_None == displayData.mBinding.GetUnit() ||
3211 eCSSUnit_Initial == displayData.mBinding.GetUnit()) {
3212 display->mBinding = nsnull;
3214 else if (eCSSUnit_Inherit == displayData.mBinding.GetUnit()) {
3215 inherited = PR_TRUE;
3216 display->mBinding = parentDisplay->mBinding;
3219 // position: enum, inherit, initial
3220 SetDiscrete(displayData.mPosition, display->mPosition, inherited,
3221 SETDSC_ENUMERATED, parentDisplay->mPosition,
3222 NS_STYLE_POSITION_STATIC, 0, 0, 0, 0);
3224 // clear: enum, none, inherit, initial
3225 SetDiscrete(displayData.mClear, display->mBreakType, inherited,
3226 SETDSC_ENUMERATED | SETDSC_NONE, parentDisplay->mBreakType,
3227 NS_STYLE_CLEAR_NONE, 0,
3228 NS_STYLE_CLEAR_NONE, 0, 0);
3230 // temp fix for bug 24000
3231 // Map 'auto' and 'avoid' to PR_FALSE, and 'always', 'left', and
3232 // 'right' to PR_TRUE.
3233 // "A conforming user agent may interpret the values 'left' and
3234 // 'right' as 'always'." - CSS2.1, section 13.3.1
3235 if (eCSSUnit_Enumerated == displayData.mBreakBefore.GetUnit()) {
3236 display->mBreakBefore = (NS_STYLE_PAGE_BREAK_AVOID != displayData.mBreakBefore.GetIntValue());
3238 else if (eCSSUnit_Auto == displayData.mBreakBefore.GetUnit() ||
3239 eCSSUnit_Initial == displayData.mBreakBefore.GetUnit()) {
3240 display->mBreakBefore = PR_FALSE;
3242 else if (eCSSUnit_Inherit == displayData.mBreakBefore.GetUnit()) {
3243 inherited = PR_TRUE;
3244 display->mBreakBefore = parentDisplay->mBreakBefore;
3247 if (eCSSUnit_Enumerated == displayData.mBreakAfter.GetUnit()) {
3248 display->mBreakAfter = (NS_STYLE_PAGE_BREAK_AVOID != displayData.mBreakAfter.GetIntValue());
3250 else if (eCSSUnit_Auto == displayData.mBreakAfter.GetUnit() ||
3251 eCSSUnit_Initial == displayData.mBreakAfter.GetUnit()) {
3252 display->mBreakAfter = PR_FALSE;
3254 else if (eCSSUnit_Inherit == displayData.mBreakAfter.GetUnit()) {
3255 inherited = PR_TRUE;
3256 display->mBreakAfter = parentDisplay->mBreakAfter;
3258 // end temp fix
3260 // float: enum, none, inherit, initial
3261 SetDiscrete(displayData.mFloat, display->mFloats, inherited,
3262 SETDSC_ENUMERATED | SETDSC_NONE, parentDisplay->mFloats,
3263 NS_STYLE_FLOAT_NONE, 0,
3264 NS_STYLE_FLOAT_NONE, 0, 0);
3266 // overflow-x: enum, auto, inherit, initial
3267 SetDiscrete(displayData.mOverflowX, display->mOverflowX, inherited,
3268 SETDSC_ENUMERATED | SETDSC_AUTO,
3269 parentDisplay->mOverflowX,
3270 NS_STYLE_OVERFLOW_VISIBLE,
3271 NS_STYLE_OVERFLOW_AUTO,
3272 0, 0, 0);
3274 // overflow-y: enum, auto, inherit, initial
3275 SetDiscrete(displayData.mOverflowY, display->mOverflowY, inherited,
3276 SETDSC_ENUMERATED | SETDSC_AUTO,
3277 parentDisplay->mOverflowY,
3278 NS_STYLE_OVERFLOW_VISIBLE,
3279 NS_STYLE_OVERFLOW_AUTO,
3280 0, 0, 0);
3282 // CSS3 overflow-x and overflow-y require some fixup as well in some
3283 // cases. NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
3284 // meaningful only when used in both dimensions.
3285 if (display->mOverflowX != display->mOverflowY &&
3286 (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
3287 display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
3288 display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
3289 display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
3290 // We can't store in the rule tree since a more specific rule might
3291 // change these conditions.
3292 inherited = PR_TRUE;
3294 // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
3295 // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
3296 if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
3297 display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
3298 if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
3299 display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
3301 // If 'visible' is specified but doesn't match the other dimension, it
3302 // turns into 'auto'.
3303 if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
3304 display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
3305 if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
3306 display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
3309 // clip property: length, auto, inherit
3310 if (eCSSUnit_Inherit == displayData.mClip.mTop.GetUnit()) { // if one is inherit, they all are
3311 inherited = PR_TRUE;
3312 display->mClipFlags = parentDisplay->mClipFlags;
3313 display->mClip = parentDisplay->mClip;
3315 // if one is initial, they all are
3316 else if (eCSSUnit_Initial == displayData.mClip.mTop.GetUnit()) {
3317 display->mClipFlags = NS_STYLE_CLIP_AUTO;
3318 display->mClip.SetRect(0,0,0,0);
3320 else {
3321 PRBool fullAuto = PR_TRUE;
3323 display->mClipFlags = 0; // clear it
3325 if (eCSSUnit_Auto == displayData.mClip.mTop.GetUnit()) {
3326 display->mClip.y = 0;
3327 display->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
3329 else if (displayData.mClip.mTop.IsLengthUnit()) {
3330 display->mClip.y = CalcLength(displayData.mClip.mTop, aContext, mPresContext, inherited);
3331 fullAuto = PR_FALSE;
3333 if (eCSSUnit_Auto == displayData.mClip.mBottom.GetUnit()) {
3334 // Setting to NS_MAXSIZE for the 'auto' case ensures that
3335 // the clip rect is nonempty. It is important that mClip be
3336 // nonempty if the actual clip rect could be nonempty.
3337 display->mClip.height = NS_MAXSIZE;
3338 display->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
3340 else if (displayData.mClip.mBottom.IsLengthUnit()) {
3341 display->mClip.height = CalcLength(displayData.mClip.mBottom, aContext, mPresContext, inherited) -
3342 display->mClip.y;
3343 fullAuto = PR_FALSE;
3345 if (eCSSUnit_Auto == displayData.mClip.mLeft.GetUnit()) {
3346 display->mClip.x = 0;
3347 display->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
3349 else if (displayData.mClip.mLeft.IsLengthUnit()) {
3350 display->mClip.x = CalcLength(displayData.mClip.mLeft, aContext, mPresContext, inherited);
3351 fullAuto = PR_FALSE;
3353 if (eCSSUnit_Auto == displayData.mClip.mRight.GetUnit()) {
3354 // Setting to NS_MAXSIZE for the 'auto' case ensures that
3355 // the clip rect is nonempty. It is important that mClip be
3356 // nonempty if the actual clip rect could be nonempty.
3357 display->mClip.width = NS_MAXSIZE;
3358 display->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
3360 else if (displayData.mClip.mRight.IsLengthUnit()) {
3361 display->mClip.width = CalcLength(displayData.mClip.mRight, aContext, mPresContext, inherited) -
3362 display->mClip.x;
3363 fullAuto = PR_FALSE;
3365 display->mClipFlags &= ~NS_STYLE_CLIP_TYPE_MASK;
3366 if (fullAuto) {
3367 display->mClipFlags |= NS_STYLE_CLIP_AUTO;
3369 else {
3370 display->mClipFlags |= NS_STYLE_CLIP_RECT;
3374 if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
3375 // CSS2 9.7 specifies display type corrections dealing with 'float'
3376 // and 'position'. Since generated content can't be floated or
3377 // positioned, we can deal with it here.
3379 if (nsCSSPseudoElements::firstLetter == aContext->GetPseudoType()) {
3380 // a non-floating first-letter must be inline
3381 // XXX this fix can go away once bug 103189 is fixed correctly
3382 display->mDisplay = NS_STYLE_DISPLAY_INLINE;
3384 // We can't cache the data in the rule tree since if a more specific
3385 // rule has 'float: left' we'll end up with the wrong 'display'
3386 // property.
3387 inherited = PR_TRUE;
3390 if (display->IsAbsolutelyPositioned()) {
3391 // 1) if position is 'absolute' or 'fixed' then display must be
3392 // block-level and float must be 'none'
3394 // Backup original display value for calculation of a hypothetical
3395 // box (CSS2 10.6.4/10.6.5).
3396 // See nsHTMLReflowState::CalculateHypotheticalBox
3397 display->mOriginalDisplay = display->mDisplay;
3398 EnsureBlockDisplay(display->mDisplay);
3399 display->mFloats = NS_STYLE_FLOAT_NONE;
3401 // We can't cache the data in the rule tree since if a more specific
3402 // rule has 'position: static' we'll end up with problems with the
3403 // 'display' and 'float' properties.
3404 inherited = PR_TRUE;
3405 } else if (display->mFloats != NS_STYLE_FLOAT_NONE) {
3406 // 2) if float is not none, and display is not none, then we must
3407 // set a block-level 'display' type per CSS2.1 section 9.7.
3409 EnsureBlockDisplay(display->mDisplay);
3411 // We can't cache the data in the rule tree since if a more specific
3412 // rule has 'float: none' we'll end up with the wrong 'display'
3413 // property.
3414 inherited = PR_TRUE;
3419 /* Convert the nsCSSValueList into an nsTArray<nsTransformFunction *>. */
3420 const nsCSSValueList *head = displayData.mTransform;
3422 if (head != nsnull) {
3423 /* There is a chance that we will discover that
3424 * the transform property has been set to 'none,' 'initial,' or 'inherit.'
3425 * If so, process appropriately.
3428 /* If it's 'none,' indicate that there are no transforms. */
3429 if (head->mValue.GetUnit() == eCSSUnit_None)
3430 display->mTransformPresent = PR_FALSE;
3432 /* If we need to inherit, do so by making a full deep-copy. */
3433 else if (head->mValue.GetUnit() == eCSSUnit_Inherit) {
3434 display->mTransformPresent = parentDisplay->mTransformPresent;
3435 if (parentDisplay->mTransformPresent)
3436 display->mTransform = parentDisplay->mTransform;
3437 inherited = PR_TRUE;
3439 /* If it's 'initial', then we reset to empty. */
3440 else if (head->mValue.GetUnit() == eCSSUnit_Initial)
3441 display->mTransformPresent = PR_FALSE;
3443 /* Otherwise, we are looking at a list of CSS tokens. We'll read each of
3444 * them in as an array of nsTransformFunction objects, then will accumulate
3445 * them all together to form the final transform matrix.
3447 else {
3449 display->mTransform =
3450 ReadTransforms(head, aContext, mPresContext, inherited);
3452 /* Make sure to say that this data is valid! */
3453 display->mTransformPresent = PR_TRUE;
3457 /* Convert -moz-transform-origin. */
3458 if (displayData.mTransformOrigin.mXValue.GetUnit() != eCSSUnit_Null ||
3459 displayData.mTransformOrigin.mXValue.GetUnit() != eCSSUnit_Null) {
3461 /* If X coordinate is an enumerated type, handle it explicitly. */
3462 if (eCSSUnit_Enumerated == displayData.mTransformOrigin.mXValue.GetUnit())
3463 display->mTransformOrigin[0].SetPercentValue
3464 (GetFloatFromBoxPosition
3465 (displayData.mTransformOrigin.mXValue.GetIntValue()));
3466 else {
3467 /* Convert lengths, percents, and inherit. Default value is 50%. */
3468 #ifdef DEBUG
3469 PRBool result =
3470 #endif
3471 SetCoord(displayData.mTransformOrigin.mXValue,
3472 display->mTransformOrigin[0],
3473 parentDisplay->mTransformOrigin[0],
3474 SETCOORD_LPH | SETCOORD_INITIAL_HALF,
3475 aContext, mPresContext, aInherited);
3476 NS_ASSERTION(result, "Malformed -moz-transform-origin parse!");
3479 /* If Y coordinate is an enumerated type, handle it explicitly. */
3480 if (eCSSUnit_Enumerated == displayData.mTransformOrigin.mYValue.GetUnit())
3481 display->mTransformOrigin[1].SetPercentValue
3482 (GetFloatFromBoxPosition
3483 (displayData.mTransformOrigin.mYValue.GetIntValue()));
3484 else {
3485 /* Convert lengths, percents, initial, inherit. */
3486 #ifdef DEBUG
3487 PRBool result =
3488 #endif
3489 SetCoord(displayData.mTransformOrigin.mYValue,
3490 display->mTransformOrigin[1],
3491 parentDisplay->mTransformOrigin[1],
3492 SETCOORD_LPH | SETCOORD_INITIAL_HALF,
3493 aContext, mPresContext, aInherited);
3494 NS_ASSERTION(result, "Malformed -moz-transform-origin parse!");
3498 COMPUTE_END_RESET(Display, display)
3501 const void*
3502 nsRuleNode::ComputeVisibilityData(void* aStartStruct,
3503 const nsRuleDataStruct& aData,
3504 nsStyleContext* aContext,
3505 nsRuleNode* aHighestNode,
3506 const RuleDetail aRuleDetail, PRBool aInherited)
3508 COMPUTE_START_INHERITED(Visibility, (mPresContext),
3509 visibility, parentVisibility,
3510 Display, displayData)
3512 // direction: enum, inherit, initial
3513 SetDiscrete(displayData.mDirection, visibility->mDirection, inherited,
3514 SETDSC_ENUMERATED, parentVisibility->mDirection,
3515 (GET_BIDI_OPTION_DIRECTION(mPresContext->GetBidi())
3516 == IBMBIDI_TEXTDIRECTION_RTL)
3517 ? NS_STYLE_DIRECTION_RTL : NS_STYLE_DIRECTION_LTR,
3518 0, 0, 0, 0);
3520 // visibility: enum, inherit, initial
3521 SetDiscrete(displayData.mVisibility, visibility->mVisible, inherited,
3522 SETDSC_ENUMERATED, parentVisibility->mVisible,
3523 NS_STYLE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
3525 // lang: string, inherit
3526 // this is not a real CSS property, it is a html attribute mapped to CSS struture
3527 if (eCSSUnit_String == displayData.mLang.GetUnit()) {
3528 if (!gLangService) {
3529 CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService);
3532 if (gLangService) {
3533 nsAutoString lang;
3534 displayData.mLang.GetStringValue(lang);
3535 visibility->mLangGroup = gLangService->LookupLanguage(lang);
3539 COMPUTE_END_INHERITED(Visibility, visibility)
3542 const void*
3543 nsRuleNode::ComputeColorData(void* aStartStruct,
3544 const nsRuleDataStruct& aData,
3545 nsStyleContext* aContext,
3546 nsRuleNode* aHighestNode,
3547 const RuleDetail aRuleDetail, PRBool aInherited)
3549 COMPUTE_START_INHERITED(Color, (mPresContext), color, parentColor,
3550 Color, colorData)
3552 // color: color, string, inherit
3553 // Special case for currentColor. According to CSS3, setting color to 'currentColor'
3554 // should behave as if it is inherited
3555 if (colorData.mColor.GetUnit() == eCSSUnit_EnumColor &&
3556 colorData.mColor.GetIntValue() == NS_COLOR_CURRENTCOLOR) {
3557 color->mColor = parentColor->mColor;
3558 inherited = PR_TRUE;
3560 else if (colorData.mColor.GetUnit() == eCSSUnit_Initial) {
3561 color->mColor = mPresContext->DefaultColor();
3563 else {
3564 SetColor(colorData.mColor, parentColor->mColor, mPresContext, aContext, color->mColor,
3565 inherited);
3568 COMPUTE_END_INHERITED(Color, color)
3571 const void*
3572 nsRuleNode::ComputeBackgroundData(void* aStartStruct,
3573 const nsRuleDataStruct& aData,
3574 nsStyleContext* aContext,
3575 nsRuleNode* aHighestNode,
3576 const RuleDetail aRuleDetail,
3577 PRBool aInherited)
3579 COMPUTE_START_RESET(Background, (), bg, parentBG, Color, colorData)
3581 // save parentFlags in case bg == parentBG and we clobber them later
3582 PRUint8 parentFlags = parentBG->mBackgroundFlags;
3584 // background-color: color, string, inherit
3585 if (eCSSUnit_Initial == colorData.mBackColor.GetUnit()) {
3586 bg->mBackgroundColor = NS_RGBA(0, 0, 0, 0);
3587 } else if (!SetColor(colorData.mBackColor, parentBG->mBackgroundColor,
3588 mPresContext, aContext, bg->mBackgroundColor,
3589 inherited)) {
3590 NS_ASSERTION(eCSSUnit_Null == colorData.mBackColor.GetUnit(),
3591 "unexpected color unit");
3594 // background-image: url (stored as image), none, inherit
3595 if (eCSSUnit_Image == colorData.mBackImage.GetUnit()) {
3596 bg->mBackgroundImage = colorData.mBackImage.GetImageValue();
3598 else if (eCSSUnit_None == colorData.mBackImage.GetUnit() ||
3599 eCSSUnit_Initial == colorData.mBackImage.GetUnit()) {
3600 bg->mBackgroundImage = nsnull;
3602 else if (eCSSUnit_Inherit == colorData.mBackImage.GetUnit()) {
3603 inherited = PR_TRUE;
3604 bg->mBackgroundImage = parentBG->mBackgroundImage;
3607 if (bg->mBackgroundImage) {
3608 bg->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE;
3609 } else {
3610 bg->mBackgroundFlags |= NS_STYLE_BG_IMAGE_NONE;
3613 // background-repeat: enum, inherit, initial
3614 SetDiscrete(colorData.mBackRepeat, bg->mBackgroundRepeat, inherited,
3615 SETDSC_ENUMERATED, parentBG->mBackgroundRepeat,
3616 NS_STYLE_BG_REPEAT_XY, 0, 0, 0, 0);
3618 // background-attachment: enum, inherit, initial
3619 SetDiscrete(colorData.mBackAttachment, bg->mBackgroundAttachment, inherited,
3620 SETDSC_ENUMERATED, parentBG->mBackgroundAttachment,
3621 NS_STYLE_BG_ATTACHMENT_SCROLL, 0, 0, 0, 0);
3623 // background-clip: enum, inherit, initial
3624 SetDiscrete(colorData.mBackClip, bg->mBackgroundClip, inherited,
3625 SETDSC_ENUMERATED, parentBG->mBackgroundClip,
3626 NS_STYLE_BG_CLIP_BORDER, 0, 0, 0, 0);
3628 // background-inline-policy: enum, inherit, initial
3629 SetDiscrete(colorData.mBackInlinePolicy, bg->mBackgroundInlinePolicy,
3630 inherited, SETDSC_ENUMERATED,
3631 parentBG->mBackgroundInlinePolicy,
3632 NS_STYLE_BG_INLINE_POLICY_CONTINUOUS, 0, 0, 0, 0);
3634 // background-origin: enum, inherit, initial
3635 SetDiscrete(colorData.mBackOrigin, bg->mBackgroundOrigin, inherited,
3636 SETDSC_ENUMERATED, parentBG->mBackgroundOrigin,
3637 NS_STYLE_BG_ORIGIN_PADDING, 0, 0, 0, 0);
3639 // background-position: enum, length, percent (flags), inherit
3640 if (eCSSUnit_Percent == colorData.mBackPosition.mXValue.GetUnit()) {
3641 bg->mBackgroundXPosition.mFloat = colorData.mBackPosition.mXValue.GetPercentValue();
3642 bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PERCENT;
3643 bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH;
3645 else if (colorData.mBackPosition.mXValue.IsLengthUnit()) {
3646 bg->mBackgroundXPosition.mCoord = CalcLength(colorData.mBackPosition.mXValue,
3647 aContext, mPresContext, inherited);
3648 bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_LENGTH;
3649 bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_PERCENT;
3651 else if (eCSSUnit_Enumerated == colorData.mBackPosition.mXValue.GetUnit()) {
3652 bg->mBackgroundXPosition.mFloat =
3653 GetFloatFromBoxPosition(colorData.mBackPosition.mXValue.GetIntValue());
3655 bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PERCENT;
3656 bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH;
3658 else if (eCSSUnit_Inherit == colorData.mBackPosition.mXValue.GetUnit()) {
3659 inherited = PR_TRUE;
3660 bg->mBackgroundXPosition = parentBG->mBackgroundXPosition;
3661 bg->mBackgroundFlags &= ~(NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT);
3662 bg->mBackgroundFlags |= (parentFlags & (NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT));
3664 else if (eCSSUnit_Initial == colorData.mBackPosition.mXValue.GetUnit()) {
3665 bg->mBackgroundFlags &= ~(NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT);
3668 if (eCSSUnit_Percent == colorData.mBackPosition.mYValue.GetUnit()) {
3669 bg->mBackgroundYPosition.mFloat = colorData.mBackPosition.mYValue.GetPercentValue();
3670 bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PERCENT;
3671 bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
3673 else if (colorData.mBackPosition.mYValue.IsLengthUnit()) {
3674 bg->mBackgroundYPosition.mCoord = CalcLength(colorData.mBackPosition.mYValue,
3675 aContext, mPresContext, inherited);
3676 bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_LENGTH;
3677 bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_PERCENT;
3679 else if (eCSSUnit_Enumerated == colorData.mBackPosition.mYValue.GetUnit()) {
3680 bg->mBackgroundYPosition.mFloat =
3681 GetFloatFromBoxPosition(colorData.mBackPosition.mYValue.GetIntValue());
3683 bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PERCENT;
3684 bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
3686 else if (eCSSUnit_Inherit == colorData.mBackPosition.mYValue.GetUnit()) {
3687 inherited = PR_TRUE;
3688 bg->mBackgroundYPosition = parentBG->mBackgroundYPosition;
3689 bg->mBackgroundFlags &= ~(NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT);
3690 bg->mBackgroundFlags |= (parentFlags & (NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT));
3692 else if (eCSSUnit_Initial == colorData.mBackPosition.mYValue.GetUnit()) {
3693 bg->mBackgroundFlags &= ~(NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT);
3696 COMPUTE_END_RESET(Background, bg)
3699 const void*
3700 nsRuleNode::ComputeMarginData(void* aStartStruct,
3701 const nsRuleDataStruct& aData,
3702 nsStyleContext* aContext,
3703 nsRuleNode* aHighestNode,
3704 const RuleDetail aRuleDetail, PRBool aInherited)
3706 COMPUTE_START_RESET(Margin, (), margin, parentMargin, Margin, marginData)
3708 // margin: length, percent, auto, inherit
3709 nsStyleCoord coord;
3710 nsCSSRect ourMargin(marginData.mMargin);
3711 AdjustLogicalBoxProp(aContext,
3712 marginData.mMarginLeftLTRSource,
3713 marginData.mMarginLeftRTLSource,
3714 marginData.mMarginStart, marginData.mMarginEnd,
3715 NS_SIDE_LEFT, ourMargin, inherited);
3716 AdjustLogicalBoxProp(aContext,
3717 marginData.mMarginRightLTRSource,
3718 marginData.mMarginRightRTLSource,
3719 marginData.mMarginEnd, marginData.mMarginStart,
3720 NS_SIDE_RIGHT, ourMargin, inherited);
3721 NS_FOR_CSS_SIDES(side) {
3722 nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
3723 if (SetCoord(ourMargin.*(nsCSSRect::sides[side]),
3724 coord, parentCoord, SETCOORD_LPAH | SETCOORD_INITIAL_ZERO,
3725 aContext, mPresContext, inherited)) {
3726 margin->mMargin.Set(side, coord);
3730 margin->RecalcData();
3731 COMPUTE_END_RESET(Margin, margin)
3734 const void*
3735 nsRuleNode::ComputeBorderData(void* aStartStruct,
3736 const nsRuleDataStruct& aData,
3737 nsStyleContext* aContext,
3738 nsRuleNode* aHighestNode,
3739 const RuleDetail aRuleDetail, PRBool aInherited)
3741 COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder,
3742 Margin, marginData)
3744 // -moz-box-shadow: none, list, inherit, initial
3745 nsCSSValueList* list = marginData.mBoxShadow;
3746 if (list) {
3747 // This handles 'none' and 'initial'
3748 border->mBoxShadow = nsnull;
3750 if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
3751 inherited = PR_TRUE;
3752 border->mBoxShadow = parentBorder->mBoxShadow;
3753 } else if (eCSSUnit_Array == list->mValue.GetUnit()) {
3754 // List of arrays
3755 border->mBoxShadow = GetShadowData(list, aContext, PR_TRUE, inherited);
3759 // border-width, border-*-width: length, enum, inherit
3760 nsStyleCoord coord;
3761 nsCSSRect ourBorderWidth(marginData.mBorderWidth);
3762 AdjustLogicalBoxProp(aContext,
3763 marginData.mBorderLeftWidthLTRSource,
3764 marginData.mBorderLeftWidthRTLSource,
3765 marginData.mBorderStartWidth,
3766 marginData.mBorderEndWidth,
3767 NS_SIDE_LEFT, ourBorderWidth, inherited);
3768 AdjustLogicalBoxProp(aContext,
3769 marginData.mBorderRightWidthLTRSource,
3770 marginData.mBorderRightWidthRTLSource,
3771 marginData.mBorderEndWidth,
3772 marginData.mBorderStartWidth,
3773 NS_SIDE_RIGHT, ourBorderWidth, inherited);
3774 { // scope for compilers with broken |for| loop scoping
3775 NS_FOR_CSS_SIDES(side) {
3776 const nsCSSValue &value = ourBorderWidth.*(nsCSSRect::sides[side]);
3777 NS_ASSERTION(eCSSUnit_Percent != value.GetUnit(),
3778 "Percentage borders not implemented yet "
3779 "If implementing, make sure to fix all consumers of "
3780 "nsStyleBorder, the IsPercentageAwareChild method, "
3781 "the nsAbsoluteContainingBlock::FrameDependsOnContainer "
3782 "method, the "
3783 "nsLineLayout::IsPercentageAwareReplacedElement method "
3784 "and probably some other places");
3785 if (eCSSUnit_Enumerated == value.GetUnit()) {
3786 NS_ASSERTION(value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
3787 value.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
3788 value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
3789 "Unexpected enum value");
3790 border->SetBorderWidth(side,
3791 (mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
3793 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
3794 else if (SetCoord(value, coord, nsStyleCoord(), SETCOORD_LENGTH,
3795 aContext, mPresContext, inherited)) {
3796 NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
3797 border->SetBorderWidth(side, coord.GetCoordValue());
3799 else if (eCSSUnit_Inherit == value.GetUnit()) {
3800 inherited = PR_TRUE;
3801 border->SetBorderWidth(side,
3802 parentBorder->GetComputedBorder().side(side));
3804 else if (eCSSUnit_Initial == value.GetUnit()) {
3805 border->SetBorderWidth(side,
3806 (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
3808 else {
3809 NS_ASSERTION(eCSSUnit_Null == value.GetUnit(),
3810 "missing case handling border width");
3815 // border-style, border-*-style: enum, none, inherit
3816 nsCSSRect ourStyle(marginData.mBorderStyle);
3817 AdjustLogicalBoxProp(aContext,
3818 marginData.mBorderLeftStyleLTRSource,
3819 marginData.mBorderLeftStyleRTLSource,
3820 marginData.mBorderStartStyle, marginData.mBorderEndStyle,
3821 NS_SIDE_LEFT, ourStyle, inherited);
3822 AdjustLogicalBoxProp(aContext,
3823 marginData.mBorderRightStyleLTRSource,
3824 marginData.mBorderRightStyleRTLSource,
3825 marginData.mBorderEndStyle, marginData.mBorderStartStyle,
3826 NS_SIDE_RIGHT, ourStyle, inherited);
3827 { // scope for compilers with broken |for| loop scoping
3828 NS_FOR_CSS_SIDES(side) {
3829 const nsCSSValue &value = ourStyle.*(nsCSSRect::sides[side]);
3830 nsCSSUnit unit = value.GetUnit();
3831 if (eCSSUnit_Enumerated == unit) {
3832 border->SetBorderStyle(side, value.GetIntValue());
3834 else if (eCSSUnit_None == unit || eCSSUnit_Initial == unit) {
3835 border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
3837 else if (eCSSUnit_Inherit == unit) {
3838 inherited = PR_TRUE;
3839 border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
3844 // -moz-border-*-colors: color, string, enum
3845 nscolor borderColor;
3846 nscolor unused = NS_RGB(0,0,0);
3848 { // scope for compilers with broken |for| loop scoping
3849 NS_FOR_CSS_SIDES(side) {
3850 nsCSSValueList* list =
3851 marginData.mBorderColors.*(nsCSSValueListRect::sides[side]);
3852 // FIXME Bug 389404: Implement inherit and -moz-initial.
3853 if (list) {
3854 // Some composite border color information has been specified for this
3855 // border side.
3856 border->EnsureBorderColors();
3857 border->ClearBorderColors(side);
3858 while (list) {
3859 if (SetColor(list->mValue, unused, mPresContext,
3860 aContext, borderColor, inherited))
3861 border->AppendBorderColor(side, borderColor);
3862 list = list->mNext;
3868 // border-color, border-*-color: color, string, enum, inherit
3869 nsCSSRect ourBorderColor(marginData.mBorderColor);
3870 PRBool foreground;
3871 AdjustLogicalBoxProp(aContext,
3872 marginData.mBorderLeftColorLTRSource,
3873 marginData.mBorderLeftColorRTLSource,
3874 marginData.mBorderStartColor, marginData.mBorderEndColor,
3875 NS_SIDE_LEFT, ourBorderColor, inherited);
3876 AdjustLogicalBoxProp(aContext,
3877 marginData.mBorderRightColorLTRSource,
3878 marginData.mBorderRightColorRTLSource,
3879 marginData.mBorderEndColor, marginData.mBorderStartColor,
3880 NS_SIDE_RIGHT, ourBorderColor, inherited);
3881 { // scope for compilers with broken |for| loop scoping
3882 NS_FOR_CSS_SIDES(side) {
3883 const nsCSSValue &value = ourBorderColor.*(nsCSSRect::sides[side]);
3884 if (eCSSUnit_Inherit == value.GetUnit()) {
3885 if (parentContext) {
3886 inherited = PR_TRUE;
3887 parentBorder->GetBorderColor(side, borderColor, foreground);
3888 if (foreground) {
3889 // We want to inherit the color from the parent, not use the
3890 // color on the element where this chunk of style data will be
3891 // used. We can ensure that the data for the parent are fully
3892 // computed (unlike for the element where this will be used, for
3893 // which the color could be specified on a more specific rule).
3894 border->SetBorderColor(side, parentContext->GetStyleColor()->mColor);
3895 } else
3896 border->SetBorderColor(side, borderColor);
3897 } else {
3898 // We're the root
3899 border->SetBorderToForeground(side);
3902 else if (SetColor(value, unused, mPresContext, aContext, borderColor, inherited)) {
3903 border->SetBorderColor(side, borderColor);
3905 else if (eCSSUnit_Enumerated == value.GetUnit()) {
3906 switch (value.GetIntValue()) {
3907 case NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR:
3908 border->SetBorderToForeground(side);
3909 break;
3912 else if (eCSSUnit_Initial == value.GetUnit()) {
3913 border->SetBorderToForeground(side);
3918 // -moz-border-radius: length, percent, inherit
3920 const nsCSSCornerSizes& borderRadius = marginData.mBorderRadius;
3921 NS_FOR_CSS_HALF_CORNERS(corner) {
3922 nsStyleCoord parentCoord = parentBorder->mBorderRadius.Get(corner);
3923 if (SetCoord(borderRadius.GetHalfCorner(corner),
3924 coord, parentCoord, SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
3925 aContext, mPresContext, inherited))
3926 border->mBorderRadius.Set(corner, coord);
3930 // float-edge: enum, inherit, initial
3931 SetDiscrete(marginData.mFloatEdge, border->mFloatEdge, inherited,
3932 SETDSC_ENUMERATED, parentBorder->mFloatEdge,
3933 NS_STYLE_FLOAT_EDGE_CONTENT, 0, 0, 0, 0);
3935 // border-image
3936 if (eCSSUnit_Array == marginData.mBorderImage.GetUnit()) {
3937 nsCSSValue::Array *arr = marginData.mBorderImage.GetArrayValue();
3939 // the image
3940 if (eCSSUnit_Image == arr->Item(0).GetUnit()) {
3941 border->SetBorderImage(arr->Item(0).GetImageValue());
3944 // the numbers saying where to split the image
3945 NS_FOR_CSS_SIDES(side) {
3946 // an uninitialized parentCoord is ok because I'm not passing SETCOORD_INHERIT
3947 if (SetCoord(arr->Item(1 + side), coord, nsStyleCoord(),
3948 SETCOORD_FACTOR | SETCOORD_PERCENT, aContext,
3949 mPresContext, inherited)) {
3950 border->mBorderImageSplit.Set(side, coord);
3954 // possible replacement for border-width
3955 // if have one - have all four (see CSSParserImpl::ParseBorderImage())
3956 if (eCSSUnit_Null != arr->Item(5).GetUnit()) {
3957 NS_FOR_CSS_SIDES(side) {
3958 // an uninitialized parentCoord is ok because I'm not passing SETCOORD_INHERIT
3959 if (!SetCoord(arr->Item(5 + side), coord, nsStyleCoord(),
3960 SETCOORD_LENGTH, aContext, mPresContext, inherited)) {
3961 NS_NOTREACHED("SetCoord for border-width replacement from border-image failed");
3963 if (coord.GetUnit() == eStyleUnit_Coord) {
3964 border->SetBorderImageWidthOverride(side, coord.GetCoordValue());
3965 } else {
3966 NS_WARNING("a border-width replacement from border-image "
3967 "has a unit that's not eStyleUnit_Coord");
3968 border->SetBorderImageWidthOverride(side, 0);
3971 border->mHaveBorderImageWidth = PR_TRUE;
3972 } else {
3973 border->mHaveBorderImageWidth = PR_FALSE;
3976 // stretch/round/repeat keywords
3977 if (eCSSUnit_Null == arr->Item(9).GetUnit()) {
3978 // default, both horizontal and vertical are stretch
3979 border->mBorderImageHFill = NS_STYLE_BORDER_IMAGE_STRETCH;
3980 border->mBorderImageVFill = NS_STYLE_BORDER_IMAGE_STRETCH;
3981 } else {
3982 // have horizontal value
3983 border->mBorderImageHFill = arr->Item(9).GetIntValue();
3984 if (eCSSUnit_Null == arr->Item(10).GetUnit()) {
3985 // vertical same as horizontal
3986 border->mBorderImageVFill = border->mBorderImageHFill;
3987 } else {
3988 // have vertical value
3989 border->mBorderImageVFill = arr->Item(10).GetIntValue();
3992 } else if (eCSSUnit_None == marginData.mBorderImage.GetUnit() ||
3993 eCSSUnit_Initial == marginData.mBorderImage.GetUnit()) {
3994 border->mHaveBorderImageWidth = PR_FALSE;
3995 border->SetBorderImage(nsnull);
3996 } else if (eCSSUnit_Inherit == marginData.mBorderImage.GetUnit()) {
3997 NS_FOR_CSS_SIDES(side) {
3998 border->SetBorderImageWidthOverride(side, parentBorder->mBorderImageWidth.side(side));
4000 border->mBorderImageSplit = parentBorder->mBorderImageSplit;
4001 border->mBorderImageHFill = parentBorder->mBorderImageHFill;
4002 border->mBorderImageVFill = parentBorder->mBorderImageVFill;
4003 border->mHaveBorderImageWidth = parentBorder->mHaveBorderImageWidth;
4004 border->SetBorderImage(parentBorder->GetBorderImage());
4007 COMPUTE_END_RESET(Border, border)
4010 const void*
4011 nsRuleNode::ComputePaddingData(void* aStartStruct,
4012 const nsRuleDataStruct& aData,
4013 nsStyleContext* aContext,
4014 nsRuleNode* aHighestNode,
4015 const RuleDetail aRuleDetail, PRBool aInherited)
4017 COMPUTE_START_RESET(Padding, (), padding, parentPadding, Margin, marginData)
4019 // padding: length, percent, inherit
4020 nsStyleCoord coord;
4021 nsCSSRect ourPadding(marginData.mPadding);
4022 AdjustLogicalBoxProp(aContext,
4023 marginData.mPaddingLeftLTRSource,
4024 marginData.mPaddingLeftRTLSource,
4025 marginData.mPaddingStart, marginData.mPaddingEnd,
4026 NS_SIDE_LEFT, ourPadding, inherited);
4027 AdjustLogicalBoxProp(aContext,
4028 marginData.mPaddingRightLTRSource,
4029 marginData.mPaddingRightRTLSource,
4030 marginData.mPaddingEnd, marginData.mPaddingStart,
4031 NS_SIDE_RIGHT, ourPadding, inherited);
4032 NS_FOR_CSS_SIDES(side) {
4033 nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
4034 if (SetCoord(ourPadding.*(nsCSSRect::sides[side]),
4035 coord, parentCoord, SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
4036 aContext, mPresContext, inherited)) {
4037 padding->mPadding.Set(side, coord);
4041 padding->RecalcData();
4042 COMPUTE_END_RESET(Padding, padding)
4045 const void*
4046 nsRuleNode::ComputeOutlineData(void* aStartStruct,
4047 const nsRuleDataStruct& aData,
4048 nsStyleContext* aContext,
4049 nsRuleNode* aHighestNode,
4050 const RuleDetail aRuleDetail, PRBool aInherited)
4052 COMPUTE_START_RESET(Outline, (mPresContext), outline, parentOutline,
4053 Margin, marginData)
4055 // outline-width: length, enum, inherit
4056 if (eCSSUnit_Initial == marginData.mOutlineWidth.GetUnit()) {
4057 outline->mOutlineWidth =
4058 nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
4060 else {
4061 SetCoord(marginData.mOutlineWidth, outline->mOutlineWidth,
4062 parentOutline->mOutlineWidth, SETCOORD_LEH, aContext,
4063 mPresContext, inherited);
4066 // outline-offset: length, inherit
4067 nsStyleCoord tempCoord;
4068 if (SetCoord(marginData.mOutlineOffset, tempCoord,
4069 parentOutline->mOutlineOffset,
4070 SETCOORD_LH | SETCOORD_INITIAL_ZERO, aContext, mPresContext,
4071 inherited)) {
4072 outline->mOutlineOffset = tempCoord.GetCoordValue();
4073 } else {
4074 NS_ASSERTION(marginData.mOutlineOffset.GetUnit() == eCSSUnit_Null,
4075 "unexpected unit");
4078 // outline-color: color, string, enum, inherit
4079 nscolor outlineColor;
4080 nscolor unused = NS_RGB(0,0,0);
4081 if (eCSSUnit_Inherit == marginData.mOutlineColor.GetUnit()) {
4082 if (parentContext) {
4083 inherited = PR_TRUE;
4084 if (parentOutline->GetOutlineColor(outlineColor))
4085 outline->SetOutlineColor(outlineColor);
4086 else {
4087 #ifdef GFX_HAS_INVERT
4088 outline->SetOutlineInitialColor();
4089 #else
4090 // We want to inherit the color from the parent, not use the
4091 // color on the element where this chunk of style data will be
4092 // used. We can ensure that the data for the parent are fully
4093 // computed (unlike for the element where this will be used, for
4094 // which the color could be specified on a more specific rule).
4095 outline->SetOutlineColor(parentContext->GetStyleColor()->mColor);
4096 #endif
4098 } else {
4099 outline->SetOutlineInitialColor();
4102 else if (SetColor(marginData.mOutlineColor, unused, mPresContext, aContext, outlineColor, inherited))
4103 outline->SetOutlineColor(outlineColor);
4104 else if (eCSSUnit_Enumerated == marginData.mOutlineColor.GetUnit() ||
4105 eCSSUnit_Initial == marginData.mOutlineColor.GetUnit()) {
4106 outline->SetOutlineInitialColor();
4109 // -moz-outline-radius: length, percent, inherit
4111 nsStyleCoord coord;
4112 const nsCSSCornerSizes& outlineRadius = marginData.mOutlineRadius;
4113 NS_FOR_CSS_HALF_CORNERS(corner) {
4114 nsStyleCoord parentCoord = parentOutline->mOutlineRadius.Get(corner);
4115 if (SetCoord(outlineRadius.GetHalfCorner(corner),
4116 coord, parentCoord, SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
4117 aContext, mPresContext, inherited))
4118 outline->mOutlineRadius.Set(corner, coord);
4122 // outline-style: auto, enum, none, inherit, initial
4123 // cannot use SetDiscrete because of SetOutlineStyle
4124 if (eCSSUnit_Enumerated == marginData.mOutlineStyle.GetUnit())
4125 outline->SetOutlineStyle(marginData.mOutlineStyle.GetIntValue());
4126 else if (eCSSUnit_None == marginData.mOutlineStyle.GetUnit() ||
4127 eCSSUnit_Initial == marginData.mOutlineStyle.GetUnit())
4128 outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_NONE);
4129 else if (eCSSUnit_Auto == marginData.mOutlineStyle.GetUnit()) {
4130 outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_AUTO);
4131 } else if (eCSSUnit_Inherit == marginData.mOutlineStyle.GetUnit()) {
4132 inherited = PR_TRUE;
4133 outline->SetOutlineStyle(parentOutline->GetOutlineStyle());
4136 outline->RecalcData(mPresContext);
4137 COMPUTE_END_RESET(Outline, outline)
4140 const void*
4141 nsRuleNode::ComputeListData(void* aStartStruct,
4142 const nsRuleDataStruct& aData,
4143 nsStyleContext* aContext,
4144 nsRuleNode* aHighestNode,
4145 const RuleDetail aRuleDetail, PRBool aInherited)
4147 COMPUTE_START_INHERITED(List, (), list, parentList, List, listData)
4149 // list-style-type: enum, none, inherit, initial
4150 SetDiscrete(listData.mType, list->mListStyleType, inherited,
4151 SETDSC_ENUMERATED | SETDSC_NONE, parentList->mListStyleType,
4152 NS_STYLE_LIST_STYLE_DISC, 0,
4153 NS_STYLE_LIST_STYLE_NONE, 0, 0);
4155 // list-style-image: url, none, inherit
4156 if (eCSSUnit_Image == listData.mImage.GetUnit()) {
4157 list->mListStyleImage = listData.mImage.GetImageValue();
4159 else if (eCSSUnit_None == listData.mImage.GetUnit() ||
4160 eCSSUnit_Initial == listData.mImage.GetUnit()) {
4161 list->mListStyleImage = nsnull;
4163 else if (eCSSUnit_Inherit == listData.mImage.GetUnit()) {
4164 inherited = PR_TRUE;
4165 list->mListStyleImage = parentList->mListStyleImage;
4168 // list-style-position: enum, inherit, initial
4169 SetDiscrete(listData.mPosition, list->mListStylePosition, inherited,
4170 SETDSC_ENUMERATED, parentList->mListStylePosition,
4171 NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, 0, 0, 0, 0);
4173 // image region property: length, auto, inherit
4174 if (eCSSUnit_Inherit == listData.mImageRegion.mTop.GetUnit()) { // if one is inherit, they all are
4175 inherited = PR_TRUE;
4176 list->mImageRegion = parentList->mImageRegion;
4178 // if one is -moz-initial, they all are
4179 else if (eCSSUnit_Initial == listData.mImageRegion.mTop.GetUnit()) {
4180 list->mImageRegion.Empty();
4182 else {
4183 if (eCSSUnit_Auto == listData.mImageRegion.mTop.GetUnit())
4184 list->mImageRegion.y = 0;
4185 else if (listData.mImageRegion.mTop.IsLengthUnit())
4186 list->mImageRegion.y = CalcLength(listData.mImageRegion.mTop, aContext, mPresContext, inherited);
4188 if (eCSSUnit_Auto == listData.mImageRegion.mBottom.GetUnit())
4189 list->mImageRegion.height = 0;
4190 else if (listData.mImageRegion.mBottom.IsLengthUnit())
4191 list->mImageRegion.height = CalcLength(listData.mImageRegion.mBottom, aContext,
4192 mPresContext, inherited) - list->mImageRegion.y;
4194 if (eCSSUnit_Auto == listData.mImageRegion.mLeft.GetUnit())
4195 list->mImageRegion.x = 0;
4196 else if (listData.mImageRegion.mLeft.IsLengthUnit())
4197 list->mImageRegion.x = CalcLength(listData.mImageRegion.mLeft, aContext, mPresContext, inherited);
4199 if (eCSSUnit_Auto == listData.mImageRegion.mRight.GetUnit())
4200 list->mImageRegion.width = 0;
4201 else if (listData.mImageRegion.mRight.IsLengthUnit())
4202 list->mImageRegion.width = CalcLength(listData.mImageRegion.mRight, aContext, mPresContext, inherited) -
4203 list->mImageRegion.x;
4206 COMPUTE_END_INHERITED(List, list)
4209 const void*
4210 nsRuleNode::ComputePositionData(void* aStartStruct,
4211 const nsRuleDataStruct& aData,
4212 nsStyleContext* aContext,
4213 nsRuleNode* aHighestNode,
4214 const RuleDetail aRuleDetail, PRBool aInherited)
4216 COMPUTE_START_RESET(Position, (), pos, parentPos, Position, posData)
4218 // box offsets: length, percent, auto, inherit
4219 nsStyleCoord coord;
4220 NS_FOR_CSS_SIDES(side) {
4221 nsStyleCoord parentCoord = parentPos->mOffset.Get(side);
4222 if (SetCoord(posData.mOffset.*(nsCSSRect::sides[side]),
4223 coord, parentCoord, SETCOORD_LPAH | SETCOORD_INITIAL_AUTO,
4224 aContext, mPresContext, inherited)) {
4225 pos->mOffset.Set(side, coord);
4229 SetCoord(posData.mWidth, pos->mWidth, parentPos->mWidth,
4230 SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO, aContext,
4231 mPresContext, inherited);
4232 SetCoord(posData.mMinWidth, pos->mMinWidth, parentPos->mMinWidth,
4233 SETCOORD_LPEH | SETCOORD_INITIAL_ZERO, aContext,
4234 mPresContext, inherited);
4235 SetCoord(posData.mMaxWidth, pos->mMaxWidth, parentPos->mMaxWidth,
4236 SETCOORD_LPOEH | SETCOORD_INITIAL_NONE, aContext,
4237 mPresContext, inherited);
4239 SetCoord(posData.mHeight, pos->mHeight, parentPos->mHeight,
4240 SETCOORD_LPAH | SETCOORD_INITIAL_AUTO, aContext,
4241 mPresContext, inherited);
4242 SetCoord(posData.mMinHeight, pos->mMinHeight, parentPos->mMinHeight,
4243 SETCOORD_LPH | SETCOORD_INITIAL_ZERO, aContext,
4244 mPresContext, inherited);
4245 SetCoord(posData.mMaxHeight, pos->mMaxHeight, parentPos->mMaxHeight,
4246 SETCOORD_LPOH | SETCOORD_INITIAL_NONE, aContext,
4247 mPresContext, inherited);
4249 // box-sizing: enum, inherit, initial
4250 SetDiscrete(posData.mBoxSizing, pos->mBoxSizing, inherited,
4251 SETDSC_ENUMERATED, parentPos->mBoxSizing,
4252 NS_STYLE_BOX_SIZING_CONTENT, 0, 0, 0, 0);
4254 // z-index
4255 if (! SetCoord(posData.mZIndex, pos->mZIndex, parentPos->mZIndex,
4256 SETCOORD_IA | SETCOORD_INITIAL_AUTO, aContext,
4257 nsnull, inherited)) {
4258 if (eCSSUnit_Inherit == posData.mZIndex.GetUnit()) {
4259 // handle inherit, because it's ok to inherit 'auto' here
4260 inherited = PR_TRUE;
4261 pos->mZIndex = parentPos->mZIndex;
4265 COMPUTE_END_RESET(Position, pos)
4268 const void*
4269 nsRuleNode::ComputeTableData(void* aStartStruct,
4270 const nsRuleDataStruct& aData,
4271 nsStyleContext* aContext,
4272 nsRuleNode* aHighestNode,
4273 const RuleDetail aRuleDetail, PRBool aInherited)
4275 COMPUTE_START_RESET(Table, (), table, parentTable, Table, tableData)
4277 // table-layout: auto, enum, inherit, initial
4278 SetDiscrete(tableData.mLayout, table->mLayoutStrategy, inherited,
4279 SETDSC_ENUMERATED | SETDSC_AUTO,
4280 parentTable->mLayoutStrategy,
4281 NS_STYLE_TABLE_LAYOUT_AUTO,
4282 NS_STYLE_TABLE_LAYOUT_AUTO, 0, 0, 0);
4284 // rules: enum (not a real CSS prop)
4285 if (eCSSUnit_Enumerated == tableData.mRules.GetUnit())
4286 table->mRules = tableData.mRules.GetIntValue();
4288 // frame: enum (not a real CSS prop)
4289 if (eCSSUnit_Enumerated == tableData.mFrame.GetUnit())
4290 table->mFrame = tableData.mFrame.GetIntValue();
4292 // cols: enum, int (not a real CSS prop)
4293 if (eCSSUnit_Enumerated == tableData.mCols.GetUnit() ||
4294 eCSSUnit_Integer == tableData.mCols.GetUnit())
4295 table->mCols = tableData.mCols.GetIntValue();
4297 // span: pixels (not a real CSS prop)
4298 if (eCSSUnit_Enumerated == tableData.mSpan.GetUnit() ||
4299 eCSSUnit_Integer == tableData.mSpan.GetUnit())
4300 table->mSpan = tableData.mSpan.GetIntValue();
4302 COMPUTE_END_RESET(Table, table)
4305 const void*
4306 nsRuleNode::ComputeTableBorderData(void* aStartStruct,
4307 const nsRuleDataStruct& aData,
4308 nsStyleContext* aContext,
4309 nsRuleNode* aHighestNode,
4310 const RuleDetail aRuleDetail, PRBool aInherited)
4312 COMPUTE_START_INHERITED(TableBorder, (mPresContext), table, parentTable,
4313 Table, tableData)
4315 // border-collapse: enum, inherit, initial
4316 SetDiscrete(tableData.mBorderCollapse, table->mBorderCollapse, inherited,
4317 SETDSC_ENUMERATED, parentTable->mBorderCollapse,
4318 NS_STYLE_BORDER_SEPARATE, 0, 0, 0, 0);
4320 // border-spacing-x: length, inherit
4321 nsStyleCoord tempCoord;
4322 if (SetCoord(tableData.mBorderSpacing.mXValue, tempCoord,
4323 parentTable->mBorderSpacingX,
4324 SETCOORD_LH | SETCOORD_INITIAL_ZERO,
4325 aContext, mPresContext, inherited)) {
4326 table->mBorderSpacingX = tempCoord.GetCoordValue();
4327 } else {
4328 NS_ASSERTION(tableData.mBorderSpacing.mXValue.GetUnit() == eCSSUnit_Null,
4329 "unexpected unit");
4332 // border-spacing-y: length, inherit
4333 if (SetCoord(tableData.mBorderSpacing.mYValue, tempCoord,
4334 parentTable->mBorderSpacingY,
4335 SETCOORD_LH | SETCOORD_INITIAL_ZERO,
4336 aContext, mPresContext, inherited)) {
4337 table->mBorderSpacingY = tempCoord.GetCoordValue();
4338 } else {
4339 NS_ASSERTION(tableData.mBorderSpacing.mYValue.GetUnit() == eCSSUnit_Null,
4340 "unexpected unit");
4343 // caption-side: enum, inherit, initial
4344 SetDiscrete(tableData.mCaptionSide, table->mCaptionSide, inherited,
4345 SETDSC_ENUMERATED, parentTable->mCaptionSide,
4346 NS_STYLE_CAPTION_SIDE_TOP, 0, 0, 0, 0);
4348 // empty-cells: enum, inherit, initial
4349 SetDiscrete(tableData.mEmptyCells, table->mEmptyCells, inherited,
4350 SETDSC_ENUMERATED, parentTable->mEmptyCells,
4351 (mPresContext->CompatibilityMode() == eCompatibility_NavQuirks)
4352 ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
4353 : NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
4354 0, 0, 0, 0);
4356 COMPUTE_END_INHERITED(TableBorder, table)
4359 const void*
4360 nsRuleNode::ComputeContentData(void* aStartStruct,
4361 const nsRuleDataStruct& aData,
4362 nsStyleContext* aContext,
4363 nsRuleNode* aHighestNode,
4364 const RuleDetail aRuleDetail, PRBool aInherited)
4366 COMPUTE_START_RESET(Content, (), content, parentContent,
4367 Content, contentData)
4369 // content: [string, url, counter, attr, enum]+, normal, none, inherit
4370 PRUint32 count;
4371 nsAutoString buffer;
4372 nsCSSValueList* contentValue = contentData.mContent;
4373 if (contentValue) {
4374 if (eCSSUnit_Normal == contentValue->mValue.GetUnit() ||
4375 eCSSUnit_None == contentValue->mValue.GetUnit() ||
4376 eCSSUnit_Initial == contentValue->mValue.GetUnit()) {
4377 // "normal", "none", and "initial" all mean no content
4378 content->AllocateContents(0);
4380 else if (eCSSUnit_Inherit == contentValue->mValue.GetUnit()) {
4381 inherited = PR_TRUE;
4382 count = parentContent->ContentCount();
4383 if (NS_SUCCEEDED(content->AllocateContents(count))) {
4384 while (0 < count--) {
4385 content->ContentAt(count) = parentContent->ContentAt(count);
4389 else {
4390 count = 0;
4391 while (contentValue) {
4392 count++;
4393 contentValue = contentValue->mNext;
4395 if (NS_SUCCEEDED(content->AllocateContents(count))) {
4396 const nsAutoString nullStr;
4397 count = 0;
4398 contentValue = contentData.mContent;
4399 while (contentValue) {
4400 const nsCSSValue& value = contentValue->mValue;
4401 nsCSSUnit unit = value.GetUnit();
4402 nsStyleContentType type;
4403 nsStyleContentData &data = content->ContentAt(count++);
4404 switch (unit) {
4405 case eCSSUnit_String: type = eStyleContentType_String; break;
4406 case eCSSUnit_Image: type = eStyleContentType_Image; break;
4407 case eCSSUnit_Attr: type = eStyleContentType_Attr; break;
4408 case eCSSUnit_Counter: type = eStyleContentType_Counter; break;
4409 case eCSSUnit_Counters: type = eStyleContentType_Counters; break;
4410 case eCSSUnit_Enumerated:
4411 switch (value.GetIntValue()) {
4412 case NS_STYLE_CONTENT_OPEN_QUOTE:
4413 type = eStyleContentType_OpenQuote; break;
4414 case NS_STYLE_CONTENT_CLOSE_QUOTE:
4415 type = eStyleContentType_CloseQuote; break;
4416 case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
4417 type = eStyleContentType_NoOpenQuote; break;
4418 case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
4419 type = eStyleContentType_NoCloseQuote; break;
4420 case NS_STYLE_CONTENT_ALT_CONTENT:
4421 type = eStyleContentType_AltContent; break;
4422 default:
4423 NS_ERROR("bad content value");
4425 break;
4426 default:
4427 NS_ERROR("bad content type");
4429 data.mType = type;
4430 if (type == eStyleContentType_Image) {
4431 data.mContent.mImage = value.GetImageValue();
4432 NS_IF_ADDREF(data.mContent.mImage);
4434 else if (type <= eStyleContentType_Attr) {
4435 value.GetStringValue(buffer);
4436 Unquote(buffer);
4437 data.mContent.mString = NS_strdup(buffer.get());
4439 else if (type <= eStyleContentType_Counters) {
4440 data.mContent.mCounters = value.GetArrayValue();
4441 data.mContent.mCounters->AddRef();
4443 else {
4444 data.mContent.mString = nsnull;
4446 contentValue = contentValue->mNext;
4452 // counter-increment: [string [int]]+, none, inherit
4453 nsCSSValuePairList* ourIncrement = contentData.mCounterIncrement;
4454 if (ourIncrement) {
4455 if (eCSSUnit_None == ourIncrement->mXValue.GetUnit() ||
4456 eCSSUnit_Initial == ourIncrement->mXValue.GetUnit()) {
4457 content->AllocateCounterIncrements(0);
4459 else if (eCSSUnit_Inherit == ourIncrement->mXValue.GetUnit()) {
4460 inherited = PR_TRUE;
4461 count = parentContent->CounterIncrementCount();
4462 if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
4463 while (0 < count--) {
4464 const nsStyleCounterData *data =
4465 parentContent->GetCounterIncrementAt(count);
4466 content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
4470 else if (eCSSUnit_String == ourIncrement->mXValue.GetUnit()) {
4471 count = 0;
4472 while (ourIncrement) {
4473 count++;
4474 ourIncrement = ourIncrement->mNext;
4476 if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
4477 count = 0;
4478 ourIncrement = contentData.mCounterIncrement;
4479 while (ourIncrement) {
4480 PRInt32 increment;
4481 if (eCSSUnit_Integer == ourIncrement->mYValue.GetUnit()) {
4482 increment = ourIncrement->mYValue.GetIntValue();
4484 else {
4485 increment = 1;
4487 ourIncrement->mXValue.GetStringValue(buffer);
4488 content->SetCounterIncrementAt(count++, buffer, increment);
4489 ourIncrement = ourIncrement->mNext;
4495 // counter-reset: [string [int]]+, none, inherit
4496 nsCSSValuePairList* ourReset = contentData.mCounterReset;
4497 if (ourReset) {
4498 if (eCSSUnit_None == ourReset->mXValue.GetUnit() ||
4499 eCSSUnit_Initial == ourReset->mXValue.GetUnit()) {
4500 content->AllocateCounterResets(0);
4502 else if (eCSSUnit_Inherit == ourReset->mXValue.GetUnit()) {
4503 inherited = PR_TRUE;
4504 count = parentContent->CounterResetCount();
4505 if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
4506 while (0 < count--) {
4507 const nsStyleCounterData *data =
4508 parentContent->GetCounterResetAt(count);
4509 content->SetCounterResetAt(count, data->mCounter, data->mValue);
4513 else if (eCSSUnit_String == ourReset->mXValue.GetUnit()) {
4514 count = 0;
4515 while (ourReset) {
4516 count++;
4517 ourReset = ourReset->mNext;
4519 if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
4520 count = 0;
4521 ourReset = contentData.mCounterReset;
4522 while (ourReset) {
4523 PRInt32 reset;
4524 if (eCSSUnit_Integer == ourReset->mYValue.GetUnit()) {
4525 reset = ourReset->mYValue.GetIntValue();
4527 else {
4528 reset = 0;
4530 ourReset->mXValue.GetStringValue(buffer);
4531 content->SetCounterResetAt(count++, buffer, reset);
4532 ourReset = ourReset->mNext;
4538 // marker-offset: length, auto, inherit
4539 SetCoord(contentData.mMarkerOffset, content->mMarkerOffset, parentContent->mMarkerOffset,
4540 SETCOORD_LH | SETCOORD_AUTO | SETCOORD_INITIAL_AUTO, aContext,
4541 mPresContext, inherited);
4543 COMPUTE_END_RESET(Content, content)
4546 const void*
4547 nsRuleNode::ComputeQuotesData(void* aStartStruct,
4548 const nsRuleDataStruct& aData,
4549 nsStyleContext* aContext,
4550 nsRuleNode* aHighestNode,
4551 const RuleDetail aRuleDetail, PRBool aInherited)
4553 COMPUTE_START_INHERITED(Quotes, (), quotes, parentQuotes,
4554 Content, contentData)
4556 // quotes: inherit, initial, none, [string string]+
4557 nsCSSValuePairList* ourQuotes = contentData.mQuotes;
4558 if (ourQuotes) {
4559 if (eCSSUnit_Inherit == ourQuotes->mXValue.GetUnit()) {
4560 inherited = PR_TRUE;
4561 quotes->CopyFrom(*parentQuotes);
4563 else if (eCSSUnit_Initial == ourQuotes->mXValue.GetUnit()) {
4564 quotes->SetInitial();
4566 else if (eCSSUnit_None == ourQuotes->mXValue.GetUnit()) {
4567 quotes->AllocateQuotes(0);
4569 else if (eCSSUnit_String == ourQuotes->mXValue.GetUnit()) {
4570 nsAutoString buffer;
4571 nsAutoString closeBuffer;
4572 PRUint32 count = 0;
4574 while (ourQuotes) {
4575 count++;
4576 ourQuotes = ourQuotes->mNext;
4578 if (NS_SUCCEEDED(quotes->AllocateQuotes(count))) {
4579 count = 0;
4580 ourQuotes = contentData.mQuotes;
4581 while (ourQuotes) {
4582 ourQuotes->mXValue.GetStringValue(buffer);
4583 ourQuotes->mYValue.GetStringValue(closeBuffer);
4584 Unquote(buffer);
4585 Unquote(closeBuffer);
4586 quotes->SetQuotesAt(count++, buffer, closeBuffer);
4587 ourQuotes = ourQuotes->mNext;
4593 COMPUTE_END_INHERITED(Quotes, quotes)
4596 const void*
4597 nsRuleNode::ComputeXULData(void* aStartStruct,
4598 const nsRuleDataStruct& aData,
4599 nsStyleContext* aContext,
4600 nsRuleNode* aHighestNode,
4601 const RuleDetail aRuleDetail, PRBool aInherited)
4603 COMPUTE_START_RESET(XUL, (), xul, parentXUL, XUL, xulData)
4605 // box-align: enum, inherit, initial
4606 SetDiscrete(xulData.mBoxAlign, xul->mBoxAlign, inherited,
4607 SETDSC_ENUMERATED, parentXUL->mBoxAlign,
4608 NS_STYLE_BOX_ALIGN_STRETCH, 0, 0, 0, 0);
4610 // box-direction: enum, inherit, initial
4611 SetDiscrete(xulData.mBoxDirection, xul->mBoxDirection, inherited,
4612 SETDSC_ENUMERATED, parentXUL->mBoxDirection,
4613 NS_STYLE_BOX_DIRECTION_NORMAL, 0, 0, 0, 0);
4615 // box-flex: factor, inherit
4616 SetFactor(xulData.mBoxFlex, xul->mBoxFlex, inherited,
4617 parentXUL->mBoxFlex, 0.0f);
4619 // box-orient: enum, inherit, initial
4620 SetDiscrete(xulData.mBoxOrient, xul->mBoxOrient, inherited,
4621 SETDSC_ENUMERATED, parentXUL->mBoxOrient,
4622 NS_STYLE_BOX_ORIENT_HORIZONTAL, 0, 0, 0, 0);
4624 // box-pack: enum, inherit, initial
4625 SetDiscrete(xulData.mBoxPack, xul->mBoxPack, inherited,
4626 SETDSC_ENUMERATED, parentXUL->mBoxPack,
4627 NS_STYLE_BOX_PACK_START, 0, 0, 0, 0);
4629 // box-ordinal-group: integer, inherit, initial
4630 SetDiscrete(xulData.mBoxOrdinal, xul->mBoxOrdinal, inherited,
4631 SETDSC_INTEGER, parentXUL->mBoxOrdinal, 1,
4632 0, 0, 0, 0);
4634 if (eCSSUnit_Inherit == xulData.mStackSizing.GetUnit()) {
4635 inherited = PR_TRUE;
4636 xul->mStretchStack = parentXUL->mStretchStack;
4637 } else if (eCSSUnit_Initial == xulData.mStackSizing.GetUnit()) {
4638 xul->mStretchStack = PR_TRUE;
4639 } else if (eCSSUnit_Enumerated == xulData.mStackSizing.GetUnit()) {
4640 xul->mStretchStack = xulData.mStackSizing.GetIntValue() ==
4641 NS_STYLE_STACK_SIZING_STRETCH_TO_FIT;
4644 COMPUTE_END_RESET(XUL, xul)
4647 const void*
4648 nsRuleNode::ComputeColumnData(void* aStartStruct,
4649 const nsRuleDataStruct& aData,
4650 nsStyleContext* aContext,
4651 nsRuleNode* aHighestNode,
4652 const RuleDetail aRuleDetail, PRBool aInherited)
4654 COMPUTE_START_RESET(Column, (mPresContext), column, parent, Column, columnData)
4656 // column-width: length, auto, inherit
4657 SetCoord(columnData.mColumnWidth,
4658 column->mColumnWidth, parent->mColumnWidth,
4659 SETCOORD_LAH | SETCOORD_INITIAL_AUTO,
4660 aContext, mPresContext, inherited);
4662 // column-gap: length, percentage, inherit, normal
4663 SetCoord(columnData.mColumnGap,
4664 column->mColumnGap, parent->mColumnGap,
4665 SETCOORD_LPH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL,
4666 aContext, mPresContext, inherited);
4668 // column-count: auto, integer, inherit
4669 if (eCSSUnit_Auto == columnData.mColumnCount.GetUnit() ||
4670 eCSSUnit_Initial == columnData.mColumnCount.GetUnit()) {
4671 column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
4672 } else if (eCSSUnit_Integer == columnData.mColumnCount.GetUnit()) {
4673 column->mColumnCount = columnData.mColumnCount.GetIntValue();
4674 // Max 1000 columns - wallpaper for bug 345583.
4675 column->mColumnCount = PR_MIN(column->mColumnCount, 1000);
4676 } else if (eCSSUnit_Inherit == columnData.mColumnCount.GetUnit()) {
4677 inherited = PR_TRUE;
4678 column->mColumnCount = parent->mColumnCount;
4681 // column-rule-width: length, enum, inherit
4682 const nsCSSValue& widthValue = columnData.mColumnRuleWidth;
4683 if (eCSSUnit_Initial == widthValue.GetUnit()) {
4684 column->SetColumnRuleWidth(
4685 (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
4687 else if (eCSSUnit_Enumerated == widthValue.GetUnit()) {
4688 NS_ASSERTION(widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
4689 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
4690 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
4691 "Unexpected enum value");
4692 column->SetColumnRuleWidth(
4693 (mPresContext->GetBorderWidthTable())[widthValue.GetIntValue()]);
4695 else if (eCSSUnit_Inherit == widthValue.GetUnit()) {
4696 column->SetColumnRuleWidth(parent->GetComputedColumnRuleWidth());
4697 inherited = PR_TRUE;
4699 else if (widthValue.IsLengthUnit()) {
4700 column->SetColumnRuleWidth(CalcLength(widthValue, aContext,
4701 mPresContext, inherited));
4704 // column-rule-style: enum, none, inherit
4705 const nsCSSValue& styleValue = columnData.mColumnRuleStyle;
4706 if (eCSSUnit_Enumerated == styleValue.GetUnit()) {
4707 column->mColumnRuleStyle = styleValue.GetIntValue();
4709 else if (eCSSUnit_None == styleValue.GetUnit() ||
4710 eCSSUnit_Initial == styleValue.GetUnit()) {
4711 column->mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
4713 else if (eCSSUnit_Inherit == styleValue.GetUnit()) {
4714 inherited = PR_TRUE;
4715 column->mColumnRuleStyle = parent->mColumnRuleStyle;
4718 // column-rule-color: color, inherit
4719 const nsCSSValue& colorValue = columnData.mColumnRuleColor;
4720 if (eCSSUnit_Inherit == colorValue.GetUnit()) {
4721 inherited = PR_TRUE;
4722 column->mColumnRuleColorIsForeground = PR_FALSE;
4723 if (parent->mColumnRuleColorIsForeground) {
4724 column->mColumnRuleColor = parentContext->GetStyleColor()->mColor;
4725 } else {
4726 column->mColumnRuleColor = parent->mColumnRuleColor;
4729 else if (eCSSUnit_Initial == colorValue.GetUnit()) {
4730 column->mColumnRuleColorIsForeground = PR_TRUE;
4732 else if (SetColor(colorValue, 0, mPresContext, aContext, column->mColumnRuleColor, inherited)) {
4733 column->mColumnRuleColorIsForeground = PR_FALSE;
4736 COMPUTE_END_RESET(Column, column)
4739 #ifdef MOZ_SVG
4740 static void
4741 SetSVGPaint(const nsCSSValuePair& aValue, const nsStyleSVGPaint& parentPaint,
4742 nsPresContext* aPresContext, nsStyleContext *aContext,
4743 nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
4744 PRBool& aInherited)
4746 nscolor color;
4748 if (aValue.mXValue.GetUnit() == eCSSUnit_Inherit) {
4749 aResult = parentPaint;
4750 aInherited = PR_TRUE;
4751 } else if (aValue.mXValue.GetUnit() == eCSSUnit_None) {
4752 aResult.SetType(eStyleSVGPaintType_None);
4753 } else if (aValue.mXValue.GetUnit() == eCSSUnit_Initial) {
4754 aResult.SetType(aInitialPaintType);
4755 aResult.mPaint.mColor = NS_RGB(0, 0, 0);
4756 aResult.mFallbackColor = NS_RGB(0, 0, 0);
4757 } else if (aValue.mXValue.GetUnit() == eCSSUnit_URL) {
4758 aResult.SetType(eStyleSVGPaintType_Server);
4759 aResult.mPaint.mPaintServer = aValue.mXValue.GetURLValue();
4760 NS_IF_ADDREF(aResult.mPaint.mPaintServer);
4761 if (aValue.mYValue.GetUnit() == eCSSUnit_None) {
4762 aResult.mFallbackColor = NS_RGBA(0, 0, 0, 0);
4763 } else {
4764 NS_ASSERTION(aValue.mYValue.GetUnit() != eCSSUnit_Inherit, "cannot inherit fallback colour");
4765 SetColor(aValue.mYValue, NS_RGB(0, 0, 0), aPresContext, aContext, aResult.mFallbackColor, aInherited);
4767 } else if (SetColor(aValue.mXValue, parentPaint.mPaint.mColor, aPresContext, aContext, color, aInherited)) {
4768 aResult.SetType(eStyleSVGPaintType_Color);
4769 aResult.mPaint.mColor = color;
4773 const void*
4774 nsRuleNode::ComputeSVGData(void* aStartStruct,
4775 const nsRuleDataStruct& aData,
4776 nsStyleContext* aContext,
4777 nsRuleNode* aHighestNode,
4778 const RuleDetail aRuleDetail, PRBool aInherited)
4780 COMPUTE_START_INHERITED(SVG, (), svg, parentSVG, SVG, SVGData)
4782 // clip-rule: enum, inherit, initial
4783 SetDiscrete(SVGData.mClipRule, svg->mClipRule, inherited,
4784 SETDSC_ENUMERATED, parentSVG->mClipRule,
4785 NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
4787 // color-interpolation: enum, auto, inherit, initial
4788 SetDiscrete(SVGData.mColorInterpolation, svg->mColorInterpolation, inherited,
4789 SETDSC_ENUMERATED | SETDSC_AUTO,
4790 parentSVG->mColorInterpolation,
4791 NS_STYLE_COLOR_INTERPOLATION_SRGB,
4792 NS_STYLE_COLOR_INTERPOLATION_AUTO, 0, 0, 0);
4794 // color-interpolation-filters: enum, auto, inherit, initial
4795 SetDiscrete(SVGData.mColorInterpolationFilters,
4796 svg->mColorInterpolationFilters, inherited,
4797 SETDSC_ENUMERATED | SETDSC_AUTO,
4798 parentSVG->mColorInterpolationFilters,
4799 NS_STYLE_COLOR_INTERPOLATION_LINEARRGB,
4800 NS_STYLE_COLOR_INTERPOLATION_AUTO, 0, 0, 0);
4802 // fill:
4803 SetSVGPaint(SVGData.mFill, parentSVG->mFill, mPresContext, aContext,
4804 svg->mFill, eStyleSVGPaintType_Color, inherited);
4806 // fill-opacity: factor, inherit, initial
4807 SetFactor(SVGData.mFillOpacity, svg->mFillOpacity, inherited,
4808 parentSVG->mFillOpacity, 1.0f, SETFCT_OPACITY);
4810 // fill-rule: enum, inherit, initial
4811 SetDiscrete(SVGData.mFillRule, svg->mFillRule, inherited,
4812 SETDSC_ENUMERATED, parentSVG->mFillRule,
4813 NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
4815 // marker-end: url, none, inherit
4816 if (eCSSUnit_URL == SVGData.mMarkerEnd.GetUnit()) {
4817 svg->mMarkerEnd = SVGData.mMarkerEnd.GetURLValue();
4818 } else if (eCSSUnit_None == SVGData.mMarkerEnd.GetUnit() ||
4819 eCSSUnit_Initial == SVGData.mMarkerEnd.GetUnit()) {
4820 svg->mMarkerEnd = nsnull;
4821 } else if (eCSSUnit_Inherit == SVGData.mMarkerEnd.GetUnit()) {
4822 inherited = PR_TRUE;
4823 svg->mMarkerEnd = parentSVG->mMarkerEnd;
4826 // marker-mid: url, none, inherit
4827 if (eCSSUnit_URL == SVGData.mMarkerMid.GetUnit()) {
4828 svg->mMarkerMid = SVGData.mMarkerMid.GetURLValue();
4829 } else if (eCSSUnit_None == SVGData.mMarkerMid.GetUnit() ||
4830 eCSSUnit_Initial == SVGData.mMarkerMid.GetUnit()) {
4831 svg->mMarkerMid = nsnull;
4832 } else if (eCSSUnit_Inherit == SVGData.mMarkerMid.GetUnit()) {
4833 inherited = PR_TRUE;
4834 svg->mMarkerMid = parentSVG->mMarkerMid;
4837 // marker-start: url, none, inherit
4838 if (eCSSUnit_URL == SVGData.mMarkerStart.GetUnit()) {
4839 svg->mMarkerStart = SVGData.mMarkerStart.GetURLValue();
4840 } else if (eCSSUnit_None == SVGData.mMarkerStart.GetUnit() ||
4841 eCSSUnit_Initial == SVGData.mMarkerStart.GetUnit()) {
4842 svg->mMarkerStart = nsnull;
4843 } else if (eCSSUnit_Inherit == SVGData.mMarkerStart.GetUnit()) {
4844 inherited = PR_TRUE;
4845 svg->mMarkerStart = parentSVG->mMarkerStart;
4848 // pointer-events: enum, none, inherit, initial
4849 SetDiscrete(SVGData.mPointerEvents, svg->mPointerEvents, inherited,
4850 SETDSC_ENUMERATED | SETDSC_NONE, parentSVG->mPointerEvents,
4851 NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED, 0,
4852 NS_STYLE_POINTER_EVENTS_NONE, 0, 0);
4854 // shape-rendering: enum, auto, inherit
4855 SetDiscrete(SVGData.mShapeRendering, svg->mShapeRendering, inherited,
4856 SETDSC_ENUMERATED | SETDSC_AUTO,
4857 parentSVG->mShapeRendering,
4858 NS_STYLE_SHAPE_RENDERING_AUTO,
4859 NS_STYLE_SHAPE_RENDERING_AUTO, 0, 0, 0);
4861 // stroke:
4862 SetSVGPaint(SVGData.mStroke, parentSVG->mStroke, mPresContext, aContext,
4863 svg->mStroke, eStyleSVGPaintType_None, inherited);
4865 // stroke-dasharray: <dasharray>, none, inherit
4866 nsCSSValueList *list = SVGData.mStrokeDasharray;
4867 if (list) {
4868 if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
4869 // only do the copy if weren't already set up by the copy constructor
4870 // FIXME Bug 389408: This is broken when aStartStruct is non-null!
4871 if (!svg->mStrokeDasharray) {
4872 inherited = PR_TRUE;
4873 svg->mStrokeDasharrayLength = parentSVG->mStrokeDasharrayLength;
4874 if (svg->mStrokeDasharrayLength) {
4875 svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
4876 if (svg->mStrokeDasharray)
4877 memcpy(svg->mStrokeDasharray,
4878 parentSVG->mStrokeDasharray,
4879 svg->mStrokeDasharrayLength * sizeof(nsStyleCoord));
4880 else
4881 svg->mStrokeDasharrayLength = 0;
4884 } else {
4885 delete [] svg->mStrokeDasharray;
4886 svg->mStrokeDasharray = nsnull;
4887 svg->mStrokeDasharrayLength = 0;
4889 if (eCSSUnit_Initial != list->mValue.GetUnit() &&
4890 eCSSUnit_None != list->mValue.GetUnit()) {
4891 // count number of values
4892 nsCSSValueList *value = SVGData.mStrokeDasharray;
4893 while (nsnull != value) {
4894 ++svg->mStrokeDasharrayLength;
4895 value = value->mNext;
4898 NS_ASSERTION(svg->mStrokeDasharrayLength != 0, "no dasharray items");
4900 svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
4902 if (svg->mStrokeDasharray) {
4903 value = SVGData.mStrokeDasharray;
4904 PRUint32 i = 0;
4905 while (nsnull != value) {
4906 SetCoord(value->mValue,
4907 svg->mStrokeDasharray[i++], nsnull,
4908 SETCOORD_LP | SETCOORD_FACTOR,
4909 aContext, mPresContext, inherited);
4910 value = value->mNext;
4912 } else
4913 svg->mStrokeDasharrayLength = 0;
4918 // stroke-dashoffset: <dashoffset>, inherit
4919 SetCoord(SVGData.mStrokeDashoffset,
4920 svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
4921 SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_INITIAL_ZERO,
4922 aContext, mPresContext, inherited);
4924 // stroke-linecap: enum, inherit, initial
4925 SetDiscrete(SVGData.mStrokeLinecap, svg->mStrokeLinecap, inherited,
4926 SETDSC_ENUMERATED, parentSVG->mStrokeLinecap,
4927 NS_STYLE_STROKE_LINECAP_BUTT, 0, 0, 0, 0);
4929 // stroke-linejoin: enum, inherit, initial
4930 SetDiscrete(SVGData.mStrokeLinejoin, svg->mStrokeLinejoin, inherited,
4931 SETDSC_ENUMERATED, parentSVG->mStrokeLinejoin,
4932 NS_STYLE_STROKE_LINEJOIN_MITER, 0, 0, 0, 0);
4934 // stroke-miterlimit: <miterlimit>, inherit
4935 SetFactor(SVGData.mStrokeMiterlimit, svg->mStrokeMiterlimit, inherited,
4936 parentSVG->mStrokeMiterlimit, 4.0f);
4938 // stroke-opacity:
4939 SetFactor(SVGData.mStrokeOpacity, svg->mStrokeOpacity, inherited,
4940 parentSVG->mStrokeOpacity, 1.0f, SETFCT_OPACITY);
4942 // stroke-width:
4943 if (eCSSUnit_Initial == SVGData.mStrokeWidth.GetUnit()) {
4944 svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
4945 } else {
4946 SetCoord(SVGData.mStrokeWidth,
4947 svg->mStrokeWidth, parentSVG->mStrokeWidth,
4948 SETCOORD_LPH | SETCOORD_FACTOR,
4949 aContext, mPresContext, inherited);
4952 // text-anchor: enum, inherit, initial
4953 SetDiscrete(SVGData.mTextAnchor, svg->mTextAnchor, inherited,
4954 SETDSC_ENUMERATED, parentSVG->mTextAnchor,
4955 NS_STYLE_TEXT_ANCHOR_START, 0, 0, 0, 0);
4957 // text-rendering: enum, auto, inherit, initial
4958 SetDiscrete(SVGData.mTextRendering, svg->mTextRendering, inherited,
4959 SETDSC_ENUMERATED | SETDSC_AUTO,
4960 parentSVG->mTextRendering,
4961 NS_STYLE_TEXT_RENDERING_AUTO,
4962 NS_STYLE_TEXT_RENDERING_AUTO, 0, 0, 0);
4964 COMPUTE_END_INHERITED(SVG, svg)
4967 const void*
4968 nsRuleNode::ComputeSVGResetData(void* aStartStruct,
4969 const nsRuleDataStruct& aData,
4970 nsStyleContext* aContext,
4971 nsRuleNode* aHighestNode,
4972 const RuleDetail aRuleDetail, PRBool aInherited)
4974 COMPUTE_START_RESET(SVGReset, (), svgReset, parentSVGReset, SVG, SVGData)
4976 // stop-color:
4977 if (eCSSUnit_Initial == SVGData.mStopColor.GetUnit()) {
4978 svgReset->mStopColor = NS_RGB(0, 0, 0);
4979 } else {
4980 SetColor(SVGData.mStopColor, parentSVGReset->mStopColor,
4981 mPresContext, aContext, svgReset->mStopColor, inherited);
4984 // flood-color:
4985 if (eCSSUnit_Initial == SVGData.mFloodColor.GetUnit()) {
4986 svgReset->mFloodColor = NS_RGB(0, 0, 0);
4987 } else {
4988 SetColor(SVGData.mFloodColor, parentSVGReset->mFloodColor,
4989 mPresContext, aContext, svgReset->mFloodColor, inherited);
4992 // lighting-color:
4993 if (eCSSUnit_Initial == SVGData.mLightingColor.GetUnit()) {
4994 svgReset->mLightingColor = NS_RGB(255, 255, 255);
4995 } else {
4996 SetColor(SVGData.mLightingColor, parentSVGReset->mLightingColor,
4997 mPresContext, aContext, svgReset->mLightingColor, inherited);
5000 // clip-path: url, none, inherit
5001 if (eCSSUnit_URL == SVGData.mClipPath.GetUnit()) {
5002 svgReset->mClipPath = SVGData.mClipPath.GetURLValue();
5003 } else if (eCSSUnit_None == SVGData.mClipPath.GetUnit() ||
5004 eCSSUnit_Initial == SVGData.mClipPath.GetUnit()) {
5005 svgReset->mClipPath = nsnull;
5006 } else if (eCSSUnit_Inherit == SVGData.mClipPath.GetUnit()) {
5007 inherited = PR_TRUE;
5008 svgReset->mClipPath = parentSVGReset->mClipPath;
5011 // stop-opacity:
5012 SetFactor(SVGData.mStopOpacity, svgReset->mStopOpacity, inherited,
5013 parentSVGReset->mStopOpacity, 1.0f, SETFCT_OPACITY);
5015 // flood-opacity:
5016 SetFactor(SVGData.mFloodOpacity, svgReset->mFloodOpacity, inherited,
5017 parentSVGReset->mFloodOpacity, 1.0f, SETFCT_OPACITY);
5019 // dominant-baseline: enum, auto, inherit, initial
5020 SetDiscrete(SVGData.mDominantBaseline, svgReset->mDominantBaseline,
5021 inherited,
5022 SETDSC_ENUMERATED | SETDSC_AUTO,
5023 parentSVGReset->mDominantBaseline,
5024 NS_STYLE_DOMINANT_BASELINE_AUTO,
5025 NS_STYLE_DOMINANT_BASELINE_AUTO, 0, 0, 0);
5027 // filter: url, none, inherit
5028 if (eCSSUnit_URL == SVGData.mFilter.GetUnit()) {
5029 svgReset->mFilter = SVGData.mFilter.GetURLValue();
5030 } else if (eCSSUnit_None == SVGData.mFilter.GetUnit() ||
5031 eCSSUnit_Initial == SVGData.mFilter.GetUnit()) {
5032 svgReset->mFilter = nsnull;
5033 } else if (eCSSUnit_Inherit == SVGData.mFilter.GetUnit()) {
5034 inherited = PR_TRUE;
5035 svgReset->mFilter = parentSVGReset->mFilter;
5038 // mask: url, none, inherit
5039 if (eCSSUnit_URL == SVGData.mMask.GetUnit()) {
5040 svgReset->mMask = SVGData.mMask.GetURLValue();
5041 } else if (eCSSUnit_None == SVGData.mMask.GetUnit() ||
5042 eCSSUnit_Initial == SVGData.mMask.GetUnit()) {
5043 svgReset->mMask = nsnull;
5044 } else if (eCSSUnit_Inherit == SVGData.mMask.GetUnit()) {
5045 inherited = PR_TRUE;
5046 svgReset->mMask = parentSVGReset->mMask;
5049 COMPUTE_END_RESET(SVGReset, svgReset)
5051 #endif
5053 inline const void*
5054 nsRuleNode::GetParentData(const nsStyleStructID aSID)
5056 NS_PRECONDITION(mDependentBits & nsCachedStyleData::GetBitForSID(aSID),
5057 "should be called when node depends on parent data");
5058 NS_ASSERTION(mStyleData.GetStyleData(aSID) == nsnull,
5059 "both struct and dependent bits present");
5060 // Walk up the rule tree from this rule node (towards less specific
5061 // rules).
5062 PRUint32 bit = nsCachedStyleData::GetBitForSID(aSID);
5063 nsRuleNode *ruleNode = mParent;
5064 while (ruleNode->mDependentBits & bit) {
5065 NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nsnull,
5066 "both struct and dependent bits present");
5067 ruleNode = ruleNode->mParent;
5070 return ruleNode->mStyleData.GetStyleData(aSID);
5073 #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
5074 inline const nsStyle##name_ * \
5075 nsRuleNode::GetParent##name_() \
5077 NS_PRECONDITION(mDependentBits & \
5078 nsCachedStyleData::GetBitForSID(eStyleStruct_##name_), \
5079 "should be called when node depends on parent data"); \
5080 NS_ASSERTION(mStyleData.GetStyle##name_() == nsnull, \
5081 "both struct and dependent bits present"); \
5082 /* Walk up the rule tree from this rule node (towards less specific */ \
5083 /* rules). */ \
5084 PRUint32 bit = nsCachedStyleData::GetBitForSID(eStyleStruct_##name_); \
5085 nsRuleNode *ruleNode = mParent; \
5086 while (ruleNode->mDependentBits & bit) { \
5087 NS_ASSERTION(ruleNode->mStyleData.GetStyle##name_() == nsnull, \
5088 "both struct and dependent bits present"); \
5089 ruleNode = ruleNode->mParent; \
5092 return ruleNode->mStyleData.GetStyle##name_(); \
5094 #include "nsStyleStructList.h"
5095 #undef STYLE_STRUCT
5097 const void*
5098 nsRuleNode::GetStyleData(nsStyleStructID aSID,
5099 nsStyleContext* aContext,
5100 PRBool aComputeData)
5102 const void *data;
5103 if (mDependentBits & nsCachedStyleData::GetBitForSID(aSID)) {
5104 // We depend on an ancestor for this struct since the cached struct
5105 // it has is also appropriate for this rule node. Just go up the
5106 // rule tree and return the first cached struct we find.
5107 data = GetParentData(aSID);
5108 NS_ASSERTION(data, "dependent bits set but no cached struct present");
5109 return data;
5112 data = mStyleData.GetStyleData(aSID);
5113 if (NS_LIKELY(data != nsnull))
5114 return data; // We have a fully specified struct. Just return it.
5116 if (NS_UNLIKELY(!aComputeData))
5117 return nsnull;
5119 // Nothing is cached. We'll have to delve further and examine our rules.
5120 #define STYLE_STRUCT_TEST aSID
5121 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
5122 data = Get##name##Data(aContext);
5123 #include "nsStyleStructList.h"
5124 #undef STYLE_STRUCT
5125 #undef STYLE_STRUCT_TEST
5127 if (NS_LIKELY(data != nsnull))
5128 return data;
5130 NS_NOTREACHED("could not create style struct");
5131 // To ensure that |GetStyleData| never returns null (even when we're
5132 // out of memory), we'll get the style set and get a copy of the
5133 // default values for the given style struct from the set. Note that
5134 // this works fine even if |this| is a rule node that has been
5135 // destroyed (leftover from a previous rule tree) but is somehow still
5136 // used.
5137 return mPresContext->PresShell()->StyleSet()->
5138 DefaultStyleData()->GetStyleData(aSID);
5141 // See comments above in GetStyleData for an explanation of what the
5142 // code below does.
5143 #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
5144 const nsStyle##name_* \
5145 nsRuleNode::GetStyle##name_(nsStyleContext* aContext, PRBool aComputeData) \
5147 const nsStyle##name_ *data; \
5148 if (mDependentBits & \
5149 nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)) { \
5150 data = GetParent##name_(); \
5151 NS_ASSERTION(data, "dependent bits set but no cached struct present"); \
5152 return data; \
5155 data = mStyleData.GetStyle##name_(); \
5156 if (NS_LIKELY(data != nsnull)) \
5157 return data; \
5159 if (NS_UNLIKELY(!aComputeData)) \
5160 return nsnull; \
5162 data = \
5163 static_cast<const nsStyle##name_ *>(Get##name_##Data(aContext)); \
5165 if (NS_LIKELY(data != nsnull)) \
5166 return data; \
5168 NS_NOTREACHED("could not create style struct"); \
5169 return \
5170 static_cast<const nsStyle##name_ *>( \
5171 mPresContext->PresShell()->StyleSet()-> \
5172 DefaultStyleData()->GetStyleData(eStyleStruct_##name_)); \
5174 #include "nsStyleStructList.h"
5175 #undef STYLE_STRUCT
5177 void
5178 nsRuleNode::Mark()
5180 for (nsRuleNode *node = this;
5181 node && !(node->mDependentBits & NS_RULE_NODE_GC_MARK);
5182 node = node->mParent)
5183 node->mDependentBits |= NS_RULE_NODE_GC_MARK;
5186 static PLDHashOperator
5187 SweepRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
5188 PRUint32 number, void *arg)
5190 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
5191 if (entry->mRuleNode->Sweep())
5192 return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
5193 return PL_DHASH_NEXT;
5196 PRBool
5197 nsRuleNode::Sweep()
5199 // If we're not marked, then we have to delete ourself.
5200 // However, we never allow the root node to GC itself, because nsStyleSet
5201 // wants to hold onto the root node and not worry about re-creating a
5202 // rule walker if the root node is deleted.
5203 if (!(mDependentBits & NS_RULE_NODE_GC_MARK) && !IsRoot()) {
5204 Destroy();
5205 return PR_TRUE;
5208 // Clear our mark, for the next time around.
5209 mDependentBits &= ~NS_RULE_NODE_GC_MARK;
5211 // Call sweep on the children, since some may not be marked, and
5212 // remove any deleted children from the child lists.
5213 if (HaveChildren()) {
5214 if (ChildrenAreHashed()) {
5215 PLDHashTable *children = ChildrenHash();
5216 PL_DHashTableEnumerate(children, SweepRuleNodeChildren, nsnull);
5217 } else {
5218 for (nsRuleNode **children = ChildrenListPtr(); *children; ) {
5219 nsRuleNode *next = (*children)->mNextSibling;
5220 if ((*children)->Sweep()) {
5221 // This rule node was destroyed, so implicitly advance by
5222 // making *children point to the next entry.
5223 *children = next;
5224 } else {
5225 // Advance.
5226 children = &(*children)->mNextSibling;
5231 return PR_FALSE;
5234 /* static */ PRBool
5235 nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
5236 PRUint32 ruleTypeMask)
5238 nsRuleDataColor colorData;
5239 nsRuleDataMargin marginData;
5240 PRUint32 nValues = 0;
5242 PRUint32 inheritBits = 0;
5243 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND)
5244 inheritBits |= NS_STYLE_INHERIT_BIT(Background);
5246 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER)
5247 inheritBits |= NS_STYLE_INHERIT_BIT(Border);
5249 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING)
5250 inheritBits |= NS_STYLE_INHERIT_BIT(Padding);
5252 /* We're relying on the use of |aStyleContext| not mutating it! */
5253 nsRuleData ruleData(inheritBits,
5254 aStyleContext->PresContext(), aStyleContext);
5255 ruleData.mColorData = &colorData;
5256 ruleData.mMarginData = &marginData;
5258 nsCSSValue* backgroundValues[] = {
5259 &colorData.mBackColor,
5260 &colorData.mBackImage
5263 nsCSSValue* borderValues[] = {
5264 &marginData.mBorderColor.mTop,
5265 &marginData.mBorderStyle.mTop,
5266 &marginData.mBorderWidth.mTop,
5267 &marginData.mBorderColor.mRight,
5268 &marginData.mBorderStyle.mRight,
5269 &marginData.mBorderWidth.mRight,
5270 &marginData.mBorderColor.mBottom,
5271 &marginData.mBorderStyle.mBottom,
5272 &marginData.mBorderWidth.mBottom,
5273 &marginData.mBorderColor.mLeft,
5274 &marginData.mBorderStyle.mLeft,
5275 &marginData.mBorderWidth.mLeft
5276 // XXX add &marginData.mBorder{Start,End}{Width,Color,Style}
5279 nsCSSValue* paddingValues[] = {
5280 &marginData.mPadding.mTop,
5281 &marginData.mPadding.mRight,
5282 &marginData.mPadding.mBottom,
5283 &marginData.mPadding.mLeft,
5284 &marginData.mPaddingStart,
5285 &marginData.mPaddingEnd
5288 nsCSSValue* values[NS_ARRAY_LENGTH(backgroundValues) +
5289 NS_ARRAY_LENGTH(borderValues) +
5290 NS_ARRAY_LENGTH(paddingValues)];
5292 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
5293 memcpy(&values[nValues], backgroundValues, NS_ARRAY_LENGTH(backgroundValues) * sizeof(nsCSSValue*));
5294 nValues += NS_ARRAY_LENGTH(backgroundValues);
5297 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
5298 memcpy(&values[nValues], borderValues, NS_ARRAY_LENGTH(borderValues) * sizeof(nsCSSValue*));
5299 nValues += NS_ARRAY_LENGTH(borderValues);
5302 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
5303 memcpy(&values[nValues], paddingValues, NS_ARRAY_LENGTH(paddingValues) * sizeof(nsCSSValue*));
5304 nValues += NS_ARRAY_LENGTH(paddingValues);
5307 nsStyleContext* styleContext = aStyleContext;
5309 // We need to be careful not to count styles covered up by user-important or
5310 // UA-important declarations. But we do want to catch explicit inherit
5311 // styling in those and check our parent style context to see whether we have
5312 // user styling for those properties. Note that we don't care here about
5313 // inheritance due to lack of a specified value, since all the properties we
5314 // care about are reset properties.
5315 PRBool haveExplicitUAInherit;
5316 do {
5317 haveExplicitUAInherit = PR_FALSE;
5318 for (nsRuleNode* ruleNode = styleContext->GetRuleNode(); ruleNode;
5319 ruleNode = ruleNode->GetParent()) {
5320 nsIStyleRule *rule = ruleNode->GetRule();
5321 if (rule) {
5322 ruleData.mLevel = ruleNode->GetLevel();
5323 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
5324 rule->MapRuleInfoInto(&ruleData);
5325 // Do the same nulling out as in GetBorderData, GetBackgroundData
5326 // or GetPaddingData.
5327 // We are sharing with some style rule. It really owns the data.
5328 marginData.mBoxShadow = nsnull;
5330 if (ruleData.mLevel == nsStyleSet::eAgentSheet ||
5331 ruleData.mLevel == nsStyleSet::eUserSheet) {
5332 // This is a rule whose effect we want to ignore, so if any of
5333 // the properties we care about were set, set them to the dummy
5334 // value that they'll never otherwise get.
5335 for (PRUint32 i = 0; i < nValues; ++i) {
5336 nsCSSUnit unit = values[i]->GetUnit();
5337 if (unit != eCSSUnit_Null &&
5338 unit != eCSSUnit_Dummy &&
5339 unit != eCSSUnit_DummyInherit) {
5340 if (unit == eCSSUnit_Inherit) {
5341 haveExplicitUAInherit = PR_TRUE;
5342 values[i]->SetDummyInheritValue();
5343 } else {
5344 values[i]->SetDummyValue();
5348 } else {
5349 // If any of the values we care about was set by the above rule,
5350 // we have author style.
5351 for (PRUint32 i = 0; i < nValues; ++i)
5352 if (values[i]->GetUnit() != eCSSUnit_Null &&
5353 values[i]->GetUnit() != eCSSUnit_Dummy && // see above
5354 values[i]->GetUnit() != eCSSUnit_DummyInherit)
5355 return PR_TRUE;
5360 if (haveExplicitUAInherit) {
5361 // reset all the eCSSUnit_Null values to eCSSUnit_Dummy (since they're
5362 // not styled by the author, or by anyone else), and then reset all the
5363 // eCSSUnit_DummyInherit values to eCSSUnit_Null (so we will be able to
5364 // detect them being styled by the author) and move up to our parent
5365 // style context.
5366 for (PRUint32 i = 0; i < nValues; ++i)
5367 if (values[i]->GetUnit() == eCSSUnit_Null)
5368 values[i]->SetDummyValue();
5369 for (PRUint32 i = 0; i < nValues; ++i)
5370 if (values[i]->GetUnit() == eCSSUnit_DummyInherit)
5371 values[i]->Reset();
5372 styleContext = styleContext->GetParent();
5374 } while (haveExplicitUAInherit && styleContext);
5376 return PR_FALSE;