Back to index

lightning-sunbird  0.9+nobinonly
nsRuleNode.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Original Author: David W. Hyatt (hyatt@netscape.com)
00024  *   Daniel Glazman <glazman@netscape.com>
00025  *   Roger B. Sidje <rbs@maths.uq.edu.au>
00026  *   Mats Palmgren <mats.palmgren@bredband.net>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsRuleNode.h"
00043 #include "nscore.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsIDeviceContext.h"
00046 #include "nsILookAndFeel.h"
00047 #include "nsIPresShell.h"
00048 #include "nsIFontMetrics.h"
00049 #include "nsIDocShellTreeItem.h"
00050 #include "nsStyleUtil.h"
00051 #include "nsCSSPseudoElements.h"
00052 #include "nsThemeConstants.h"
00053 #include "nsITheme.h"
00054 #include "pldhash.h"
00055 #include "nsStyleContext.h"
00056 #include "nsStyleSet.h"
00057 #include "nsSize.h"
00058 #include "imgIRequest.h"
00059 #include "nsRuleData.h"
00060 #include "nsILanguageAtomService.h"
00061 #include "nsIStyleRule.h"
00062 
00063 /*
00064  * For storage of an |nsRuleNode|'s children in a linked list.
00065  */
00066 struct nsRuleList {
00067   nsRuleNode* mRuleNode;
00068   nsRuleList* mNext;
00069   
00070 public:
00071   nsRuleList(nsRuleNode* aNode, nsRuleList* aNext= nsnull) {
00072     MOZ_COUNT_CTOR(nsRuleList);
00073     mRuleNode = aNode;
00074     mNext = aNext;
00075   }
00076  
00077   ~nsRuleList() {
00078     MOZ_COUNT_DTOR(nsRuleList);
00079     mRuleNode->Destroy();
00080     if (mNext)
00081       mNext->Destroy(mNext->mRuleNode->mPresContext);
00082   }
00083 
00084   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
00085     return aContext->AllocateFromShell(sz);
00086   };
00087   void operator delete(void* aPtr) {} // Does nothing. The arena will free us up when the rule tree
00088                                       // dies.
00089 
00090   void Destroy(nsPresContext* aContext) {
00091     this->~nsRuleList();
00092     aContext->FreeToShell(sizeof(nsRuleList), this);
00093   }
00094 
00095   // Destroy this node, but not its rule node or the rest of the list.
00096   nsRuleList* DestroySelf(nsPresContext* aContext) {
00097     nsRuleList *next = mNext;
00098     MOZ_COUNT_DTOR(nsRuleList); // hack
00099     aContext->FreeToShell(sizeof(nsRuleList), this);
00100     return next;
00101   }
00102 };
00103 
00104 /*
00105  * For storage of an |nsRuleNode|'s children in a PLDHashTable.
00106  */
00107 
00108 struct ChildrenHashEntry : public PLDHashEntryHdr {
00109   // key (the rule) is |mRuleNode->GetRule()|
00110   nsRuleNode *mRuleNode;
00111 };
00112 
00113 PR_STATIC_CALLBACK(const void *)
00114 ChildrenHashGetKey(PLDHashTable *table, PLDHashEntryHdr *hdr)
00115 {
00116   ChildrenHashEntry *entry = NS_STATIC_CAST(ChildrenHashEntry*, hdr);
00117   return entry->mRuleNode->GetRule();
00118 }
00119 
00120 PR_STATIC_CALLBACK(PRBool)
00121 ChildrenHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
00122                          const void *key)
00123 {
00124   const ChildrenHashEntry *entry =
00125     NS_STATIC_CAST(const ChildrenHashEntry*, hdr);
00126   return entry->mRuleNode->GetRule() == key;
00127 }
00128 
00129 static PLDHashTableOps ChildrenHashOps = {
00130   // It's probably better to allocate the table itself using malloc and
00131   // free rather than the pres shell's arena because the table doesn't
00132   // grow very often and the pres shell's arena doesn't recycle very
00133   // large size allocations.
00134   PL_DHashAllocTable,
00135   PL_DHashFreeTable,
00136   ChildrenHashGetKey,
00137   PL_DHashVoidPtrKeyStub,
00138   ChildrenHashMatchEntry,
00139   PL_DHashMoveEntryStub,
00140   PL_DHashClearEntryStub,
00141   PL_DHashFinalizeStub,
00142   NULL
00143 };
00144 
00145 
00146 // EnsureBlockDisplay:
00147 //  - if the display value (argument) is not a block-type
00148 //    then we set it to a valid block display value
00149 //  - For enforcing the floated/positioned element CSS2 rules
00150 static void EnsureBlockDisplay(PRUint8& display)
00151 {
00152   // see if the display value is already a block
00153   switch (display) {
00154   case NS_STYLE_DISPLAY_NONE :
00155     // never change display:none *ever*
00156   case NS_STYLE_DISPLAY_TABLE :
00157   case NS_STYLE_DISPLAY_BLOCK :
00158   case NS_STYLE_DISPLAY_LIST_ITEM :
00159     // do not muck with these at all - already blocks
00160     // This is equivalent to nsStyleDisplay::IsBlockLevel.  (XXX Maybe we
00161     // should just call that?)
00162     break;
00163 
00164   case NS_STYLE_DISPLAY_INLINE_TABLE :
00165     // make inline tables into tables
00166     display = NS_STYLE_DISPLAY_TABLE;
00167     break;
00168 
00169   default :
00170     // make it a block
00171     display = NS_STYLE_DISPLAY_BLOCK;
00172   }
00173 }
00174 
00175 // XXX This should really be done in the CSS parser.
00176 nsString& Unquote(nsString& aString)
00177 {
00178   PRUnichar start = aString.First();
00179   PRUnichar end = aString.Last();
00180 
00181   if ((start == end) && 
00182       ((start == PRUnichar('\"')) || 
00183        (start == PRUnichar('\'')))) {
00184     PRInt32 length = aString.Length();
00185     aString.Truncate(length - 1);
00186     aString.Cut(0, 1);
00187   }
00188   return aString;
00189 }
00190 
00191 nscoord CalcLength(const nsCSSValue& aValue,
00192                    const nsFont* aFont, 
00193                    nsStyleContext* aStyleContext,
00194                    nsPresContext* aPresContext,
00195                    PRBool& aInherited)
00196 {
00197   NS_ASSERTION(aValue.IsLengthUnit(), "not a length unit");
00198   if (aValue.IsFixedLengthUnit()) {
00199     return aValue.GetLengthTwips();
00200   }
00201   nsCSSUnit unit = aValue.GetUnit();
00202   if (unit == eCSSUnit_Pixel) {
00203     return NSFloatPixelsToTwips(aValue.GetFloatValue(),
00204                                 aPresContext->ScaledPixelsToTwips());
00205   }
00206   // Common code for all units other than pixels:
00207   aInherited = PR_TRUE;
00208   const nsFont* font;
00209   if (aStyleContext) {
00210     font = &aStyleContext->GetStyleFont()->mFont;
00211   } else {
00212     font = aFont;
00213   }
00214   switch (unit) {
00215     case eCSSUnit_EM:
00216     case eCSSUnit_Char: {
00217       return NSToCoordRound(aValue.GetFloatValue() * (float)font->size);
00218       // XXX scale against font metrics height instead?
00219     }
00220     case eCSSUnit_EN: {
00221       return NSToCoordRound((aValue.GetFloatValue() * (float)font->size) / 2.0f);
00222     }
00223     case eCSSUnit_XHeight: {
00224       nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(*font);
00225       nscoord xHeight;
00226       fm->GetXHeight(xHeight);
00227       return NSToCoordRound(aValue.GetFloatValue() * (float)xHeight);
00228     }
00229     case eCSSUnit_CapHeight: {
00230       NS_NOTYETIMPLEMENTED("cap height unit");
00231       nscoord capHeight = ((font->size / 3) * 2); // XXX HACK!
00232       return NSToCoordRound(aValue.GetFloatValue() * (float)capHeight);
00233     }
00234     default:
00235       NS_NOTREACHED("unexpected unit");
00236       break;
00237   }
00238   return 0;
00239 }
00240 
00241 #define SETCOORD_NORMAL       0x01   // N
00242 #define SETCOORD_AUTO         0x02   // A
00243 #define SETCOORD_INHERIT      0x04   // H
00244 #define SETCOORD_PERCENT      0x08   // P
00245 #define SETCOORD_FACTOR       0x10   // F
00246 #define SETCOORD_LENGTH       0x20   // L
00247 #define SETCOORD_INTEGER      0x40   // I
00248 #define SETCOORD_ENUMERATED   0x80   // E
00249 
00250 #define SETCOORD_LP     (SETCOORD_LENGTH | SETCOORD_PERCENT)
00251 #define SETCOORD_LH     (SETCOORD_LENGTH | SETCOORD_INHERIT)
00252 #define SETCOORD_AH     (SETCOORD_AUTO | SETCOORD_INHERIT)
00253 #define SETCOORD_LAH    (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
00254 #define SETCOORD_LPH    (SETCOORD_LP | SETCOORD_INHERIT)
00255 #define SETCOORD_LPAH   (SETCOORD_LP | SETCOORD_AH)
00256 #define SETCOORD_LPEH   (SETCOORD_LP | SETCOORD_ENUMERATED | SETCOORD_INHERIT)
00257 #define SETCOORD_LE     (SETCOORD_LENGTH | SETCOORD_ENUMERATED)
00258 #define SETCOORD_LEH    (SETCOORD_LE | SETCOORD_INHERIT)
00259 #define SETCOORD_IA     (SETCOORD_INTEGER | SETCOORD_AUTO)
00260 #define SETCOORD_LAE    (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
00261 
00262 static PRBool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord, 
00263                        const nsStyleCoord& aParentCoord,
00264                        PRInt32 aMask, nsStyleContext* aStyleContext,
00265                        nsPresContext* aPresContext, PRBool& aInherited)
00266 {
00267   PRBool  result = PR_TRUE;
00268   if (aValue.GetUnit() == eCSSUnit_Null) {
00269     result = PR_FALSE;
00270   }
00271   else if (((aMask & SETCOORD_LENGTH) != 0) && 
00272            (aValue.GetUnit() == eCSSUnit_Char)) {
00273     aCoord.SetIntValue(NSToIntFloor(aValue.GetFloatValue()), eStyleUnit_Chars);
00274   } 
00275   else if (((aMask & SETCOORD_LENGTH) != 0) && 
00276            aValue.IsLengthUnit()) {
00277     aCoord.SetCoordValue(CalcLength(aValue, nsnull, aStyleContext, aPresContext, aInherited));
00278   } 
00279   else if (((aMask & SETCOORD_PERCENT) != 0) && 
00280            (aValue.GetUnit() == eCSSUnit_Percent)) {
00281     aCoord.SetPercentValue(aValue.GetPercentValue());
00282   } 
00283   else if (((aMask & SETCOORD_INTEGER) != 0) && 
00284            (aValue.GetUnit() == eCSSUnit_Integer)) {
00285     aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Integer);
00286   } 
00287   else if (((aMask & SETCOORD_ENUMERATED) != 0) && 
00288            (aValue.GetUnit() == eCSSUnit_Enumerated)) {
00289     aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Enumerated);
00290   } 
00291   else if (((aMask & SETCOORD_AUTO) != 0) && 
00292            (aValue.GetUnit() == eCSSUnit_Auto)) {
00293     aCoord.SetAutoValue();
00294   } 
00295   else if (((aMask & SETCOORD_INHERIT) != 0) && 
00296            (aValue.GetUnit() == eCSSUnit_Inherit)) {
00297     aCoord = aParentCoord;  // just inherit value from parent
00298     aInherited = PR_TRUE;
00299   }
00300   else if (((aMask & SETCOORD_NORMAL) != 0) && 
00301            (aValue.GetUnit() == eCSSUnit_Normal)) {
00302     aCoord.SetNormalValue();
00303   }
00304   else if (((aMask & SETCOORD_FACTOR) != 0) && 
00305            (aValue.GetUnit() == eCSSUnit_Number)) {
00306     aCoord.SetFactorValue(aValue.GetFloatValue());
00307   }
00308   else {
00309     result = PR_FALSE;  // didn't set anything
00310   }
00311   return result;
00312 }
00313 
00314 static PRBool SetColor(const nsCSSValue& aValue, const nscolor aParentColor, 
00315                        nsPresContext* aPresContext, nsStyleContext *aContext,
00316                        nscolor& aResult, PRBool& aInherited)
00317 {
00318   PRBool  result = PR_FALSE;
00319   nsCSSUnit unit = aValue.GetUnit();
00320 
00321   if (eCSSUnit_Color == unit) {
00322     aResult = aValue.GetColorValue();
00323     result = PR_TRUE;
00324   }
00325   else if (eCSSUnit_String == unit) {
00326     nsAutoString  value;
00327     aValue.GetStringValue(value);
00328     nscolor rgba;
00329     if (NS_ColorNameToRGB(value, &rgba)) {
00330       aResult = rgba;
00331       result = PR_TRUE;
00332     }
00333   }
00334   else if (eCSSUnit_Integer == unit) {
00335     PRInt32 intValue = aValue.GetIntValue();
00336     if (0 <= intValue) {
00337       nsILookAndFeel* look = aPresContext->LookAndFeel();
00338       nsILookAndFeel::nsColorID colorID = (nsILookAndFeel::nsColorID) intValue;
00339       if (NS_SUCCEEDED(look->GetColor(colorID, aResult))) {
00340         result = PR_TRUE;
00341       }
00342     }
00343     else {
00344       switch (intValue) {
00345         case NS_COLOR_MOZ_HYPERLINKTEXT:
00346           aResult = aPresContext->DefaultLinkColor();
00347           break;
00348         case NS_COLOR_MOZ_VISITEDHYPERLINKTEXT:
00349           aResult = aPresContext->DefaultVisitedLinkColor();
00350           break;
00351         case NS_COLOR_MOZ_ACTIVEHYPERLINKTEXT:
00352           aResult = aPresContext->DefaultActiveLinkColor();
00353           break;
00354         case NS_COLOR_CURRENTCOLOR:
00355           // The data computed from this can't be shared in the rule tree 
00356           // because they could be used on a node with a different color
00357           aInherited = PR_TRUE;
00358           aResult = aContext->GetStyleColor()->mColor;
00359           break;
00360         default:
00361           NS_NOTREACHED("Should never have an unknown negative colorID.");
00362           break;
00363       }
00364       result = PR_TRUE;
00365     }
00366   }
00367   else if (eCSSUnit_Inherit == unit) {
00368     aResult = aParentColor;
00369     result = PR_TRUE;
00370     aInherited = PR_TRUE;
00371   }
00372   return result;
00373 }
00374 
00375 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
00376 // (which comes from the presShell) to perform the allocation.
00377 void* 
00378 nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
00379 {
00380   // Check the recycle list first.
00381   return aPresContext->AllocateFromShell(sz);
00382 }
00383 
00384 // Overridden to prevent the global delete from being called, since the memory
00385 // came out of an nsIArena instead of the global delete operator's heap.
00386 void 
00387 nsRuleNode::Destroy()
00388 {
00389   // Destroy ourselves.
00390   this->~nsRuleNode();
00391   
00392   // Don't let the memory be freed, since it will be recycled
00393   // instead. Don't call the global operator delete.
00394   mPresContext->FreeToShell(sizeof(nsRuleNode), this);
00395 }
00396 
00397 nsRuleNode* nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
00398 {
00399   return new (aPresContext) nsRuleNode(aPresContext, nsnull, nsnull);
00400 }
00401 
00402 nsILanguageAtomService* nsRuleNode::gLangService = nsnull;
00403 
00404 nsRuleNode::nsRuleNode(nsPresContext* aContext, nsIStyleRule* aRule, nsRuleNode* aParent)
00405   : mPresContext(aContext),
00406     mParent(aParent),
00407     mRule(aRule),
00408     mChildrenTaggedPtr(nsnull),
00409     mDependentBits(0),
00410     mNoneBits(0)
00411 {
00412   MOZ_COUNT_CTOR(nsRuleNode);
00413   NS_IF_ADDREF(mRule);
00414 }
00415 
00416 PR_STATIC_CALLBACK(PLDHashOperator)
00417 DeleteRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
00418                        PRUint32 number, void *arg)
00419 {
00420   ChildrenHashEntry *entry = NS_STATIC_CAST(ChildrenHashEntry*, hdr);
00421   entry->mRuleNode->Destroy();
00422   return PL_DHASH_NEXT;
00423 }
00424 
00425 nsRuleNode::~nsRuleNode()
00426 {
00427   MOZ_COUNT_DTOR(nsRuleNode);
00428   if (mStyleData.mResetData || mStyleData.mInheritedData)
00429     mStyleData.Destroy(0, mPresContext);
00430   if (ChildrenAreHashed()) {
00431     PLDHashTable *children = ChildrenHash();
00432     PL_DHashTableEnumerate(children, DeleteRuleNodeChildren, nsnull);
00433     PL_DHashTableDestroy(children);
00434   } else if (HaveChildren())
00435     ChildrenList()->Destroy(mPresContext);
00436   NS_IF_RELEASE(mRule);
00437 }
00438 
00439 nsresult 
00440 nsRuleNode::Transition(nsIStyleRule* aRule, nsRuleNode** aResult)
00441 {
00442   nsRuleNode* next = nsnull;
00443 
00444   if (HaveChildren() && !ChildrenAreHashed()) {
00445     PRInt32 numKids = 0;
00446     nsRuleList* curr = ChildrenList();
00447     while (curr && curr->mRuleNode->mRule != aRule) {
00448       curr = curr->mNext;
00449       ++numKids;
00450     }
00451     if (curr)
00452       next = curr->mRuleNode;
00453     else if (numKids >= kMaxChildrenInList)
00454       ConvertChildrenToHash();
00455   }
00456 
00457   if (ChildrenAreHashed()) {
00458     ChildrenHashEntry *entry = NS_STATIC_CAST(ChildrenHashEntry*,
00459         PL_DHashTableOperate(ChildrenHash(), aRule, PL_DHASH_ADD));
00460     if (entry->mRuleNode)
00461       next = entry->mRuleNode;
00462     else {
00463       next = entry->mRuleNode =
00464           new (mPresContext) nsRuleNode(mPresContext, aRule, this);
00465       if (!next) {
00466         PL_DHashTableRawRemove(ChildrenHash(), entry);
00467         *aResult = nsnull;
00468         return NS_ERROR_OUT_OF_MEMORY;
00469       }
00470     }
00471   } else if (!next) {
00472     // Create the new entry in our list.
00473     next = new (mPresContext) nsRuleNode(mPresContext, aRule, this);
00474     if (!next) {
00475       *aResult = nsnull;
00476       return NS_ERROR_OUT_OF_MEMORY;
00477     }
00478     nsRuleList* newChildrenList = new (mPresContext) nsRuleList(next, ChildrenList());
00479     if (NS_UNLIKELY(!newChildrenList)) {
00480       next->Destroy();
00481       *aResult = nsnull;
00482       return NS_ERROR_OUT_OF_MEMORY;
00483     }
00484     SetChildrenList(newChildrenList);
00485   }
00486   
00487   *aResult = next;
00488   return NS_OK;
00489 }
00490 
00491 void
00492 nsRuleNode::ConvertChildrenToHash()
00493 {
00494   NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
00495                "must have a non-empty list of children");
00496   PLDHashTable *hash = PL_NewDHashTable(&ChildrenHashOps, nsnull,
00497                                         sizeof(ChildrenHashEntry),
00498                                         kMaxChildrenInList * 4);
00499   if (!hash)
00500     return;
00501   for (nsRuleList* curr = ChildrenList(); curr;
00502        curr = curr->DestroySelf(mPresContext)) {
00503     // This will never fail because of the initial size we gave the table.
00504     ChildrenHashEntry *entry = NS_STATIC_CAST(ChildrenHashEntry*,
00505         PL_DHashTableOperate(hash, curr->mRuleNode->mRule, PL_DHASH_ADD));
00506     NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
00507     entry->mRuleNode = curr->mRuleNode;
00508   }
00509   SetChildrenHash(hash);
00510 }
00511 
00512 PR_STATIC_CALLBACK(PLDHashOperator)
00513 ClearStyleDataHelper(PLDHashTable *table, PLDHashEntryHdr *hdr,
00514                                PRUint32 number, void *arg)
00515 {
00516   ChildrenHashEntry *entry = NS_STATIC_CAST(ChildrenHashEntry*, hdr);
00517   entry->mRuleNode->ClearStyleData();
00518   return PL_DHASH_NEXT;
00519 }
00520 
00521 nsresult
00522 nsRuleNode::ClearStyleData()
00523 {
00524   // Blow away all data stored at this node.
00525   if (mStyleData.mResetData || mStyleData.mInheritedData)
00526     mStyleData.Destroy(0, mPresContext);
00527 
00528   mNoneBits &= ~NS_STYLE_INHERIT_MASK;
00529   mDependentBits &= ~NS_STYLE_INHERIT_MASK;
00530 
00531   if (ChildrenAreHashed())
00532     PL_DHashTableEnumerate(ChildrenHash(),
00533                            ClearStyleDataHelper, nsnull);
00534   else
00535     for (nsRuleList* curr = ChildrenList(); curr; curr = curr->mNext)
00536       curr->mRuleNode->ClearStyleData();
00537 
00538   return NS_OK;
00539 }
00540 
00541 inline void
00542 nsRuleNode::PropagateNoneBit(PRUint32 aBit, nsRuleNode* aHighestNode)
00543 {
00544   nsRuleNode* curr = this;
00545   for (;;) {
00546     NS_ASSERTION(!(curr->mNoneBits & aBit), "propagating too far");
00547     curr->mNoneBits |= aBit;
00548     if (curr == aHighestNode)
00549       break;
00550     curr = curr->mParent;
00551   }
00552 }
00553 
00554 inline void
00555 nsRuleNode::PropagateDependentBit(PRUint32 aBit, nsRuleNode* aHighestNode)
00556 {
00557   for (nsRuleNode* curr = this; curr != aHighestNode; curr = curr->mParent) {
00558     if (curr->mDependentBits & aBit) {
00559 #ifdef DEBUG
00560       while (curr != aHighestNode) {
00561         NS_ASSERTION(curr->mDependentBits & aBit, "bit not set");
00562         curr = curr->mParent;
00563       }
00564 #endif
00565       break;
00566     }
00567 
00568     curr->mDependentBits |= aBit;
00569   }
00570 }
00571 
00572 /*
00573  * The following "Check" functions are used for determining what type of
00574  * sharing can be used for the data on this rule node.  MORE HERE...
00575  */
00576 
00577 /* the information for a property (or in some cases, a rect group of
00578    properties) */
00579 
00580 struct PropertyCheckData {
00581   size_t offset;
00582   nsCSSType type;
00583 };
00584 
00585 /* the information for all the properties in a style struct */
00586 
00587 typedef nsRuleNode::RuleDetail
00588   (* PR_CALLBACK CheckCallbackFn)(const nsRuleDataStruct& aData);
00589 
00590 struct StructCheckData {
00591   const PropertyCheckData* props;
00592   PRInt32 nprops;
00593   CheckCallbackFn callback;
00594 };
00595 
00596 
00602 inline void
00603 ExamineCSSValue(const nsCSSValue& aValue,
00604                 PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
00605 {
00606   if (aValue.GetUnit() != eCSSUnit_Null) {
00607     ++aSpecifiedCount;
00608     if (aValue.GetUnit() == eCSSUnit_Inherit) {
00609       ++aInheritedCount;
00610     }
00611   }
00612 }
00613 
00614 static void
00615 ExamineCSSValuePair(const nsCSSValuePair* aValuePair,
00616                     PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
00617 {
00618   NS_PRECONDITION(aValuePair, "Must have a value pair");
00619   
00620   ExamineCSSValue(aValuePair->mXValue, aSpecifiedCount, aInheritedCount);
00621   ExamineCSSValue(aValuePair->mYValue, aSpecifiedCount, aInheritedCount);
00622 }
00623 
00624 static void
00625 ExamineCSSRect(const nsCSSRect* aRect,
00626                PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
00627 {
00628   NS_PRECONDITION(aRect, "Must have a rect");
00629 
00630   NS_FOR_CSS_SIDES(side) {
00631     ExamineCSSValue(aRect->*(nsCSSRect::sides[side]),
00632                     aSpecifiedCount, aInheritedCount);
00633   }
00634 }
00635 
00636 PR_STATIC_CALLBACK(nsRuleNode::RuleDetail)
00637 CheckFontCallback(const nsRuleDataStruct& aData)
00638 {
00639   const nsRuleDataFont& fontData =
00640       NS_STATIC_CAST(const nsRuleDataFont&, aData);
00641   if (eCSSUnit_Enumerated == fontData.mFamily.GetUnit()) {
00642     // A special case. We treat this as a fully specified font,
00643     // since no other font props are legal with a system font.
00644     PRInt32 family = fontData.mFamily.GetIntValue();
00645     if ((family == NS_STYLE_FONT_CAPTION) ||
00646         (family == NS_STYLE_FONT_ICON) ||
00647         (family == NS_STYLE_FONT_MENU) ||
00648         (family == NS_STYLE_FONT_MESSAGE_BOX) ||
00649         (family == NS_STYLE_FONT_SMALL_CAPTION) ||
00650         (family == NS_STYLE_FONT_STATUS_BAR) ||
00651         (family == NS_STYLE_FONT_WINDOW) ||
00652         (family == NS_STYLE_FONT_DOCUMENT) ||
00653         (family == NS_STYLE_FONT_WORKSPACE) ||
00654         (family == NS_STYLE_FONT_DESKTOP) ||
00655         (family == NS_STYLE_FONT_INFO) ||
00656         (family == NS_STYLE_FONT_DIALOG) ||
00657         (family == NS_STYLE_FONT_BUTTON) ||
00658         (family == NS_STYLE_FONT_PULL_DOWN_MENU) ||
00659         (family == NS_STYLE_FONT_LIST) ||
00660         (family == NS_STYLE_FONT_FIELD))
00661       // Mixed rather than Reset in case another sub-property has
00662       // an explicit 'inherit'.   XXXperf Could check them.
00663       return nsRuleNode::eRuleFullMixed;
00664   }
00665   return nsRuleNode::eRuleUnknown;
00666 }
00667 
00668 // for nsCSSPropList.h, so we get information on things in the style
00669 // structs but not nsCSS*
00670 #define CSS_PROP_INCLUDE_NOT_CSS
00671 
00672 static const PropertyCheckData FontCheckProperties[] = {
00673 #define CSS_PROP_FONT(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00674   { offsetof(nsRuleData##datastruct_, member_), type_ },
00675 #include "nsCSSPropList.h"
00676 #undef CSS_PROP_FONT
00677 };
00678 
00679 static const PropertyCheckData DisplayCheckProperties[] = {
00680 #define CSS_PROP_DISPLAY(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00681   { offsetof(nsRuleData##datastruct_, member_), type_ },
00682 #include "nsCSSPropList.h"
00683 #undef CSS_PROP_DISPLAY
00684 };
00685 
00686 static const PropertyCheckData VisibilityCheckProperties[] = {
00687 #define CSS_PROP_VISIBILITY(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00688   { offsetof(nsRuleData##datastruct_, member_), type_ },
00689 #include "nsCSSPropList.h"
00690 #undef CSS_PROP_VISIBILITY
00691 };
00692 
00693 static const PropertyCheckData MarginCheckProperties[] = {
00694 #define CSS_PROP_MARGIN(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00695   { offsetof(nsRuleData##datastruct_, member_), type_ },
00696 #include "nsCSSPropList.h"
00697 #undef CSS_PROP_MARGIN
00698 };
00699 
00700 static const PropertyCheckData BorderCheckProperties[] = {
00701 #define CSS_PROP_BORDER(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00702   { offsetof(nsRuleData##datastruct_, member_), type_ },
00703 #include "nsCSSPropList.h"
00704 #undef CSS_PROP_BORDER
00705 };
00706 
00707 static const PropertyCheckData PaddingCheckProperties[] = {
00708 #define CSS_PROP_PADDING(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00709   { offsetof(nsRuleData##datastruct_, member_), type_ },
00710 #include "nsCSSPropList.h"
00711 #undef CSS_PROP_PADDING
00712 };
00713 
00714 static const PropertyCheckData OutlineCheckProperties[] = {
00715 #define CSS_PROP_OUTLINE(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00716   { offsetof(nsRuleData##datastruct_, member_), type_ },
00717 #include "nsCSSPropList.h"
00718 #undef CSS_PROP_OUTLINE
00719 };
00720 
00721 static const PropertyCheckData ListCheckProperties[] = {
00722 #define CSS_PROP_LIST(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00723   { offsetof(nsRuleData##datastruct_, member_), type_ },
00724 #include "nsCSSPropList.h"
00725 #undef CSS_PROP_LIST
00726 };
00727 
00728 static const PropertyCheckData ColorCheckProperties[] = {
00729 #define CSS_PROP_COLOR(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00730   { offsetof(nsRuleData##datastruct_, member_), type_ },
00731 #include "nsCSSPropList.h"
00732 #undef CSS_PROP_COLOR
00733 };
00734 
00735 static const PropertyCheckData BackgroundCheckProperties[] = {
00736 #define CSS_PROP_BACKGROUND(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00737   { offsetof(nsRuleData##datastruct_, member_), type_ },
00738 #include "nsCSSPropList.h"
00739 #undef CSS_PROP_BACKGROUND
00740 };
00741 
00742 static const PropertyCheckData PositionCheckProperties[] = {
00743 #define CSS_PROP_POSITION(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00744   { offsetof(nsRuleData##datastruct_, member_), type_ },
00745 #include "nsCSSPropList.h"
00746 #undef CSS_PROP_POSITION
00747 };
00748 
00749 static const PropertyCheckData TableCheckProperties[] = {
00750 #define CSS_PROP_TABLE(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00751   { offsetof(nsRuleData##datastruct_, member_), type_ },
00752 #include "nsCSSPropList.h"
00753 #undef CSS_PROP_TABLE
00754 };
00755 
00756 static const PropertyCheckData TableBorderCheckProperties[] = {
00757 #define CSS_PROP_TABLEBORDER(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00758   { offsetof(nsRuleData##datastruct_, member_), type_ },
00759 #include "nsCSSPropList.h"
00760 #undef CSS_PROP_TABLEBORDER
00761 };
00762 
00763 static const PropertyCheckData ContentCheckProperties[] = {
00764 #define CSS_PROP_CONTENT(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00765   { offsetof(nsRuleData##datastruct_, member_), type_ },
00766 #include "nsCSSPropList.h"
00767 #undef CSS_PROP_CONTENT
00768 };
00769 
00770 static const PropertyCheckData QuotesCheckProperties[] = {
00771 #define CSS_PROP_QUOTES(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00772   { offsetof(nsRuleData##datastruct_, member_), type_ },
00773 #include "nsCSSPropList.h"
00774 #undef CSS_PROP_QUOTES
00775 };
00776 
00777 static const PropertyCheckData TextCheckProperties[] = {
00778 #define CSS_PROP_TEXT(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00779   { offsetof(nsRuleData##datastruct_, member_), type_ },
00780 #include "nsCSSPropList.h"
00781 #undef CSS_PROP_TEXT
00782 };
00783 
00784 static const PropertyCheckData TextResetCheckProperties[] = {
00785 #define CSS_PROP_TEXTRESET(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00786   { offsetof(nsRuleData##datastruct_, member_), type_ },
00787 #include "nsCSSPropList.h"
00788 #undef CSS_PROP_TEXTRESET
00789 };
00790 
00791 static const PropertyCheckData UserInterfaceCheckProperties[] = {
00792 #define CSS_PROP_USERINTERFACE(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00793   { offsetof(nsRuleData##datastruct_, member_), type_ },
00794 #include "nsCSSPropList.h"
00795 #undef CSS_PROP_USERINTERFACE
00796 };
00797 
00798 static const PropertyCheckData UIResetCheckProperties[] = {
00799 #define CSS_PROP_UIRESET(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00800   { offsetof(nsRuleData##datastruct_, member_), type_ },
00801 #include "nsCSSPropList.h"
00802 #undef CSS_PROP_UIRESET
00803 };
00804 
00805 static const PropertyCheckData XULCheckProperties[] = {
00806 #define CSS_PROP_XUL(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00807   { offsetof(nsRuleData##datastruct_, member_), type_ },
00808 #include "nsCSSPropList.h"
00809 #undef CSS_PROP_XUL
00810 };
00811 
00812 #ifdef MOZ_SVG
00813 static const PropertyCheckData SVGCheckProperties[] = {
00814 #define CSS_PROP_SVG(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00815   { offsetof(nsRuleData##datastruct_, member_), type_ },
00816 #include "nsCSSPropList.h"
00817 #undef CSS_PROP_SVG
00818 };
00819 
00820 static const PropertyCheckData SVGResetCheckProperties[] = {
00821 #define CSS_PROP_SVGRESET(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00822   { offsetof(nsRuleData##datastruct_, member_), type_ },
00823 #include "nsCSSPropList.h"
00824 #undef CSS_PROP_SVGRESET
00825 };  
00826 #endif
00827 
00828 static const PropertyCheckData ColumnCheckProperties[] = {
00829 #define CSS_PROP_COLUMN(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00830   { offsetof(nsRuleData##datastruct_, member_), type_ },
00831 #include "nsCSSPropList.h"
00832 #undef CSS_PROP_COLUMN
00833 };
00834 
00835 #undef CSS_PROP_INCLUDE_NOT_CSS
00836   
00837 static const StructCheckData gCheckProperties[] = {
00838 
00839 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
00840   {name##CheckProperties, \
00841    sizeof(name##CheckProperties)/sizeof(PropertyCheckData), \
00842    checkdata_cb},
00843 #include "nsStyleStructList.h"
00844 #undef STYLE_STRUCT
00845   {nsnull, 0, nsnull}
00846 
00847 };
00848 
00849 
00850 
00851 // XXXldb Taking the address of a reference is evil.
00852 
00853 inline const nsCSSValue&
00854 ValueAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
00855 {
00856   return * NS_REINTERPRET_CAST(const nsCSSValue*,
00857                      NS_REINTERPRET_CAST(const char*, &aRuleDataStruct) + aOffset);
00858 }
00859 
00860 inline const nsCSSRect*
00861 RectAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
00862 {
00863   return NS_REINTERPRET_CAST(const nsCSSRect*,
00864                      NS_REINTERPRET_CAST(const char*, &aRuleDataStruct) + aOffset);
00865 }
00866 
00867 inline const nsCSSValuePair*
00868 ValuePairAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
00869 {
00870   return NS_REINTERPRET_CAST(const nsCSSValuePair*,
00871                      NS_REINTERPRET_CAST(const char*, &aRuleDataStruct) + aOffset);
00872 }
00873 
00874 inline const nsCSSValueList*
00875 ValueListAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
00876 {
00877   return * NS_REINTERPRET_CAST(const nsCSSValueList*const*,
00878                      NS_REINTERPRET_CAST(const char*, &aRuleDataStruct) + aOffset);
00879 }
00880 
00881 inline const nsCSSValueList**
00882 ValueListArrayAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
00883 {
00884   return * NS_REINTERPRET_CAST(const nsCSSValueList**const*,
00885                      NS_REINTERPRET_CAST(const char*, &aRuleDataStruct) + aOffset);
00886 }
00887 
00888 inline const nsCSSCounterData*
00889 CounterDataAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
00890 {
00891   return * NS_REINTERPRET_CAST(const nsCSSCounterData*const*,
00892                      NS_REINTERPRET_CAST(const char*, &aRuleDataStruct) + aOffset);
00893 }
00894 
00895 inline const nsCSSQuotes*
00896 QuotesAtOffset(const nsRuleDataStruct& aRuleDataStruct, size_t aOffset)
00897 {
00898   return * NS_REINTERPRET_CAST(const nsCSSQuotes*const*,
00899                      NS_REINTERPRET_CAST(const char*, &aRuleDataStruct) + aOffset);
00900 }
00901 
00902 inline nsRuleNode::RuleDetail
00903 nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID,
00904                                      const nsRuleDataStruct& aRuleDataStruct)
00905 {
00906   const StructCheckData *structData = gCheckProperties + aSID;
00907   if (structData->callback) {
00908     nsRuleNode::RuleDetail res = (*structData->callback)(aRuleDataStruct);
00909     if (res != eRuleUnknown)
00910       return res;
00911   }
00912 
00913   // Build a count of the:
00914   PRUint32 total = 0,      // total number of props in the struct
00915            specified = 0,  // number that were specified for this node
00916            inherited = 0;  // number that were 'inherit' (and not
00917                            //   eCSSUnit_Inherit) for this node
00918   PRBool canHaveExplicitInherit = PR_FALSE;
00919 
00920   for (const PropertyCheckData *prop = structData->props,
00921                            *prop_end = prop + structData->nprops;
00922        prop != prop_end;
00923        ++prop)
00924     switch (prop->type) {
00925 
00926       case eCSSType_Value:
00927         ++total;
00928         ExamineCSSValue(ValueAtOffset(aRuleDataStruct, prop->offset),
00929                         specified, inherited);
00930         break;
00931 
00932       case eCSSType_Rect:
00933         total += 4;
00934         ExamineCSSRect(RectAtOffset(aRuleDataStruct, prop->offset),
00935                        specified, inherited);
00936         break;
00937 
00938       case eCSSType_ValuePair:
00939         total += 2;
00940         ExamineCSSValuePair(ValuePairAtOffset(aRuleDataStruct, prop->offset),
00941                             specified, inherited);
00942         break;
00943         
00944       case eCSSType_ValueList:
00945         {
00946           ++total;
00947           const nsCSSValueList* valueList =
00948               ValueListAtOffset(aRuleDataStruct, prop->offset);
00949           if (valueList) {
00950             ++specified;
00951             if (eCSSUnit_Inherit == valueList->mValue.GetUnit()) {
00952               ++inherited;
00953             }
00954           }
00955         }
00956         break;
00957 
00958       case eCSSType_CounterData:
00959         {
00960           ++total;
00961           const nsCSSCounterData* counterData =
00962               CounterDataAtOffset(aRuleDataStruct, prop->offset);
00963           if (counterData) {
00964             ++specified;
00965             if (eCSSUnit_Inherit == counterData->mCounter.GetUnit()) {
00966               ++inherited;
00967             }
00968           }
00969         }
00970         break;
00971 
00972       case eCSSType_Quotes:
00973         {
00974           ++total;
00975           const nsCSSQuotes* quotes =
00976               QuotesAtOffset(aRuleDataStruct, prop->offset);
00977           if (quotes) {
00978             ++specified;
00979             if (eCSSUnit_Inherit == quotes->mOpen.GetUnit()) {
00980               ++inherited;
00981             }
00982           }
00983         }
00984         break;
00985 
00986       case eCSSType_Shadow:
00987         NS_NOTYETIMPLEMENTED("nsCSSShadow not yet transferred to structs");
00988         break;
00989 
00990       default:
00991         NS_NOTREACHED("unknown type");
00992         break;
00993 
00994     }
00995 
00996 #if 0
00997   printf("CheckSpecifiedProperties: SID=%d total=%d spec=%d inh=%d chei=%s.\n",
00998     aSID, total, specified, inherited, canHaveExplicitInherit?"true":"false");
00999 #endif
01000 
01001   if (canHaveExplicitInherit) {
01002     if (specified == total)
01003       return eRuleFullMixed;
01004     return eRulePartialMixed;
01005   }
01006   if (inherited == total)
01007     return eRuleFullInherited;
01008   if (specified == total) {
01009     if (inherited == 0)
01010       return eRuleFullReset;
01011     return eRuleFullMixed;
01012   }
01013   if (specified == 0)
01014     return eRuleNone;
01015   if (specified == inherited)
01016     return eRulePartialInherited;
01017   if (inherited == 0)
01018     return eRulePartialReset;
01019   return eRulePartialMixed;
01020 }
01021 
01022 const nsStyleStruct*
01023 nsRuleNode::GetDisplayData(nsStyleContext* aContext)
01024 {
01025   nsRuleDataDisplay displayData; // Declare a struct with null CSS values.
01026   nsRuleData ruleData(eStyleStruct_Display, mPresContext, aContext);
01027   ruleData.mDisplayData = &displayData;
01028 
01029   return WalkRuleTree(eStyleStruct_Display, aContext, &ruleData, &displayData);
01030 }
01031 
01032 const nsStyleStruct*
01033 nsRuleNode::GetVisibilityData(nsStyleContext* aContext)
01034 {
01035   nsRuleDataDisplay displayData; // Declare a struct with null CSS values.
01036   nsRuleData ruleData(eStyleStruct_Visibility, mPresContext, aContext);
01037   ruleData.mDisplayData = &displayData;
01038 
01039   return WalkRuleTree(eStyleStruct_Visibility, aContext, &ruleData, &displayData);
01040 }
01041 
01042 const nsStyleStruct*
01043 nsRuleNode::GetTextData(nsStyleContext* aContext)
01044 {
01045   nsRuleDataText textData; // Declare a struct with null CSS values.
01046   nsRuleData ruleData(eStyleStruct_Text, mPresContext, aContext);
01047   ruleData.mTextData = &textData;
01048 
01049   return WalkRuleTree(eStyleStruct_Text, aContext, &ruleData, &textData);
01050 }
01051 
01052 const nsStyleStruct*
01053 nsRuleNode::GetTextResetData(nsStyleContext* aContext)
01054 {
01055   nsRuleDataText textData; // Declare a struct with null CSS values.
01056   nsRuleData ruleData(eStyleStruct_TextReset, mPresContext, aContext);
01057   ruleData.mTextData = &textData;
01058 
01059   return WalkRuleTree(eStyleStruct_TextReset, aContext, &ruleData, &textData);
01060 }
01061 
01062 const nsStyleStruct*
01063 nsRuleNode::GetUserInterfaceData(nsStyleContext* aContext)
01064 {
01065   nsRuleDataUserInterface uiData; // Declare a struct with null CSS values.
01066   nsRuleData ruleData(eStyleStruct_UserInterface, mPresContext, aContext);
01067   ruleData.mUserInterfaceData = &uiData;
01068 
01069   const nsStyleStruct* res = WalkRuleTree(eStyleStruct_UserInterface, aContext, &ruleData, &uiData);
01070   uiData.mCursor = nsnull;
01071   return res;
01072 }
01073 
01074 const nsStyleStruct*
01075 nsRuleNode::GetUIResetData(nsStyleContext* aContext)
01076 {
01077   nsRuleDataUserInterface uiData; // Declare a struct with null CSS values.
01078   nsRuleData ruleData(eStyleStruct_UIReset, mPresContext, aContext);
01079   ruleData.mUserInterfaceData = &uiData;
01080 
01081   const nsStyleStruct* res = WalkRuleTree(eStyleStruct_UIReset, aContext, &ruleData, &uiData);
01082   return res;
01083 }
01084 
01085 const nsStyleStruct*
01086 nsRuleNode::GetFontData(nsStyleContext* aContext)
01087 {
01088   nsRuleDataFont fontData; // Declare a struct with null CSS values.
01089   nsRuleData ruleData(eStyleStruct_Font, mPresContext, aContext);
01090   ruleData.mFontData = &fontData;
01091 
01092   return WalkRuleTree(eStyleStruct_Font, aContext, &ruleData, &fontData);
01093 }
01094 
01095 const nsStyleStruct*
01096 nsRuleNode::GetColorData(nsStyleContext* aContext)
01097 {
01098   nsRuleDataColor colorData; // Declare a struct with null CSS values.
01099   nsRuleData ruleData(eStyleStruct_Color, mPresContext, aContext);
01100   ruleData.mColorData = &colorData;
01101 
01102   return WalkRuleTree(eStyleStruct_Color, aContext, &ruleData, &colorData);
01103 }
01104 
01105 const nsStyleStruct*
01106 nsRuleNode::GetBackgroundData(nsStyleContext* aContext)
01107 {
01108   nsRuleDataColor colorData; // Declare a struct with null CSS values.
01109   nsRuleData ruleData(eStyleStruct_Background, mPresContext, aContext);
01110   ruleData.mColorData = &colorData;
01111 
01112   return WalkRuleTree(eStyleStruct_Background, aContext, &ruleData, &colorData);
01113 }
01114 
01115 const nsStyleStruct*
01116 nsRuleNode::GetMarginData(nsStyleContext* aContext)
01117 {
01118   nsRuleDataMargin marginData; // Declare a struct with null CSS values.
01119   nsRuleData ruleData(eStyleStruct_Margin, mPresContext, aContext);
01120   ruleData.mMarginData = &marginData;
01121 
01122   return WalkRuleTree(eStyleStruct_Margin, aContext, &ruleData, &marginData);
01123 }
01124 
01125 const nsStyleStruct*
01126 nsRuleNode::GetBorderData(nsStyleContext* aContext)
01127 {
01128   nsRuleDataMargin marginData; // Declare a struct with null CSS values.
01129   nsRuleData ruleData(eStyleStruct_Border, mPresContext, aContext);
01130   ruleData.mMarginData = &marginData;
01131 
01132   return WalkRuleTree(eStyleStruct_Border, aContext, &ruleData, &marginData);
01133 }
01134 
01135 const nsStyleStruct*
01136 nsRuleNode::GetPaddingData(nsStyleContext* aContext)
01137 {
01138   nsRuleDataMargin marginData; // Declare a struct with null CSS values.
01139   nsRuleData ruleData(eStyleStruct_Padding, mPresContext, aContext);
01140   ruleData.mMarginData = &marginData;
01141 
01142   return WalkRuleTree(eStyleStruct_Padding, aContext, &ruleData, &marginData);
01143 }
01144 
01145 const nsStyleStruct*
01146 nsRuleNode::GetOutlineData(nsStyleContext* aContext)
01147 {
01148   nsRuleDataMargin marginData; // Declare a struct with null CSS values.
01149   nsRuleData ruleData(eStyleStruct_Outline, mPresContext, aContext);
01150   ruleData.mMarginData = &marginData;
01151 
01152   return WalkRuleTree(eStyleStruct_Outline, aContext, &ruleData, &marginData);
01153 }
01154 
01155 const nsStyleStruct*
01156 nsRuleNode::GetListData(nsStyleContext* aContext)
01157 {
01158   nsRuleDataList listData; // Declare a struct with null CSS values.
01159   nsRuleData ruleData(eStyleStruct_List, mPresContext, aContext);
01160   ruleData.mListData = &listData;
01161 
01162   return WalkRuleTree(eStyleStruct_List, aContext, &ruleData, &listData);
01163 }
01164 
01165 const nsStyleStruct*
01166 nsRuleNode::GetPositionData(nsStyleContext* aContext)
01167 {
01168   nsRuleDataPosition posData; // Declare a struct with null CSS values.
01169   nsRuleData ruleData(eStyleStruct_Position, mPresContext, aContext);
01170   ruleData.mPositionData = &posData;
01171 
01172   return WalkRuleTree(eStyleStruct_Position, aContext, &ruleData, &posData);
01173 }
01174 
01175 const nsStyleStruct*
01176 nsRuleNode::GetTableData(nsStyleContext* aContext)
01177 {
01178   nsRuleDataTable tableData; // Declare a struct with null CSS values.
01179   nsRuleData ruleData(eStyleStruct_Table, mPresContext, aContext);
01180   ruleData.mTableData = &tableData;
01181 
01182   return WalkRuleTree(eStyleStruct_Table, aContext, &ruleData, &tableData);
01183 }
01184 
01185 const nsStyleStruct*
01186 nsRuleNode::GetTableBorderData(nsStyleContext* aContext)
01187 {
01188   nsRuleDataTable tableData; // Declare a struct with null CSS values.
01189   nsRuleData ruleData(eStyleStruct_TableBorder, mPresContext, aContext);
01190   ruleData.mTableData = &tableData;
01191 
01192   return WalkRuleTree(eStyleStruct_TableBorder, aContext, &ruleData, &tableData);
01193 }
01194 
01195 const nsStyleStruct*
01196 nsRuleNode::GetContentData(nsStyleContext* aContext)
01197 {
01198   nsRuleDataContent contentData; // Declare a struct with null CSS values.
01199   nsRuleData ruleData(eStyleStruct_Content, mPresContext, aContext);
01200   ruleData.mContentData = &contentData;
01201 
01202   const nsStyleStruct* res = WalkRuleTree(eStyleStruct_Content, aContext, &ruleData, &contentData);
01203   contentData.mCounterIncrement = contentData.mCounterReset = nsnull;
01204   contentData.mContent = nsnull; // We are sharing with some style rule.  It really owns the data.
01205   return res;
01206 }
01207 
01208 const nsStyleStruct*
01209 nsRuleNode::GetQuotesData(nsStyleContext* aContext)
01210 {
01211   nsRuleDataContent contentData; // Declare a struct with null CSS values.
01212   nsRuleData ruleData(eStyleStruct_Quotes, mPresContext, aContext);
01213   ruleData.mContentData = &contentData;
01214 
01215   const nsStyleStruct* res = WalkRuleTree(eStyleStruct_Quotes, aContext, &ruleData, &contentData);
01216   contentData.mQuotes = nsnull; // We are sharing with some style rule.  It really owns the data.
01217   return res;
01218 }
01219 
01220 const nsStyleStruct*
01221 nsRuleNode::GetXULData(nsStyleContext* aContext)
01222 {
01223   nsRuleDataXUL xulData; // Declare a struct with null CSS values.
01224   nsRuleData ruleData(eStyleStruct_XUL, mPresContext, aContext);
01225   ruleData.mXULData = &xulData;
01226 
01227   return WalkRuleTree(eStyleStruct_XUL, aContext, &ruleData, &xulData);
01228 }
01229 
01230 const nsStyleStruct*
01231 nsRuleNode::GetColumnData(nsStyleContext* aContext)
01232 {
01233   nsRuleDataColumn columnData; // Declare a struct with null CSS values.
01234   nsRuleData ruleData(eStyleStruct_Column, mPresContext, aContext);
01235   ruleData.mColumnData = &columnData;
01236 
01237   return WalkRuleTree(eStyleStruct_Column, aContext, &ruleData, &columnData);
01238 }
01239 
01240 #ifdef MOZ_SVG
01241 const nsStyleStruct*
01242 nsRuleNode::GetSVGData(nsStyleContext* aContext)
01243 {
01244   nsRuleDataSVG svgData; // Declare a struct with null CSS values.
01245   nsRuleData ruleData(eStyleStruct_SVG, mPresContext, aContext);
01246   ruleData.mSVGData = &svgData;
01247 
01248   const nsStyleStruct *res = WalkRuleTree(eStyleStruct_SVG, aContext, &ruleData, &svgData);
01249   svgData.mStrokeDasharray = nsnull; // We are sharing with some style rule.  It really owns the data.
01250   return res;
01251 }
01252 
01253 const nsStyleStruct*
01254 nsRuleNode::GetSVGResetData(nsStyleContext* aContext)
01255 {
01256   nsRuleDataSVG svgData; // Declare a struct with null CSS values.
01257   nsRuleData ruleData(eStyleStruct_SVGReset, mPresContext, aContext);
01258   ruleData.mSVGData = &svgData;
01259 
01260   return WalkRuleTree(eStyleStruct_SVGReset, aContext, &ruleData, &svgData);
01261 }
01262 #endif
01263 
01264 const nsStyleStruct*
01265 nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
01266                          nsStyleContext* aContext, 
01267                          nsRuleData* aRuleData,
01268                          nsRuleDataStruct* aSpecificData)
01269 {
01270   // We start at the most specific rule in the tree.  
01271   nsStyleStruct* startStruct = nsnull;
01272   
01273   nsRuleNode* ruleNode = this;
01274   nsRuleNode* highestNode = nsnull; // The highest node in the rule tree
01275                                     // that has the same properties
01276                                     // specified for struct |aSID| as
01277                                     // |this| does.
01278   nsRuleNode* rootNode = this; // After the loop below, this will be the
01279                                // highest node that we've walked without
01280                                // finding cached data on the rule tree.
01281                                // If we don't find any cached data, it
01282                                // will be the root.  (XXX misnamed)
01283   RuleDetail detail = eRuleNone;
01284   PRUint32 bit = nsCachedStyleData::GetBitForSID(aSID);
01285 
01286   while (ruleNode) {
01287     // See if this rule node has cached the fact that the remaining
01288     // nodes along this path specify no data whatsoever.
01289     if (ruleNode->mNoneBits & bit)
01290       break;
01291 
01292     // If the dependent bit is set on a rule node for this struct, that
01293     // means its rule won't have any information to add, so skip it.
01294     // XXXldb I don't understand why we need to check |detail| here, but
01295     // we do.
01296     if (detail == eRuleNone)
01297       while (ruleNode->mDependentBits & bit) {
01298         NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nsnull,
01299                      "dependent bit with cached data makes no sense");
01300         // Climb up to the next rule in the tree (a less specific rule).
01301         rootNode = ruleNode;
01302         ruleNode = ruleNode->mParent;
01303         NS_ASSERTION(!(ruleNode->mNoneBits & bit), "can't have both bits set");
01304       }
01305 
01306     // Check for cached data after the inner loop above -- otherwise
01307     // we'll miss it.
01308     startStruct = ruleNode->mStyleData.GetStyleData(aSID);
01309     if (startStruct)
01310       break; // We found a rule with fully specified data.  We don't
01311              // need to go up the tree any further, since the remainder
01312              // of this branch has already been computed.
01313 
01314     // Ask the rule to fill in the properties that it specifies.
01315     nsIStyleRule *rule = ruleNode->mRule;
01316     if (rule)
01317       rule->MapRuleInfoInto(aRuleData);
01318 
01319     // Now we check to see how many properties have been specified by
01320     // the rules we've examined so far.
01321     RuleDetail oldDetail = detail;
01322     detail = CheckSpecifiedProperties(aSID, *aSpecificData);
01323   
01324     if (oldDetail == eRuleNone && detail != eRuleNone)
01325       highestNode = ruleNode;
01326 
01327     if (detail == eRuleFullReset ||
01328         detail == eRuleFullMixed ||
01329         detail == eRuleFullInherited)
01330       break; // We don't need to examine any more rules.  All properties
01331              // have been fully specified.
01332 
01333     // Climb up to the next rule in the tree (a less specific rule).
01334     rootNode = ruleNode;
01335     ruleNode = ruleNode->mParent;
01336   }
01337 
01338   PRBool isReset = nsCachedStyleData::IsReset(aSID);
01339   if (!highestNode)
01340     highestNode = rootNode;
01341 
01342   if (!aRuleData->mCanStoreInRuleTree)
01343     detail = eRulePartialMixed; // Treat as though some data is specified to avoid
01344                                 // the optimizations and force data computation.
01345 
01346   if (detail == eRuleNone && startStruct && !aRuleData->mPostResolveCallback) {
01347     // We specified absolutely no rule information, but a parent rule in the tree
01348     // specified all the rule information.  We set a bit along the branch from our
01349     // node in the tree to the node that specified the data that tells nodes on that
01350     // branch that they never need to examine their rules for this particular struct type
01351     // ever again.
01352     PropagateDependentBit(bit, ruleNode);
01353     return startStruct;
01354   }
01355   else if (!startStruct && ((!isReset && (detail == eRuleNone || detail == eRulePartialInherited)) 
01356                              || detail == eRuleFullInherited)) {
01357     // We specified no non-inherited information and neither did any of
01358     // our parent rules.
01359 
01360     // We set a bit along the branch from the highest node (ruleNode)
01361     // down to our node (this) indicating that no non-inherited data was
01362     // specified.  This bit is guaranteed to be set already on the path
01363     // from the highest node to the root node in the case where
01364     // (detail == eRuleNone), which is the most common case here.
01365     // We must check |!isReset| because the Compute*Data functions for
01366     // reset structs wouldn't handle none bits correctly.
01367     if (highestNode != this && !isReset)
01368       PropagateNoneBit(bit, highestNode);
01369     
01370     // All information must necessarily be inherited from our parent style context.
01371     // In the absence of any computed data in the rule tree and with
01372     // no rules specified that didn't have values of 'inherit', we should check our parent.
01373     nsStyleContext* parentContext = aContext->GetParent();
01374     if (parentContext) {
01375       // We have a parent, and so we should just inherit from the parent.
01376       // Set the inherit bits on our context.  These bits tell the style context that
01377       // it never has to go back to the rule tree for data.  Instead the style context tree
01378       // should be walked to find the data.
01379       const nsStyleStruct* parentStruct = parentContext->GetStyleData(aSID);
01380       aContext->AddStyleBit(bit); // makes const_cast OK.
01381       aContext->SetStyle(aSID, NS_CONST_CAST(nsStyleStruct*, parentStruct));
01382       return parentStruct;
01383     }
01384     else
01385       // We are the root.  In the case of fonts, the default values just
01386       // come from the pres context.
01387       return SetDefaultOnRoot(aSID, aContext);
01388   }
01389 
01390   // We need to compute the data from the information that the rules specified.
01391   const nsStyleStruct* res;
01392 #define STYLE_STRUCT_TEST aSID
01393 #define STYLE_STRUCT(name, checkdata_cb, ctor_args)                           \
01394   res = Compute##name##Data(startStruct, *aSpecificData, aContext,            \
01395                       highestNode, detail, !aRuleData->mCanStoreInRuleTree);
01396 #include "nsStyleStructList.h"
01397 #undef STYLE_STRUCT
01398 #undef STYLE_STRUCT_TEST
01399 
01400   // If we have a post-resolve callback, handle that now.
01401   if (aRuleData->mPostResolveCallback && (NS_LIKELY(res != nsnull)))
01402     (*aRuleData->mPostResolveCallback)((nsStyleStruct*)res, aRuleData);
01403 
01404   // Now return the result.
01405   return res;
01406 }
01407 
01408 static PRBool
01409 IsChrome(nsPresContext* aPresContext)
01410 {
01411   PRBool isChrome = PR_FALSE;
01412   nsCOMPtr<nsISupports> container = aPresContext->GetContainer();
01413   if (container) {
01414     nsresult result;
01415     nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(container, &result));
01416     if (NS_SUCCEEDED(result) && docShell) {
01417       PRInt32 docShellType;
01418       result = docShell->GetItemType(&docShellType);
01419       if (NS_SUCCEEDED(result)) {
01420         isChrome = nsIDocShellTreeItem::typeChrome == docShellType;
01421       }
01422     }
01423   }
01424   return isChrome;
01425 }
01426 
01427 const nsStyleStruct*
01428 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
01429 {
01430   switch (aSID) {
01431     case eStyleStruct_Font: 
01432     {
01433       nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
01434       if (NS_LIKELY(fontData != nsnull)) {
01435         nscoord minimumFontSize =
01436           mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
01437 
01438         if (minimumFontSize > 0 && !IsChrome(mPresContext)) {
01439           fontData->mFont.size = PR_MAX(fontData->mSize, minimumFontSize);
01440         }
01441         else {
01442           fontData->mFont.size = fontData->mSize;
01443         }
01444         aContext->SetStyle(eStyleStruct_Font, fontData);
01445       }
01446       return fontData;
01447     }
01448     case eStyleStruct_Display:
01449     {
01450       nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay();
01451       if (NS_LIKELY(disp != nsnull)) {
01452         aContext->SetStyle(eStyleStruct_Display, disp);
01453       }
01454       return disp;
01455     }
01456     case eStyleStruct_Visibility:
01457     {
01458       nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
01459       if (NS_LIKELY(vis != nsnull)) {
01460         aContext->SetStyle(eStyleStruct_Visibility, vis);
01461       }
01462       return vis;
01463     }
01464     case eStyleStruct_Text:
01465     {
01466       nsStyleText* text = new (mPresContext) nsStyleText();
01467       if (NS_LIKELY(text != nsnull)) {
01468         aContext->SetStyle(eStyleStruct_Text, text);
01469       }
01470       return text;
01471     }
01472     case eStyleStruct_TextReset:
01473     {
01474       nsStyleTextReset* text = new (mPresContext) nsStyleTextReset();
01475       if (NS_LIKELY(text != nsnull)) {
01476         aContext->SetStyle(eStyleStruct_TextReset, text);
01477       }
01478       return text;
01479     }
01480     case eStyleStruct_Color:
01481     {
01482       nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
01483       if (NS_LIKELY(color != nsnull)) {
01484         aContext->SetStyle(eStyleStruct_Color, color);
01485       }
01486       return color;
01487     }
01488     case eStyleStruct_Background:
01489     {
01490       nsStyleBackground* bg = new (mPresContext) nsStyleBackground(mPresContext);
01491       if (NS_LIKELY(bg != nsnull)) {
01492         aContext->SetStyle(eStyleStruct_Background, bg);
01493       }
01494       return bg;
01495     }
01496     case eStyleStruct_Margin:
01497     {
01498       nsStyleMargin* margin = new (mPresContext) nsStyleMargin();
01499       if (NS_LIKELY(margin != nsnull)) {
01500         aContext->SetStyle(eStyleStruct_Margin, margin);
01501       }
01502       return margin;
01503     }
01504     case eStyleStruct_Border:
01505     {
01506       nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
01507       if (NS_LIKELY(border != nsnull)) {
01508         aContext->SetStyle(eStyleStruct_Border, border);
01509       }
01510       return border;
01511     }
01512     case eStyleStruct_Padding:
01513     {
01514       nsStylePadding* padding = new (mPresContext) nsStylePadding();
01515       if (NS_LIKELY(padding != nsnull)) {
01516         aContext->SetStyle(eStyleStruct_Padding, padding);
01517       }
01518       return padding;
01519     }
01520     case eStyleStruct_Outline:
01521     {
01522       nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
01523       if (NS_LIKELY(outline != nsnull)) {
01524         aContext->SetStyle(eStyleStruct_Outline, outline);
01525       }
01526       return outline;
01527     }
01528     case eStyleStruct_List:
01529     {
01530       nsStyleList* list = new (mPresContext) nsStyleList();
01531       if (NS_LIKELY(list != nsnull)) {
01532         aContext->SetStyle(eStyleStruct_List, list);
01533       }
01534       return list;
01535     }
01536     case eStyleStruct_Position:
01537     {
01538       nsStylePosition* pos = new (mPresContext) nsStylePosition();
01539       if (NS_LIKELY(pos != nsnull)) {
01540         aContext->SetStyle(eStyleStruct_Position, pos);
01541       }
01542       return pos;
01543     }
01544     case eStyleStruct_Table:
01545     {
01546       nsStyleTable* table = new (mPresContext) nsStyleTable();
01547       if (NS_LIKELY(table != nsnull)) {
01548         aContext->SetStyle(eStyleStruct_Table, table);
01549       }
01550       return table;
01551     }
01552     case eStyleStruct_TableBorder:
01553     {
01554       nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
01555       if (NS_LIKELY(table != nsnull)) {
01556         aContext->SetStyle(eStyleStruct_TableBorder, table);
01557       }
01558       return table;
01559     }
01560     case eStyleStruct_Content:
01561     {
01562       nsStyleContent* content = new (mPresContext) nsStyleContent();
01563       if (NS_LIKELY(content != nsnull)) {
01564         aContext->SetStyle(eStyleStruct_Content, content);
01565       }
01566       return content;
01567     }
01568     case eStyleStruct_Quotes:
01569     {
01570       nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes();
01571       if (NS_LIKELY(quotes != nsnull)) {
01572         aContext->SetStyle(eStyleStruct_Quotes, quotes);
01573       }
01574       return quotes;
01575     }
01576     case eStyleStruct_UserInterface:
01577     {
01578       nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface();
01579       if (NS_LIKELY(ui != nsnull)) {
01580         aContext->SetStyle(eStyleStruct_UserInterface, ui);
01581       }
01582       return ui;
01583     }
01584     case eStyleStruct_UIReset:
01585     {
01586       nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset();
01587       if (NS_LIKELY(ui != nsnull)) {
01588         aContext->SetStyle(eStyleStruct_UIReset, ui);
01589       }
01590       return ui;
01591     }
01592 
01593     case eStyleStruct_XUL:
01594     {
01595       nsStyleXUL* xul = new (mPresContext) nsStyleXUL();
01596       if (NS_LIKELY(xul != nsnull)) {
01597         aContext->SetStyle(eStyleStruct_XUL, xul);
01598       }
01599       return xul;
01600     }
01601 
01602     case eStyleStruct_Column:
01603     {
01604       nsStyleColumn* column = new (mPresContext) nsStyleColumn();
01605       if (NS_LIKELY(column != nsnull)) {
01606         aContext->SetStyle(eStyleStruct_Column, column);
01607       }
01608       return column;
01609     }
01610 
01611 #ifdef MOZ_SVG
01612     case eStyleStruct_SVG:
01613     {
01614       nsStyleSVG* svg = new (mPresContext) nsStyleSVG();
01615       if (NS_LIKELY(svg != nsnull)) {
01616         aContext->SetStyle(eStyleStruct_SVG, svg);
01617       }
01618       return svg;
01619     }
01620 
01621     case eStyleStruct_SVGReset:
01622     {
01623       nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset();
01624       if (NS_LIKELY(svgReset != nsnull)) {
01625         aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
01626       }
01627       return svgReset;
01628     }
01629 #endif
01630   }
01631   return nsnull;
01632 }
01633 
01634 /*
01635  * This function handles cascading of *-left or *-right box properties
01636  * against *-start (which is L for LTR and R for RTL) or *-end (which is
01637  * R for LTR and L for RTL).
01638  *
01639  * Cascading these properties correctly is hard because we need to
01640  * cascade two properties as one, but which two properties depends on a
01641  * third property ('direction').  We solve this by treating each of
01642  * these properties (say, 'margin-start') as a shorthand that sets a
01643  * property containing the value of the property specified
01644  * ('margin-start-value') and sets a pair of properties
01645  * ('margin-left-ltr-source' and 'margin-right-rtl-source') saying which
01646  * of the properties we use.  Thus, when we want to compute the value of
01647  * 'margin-left' when 'direction' is 'ltr', we look at the value of
01648  * 'margin-left-ltr-source', which tells us whether to use the highest
01649  * 'margin-left' in the cascade or the highest 'margin-start'.
01650  *
01651  * Finally, since we can compute the normal (*-left and *-right)
01652  * properties in a loop, this function works by assuming the computation
01653  * for those properties has happened as though we have not implemented
01654  * the logical properties (*-start and *-end).  It is the responsibility
01655  * of this function to replace the computed values with the values
01656  * computed from the logical properties when needed.
01657  */
01658 void
01659 nsRuleNode::AdjustLogicalBoxProp(nsStyleContext* aContext,
01660                                  const nsCSSValue& aLTRSource,
01661                                  const nsCSSValue& aRTLSource,
01662                                  const nsCSSValue& aLTRLogicalValue,
01663                                  const nsCSSValue& aRTLLogicalValue,
01664                                  const nsStyleSides& aParentRect,
01665                                  nsStyleSides& aRect,
01666                                  PRUint8 aSide,
01667                                  PRInt32 aMask,
01668                                  PRBool& aInherited)
01669 {
01670   PRBool LTRlogical = aLTRSource.GetUnit() == eCSSUnit_Enumerated &&
01671                       aLTRSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
01672   PRBool RTLlogical = aRTLSource.GetUnit() == eCSSUnit_Enumerated &&
01673                       aRTLSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
01674   if (LTRlogical || RTLlogical) {
01675     // We can't cache anything on the rule tree if we use any data from
01676     // the style context, since data cached in the rule tree could be
01677     // used with a style context with a different value.
01678     aInherited = PR_TRUE;
01679     PRUint8 dir = aContext->GetStyleVisibility()->mDirection;
01680 
01681     nsStyleCoord parentCoord;
01682     nsStyleCoord coord;
01683     aParentRect.Get(aSide, parentCoord);
01684     if (dir == NS_STYLE_DIRECTION_LTR) {
01685       if (LTRlogical &&
01686           SetCoord(aLTRLogicalValue, coord, parentCoord, aMask, aContext,
01687                    mPresContext, aInherited))
01688         aRect.Set(aSide, coord);
01689     } else {
01690       if (RTLlogical &&
01691           SetCoord(aRTLLogicalValue, coord, parentCoord, aMask, aContext,
01692                    mPresContext, aInherited))
01693         aRect.Set(aSide, coord);
01694     }
01695   }
01696 }
01697   
01698 /* static */ void
01699 nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
01700                     nscoord aMinFontSize, PRBool aUseDocumentFonts,
01701                     PRBool aIsGeneric, const nsRuleDataFont& aFontData,
01702                     const nsFont& aDefaultFont, const nsStyleFont* aParentFont,
01703                     nsStyleFont* aFont, PRBool& aInherited)
01704 {
01705   const nsFont* defaultVariableFont =
01706     aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID);
01707 
01708   const nsFont* defaultFixedFont =
01709     aPresContext->GetDefaultFont(kPresContext_DefaultFixedFont_ID);
01710 
01711   // font-family: string list, enum, inherit
01712   if (eCSSUnit_String == aFontData.mFamily.GetUnit()) {
01713     // set the correct font if we are using DocumentFonts OR we are overriding for XUL
01714     // MJA: bug 31816
01715     if (aUseDocumentFonts) {
01716       if (!aIsGeneric) {
01717         // only bother appending fallback fonts if this isn't a fallback generic font itself
01718         aFont->mFont.name.Append((PRUnichar)',');
01719         aFont->mFont.name.Append(aDefaultFont.name);
01720       }
01721     }
01722     else {
01723       // now set to defaults
01724       aFont->mFont.name = aDefaultFont.name;
01725     }
01726     aFont->mFont.familyNameQuirks =
01727         (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks &&
01728          aFontData.mFamilyFromHTML);
01729   }
01730   else if (eCSSUnit_Enumerated == aFontData.mFamily.GetUnit()) {
01731     nsSystemFontID sysID;
01732     switch (aFontData.mFamily.GetIntValue()) {
01733       // If you add fonts to this list, you need to also patch the list
01734       // in CheckFontCallback (also in this file).
01735       case NS_STYLE_FONT_CAPTION:       sysID = eSystemFont_Caption;      break;    // css2
01736       case NS_STYLE_FONT_ICON:          sysID = eSystemFont_Icon;         break;
01737       case NS_STYLE_FONT_MENU:          sysID = eSystemFont_Menu;         break;
01738       case NS_STYLE_FONT_MESSAGE_BOX:   sysID = eSystemFont_MessageBox;   break;
01739       case NS_STYLE_FONT_SMALL_CAPTION: sysID = eSystemFont_SmallCaption; break;
01740       case NS_STYLE_FONT_STATUS_BAR:    sysID = eSystemFont_StatusBar;    break;
01741       case NS_STYLE_FONT_WINDOW:        sysID = eSystemFont_Window;       break;    // css3
01742       case NS_STYLE_FONT_DOCUMENT:      sysID = eSystemFont_Document;     break;
01743       case NS_STYLE_FONT_WORKSPACE:     sysID = eSystemFont_Workspace;    break;
01744       case NS_STYLE_FONT_DESKTOP:       sysID = eSystemFont_Desktop;      break;
01745       case NS_STYLE_FONT_INFO:          sysID = eSystemFont_Info;         break;
01746       case NS_STYLE_FONT_DIALOG:        sysID = eSystemFont_Dialog;       break;
01747       case NS_STYLE_FONT_BUTTON:        sysID = eSystemFont_Button;       break;
01748       case NS_STYLE_FONT_PULL_DOWN_MENU:sysID = eSystemFont_PullDownMenu; break;
01749       case NS_STYLE_FONT_LIST:          sysID = eSystemFont_List;         break;
01750       case NS_STYLE_FONT_FIELD:         sysID = eSystemFont_Field;        break;
01751     }
01752 
01753     // GetSystemFont sets the font face but not necessarily the size
01754     aFont->mFont.size = defaultVariableFont->size;
01755 
01756     if (NS_FAILED(aPresContext->DeviceContext()->GetSystemFont(sysID,
01757                                                              &aFont->mFont))) {
01758         aFont->mFont.name = defaultVariableFont->name;
01759     }
01760     // this becomes our cascading size
01761     aFont->mSize = aFont->mFont.size =
01762       nsStyleFont::ZoomText(aPresContext, aFont->mFont.size);
01763 
01764     aFont->mFont.familyNameQuirks = PR_FALSE;
01765 
01766     // XXXldb All of this platform-specific stuff should be in the
01767     // nsIDeviceContext implementations, not here.
01768 
01769 #ifdef XP_WIN
01770     //
01771     // As far as I can tell the system default fonts and sizes for
01772     // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are 
01773     // all pre-determined and cannot be changed by either the control panel 
01774     // or programmtically.
01775     //
01776     switch (sysID) {
01777       // Fields (text fields)
01778       // Button and Selects (listboxes/comboboxes)
01779       //    We use whatever font is defined by the system. Which it appears
01780       //    (and the assumption is) it is always a proportional font. Then we
01781       //    always use 2 points smaller than what the browser has defined as
01782       //    the default proportional font.
01783       case eSystemFont_Field:
01784       case eSystemFont_Button:
01785       case eSystemFont_List:
01786         // Assumption: system defined font is proportional
01787         aFont->mSize = nsStyleFont::ZoomText(aPresContext,
01788              PR_MAX(defaultVariableFont->size - NSIntPointsToTwips(2), 0));
01789         break;
01790     }
01791 #endif
01792   }
01793   else if (eCSSUnit_Inherit == aFontData.mFamily.GetUnit()) {
01794     aInherited = PR_TRUE;
01795     aFont->mFont.name = aParentFont->mFont.name;
01796     aFont->mFont.familyNameQuirks = aParentFont->mFont.familyNameQuirks;
01797   }
01798   else if (eCSSUnit_Initial == aFontData.mFamily.GetUnit()) {
01799     aFont->mFont.name = aDefaultFont.name;
01800     aFont->mFont.familyNameQuirks = PR_FALSE;
01801   }
01802 
01803   // font-style: enum, normal, inherit
01804   if (eCSSUnit_Enumerated == aFontData.mStyle.GetUnit()) {
01805     aFont->mFont.style = aFontData.mStyle.GetIntValue();
01806   }
01807   else if (eCSSUnit_Normal == aFontData.mStyle.GetUnit()) {
01808     aFont->mFont.style = NS_STYLE_FONT_STYLE_NORMAL;
01809   }
01810   else if (eCSSUnit_Inherit == aFontData.mStyle.GetUnit()) {
01811     aInherited = PR_TRUE;
01812     aFont->mFont.style = aParentFont->mFont.style;
01813   }
01814   else if (eCSSUnit_Initial == aFontData.mStyle.GetUnit()) {
01815     aFont->mFont.style = aDefaultFont.style;
01816   }
01817 
01818   // font-variant: enum, normal, inherit
01819   if (eCSSUnit_Enumerated == aFontData.mVariant.GetUnit()) {
01820     aFont->mFont.variant = aFontData.mVariant.GetIntValue();
01821   }
01822   else if (eCSSUnit_Normal == aFontData.mVariant.GetUnit()) {
01823     aFont->mFont.variant = NS_STYLE_FONT_VARIANT_NORMAL;
01824   }
01825   else if (eCSSUnit_Inherit == aFontData.mVariant.GetUnit()) {
01826     aInherited = PR_TRUE;
01827     aFont->mFont.variant = aParentFont->mFont.variant;
01828   }
01829   else if (eCSSUnit_Initial == aFontData.mVariant.GetUnit()) {
01830     aFont->mFont.variant = aDefaultFont.variant;
01831   }
01832 
01833   // font-weight: int, enum, normal, inherit
01834   if (eCSSUnit_Integer == aFontData.mWeight.GetUnit()) {
01835     aFont->mFont.weight = aFontData.mWeight.GetIntValue();
01836   }
01837   else if (eCSSUnit_Enumerated == aFontData.mWeight.GetUnit()) {
01838     PRInt32 value = aFontData.mWeight.GetIntValue();
01839     switch (value) {
01840       case NS_STYLE_FONT_WEIGHT_NORMAL:
01841       case NS_STYLE_FONT_WEIGHT_BOLD:
01842         aFont->mFont.weight = value;
01843         break;
01844       case NS_STYLE_FONT_WEIGHT_BOLDER:
01845       case NS_STYLE_FONT_WEIGHT_LIGHTER:
01846         aInherited = PR_TRUE;
01847         aFont->mFont.weight = nsStyleUtil::ConstrainFontWeight(aParentFont->mFont.weight + value);
01848         break;
01849     }
01850   }
01851   else if (eCSSUnit_Normal == aFontData.mWeight.GetUnit()) {
01852     aFont->mFont.weight = NS_STYLE_FONT_WEIGHT_NORMAL;
01853   }
01854   else if (eCSSUnit_Inherit == aFontData.mWeight.GetUnit()) {
01855     aInherited = PR_TRUE;
01856     aFont->mFont.weight = aParentFont->mFont.weight;
01857   }
01858   else if (eCSSUnit_Initial == aFontData.mWeight.GetUnit()) {
01859     aFont->mFont.weight = aDefaultFont.weight;
01860   }
01861 
01862   // font-size: enum, length, percent, inherit
01863   PRBool zoom = PR_FALSE;
01864   if (eCSSUnit_Enumerated == aFontData.mSize.GetUnit()) {
01865     PRInt32 value = aFontData.mSize.GetIntValue();
01866     PRInt32 scaler = aPresContext->FontScaler();
01867     float scaleFactor = nsStyleUtil::GetScalingFactor(scaler);
01868 
01869     zoom = PR_TRUE;
01870     if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) && 
01871         (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
01872       aFont->mSize = nsStyleUtil::CalcFontPointSize(value, (PRInt32)aDefaultFont.size, scaleFactor, aPresContext, eFontSize_CSS);
01873     }
01874     else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
01875       // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
01876       aFont->mSize = nsStyleUtil::CalcFontPointSize(value, (PRInt32)aDefaultFont.size, scaleFactor, aPresContext);
01877     }
01878     else if (NS_STYLE_FONT_SIZE_LARGER      == value ||
01879              NS_STYLE_FONT_SIZE_SMALLER     == value) {
01880 
01881       aInherited = PR_TRUE;
01882 
01883       // Un-zoom so we use the tables correctly.  We'll then rezoom due
01884       // to the |zoom = PR_TRUE| above.
01885       nscoord parentSize =
01886           nsStyleFont::UnZoomText(aPresContext, aParentFont->mSize);
01887 
01888       if (NS_STYLE_FONT_SIZE_LARGER == value) {
01889         aFont->mSize = nsStyleUtil::FindNextLargerFontSize(parentSize, (PRInt32)aDefaultFont.size,
01890                                                            scaleFactor, aPresContext, eFontSize_CSS);
01891         NS_ASSERTION(aFont->mSize > parentSize, "FindNextLargerFontSize failed.");
01892       } 
01893       else {
01894         aFont->mSize = nsStyleUtil::FindNextSmallerFontSize(parentSize, (PRInt32)aDefaultFont.size,
01895                                                             scaleFactor, aPresContext, eFontSize_CSS);
01896         NS_ASSERTION(aFont->mSize < parentSize, 
01897             "FindNextSmallerFontSize failed; this is expected if parentFont size <= 1px");
01898       }
01899     } else {
01900       NS_NOTREACHED("unexpected value");
01901     }
01902   }
01903   else if (aFontData.mSize.IsLengthUnit()) {
01904     aFont->mSize = CalcLength(aFontData.mSize, &aParentFont->mFont, nsnull, aPresContext, aInherited);
01905     zoom = aFontData.mSize.IsFixedLengthUnit() ||
01906            aFontData.mSize.GetUnit() == eCSSUnit_Pixel;
01907   }
01908   else if (eCSSUnit_Percent == aFontData.mSize.GetUnit()) {
01909     aInherited = PR_TRUE;
01910     aFont->mSize = (nscoord)((float)(aParentFont->mSize) * aFontData.mSize.GetPercentValue());
01911     zoom = PR_FALSE;
01912   }
01913   else if (eCSSUnit_Inherit == aFontData.mSize.GetUnit()) {
01914     aInherited = PR_TRUE;
01915     aFont->mSize = aParentFont->mSize;
01916     zoom = PR_FALSE;
01917   }
01918   else if (eCSSUnit_Initial == aFontData.mSize.GetUnit()) {
01919     aFont->mSize = aDefaultFont.size;
01920     zoom = PR_TRUE;
01921   }
01922 
01923   // We want to zoom the cascaded size so that em-based measurements,
01924   // line-heights, etc., work.
01925   if (zoom)
01926     aFont->mSize = nsStyleFont::ZoomText(aPresContext, aFont->mSize);
01927 
01928   // enforce the user' specified minimum font-size on the value that we expose
01929   aFont->mFont.size = PR_MAX(aFont->mSize, aMinFontSize);
01930 
01931   // font-size-adjust: number, none, inherit
01932   if (eCSSUnit_Number == aFontData.mSizeAdjust.GetUnit()) {
01933     aFont->mFont.sizeAdjust = aFontData.mSizeAdjust.GetFloatValue();
01934   }
01935   else if (eCSSUnit_None == aFontData.mSizeAdjust.GetUnit()) {
01936     aFont->mFont.sizeAdjust = 0.0f;
01937   }
01938   else if (eCSSUnit_Inherit == aFontData.mSizeAdjust.GetUnit()) {
01939     aInherited = PR_TRUE;
01940     aFont->mFont.sizeAdjust = aParentFont->mFont.sizeAdjust;
01941   }
01942   else if (eCSSUnit_Initial == aFontData.mSizeAdjust.GetUnit()) {
01943     aFont->mFont.sizeAdjust = 0.0f;
01944   }
01945 }
01946 
01947 // SetGenericFont:
01948 //  - backtrack to an ancestor with the same generic font name (possibly
01949 //    up to the root where default values come from the presentation context)
01950 //  - re-apply cascading rules from there without caching intermediate values
01951 /* static */ void
01952 nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
01953                            nsStyleContext* aContext,
01954                            const nsRuleDataFont& aFontData,
01955                            PRUint8 aGenericFontID, nscoord aMinFontSize,
01956                            PRBool aUseDocumentFonts, nsStyleFont* aFont)
01957 {
01958   // walk up the contexts until a context with the desired generic font
01959   nsAutoVoidArray contextPath;
01960   nsStyleContext* higherContext = aContext->GetParent();
01961   while (higherContext) {
01962     if (higherContext->GetStyleFont()->mFlags & aGenericFontID) {
01963       // done walking up the higher contexts
01964       break;
01965     }
01966     contextPath.AppendElement(higherContext);
01967     higherContext = higherContext->GetParent();
01968   }
01969 
01970   // re-apply the cascading rules, starting from the higher context
01971 
01972   // If we stopped earlier because we reached the root of the style tree,
01973   // we will start with the default generic font from the presentation
01974   // context. Otherwise we start with the higher context.
01975   const nsFont* defaultFont = aPresContext->GetDefaultFont(aGenericFontID);
01976   nsStyleFont parentFont(*defaultFont);
01977   parentFont.mSize = parentFont.mFont.size
01978       = nsStyleFont::ZoomText(aPresContext, parentFont.mSize);
01979   if (higherContext) {
01980     const nsStyleFont* tmpFont = higherContext->GetStyleFont();
01981     parentFont.mFlags = tmpFont->mFlags;
01982     parentFont.mFont = tmpFont->mFont;
01983     parentFont.mSize = tmpFont->mSize;
01984   }
01985   aFont->mFlags = parentFont.mFlags;
01986   aFont->mFont = parentFont.mFont;
01987   aFont->mSize = parentFont.mSize;
01988 
01989   PRBool dummy;
01990   PRUint32 fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
01991   
01992   for (PRInt32 i = contextPath.Count() - 1; i >= 0; --i) {
01993     nsStyleContext* context = (nsStyleContext*)contextPath[i];
01994     nsRuleDataFont fontData; // Declare a struct with null CSS values.
01995     nsRuleData ruleData(eStyleStruct_Font, aPresContext, context);
01996     ruleData.mFontData = &fontData;
01997 
01998     // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
01999     for (nsRuleNode* ruleNode = context->GetRuleNode(); ruleNode;
02000          ruleNode = ruleNode->GetParent()) {
02001       if (ruleNode->mNoneBits & fontBit)
02002         // no more font rules on this branch, get out
02003         break;
02004 
02005       nsIStyleRule *rule = ruleNode->GetRule();
02006       if (rule)
02007         rule->MapRuleInfoInto(&ruleData);
02008     }
02009 
02010     // Compute the delta from the information that the rules specified
02011     fontData.mFamily.Reset(); // avoid unnecessary operations in SetFont()
02012 
02013     nsRuleNode::SetFont(aPresContext, context, aMinFontSize,
02014                         aUseDocumentFonts, PR_TRUE, fontData, *defaultFont,
02015                         &parentFont, aFont, dummy);
02016 
02017     // XXX Not sure if we need to do this here
02018     // If we have a post-resolve callback, handle that now.
02019     if (ruleData.mPostResolveCallback)
02020       (ruleData.mPostResolveCallback)((nsStyleStruct*)aFont, &ruleData);
02021 
02022     parentFont.mFlags = aFont->mFlags;
02023     parentFont.mFont = aFont->mFont;
02024     parentFont.mSize = aFont->mSize;
02025   }
02026 
02027   // Finish off by applying our own rules. In this case, aFontData
02028   // already has the current cascading information that we want. We
02029   // can just compute the delta from the parent.
02030   nsRuleNode::SetFont(aPresContext, aContext, aMinFontSize,
02031                       aUseDocumentFonts, PR_TRUE, aFontData, *defaultFont,
02032                       &parentFont, aFont, dummy);
02033 }
02034 
02035 const nsStyleStruct* 
02036 nsRuleNode::ComputeFontData(nsStyleStruct* aStartStruct,
02037                             const nsRuleDataStruct& aData, 
02038                             nsStyleContext* aContext, 
02039                             nsRuleNode* aHighestNode,
02040                             const RuleDetail& aRuleDetail, PRBool aInherited)
02041 {
02042   nsStyleContext* parentContext = aContext->GetParent();
02043 
02044   const nsRuleDataFont& fontData = NS_STATIC_CAST(const nsRuleDataFont&, aData);
02045   nsStyleFont* font = nsnull;
02046   const nsStyleFont* parentFont = nsnull;
02047   PRBool inherited = aInherited;
02048 
02049   // This optimization is a little weaker here since 'em', etc., for
02050   // 'font-size' require inheritance.
02051   if (parentContext &&
02052       (aRuleDetail != eRuleFullReset ||
02053        (fontData.mSize.IsRelativeLengthUnit() &&
02054         fontData.mSize.GetUnit() != eCSSUnit_Pixel) ||
02055        fontData.mSize.GetUnit() == eCSSUnit_Percent))
02056     parentFont = parentContext->GetStyleFont();
02057   if (aStartStruct)
02058     // We only need to compute the delta between this computed data and our
02059     // computed data.
02060     font = new (mPresContext) nsStyleFont(*NS_STATIC_CAST(nsStyleFont*, aStartStruct));
02061   else {
02062     // XXXldb What about eRuleFullInherited?  Which path is faster?
02063     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {
02064       // No question. We will have to inherit. Go ahead and init
02065       // with inherited vals from parent.
02066       inherited = PR_TRUE;
02067       if (parentFont)
02068         font = new (mPresContext) nsStyleFont(*parentFont);
02069       else
02070         font = new (mPresContext) nsStyleFont(mPresContext);
02071     }
02072     else
02073       font = new (mPresContext) nsStyleFont(mPresContext);
02074   }
02075 
02076   if (NS_UNLIKELY(!font))
02077     return nsnull; // Out Of Memory
02078   if (!parentFont)
02079     parentFont = font;
02080 
02081   // See if there is a minimum font-size constraint to honor
02082   nscoord minimumFontSize = 
02083     mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
02084 
02085   if (minimumFontSize < 0)
02086     minimumFontSize = 0;
02087 
02088   PRBool useDocumentFonts = PR_TRUE;
02089 
02090   // Figure out if we are a generic font
02091   PRUint8 generic = kGenericFont_NONE;
02092   if (eCSSUnit_String == fontData.mFamily.GetUnit()) {
02093     fontData.mFamily.GetStringValue(font->mFont.name);
02094     nsFont::GetGenericID(font->mFont.name, &generic);
02095 
02096     // MJA: bug 31816
02097     // if we are not using document fonts, but this is a XUL document,
02098     // then we use the document fonts anyway
02099     useDocumentFonts =
02100       mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
02101   }
02102 
02103   // See if we are in the chrome
02104   // We only need to know this to determine if we have to use the
02105   // document fonts (overriding the useDocumentFonts flag), or to
02106   // determine if we have to override the minimum font-size constraint.
02107   if ((!useDocumentFonts || minimumFontSize > 0) && IsChrome(mPresContext)) {
02108     useDocumentFonts = PR_TRUE;
02109     minimumFontSize = 0;
02110   }
02111 
02112   // If we don't have to use document fonts, then we are only entitled
02113   // to use the user's default variable-width font and fixed-width font
02114   if (!useDocumentFonts) {
02115     if (generic != kGenericFont_moz_fixed)
02116       generic = kGenericFont_NONE;
02117   }
02118 
02119   // Now compute our font struct
02120   if (generic == kGenericFont_NONE) {
02121     // continue the normal processing
02122     // our default font is the most recent generic font
02123     const nsFont* defaultFont =
02124       mPresContext->GetDefaultFont(parentFont->mFlags & NS_STYLE_FONT_FACE_MASK);
02125 
02126     nsRuleNode::SetFont(mPresContext, aContext, minimumFontSize,
02127                         useDocumentFonts, PR_FALSE,
02128                         fontData, *defaultFont, parentFont, font, inherited);
02129   }
02130   else {
02131     // re-calculate the font as a generic font
02132     inherited = PR_TRUE;
02133     nsRuleNode::SetGenericFont(mPresContext, aContext, fontData, generic,
02134                                minimumFontSize, useDocumentFonts, font);
02135   }
02136   // Set our generic font's bit to inform our descendants
02137   font->mFlags &= ~NS_STYLE_FONT_FACE_MASK;
02138   font->mFlags |= generic;
02139 
02140   if (inherited)
02141     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
02142     // style context.
02143     aContext->SetStyle(eStyleStruct_Font, font);
02144   else {
02145     // We were fully specified and can therefore be cached right on the rule node.
02146     if (!aHighestNode->mStyleData.mInheritedData) {
02147       aHighestNode->mStyleData.mInheritedData = new (mPresContext) nsInheritedStyleData;
02148       if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) {
02149         font->Destroy(mPresContext);
02150         return nsnull;
02151       }
02152     }
02153     aHighestNode->mStyleData.mInheritedData->mFontData = font;
02154     // Propagate the bit down.
02155     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Font), aHighestNode);
02156   }
02157 
02158   return font;
02159 }
02160 
02161 const nsStyleStruct*
02162 nsRuleNode::ComputeTextData(nsStyleStruct* aStartStruct,
02163                             const nsRuleDataStruct& aData, 
02164                             nsStyleContext* aContext, 
02165                             nsRuleNode* aHighestNode,
02166                             const RuleDetail& aRuleDetail, PRBool aInherited)
02167 {
02168   nsStyleContext* parentContext = aContext->GetParent();
02169 
02170   const nsRuleDataText& textData = NS_STATIC_CAST(const nsRuleDataText&, aData);
02171   nsStyleText* text = nsnull;
02172   const nsStyleText* parentText = nsnull;
02173   PRBool inherited = aInherited;
02174 
02175   if (parentContext && aRuleDetail != eRuleFullReset)
02176     parentText = parentContext->GetStyleText();
02177   if (aStartStruct)
02178     // We only need to compute the delta between this computed data and our
02179     // computed data.
02180     text = new (mPresContext) nsStyleText(*NS_STATIC_CAST(nsStyleText*, aStartStruct));
02181   else {
02182     // XXXldb What about eRuleFullInherited?  Which path is faster?
02183     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {
02184       // No question. We will have to inherit. Go ahead and init
02185       // with inherited vals from parent.
02186       inherited = PR_TRUE;
02187       if (parentText)
02188         text = new (mPresContext) nsStyleText(*parentText);
02189       else
02190         text = new (mPresContext) nsStyleText();
02191     }
02192     else
02193       text = new (mPresContext) nsStyleText();
02194   }
02195 
02196   if (NS_UNLIKELY(!text))
02197     return nsnull;  // Out Of Memory
02198   if (!parentText)
02199     parentText = text;
02200 
02201     // letter-spacing: normal, length, inherit
02202   SetCoord(textData.mLetterSpacing, text->mLetterSpacing, parentText->mLetterSpacing,
02203            SETCOORD_LH | SETCOORD_NORMAL, aContext, mPresContext, inherited);
02204 
02205   // line-height: normal, number, length, percent, inherit
02206   if (eCSSUnit_Percent == textData.mLineHeight.GetUnit()) {
02207     inherited = PR_TRUE;
02208     // Use |mFont.size| to pick up minimum font size.
02209     text->mLineHeight.SetCoordValue(
02210         nscoord(float(aContext->GetStyleFont()->mFont.size) *
02211                 textData.mLineHeight.GetPercentValue()));
02212   } else {
02213     SetCoord(textData.mLineHeight, text->mLineHeight, parentText->mLineHeight,
02214              SETCOORD_LH | SETCOORD_FACTOR | SETCOORD_NORMAL,
02215              aContext, mPresContext, inherited);
02216     if (textData.mLineHeight.IsFixedLengthUnit() ||
02217         textData.mLineHeight.GetUnit() == eCSSUnit_Pixel) {
02218       nscoord lh = nsStyleFont::ZoomText(mPresContext,
02219                                          text->mLineHeight.GetCoordValue());
02220       nscoord minimumFontSize =
02221         mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
02222 
02223       if (minimumFontSize > 0 && !IsChrome(mPresContext)) {
02224         // If we applied a minimum font size, scale the line height by
02225         // the same ratio.  (If we *might* have applied a minimum font
02226         // size, we can't cache in the rule tree.)
02227         inherited = PR_TRUE;
02228         const nsStyleFont *font = aContext->GetStyleFont();
02229         if (font->mSize != 0) {
02230           lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
02231         } else {
02232           lh = minimumFontSize;
02233         }
02234       }
02235       text->mLineHeight.SetCoordValue(lh);
02236     }
02237   }
02238 
02239 
02240   // text-align: enum, string, inherit
02241   if (eCSSUnit_Enumerated == textData.mTextAlign.GetUnit()) {
02242     text->mTextAlign = textData.mTextAlign.GetIntValue();
02243   }
02244   else if (eCSSUnit_String == textData.mTextAlign.GetUnit()) {
02245     NS_NOTYETIMPLEMENTED("align string");
02246   }
02247   else if (eCSSUnit_Inherit == textData.mTextAlign.GetUnit()) {
02248     inherited = PR_TRUE;
02249     text->mTextAlign = parentText->mTextAlign;
02250   }
02251   else if (eCSSUnit_Initial == textData.mTextAlign.GetUnit())
02252     text->mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
02253 
02254   // text-indent: length, percent, inherit
02255   SetCoord(textData.mTextIndent, text->mTextIndent, parentText->mTextIndent,
02256            SETCOORD_LPH, aContext, mPresContext, inherited);
02257 
02258   // text-transform: enum, none, inherit
02259   if (eCSSUnit_Enumerated == textData.mTextTransform.GetUnit()) {
02260     text->mTextTransform = textData.mTextTransform.GetIntValue();
02261   }
02262   else if (eCSSUnit_None == textData.mTextTransform.GetUnit()) {
02263     text->mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE;
02264   }
02265   else if (eCSSUnit_Inherit == textData.mTextTransform.GetUnit()) {
02266     inherited = PR_TRUE;
02267     text->mTextTransform = parentText->mTextTransform;
02268   }
02269 
02270   // white-space: enum, normal, inherit
02271   if (eCSSUnit_Enumerated == textData.mWhiteSpace.GetUnit()) {
02272     text->mWhiteSpace = textData.mWhiteSpace.GetIntValue();
02273   }
02274   else if (eCSSUnit_Normal == textData.mWhiteSpace.GetUnit()) {
02275     text->mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL;
02276   }
02277   else if (eCSSUnit_Inherit == textData.mWhiteSpace.GetUnit()) {
02278     inherited = PR_TRUE;
02279     text->mWhiteSpace = parentText->mWhiteSpace;
02280   }
02281 
02282   // word-spacing: normal, length, inherit
02283   SetCoord(textData.mWordSpacing, text->mWordSpacing, parentText->mWordSpacing,
02284            SETCOORD_LH | SETCOORD_NORMAL, aContext, mPresContext, inherited);
02285 
02286   if (inherited)
02287     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
02288     // style context.
02289     aContext->SetStyle(eStyleStruct_Text, text);
02290   else {
02291     // We were fully specified and can therefore be cached right on the rule node.
02292     if (!aHighestNode->mStyleData.mInheritedData) {
02293       aHighestNode->mStyleData.mInheritedData = new (mPresContext) nsInheritedStyleData;
02294       if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) {
02295         text->Destroy(mPresContext);
02296         return nsnull;
02297       }
02298     }
02299     aHighestNode->mStyleData.mInheritedData->mTextData = text;
02300     // Propagate the bit down.
02301     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Text), aHighestNode);
02302   }
02303 
02304   return text;
02305 }
02306 
02307 const nsStyleStruct*
02308 nsRuleNode::ComputeTextResetData(nsStyleStruct* aStartData,
02309                                  const nsRuleDataStruct& aData, 
02310                                  nsStyleContext* aContext, 
02311                                  nsRuleNode* aHighestNode,
02312                                  const RuleDetail& aRuleDetail, PRBool aInherited)
02313 {
02314   nsStyleContext* parentContext = aContext->GetParent();
02315 
02316   const nsRuleDataText& textData = NS_STATIC_CAST(const nsRuleDataText&, aData);
02317   nsStyleTextReset* text;
02318   if (aStartData)
02319     // We only need to compute the delta between this computed data and our
02320     // computed data.
02321     text = new (mPresContext) nsStyleTextReset(*NS_STATIC_CAST(nsStyleTextReset*, aStartData));
02322   else
02323     text = new (mPresContext) nsStyleTextReset();
02324 
02325   if (NS_UNLIKELY(!text))
02326     return nsnull;  // Out Of Memory
02327 
02328   const nsStyleTextReset* parentText = text;
02329   if (parentContext && 
02330       aRuleDetail != eRuleFullReset &&
02331       aRuleDetail != eRulePartialReset &&
02332       aRuleDetail != eRuleNone)
02333     parentText = parentContext->GetStyleTextReset();
02334   PRBool inherited = aInherited;
02335   
02336   // vertical-align: enum, length, percent, inherit
02337   SetCoord(textData.mVerticalAlign, text->mVerticalAlign, parentText->mVerticalAlign,
02338            SETCOORD_LPH | SETCOORD_ENUMERATED, aContext, mPresContext, inherited);
02339 
02340   // text-decoration: none, enum (bit field), inherit
02341   if (eCSSUnit_Enumerated == textData.mDecoration.GetUnit()) {
02342     PRInt32 td = textData.mDecoration.GetIntValue();
02343     text->mTextDecoration = td;
02344     if (td & NS_STYLE_TEXT_DECORATION_PREF_ANCHORS) {
02345       PRBool underlineLinks =
02346         mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
02347       if (underlineLinks) {
02348         text->mTextDecoration |= NS_STYLE_TEXT_DECORATION_UNDERLINE;
02349       }
02350       else {
02351         text->mTextDecoration &= ~NS_STYLE_TEXT_DECORATION_UNDERLINE;
02352       }
02353     }
02354   }
02355   else if (eCSSUnit_None == textData.mDecoration.GetUnit()) {
02356     text->mTextDecoration = NS_STYLE_TEXT_DECORATION_NONE;
02357   }
02358   else if (eCSSUnit_Inherit == textData.mDecoration.GetUnit()) {
02359     inherited = PR_TRUE;
02360     text->mTextDecoration = parentText->mTextDecoration;
02361   }
02362 
02363   // unicode-bidi: enum, normal, inherit
02364   if (eCSSUnit_Normal == textData.mUnicodeBidi.GetUnit() ) {
02365     text->mUnicodeBidi = NS_STYLE_UNICODE_BIDI_NORMAL;
02366   }
02367   else if (eCSSUnit_Enumerated == textData.mUnicodeBidi.GetUnit() ) {
02368     text->mUnicodeBidi = textData.mUnicodeBidi.GetIntValue();
02369   }
02370   else if (eCSSUnit_Inherit == textData.mUnicodeBidi.GetUnit() ) {
02371     inherited = PR_TRUE;
02372     text->mUnicodeBidi = parentText->mUnicodeBidi;
02373   }
02374 
02375   if (inherited)
02376     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
02377     // style context.
02378     aContext->SetStyle(eStyleStruct_TextReset, text);
02379   else {
02380     // We were fully specified and can therefore be cached right on the rule node.
02381     if (!aHighestNode->mStyleData.mResetData) {
02382       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
02383       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
02384         text->Destroy(mPresContext);
02385         return nsnull;
02386       }
02387     }
02388     aHighestNode->mStyleData.mResetData->mTextResetData = text;
02389     // Propagate the bit down.
02390     PropagateDependentBit(NS_STYLE_INHERIT_BIT(TextReset), aHighestNode);
02391   }
02392 
02393   return text;
02394 }
02395 
02396 const nsStyleStruct*
02397 nsRuleNode::ComputeUserInterfaceData(nsStyleStruct* aStartData,
02398                                      const nsRuleDataStruct& aData, 
02399                                      nsStyleContext* aContext, 
02400                                      nsRuleNode* aHighestNode,
02401                                      const RuleDetail& aRuleDetail,
02402                                      PRBool aInherited)
02403 {
02404   nsStyleContext* parentContext = aContext->GetParent();
02405 
02406   const nsRuleDataUserInterface& uiData = NS_STATIC_CAST(const nsRuleDataUserInterface&, aData);
02407   nsStyleUserInterface* ui = nsnull;
02408   const nsStyleUserInterface* parentUI = nsnull;
02409   PRBool inherited = aInherited;
02410 
02411   if (parentContext && aRuleDetail != eRuleFullReset)
02412     parentUI = parentContext->GetStyleUserInterface();
02413   if (aStartData)
02414     // We only need to compute the delta between this computed data and our
02415     // computed data.
02416     ui = new (mPresContext) nsStyleUserInterface(*NS_STATIC_CAST(nsStyleUserInterface*, aStartData));
02417   else {
02418     // XXXldb What about eRuleFullInherited?  Which path is faster?
02419     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {
02420       // No question. We will have to inherit. Go ahead and init
02421       // with inherited vals from parent.
02422       inherited = PR_TRUE;
02423       if (parentUI)
02424         ui = new (mPresContext) nsStyleUserInterface(*parentUI);
02425       else
02426         ui = new (mPresContext) nsStyleUserInterface();
02427     }
02428     else
02429       ui = new (mPresContext) nsStyleUserInterface();
02430   }
02431 
02432   if (NS_UNLIKELY(!ui))
02433     return nsnull;  // Out Of Memory
02434   if (!parentUI)
02435     parentUI = ui;
02436 
02437   // cursor: enum, auto, url, inherit
02438   nsCSSValueList*  list = uiData.mCursor;
02439   if (nsnull != list) {
02440     delete [] ui->mCursorArray;
02441     ui->mCursorArray = nsnull;
02442     ui->mCursorArrayLength = 0;
02443 
02444     if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
02445       inherited = PR_TRUE;
02446       ui->mCursor = parentUI->mCursor;
02447       ui->CopyCursorArrayFrom(*parentUI);
02448     }
02449     else {
02450       // The parser will never create a list that is *all* URL values --
02451       // that's invalid.
02452       PRUint32 arrayLength = 0;
02453       for (nsCSSValueList *list2 = list;
02454            list2->mValue.GetUnit() == eCSSUnit_Array; list2 = list2->mNext)
02455         if (list2->mValue.GetArrayValue()->Item(0).GetImageValue())
02456           ++arrayLength;
02457 
02458       if (arrayLength != 0) {
02459         ui->mCursorArray = new nsCursorImage[arrayLength];
02460         if (ui->mCursorArray) {
02461           ui->mCursorArrayLength = arrayLength;
02462 
02463           for (nsCursorImage *item = ui->mCursorArray;
02464                list->mValue.GetUnit() == eCSSUnit_Array;
02465                list = list->mNext) {
02466             nsCSSValue::Array *arr = list->mValue.GetArrayValue();
02467             imgIRequest *req = arr->Item(0).GetImageValue();
02468             if (req) {
02469               item->mImage = req;
02470               if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
02471                 item->mHaveHotspot = PR_TRUE;
02472                 item->mHotspotX = arr->Item(1).GetFloatValue(),
02473                 item->mHotspotY = arr->Item(2).GetFloatValue();
02474               }
02475               ++item;
02476             }
02477           }
02478         }
02479       }
02480 
02481       if (eCSSUnit_Enumerated == list->mValue.GetUnit()) {
02482         ui->mCursor = list->mValue.GetIntValue();
02483       }
02484       else if (eCSSUnit_Auto == list->mValue.GetUnit()) {
02485         ui->mCursor = NS_STYLE_CURSOR_AUTO;
02486       }
02487     }
02488   }
02489 
02490   // user-input: auto, none, enum, inherit
02491   if (eCSSUnit_Enumerated == uiData.mUserInput.GetUnit()) {
02492     ui->mUserInput = uiData.mUserInput.GetIntValue();
02493   }
02494   else if (eCSSUnit_Auto == uiData.mUserInput.GetUnit()) {
02495     ui->mUserInput = NS_STYLE_USER_INPUT_AUTO;
02496   }
02497   else if (eCSSUnit_None == uiData.mUserInput.GetUnit()) {
02498     ui->mUserInput = NS_STYLE_USER_INPUT_NONE;
02499   }
02500   else if (eCSSUnit_Inherit == uiData.mUserInput.GetUnit()) {
02501     inherited = PR_TRUE;
02502     ui->mUserInput = parentUI->mUserInput;
02503   }
02504 
02505   // user-modify: enum, inherit
02506   if (eCSSUnit_Enumerated == uiData.mUserModify.GetUnit()) {
02507     ui->mUserModify = uiData.mUserModify.GetIntValue();
02508   }
02509   else if (eCSSUnit_Inherit == uiData.mUserModify.GetUnit()) {
02510     inherited = PR_TRUE;
02511     ui->mUserModify = parentUI->mUserModify;
02512   }
02513 
02514   // user-focus: none, normal, enum, inherit
02515   if (eCSSUnit_Enumerated == uiData.mUserFocus.GetUnit()) {
02516     ui->mUserFocus = uiData.mUserFocus.GetIntValue();
02517   }
02518   else if (eCSSUnit_None == uiData.mUserFocus.GetUnit()) {
02519     ui->mUserFocus = NS_STYLE_USER_FOCUS_NONE;
02520   }
02521   else if (eCSSUnit_Normal == uiData.mUserFocus.GetUnit()) {
02522     ui->mUserFocus = NS_STYLE_USER_FOCUS_NORMAL;
02523   }
02524   else if (eCSSUnit_Inherit == uiData.mUserFocus.GetUnit()) {
02525     inherited = PR_TRUE;
02526     ui->mUserFocus = parentUI->mUserFocus;
02527   }
02528 
02529   if (inherited)
02530     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
02531     // style context.
02532     aContext->SetStyle(eStyleStruct_UserInterface, ui);
02533   else {
02534     // We were fully specified and can therefore be cached right on the rule node.
02535     if (!aHighestNode->mStyleData.mInheritedData) {
02536       aHighestNode->mStyleData.mInheritedData = new (mPresContext) nsInheritedStyleData;
02537       if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) {
02538         ui->Destroy(mPresContext);
02539         return nsnull;
02540       }
02541     }    
02542     aHighestNode->mStyleData.mInheritedData->mUserInterfaceData = ui;
02543     // Propagate the bit down.
02544     PropagateDependentBit(NS_STYLE_INHERIT_BIT(UserInterface), aHighestNode);
02545   }
02546 
02547   return ui;
02548 }
02549 
02550 const nsStyleStruct*
02551 nsRuleNode::ComputeUIResetData(nsStyleStruct* aStartData,
02552                                const nsRuleDataStruct& aData, 
02553                                nsStyleContext* aContext, 
02554                                nsRuleNode* aHighestNode,
02555                                const RuleDetail& aRuleDetail, PRBool aInherited)
02556 {
02557   nsStyleContext* parentContext = aContext->GetParent();
02558 
02559   const nsRuleDataUserInterface& uiData = NS_STATIC_CAST(const nsRuleDataUserInterface&, aData);
02560   nsStyleUIReset* ui;
02561   if (aStartData)
02562     // We only need to compute the delta between this computed data and our
02563     // computed data.
02564     ui = new (mPresContext) nsStyleUIReset(*NS_STATIC_CAST(nsStyleUIReset*, aStartData));
02565   else
02566     ui = new (mPresContext) nsStyleUIReset();
02567 
02568   if (NS_UNLIKELY(!ui))
02569     return nsnull;  // Out Of Memory
02570 
02571   const nsStyleUIReset* parentUI = ui;
02572   if (parentContext && 
02573       aRuleDetail != eRuleFullReset &&
02574       aRuleDetail != eRulePartialReset &&
02575       aRuleDetail != eRuleNone)
02576     parentUI = parentContext->GetStyleUIReset();
02577   PRBool inherited = aInherited;
02578   
02579   // user-select: none, enum, inherit
02580   if (eCSSUnit_Enumerated == uiData.mUserSelect.GetUnit()) {
02581     ui->mUserSelect = uiData.mUserSelect.GetIntValue();
02582   }
02583   else if (eCSSUnit_None == uiData.mUserSelect.GetUnit()) {
02584     ui->mUserSelect = NS_STYLE_USER_SELECT_NONE;
02585   }
02586   else if (eCSSUnit_Inherit == uiData.mUserSelect.GetUnit()) {
02587     inherited = PR_TRUE;
02588     ui->mUserSelect = parentUI->mUserSelect;
02589   }
02590 
02591   // force-broken-image-icons: integer
02592   if (eCSSUnit_Integer == uiData.mForceBrokenImageIcon.GetUnit()) {
02593     ui->mForceBrokenImageIcon = uiData.mForceBrokenImageIcon.GetIntValue();
02594   }
02595   
02596   if (inherited)
02597     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
02598     // style context.
02599     aContext->SetStyle(eStyleStruct_UIReset, ui);
02600   else {
02601     // We were fully specified and can therefore be cached right on the rule node.
02602     if (!aHighestNode->mStyleData.mResetData) {
02603       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
02604       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
02605         ui->Destroy(mPresContext);
02606         return nsnull;
02607       }
02608     }
02609     aHighestNode->mStyleData.mResetData->mUIResetData = ui;
02610     // Propagate the bit down.
02611     PropagateDependentBit(NS_STYLE_INHERIT_BIT(UIReset), aHighestNode);
02612   }
02613 
02614   return ui;
02615 }
02616 
02617 const nsStyleStruct*
02618 nsRuleNode::ComputeDisplayData(nsStyleStruct* aStartStruct,
02619                                const nsRuleDataStruct& aData, 
02620                                nsStyleContext* aContext, 
02621                                nsRuleNode* aHighestNode,
02622                                const RuleDetail& aRuleDetail, PRBool aInherited)
02623 {
02624   nsStyleContext* parentContext = aContext->GetParent();
02625 
02626   const nsRuleDataDisplay& displayData = NS_STATIC_CAST(const nsRuleDataDisplay&, aData);
02627   nsStyleDisplay* display;
02628   if (aStartStruct)
02629     // We only need to compute the delta between this computed data and our
02630     // computed data.
02631     display = new (mPresContext) nsStyleDisplay(*NS_STATIC_CAST(nsStyleDisplay*, aStartStruct));
02632   else
02633     display = new (mPresContext) nsStyleDisplay();
02634 
02635   if (NS_UNLIKELY(!display))
02636     return nsnull;  // Out Of Memory
02637 
02638   const nsStyleDisplay* parentDisplay = display;
02639   nsIAtom* pseudoTag = aContext->GetPseudoType();
02640   PRBool generatedContent = (pseudoTag == nsCSSPseudoElements::before || 
02641                              pseudoTag == nsCSSPseudoElements::after);
02642 
02643   if (parentContext && 
02644       ((aRuleDetail != eRuleFullReset &&
02645         aRuleDetail != eRulePartialReset &&
02646         aRuleDetail != eRuleNone) ||
02647        generatedContent))
02648     parentDisplay = parentContext->GetStyleDisplay();
02649   PRBool inherited = aInherited;
02650 
02651   // opacity: factor, inherit
02652   if (eCSSUnit_Number == displayData.mOpacity.GetUnit()) {
02653     display->mOpacity = displayData.mOpacity.GetFloatValue();
02654     if (display->mOpacity > 1.0f)
02655       display->mOpacity = 1.0f;
02656     if (display->mOpacity < 0.0f)
02657       display->mOpacity = 0.0f;
02658   }
02659   else if (eCSSUnit_Inherit == displayData.mOpacity.GetUnit()) {
02660     inherited = PR_TRUE;
02661     display->mOpacity = parentDisplay->mOpacity;
02662   }
02663 
02664   // display: enum, none, inherit
02665   if (eCSSUnit_Enumerated == displayData.mDisplay.GetUnit()) {
02666     display->mDisplay = displayData.mDisplay.GetIntValue();
02667   }
02668   else if (eCSSUnit_None == displayData.mDisplay.GetUnit()) {
02669     display->mDisplay = NS_STYLE_DISPLAY_NONE;
02670   }
02671   else if (eCSSUnit_Inherit == displayData.mDisplay.GetUnit()) {
02672     inherited = PR_TRUE;
02673     display->mDisplay = parentDisplay->mDisplay;
02674   }
02675 
02676   // appearance: enum, none, inherit
02677   if (eCSSUnit_Enumerated == displayData.mAppearance.GetUnit()) {
02678     display->mAppearance = displayData.mAppearance.GetIntValue();
02679   }
02680   else if (eCSSUnit_None == displayData.mAppearance.GetUnit()) {
02681     display->mAppearance = NS_THEME_NONE;
02682   }
02683   else if (eCSSUnit_Inherit == displayData.mAppearance.GetUnit()) {
02684     inherited = PR_TRUE;
02685     display->mAppearance = parentDisplay->mAppearance;
02686   }
02687 
02688   // binding: url, none, inherit
02689   if (eCSSUnit_URL == displayData.mBinding.GetUnit()) {
02690     display->mBinding = displayData.mBinding.GetURLValue();
02691   }
02692   else if (eCSSUnit_None == displayData.mBinding.GetUnit()) {
02693     display->mBinding = nsnull;
02694   }
02695   else if (eCSSUnit_Inherit == displayData.mBinding.GetUnit()) {
02696     inherited = PR_TRUE;
02697     display->mBinding = parentDisplay->mBinding;
02698   }
02699 
02700   // position: enum, inherit
02701   if (eCSSUnit_Enumerated == displayData.mPosition.GetUnit()) {
02702     display->mPosition = displayData.mPosition.GetIntValue();
02703   }
02704   else if (eCSSUnit_Inherit == displayData.mPosition.GetUnit()) {
02705     inherited = PR_TRUE;
02706     display->mPosition = parentDisplay->mPosition;
02707   }
02708 
02709   // clear: enum, none, inherit
02710   if (eCSSUnit_Enumerated == displayData.mClear.GetUnit()) {
02711     display->mBreakType = displayData.mClear.GetIntValue();
02712   }
02713   else if (eCSSUnit_None == displayData.mClear.GetUnit()) {
02714     display->mBreakType = NS_STYLE_CLEAR_NONE;
02715   }
02716   else if (eCSSUnit_Inherit == displayData.mClear.GetUnit()) {
02717     inherited = PR_TRUE;
02718     display->mBreakType = parentDisplay->mBreakType;
02719   }
02720 
02721   // temp fix for bug 24000
02722   if (eCSSUnit_Enumerated == displayData.mBreakBefore.GetUnit()) {
02723     display->mBreakBefore = (NS_STYLE_PAGE_BREAK_ALWAYS == displayData.mBreakBefore.GetIntValue());
02724   }
02725   if (eCSSUnit_Enumerated == displayData.mBreakAfter.GetUnit()) {
02726     display->mBreakAfter = (NS_STYLE_PAGE_BREAK_ALWAYS == displayData.mBreakAfter.GetIntValue());
02727   }
02728   // end temp fix
02729 
02730   // float: enum, none, inherit
02731   if (eCSSUnit_Enumerated == displayData.mFloat.GetUnit()) {
02732     display->mFloats = displayData.mFloat.GetIntValue();
02733   }
02734   else if (eCSSUnit_None == displayData.mFloat.GetUnit()) {
02735     display->mFloats = NS_STYLE_FLOAT_NONE;
02736   }
02737   else if (eCSSUnit_Inherit == displayData.mFloat.GetUnit()) {
02738     inherited = PR_TRUE;
02739     display->mFloats = parentDisplay->mFloats;
02740   }
02741 
02742   // overflow-x: enum, auto, inherit
02743   if (eCSSUnit_Enumerated == displayData.mOverflowX.GetUnit()) {
02744     display->mOverflowX = displayData.mOverflowX.GetIntValue();
02745   }
02746   else if (eCSSUnit_Auto == displayData.mOverflowX.GetUnit()) {
02747     display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
02748   }
02749   else if (eCSSUnit_Inherit == displayData.mOverflowX.GetUnit()) {
02750     inherited = PR_TRUE;
02751     display->mOverflowX = parentDisplay->mOverflowX;
02752   }
02753 
02754   // overflow-y: enum, auto, inherit
02755   if (eCSSUnit_Enumerated == displayData.mOverflowY.GetUnit()) {
02756     display->mOverflowY = displayData.mOverflowY.GetIntValue();
02757   }
02758   else if (eCSSUnit_Auto == displayData.mOverflowY.GetUnit()) {
02759     display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
02760   }
02761   else if (eCSSUnit_Inherit == displayData.mOverflowY.GetUnit()) {
02762     inherited = PR_TRUE;
02763     display->mOverflowY = parentDisplay->mOverflowY;
02764   }
02765 
02766   // CSS3 overflow-x and overflow-y require some fixup as well in some
02767   // cases.  NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
02768   // meaningful only when used in both dimensions.
02769   if (display->mOverflowX != display->mOverflowY &&
02770       (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
02771        display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
02772        display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
02773        display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
02774     // We can't store in the rule tree since a more specific rule might
02775     // change these conditions.
02776     inherited = PR_TRUE;
02777 
02778     // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
02779     // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
02780     if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
02781       display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
02782     if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
02783       display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
02784 
02785     // If 'visible' is specified but doesn't match the other dimension, it
02786     // turns into 'auto'.
02787     if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
02788       display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
02789     if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
02790       display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
02791   }
02792 
02793   // clip property: length, auto, inherit
02794   if (eCSSUnit_Inherit == displayData.mClip.mTop.GetUnit()) { // if one is inherit, they all are
02795     inherited = PR_TRUE;
02796     display->mClipFlags = parentDisplay->mClipFlags;
02797     display->mClip = parentDisplay->mClip;
02798   }
02799   else {
02800     PRBool  fullAuto = PR_TRUE;
02801 
02802     display->mClipFlags = 0; // clear it
02803 
02804     if (eCSSUnit_Auto == displayData.mClip.mTop.GetUnit()) {
02805       display->mClip.y = 0;
02806       display->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
02807     } 
02808     else if (displayData.mClip.mTop.IsLengthUnit()) {
02809       display->mClip.y = CalcLength(displayData.mClip.mTop, nsnull, aContext, mPresContext, inherited);
02810       fullAuto = PR_FALSE;
02811     }
02812     if (eCSSUnit_Auto == displayData.mClip.mBottom.GetUnit()) {
02813       // Setting to NS_MAXSIZE for the 'auto' case ensures that
02814       // the clip rect is nonempty. It is important that mClip be
02815       // nonempty if the actual clip rect could be nonempty.
02816       display->mClip.height = NS_MAXSIZE;
02817       display->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
02818     } 
02819     else if (displayData.mClip.mBottom.IsLengthUnit()) {
02820       display->mClip.height = CalcLength(displayData.mClip.mBottom, nsnull, aContext, mPresContext, inherited) -
02821                               display->mClip.y;
02822       fullAuto = PR_FALSE;
02823     }
02824     if (eCSSUnit_Auto == displayData.mClip.mLeft.GetUnit()) {
02825       display->mClip.x = 0;
02826       display->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
02827     } 
02828     else if (displayData.mClip.mLeft.IsLengthUnit()) {
02829       display->mClip.x = CalcLength(displayData.mClip.mLeft, nsnull, aContext, mPresContext, inherited);
02830       fullAuto = PR_FALSE;
02831     }
02832     if (eCSSUnit_Auto == displayData.mClip.mRight.GetUnit()) {
02833       // Setting to NS_MAXSIZE for the 'auto' case ensures that
02834       // the clip rect is nonempty. It is important that mClip be
02835       // nonempty if the actual clip rect could be nonempty.
02836       display->mClip.width = NS_MAXSIZE;
02837       display->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
02838     } 
02839     else if (displayData.mClip.mRight.IsLengthUnit()) {
02840       display->mClip.width = CalcLength(displayData.mClip.mRight, nsnull, aContext, mPresContext, inherited) -
02841                              display->mClip.x;
02842       fullAuto = PR_FALSE;
02843     }
02844     display->mClipFlags &= ~NS_STYLE_CLIP_TYPE_MASK;
02845     if (fullAuto) {
02846       display->mClipFlags |= NS_STYLE_CLIP_AUTO;
02847     }
02848     else {
02849       display->mClipFlags |= NS_STYLE_CLIP_RECT;
02850     }
02851   }
02852 
02853   // CSS2 specified fixups:
02854   if (generatedContent) {
02855     // According to CSS2 section 12.1, :before and :after
02856     // pseudo-elements must not be positioned or floated (CSS2 12.1) and
02857     // must be limited to certain display types (depending on the
02858     // display type of the element to which they are attached).
02859 
02860     if (display->mPosition != NS_STYLE_POSITION_STATIC)
02861       display->mPosition = NS_STYLE_POSITION_STATIC;
02862     if (display->mFloats != NS_STYLE_FLOAT_NONE)
02863       display->mFloats = NS_STYLE_FLOAT_NONE;
02864 
02865     PRUint8 displayValue = display->mDisplay;
02866     if (displayValue != NS_STYLE_DISPLAY_NONE &&
02867         displayValue != NS_STYLE_DISPLAY_INLINE) {
02868       inherited = PR_TRUE;
02869       if (parentDisplay->IsBlockLevel() ||
02870           parentDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL ||
02871           parentDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION) {
02872         // If the subject of the selector is a block-level element,
02873         // allowed values are 'none', 'inline', 'block', and 'marker'.
02874         // If the value of the 'display' has any other value, the
02875         // pseudo-element will behave as if the value were 'block'.
02876         if (displayValue != NS_STYLE_DISPLAY_BLOCK &&
02877             displayValue != NS_STYLE_DISPLAY_MARKER)
02878           display->mDisplay = NS_STYLE_DISPLAY_BLOCK;
02879       } else {
02880         // If the subject of the selector is an inline-level element,
02881         // allowed values are 'none' and 'inline'. If the value of the
02882         // 'display' has any other value, the pseudo-element will behave
02883         // as if the value were 'inline'.
02884         display->mDisplay = NS_STYLE_DISPLAY_INLINE;
02885       }
02886     }
02887   }
02888   else if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
02889     // CSS2 9.7 specifies display type corrections dealing with 'float'
02890     // and 'position'.  Since generated content can't be floated or
02891     // positioned, we can deal with it here.
02892 
02893     // 1) if float is not none, and display is not none, then we must
02894     // set a block-level 'display' type per CSS2.1 section 9.7.
02895     if (display->mFloats != NS_STYLE_FLOAT_NONE) {
02896       EnsureBlockDisplay(display->mDisplay);
02897       
02898       // We can't cache the data in the rule tree since if a more specific
02899       // rule has 'float: none' we'll end up with the wrong 'display'
02900       // property.
02901       inherited = PR_TRUE;
02902     } else if (nsCSSPseudoElements::firstLetter == pseudoTag) {
02903       // a non-floating first-letter must be inline
02904       // XXX this fix can go away once bug 103189 is fixed correctly
02905       display->mDisplay = NS_STYLE_DISPLAY_INLINE;
02906       
02907       // We can't cache the data in the rule tree since if a more specific
02908       // rule has 'float: left' we'll end up with the wrong 'display'
02909       // property.
02910       inherited = PR_TRUE;
02911     }
02912     
02913     // 2) if position is 'absolute' or 'fixed' then display must be
02914     // block-level and float must be 'none'
02915     if (display->IsAbsolutelyPositioned()) {
02916       // Backup original display value for calculation of a hypothetical
02917       // box (CSS2 10.6.4/10.6.5).
02918       // See nsHTMLReflowState::CalculateHypotheticalBox
02919       display->mOriginalDisplay = display->mDisplay;
02920       EnsureBlockDisplay(display->mDisplay);
02921       display->mFloats = NS_STYLE_FLOAT_NONE;
02922       
02923       // We can't cache the data in the rule tree since if a more specific
02924       // rule has 'position: static' we'll end up with problems with the
02925       // 'display' and 'float' properties.
02926       inherited = PR_TRUE;
02927     }
02928   }
02929 
02930   if (inherited)
02931     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
02932     // style context.
02933     aContext->SetStyle(eStyleStruct_Display, display);
02934   else {
02935     // We were fully specified and can therefore be cached right on the rule node.
02936     if (!aHighestNode->mStyleData.mResetData) {
02937       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
02938       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
02939         display->Destroy(mPresContext);
02940         return nsnull;
02941       }
02942     }
02943     aHighestNode->mStyleData.mResetData->mDisplayData = display;
02944     // Propagate the bit down.
02945     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Display), aHighestNode);
02946   }
02947 
02948   return display;
02949 }
02950 
02951 const nsStyleStruct*
02952 nsRuleNode::ComputeVisibilityData(nsStyleStruct* aStartStruct,
02953                                   const nsRuleDataStruct& aData, 
02954                                   nsStyleContext* aContext, 
02955                                   nsRuleNode* aHighestNode,
02956                                   const RuleDetail& aRuleDetail, PRBool aInherited)
02957 {
02958   nsStyleContext* parentContext = aContext->GetParent();
02959 
02960   const nsRuleDataDisplay& displayData = NS_STATIC_CAST(const nsRuleDataDisplay&, aData);
02961   nsStyleVisibility* visibility = nsnull;
02962   const nsStyleVisibility* parentVisibility = nsnull;
02963   PRBool inherited = aInherited;
02964 
02965   if (parentContext && aRuleDetail != eRuleFullReset)
02966     parentVisibility = parentContext->GetStyleVisibility();
02967   if (aStartStruct)
02968     // We only need to compute the delta between this computed data and our
02969     // computed data.
02970     visibility = new (mPresContext) nsStyleVisibility(*NS_STATIC_CAST(nsStyleVisibility*, aStartStruct));
02971   else {
02972     // XXXldb What about eRuleFullInherited?  Which path is faster?
02973     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {
02974       // No question. We will have to inherit. Go ahead and init
02975       // with inherited vals from parent.
02976       inherited = PR_TRUE;
02977       if (parentVisibility)
02978         visibility = new (mPresContext) nsStyleVisibility(*parentVisibility);
02979       else
02980         visibility = new (mPresContext) nsStyleVisibility(mPresContext);
02981     }
02982     else
02983       visibility = new (mPresContext) nsStyleVisibility(mPresContext);
02984   }
02985 
02986   if (NS_UNLIKELY(!visibility))
02987     return nsnull;  // Out Of Memory
02988   if (!parentVisibility)
02989     parentVisibility = visibility;
02990 
02991   // direction: enum, inherit
02992   if (eCSSUnit_Enumerated == displayData.mDirection.GetUnit()) {
02993     visibility->mDirection = displayData.mDirection.GetIntValue();
02994     if (NS_STYLE_DIRECTION_RTL == visibility->mDirection)
02995       mPresContext->SetBidiEnabled(PR_TRUE);
02996   }
02997   else if (eCSSUnit_Inherit == displayData.mDirection.GetUnit()) {
02998     inherited = PR_TRUE;
02999     visibility->mDirection = parentVisibility->mDirection;
03000   }
03001 
03002   // visibility: enum, inherit
03003   if (eCSSUnit_Enumerated == displayData.mVisibility.GetUnit()) {
03004     visibility->mVisible = displayData.mVisibility.GetIntValue();
03005   }
03006   else if (eCSSUnit_Inherit == displayData.mVisibility.GetUnit()) {
03007     inherited = PR_TRUE;
03008     visibility->mVisible = parentVisibility->mVisible;
03009   }
03010 
03011   // lang: string, inherit
03012   // this is not a real CSS property, it is a html attribute mapped to CSS struture
03013   if (eCSSUnit_String == displayData.mLang.GetUnit()) {
03014     if (!gLangService) {
03015       CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService);
03016     }
03017 
03018     if (gLangService) {
03019       nsAutoString lang;
03020       displayData.mLang.GetStringValue(lang);
03021       visibility->mLangGroup = gLangService->LookupLanguage(lang);
03022     }
03023   } 
03024 
03025   if (inherited)
03026     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
03027     // style context.
03028     aContext->SetStyle(eStyleStruct_Visibility, visibility);
03029   else {
03030     // We were fully specified and can therefore be cached right on the rule node.
03031     if (!aHighestNode->mStyleData.mInheritedData) {
03032       aHighestNode->mStyleData.mInheritedData = new (mPresContext) nsInheritedStyleData;
03033       if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) {
03034         visibility->Destroy(mPresContext);
03035         return nsnull;
03036       }
03037     }
03038     aHighestNode->mStyleData.mInheritedData->mVisibilityData = visibility;
03039     // Propagate the bit down.
03040     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Visibility), aHighestNode);
03041   }
03042 
03043   return visibility;
03044 }
03045 
03046 const nsStyleStruct*
03047 nsRuleNode::ComputeColorData(nsStyleStruct* aStartStruct,
03048                              const nsRuleDataStruct& aData, 
03049                              nsStyleContext* aContext, 
03050                              nsRuleNode* aHighestNode,
03051                              const RuleDetail& aRuleDetail, PRBool aInherited)
03052 {
03053   nsStyleContext* parentContext = aContext->GetParent();
03054 
03055   const nsRuleDataColor& colorData = NS_STATIC_CAST(const nsRuleDataColor&, aData);
03056   nsStyleColor* color = nsnull;
03057   const nsStyleColor* parentColor = nsnull;
03058   PRBool inherited = aInherited;
03059 
03060   if (parentContext && aRuleDetail != eRuleFullReset)
03061     parentColor = parentContext->GetStyleColor();
03062   if (aStartStruct)
03063     // We only need to compute the delta between this computed data and our
03064     // computed data.
03065     color = new (mPresContext) nsStyleColor(*NS_STATIC_CAST(nsStyleColor*, aStartStruct));
03066   else {
03067     // XXXldb What about eRuleFullInherited?  Which path is faster?
03068     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {
03069       // No question. We will have to inherit. Go ahead and init
03070       // with inherited vals from parent.
03071       inherited = PR_TRUE;
03072       if (parentColor)
03073         color = new (mPresContext) nsStyleColor(*parentColor);
03074       else
03075         color = new (mPresContext) nsStyleColor(mPresContext);
03076     }
03077     else
03078       color = new (mPresContext) nsStyleColor(mPresContext);
03079   }
03080 
03081   if (NS_UNLIKELY(!color))
03082     return nsnull;  // Out Of Memory
03083   if (!parentColor)
03084     parentColor = color;
03085 
03086   // color: color, string, inherit
03087   // Special case for currentColor.  According to CSS3, setting color to 'currentColor'
03088   // should behave as if it is inherited
03089   if (colorData.mColor.GetUnit() == eCSSUnit_Integer && 
03090       colorData.mColor.GetIntValue() == NS_COLOR_CURRENTCOLOR) {
03091     color->mColor = parentColor->mColor;
03092     inherited = PR_TRUE;
03093   } else {
03094     SetColor(colorData.mColor, parentColor->mColor, mPresContext, aContext, color->mColor, 
03095              inherited);
03096   }
03097 
03098   if (inherited)
03099     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
03100     // style context.
03101     aContext->SetStyle(eStyleStruct_Color, color);
03102   else {
03103     // We were fully specified and can therefore be cached right on the rule node.
03104     if (!aHighestNode->mStyleData.mInheritedData) {
03105       aHighestNode->mStyleData.mInheritedData = new (mPresContext) nsInheritedStyleData;
03106       if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) {
03107         color->Destroy(mPresContext);
03108         return nsnull;
03109       }
03110     }
03111     aHighestNode->mStyleData.mInheritedData->mColorData = color;
03112     // Propagate the bit down.
03113     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Color), aHighestNode);
03114   }
03115 
03116   return color;
03117 }
03118 
03119 const nsStyleStruct*
03120 nsRuleNode::ComputeBackgroundData(nsStyleStruct* aStartStruct,
03121                                   const nsRuleDataStruct& aData, 
03122                                   nsStyleContext* aContext, 
03123                                   nsRuleNode* aHighestNode,
03124                                   const RuleDetail& aRuleDetail, PRBool aInherited)
03125 {
03126   nsStyleContext* parentContext = aContext->GetParent();
03127 
03128   const nsRuleDataColor& colorData = NS_STATIC_CAST(const nsRuleDataColor&, aData);
03129   nsStyleBackground* bg;
03130   if (aStartStruct)
03131     // We only need to compute the delta between this computed data and our
03132     // computed data.
03133     bg = new (mPresContext) nsStyleBackground(*NS_STATIC_CAST(nsStyleBackground*, aStartStruct));
03134   else
03135     bg = new (mPresContext) nsStyleBackground(mPresContext);
03136 
03137   if (NS_UNLIKELY(!bg))
03138     return nsnull;  // Out Of Memory
03139 
03140   const nsStyleBackground* parentBG = bg;
03141   if (parentContext && 
03142       aRuleDetail != eRuleFullReset &&
03143       aRuleDetail != eRulePartialReset &&
03144       aRuleDetail != eRuleNone)
03145     parentBG = parentContext->GetStyleBackground();
03146   PRBool inherited = aInherited;
03147   // save parentFlags in case bg == parentBG and we clobber them later
03148   PRUint8 parentFlags = parentBG->mBackgroundFlags;
03149 
03150   // background-color: color, string, enum (flags), inherit
03151   if (eCSSUnit_Inherit == colorData.mBackColor.GetUnit()) { // do inherit first, so SetColor doesn't do it
03152     bg->mBackgroundColor = parentBG->mBackgroundColor;
03153     bg->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT;
03154     bg->mBackgroundFlags |= (parentFlags & NS_STYLE_BG_COLOR_TRANSPARENT);
03155     inherited = PR_TRUE;
03156   }
03157   else if (SetColor(colorData.mBackColor, parentBG->mBackgroundColor, 
03158                     mPresContext, aContext, bg->mBackgroundColor, inherited)) {
03159     bg->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT;
03160   }
03161   else if (eCSSUnit_Enumerated == colorData.mBackColor.GetUnit()) {
03162     //bg->mBackgroundColor = parentBG->mBackgroundColor; XXXwdh crap crap crap!
03163     bg->mBackgroundFlags |= NS_STYLE_BG_COLOR_TRANSPARENT;
03164   }
03165 
03166   // background-image: url (stored as image), none, inherit
03167   if (eCSSUnit_Image == colorData.mBackImage.GetUnit()) {
03168     bg->mBackgroundImage = colorData.mBackImage.GetImageValue();
03169     bg->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE;
03170   }
03171   else if (eCSSUnit_None == colorData.mBackImage.GetUnit()) {
03172     bg->mBackgroundImage = nsnull;
03173     bg->mBackgroundFlags |= NS_STYLE_BG_IMAGE_NONE;
03174   }
03175   else if (eCSSUnit_Inherit == colorData.mBackImage.GetUnit()) {
03176     inherited = PR_TRUE;
03177     bg->mBackgroundImage = parentBG->mBackgroundImage;
03178     bg->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE;
03179     bg->mBackgroundFlags |= (parentFlags & NS_STYLE_BG_IMAGE_NONE);
03180   }
03181 
03182   // background-repeat: enum, inherit
03183   if (eCSSUnit_Enumerated == colorData.mBackRepeat.GetUnit()) {
03184     bg->mBackgroundRepeat = colorData.mBackRepeat.GetIntValue();
03185   }
03186   else if (eCSSUnit_Inherit == colorData.mBackRepeat.GetUnit()) {
03187     inherited = PR_TRUE;
03188     bg->mBackgroundRepeat = parentBG->mBackgroundRepeat;
03189   }
03190 
03191   // background-attachment: enum, inherit
03192   if (eCSSUnit_Enumerated == colorData.mBackAttachment.GetUnit()) {
03193     bg->mBackgroundAttachment = colorData.mBackAttachment.GetIntValue();
03194   }
03195   else if (eCSSUnit_Inherit == colorData.mBackAttachment.GetUnit()) {
03196     inherited = PR_TRUE;
03197     bg->mBackgroundAttachment = parentBG->mBackgroundAttachment;
03198   }
03199 
03200   // background-clip: enum, inherit, initial
03201   if (eCSSUnit_Enumerated == colorData.mBackClip.GetUnit()) {
03202     bg->mBackgroundClip = colorData.mBackClip.GetIntValue();
03203   }
03204   else if (eCSSUnit_Inherit == colorData.mBackClip.GetUnit()) {
03205     bg->mBackgroundClip = parentBG->mBackgroundClip;
03206   }
03207   else if (eCSSUnit_Initial == colorData.mBackClip.GetUnit()) {
03208     bg->mBackgroundClip = NS_STYLE_BG_CLIP_BORDER;
03209   }
03210 
03211   // background-inline-policy: enum, inherit, initial
03212   if (eCSSUnit_Enumerated == colorData.mBackInlinePolicy.GetUnit()) {
03213     bg->mBackgroundInlinePolicy = colorData.mBackInlinePolicy.GetIntValue();
03214   }
03215   else if (eCSSUnit_Inherit == colorData.mBackInlinePolicy.GetUnit()) {
03216     bg->mBackgroundInlinePolicy = parentBG->mBackgroundInlinePolicy;
03217   }
03218   else if (eCSSUnit_Initial == colorData.mBackInlinePolicy.GetUnit()) {
03219     bg->mBackgroundInlinePolicy = NS_STYLE_BG_INLINE_POLICY_CONTINUOUS;
03220   }
03221 
03222   // background-origin: enum, inherit, initial
03223   if (eCSSUnit_Enumerated == colorData.mBackOrigin.GetUnit()) {
03224     bg->mBackgroundOrigin = colorData.mBackOrigin.GetIntValue();
03225   }
03226   else if (eCSSUnit_Inherit == colorData.mBackOrigin.GetUnit()) {
03227     bg->mBackgroundOrigin = parentBG->mBackgroundOrigin;
03228   }
03229   else if (eCSSUnit_Initial == colorData.mBackOrigin.GetUnit()) {
03230     bg->mBackgroundOrigin = NS_STYLE_BG_ORIGIN_PADDING;
03231   }
03232 
03233   // background-position: enum, length, percent (flags), inherit
03234   if (eCSSUnit_Percent == colorData.mBackPositionX.GetUnit()) {
03235     bg->mBackgroundXPosition.mFloat = colorData.mBackPositionX.GetPercentValue();
03236     bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PERCENT;
03237     bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH;
03238   }
03239   else if (colorData.mBackPositionX.IsLengthUnit()) {
03240     bg->mBackgroundXPosition.mCoord = CalcLength(colorData.mBackPositionX, nsnull, 
03241                                                  aContext, mPresContext, inherited);
03242     bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_LENGTH;
03243     bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_PERCENT;
03244   }
03245   else if (eCSSUnit_Enumerated == colorData.mBackPositionX.GetUnit()) {
03246     bg->mBackgroundXPosition.mFloat = (float)colorData.mBackPositionX.GetIntValue() / 100.0f;
03247     bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PERCENT;
03248     bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH;
03249   }
03250   else if (eCSSUnit_Inherit == colorData.mBackPositionX.GetUnit()) {
03251     inherited = PR_TRUE;
03252     bg->mBackgroundXPosition = parentBG->mBackgroundXPosition;
03253     bg->mBackgroundFlags &= ~(NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT);
03254     bg->mBackgroundFlags |= (parentFlags & (NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT));
03255   }
03256 
03257   if (eCSSUnit_Percent == colorData.mBackPositionY.GetUnit()) {
03258     bg->mBackgroundYPosition.mFloat = colorData.mBackPositionY.GetPercentValue();
03259     bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PERCENT;
03260     bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
03261   }
03262   else if (colorData.mBackPositionY.IsLengthUnit()) {
03263     bg->mBackgroundYPosition.mCoord = CalcLength(colorData.mBackPositionY, nsnull,
03264                                                  aContext, mPresContext, inherited);
03265     bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_LENGTH;
03266     bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_PERCENT;
03267   }
03268   else if (eCSSUnit_Enumerated == colorData.mBackPositionY.GetUnit()) {
03269     bg->mBackgroundYPosition.mFloat = (float)colorData.mBackPositionY.GetIntValue() / 100.0f;
03270     bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PERCENT;
03271     bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
03272   }
03273   else if (eCSSUnit_Inherit == colorData.mBackPositionY.GetUnit()) {
03274     inherited = PR_TRUE;
03275     bg->mBackgroundYPosition = parentBG->mBackgroundYPosition;
03276     bg->mBackgroundFlags &= ~(NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT);
03277     bg->mBackgroundFlags |= (parentFlags & (NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT));
03278   }
03279 
03280   if (inherited)
03281     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
03282     // style context.
03283     aContext->SetStyle(eStyleStruct_Background, bg);
03284   else {
03285     // We were fully specified and can therefore be cached right on the rule node.
03286     if (!aHighestNode->mStyleData.mResetData) {
03287       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
03288       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
03289         bg->Destroy(mPresContext);
03290         return nsnull;
03291       }
03292     }
03293     aHighestNode->mStyleData.mResetData->mBackgroundData = bg;
03294     // Propagate the bit down.
03295     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Background), aHighestNode);
03296   }
03297 
03298   return bg;
03299 }
03300 
03301 const nsStyleStruct*
03302 nsRuleNode::ComputeMarginData(nsStyleStruct* aStartStruct,
03303                               const nsRuleDataStruct& aData, 
03304                               nsStyleContext* aContext, 
03305                               nsRuleNode* aHighestNode,
03306                               const RuleDetail& aRuleDetail, PRBool aInherited)
03307 {
03308   nsStyleContext* parentContext = aContext->GetParent();
03309 
03310   const nsRuleDataMargin& marginData = NS_STATIC_CAST(const nsRuleDataMargin&, aData);
03311   nsStyleMargin* margin;
03312   if (aStartStruct)
03313     // We only need to compute the delta between this computed data and our
03314     // computed data.
03315     margin = new (mPresContext) nsStyleMargin(*NS_STATIC_CAST(nsStyleMargin*, aStartStruct));
03316   else
03317     margin = new (mPresContext) nsStyleMargin();
03318 
03319   if (NS_UNLIKELY(!margin))
03320     return nsnull;  // Out Of Memory
03321 
03322   const nsStyleMargin* parentMargin = margin;
03323   if (parentContext && 
03324       aRuleDetail != eRuleFullReset &&
03325       aRuleDetail != eRulePartialReset &&
03326       aRuleDetail != eRuleNone)
03327     parentMargin = parentContext->GetStyleMargin();
03328   PRBool inherited = aInherited;
03329 
03330   // margin: length, percent, auto, inherit
03331   nsStyleCoord  coord;
03332   nsStyleCoord  parentCoord;
03333   NS_FOR_CSS_SIDES(side) {
03334     parentMargin->mMargin.Get(side, parentCoord);
03335     if (SetCoord(marginData.mMargin.*(nsCSSRect::sides[side]),
03336                  coord, parentCoord, SETCOORD_LPAH,
03337                  aContext, mPresContext, inherited)) {
03338       margin->mMargin.Set(side, coord);
03339     }
03340   }
03341 
03342   AdjustLogicalBoxProp(aContext,
03343                        marginData.mMarginLeftLTRSource,
03344                        marginData.mMarginLeftRTLSource,
03345                        marginData.mMarginStart, marginData.mMarginEnd,
03346                        parentMargin->mMargin, margin->mMargin,
03347                        NS_SIDE_LEFT, SETCOORD_LPAH, inherited);
03348   AdjustLogicalBoxProp(aContext,
03349                        marginData.mMarginRightLTRSource,
03350                        marginData.mMarginRightRTLSource,
03351                        marginData.mMarginEnd, marginData.mMarginStart,
03352                        parentMargin->mMargin, margin->mMargin,
03353                        NS_SIDE_RIGHT, SETCOORD_LPAH, inherited);
03354 
03355   if (inherited)
03356     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
03357     // style context.
03358     aContext->SetStyle(eStyleStruct_Margin, margin);
03359   else {
03360     // We were fully specified and can therefore be cached right on the rule node.
03361     if (!aHighestNode->mStyleData.mResetData) {
03362       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
03363       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
03364         margin->Destroy(mPresContext);
03365         return nsnull;
03366       }
03367     }
03368     aHighestNode->mStyleData.mResetData->mMarginData = margin;
03369     // Propagate the bit down.
03370     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Margin), aHighestNode);
03371   }
03372 
03373   margin->RecalcData();
03374   return margin;
03375 }
03376 
03377 const nsStyleStruct* 
03378 nsRuleNode::ComputeBorderData(nsStyleStruct* aStartStruct,
03379                               const nsRuleDataStruct& aData, 
03380                               nsStyleContext* aContext, 
03381                               nsRuleNode* aHighestNode,
03382                               const RuleDetail& aRuleDetail, PRBool aInherited)
03383 {
03384   nsStyleContext* parentContext = aContext->GetParent();
03385 
03386   const nsRuleDataMargin& marginData = NS_STATIC_CAST(const nsRuleDataMargin&, aData);
03387   nsStyleBorder* border;
03388   if (aStartStruct)
03389     // We only need to compute the delta between this computed data and our
03390     // computed data.
03391     border = new (mPresContext) nsStyleBorder(*NS_STATIC_CAST(nsStyleBorder*, aStartStruct));
03392   else
03393     border = new (mPresContext) nsStyleBorder(mPresContext);
03394   
03395   if (NS_UNLIKELY(!border))
03396     return nsnull;  // Out Of Memory
03397 
03398   const nsStyleBorder* parentBorder = border;
03399   if (parentContext && 
03400       aRuleDetail != eRuleFullReset &&
03401       aRuleDetail != eRulePartialReset &&
03402       aRuleDetail != eRuleNone)
03403     parentBorder = parentContext->GetStyleBorder();
03404   PRBool inherited = aInherited;
03405 
03406   // border-size: length, enum, inherit
03407   nsStyleCoord  coord;
03408   nsStyleCoord  parentCoord;
03409   { // scope for compilers with broken |for| loop scoping
03410     NS_FOR_CSS_SIDES(side) {
03411       const nsCSSValue &value = marginData.mBorderWidth.*(nsCSSRect::sides[side]);
03412       NS_ASSERTION(eCSSUnit_Percent != value.GetUnit(),
03413                    "Percentage borders not implemented yet "
03414                    "If implementing, make sure to fix all consumers of "
03415                    "nsStyleBorder, the IsPercentageAwareChild method, "
03416                    "the nsAbsoluteContainingBlock::FrameDependsOnContainer "
03417                    "method, the "
03418                    "nsLineLayout::IsPercentageAwareReplacedElement method "
03419                    "and probably some other places");
03420       if (eCSSUnit_Enumerated == value.GetUnit()) {
03421         NS_ASSERTION(value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
03422                      value.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
03423                      value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
03424                      "Unexpected enum value");
03425         border->SetBorderWidth(side,
03426                                (mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
03427       }
03428       else if (SetCoord(value, coord, parentCoord, SETCOORD_LENGTH, aContext,
03429                         mPresContext, inherited)) {
03430         if (coord.GetUnit() == eStyleUnit_Coord) {
03431           border->SetBorderWidth(side, coord.GetCoordValue());
03432         }
03433 #ifdef DEBUG
03434         else {
03435           NS_ASSERTION(coord.GetUnit() == eStyleUnit_Chars, "unexpected unit");
03436           NS_WARNING("Border set in chars; we don't handle that");
03437         }
03438 #endif        
03439       }
03440       else if (eCSSUnit_Inherit == value.GetUnit()) {
03441         inherited = PR_TRUE;
03442         border->SetBorderWidth(side, parentBorder->GetBorderWidth(side));
03443       }
03444       else if (eCSSUnit_Initial == value.GetUnit()) {
03445         border->SetBorderWidth(side,
03446           (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
03447       }
03448     }
03449   }
03450 
03451   // border-style: enum, none, inhert
03452   const nsCSSRect& ourStyle = marginData.mBorderStyle;
03453   { // scope for compilers with broken |for| loop scoping
03454     NS_FOR_CSS_SIDES(side) {
03455       const nsCSSValue &value = ourStyle.*(nsCSSRect::sides[side]);
03456       nsCSSUnit unit = value.GetUnit();
03457       if (eCSSUnit_Enumerated == unit) {
03458         border->SetBorderStyle(side, value.GetIntValue());
03459       }
03460       else if (eCSSUnit_None == unit || eCSSUnit_Initial == unit) {
03461         border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
03462       }
03463       else if (eCSSUnit_Inherit == unit) {
03464         inherited = PR_TRUE;
03465         border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
03466       }
03467     }
03468   }
03469 
03470   // border-colors: color, string, enum
03471   nscolor borderColor;
03472   nscolor unused = NS_RGB(0,0,0);
03473   
03474   { // scope for compilers with broken |for| loop scoping
03475     NS_FOR_CSS_SIDES(side) {
03476       nsCSSValueList* list =
03477           marginData.mBorderColors.*(nsCSSValueListRect::sides[side]);
03478       if (list) {
03479         // Some composite border color information has been specified for this
03480         // border side.
03481         border->EnsureBorderColors();
03482         border->ClearBorderColors(side);
03483         while (list) {
03484           if (SetColor(list->mValue, unused, mPresContext, aContext, borderColor, inherited))
03485             border->AppendBorderColor(side, borderColor, PR_FALSE);
03486           else if (eCSSUnit_Enumerated == list->mValue.GetUnit() &&
03487                    NS_STYLE_COLOR_TRANSPARENT == list->mValue.GetIntValue())
03488             border->AppendBorderColor(side, nsnull, PR_TRUE);
03489           list = list->mNext;
03490         }
03491       }
03492     }
03493   }
03494 
03495   // border-color: color, string, enum, inherit
03496   const nsCSSRect& ourBorderColor = marginData.mBorderColor;
03497   PRBool transparent;
03498   PRBool foreground;
03499 
03500   { // scope for compilers with broken |for| loop scoping
03501     NS_FOR_CSS_SIDES(side) {
03502       const nsCSSValue &value = ourBorderColor.*(nsCSSRect::sides[side]);
03503       if (eCSSUnit_Inherit == value.GetUnit()) {
03504         if (parentContext) {
03505           inherited = PR_TRUE;
03506           parentBorder->GetBorderColor(side, borderColor,
03507                                        transparent, foreground);
03508           if (transparent)
03509             border->SetBorderTransparent(side);
03510           else if (foreground) {
03511             // We want to inherit the color from the parent, not use the
03512             // color on the element where this chunk of style data will be
03513             // used.  We can ensure that the data for the parent are fully
03514             // computed (unlike for the element where this will be used, for
03515             // which the color could be specified on a more specific rule).
03516             border->SetBorderColor(side, parentContext->GetStyleColor()->mColor);
03517           } else
03518             border->SetBorderColor(side, borderColor);
03519         } else {
03520           // We're the root
03521           border->SetBorderToForeground(side);
03522         }
03523       }
03524       else if (SetColor(value, unused, mPresContext, aContext, borderColor, inherited)) {
03525         border->SetBorderColor(side, borderColor);
03526       }
03527       else if (eCSSUnit_Enumerated == value.GetUnit()) {
03528         switch (value.GetIntValue()) {
03529           case NS_STYLE_COLOR_TRANSPARENT:
03530             border->SetBorderTransparent(side);
03531             break;
03532           case NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR:
03533             border->SetBorderToForeground(side);
03534             break;
03535         }
03536       }
03537     }
03538   }
03539 
03540   // -moz-border-radius: length, percent, inherit
03541   { // scope for compilers with broken |for| loop scoping
03542     NS_FOR_CSS_SIDES(side) {
03543       parentBorder->mBorderRadius.Get(side, parentCoord);
03544       if (SetCoord(marginData.mBorderRadius.*(nsCSSRect::sides[side]), coord,
03545                    parentCoord, SETCOORD_LPH, aContext, mPresContext,
03546                    inherited))
03547         border->mBorderRadius.Set(side, coord);
03548     }
03549   }
03550 
03551   // float-edge: enum, inherit
03552   if (eCSSUnit_Enumerated == marginData.mFloatEdge.GetUnit())
03553     border->mFloatEdge = marginData.mFloatEdge.GetIntValue();
03554   else if (eCSSUnit_Inherit == marginData.mFloatEdge.GetUnit()) {
03555     inherited = PR_TRUE;
03556     border->mFloatEdge = parentBorder->mFloatEdge;
03557   }
03558 
03559   if (inherited)
03560     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
03561     // style context.
03562     aContext->SetStyle(eStyleStruct_Border, border);
03563   else {
03564     // We were fully specified and can therefore be cached right on the rule node.
03565     if (!aHighestNode->mStyleData.mResetData) {
03566       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
03567       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
03568         border->Destroy(mPresContext);
03569         return nsnull;
03570       }
03571     }
03572     aHighestNode->mStyleData.mResetData->mBorderData = border;
03573     // Propagate the bit down.
03574     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Border), aHighestNode);
03575   }
03576 
03577   return border;
03578 }
03579   
03580 const nsStyleStruct*
03581 nsRuleNode::ComputePaddingData(nsStyleStruct* aStartStruct,
03582                                const nsRuleDataStruct& aData, 
03583                                nsStyleContext* aContext, 
03584                                nsRuleNode* aHighestNode,
03585                                const RuleDetail& aRuleDetail, PRBool aInherited)
03586 {
03587   nsStyleContext* parentContext = aContext->GetParent();
03588 
03589   const nsRuleDataMargin& marginData = NS_STATIC_CAST(const nsRuleDataMargin&, aData);
03590   nsStylePadding* padding;
03591   if (aStartStruct)
03592     // We only need to compute the delta between this computed data and our
03593     // computed data.
03594     padding = new (mPresContext) nsStylePadding(*NS_STATIC_CAST(nsStylePadding*, aStartStruct));
03595   else
03596     padding = new (mPresContext) nsStylePadding();
03597   
03598   if (NS_UNLIKELY(!padding))
03599     return nsnull;  // Out Of Memory
03600 
03601   const nsStylePadding* parentPadding = padding;
03602   if (parentContext && 
03603       aRuleDetail != eRuleFullReset &&
03604       aRuleDetail != eRulePartialReset &&
03605       aRuleDetail != eRuleNone)
03606     parentPadding = parentContext->GetStylePadding();
03607   PRBool inherited = aInherited;
03608 
03609   // padding: length, percent, inherit
03610   nsStyleCoord  coord;
03611   nsStyleCoord  parentCoord;
03612   NS_FOR_CSS_SIDES(side) {
03613     parentPadding->mPadding.Get(side, parentCoord);
03614     if (SetCoord(marginData.mPadding.*(nsCSSRect::sides[side]),
03615                  coord, parentCoord, SETCOORD_LPH,
03616                  aContext, mPresContext, inherited)) {
03617       padding->mPadding.Set(side, coord);
03618     }
03619   }
03620 
03621   AdjustLogicalBoxProp(aContext,
03622                        marginData.mPaddingLeftLTRSource,
03623                        marginData.mPaddingLeftRTLSource,
03624                        marginData.mPaddingStart, marginData.mPaddingEnd,
03625                        parentPadding->mPadding, padding->mPadding,
03626                        NS_SIDE_LEFT, SETCOORD_LPH, inherited);
03627   AdjustLogicalBoxProp(aContext,
03628                        marginData.mPaddingRightLTRSource,
03629                        marginData.mPaddingRightRTLSource,
03630                        marginData.mPaddingEnd, marginData.mPaddingStart,
03631                        parentPadding->mPadding, padding->mPadding,
03632                        NS_SIDE_RIGHT, SETCOORD_LPH, inherited);
03633 
03634   if (inherited)
03635     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
03636     // style context.
03637     aContext->SetStyle(eStyleStruct_Padding, padding);
03638   else {
03639     // We were fully specified and can therefore be cached right on the rule node.
03640     if (!aHighestNode->mStyleData.mResetData) {
03641       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
03642       if (!aHighestNode->mStyleData.mResetData) {
03643         delete padding;
03644         return nsnull;
03645       }
03646     }
03647     aHighestNode->mStyleData.mResetData->mPaddingData = padding;
03648     // Propagate the bit down.
03649     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Padding), aHighestNode);
03650   }
03651 
03652   padding->RecalcData();
03653   return padding;
03654 }
03655 
03656 const nsStyleStruct*
03657 nsRuleNode::ComputeOutlineData(nsStyleStruct* aStartStruct,
03658                                const nsRuleDataStruct& aData, 
03659                                nsStyleContext* aContext, 
03660                                nsRuleNode* aHighestNode,
03661                                const RuleDetail& aRuleDetail, PRBool aInherited)
03662 {
03663   nsStyleContext* parentContext = aContext->GetParent();
03664 
03665   const nsRuleDataMargin& marginData = NS_STATIC_CAST(const nsRuleDataMargin&, aData);
03666   nsStyleOutline* outline;
03667   if (aStartStruct)
03668     // We only need to compute the delta between this computed data and our
03669     // computed data.
03670     outline = new (mPresContext) nsStyleOutline(*NS_STATIC_CAST(nsStyleOutline*, aStartStruct));
03671   else
03672     outline = new (mPresContext) nsStyleOutline(mPresContext);
03673   
03674   if (NS_UNLIKELY(!outline))
03675     return nsnull;  // Out Of Memory
03676 
03677   const nsStyleOutline* parentOutline = outline;
03678   if (parentContext && 
03679       aRuleDetail != eRuleFullReset &&
03680       aRuleDetail != eRulePartialReset &&
03681       aRuleDetail != eRuleNone)
03682     parentOutline = parentContext->GetStyleOutline();
03683   PRBool inherited = aInherited;
03684 
03685   // outline-width: length, enum, inherit
03686   SetCoord(marginData.mOutlineWidth, outline->mOutlineWidth, parentOutline->mOutlineWidth,
03687            SETCOORD_LEH, aContext, mPresContext, inherited);
03688 
03689   // outline-offset: length, inherit
03690   SetCoord(marginData.mOutlineOffset, outline->mOutlineOffset, parentOutline->mOutlineOffset,
03691            SETCOORD_LH, aContext, mPresContext, inherited);
03692   
03693 
03694   // outline-color: color, string, enum, inherit
03695   nscolor outlineColor;
03696   nscolor unused = NS_RGB(0,0,0);
03697   if (eCSSUnit_Inherit == marginData.mOutlineColor.GetUnit()) {
03698     inherited = PR_TRUE;
03699     if (parentOutline->GetOutlineColor(outlineColor))
03700       outline->SetOutlineColor(outlineColor);
03701     else
03702       outline->SetOutlineInvert();
03703   }
03704   else if (SetColor(marginData.mOutlineColor, unused, mPresContext, aContext, outlineColor, inherited))
03705     outline->SetOutlineColor(outlineColor);
03706   else if (eCSSUnit_Enumerated == marginData.mOutlineColor.GetUnit())
03707     outline->SetOutlineInvert();
03708 
03709 // -moz-outline-radius: length, percent, inherit
03710   nsStyleCoord  coord;
03711   nsStyleCoord  parentCoord;
03712   { // scope for compilers with broken |for| loop scoping
03713     NS_FOR_CSS_SIDES(side) {
03714       parentOutline->mOutlineRadius.Get(side, parentCoord);
03715       if (SetCoord(marginData.mOutlineRadius.*(nsCSSRect::sides[side]), coord,
03716                    parentCoord, SETCOORD_LPH, aContext, mPresContext,
03717                    inherited))
03718         outline->mOutlineRadius.Set(side, coord);
03719     }
03720   }
03721 
03722   // outline-style: auto, enum, none, inherit
03723   if (eCSSUnit_Enumerated == marginData.mOutlineStyle.GetUnit())
03724     outline->SetOutlineStyle(marginData.mOutlineStyle.GetIntValue());
03725   else if (eCSSUnit_None == marginData.mOutlineStyle.GetUnit())
03726     outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_NONE);
03727   else if (eCSSUnit_Auto == marginData.mOutlineStyle.GetUnit()) {
03728     outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_AUTO);
03729   } else if (eCSSUnit_Inherit == marginData.mOutlineStyle.GetUnit()) {
03730     inherited = PR_TRUE;
03731     outline->SetOutlineStyle(parentOutline->GetOutlineStyle());
03732   }
03733 
03734   if (inherited)
03735     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
03736     // style context.
03737     aContext->SetStyle(eStyleStruct_Outline, outline);
03738   else {
03739     // We were fully specified and can therefore be cached right on the rule node.
03740     if (!aHighestNode->mStyleData.mResetData) {
03741       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
03742       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
03743         outline->Destroy(mPresContext);
03744         return nsnull;
03745       }
03746     }
03747     aHighestNode->mStyleData.mResetData->mOutlineData = outline;
03748     // Propagate the bit down.
03749     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Outline), aHighestNode);
03750   }
03751 
03752   outline->RecalcData(mPresContext);
03753   return outline;
03754 }
03755 
03756 const nsStyleStruct* 
03757 nsRuleNode::ComputeListData(nsStyleStruct* aStartStruct,
03758                             const nsRuleDataStruct& aData, 
03759                             nsStyleContext* aContext, 
03760                             nsRuleNode* aHighestNode,
03761                             const RuleDetail& aRuleDetail, PRBool aInherited)
03762 {
03763   nsStyleContext* parentContext = aContext->GetParent();
03764 
03765   const nsRuleDataList& listData = NS_STATIC_CAST(const nsRuleDataList&, aData);
03766   nsStyleList* list = nsnull;
03767   const nsStyleList* parentList = nsnull;
03768   PRBool inherited = aInherited;
03769 
03770   if (parentContext && aRuleDetail != eRuleFullReset)
03771     parentList = parentContext->GetStyleList();
03772   if (aStartStruct)
03773     // We only need to compute the delta between this computed data and our
03774     // computed data.
03775     list = new (mPresContext) nsStyleList(*NS_STATIC_CAST(nsStyleList*, aStartStruct));
03776   else {
03777     // XXXldb What about eRuleFullInherited?  Which path is faster?
03778     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {
03779       // No question. We will have to inherit. Go ahead and init
03780       // with inherited vals from parent.
03781       inherited = PR_TRUE;
03782       if (parentList)
03783         list = new (mPresContext) nsStyleList(*parentList);
03784       else
03785         list = new (mPresContext) nsStyleList();
03786     }
03787     else
03788       list = new (mPresContext) nsStyleList();
03789   }
03790 
03791   if (NS_UNLIKELY(!list))
03792     return nsnull;  // Out Of Memory
03793   if (!parentList)
03794     parentList = list;
03795 
03796   // list-style-type: enum, none, inherit
03797   if (eCSSUnit_Enumerated == listData.mType.GetUnit()) {
03798     list->mListStyleType = listData.mType.GetIntValue();
03799   }
03800   else if (eCSSUnit_None == listData.mType.GetUnit()) {
03801     list->mListStyleType = NS_STYLE_LIST_STYLE_NONE;
03802   }
03803   else if (eCSSUnit_Inherit == listData.mType.GetUnit()) {
03804     inherited = PR_TRUE;
03805     list->mListStyleType = parentList->mListStyleType;
03806   }
03807 
03808   // list-style-image: url, none, inherit
03809   if (eCSSUnit_Image == listData.mImage.GetUnit()) {
03810     list->mListStyleImage = listData.mImage.GetImageValue();
03811   }
03812   else if (eCSSUnit_None == listData.mImage.GetUnit()) {
03813     list->mListStyleImage = nsnull;
03814   }
03815   else if (eCSSUnit_Inherit == listData.mImage.GetUnit()) {
03816     inherited = PR_TRUE;
03817     list->mListStyleImage = parentList->mListStyleImage;
03818   }
03819 
03820   // list-style-position: enum, inherit
03821   if (eCSSUnit_Enumerated == listData.mPosition.GetUnit()) {
03822     list->mListStylePosition = listData.mPosition.GetIntValue();
03823   }
03824   else if (eCSSUnit_Inherit == listData.mPosition.GetUnit()) {
03825     inherited = PR_TRUE;
03826     list->mListStylePosition = parentList->mListStylePosition;
03827   }
03828 
03829   // image region property: length, auto, inherit
03830   if (eCSSUnit_Inherit == listData.mImageRegion.mTop.GetUnit()) { // if one is inherit, they all are
03831     inherited = PR_TRUE;
03832     list->mImageRegion = parentList->mImageRegion;
03833   }
03834   else {
03835     if (eCSSUnit_Auto == listData.mImageRegion.mTop.GetUnit())
03836       list->mImageRegion.y = 0;
03837     else if (listData.mImageRegion.mTop.IsLengthUnit())
03838       list->mImageRegion.y = CalcLength(listData.mImageRegion.mTop, nsnull, aContext, mPresContext, inherited);
03839       
03840     if (eCSSUnit_Auto == listData.mImageRegion.mBottom.GetUnit())
03841       list->mImageRegion.height = 0;
03842     else if (listData.mImageRegion.mBottom.IsLengthUnit())
03843       list->mImageRegion.height = CalcLength(listData.mImageRegion.mBottom, nsnull, aContext, 
03844                                             mPresContext, inherited) - list->mImageRegion.y;
03845   
03846     if (eCSSUnit_Auto == listData.mImageRegion.mLeft.GetUnit())
03847       list->mImageRegion.x = 0;
03848     else if (listData.mImageRegion.mLeft.IsLengthUnit())
03849       list->mImageRegion.x = CalcLength(listData.mImageRegion.mLeft, nsnull, aContext, mPresContext, inherited);
03850       
03851     if (eCSSUnit_Auto == listData.mImageRegion.mRight.GetUnit())
03852       list->mImageRegion.width = 0;
03853     else if (listData.mImageRegion.mRight.IsLengthUnit())
03854       list->mImageRegion.width = CalcLength(listData.mImageRegion.mRight, nsnull, aContext, mPresContext, inherited) -
03855                                 list->mImageRegion.x;
03856   }
03857 
03858   if (inherited)
03859     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
03860     // style context.
03861     aContext->SetStyle(eStyleStruct_List, list);
03862   else {
03863     // We were fully specified and can therefore be cached right on the rule node.
03864     if (!aHighestNode->mStyleData.mInheritedData) {
03865       aHighestNode->mStyleData.mInheritedData = new (mPresContext) nsInheritedStyleData;
03866       if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) {
03867         list->Destroy(mPresContext);
03868         return nsnull;
03869       }
03870     }
03871     aHighestNode->mStyleData.mInheritedData->mListData = list;
03872     // Propagate the bit down.
03873     PropagateDependentBit(NS_STYLE_INHERIT_BIT(List), aHighestNode);
03874   }
03875 
03876   return list;
03877 }
03878 
03879 const nsStyleStruct* 
03880 nsRuleNode::ComputePositionData(nsStyleStruct* aStartStruct,
03881                                 const nsRuleDataStruct& aData, 
03882                                 nsStyleContext* aContext, 
03883                                 nsRuleNode* aHighestNode,
03884                                 const RuleDetail& aRuleDetail, PRBool aInherited)
03885 {
03886   nsStyleContext* parentContext = aContext->GetParent();
03887 
03888   const nsRuleDataPosition& posData = NS_STATIC_CAST(const nsRuleDataPosition&, aData);
03889   nsStylePosition* pos;
03890   if (aStartStruct)
03891     // We only need to compute the delta between this computed data and our
03892     // computed data.
03893     pos = new (mPresContext) nsStylePosition(*NS_STATIC_CAST(nsStylePosition*, aStartStruct));
03894   else
03895     pos = new (mPresContext) nsStylePosition();
03896   
03897   if (NS_UNLIKELY(!pos))
03898     return nsnull;  // Out Of Memory
03899 
03900   const nsStylePosition* parentPos = pos;
03901   if (parentContext && 
03902       aRuleDetail != eRuleFullReset &&
03903       aRuleDetail != eRulePartialReset &&
03904       aRuleDetail != eRuleNone)
03905     parentPos = parentContext->GetStylePosition();
03906   PRBool inherited = aInherited;
03907 
03908   // box offsets: length, percent, auto, inherit
03909   nsStyleCoord  coord;
03910   nsStyleCoord  parentCoord;
03911   NS_FOR_CSS_SIDES(side) {
03912     parentPos->mOffset.Get(side, parentCoord);
03913     if (SetCoord(posData.mOffset.*(nsCSSRect::sides[side]),
03914                  coord, parentCoord, SETCOORD_LPAH,
03915                  aContext, mPresContext, inherited)) {
03916       pos->mOffset.Set(side, coord);
03917     }
03918   }
03919 
03920   if (posData.mWidth.GetUnit() == eCSSUnit_Proportional)
03921     pos->mWidth.SetIntValue((PRInt32)(posData.mWidth.GetFloatValue()), eStyleUnit_Proportional);
03922   else 
03923     SetCoord(posData.mWidth, pos->mWidth, parentPos->mWidth,
03924              SETCOORD_LPAH, aContext, mPresContext, inherited);
03925   SetCoord(posData.mMinWidth, pos->mMinWidth, parentPos->mMinWidth,
03926            SETCOORD_LPH, aContext, mPresContext, inherited);
03927   if (! SetCoord(posData.mMaxWidth, pos->mMaxWidth, parentPos->mMaxWidth,
03928                  SETCOORD_LPH, aContext, mPresContext, inherited)) {
03929     if (eCSSUnit_None == posData.mMaxWidth.GetUnit()) {
03930       pos->mMaxWidth.Reset();
03931     }
03932   }
03933 
03934   SetCoord(posData.mHeight, pos->mHeight, parentPos->mHeight,
03935            SETCOORD_LPAH, aContext, mPresContext, inherited);
03936   SetCoord(posData.mMinHeight, pos->mMinHeight, parentPos->mMinHeight,
03937            SETCOORD_LPH, aContext, mPresContext, inherited);
03938   if (! SetCoord(posData.mMaxHeight, pos->mMaxHeight, parentPos->mMaxHeight,
03939                  SETCOORD_LPH, aContext, mPresContext, inherited)) {
03940     if (eCSSUnit_None == posData.mMaxHeight.GetUnit()) {
03941       pos->mMaxHeight.Reset();
03942     }
03943   }
03944 
03945   // box-sizing: enum, inherit
03946   if (eCSSUnit_Enumerated == posData.mBoxSizing.GetUnit()) {
03947     pos->mBoxSizing = posData.mBoxSizing.GetIntValue();
03948   }
03949   else if (eCSSUnit_Inherit == posData.mBoxSizing.GetUnit()) {
03950     inherited = PR_TRUE;
03951     pos->mBoxSizing = parentPos->mBoxSizing;
03952   }
03953 
03954   // z-index
03955   if (! SetCoord(posData.mZIndex, pos->mZIndex, parentPos->mZIndex,
03956                  SETCOORD_IA, aContext, nsnull, inherited)) {
03957     if (eCSSUnit_Inherit == posData.mZIndex.GetUnit()) {
03958       // handle inherit, because it's ok to inherit 'auto' here
03959       inherited = PR_TRUE;
03960       pos->mZIndex = parentPos->mZIndex;
03961     }
03962   }
03963 
03964   if (inherited)
03965     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
03966     // style context.
03967     aContext->SetStyle(eStyleStruct_Position, pos);
03968   else {
03969     // We were fully specified and can therefore be cached right on the rule node.
03970     if (!aHighestNode->mStyleData.mResetData) {
03971       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
03972       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
03973         pos->Destroy(mPresContext);
03974         return nsnull;
03975       }
03976     }
03977     aHighestNode->mStyleData.mResetData->mPositionData = pos;
03978     // Propagate the bit down.
03979     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Position), aHighestNode);
03980   }
03981 
03982   return pos;
03983 }
03984 
03985 const nsStyleStruct* 
03986 nsRuleNode::ComputeTableData(nsStyleStruct* aStartStruct,
03987                              const nsRuleDataStruct& aData, 
03988                              nsStyleContext* aContext, 
03989                              nsRuleNode* aHighestNode,
03990                              const RuleDetail& aRuleDetail, PRBool aInherited)
03991 {
03992   nsStyleContext* parentContext = aContext->GetParent();
03993 
03994   const nsRuleDataTable& tableData = NS_STATIC_CAST(const nsRuleDataTable&, aData);
03995   nsStyleTable* table;
03996   if (aStartStruct)
03997     // We only need to compute the delta between this computed data and our
03998     // computed data.
03999     table = new (mPresContext) nsStyleTable(*NS_STATIC_CAST(nsStyleTable*, aStartStruct));
04000   else
04001     table = new (mPresContext) nsStyleTable();
04002   
04003   if (!table)
04004     return nsnull;  // Out Of Memory
04005 
04006   const nsStyleTable* parentTable = table;
04007   if (parentContext && 
04008       aRuleDetail != eRuleFullReset &&
04009       aRuleDetail != eRulePartialReset &&
04010       aRuleDetail != eRuleNone)
04011     parentTable = parentContext->GetStyleTable();
04012   PRBool inherited = aInherited;
04013 
04014   // table-layout: auto, enum, inherit
04015   if (eCSSUnit_Enumerated == tableData.mLayout.GetUnit())
04016     table->mLayoutStrategy = tableData.mLayout.GetIntValue();
04017   else if (eCSSUnit_Auto == tableData.mLayout.GetUnit())
04018     table->mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO;
04019   else if (eCSSUnit_Inherit == tableData.mLayout.GetUnit()) {
04020     inherited = PR_TRUE;
04021     table->mLayoutStrategy = parentTable->mLayoutStrategy;
04022   }
04023 
04024   // rules: enum (not a real CSS prop)
04025   if (eCSSUnit_Enumerated == tableData.mRules.GetUnit())
04026     table->mRules = tableData.mRules.GetIntValue();
04027 
04028   // frame: enum (not a real CSS prop)
04029   if (eCSSUnit_Enumerated == tableData.mFrame.GetUnit())
04030     table->mFrame = tableData.mFrame.GetIntValue();
04031 
04032   // cols: enum, int (not a real CSS prop)
04033   if (eCSSUnit_Enumerated == tableData.mCols.GetUnit() ||
04034       eCSSUnit_Integer == tableData.mCols.GetUnit())
04035     table->mCols = tableData.mCols.GetIntValue();
04036 
04037   // span: pixels (not a real CSS prop)
04038   if (eCSSUnit_Enumerated == tableData.mSpan.GetUnit() ||
04039       eCSSUnit_Integer == tableData.mSpan.GetUnit())
04040     table->mSpan = tableData.mSpan.GetIntValue();
04041     
04042   if (inherited)
04043     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
04044     // style context.
04045     aContext->SetStyle(eStyleStruct_Table, table);
04046   else {
04047     // We were fully specified and can therefore be cached right on the rule node.
04048     if (!aHighestNode->mStyleData.mResetData) {
04049       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
04050       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
04051         table->Destroy(mPresContext);
04052         return nsnull;
04053       }
04054     }
04055     aHighestNode->mStyleData.mResetData->mTableData = table;
04056     // Propagate the bit down.
04057     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Table), aHighestNode);
04058   }
04059 
04060   return table;
04061 }
04062 
04063 const nsStyleStruct* 
04064 nsRuleNode::ComputeTableBorderData(nsStyleStruct* aStartStruct,
04065                                    const nsRuleDataStruct& aData, 
04066                                    nsStyleContext* aContext, 
04067                                    nsRuleNode* aHighestNode,
04068                                    const RuleDetail& aRuleDetail, PRBool aInherited)
04069 {
04070   nsStyleContext* parentContext = aContext->GetParent();
04071 
04072   const nsRuleDataTable& tableData = NS_STATIC_CAST(const nsRuleDataTable&, aData);
04073   nsStyleTableBorder* table = nsnull;
04074   const nsStyleTableBorder* parentTable = nsnull;
04075   PRBool inherited = aInherited;
04076 
04077   if (parentContext && aRuleDetail != eRuleFullReset)
04078     parentTable = parentContext->GetStyleTableBorder();
04079   if (aStartStruct)
04080     // We only need to compute the delta between this computed data and our
04081     // computed data.
04082     table = new (mPresContext) nsStyleTableBorder(*NS_STATIC_CAST(nsStyleTableBorder*, aStartStruct));
04083   else {
04084     // XXXldb What about eRuleFullInherited?  Which path is faster?
04085     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {
04086       // No question. We will have to inherit. Go ahead and init
04087       // with inherited vals from parent.
04088       inherited = PR_TRUE;
04089       if (parentTable)
04090         table = new (mPresContext) nsStyleTableBorder(*parentTable);
04091       else
04092         table = new (mPresContext) nsStyleTableBorder(mPresContext);
04093     }
04094     else
04095       table = new (mPresContext) nsStyleTableBorder(mPresContext);
04096   }
04097 
04098   if (NS_UNLIKELY(!table))
04099     return nsnull;  // Out Of Memory
04100   if (!parentTable)
04101     parentTable = table;
04102 
04103   // border-collapse: enum, inherit
04104   if (eCSSUnit_Enumerated == tableData.mBorderCollapse.GetUnit()) {
04105     table->mBorderCollapse = tableData.mBorderCollapse.GetIntValue();
04106   }
04107   else if (eCSSUnit_Inherit == tableData.mBorderCollapse.GetUnit()) {
04108     inherited = PR_TRUE;
04109     table->mBorderCollapse = parentTable->mBorderCollapse;
04110   }
04111 
04112   // border-spacing-x: length, inherit
04113   SetCoord(tableData.mBorderSpacing.mXValue, table->mBorderSpacingX,
04114            parentTable->mBorderSpacingX, SETCOORD_LH,
04115            aContext, mPresContext, inherited);
04116   // border-spacing-y: length, inherit
04117   SetCoord(tableData.mBorderSpacing.mYValue, table->mBorderSpacingY,
04118            parentTable->mBorderSpacingY, SETCOORD_LH,
04119            aContext, mPresContext, inherited);
04120 
04121   // caption-side: enum, inherit
04122   if (eCSSUnit_Enumerated == tableData.mCaptionSide.GetUnit()) {
04123     table->mCaptionSide = tableData.mCaptionSide.GetIntValue();
04124   }
04125   else if (eCSSUnit_Inherit == tableData.mCaptionSide.GetUnit()) {
04126     inherited = PR_TRUE;
04127     table->mCaptionSide = parentTable->mCaptionSide;
04128   }
04129 
04130   // empty-cells: enum, inherit
04131   if (eCSSUnit_Enumerated == tableData.mEmptyCells.GetUnit()) {
04132     table->mEmptyCells = tableData.mEmptyCells.GetIntValue();
04133   }
04134   else if (eCSSUnit_Inherit == tableData.mEmptyCells.GetUnit()) {
04135     inherited = PR_TRUE;
04136     table->mEmptyCells = parentTable->mEmptyCells;
04137   }
04138 
04139   if (inherited)
04140     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
04141     // style context.
04142     aContext->SetStyle(eStyleStruct_TableBorder, table);
04143   else {
04144     // We were fully specified and can therefore be cached right on the rule node.
04145     if (!aHighestNode->mStyleData.mInheritedData) {
04146       aHighestNode->mStyleData.mInheritedData = new (mPresContext) nsInheritedStyleData;
04147       if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) {
04148         table->Destroy(mPresContext);
04149         return nsnull;
04150       }
04151     }
04152     aHighestNode->mStyleData.mInheritedData->mTableBorderData = table;
04153     // Propagate the bit down.
04154     PropagateDependentBit(NS_STYLE_INHERIT_BIT(TableBorder), aHighestNode);
04155   }
04156 
04157   return table;
04158 }
04159 
04160 const nsStyleStruct* 
04161 nsRuleNode::ComputeContentData(nsStyleStruct* aStartStruct,
04162                                const nsRuleDataStruct& aData, 
04163                                nsStyleContext* aContext, 
04164                                nsRuleNode* aHighestNode,
04165                                const RuleDetail& aRuleDetail, PRBool aInherited)
04166 {
04167   nsStyleContext* parentContext = aContext->GetParent();
04168 
04169   const nsRuleDataContent& contentData = NS_STATIC_CAST(const nsRuleDataContent&, aData);
04170   nsStyleContent* content;
04171   if (aStartStruct)
04172     // We only need to compute the delta between this computed data and our
04173     // computed data.
04174     content = new (mPresContext) nsStyleContent(*NS_STATIC_CAST(nsStyleContent*, aStartStruct));
04175   else
04176     content = new (mPresContext) nsStyleContent();
04177   
04178   if (NS_UNLIKELY(!content))
04179     return nsnull;  // Out Of Memory
04180 
04181   const nsStyleContent* parentContent = content;
04182   if (parentContext && 
04183       aRuleDetail != eRuleFullReset &&
04184       aRuleDetail != eRulePartialReset &&
04185       aRuleDetail != eRuleNone)
04186     parentContent = parentContext->GetStyleContent();
04187   PRBool inherited = aInherited;
04188 
04189   // content: [string, url, counter, attr, enum]+, normal, inherit
04190   PRUint32 count;
04191   nsAutoString  buffer;
04192   nsCSSValueList* contentValue = contentData.mContent;
04193   if (contentValue) {
04194     if (eCSSUnit_Normal == contentValue->mValue.GetUnit() ||
04195         eCSSUnit_Initial == contentValue->mValue.GetUnit()) {
04196       // "normal" and "initial" both mean no content
04197       content->AllocateContents(0);
04198     }
04199     else if (eCSSUnit_Inherit == contentValue->mValue.GetUnit()) {
04200       inherited = PR_TRUE;
04201       count = parentContent->ContentCount();
04202       if (NS_SUCCEEDED(content->AllocateContents(count))) {
04203         while (0 < count--) {
04204           content->ContentAt(count) = parentContent->ContentAt(count);
04205         }
04206       }
04207     }
04208     else {
04209       count = 0;
04210       while (contentValue) {
04211         count++;
04212         contentValue = contentValue->mNext;
04213       }
04214       if (NS_SUCCEEDED(content->AllocateContents(count))) {
04215         const nsAutoString  nullStr;
04216         count = 0;
04217         contentValue = contentData.mContent;
04218         while (contentValue) {
04219           const nsCSSValue& value = contentValue->mValue;
04220           nsCSSUnit unit = value.GetUnit();
04221           nsStyleContentType type;
04222           nsStyleContentData &data = content->ContentAt(count++);
04223           switch (unit) {
04224             case eCSSUnit_String:   type = eStyleContentType_String;    break;
04225             case eCSSUnit_Image:    type = eStyleContentType_Image;       break;
04226             case eCSSUnit_Attr:     type = eStyleContentType_Attr;      break;
04227             case eCSSUnit_Counter:  type = eStyleContentType_Counter;   break;
04228             case eCSSUnit_Counters: type = eStyleContentType_Counters;  break;
04229             case eCSSUnit_Enumerated:
04230               switch (value.GetIntValue()) {
04231                 case NS_STYLE_CONTENT_OPEN_QUOTE:     
04232                   type = eStyleContentType_OpenQuote;     break;
04233                 case NS_STYLE_CONTENT_CLOSE_QUOTE:
04234                   type = eStyleContentType_CloseQuote;    break;
04235                 case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
04236                   type = eStyleContentType_NoOpenQuote;   break;
04237                 case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
04238                   type = eStyleContentType_NoCloseQuote;  break;
04239                 default:
04240                   NS_ERROR("bad content value");
04241               }
04242               break;
04243             default:
04244               NS_ERROR("bad content type");
04245           }
04246           data.mType = type;
04247           if (type == eStyleContentType_Image) {
04248             data.mContent.mImage = value.GetImageValue();
04249             NS_IF_ADDREF(data.mContent.mImage);
04250           }
04251           else if (type <= eStyleContentType_Attr) {
04252             value.GetStringValue(buffer);
04253             Unquote(buffer);
04254             data.mContent.mString = nsCRT::strdup(buffer.get());
04255           }
04256           else if (type <= eStyleContentType_Counters) {
04257             data.mContent.mCounters = value.GetArrayValue();
04258             data.mContent.mCounters->AddRef();
04259           }
04260           else {
04261             data.mContent.mString = nsnull;
04262           }
04263           contentValue = contentValue->mNext;
04264         }
04265       } 
04266     }
04267   }
04268 
04269   // counter-increment: [string [int]]+, none, inherit
04270   nsCSSCounterData* ourIncrement = contentData.mCounterIncrement;
04271   if (ourIncrement) {
04272     if (eCSSUnit_None == ourIncrement->mCounter.GetUnit() ||
04273         eCSSUnit_Initial == ourIncrement->mCounter.GetUnit()) {
04274       content->AllocateCounterIncrements(0);
04275     }
04276     else if (eCSSUnit_Inherit == ourIncrement->mCounter.GetUnit()) {
04277       inherited = PR_TRUE;
04278       count = parentContent->CounterIncrementCount();
04279       if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
04280         while (0 < count--) {
04281           const nsStyleCounterData *data =
04282             parentContent->GetCounterIncrementAt(count);
04283           content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
04284         }
04285       }
04286     }
04287     else if (eCSSUnit_String == ourIncrement->mCounter.GetUnit()) {
04288       count = 0;
04289       while (ourIncrement) {
04290         count++;
04291         ourIncrement = ourIncrement->mNext;
04292       }
04293       if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
04294         count = 0;
04295         ourIncrement = contentData.mCounterIncrement;
04296         while (ourIncrement) {
04297           PRInt32 increment;
04298           if (eCSSUnit_Integer == ourIncrement->mValue.GetUnit()) {
04299             increment = ourIncrement->mValue.GetIntValue();
04300           }
04301           else {
04302             increment = 1;
04303           }
04304           ourIncrement->mCounter.GetStringValue(buffer);
04305           content->SetCounterIncrementAt(count++, buffer, increment);
04306           ourIncrement = ourIncrement->mNext;
04307         }
04308       }
04309     }
04310   }
04311 
04312   // counter-reset: [string [int]]+, none, inherit
04313   nsCSSCounterData* ourReset = contentData.mCounterReset;
04314   if (ourReset) {
04315     if (eCSSUnit_None == ourReset->mCounter.GetUnit() ||
04316         eCSSUnit_Initial == ourReset->mCounter.GetUnit()) {
04317       content->AllocateCounterResets(0);
04318     }
04319     else if (eCSSUnit_Inherit == ourReset->mCounter.GetUnit()) {
04320       inherited = PR_TRUE;
04321       count = parentContent->CounterResetCount();
04322       if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
04323         while (0 < count--) {
04324           const nsStyleCounterData *data =
04325             parentContent->GetCounterResetAt(count);
04326           content->SetCounterResetAt(count, data->mCounter, data->mValue);
04327         }
04328       }
04329     }
04330     else if (eCSSUnit_String == ourReset->mCounter.GetUnit()) {
04331       count = 0;
04332       while (ourReset) {
04333         count++;
04334         ourReset = ourReset->mNext;
04335       }
04336       if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
04337         count = 0;
04338         ourReset = contentData.mCounterReset;
04339         while (ourReset) {
04340           PRInt32 reset;
04341           if (eCSSUnit_Integer == ourReset->mValue.GetUnit()) {
04342             reset = ourReset->mValue.GetIntValue();
04343           }
04344           else {
04345             reset = 0;
04346           }
04347           ourReset->mCounter.GetStringValue(buffer);
04348           content->SetCounterResetAt(count++, buffer, reset);
04349           ourReset = ourReset->mNext;
04350         }
04351       }
04352     }
04353   }
04354 
04355   // marker-offset: length, auto, inherit
04356   SetCoord(contentData.mMarkerOffset, content->mMarkerOffset, parentContent->mMarkerOffset,
04357            SETCOORD_LH | SETCOORD_AUTO, aContext, mPresContext, inherited);
04358     
04359   if (inherited)
04360     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
04361     // style context.
04362     aContext->SetStyle(eStyleStruct_Content, content);
04363   else {
04364     // We were fully specified and can therefore be cached right on the rule node.
04365     if (!aHighestNode->mStyleData.mResetData) {
04366       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
04367       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
04368         content->Destroy(mPresContext);
04369         return nsnull;
04370       }
04371     }
04372     aHighestNode->mStyleData.mResetData->mContentData = content;
04373     // Propagate the bit down.
04374     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Content), aHighestNode);
04375   }
04376 
04377   return content;
04378 }
04379 
04380 const nsStyleStruct* 
04381 nsRuleNode::ComputeQuotesData(nsStyleStruct* aStartStruct,
04382                               const nsRuleDataStruct& aData, 
04383                               nsStyleContext* aContext, 
04384                               nsRuleNode* aHighestNode,
04385                               const RuleDetail& aRuleDetail, PRBool aInherited)
04386 {
04387   nsStyleContext* parentContext = aContext->GetParent();
04388 
04389   const nsRuleDataContent& contentData = NS_STATIC_CAST(const nsRuleDataContent&, aData);
04390   nsStyleQuotes* quotes = nsnull;
04391   const nsStyleQuotes* parentQuotes = nsnull;
04392   PRBool inherited = aInherited;
04393 
04394   if (parentContext && aRuleDetail != eRuleFullReset)
04395     parentQuotes = parentContext->GetStyleQuotes();
04396   if (aStartStruct)
04397     // We only need to compute the delta between this computed data and our
04398     // computed data.
04399     quotes = new (mPresContext) nsStyleQuotes(*NS_STATIC_CAST(nsStyleQuotes*, aStartStruct));
04400   else {
04401     // XXXldb What about eRuleFullInherited?  Which path is faster?
04402     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {
04403       // No question. We will have to inherit. Go ahead and init
04404       // with inherited vals from parent.
04405       inherited = PR_TRUE;
04406       if (parentQuotes)
04407         quotes = new (mPresContext) nsStyleQuotes(*parentQuotes);
04408       else
04409         quotes = new (mPresContext) nsStyleQuotes();
04410     }
04411     else
04412       quotes = new (mPresContext) nsStyleQuotes();
04413   }
04414 
04415   if (NS_UNLIKELY(!quotes))
04416     return nsnull;  // Out Of Memory
04417   if (!parentQuotes)
04418     parentQuotes = quotes;
04419 
04420   // quotes: [string string]+, none, inherit
04421   PRUint32 count;
04422   nsAutoString  buffer;
04423   nsCSSQuotes* ourQuotes = contentData.mQuotes;
04424   if (ourQuotes) {
04425     nsAutoString  closeBuffer;
04426     if (eCSSUnit_Inherit == ourQuotes->mOpen.GetUnit()) {
04427       inherited = PR_TRUE;
04428       count = parentQuotes->QuotesCount();
04429       if (NS_SUCCEEDED(quotes->AllocateQuotes(count))) {
04430         while (0 < count--) {
04431           parentQuotes->GetQuotesAt(count, buffer, closeBuffer);
04432           quotes->SetQuotesAt(count, buffer, closeBuffer);
04433         }
04434       }
04435     }
04436     else if (eCSSUnit_None == ourQuotes->mOpen.GetUnit()) {
04437       quotes->AllocateQuotes(0);
04438     }
04439     else if (eCSSUnit_String == ourQuotes->mOpen.GetUnit()) {
04440       count = 0;
04441       while (ourQuotes) {
04442         count++;
04443         ourQuotes = ourQuotes->mNext;
04444       }
04445       if (NS_SUCCEEDED(quotes->AllocateQuotes(count))) {
04446         count = 0;
04447         ourQuotes = contentData.mQuotes;
04448         while (ourQuotes) {
04449           ourQuotes->mOpen.GetStringValue(buffer);
04450           ourQuotes->mClose.GetStringValue(closeBuffer);
04451           Unquote(buffer);
04452           Unquote(closeBuffer);
04453           quotes->SetQuotesAt(count++, buffer, closeBuffer);
04454           ourQuotes = ourQuotes->mNext;
04455         }
04456       }
04457     }
04458   }
04459 
04460   if (inherited)
04461     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
04462     // style context.
04463     aContext->SetStyle(eStyleStruct_Quotes, quotes);
04464   else {
04465     // We were fully specified and can therefore be cached right on the rule node.
04466     if (!aHighestNode->mStyleData.mInheritedData) {
04467       aHighestNode->mStyleData.mInheritedData = new (mPresContext) nsInheritedStyleData;
04468       if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) {
04469         quotes->Destroy(mPresContext);
04470         return nsnull;
04471       }
04472     }
04473     aHighestNode->mStyleData.mInheritedData->mQuotesData = quotes;
04474     // Propagate the bit down.
04475     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Quotes), aHighestNode);
04476   }
04477 
04478   return quotes;
04479 }
04480 
04481 const nsStyleStruct* 
04482 nsRuleNode::ComputeXULData(nsStyleStruct* aStartStruct,
04483                            const nsRuleDataStruct& aData, 
04484                            nsStyleContext* aContext, 
04485                            nsRuleNode* aHighestNode,
04486                            const RuleDetail& aRuleDetail, PRBool aInherited)
04487 {
04488   nsStyleContext* parentContext = aContext->GetParent();
04489 
04490   const nsRuleDataXUL& xulData = NS_STATIC_CAST(const nsRuleDataXUL&, aData);
04491   nsStyleXUL* xul = nsnull;
04492   
04493   if (aStartStruct)
04494     // We only need to compute the delta between this computed data and our
04495     // computed data.
04496     xul = new (mPresContext) nsStyleXUL(*NS_STATIC_CAST(nsStyleXUL*, aStartStruct));
04497   else
04498     xul = new (mPresContext) nsStyleXUL();
04499 
04500   if (NS_UNLIKELY(!xul))
04501     return nsnull;  // Out Of Memory
04502 
04503   const nsStyleXUL* parentXUL = xul;
04504   if (parentContext && 
04505       aRuleDetail != eRuleFullReset &&
04506       aRuleDetail != eRulePartialReset &&
04507       aRuleDetail != eRuleNone)
04508     parentXUL = parentContext->GetStyleXUL();
04509 
04510   PRBool inherited = aInherited;
04511 
04512   // box-align: enum, inherit
04513   if (eCSSUnit_Enumerated == xulData.mBoxAlign.GetUnit()) {
04514     xul->mBoxAlign = xulData.mBoxAlign.GetIntValue();
04515   }
04516   else if (eCSSUnit_Inherit == xulData.mBoxAlign.GetUnit()) {
04517     inherited = PR_TRUE;
04518     xul->mBoxAlign = parentXUL->mBoxAlign;
04519   }
04520 
04521   // box-direction: enum, inherit
04522   if (eCSSUnit_Enumerated == xulData.mBoxDirection.GetUnit()) {
04523     xul->mBoxDirection = xulData.mBoxDirection.GetIntValue();
04524   }
04525   else if (eCSSUnit_Inherit == xulData.mBoxDirection.GetUnit()) {
04526     inherited = PR_TRUE;
04527     xul->mBoxDirection = parentXUL->mBoxDirection;
04528   }
04529 
04530   // box-flex: factor, inherit
04531   if (eCSSUnit_Number == xulData.mBoxFlex.GetUnit()) {
04532     xul->mBoxFlex = xulData.mBoxFlex.GetFloatValue();
04533   }
04534   else if (eCSSUnit_Inherit == xulData.mBoxOrient.GetUnit()) {
04535     inherited = PR_TRUE;
04536     xul->mBoxFlex = parentXUL->mBoxFlex;
04537   }
04538 
04539   // box-orient: enum, inherit
04540   if (eCSSUnit_Enumerated == xulData.mBoxOrient.GetUnit()) {
04541     xul->mBoxOrient = xulData.mBoxOrient.GetIntValue();
04542   }
04543   else if (eCSSUnit_Inherit == xulData.mBoxOrient.GetUnit()) {
04544     inherited = PR_TRUE;
04545     xul->mBoxOrient = parentXUL->mBoxOrient;
04546   }
04547 
04548   // box-pack: enum, inherit
04549   if (eCSSUnit_Enumerated == xulData.mBoxPack.GetUnit()) {
04550     xul->mBoxPack = xulData.mBoxPack.GetIntValue();
04551   }
04552   else if (eCSSUnit_Inherit == xulData.mBoxPack.GetUnit()) {
04553     inherited = PR_TRUE;
04554     xul->mBoxPack = parentXUL->mBoxPack;
04555   }
04556 
04557   // box-ordinal-group: integer
04558   if (eCSSUnit_Integer == xulData.mBoxOrdinal.GetUnit()) {
04559     xul->mBoxOrdinal = xulData.mBoxOrdinal.GetIntValue();
04560   }
04561 
04562   if (inherited)
04563     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
04564     // style context.
04565     aContext->SetStyle(eStyleStruct_XUL, xul);
04566   else {
04567     // We were fully specified and can therefore be cached right on the rule node.
04568     if (!aHighestNode->mStyleData.mResetData) {
04569       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
04570       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
04571         xul->Destroy(mPresContext);
04572         return nsnull;
04573       }
04574     }
04575     aHighestNode->mStyleData.mResetData->mXULData = xul;
04576     // Propagate the bit down.
04577     PropagateDependentBit(NS_STYLE_INHERIT_BIT(XUL), aHighestNode);
04578   }
04579 
04580   return xul;
04581 }
04582 
04583 const nsStyleStruct* 
04584 nsRuleNode::ComputeColumnData(nsStyleStruct* aStartStruct,
04585                               const nsRuleDataStruct& aData, 
04586                               nsStyleContext* aContext, 
04587                               nsRuleNode* aHighestNode,
04588                               const RuleDetail& aRuleDetail, PRBool aInherited)
04589 {
04590   nsStyleContext* parentContext = aContext->GetParent();
04591 
04592   const nsRuleDataColumn& columnData = NS_STATIC_CAST(const nsRuleDataColumn&, aData);
04593   nsStyleColumn* column = nsnull;
04594   
04595   if (aStartStruct)
04596     // We only need to compute the delta between this computed data and our
04597     // computed data.
04598     column = new (mPresContext) nsStyleColumn(*NS_STATIC_CAST(nsStyleColumn*, aStartStruct));
04599   else
04600     column = new (mPresContext) nsStyleColumn();
04601 
04602   if (NS_UNLIKELY(!column))
04603     return nsnull;  // Out Of Memory
04604 
04605   const nsStyleColumn* parent = column;
04606   if (parentContext && 
04607       aRuleDetail != eRuleFullReset &&
04608       aRuleDetail != eRulePartialReset &&
04609       aRuleDetail != eRuleNone)
04610     parent = parentContext->GetStyleColumn();
04611 
04612   PRBool inherited = aInherited;
04613 
04614   // column-width: length, auto, inherit
04615   SetCoord(columnData.mColumnWidth,
04616            column->mColumnWidth, parent->mColumnWidth, SETCOORD_LAH,
04617            aContext, mPresContext, inherited);
04618 
04619   // column-gap: length, percentage, inherit
04620   SetCoord(columnData.mColumnGap,
04621            column->mColumnGap, parent->mColumnGap, SETCOORD_LPH,
04622            aContext, mPresContext, inherited);
04623 
04624   // column-count: auto, integer, inherit
04625   if (eCSSUnit_Auto == columnData.mColumnCount.GetUnit()) {
04626     column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
04627   } else if (eCSSUnit_Integer == columnData.mColumnCount.GetUnit()) {
04628     column->mColumnCount = columnData.mColumnCount.GetIntValue();
04629     // Max 1000 columns - wallpaper for bug 345583.
04630     column->mColumnCount = PR_MIN(column->mColumnCount, 1000);
04631   } else if (eCSSUnit_Inherit == columnData.mColumnCount.GetUnit()) {
04632     inherited = PR_TRUE;
04633     column->mColumnCount = parent->mColumnCount;
04634   }
04635 
04636   if (inherited)
04637     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
04638     // style context.
04639     aContext->SetStyle(eStyleStruct_Column, column);
04640   else {
04641     // We were fully specified and can therefore be cached right on the rule node.
04642     if (!aHighestNode->mStyleData.mResetData) {
04643       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
04644       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
04645         column->Destroy(mPresContext);
04646         return nsnull;
04647       }
04648     }
04649     aHighestNode->mStyleData.mResetData->mColumnData = column;
04650     // Propagate the bit down.
04651     PropagateDependentBit(NS_STYLE_INHERIT_BIT(Column), aHighestNode);
04652   }
04653 
04654   return column;
04655 }
04656 
04657 #ifdef MOZ_SVG
04658 static void
04659 SetSVGPaint(const nsCSSValue& aValue, const nsStyleSVGPaint& parentPaint,
04660             nsPresContext* aPresContext, nsStyleContext *aContext, 
04661             nsStyleSVGPaint& aResult, PRBool& aInherited)
04662 {
04663   if (aValue.GetUnit() == eCSSUnit_Inherit) {
04664     aResult = parentPaint;
04665     aInherited = PR_TRUE;
04666   } else if (aValue.GetUnit() == eCSSUnit_None) {
04667     aResult.mType = eStyleSVGPaintType_None;
04668   } else if (aValue.GetUnit() == eCSSUnit_URL) {
04669     aResult.mType = eStyleSVGPaintType_Server;
04670     aResult.mPaint.mPaintServer = aValue.GetURLValue();
04671     NS_IF_ADDREF(aResult.mPaint.mPaintServer);
04672   } else if (SetColor(aValue, parentPaint.mPaint.mColor, aPresContext, aContext, aResult.mPaint.mColor, aInherited)) {
04673     aResult.mType = eStyleSVGPaintType_Color;
04674   }
04675 }
04676 
04677 static void
04678 SetSVGOpacity(const nsCSSValue& aValue, float parentOpacity, float& opacity, PRBool& aInherited)
04679 {
04680   if (aValue.GetUnit() == eCSSUnit_Inherit) {
04681     opacity = parentOpacity;
04682     aInherited = PR_TRUE;
04683   }
04684   else if (aValue.GetUnit() == eCSSUnit_Number) {
04685     opacity = aValue.GetFloatValue();
04686     opacity = PR_MAX(opacity, 0.0f);
04687     opacity = PR_MIN(opacity, 1.0f);
04688   }
04689 }
04690 
04691 const nsStyleStruct* 
04692 nsRuleNode::ComputeSVGData(nsStyleStruct* aStartStruct,
04693                            const nsRuleDataStruct& aData, 
04694                            nsStyleContext* aContext, 
04695                            nsRuleNode* aHighestNode,
04696                            const RuleDetail& aRuleDetail, PRBool aInherited)
04697 {
04698   nsStyleContext* parentContext = aContext->GetParent();
04699 
04700   const nsRuleDataSVG& SVGData = NS_STATIC_CAST(const nsRuleDataSVG&, aData);
04701   nsStyleSVG* svg = nsnull;
04702   const nsStyleSVG* parentSVG = nsnull;
04703   PRBool inherited = aInherited;
04704 
04705   if (parentContext && aRuleDetail != eRuleFullReset)
04706     parentSVG = parentContext->GetStyleSVG();
04707   if (aStartStruct)
04708     // We only need to compute the delta between this computed data and our
04709     // computed data.
04710     svg = new (mPresContext) nsStyleSVG(*NS_STATIC_CAST(nsStyleSVG*, aStartStruct));
04711   else {
04712     // XXXldb What about eRuleFullInherited?  Which path is faster?
04713     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {
04714       // No question. We will have to inherit. Go ahead and init
04715       // with inherited vals from parent.
04716       inherited = PR_TRUE;
04717       if (parentSVG)
04718         svg = new (mPresContext) nsStyleSVG(*parentSVG);
04719       else
04720         svg = new (mPresContext) nsStyleSVG();
04721     }
04722     else
04723       svg = new (mPresContext) nsStyleSVG();
04724   }
04725 
04726   if (NS_UNLIKELY(!svg))
04727     return nsnull;  // Out Of Memory
04728   if (!parentSVG)
04729     parentSVG = svg;
04730 
04731   // clip-rule: enum, inherit
04732   if (eCSSUnit_Enumerated == SVGData.mClipRule.GetUnit()) {
04733     svg->mClipRule = SVGData.mClipRule.GetIntValue();
04734   }
04735   else if (eCSSUnit_Inherit == SVGData.mClipRule.GetUnit()) {
04736     inherited = PR_TRUE;
04737     svg->mClipRule = parentSVG->mClipRule;
04738   }
04739 
04740   // fill: 
04741   SetSVGPaint(SVGData.mFill, parentSVG->mFill, mPresContext, aContext, svg->mFill, inherited);
04742 
04743   // fill-opacity:
04744   SetSVGOpacity(SVGData.mFillOpacity, parentSVG->mFillOpacity, svg->mFillOpacity, inherited);
04745 
04746   // fill-rule: enum, inherit
04747   if (eCSSUnit_Enumerated == SVGData.mFillRule.GetUnit()) {
04748     svg->mFillRule = SVGData.mFillRule.GetIntValue();
04749   }
04750   else if (eCSSUnit_Inherit == SVGData.mFillRule.GetUnit()) {
04751     inherited = PR_TRUE;
04752     svg->mFillRule = parentSVG->mFillRule;
04753   }
04754   
04755   // marker-end: url, none, inherit
04756   if (eCSSUnit_URL == SVGData.mMarkerEnd.GetUnit()) {
04757     svg->mMarkerEnd = SVGData.mMarkerEnd.GetURLValue();
04758   } else if (eCSSUnit_None == SVGData.mMarkerEnd.GetUnit()) {
04759     svg->mMarkerEnd = nsnull;
04760   } else if (eCSSUnit_Inherit == SVGData.mMarkerEnd.GetUnit()) {
04761     inherited = PR_TRUE;
04762     svg->mMarkerEnd = parentSVG->mMarkerEnd;
04763   }
04764 
04765   // marker-mid: url, none, inherit
04766   if (eCSSUnit_URL == SVGData.mMarkerMid.GetUnit()) {
04767     svg->mMarkerMid = SVGData.mMarkerMid.GetURLValue();
04768   } else if (eCSSUnit_None == SVGData.mMarkerMid.GetUnit()) {
04769     svg->mMarkerMid = nsnull;
04770   } else if (eCSSUnit_Inherit == SVGData.mMarkerMid.GetUnit()) {
04771     inherited = PR_TRUE;
04772     svg->mMarkerMid = parentSVG->mMarkerMid;
04773   }
04774 
04775   // marker-start: url, none, inherit
04776   if (eCSSUnit_URL == SVGData.mMarkerStart.GetUnit()) {
04777     svg->mMarkerStart = SVGData.mMarkerStart.GetURLValue();
04778   } else if (eCSSUnit_None == SVGData.mMarkerStart.GetUnit()) {
04779     svg->mMarkerStart = nsnull;
04780   } else if (eCSSUnit_Inherit == SVGData.mMarkerStart.GetUnit()) {
04781     inherited = PR_TRUE;
04782     svg->mMarkerStart = parentSVG->mMarkerStart;
04783   }
04784 
04785   // pointer-events: enum, inherit
04786   if (eCSSUnit_Enumerated == SVGData.mPointerEvents.GetUnit()) {
04787     svg->mPointerEvents = SVGData.mPointerEvents.GetIntValue();
04788   } else if (eCSSUnit_None == SVGData.mPointerEvents.GetUnit()) {
04789     svg->mPointerEvents = NS_STYLE_POINTER_EVENTS_NONE;
04790   } else if (eCSSUnit_Inherit == SVGData.mPointerEvents.GetUnit()) {
04791     inherited = PR_TRUE;
04792     svg->mPointerEvents = parentSVG->mPointerEvents;
04793   }
04794 
04795   // shape-rendering: enum, auto, inherit
04796   if (eCSSUnit_Enumerated == SVGData.mShapeRendering.GetUnit()) {
04797     svg->mShapeRendering = SVGData.mShapeRendering.GetIntValue();
04798   }
04799   else if (eCSSUnit_Auto == SVGData.mShapeRendering.GetUnit()) {
04800     svg->mShapeRendering = NS_STYLE_SHAPE_RENDERING_AUTO;
04801   }
04802   else if (eCSSUnit_Inherit == SVGData.mShapeRendering.GetUnit()) {
04803     inherited = PR_TRUE;
04804     svg->mShapeRendering = parentSVG->mShapeRendering;
04805   }
04806 
04807   // stroke: 
04808   SetSVGPaint(SVGData.mStroke, parentSVG->mStroke, mPresContext, aContext, svg->mStroke, inherited);
04809 
04810   // stroke-dasharray: <dasharray>, none, inherit
04811   nsCSSValueList *list = SVGData.mStrokeDasharray;
04812   if (list) {
04813     if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
04814       // only do the copy if weren't already set up by the copy constructor
04815       if (!svg->mStrokeDasharray) {
04816         inherited = PR_TRUE;
04817         svg->mStrokeDasharrayLength = parentSVG->mStrokeDasharrayLength;
04818         if (svg->mStrokeDasharrayLength) {
04819           svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
04820           if (svg->mStrokeDasharray)
04821             memcpy(svg->mStrokeDasharray,
04822                    parentSVG->mStrokeDasharray,
04823                    svg->mStrokeDasharrayLength * sizeof(float));
04824           else
04825             svg->mStrokeDasharrayLength = 0;
04826         }
04827       }
04828     } else {
04829       delete [] svg->mStrokeDasharray;
04830       svg->mStrokeDasharray = nsnull;
04831       svg->mStrokeDasharrayLength = 0;
04832       
04833       if (eCSSUnit_Initial != list->mValue.GetUnit() &&
04834           eCSSUnit_None    != list->mValue.GetUnit()) {
04835         // count number of values
04836         nsCSSValueList *value = SVGData.mStrokeDasharray;
04837         while (nsnull != value) {
04838           ++svg->mStrokeDasharrayLength;
04839           value = value->mNext;
04840         }
04841         
04842         NS_ASSERTION(svg->mStrokeDasharrayLength != 0, "no dasharray items");
04843         
04844         svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
04845 
04846         if (svg->mStrokeDasharray) {
04847           value = SVGData.mStrokeDasharray;
04848           PRUint32 i = 0;
04849           while (nsnull != value) {
04850             SetCoord(value->mValue,
04851                      svg->mStrokeDasharray[i++], nsnull,
04852                      SETCOORD_LP | SETCOORD_FACTOR,
04853                      aContext, mPresContext, inherited);
04854             value = value->mNext;
04855           }
04856         } else
04857           svg->mStrokeDasharrayLength = 0;
04858       }
04859     }
04860   }
04861 
04862   // stroke-dashoffset: <dashoffset>, inherit
04863   SetCoord(SVGData.mStrokeDashoffset,
04864            svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
04865            SETCOORD_LPH | SETCOORD_FACTOR,
04866            aContext, mPresContext, inherited);
04867 
04868   // stroke-linecap: enum, inherit
04869   if (eCSSUnit_Enumerated == SVGData.mStrokeLinecap.GetUnit()) {
04870     svg->mStrokeLinecap = SVGData.mStrokeLinecap.GetIntValue();
04871   }
04872   else if (eCSSUnit_Inherit == SVGData.mStrokeLinecap.GetUnit()) {
04873     inherited = PR_TRUE;
04874     svg->mStrokeLinecap = parentSVG->mStrokeLinecap;
04875   }
04876 
04877   // stroke-linejoin: enum, inherit
04878   if (eCSSUnit_Enumerated == SVGData.mStrokeLinejoin.GetUnit()) {
04879     svg->mStrokeLinejoin = SVGData.mStrokeLinejoin.GetIntValue();
04880   }
04881   else if (eCSSUnit_Inherit == SVGData.mStrokeLinejoin.GetUnit()) {
04882     inherited = PR_TRUE;
04883     svg->mStrokeLinejoin = parentSVG->mStrokeLinejoin;
04884   }
04885 
04886   // stroke-miterlimit: <miterlimit>, inherit
04887   if (eCSSUnit_Number == SVGData.mStrokeMiterlimit.GetUnit()) {
04888     svg->mStrokeMiterlimit = SVGData.mStrokeMiterlimit.GetFloatValue();
04889   }
04890   else if (eCSSUnit_Inherit == SVGData.mStrokeMiterlimit.GetUnit()) {
04891     svg->mStrokeMiterlimit = parentSVG->mStrokeMiterlimit;
04892     inherited = PR_TRUE;
04893   }
04894 
04895   // stroke-opacity:
04896   SetSVGOpacity(SVGData.mStrokeOpacity, parentSVG->mStrokeOpacity, svg->mStrokeOpacity, inherited);  
04897 
04898   // stroke-width:
04899   SetCoord(SVGData.mStrokeWidth,
04900            svg->mStrokeWidth, parentSVG->mStrokeWidth,
04901            SETCOORD_LPH | SETCOORD_FACTOR,
04902            aContext, mPresContext, inherited);
04903 
04904   // text-anchor: enum, inherit
04905   if (eCSSUnit_Enumerated == SVGData.mTextAnchor.GetUnit()) {
04906     svg->mTextAnchor = SVGData.mTextAnchor.GetIntValue();
04907   }
04908   else if (eCSSUnit_Inherit == SVGData.mTextAnchor.GetUnit()) {
04909     inherited = PR_TRUE;
04910     svg->mTextAnchor = parentSVG->mTextAnchor;
04911   }
04912   
04913   // text-rendering: enum, auto, inherit
04914   if (eCSSUnit_Enumerated == SVGData.mTextRendering.GetUnit()) {
04915     svg->mTextRendering = SVGData.mTextRendering.GetIntValue();
04916   }
04917   else if (eCSSUnit_Auto == SVGData.mTextRendering.GetUnit()) {
04918     svg->mTextRendering = NS_STYLE_TEXT_RENDERING_AUTO;
04919   }
04920   else if (eCSSUnit_Inherit == SVGData.mTextRendering.GetUnit()) {
04921     inherited = PR_TRUE;
04922     svg->mTextRendering = parentSVG->mTextRendering;
04923   }
04924 
04925   if (inherited)
04926     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
04927     // style context.
04928     aContext->SetStyle(eStyleStruct_SVG, svg);
04929   else {
04930     // We were fully specified and can therefore be cached right on the rule node.
04931     if (!aHighestNode->mStyleData.mInheritedData) {
04932       aHighestNode->mStyleData.mInheritedData = new (mPresContext) nsInheritedStyleData;
04933       if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) {
04934         svg->Destroy(mPresContext);
04935         return nsnull;
04936       }
04937     }
04938     aHighestNode->mStyleData.mInheritedData->mSVGData = svg;
04939     // Propagate the bit down.
04940     PropagateDependentBit(NS_STYLE_INHERIT_BIT(SVG), aHighestNode);
04941   }
04942 
04943   return svg;
04944 }
04945 
04946 const nsStyleStruct* 
04947 nsRuleNode::ComputeSVGResetData(nsStyleStruct* aStartStruct,
04948                                 const nsRuleDataStruct& aData,
04949                                 nsStyleContext* aContext, 
04950                                 nsRuleNode* aHighestNode,
04951                                 const RuleDetail& aRuleDetail, PRBool aInherited)
04952 {
04953   nsStyleContext* parentContext = aContext->GetParent();
04954 
04955   const nsRuleDataSVG& SVGData = NS_STATIC_CAST(const nsRuleDataSVG&, aData);
04956   nsStyleSVGReset* svgReset;
04957 
04958   if (aStartStruct)
04959     // We only need to compute the delta between this computed data and our
04960     // computed data.
04961     svgReset = new (mPresContext) nsStyleSVGReset(*NS_STATIC_CAST(nsStyleSVGReset*,aStartStruct));
04962   else 
04963     svgReset = new (mPresContext) nsStyleSVGReset();
04964 
04965   if (NS_UNLIKELY(!svgReset)) {
04966     return nsnull;  // Out Of Memory
04967   }
04968 
04969   const nsStyleSVGReset* parentSVGReset = svgReset;
04970   if (parentContext && 
04971       aRuleDetail != eRuleFullReset &&
04972       aRuleDetail != eRulePartialReset &&
04973       aRuleDetail != eRuleNone)
04974     parentSVGReset = parentContext->GetStyleSVGReset();
04975 
04976   PRBool inherited = aInherited;
04977 
04978   // stop-color: 
04979   SetSVGPaint(SVGData.mStopColor, parentSVGReset->mStopColor,
04980               mPresContext, aContext, svgReset->mStopColor, inherited);
04981 
04982   // clip-path: url, none, inherit
04983   if (eCSSUnit_URL == SVGData.mClipPath.GetUnit()) {
04984     svgReset->mClipPath = SVGData.mClipPath.GetURLValue();
04985   } else if (eCSSUnit_None == SVGData.mClipPath.GetUnit()) {
04986     svgReset->mClipPath = nsnull;
04987   } else if (eCSSUnit_Inherit == SVGData.mClipPath.GetUnit()) {
04988     inherited = PR_TRUE;
04989     svgReset->mClipPath = parentSVGReset->mClipPath;
04990   }
04991 
04992   // stop-opacity:
04993   SetSVGOpacity(SVGData.mStopOpacity, parentSVGReset->mStopOpacity,
04994                 svgReset->mStopOpacity, inherited);
04995 
04996   // dominant-baseline: enum, auto, inherit
04997   if (eCSSUnit_Enumerated == SVGData.mDominantBaseline.GetUnit()) {
04998     svgReset->mDominantBaseline = SVGData.mDominantBaseline.GetIntValue();
04999   }
05000   else if (eCSSUnit_Auto == SVGData.mDominantBaseline.GetUnit()) {
05001     svgReset->mDominantBaseline = NS_STYLE_DOMINANT_BASELINE_AUTO;
05002   }
05003   else if (eCSSUnit_Inherit == SVGData.mDominantBaseline.GetUnit()) {
05004     inherited = PR_TRUE;
05005     svgReset->mDominantBaseline = parentSVGReset->mDominantBaseline;
05006   }
05007 
05008   
05009   if (inherited)
05010     // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
05011     // style context.
05012     aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
05013   else {
05014     // We were fully specified and can therefore be cached right on the rule node.
05015     if (!aHighestNode->mStyleData.mResetData) {
05016       aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData;
05017       if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) {
05018         svgReset->Destroy(mPresContext);
05019         return nsnull;
05020       }
05021     }
05022     aHighestNode->mStyleData.mResetData->mSVGResetData = svgReset;
05023     // Propagate the bit down.
05024     PropagateDependentBit(NS_STYLE_INHERIT_BIT(SVGReset), aHighestNode);
05025   }
05026 
05027   return svgReset;
05028 }
05029 #endif
05030 
05031 inline const nsStyleStruct* 
05032 nsRuleNode::GetParentData(const nsStyleStructID aSID)
05033 {
05034   NS_PRECONDITION(mDependentBits & nsCachedStyleData::GetBitForSID(aSID),
05035                   "should be called when node depends on parent data");
05036   NS_ASSERTION(mStyleData.GetStyleData(aSID) == nsnull,
05037                "both struct and dependent bits present");
05038   // Walk up the rule tree from this rule node (towards less specific
05039   // rules).
05040   PRUint32 bit = nsCachedStyleData::GetBitForSID(aSID);
05041   nsRuleNode *ruleNode = mParent;
05042   while (ruleNode->mDependentBits & bit) {
05043     NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nsnull,
05044                  "both struct and dependent bits present");
05045     ruleNode = ruleNode->mParent;
05046   }
05047 
05048   return ruleNode->mStyleData.GetStyleData(aSID);
05049 }
05050 
05051 const nsStyleStruct* 
05052 nsRuleNode::GetStyleData(nsStyleStructID aSID, 
05053                          nsStyleContext* aContext,
05054                          PRBool aComputeData)
05055 {
05056   const nsStyleStruct *data;
05057   if (mDependentBits & nsCachedStyleData::GetBitForSID(aSID)) {
05058     // We depend on an ancestor for this struct since the cached struct
05059     // it has is also appropriate for this rule node.  Just go up the
05060     // rule tree and return the first cached struct we find.
05061     data = GetParentData(aSID);
05062     NS_ASSERTION(data, "dependent bits set but no cached struct present");
05063     return data;
05064   }
05065 
05066   data = mStyleData.GetStyleData(aSID);
05067   if (NS_LIKELY(data != nsnull))
05068     return data; // We have a fully specified struct. Just return it.
05069 
05070   if (NS_UNLIKELY(!aComputeData))
05071     return nsnull;
05072 
05073   // Nothing is cached.  We'll have to delve further and examine our rules.
05074 #define STYLE_STRUCT_TEST aSID
05075 #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
05076   data = Get##name##Data(aContext);
05077 #include "nsStyleStructList.h"
05078 #undef STYLE_STRUCT
05079 #undef STYLE_STRUCT_TEST
05080 
05081   if (NS_LIKELY(data != nsnull))
05082     return data;
05083 
05084   NS_NOTREACHED("could not create style struct");
05085   // To ensure that |GetStyleData| never returns null (even when we're
05086   // out of memory), we'll get the style set and get a copy of the
05087   // default values for the given style struct from the set.  Note that
05088   // this works fine even if |this| is a rule node that has been
05089   // destroyed (leftover from a previous rule tree) but is somehow still
05090   // used.
05091   return mPresContext->PresShell()->StyleSet()->
05092     DefaultStyleData()->GetStyleData(aSID);
05093 }
05094 
05095 void
05096 nsRuleNode::Mark()
05097 {
05098   for (nsRuleNode *node = this;
05099        node && !(node->mDependentBits & NS_RULE_NODE_GC_MARK);
05100        node = node->mParent)
05101     node->mDependentBits |= NS_RULE_NODE_GC_MARK;
05102 }
05103 
05104 PR_STATIC_CALLBACK(PLDHashOperator)
05105 SweepRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
05106                       PRUint32 number, void *arg)
05107 {
05108   ChildrenHashEntry *entry = NS_STATIC_CAST(ChildrenHashEntry*, hdr);
05109   if (entry->mRuleNode->Sweep())
05110     return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
05111   return PL_DHASH_NEXT;
05112 }
05113 
05114 PRBool
05115 nsRuleNode::Sweep()
05116 {
05117   // If we're not marked, then we have to delete ourself.
05118   // However, we never allow the root node to GC itself, because nsStyleSet
05119   // wants to hold onto the root node and not worry about re-creating a
05120   // rule walker if the root node is deleted.
05121   if (!(mDependentBits & NS_RULE_NODE_GC_MARK) && !IsRoot()) {
05122     Destroy();
05123     return PR_TRUE;
05124   }
05125 
05126   // Clear our mark, for the next time around.
05127   mDependentBits &= ~NS_RULE_NODE_GC_MARK;
05128 
05129   // Call sweep on the children, since some may not be marked, and
05130   // remove any deleted children from the child lists.
05131   if (HaveChildren()) {
05132     if (ChildrenAreHashed()) {
05133       PLDHashTable *children = ChildrenHash();
05134       PL_DHashTableEnumerate(children, SweepRuleNodeChildren, nsnull);
05135     } else {
05136       for (nsRuleList **children = ChildrenListPtr(); *children; ) {
05137         if ((*children)->mRuleNode->Sweep()) {
05138           // This rule node was destroyed, so remove this entry, and
05139           // implicitly advance by making *children point to the next
05140           // entry.
05141           *children = (*children)->DestroySelf(mPresContext);
05142         } else {
05143           // Advance.
05144           children = &(*children)->mNext;
05145         }
05146       }
05147     }
05148   }
05149   return PR_FALSE;
05150 }