Back to index

lightning-sunbird  0.9+nobinonly
nsStyleContext.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.org 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  *   David Hyatt <hyatt@netscape.com>
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039  
00040 #include "nsStyleConsts.h"
00041 #include "nsString.h"
00042 #include "nsPresContext.h"
00043 #include "nsIStyleRule.h"
00044 #include "nsCRT.h"
00045 
00046 #include "nsCOMPtr.h"
00047 #include "nsStyleSet.h"
00048 #include "nsIPresShell.h"
00049 #include "nsLayoutAtoms.h"
00050 #include "prenv.h"
00051 
00052 #include "nsRuleNode.h"
00053 #include "nsUnitConversion.h"
00054 #include "nsStyleContext.h"
00055 #include "imgIRequest.h"
00056 
00057 #include "nsPrintfCString.h"
00058 
00059 #ifdef DEBUG
00060 // #define NOISY_DEBUG
00061 #endif
00062 
00063 //----------------------------------------------------------------------
00064 
00065 
00066 nsStyleContext::nsStyleContext(nsStyleContext* aParent,
00067                                nsIAtom* aPseudoTag,
00068                                nsRuleNode* aRuleNode,
00069                                nsPresContext* aPresContext)
00070   : mParent(aParent),
00071     mChild(nsnull),
00072     mEmptyChild(nsnull),
00073     mPseudoTag(aPseudoTag),
00074     mRuleNode(aRuleNode),
00075     mBits(0),
00076     mRefCnt(0)
00077 {
00078   mNextSibling = this;
00079   mPrevSibling = this;
00080   if (mParent) {
00081     mParent->AddRef();
00082     mParent->AppendChild(this);
00083   }
00084 
00085   ApplyStyleFixups(aPresContext);
00086 
00087   NS_ASSERTION(NS_STYLE_INHERIT_MASK &
00088                (1 << PRInt32(nsStyleStructID_Length - 1)) != 0,
00089                "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
00090 }
00091 
00092 nsStyleContext::~nsStyleContext()
00093 {
00094   NS_ASSERTION((nsnull == mChild) && (nsnull == mEmptyChild), "destructing context with children");
00095 
00096   nsPresContext *presContext = mRuleNode->GetPresContext();
00097 
00098   presContext->PresShell()->StyleSet()->
00099     NotifyStyleContextDestroyed(presContext, this);
00100 
00101   if (mParent) {
00102     mParent->RemoveChild(this);
00103     mParent->Release();
00104   }
00105 
00106   // Free up our data structs.
00107   if (mCachedStyleData.mResetData || mCachedStyleData.mInheritedData) {
00108     mCachedStyleData.Destroy(mBits, presContext);
00109   }
00110 }
00111 
00112 void nsStyleContext::AppendChild(nsStyleContext* aChild)
00113 {
00114   if (aChild->mRuleNode->IsRoot()) {
00115     // The child matched no rules.
00116     if (!mEmptyChild) {
00117       mEmptyChild = aChild;
00118     }
00119     else {
00120       aChild->mNextSibling = mEmptyChild;
00121       aChild->mPrevSibling = mEmptyChild->mPrevSibling;
00122       mEmptyChild->mPrevSibling->mNextSibling = aChild;
00123       mEmptyChild->mPrevSibling = aChild;
00124     }
00125   }
00126   else {
00127     if (!mChild) {
00128       mChild = aChild;
00129     }
00130     else {
00131       aChild->mNextSibling = mChild;
00132       aChild->mPrevSibling = mChild->mPrevSibling;
00133       mChild->mPrevSibling->mNextSibling = aChild;
00134       mChild->mPrevSibling = aChild;
00135     }
00136   }
00137 }
00138 
00139 void nsStyleContext::RemoveChild(nsStyleContext* aChild)
00140 {
00141   NS_PRECONDITION(nsnull != aChild && this == aChild->mParent, "bad argument");
00142 
00143   if (aChild->mRuleNode->IsRoot()) { // is empty 
00144     if (aChild->mPrevSibling != aChild) { // has siblings
00145       if (mEmptyChild == aChild) {
00146         mEmptyChild = mEmptyChild->mNextSibling;
00147       }
00148     } 
00149     else {
00150       NS_ASSERTION(mEmptyChild == aChild, "bad sibling pointers");
00151       mEmptyChild = nsnull;
00152     }
00153   }
00154   else {  // isn't empty
00155     if (aChild->mPrevSibling != aChild) { // has siblings
00156       if (mChild == aChild) {
00157         mChild = mChild->mNextSibling;
00158       }
00159     }
00160     else {
00161       NS_ASSERTION(mChild == aChild, "bad sibling pointers");
00162       if (mChild == aChild) {
00163         mChild = nsnull;
00164       }
00165     }
00166   }
00167   aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
00168   aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
00169   aChild->mNextSibling = aChild;
00170   aChild->mPrevSibling = aChild;
00171 }
00172 
00173 already_AddRefed<nsStyleContext>
00174 nsStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag, 
00175                                    nsRuleNode* aRuleNode)
00176 {
00177   PRUint32 threshold = 10; // The # of siblings we're willing to examine
00178                            // before just giving this whole thing up.
00179 
00180   nsStyleContext* aResult = nsnull;
00181 
00182   if ((nsnull != mChild) || (nsnull != mEmptyChild)) {
00183     nsStyleContext* child;
00184     if (aRuleNode->IsRoot()) {
00185       if (nsnull != mEmptyChild) {
00186         child = mEmptyChild;
00187         do {
00188           if (aPseudoTag == child->mPseudoTag) {
00189             aResult = child;
00190             break;
00191           }
00192           child = child->mNextSibling;
00193           threshold--;
00194           if (threshold == 0)
00195             break;
00196         } while (child != mEmptyChild);
00197       }
00198     }
00199     else if (nsnull != mChild) {
00200       child = mChild;
00201       
00202       do {
00203         if (child->mRuleNode == aRuleNode && child->mPseudoTag == aPseudoTag) {
00204           aResult = child;
00205           break;
00206         }
00207         child = child->mNextSibling;
00208         threshold--;
00209         if (threshold == 0)
00210           break;
00211       } while (child != mChild);
00212     }
00213   }
00214 
00215   if (aResult)
00216     aResult->AddRef();
00217 
00218   return aResult;
00219 }
00220 
00221 
00222 PRBool nsStyleContext::Equals(const nsStyleContext* aOther) const
00223 {
00224   PRBool  result = PR_TRUE;
00225   const nsStyleContext* other = (nsStyleContext*)aOther;
00226 
00227   if (other != this) {
00228     if (mParent != other->mParent) {
00229       result = PR_FALSE;
00230     }
00231     else if (mBits != other->mBits) {
00232       result = PR_FALSE;
00233     }
00234     else if (mPseudoTag != other->mPseudoTag) {
00235       result = PR_FALSE;
00236     }
00237     else if (mRuleNode != other->mRuleNode) {
00238       result = PR_FALSE;
00239     }
00240   }
00241   return result;
00242 }
00243 
00244 //=========================================================================================================
00245 
00246 const nsStyleStruct* nsStyleContext::GetStyleData(nsStyleStructID aSID)
00247 {
00248   const nsStyleStruct* cachedData = mCachedStyleData.GetStyleData(aSID); 
00249   if (cachedData)
00250     return cachedData; // We have computed data stored on this node in the context tree.
00251   return mRuleNode->GetStyleData(aSID, this, PR_TRUE); // Our rule node will take care of it for us.
00252 }
00253 
00254 inline const nsStyleStruct* nsStyleContext::PeekStyleData(nsStyleStructID aSID)
00255 {
00256   const nsStyleStruct* cachedData = mCachedStyleData.GetStyleData(aSID); 
00257   if (cachedData)
00258     return cachedData; // We have computed data stored on this node in the context tree.
00259   return mRuleNode->GetStyleData(aSID, this, PR_FALSE); // Our rule node will take care of it for us.
00260 }
00261 
00262 void
00263 nsStyleContext::GetBorderPaddingFor(nsStyleBorderPadding& aBorderPadding)
00264 {
00265   nsMargin padding;
00266   if (GetStylePadding()->GetPadding(padding)) {
00267     padding += GetStyleBorder()->GetBorder();
00268     aBorderPadding.SetBorderPadding(padding);
00269   }
00270 }
00271 
00272 // This is an evil evil function, since it forces you to alloc your own separate copy of
00273 // style data!  Do not use this function unless you absolutely have to!  You should avoid
00274 // this at all costs! -dwh
00275 nsStyleStruct* 
00276 nsStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID)
00277 {
00278   // If we already own the struct and no kids could depend on it, then
00279   // just return it.  (We leak in this case if there are kids -- and this
00280   // function really shouldn't be called for style contexts that could
00281   // have kids depending on the data.  ClearStyleData would be OK, but
00282   // this test for no mChild or mEmptyChild doesn't catch that case.)
00283   const nsStyleStruct *current = GetStyleData(aSID);
00284   if (!mChild && !mEmptyChild &&
00285       !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
00286       mCachedStyleData.GetStyleData(aSID))
00287     return NS_CONST_CAST(nsStyleStruct*, current);
00288 
00289   nsStyleStruct* result;
00290   nsPresContext *presContext = PresContext();
00291   switch (aSID) {
00292 
00293 #define UNIQUE_CASE(c_)                                                       \
00294   case eStyleStruct_##c_:                                                     \
00295     result = new (presContext) nsStyle##c_(                                   \
00296       * NS_STATIC_CAST(const nsStyle##c_ *, current));                        \
00297     break;
00298 
00299   UNIQUE_CASE(Display)
00300   UNIQUE_CASE(Background)
00301   UNIQUE_CASE(Text)
00302   UNIQUE_CASE(TextReset)
00303 
00304 #undef UNIQUE_CASE
00305 
00306   default:
00307     NS_ERROR("Struct type not supported.  Please find another way to do this if you can!\n");
00308     return nsnull;
00309   }
00310 
00311   if (!result) {
00312     NS_WARNING("Ran out of memory while trying to allocate memory for a unique nsStyleStruct! "
00313                "Returning the non-unique data.");
00314     return NS_CONST_CAST(nsStyleStruct*, current);
00315   }
00316 
00317   SetStyle(aSID, result);
00318   mBits &= ~nsCachedStyleData::GetBitForSID(aSID);
00319 
00320   return result;
00321 }
00322 
00323 void
00324 nsStyleContext::SetStyle(nsStyleStructID aSID, nsStyleStruct* aStruct)
00325 {
00326   // This method should only be called from nsRuleNode!  It is not a public
00327   // method!
00328   
00329   NS_ASSERTION(aSID >= 0 && aSID < nsStyleStructID_Length, "out of bounds");
00330 
00331   // NOTE:  nsCachedStyleData::GetStyleData works roughly the same way.
00332   // See the comments there (in nsRuleNode.h) for more details about
00333   // what this is doing and why.
00334 
00335   const nsCachedStyleData::StyleStructInfo& info =
00336       nsCachedStyleData::gInfo[aSID];
00337   char* resetOrInheritSlot = NS_REINTERPRET_CAST(char*, &mCachedStyleData) +
00338                              info.mCachedStyleDataOffset;
00339   char* resetOrInherit = NS_REINTERPRET_CAST(char*,
00340       *NS_REINTERPRET_CAST(void**, resetOrInheritSlot));
00341   if (!resetOrInherit) {
00342     nsPresContext *presContext = mRuleNode->GetPresContext();
00343     if (mCachedStyleData.IsReset(aSID)) {
00344       mCachedStyleData.mResetData = new (presContext) nsResetStyleData;
00345       resetOrInherit = NS_REINTERPRET_CAST(char*, mCachedStyleData.mResetData);
00346     } else {
00347       mCachedStyleData.mInheritedData =
00348           new (presContext) nsInheritedStyleData;
00349       resetOrInherit =
00350           NS_REINTERPRET_CAST(char*, mCachedStyleData.mInheritedData);
00351     }
00352   }
00353   char* dataSlot = resetOrInherit + info.mInheritResetOffset;
00354   *NS_REINTERPRET_CAST(nsStyleStruct**, dataSlot) = aStruct;
00355 }
00356 
00357 void
00358 nsStyleContext::ApplyStyleFixups(nsPresContext* aPresContext)
00359 {
00360   // See if we have any text decorations.
00361   // First see if our parent has text decorations.  If our parent does, then we inherit the bit.
00362   if (mParent && mParent->HasTextDecorations())
00363     mBits |= NS_STYLE_HAS_TEXT_DECORATIONS;
00364   else {
00365     // We might have defined a decoration.
00366     const nsStyleTextReset* text = GetStyleTextReset();
00367     if (text->mTextDecoration != NS_STYLE_TEXT_DECORATION_NONE &&
00368         text->mTextDecoration != NS_STYLE_TEXT_DECORATION_OVERRIDE_ALL)
00369       mBits |= NS_STYLE_HAS_TEXT_DECORATIONS;
00370   }
00371 
00372   // Correct tables.
00373   const nsStyleDisplay* disp = GetStyleDisplay();
00374   if (disp->mDisplay == NS_STYLE_DISPLAY_TABLE) {
00375     // -moz-center and -moz-right are used for HTML's alignment
00376     // This is covering the <div align="right"><table>...</table></div> case.
00377     // In this case, we don't want to inherit the text alignment into the table.
00378     const nsStyleText* text = GetStyleText();
00379     
00380     if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
00381         text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)
00382     {
00383       nsStyleText* uniqueText = (nsStyleText*)GetUniqueStyleData(eStyleStruct_Text);
00384       uniqueText->mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
00385     }
00386   }
00387 
00388   // CSS2.1 section 9.2.4 specifies fixups for the 'display' property of
00389   // the root element.  We can't implement them in nsRuleNode because we
00390   // don't want to store all display structs that aren't 'block',
00391   // 'inline', or 'table' in the style context tree on the off chance
00392   // that the root element has its style reresolved later.  So do them
00393   // here if needed, by changing the style data, so that other code
00394   // doesn't get confused by looking at the style data.
00395   if (!mParent) {
00396     if (disp->mDisplay != NS_STYLE_DISPLAY_NONE &&
00397         disp->mDisplay != NS_STYLE_DISPLAY_BLOCK &&
00398         disp->mDisplay != NS_STYLE_DISPLAY_TABLE) {
00399       nsStyleDisplay *mutable_display = NS_STATIC_CAST(nsStyleDisplay*,
00400         GetUniqueStyleData(eStyleStruct_Display));
00401       if (mutable_display->mDisplay == NS_STYLE_DISPLAY_INLINE_TABLE)
00402         mutable_display->mDisplay = NS_STYLE_DISPLAY_TABLE;
00403       else
00404         mutable_display->mDisplay = NS_STYLE_DISPLAY_BLOCK;
00405     }
00406   }
00407 
00408   // Computer User Interface style, to trigger loads of cursors
00409   GetStyleUserInterface();
00410 }
00411 
00412 void
00413 nsStyleContext::ClearStyleData(nsPresContext* aPresContext)
00414 {
00415   // First we need to clear out all of our style data.
00416   if (mCachedStyleData.mResetData || mCachedStyleData.mInheritedData)
00417     mCachedStyleData.Destroy(mBits, aPresContext);
00418 
00419   mBits = 0; // Clear all bits.
00420 
00421   ApplyStyleFixups(aPresContext);
00422 
00423   if (mChild) {
00424     nsStyleContext* child = mChild;
00425     do {
00426       child->ClearStyleData(aPresContext);
00427       child = child->mNextSibling;
00428     } while (mChild != child);
00429   }
00430   
00431   if (mEmptyChild) {
00432     nsStyleContext* child = mEmptyChild;
00433     do {
00434       child->ClearStyleData(aPresContext);
00435       child = child->mNextSibling;
00436     } while (mEmptyChild != child);
00437   }
00438 }
00439 
00440 nsChangeHint
00441 nsStyleContext::CalcStyleDifference(nsStyleContext* aOther)
00442 {
00443   nsChangeHint hint = NS_STYLE_HINT_NONE;
00444   NS_ENSURE_TRUE(aOther, hint);
00445   // We must always ensure that we populate the structs on the new style
00446   // context that are filled in on the old context, so that if we get
00447   // two style changes in succession, the second of which causes a real
00448   // style change, the PeekStyleData doesn't fail.
00449 
00450   // If our rule nodes are the same, then we are looking at the same
00451   // style data.  We know this because CalcStyleDifference is always
00452   // called on two style contexts that point to the same element, so we
00453   // know that our position in the style context tree is the same and
00454   // our position in the rule node tree is also the same.
00455   PRBool compare = mRuleNode != aOther->mRuleNode;
00456 
00457   nsChangeHint maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
00458       nsChangeHint_UpdateCursor);
00459   
00460 #define DO_STRUCT_DIFFERENCE(struct_)                                         \
00461   PR_BEGIN_MACRO                                                              \
00462     NS_ASSERTION(NS_IsHintSubset(nsStyle##struct_::MaxDifference(), maxHint), \
00463                  "Struct placed in the wrong maxHint section");               \
00464     const nsStyle##struct_* this##struct_ =                                   \
00465         NS_STATIC_CAST(const nsStyle##struct_*,                               \
00466                       PeekStyleData(NS_GET_STYLESTRUCTID(nsStyle##struct_))); \
00467     if (this##struct_) {                                                      \
00468       const nsStyle##struct_* other##struct_ =                                \
00469           NS_STATIC_CAST(const nsStyle##struct_*,                             \
00470                aOther->GetStyleData(NS_GET_STYLESTRUCTID(nsStyle##struct_))); \
00471       if (compare &&                                                          \
00472           !NS_IsHintSubset(maxHint, hint) &&                                  \
00473           this##struct_ != other##struct_) {                                  \
00474         NS_ASSERTION(NS_IsHintSubset(                                         \
00475              this##struct_->CalcDifference(*other##struct_),                  \
00476              nsStyle##struct_::MaxDifference()),                              \
00477              "CalcDifference() returned bigger hint than MaxDifference()");   \
00478         NS_UpdateHint(hint, this##struct_->CalcDifference(*other##struct_));  \
00479       }                                                                       \
00480     }                                                                         \
00481   PR_END_MACRO
00482 
00483   // We begin by examining those style structs that are capable of
00484   // causing the maximal difference, a FRAMECHANGE.
00485   // FRAMECHANGE Structs: Display, XUL, Content, UserInterface,
00486   // Visibility, Outline, TableBorder, Table, Background, UIReset, Quotes
00487   DO_STRUCT_DIFFERENCE(Display);
00488   DO_STRUCT_DIFFERENCE(XUL);
00489   DO_STRUCT_DIFFERENCE(Column);
00490   DO_STRUCT_DIFFERENCE(Content);
00491   DO_STRUCT_DIFFERENCE(UserInterface);
00492   DO_STRUCT_DIFFERENCE(Visibility);
00493   DO_STRUCT_DIFFERENCE(Outline);
00494   DO_STRUCT_DIFFERENCE(TableBorder);
00495   DO_STRUCT_DIFFERENCE(Table);
00496   DO_STRUCT_DIFFERENCE(Background);
00497   DO_STRUCT_DIFFERENCE(UIReset);
00498   // If the quotes implementation is ever going to change we might not need
00499   // a framechange here and a reflow should be sufficient.  See bug 35768.
00500   DO_STRUCT_DIFFERENCE(Quotes);
00501 
00502   // At this point, we know that the worst kind of damage we could do is
00503   // a reflow.
00504   maxHint = NS_STYLE_HINT_REFLOW;
00505       
00506   // The following structs cause (as their maximal difference) a reflow
00507   // to occur.  REFLOW Structs: Font, Margin, Padding, Border, List,
00508   // Position, Text, TextReset
00509   DO_STRUCT_DIFFERENCE(Font);
00510   DO_STRUCT_DIFFERENCE(Margin);
00511   DO_STRUCT_DIFFERENCE(Padding);
00512   DO_STRUCT_DIFFERENCE(Border);
00513   DO_STRUCT_DIFFERENCE(List);
00514   DO_STRUCT_DIFFERENCE(Position);
00515   DO_STRUCT_DIFFERENCE(Text);
00516   DO_STRUCT_DIFFERENCE(TextReset);
00517 
00518   // At this point, we know that the worst kind of damage we could do is
00519   // a re-render (i.e., a VISUAL change).
00520   maxHint = NS_STYLE_HINT_VISUAL;
00521 
00522   // The following structs cause (as their maximal difference) a
00523   // re-render to occur.  VISUAL Structs: Color
00524   DO_STRUCT_DIFFERENCE(Color);
00525 #ifdef MOZ_SVG
00526   DO_STRUCT_DIFFERENCE(SVG);
00527 #endif
00528 
00529 #undef DO_STRUCT_DIFFERENCE
00530 
00531   return hint;
00532 }
00533 
00534 void
00535 nsStyleContext::Mark()
00536 {
00537   // Mark our rule node.
00538   mRuleNode->Mark();
00539 
00540   // Mark our children (i.e., tell them to mark their rule nodes, etc.).
00541   if (mChild) {
00542     nsStyleContext* child = mChild;
00543     do {
00544       child->Mark();
00545       child = child->mNextSibling;
00546     } while (mChild != child);
00547   }
00548   
00549   if (mEmptyChild) {
00550     nsStyleContext* child = mEmptyChild;
00551     do {
00552       child->Mark();
00553       child = child->mNextSibling;
00554     } while (mEmptyChild != child);
00555   }
00556 }
00557 
00558 #ifdef DEBUG
00559 
00560 class URICString : public nsCAutoString {
00561 public:
00562   URICString(nsIURI* aURI) {
00563     if (aURI) {
00564       aURI->GetSpec(*this);
00565     } else {
00566       Assign("[none]");
00567     }
00568   }
00569 
00570   URICString(imgIRequest* aImageRequest) {
00571     nsCOMPtr<nsIURI> uri;
00572     if (aImageRequest) {
00573       aImageRequest->GetURI(getter_AddRefs(uri));
00574     }
00575     if (uri) {
00576       uri->GetSpec(*this);
00577     } else {
00578       Assign("[none]");
00579     }
00580   }
00581   
00582   URICString& operator=(const URICString& aOther) {
00583     Assign(aOther);
00584     return *this;
00585   }
00586 };
00587 
00588 void nsStyleContext::List(FILE* out, PRInt32 aIndent)
00589 {
00590   // Indent
00591   PRInt32 ix;
00592   for (ix = aIndent; --ix >= 0; ) fputs("  ", out);
00593   fprintf(out, "%p(%d) parent=%p ",
00594           (void*)this, mRefCnt, (void *)mParent);
00595   if (mPseudoTag) {
00596     nsAutoString  buffer;
00597     mPseudoTag->ToString(buffer);
00598     fputs(NS_LossyConvertUCS2toASCII(buffer).get(), out);
00599     fputs(" ", out);
00600   }
00601 
00602   if (mRuleNode) {
00603     fputs("{\n", out);
00604     nsRuleNode* ruleNode = mRuleNode;
00605     while (ruleNode) {
00606       nsIStyleRule *styleRule = ruleNode->GetRule();
00607       if (styleRule) {
00608         styleRule->List(out, aIndent + 1);
00609       }
00610       ruleNode = ruleNode->GetParent();
00611     }
00612     for (ix = aIndent; --ix >= 0; ) fputs("  ", out);
00613     fputs("}\n", out);
00614   }
00615   else {
00616     fputs("{}\n", out);
00617   }
00618 
00619   if (nsnull != mChild) {
00620     nsStyleContext* child = mChild;
00621     do {
00622       child->List(out, aIndent + 1);
00623       child = child->mNextSibling;
00624     } while (mChild != child);
00625   }
00626   if (nsnull != mEmptyChild) {
00627     nsStyleContext* child = mEmptyChild;
00628     do {
00629       child->List(out, aIndent + 1);
00630       child = child->mNextSibling;
00631     } while (mEmptyChild != child);
00632   }
00633 }
00634 
00635 static void IndentBy(FILE* out, PRInt32 aIndent) {
00636   while (--aIndent >= 0) fputs("  ", out);
00637 }
00638 // virtual 
00639 void nsStyleContext::DumpRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
00640 {
00641   nsAutoString str;
00642 
00643   // FONT
00644   IndentBy(out,aIndent);
00645   const nsStyleFont* font = GetStyleFont();
00646   fprintf(out, "<font %s %d %d %d />\n", 
00647           NS_ConvertUCS2toUTF8(font->mFont.name).get(),
00648           font->mFont.size,
00649           font->mSize,
00650           font->mFlags);
00651 
00652   // COLOR
00653   IndentBy(out,aIndent);
00654   const nsStyleColor* color = GetStyleColor();
00655   fprintf(out, "<color data=\"%ld\"/>\n", 
00656     (long)color->mColor);
00657 
00658   // BACKGROUND
00659   IndentBy(out,aIndent);
00660   const nsStyleBackground* bg = GetStyleBackground();
00661   fprintf(out, "<background data=\"%d %d %d %ld %ld %ld %s\"/>\n",
00662     (int)bg->mBackgroundAttachment,
00663     (int)bg->mBackgroundFlags,
00664     (int)bg->mBackgroundRepeat,
00665     (long)bg->mBackgroundColor,
00666     // XXX These aren't initialized unless flags are set:
00667     (long)bg->mBackgroundXPosition.mCoord, // potentially lossy on some platforms
00668     (long)bg->mBackgroundYPosition.mCoord, // potentially lossy on some platforms
00669     URICString(bg->mBackgroundImage).get());
00670  
00671   // SPACING (ie. margin, padding, border, outline)
00672   IndentBy(out,aIndent);
00673   fprintf(out, "<spacing data=\"");
00674 
00675   const nsStyleMargin* margin = GetStyleMargin();
00676   margin->mMargin.ToString(str);
00677   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00678   
00679   const nsStylePadding* padding = GetStylePadding();
00680   padding->mPadding.ToString(str);
00681   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00682   
00683   const nsStyleBorder* border = GetStyleBorder();
00684 #ifdef NS_COORD_IS_FLOAT
00685   const char format [] = "top: %ftw right: %ftw bottom: %ftw left: %ftw";
00686 #else
00687   const char format [] = "top: %dtw right: %dtw bottom: %dtw left: %dtw";
00688 #endif
00689   nsPrintfCString output(format,
00690                          border->GetBorderWidth(NS_SIDE_TOP),
00691                          border->GetBorderWidth(NS_SIDE_RIGHT),
00692                          border->GetBorderWidth(NS_SIDE_BOTTOM),
00693                          border->GetBorderWidth(NS_SIDE_LEFT));
00694   fprintf(out, "%s ", output.get());
00695   border->mBorderRadius.ToString(str);
00696   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00697   
00698   const nsStyleOutline* outline = GetStyleOutline();
00699   outline->mOutlineRadius.ToString(str);
00700   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00701   outline->mOutlineWidth.ToString(str);
00702   fprintf(out, "%s", NS_ConvertUCS2toUTF8(str).get());
00703   fprintf(out, "%d", (int)border->mFloatEdge);
00704   fprintf(out, "\" />\n");
00705 
00706   // LIST
00707   IndentBy(out,aIndent);
00708   const nsStyleList* list = GetStyleList();
00709   fprintf(out, "<list data=\"%d %d %s\" />\n",
00710     (int)list->mListStyleType,
00711     (int)list->mListStyleType,
00712     URICString(list->mListStyleImage).get());
00713 
00714   // POSITION
00715   IndentBy(out,aIndent);
00716   const nsStylePosition* pos = GetStylePosition();
00717   fprintf(out, "<position data=\"");
00718   pos->mOffset.ToString(str);
00719   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00720   pos->mWidth.ToString(str);
00721   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00722   pos->mMinWidth.ToString(str);
00723   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00724   pos->mMaxWidth.ToString(str);
00725   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00726   pos->mHeight.ToString(str);
00727   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00728   pos->mMinHeight.ToString(str);
00729   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00730   pos->mMaxHeight.ToString(str);
00731   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00732   fprintf(out, "%d ", (int)pos->mBoxSizing);
00733   pos->mZIndex.ToString(str);
00734   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00735   fprintf(out, "\" />\n");
00736 
00737   // TEXT
00738   IndentBy(out,aIndent);
00739   const nsStyleText* text = GetStyleText();
00740   fprintf(out, "<text data=\"%d %d %d ",
00741     (int)text->mTextAlign,
00742     (int)text->mTextTransform,
00743     (int)text->mWhiteSpace);
00744   text->mLetterSpacing.ToString(str);
00745   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00746   text->mLineHeight.ToString(str);
00747   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00748   text->mTextIndent.ToString(str);
00749   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00750   text->mWordSpacing.ToString(str);
00751   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00752   fprintf(out, "\" />\n");
00753   
00754   // TEXT RESET
00755   IndentBy(out,aIndent);
00756   const nsStyleTextReset* textReset = GetStyleTextReset();
00757   fprintf(out, "<textreset data=\"%d ",
00758     (int)textReset->mTextDecoration);
00759   textReset->mVerticalAlign.ToString(str);
00760   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00761   fprintf(out, "\" />\n");
00762 
00763   // DISPLAY
00764   IndentBy(out,aIndent);
00765   const nsStyleDisplay* disp = GetStyleDisplay();
00766   fprintf(out, "<display data=\"%d %d %f %d %d %d %d %d %d %d %ld %ld %ld %ld %s\" />\n",
00767     (int)disp->mPosition,
00768     (int)disp->mDisplay,
00769     (float)disp->mOpacity,      
00770     (int)disp->mFloats,
00771     (int)disp->mBreakType,
00772     (int)disp->mBreakBefore,
00773     (int)disp->mBreakAfter,
00774     (int)disp->mOverflowX,
00775     (int)disp->mOverflowY,
00776     (int)disp->mClipFlags,
00777     (long)disp->mClip.x,
00778     (long)disp->mClip.y,
00779     (long)disp->mClip.width,
00780     (long)disp->mClip.height,
00781     URICString(disp->mBinding).get()
00782     );
00783   
00784   // VISIBILITY
00785   IndentBy(out,aIndent);
00786   const nsStyleVisibility* vis = GetStyleVisibility();
00787   fprintf(out, "<visibility data=\"%d %d\" />\n",
00788     (int)vis->mDirection,
00789     (int)vis->mVisible
00790     );
00791 
00792   // TABLE
00793   IndentBy(out,aIndent);
00794   const nsStyleTable* table = GetStyleTable();
00795   fprintf(out, "<table data=\"%d %d %d ",
00796     (int)table->mLayoutStrategy,
00797     (int)table->mFrame,
00798     (int)table->mRules);
00799   fprintf(out, "%ld %ld ",
00800     (long)table->mCols,
00801     (long)table->mSpan);
00802   fprintf(out, "\" />\n");
00803 
00804   // TABLEBORDER
00805   IndentBy(out,aIndent);
00806   const nsStyleTableBorder* tableBorder = GetStyleTableBorder();
00807   fprintf(out, "<tableborder data=\"%d ",
00808     (int)tableBorder->mBorderCollapse);
00809   tableBorder->mBorderSpacingX.ToString(str);
00810   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00811   tableBorder->mBorderSpacingY.ToString(str);
00812   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00813   fprintf(out, "%d %d ",
00814     (int)tableBorder->mCaptionSide,
00815     (int)tableBorder->mEmptyCells);
00816   fprintf(out, "\" />\n");
00817 
00818   // CONTENT
00819   IndentBy(out,aIndent);
00820   const nsStyleContent* content = GetStyleContent();
00821   fprintf(out, "<content data=\"%ld %ld %ld ",
00822     (long)content->ContentCount(),
00823     (long)content->CounterIncrementCount(),
00824     (long)content->CounterResetCount());
00825   // XXX: iterate over the content and counters...
00826   content->mMarkerOffset.ToString(str);
00827   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00828   fprintf(out, "\" />\n");
00829 
00830   // QUOTES
00831   IndentBy(out,aIndent);
00832   const nsStyleQuotes* quotes = GetStyleQuotes();
00833   fprintf(out, "<quotes data=\"%ld ",
00834     (long)quotes->QuotesCount());
00835   // XXX: iterate over the quotes...
00836   fprintf(out, "\" />\n");
00837 
00838   // UI
00839   IndentBy(out,aIndent);
00840   const nsStyleUserInterface* ui = GetStyleUserInterface();
00841   fprintf(out, "<ui data=\"%d %d %d %d\" />\n",
00842     (int)ui->mUserInput,
00843     (int)ui->mUserModify,
00844     (int)ui->mUserFocus, 
00845     (int)ui->mCursor);
00846 
00847   // UIReset
00848   IndentBy(out,aIndent);
00849   const nsStyleUIReset* uiReset = GetStyleUIReset();
00850   fprintf(out, "<uireset data=\"%d\" />\n",
00851     (int)uiReset->mUserSelect);
00852 
00853   // Column
00854   IndentBy(out,aIndent);
00855   const nsStyleColumn* column = GetStyleColumn();
00856   fprintf(out, "<column data=\"%d ",
00857     (int)column->mColumnCount);
00858   column->mColumnWidth.ToString(str);
00859   fprintf(out, "%s ", NS_ConvertUCS2toUTF8(str).get());
00860   column->mColumnGap.ToString(str);
00861   fprintf(out, "%s", NS_ConvertUCS2toUTF8(str).get());
00862   fprintf(out, "\" />\n");
00863 
00864   // XUL
00865   IndentBy(out,aIndent);
00866   const nsStyleXUL* xul = GetStyleXUL();
00867   fprintf(out, "<xul data=\"%d %d %d %d %d %d",
00868     (int)xul->mBoxAlign,
00869     (int)xul->mBoxDirection,
00870     (int)xul->mBoxFlex,
00871     (int)xul->mBoxOrient,
00872     (int)xul->mBoxPack,
00873     (int)xul->mBoxOrdinal);
00874   fprintf(out, "\" />\n");
00875 
00876 #ifdef MOZ_SVG
00877   // SVG
00878   IndentBy(out,aIndent);
00879   const nsStyleSVG* svg = GetStyleSVG();
00880   fprintf(out, "<svg data=\"%d ",(int)svg->mFill.mType);
00881   if (svg->mFill.mType == eStyleSVGPaintType_Server)
00882     fprintf(out, "%s ", URICString(svg->mFill.mPaint.mPaintServer).get());
00883   else
00884     fprintf(out, "%ld ", (long)svg->mFill.mPaint.mColor);
00885 
00886   fprintf(out, "%d ", (int)svg->mStroke.mType);
00887   if (svg->mStroke.mType == eStyleSVGPaintType_Server)
00888     fprintf(out, "%s ", URICString(svg->mStroke.mPaint.mPaintServer).get());
00889   else
00890     fprintf(out, "%ld ", (long)svg->mStroke.mPaint.mColor);
00891 
00892   fprintf(out, "%s %s %s ",
00893           URICString(svg->mMarkerEnd).get(),
00894           URICString(svg->mMarkerMid).get(),
00895           URICString(svg->mMarkerStart).get());
00896 
00897   for (PRUint32 i = 0; i < svg->mStrokeDasharrayLength; i++) {
00898     svg->mStrokeDasharray[i].ToString(str);
00899     fprintf(out,
00900             "%s%c",
00901             NS_ConvertUCS2toUTF8(str).get(),
00902             (i == svg->mStrokeDasharrayLength) ? ' ' : ',');
00903   }
00904 
00905   svg->mStrokeDashoffset.ToString(str);
00906   fprintf(out, "%f %s %f %f ",
00907           svg->mFillOpacity,
00908           NS_ConvertUCS2toUTF8(str).get(),
00909           svg->mStrokeMiterlimit,
00910           svg->mStrokeOpacity);
00911   svg->mStrokeWidth.ToString(str);
00912   fprintf(out, "%s %d %d %d %d %d %d %d %d %d\" />\n",
00913           NS_ConvertUCS2toUTF8(str).get(),
00914           (int)svg->mStrokeDasharrayLength,
00915           (int)svg->mClipRule,
00916           (int)svg->mFillRule,
00917           (int)svg->mPointerEvents,
00918           (int)svg->mShapeRendering,
00919           (int)svg->mStrokeLinecap,
00920           (int)svg->mStrokeLinejoin,
00921           (int)svg->mTextAnchor,
00922           (int)svg->mTextRendering);
00923 
00924   // SVGReset
00925   IndentBy(out,aIndent);
00926   const nsStyleSVGReset* svgReset = GetStyleSVGReset();
00927 
00928   fprintf(out, "<svgreset data=\"%d ", (int)svgReset->mStopColor.mType);
00929   if (svgReset->mStopColor.mType == eStyleSVGPaintType_Server)
00930     fprintf(out, "%s ",
00931             URICString(svgReset->mStopColor.mPaint.mPaintServer).get());
00932   else
00933     fprintf(out, "%ld ", (long)svgReset->mStopColor.mPaint.mColor);
00934 
00935   fprintf(out, "%s %f %d\" />\n",
00936           URICString(svgReset->mClipPath).get(),
00937           svgReset->mStopOpacity,
00938           (int)svgReset->mDominantBaseline);
00939 #endif
00940   //#insert new style structs here#
00941 }
00942 #endif
00943 
00944 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
00945 // (which comes from the presShell) to perform the allocation.
00946 void* 
00947 nsStyleContext::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
00948 {
00949   // Check the recycle list first.
00950   return aPresContext->AllocateFromShell(sz);
00951 }
00952 
00953 // Overridden to prevent the global delete from being called, since the memory
00954 // came out of an nsIArena instead of the global delete operator's heap.
00955 void 
00956 nsStyleContext::Destroy()
00957 {
00958   // Get the pres context from our rule node.
00959   nsCOMPtr<nsPresContext> presContext = mRuleNode->GetPresContext();
00960 
00961   // Call our destructor.
00962   this->~nsStyleContext();
00963 
00964   // Don't let the memory be freed, since it will be recycled
00965   // instead. Don't call the global operator delete.
00966   presContext->FreeToShell(sizeof(nsStyleContext), this);
00967 }
00968 
00969 already_AddRefed<nsStyleContext>
00970 NS_NewStyleContext(nsStyleContext* aParentContext,
00971                    nsIAtom* aPseudoTag,
00972                    nsRuleNode* aRuleNode,
00973                    nsPresContext* aPresContext)
00974 {
00975   nsStyleContext* context = new (aPresContext) nsStyleContext(aParentContext, aPseudoTag, 
00976                                                               aRuleNode, aPresContext);
00977   if (context)
00978     context->AddRef();
00979   return context;
00980 }
00981