Back to index

lightning-sunbird  0.9+nobinonly
nsStyleSet.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  *   Daniel Glazman <glazman@netscape.com>
00024  *   Brian Ryner    <bryner@brianryner.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 #include "nsStyleSet.h"
00040 #include "nsNetUtil.h"
00041 #include "nsICSSStyleSheet.h"
00042 #include "nsIDocument.h"
00043 #include "nsRuleWalker.h"
00044 #include "nsStyleContext.h"
00045 #include "nsICSSStyleRule.h"
00046 #include "nsCSSAnonBoxes.h"
00047 #include "nsCSSPseudoElements.h"
00048 #include "nsCSSRuleProcessor.h"
00049 #include "nsIContent.h"
00050 #include "nsIFrame.h"
00051 
00052 nsIURI *nsStyleSet::gQuirkURI = 0;
00053 
00054 nsStyleSet::nsStyleSet()
00055   : mRuleTree(nsnull),
00056     mRuleWalker(nsnull),
00057     mDestroyedCount(0),
00058     mBatching(0),
00059     mInShutdown(PR_FALSE),
00060     mAuthorStyleDisabled(PR_FALSE),
00061     mDirty(0)
00062 {
00063 }
00064 
00065 nsresult
00066 nsStyleSet::Init(nsPresContext *aPresContext)
00067 {
00068   if (!gQuirkURI) {
00069     static const char kQuirk_href[] = "resource://gre/res/quirk.css";
00070     NS_NewURI(&gQuirkURI, kQuirk_href);
00071     NS_ENSURE_TRUE(gQuirkURI, NS_ERROR_OUT_OF_MEMORY);
00072   }
00073 
00074   if (!BuildDefaultStyleData(aPresContext)) {
00075     mDefaultStyleData.Destroy(0, aPresContext);
00076     return NS_ERROR_OUT_OF_MEMORY;
00077   }
00078 
00079   mRuleTree = nsRuleNode::CreateRootNode(aPresContext);
00080   if (!mRuleTree) {
00081     mDefaultStyleData.Destroy(0, aPresContext);
00082     return NS_ERROR_OUT_OF_MEMORY;
00083   }
00084 
00085   mRuleWalker = new nsRuleWalker(mRuleTree);
00086   if (!mRuleWalker) {
00087     mRuleTree->Destroy();
00088     mDefaultStyleData.Destroy(0, aPresContext);
00089     return NS_ERROR_OUT_OF_MEMORY;
00090   }
00091 
00092   return NS_OK;
00093 }
00094 
00095 nsresult
00096 nsStyleSet::GatherRuleProcessors(sheetType aType)
00097 {
00098   mRuleProcessors[aType] = nsnull;
00099   if (mAuthorStyleDisabled && (aType == eDocSheet || 
00100                                aType == ePresHintSheet ||
00101                                aType == eHTMLPresHintSheet ||
00102                                aType == eStyleAttrSheet)) {
00103     //don't regather if this level is disabled
00104     return NS_OK;
00105   }
00106   if (mSheets[aType].Count()) {
00107     switch (aType) {
00108       case eAgentSheet:
00109       case eUserSheet:
00110       case eDocSheet:
00111       case eOverrideSheet: {
00112         // levels containing CSS stylesheets
00113         nsCOMArray<nsIStyleSheet>& sheets = mSheets[aType];
00114         nsCOMArray<nsICSSStyleSheet> cssSheets(sheets.Count());
00115         for (PRInt32 i = 0, i_end = sheets.Count(); i < i_end; ++i) {
00116           nsCOMPtr<nsICSSStyleSheet> cssSheet = do_QueryInterface(sheets[i]);
00117           NS_ASSERTION(cssSheet, "not a CSS sheet");
00118           cssSheets.AppendObject(cssSheet);
00119         }
00120         mRuleProcessors[aType] = new nsCSSRuleProcessor(cssSheets);
00121       } break;
00122 
00123       default:
00124         // levels containing non-CSS stylesheets
00125         NS_ASSERTION(mSheets[aType].Count() == 1, "only one sheet per level");
00126         mRuleProcessors[aType] = do_QueryInterface(mSheets[aType][0]);
00127         break;
00128     }
00129   }
00130 
00131   return NS_OK;
00132 }
00133 
00134 #ifdef DEBUG
00135 #define CHECK_APPLICABLE \
00136 PR_BEGIN_MACRO \
00137   PRBool applicable = PR_TRUE; \
00138   aSheet->GetApplicable(applicable); \
00139   NS_ASSERTION(applicable, "Inapplicable sheet being placed in style set"); \
00140 PR_END_MACRO
00141 #else
00142 #define CHECK_APPLICABLE
00143 #endif
00144 
00145 nsresult
00146 nsStyleSet::AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
00147 {
00148   NS_PRECONDITION(aSheet, "null arg");
00149   CHECK_APPLICABLE;
00150   mSheets[aType].RemoveObject(aSheet);
00151   if (!mSheets[aType].AppendObject(aSheet))
00152     return NS_ERROR_OUT_OF_MEMORY;
00153 
00154   if (!mBatching)
00155     return GatherRuleProcessors(aType);
00156 
00157   mDirty |= 1 << aType;
00158   return NS_OK;
00159 }
00160 
00161 nsresult
00162 nsStyleSet::PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
00163 {
00164   NS_PRECONDITION(aSheet, "null arg");
00165   CHECK_APPLICABLE;
00166   mSheets[aType].RemoveObject(aSheet);
00167   if (!mSheets[aType].InsertObjectAt(aSheet, 0))
00168     return NS_ERROR_OUT_OF_MEMORY;
00169 
00170   if (!mBatching)
00171     return GatherRuleProcessors(aType);
00172 
00173   mDirty |= 1 << aType;
00174   return NS_OK;
00175 }
00176 
00177 nsresult
00178 nsStyleSet::RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
00179 {
00180   NS_PRECONDITION(aSheet, "null arg");
00181 #ifdef DEBUG
00182   PRBool complete = PR_TRUE;
00183   aSheet->GetComplete(complete);
00184   NS_ASSERTION(complete, "Incomplete sheet being removed from style set");
00185 #endif
00186   mSheets[aType].RemoveObject(aSheet);
00187   if (!mBatching)
00188     return GatherRuleProcessors(aType);
00189 
00190   mDirty |= 1 << aType;
00191   return NS_OK;
00192 }
00193 
00194 nsresult
00195 nsStyleSet::ReplaceSheets(sheetType aType,
00196                           const nsCOMArray<nsIStyleSheet> &aNewSheets)
00197 {
00198   mSheets[aType].Clear();
00199   if (!mSheets[aType].AppendObjects(aNewSheets))
00200     return NS_ERROR_OUT_OF_MEMORY;
00201 
00202   if (!mBatching)
00203     return GatherRuleProcessors(aType);
00204 
00205   mDirty |= 1 << aType;
00206   return NS_OK;
00207 }
00208 
00209 PRBool
00210 nsStyleSet::GetAuthorStyleDisabled()
00211 {
00212   return mAuthorStyleDisabled;
00213 }
00214 
00215 nsresult
00216 nsStyleSet::SetAuthorStyleDisabled(PRBool aStyleDisabled)
00217 {
00218   if (aStyleDisabled == !mAuthorStyleDisabled) {
00219     mAuthorStyleDisabled = aStyleDisabled;
00220     BeginUpdate();
00221     mDirty |= 1 << eDocSheet |
00222               1 << ePresHintSheet |
00223               1 << eHTMLPresHintSheet |
00224               1 << eStyleAttrSheet;
00225     return EndUpdate();
00226   }
00227   return NS_OK;
00228 }
00229 
00230 // -------- Doc Sheets
00231 
00232 nsresult
00233 nsStyleSet::AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument)
00234 {
00235   NS_PRECONDITION(aSheet && aDocument, "null arg");
00236   CHECK_APPLICABLE;
00237 
00238   nsCOMArray<nsIStyleSheet>& docSheets = mSheets[eDocSheet];
00239 
00240   docSheets.RemoveObject(aSheet);
00241   // lowest index first
00242   PRInt32 newDocIndex = aDocument->GetIndexOfStyleSheet(aSheet);
00243   PRInt32 count = docSheets.Count();
00244   PRInt32 index;
00245   for (index = 0; index < count; index++) {
00246     nsIStyleSheet* sheet = docSheets.ObjectAt(index);
00247     PRInt32 sheetDocIndex = aDocument->GetIndexOfStyleSheet(sheet);
00248     if (sheetDocIndex > newDocIndex)
00249       break;
00250   }
00251   if (!docSheets.InsertObjectAt(aSheet, index))
00252     return NS_ERROR_OUT_OF_MEMORY;
00253   if (!mBatching)
00254     return GatherRuleProcessors(eDocSheet);
00255 
00256   mDirty |= 1 << eDocSheet;
00257   return NS_OK;
00258 }
00259 
00260 #undef CHECK_APPLICABLE
00261 
00262 // Batching
00263 void
00264 nsStyleSet::BeginUpdate()
00265 {
00266   ++mBatching;
00267 }
00268 
00269 nsresult
00270 nsStyleSet::EndUpdate()
00271 {
00272   NS_ASSERTION(mBatching > 0, "Unbalanced EndUpdate");
00273   if (--mBatching) {
00274     // We're not completely done yet.
00275     return NS_OK;
00276   }
00277 
00278   for (int i = 0; i < eSheetTypeCount; ++i) {
00279     if (mDirty & (1 << i)) {
00280       nsresult rv = GatherRuleProcessors(sheetType(i));
00281       NS_ENSURE_SUCCESS(rv, rv);
00282     }
00283   }
00284 
00285   mDirty = 0;
00286   return NS_OK;
00287 }
00288 
00289 void
00290 nsStyleSet::EnableQuirkStyleSheet(PRBool aEnable)
00291 {
00292   if (!mQuirkStyleSheet) {
00293     // first find the quirk sheet:
00294     // - run through all of the agent sheets and check for a CSSStyleSheet that
00295     //   has the URL we want
00296     PRInt32 nSheets = mSheets[eAgentSheet].Count();
00297     for (PRInt32 i = 0; i < nSheets; ++i) {
00298       nsIStyleSheet *sheet = mSheets[eAgentSheet].ObjectAt(i);
00299       NS_ASSERTION(sheet, "mAgentSheets should not contain null sheets");
00300 
00301       nsICSSStyleSheet *cssSheet = NS_STATIC_CAST(nsICSSStyleSheet*, sheet);
00302       NS_ASSERTION(nsCOMPtr<nsICSSStyleSheet>(do_QueryInterface(sheet)) == cssSheet,
00303                    "Agent sheet must be a CSSStyleSheet");
00304 
00305       nsCOMPtr<nsIStyleSheet> quirkSheet;
00306       PRBool bHasSheet = PR_FALSE;
00307       if (NS_SUCCEEDED(cssSheet->ContainsStyleSheet(gQuirkURI, bHasSheet, 
00308                                                     getter_AddRefs(quirkSheet))) 
00309           && bHasSheet) {
00310         NS_ASSERTION(quirkSheet, "QuirkSheet must be set: ContainsStyleSheet is hosed");
00311         // cache the sheet for faster lookup next time
00312         mQuirkStyleSheet = quirkSheet;
00313         // only one quirk style sheet can exist, so stop looking
00314         break;
00315       }
00316     }
00317   }
00318   NS_ASSERTION(mQuirkStyleSheet, "no quirk stylesheet");
00319   if (mQuirkStyleSheet) {
00320 #ifdef DEBUG_dbaron_off // XXX Make this |DEBUG| once it stops firing.
00321     PRBool applicableNow;
00322     mQuirkStyleSheet->GetApplicable(applicableNow);
00323     NS_ASSERTION(!mRuleProcessors[eAgentSheet] || aEnable == applicableNow,
00324                  "enabling/disabling quirk stylesheet too late or incomplete quirk stylesheet");
00325     if (mRuleProcessors[eAgentSheet] && aEnable == applicableNow)
00326       printf("WARNING: We set the quirks mode too many times.\n"); // we do!
00327 #endif
00328     mQuirkStyleSheet->SetEnabled(aEnable);
00329   }
00330 }
00331 
00332 static PRBool
00333 EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
00334 {
00335   ElementRuleProcessorData* data =
00336     NS_STATIC_CAST(ElementRuleProcessorData*, aData);
00337 
00338   aProcessor->RulesMatching(data);
00339   return PR_TRUE;
00340 }
00341 
00348 already_AddRefed<nsStyleContext>
00349 nsStyleSet::GetContext(nsPresContext* aPresContext, 
00350                        nsStyleContext* aParentContext, 
00351                        nsIAtom* aPseudoTag)
00352 {
00353   nsStyleContext* result = nsnull;
00354   nsRuleNode* ruleNode = mRuleWalker->GetCurrentNode();
00355       
00356   if (aParentContext)
00357     result = aParentContext->FindChildWithRules(aPseudoTag, ruleNode).get();
00358 
00359 #ifdef NOISY_DEBUG
00360   if (result)
00361     fprintf(stdout, "--- SharedSC %d ---\n", ++gSharedCount);
00362   else
00363     fprintf(stdout, "+++ NewSC %d +++\n", ++gNewCount);
00364 #endif
00365 
00366   if (!result) {
00367     result = NS_NewStyleContext(aParentContext, aPseudoTag, ruleNode,
00368                                 aPresContext).get();
00369     if (!aParentContext && result)
00370       mRoots.AppendElement(result);
00371   }
00372 
00373   return result;
00374 }
00375 
00376 void
00377 nsStyleSet::AddImportantRules(nsRuleNode* aCurrLevelNode,
00378                               nsRuleNode* aLastPrevLevelNode)
00379 {
00380   if (!aCurrLevelNode || aCurrLevelNode == aLastPrevLevelNode)
00381     return;
00382 
00383   AddImportantRules(aCurrLevelNode->GetParent(), aLastPrevLevelNode);
00384 
00385   nsIStyleRule *rule = aCurrLevelNode->GetRule();
00386   nsCOMPtr<nsICSSStyleRule> cssRule(do_QueryInterface(rule));
00387   if (cssRule) {
00388     nsCOMPtr<nsIStyleRule> impRule = cssRule->GetImportantRule();
00389     if (impRule)
00390       mRuleWalker->Forward(impRule);
00391   }
00392 }
00393 
00394 #ifdef DEBUG
00395 void
00396 nsStyleSet::AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
00397                                    nsRuleNode* aLastPrevLevelNode)
00398 {
00399   if (!aCurrLevelNode || aCurrLevelNode == aLastPrevLevelNode)
00400     return;
00401 
00402   AssertNoImportantRules(aCurrLevelNode->GetParent(), aLastPrevLevelNode);
00403 
00404   nsIStyleRule *rule = aCurrLevelNode->GetRule();
00405   nsCOMPtr<nsICSSStyleRule> cssRule(do_QueryInterface(rule));
00406   if (cssRule) {
00407     nsCOMPtr<nsIStyleRule> impRule = cssRule->GetImportantRule();
00408     NS_ASSERTION(!impRule, "Unexpected important rule");
00409   }
00410 }
00411 
00412 void
00413 nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
00414                              nsRuleNode* aLastPrevLevelNode)
00415 {
00416   if (!aCurrLevelNode || aCurrLevelNode == aLastPrevLevelNode)
00417     return;
00418 
00419   AssertNoImportantRules(aCurrLevelNode->GetParent(), aLastPrevLevelNode);
00420 
00421   nsIStyleRule *rule = aCurrLevelNode->GetRule();
00422   nsCOMPtr<nsICSSStyleRule> cssRule(do_QueryInterface(rule));
00423   NS_ASSERTION(!cssRule, "Unexpected CSS rule");
00424 }
00425 #endif
00426 
00427 // Enumerate the rules in a way that cares about the order of the rules.
00428 void
00429 nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc, 
00430                       RuleProcessorData* aData)
00431 {
00432   // Cascading order:
00433   // [least important]
00434   //  1. UA normal rules                    = Agent        normal
00435   //  2. Presentation hints                 = PresHint     normal
00436   //  3. User normal rules                  = User         normal
00437   //  2. HTML Presentation hints            = HTMLPresHint normal
00438   //  5. Author normal rules                = Document     normal
00439   //  6. Override normal rules              = Override     normal
00440   //  7. Author !important rules            = Document     !important
00441   //  8. Override !important rules          = Override     !important
00442   //  9. User !important rules              = User         !important
00443   // 10. UA !important rules                = Agent        !important
00444   // [most important]
00445 
00446   NS_PRECONDITION(SheetCount(ePresHintSheet) == 0 ||
00447                   SheetCount(eHTMLPresHintSheet) == 0,
00448                   "Can't have both types of preshint sheets at once!");
00449   
00450   if (mRuleProcessors[eAgentSheet])
00451     (*aCollectorFunc)(mRuleProcessors[eAgentSheet], aData);
00452   nsRuleNode* lastAgentRN = mRuleWalker->GetCurrentNode();
00453 
00454   if (mRuleProcessors[ePresHintSheet])
00455     (*aCollectorFunc)(mRuleProcessors[ePresHintSheet], aData);
00456   nsRuleNode* lastPresHintRN = mRuleWalker->GetCurrentNode();
00457   
00458   if (mRuleProcessors[eUserSheet])
00459     (*aCollectorFunc)(mRuleProcessors[eUserSheet], aData);
00460   nsRuleNode* lastUserRN = mRuleWalker->GetCurrentNode();
00461 
00462   if (mRuleProcessors[eHTMLPresHintSheet])
00463     (*aCollectorFunc)(mRuleProcessors[eHTMLPresHintSheet], aData);
00464   nsRuleNode* lastHTMLPresHintRN = mRuleWalker->GetCurrentNode();
00465   
00466   PRBool cutOffInheritance = PR_FALSE;
00467   if (mStyleRuleSupplier) {
00468     // We can supply additional document-level sheets that should be walked.
00469     mStyleRuleSupplier->WalkRules(this, aCollectorFunc, aData,
00470                                   &cutOffInheritance);
00471   }
00472   if (!cutOffInheritance && mRuleProcessors[eDocSheet]) // NOTE: different
00473     (*aCollectorFunc)(mRuleProcessors[eDocSheet], aData);
00474   if (mRuleProcessors[eStyleAttrSheet])
00475     (*aCollectorFunc)(mRuleProcessors[eStyleAttrSheet], aData);
00476 
00477   if (mRuleProcessors[eOverrideSheet])
00478     (*aCollectorFunc)(mRuleProcessors[eOverrideSheet], aData);
00479   nsRuleNode* lastOvrRN = mRuleWalker->GetCurrentNode();
00480 
00481   // There should be no important rules in the preshint or HTMLpreshint level
00482   AddImportantRules(lastOvrRN, lastHTMLPresHintRN);  // doc and override
00483 #ifdef DEBUG
00484   AssertNoCSSRules(lastHTMLPresHintRN, lastUserRN);
00485   AssertNoImportantRules(lastHTMLPresHintRN, lastUserRN); // HTML preshints
00486 #endif
00487   AddImportantRules(lastUserRN, lastPresHintRN); //user
00488 #ifdef DEBUG
00489   AssertNoImportantRules(lastPresHintRN, lastAgentRN); // preshints
00490 #endif
00491   AddImportantRules(lastAgentRN, nsnull);     //agent
00492 
00493 }
00494 
00495 // Enumerate all the rules in a way that doesn't care about the order
00496 // of the rules and doesn't walk !important-rules.
00497 void
00498 nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
00499                                RuleProcessorData* aData)
00500 {
00501   NS_PRECONDITION(SheetCount(ePresHintSheet) == 0 ||
00502                   SheetCount(eHTMLPresHintSheet) == 0,
00503                   "Can't have both types of preshint sheets at once!");
00504   
00505   if (mRuleProcessors[eAgentSheet])
00506     (*aFunc)(mRuleProcessors[eAgentSheet], aData);
00507   if (mRuleProcessors[ePresHintSheet])
00508     (*aFunc)(mRuleProcessors[ePresHintSheet], aData);
00509   if (mRuleProcessors[eUserSheet])
00510     (*aFunc)(mRuleProcessors[eUserSheet], aData);
00511   if (mRuleProcessors[eHTMLPresHintSheet])
00512     (*aFunc)(mRuleProcessors[eHTMLPresHintSheet], aData);
00513   
00514   PRBool cutOffInheritance = PR_FALSE;
00515   if (mStyleRuleSupplier) {
00516     // We can supply additional document-level sheets that should be walked.
00517     mStyleRuleSupplier->WalkRules(this, aFunc, aData, &cutOffInheritance);
00518   }
00519   if (!cutOffInheritance && mRuleProcessors[eDocSheet]) // NOTE: different
00520     (*aFunc)(mRuleProcessors[eDocSheet], aData);
00521   if (mRuleProcessors[eStyleAttrSheet])
00522     (*aFunc)(mRuleProcessors[eStyleAttrSheet], aData);
00523   if (mRuleProcessors[eOverrideSheet])
00524     (*aFunc)(mRuleProcessors[eOverrideSheet], aData);
00525 }
00526 
00527 PRBool nsStyleSet::BuildDefaultStyleData(nsPresContext* aPresContext)
00528 {
00529   NS_ASSERTION(!mDefaultStyleData.mResetData &&
00530                !mDefaultStyleData.mInheritedData,
00531                "leaking default style data");
00532   mDefaultStyleData.mResetData = new (aPresContext) nsResetStyleData;
00533   if (!mDefaultStyleData.mResetData)
00534     return PR_FALSE;
00535   mDefaultStyleData.mInheritedData = new (aPresContext) nsInheritedStyleData;
00536   if (!mDefaultStyleData.mInheritedData)
00537     return PR_FALSE;
00538 
00539 #define SSARG_PRESCONTEXT aPresContext
00540 
00541 #define CREATE_DATA(name, type, args) \
00542   if (!(mDefaultStyleData.m##type##Data->m##name##Data = \
00543           new (aPresContext) nsStyle##name args)) \
00544     return PR_FALSE;
00545 
00546 #define STYLE_STRUCT_INHERITED(name, checkdata_cb, ctor_args) \
00547   CREATE_DATA(name, Inherited, ctor_args)
00548 #define STYLE_STRUCT_RESET(name, checkdata_cb, ctor_args) \
00549   CREATE_DATA(name, Reset, ctor_args)
00550 
00551 #include "nsStyleStructList.h"
00552 
00553 #undef STYLE_STRUCT_INHERITED
00554 #undef STYLE_STRUCT_RESET
00555 #undef SSARG_PRESCONTEXT
00556 
00557   return PR_TRUE;
00558 }
00559 
00560 already_AddRefed<nsStyleContext>
00561 nsStyleSet::ResolveStyleFor(nsIContent* aContent,
00562                             nsStyleContext* aParentContext)
00563 {
00564   NS_ENSURE_FALSE(mInShutdown, nsnull);
00565   
00566   nsStyleContext*  result = nsnull;
00567   nsPresContext* presContext = PresContext();
00568 
00569   NS_ASSERTION(aContent, "must have content");
00570   NS_ASSERTION(aContent->IsContentOfType(nsIContent::eELEMENT),
00571                "content must be element");
00572 
00573   if (aContent && presContext) {
00574     if (mRuleProcessors[eAgentSheet]        ||
00575         mRuleProcessors[ePresHintSheet]     ||
00576         mRuleProcessors[eUserSheet]         ||
00577         mRuleProcessors[eHTMLPresHintSheet] ||
00578         mRuleProcessors[eDocSheet]          ||
00579         mRuleProcessors[eStyleAttrSheet]    ||
00580         mRuleProcessors[eOverrideSheet]) {
00581       ElementRuleProcessorData data(presContext, aContent, mRuleWalker);
00582       FileRules(EnumRulesMatching, &data);
00583       result = GetContext(presContext, aParentContext, nsnull).get();
00584 
00585       // Now reset the walker back to the root of the tree.
00586       mRuleWalker->Reset();
00587     }
00588   }
00589 
00590   return result;
00591 }
00592 
00593 already_AddRefed<nsStyleContext>
00594 nsStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext)
00595 {
00596   nsStyleContext* result = nsnull;
00597   nsPresContext *presContext = PresContext();
00598 
00599   if (presContext) {
00600     if (mRuleProcessors[eAgentSheet]        ||
00601         mRuleProcessors[ePresHintSheet]     ||
00602         mRuleProcessors[eUserSheet]         ||
00603         mRuleProcessors[eHTMLPresHintSheet] ||
00604         mRuleProcessors[eDocSheet]          ||
00605         mRuleProcessors[eStyleAttrSheet]    ||
00606         mRuleProcessors[eOverrideSheet]) {
00607       result = GetContext(presContext, aParentContext,
00608                           nsCSSAnonBoxes::mozNonElement).get();
00609       NS_ASSERTION(mRuleWalker->AtRoot(), "rule walker must be at root");
00610     }
00611   }
00612 
00613   return result;
00614 }
00615 
00616 
00617 static PRBool
00618 EnumPseudoRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
00619 {
00620   PseudoRuleProcessorData* data =
00621     NS_STATIC_CAST(PseudoRuleProcessorData*, aData);
00622 
00623   aProcessor->RulesMatching(data);
00624   return PR_TRUE;
00625 }
00626 
00627 already_AddRefed<nsStyleContext>
00628 nsStyleSet::ResolvePseudoStyleFor(nsIContent* aParentContent,
00629                                   nsIAtom* aPseudoTag,
00630                                   nsStyleContext* aParentContext,
00631                                   nsICSSPseudoComparator* aComparator)
00632 {
00633   NS_ENSURE_FALSE(mInShutdown, nsnull);
00634 
00635   nsStyleContext*  result = nsnull;
00636   nsPresContext *presContext = PresContext();
00637 
00638   NS_ASSERTION(aPseudoTag, "must have pseudo tag");
00639   NS_ASSERTION(!aParentContent ||
00640                aParentContent->IsContentOfType(nsIContent::eELEMENT),
00641                "content (if non-null) must be element");
00642 
00643   if (aPseudoTag && presContext) {
00644     if (mRuleProcessors[eAgentSheet]        ||
00645         mRuleProcessors[ePresHintSheet]     ||
00646         mRuleProcessors[eUserSheet]         ||
00647         mRuleProcessors[eHTMLPresHintSheet] ||
00648         mRuleProcessors[eDocSheet]          ||
00649         mRuleProcessors[eStyleAttrSheet]    ||
00650         mRuleProcessors[eOverrideSheet]) {
00651       PseudoRuleProcessorData data(presContext, aParentContent, aPseudoTag,
00652                                    aComparator, mRuleWalker);
00653       FileRules(EnumPseudoRulesMatching, &data);
00654 
00655       result = GetContext(presContext, aParentContext, aPseudoTag).get();
00656 
00657       // Now reset the walker back to the root of the tree.
00658       mRuleWalker->Reset();
00659     }
00660   }
00661 
00662   return result;
00663 }
00664 
00665 already_AddRefed<nsStyleContext>
00666 nsStyleSet::ProbePseudoStyleFor(nsIContent* aParentContent,
00667                                 nsIAtom* aPseudoTag,
00668                                 nsStyleContext* aParentContext)
00669 {
00670   NS_ENSURE_FALSE(mInShutdown, nsnull);
00671   
00672   nsStyleContext*  result = nsnull;
00673   nsPresContext *presContext = PresContext();
00674 
00675   NS_ASSERTION(aPseudoTag, "must have pseudo tag");
00676   NS_ASSERTION(!aParentContent ||
00677                aParentContent->IsContentOfType(nsIContent::eELEMENT),
00678                "content (if non-null) must be element");
00679 
00680   if (aPseudoTag && presContext) {
00681     if (mRuleProcessors[eAgentSheet]        ||
00682         mRuleProcessors[ePresHintSheet]     ||
00683         mRuleProcessors[eUserSheet]         ||
00684         mRuleProcessors[eHTMLPresHintSheet] ||
00685         mRuleProcessors[eDocSheet]          ||
00686         mRuleProcessors[eStyleAttrSheet]    ||
00687         mRuleProcessors[eOverrideSheet]) {
00688       PseudoRuleProcessorData data(presContext, aParentContent, aPseudoTag,
00689                                    nsnull, mRuleWalker);
00690       FileRules(EnumPseudoRulesMatching, &data);
00691 
00692       if (!mRuleWalker->AtRoot())
00693         result = GetContext(presContext, aParentContext, aPseudoTag).get();
00694 
00695       // Now reset the walker back to the root of the tree.
00696       mRuleWalker->Reset();
00697     }
00698   }
00699 
00700   // For :before and :after pseudo-elements, having display: none or no
00701   // 'content' property is equivalent to not having the pseudo-element
00702   // at all.
00703   if (result &&
00704       (aPseudoTag == nsCSSPseudoElements::before ||
00705        aPseudoTag == nsCSSPseudoElements::after)) {
00706     const nsStyleDisplay *display = result->GetStyleDisplay();
00707     const nsStyleContent *content = result->GetStyleContent();
00708     // XXXldb What is contentCount for |content: ""|?
00709     if (display->mDisplay == NS_STYLE_DISPLAY_NONE ||
00710         content->ContentCount() == 0) {
00711       result->Release();
00712       result = nsnull;
00713     }
00714   }
00715   
00716   return result;
00717 }
00718 
00719 void
00720 nsStyleSet::BeginShutdown(nsPresContext* aPresContext)
00721 {
00722   mInShutdown = 1;
00723   mRoots.Clear(); // no longer valid, since we won't keep it up to date
00724 }
00725 
00726 void
00727 nsStyleSet::Shutdown(nsPresContext* aPresContext)
00728 {
00729   delete mRuleWalker;
00730   mRuleWalker = nsnull;
00731 
00732   mRuleTree->Destroy();
00733   mRuleTree = nsnull;
00734 
00735   mDefaultStyleData.Destroy(0, aPresContext);
00736 }
00737 
00738 static const PRInt32 kGCInterval = 1000;
00739 
00740 void
00741 nsStyleSet::NotifyStyleContextDestroyed(nsPresContext* aPresContext,
00742                                         nsStyleContext* aStyleContext)
00743 {
00744   if (mInShutdown)
00745     return;
00746 
00747   if (!aStyleContext->GetParent()) {
00748     mRoots.RemoveElement(aStyleContext);
00749   }
00750 
00751   if (++mDestroyedCount == kGCInterval) {
00752     mDestroyedCount = 0;
00753 
00754     // Mark the style context tree by marking all roots, which will mark
00755     // all descendants.  This will reach style contexts in the
00756     // undisplayed map and "additional style contexts" since they are
00757     // descendants of the root.
00758     for (PRInt32 i = mRoots.Count() - 1; i >= 0; --i) {
00759       NS_STATIC_CAST(nsStyleContext*,mRoots[i])->Mark();
00760     }
00761 
00762     // Sweep the rule tree.
00763     NS_ASSERTION(mRuleWalker->AtRoot(), "Rule walker should be at root");
00764 #ifdef DEBUG
00765     PRBool deleted =
00766 #endif
00767       mRuleTree->Sweep();
00768 
00769     NS_ASSERTION(!deleted, "Root node must not be gc'd");
00770   }
00771 }
00772 
00773 void
00774 nsStyleSet::ClearStyleData(nsPresContext* aPresContext)
00775 {
00776   mRuleTree->ClearStyleData();
00777 
00778   for (PRInt32 i = mRoots.Count() - 1; i >= 0; --i) {
00779     NS_STATIC_CAST(nsStyleContext*,mRoots[i])->ClearStyleData(aPresContext);
00780   }
00781 }
00782 
00783 already_AddRefed<nsStyleContext>
00784 nsStyleSet::ReParentStyleContext(nsPresContext* aPresContext,
00785                                  nsStyleContext* aStyleContext, 
00786                                  nsStyleContext* aNewParentContext)
00787 {
00788   NS_ASSERTION(aPresContext, "must have pres context");
00789   NS_ASSERTION(aStyleContext, "must have style context");
00790 
00791   if (aPresContext && aStyleContext) {
00792     if (aStyleContext->GetParent() == aNewParentContext) {
00793       aStyleContext->AddRef();
00794       return aStyleContext;
00795     }
00796     else {  // really a new parent
00797       nsIAtom* pseudoTag = aStyleContext->GetPseudoType();
00798 
00799       nsRuleNode* ruleNode = aStyleContext->GetRuleNode();
00800       mRuleWalker->SetCurrentNode(ruleNode);
00801 
00802       already_AddRefed<nsStyleContext> result =
00803           GetContext(aPresContext, aNewParentContext, pseudoTag);
00804       mRuleWalker->Reset();
00805       return result;
00806     }
00807   }
00808   return nsnull;
00809 }
00810 
00811 struct StatefulData : public StateRuleProcessorData {
00812   StatefulData(nsPresContext* aPresContext,
00813                nsIContent* aContent, PRInt32 aStateMask)
00814     : StateRuleProcessorData(aPresContext, aContent, aStateMask),
00815       mHint(nsReStyleHint(0))
00816   {}
00817   nsReStyleHint   mHint;
00818 }; 
00819 
00820 static PRBool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
00821                                     void *aData)
00822 {
00823   StatefulData* data = (StatefulData*)aData;
00824   nsReStyleHint hint;
00825   aProcessor->HasStateDependentStyle(data, &hint);
00826   data->mHint = nsReStyleHint(data->mHint | hint);
00827   return PR_TRUE; // continue
00828 }
00829 
00830 // Test if style is dependent on content state
00831 nsReStyleHint
00832 nsStyleSet::HasStateDependentStyle(nsPresContext* aPresContext,
00833                                    nsIContent*     aContent,
00834                                    PRInt32         aStateMask)
00835 {
00836   nsReStyleHint result = nsReStyleHint(0);
00837 
00838   if (aContent->IsContentOfType(nsIContent::eELEMENT) &&
00839       (mRuleProcessors[eAgentSheet]        ||
00840        mRuleProcessors[ePresHintSheet]     ||
00841        mRuleProcessors[eUserSheet]         ||
00842        mRuleProcessors[eHTMLPresHintSheet] ||
00843        mRuleProcessors[eDocSheet]          ||
00844        mRuleProcessors[eStyleAttrSheet]    ||
00845        mRuleProcessors[eOverrideSheet])) {
00846     StatefulData data(aPresContext, aContent, aStateMask);
00847     WalkRuleProcessors(SheetHasStatefulStyle, &data);
00848     result = data.mHint;
00849   }
00850 
00851   return result;
00852 }
00853 
00854 struct AttributeData : public AttributeRuleProcessorData {
00855   AttributeData(nsPresContext* aPresContext,
00856                 nsIContent* aContent, nsIAtom* aAttribute, PRInt32 aModType)
00857     : AttributeRuleProcessorData(aPresContext, aContent, aAttribute, aModType),
00858       mHint(nsReStyleHint(0))
00859   {}
00860   nsReStyleHint   mHint;
00861 }; 
00862 
00863 static PRBool
00864 SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
00865 {
00866   AttributeData* data = (AttributeData*)aData;
00867   nsReStyleHint hint;
00868   aProcessor->HasAttributeDependentStyle(data, &hint);
00869   data->mHint = nsReStyleHint(data->mHint | hint);
00870   return PR_TRUE; // continue
00871 }
00872 
00873 // Test if style is dependent on content state
00874 nsReStyleHint
00875 nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext,
00876                                        nsIContent*     aContent,
00877                                        nsIAtom*        aAttribute,
00878                                        PRInt32         aModType)
00879 {
00880   nsReStyleHint result = nsReStyleHint(0);
00881 
00882   if (aContent->IsContentOfType(nsIContent::eELEMENT) &&
00883       (mRuleProcessors[eAgentSheet]        ||
00884        mRuleProcessors[ePresHintSheet]     ||
00885        mRuleProcessors[eUserSheet]         ||
00886        mRuleProcessors[eHTMLPresHintSheet] ||
00887        mRuleProcessors[eDocSheet]          ||
00888        mRuleProcessors[eStyleAttrSheet]    ||
00889        mRuleProcessors[eOverrideSheet])) {
00890     AttributeData data(aPresContext, aContent, aAttribute, aModType);
00891     WalkRuleProcessors(SheetHasAttributeStyle, &data);
00892     result = data.mHint;
00893   }
00894 
00895   return result;
00896 }