CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / layout / style / nsStyleSet.cpp
blob893bc598d5aa2c858ab453f78aff96879fbb8294
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Daniel Glazman <glazman@netscape.com>
24 * Brian Ryner <bryner@brianryner.com>
25 * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * the container for the style sheets that apply to a presentation, and
43 * the internal API that the style system exposes for creating (and
44 * potentially re-creating) style contexts
47 #include "nsStyleSet.h"
48 #include "nsNetUtil.h"
49 #include "nsCSSStyleSheet.h"
50 #include "nsIDocument.h"
51 #include "nsRuleWalker.h"
52 #include "nsStyleContext.h"
53 #include "nsICSSStyleRule.h"
54 #include "nsCSSAnonBoxes.h"
55 #include "nsCSSPseudoElements.h"
56 #include "nsCSSRuleProcessor.h"
57 #include "nsIContent.h"
58 #include "nsIFrame.h"
59 #include "nsContentUtils.h"
60 #include "nsRuleProcessorData.h"
61 #include "nsTransitionManager.h"
62 #include "nsIEventStateManager.h"
63 #include "mozilla/dom/Element.h"
65 using namespace mozilla::dom;
67 NS_IMPL_ISUPPORTS1(nsEmptyStyleRule, nsIStyleRule)
69 /* virtual */ void
70 nsEmptyStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
74 #ifdef DEBUG
75 /* virtual */ void
76 nsEmptyStyleRule::List(FILE* out, PRInt32 aIndent) const
79 #endif
81 static const nsStyleSet::sheetType gCSSSheetTypes[] = {
82 nsStyleSet::eAgentSheet,
83 nsStyleSet::eUserSheet,
84 nsStyleSet::eDocSheet,
85 nsStyleSet::eOverrideSheet
88 nsStyleSet::nsStyleSet()
89 : mRuleTree(nsnull),
90 mUnusedRuleNodeCount(0),
91 mBatching(0),
92 mInShutdown(PR_FALSE),
93 mAuthorStyleDisabled(PR_FALSE),
94 mInReconstruct(PR_FALSE),
95 mDirty(0)
99 nsresult
100 nsStyleSet::Init(nsPresContext *aPresContext)
102 mFirstLineRule = new nsEmptyStyleRule;
103 mFirstLetterRule = new nsEmptyStyleRule;
104 if (!mFirstLineRule || !mFirstLetterRule) {
105 return NS_ERROR_OUT_OF_MEMORY;
108 if (!BuildDefaultStyleData(aPresContext)) {
109 mDefaultStyleData.Destroy(0, aPresContext);
110 return NS_ERROR_OUT_OF_MEMORY;
113 mRuleTree = nsRuleNode::CreateRootNode(aPresContext);
114 if (!mRuleTree) {
115 mDefaultStyleData.Destroy(0, aPresContext);
116 return NS_ERROR_OUT_OF_MEMORY;
119 GatherRuleProcessors(eTransitionSheet);
121 return NS_OK;
124 nsresult
125 nsStyleSet::BeginReconstruct()
127 NS_ASSERTION(!mInReconstruct, "Unmatched begin/end?");
128 NS_ASSERTION(mRuleTree, "Reconstructing before first construction?");
130 // Create a new rule tree root
131 nsRuleNode* newTree =
132 nsRuleNode::CreateRootNode(mRuleTree->GetPresContext());
133 if (!newTree)
134 return NS_ERROR_OUT_OF_MEMORY;
136 // Save the old rule tree so we can destroy it later
137 if (!mOldRuleTrees.AppendElement(mRuleTree)) {
138 newTree->Destroy();
139 return NS_ERROR_OUT_OF_MEMORY;
142 // We need to keep mRoots so that the rule tree GC will only free the
143 // rule trees that really aren't referenced anymore (which should be
144 // all of them, if there are no bugs in reresolution code).
146 mInReconstruct = PR_TRUE;
147 mRuleTree = newTree;
149 return NS_OK;
152 void
153 nsStyleSet::EndReconstruct()
155 NS_ASSERTION(mInReconstruct, "Unmatched begin/end?");
156 mInReconstruct = PR_FALSE;
157 #ifdef DEBUG
158 for (PRInt32 i = mRoots.Length() - 1; i >= 0; --i) {
159 nsRuleNode *n = mRoots[i]->GetRuleNode();
160 while (n->GetParent()) {
161 n = n->GetParent();
163 // Since nsStyleContext's mParent and mRuleNode are immutable, and
164 // style contexts own their parents, and nsStyleContext asserts in
165 // its constructor that the style context and its parent are in the
166 // same rule tree, we don't need to check any of the children of
167 // mRoots; we only need to check the rule nodes of mRoots
168 // themselves.
170 NS_ASSERTION(n == mRuleTree, "style context has old rule node");
172 #endif
173 // This *should* destroy the only element of mOldRuleTrees, but in
174 // case of some bugs (which would trigger the above assertions), it
175 // won't.
176 GCRuleTrees();
179 void
180 nsStyleSet::SetQuirkStyleSheet(nsIStyleSheet* aQuirkStyleSheet)
182 NS_ASSERTION(aQuirkStyleSheet, "Must have quirk sheet if this is called");
183 NS_ASSERTION(!mQuirkStyleSheet, "Multiple calls to SetQuirkStyleSheet?");
184 NS_ASSERTION(mSheets[eAgentSheet].IndexOf(aQuirkStyleSheet) != -1,
185 "Quirk style sheet not one of our agent sheets?");
186 mQuirkStyleSheet = aQuirkStyleSheet;
189 nsresult
190 nsStyleSet::GatherRuleProcessors(sheetType aType)
192 mRuleProcessors[aType] = nsnull;
193 if (mAuthorStyleDisabled && (aType == eDocSheet ||
194 aType == ePresHintSheet ||
195 aType == eStyleAttrSheet)) {
196 //don't regather if this level is disabled
197 return NS_OK;
199 if (aType == eTransitionSheet) {
200 // We have no sheet for the transitions level; just a rule
201 // processor. (XXX: We should probably do this for the other
202 // non-CSS levels too!)
203 mRuleProcessors[aType] = PresContext()->TransitionManager();
204 return NS_OK;
206 if (mSheets[aType].Count()) {
207 switch (aType) {
208 case eAgentSheet:
209 case eUserSheet:
210 case eDocSheet:
211 case eOverrideSheet: {
212 // levels containing CSS stylesheets
213 nsCOMArray<nsIStyleSheet>& sheets = mSheets[aType];
214 nsTArray<nsRefPtr<nsCSSStyleSheet> > cssSheets(sheets.Count());
215 for (PRInt32 i = 0, i_end = sheets.Count(); i < i_end; ++i) {
216 nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(sheets[i]);
217 NS_ASSERTION(cssSheet, "not a CSS sheet");
218 cssSheets.AppendElement(cssSheet);
220 mRuleProcessors[aType] = new nsCSSRuleProcessor(cssSheets,
221 PRUint8(aType));
222 } break;
224 default:
225 // levels containing non-CSS stylesheets
226 NS_ASSERTION(mSheets[aType].Count() == 1, "only one sheet per level");
227 mRuleProcessors[aType] = do_QueryInterface(mSheets[aType][0]);
228 break;
232 return NS_OK;
235 nsresult
236 nsStyleSet::AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
238 NS_PRECONDITION(aSheet, "null arg");
239 NS_ASSERTION(aSheet->IsApplicable(),
240 "Inapplicable sheet being placed in style set");
241 mSheets[aType].RemoveObject(aSheet);
242 if (!mSheets[aType].AppendObject(aSheet))
243 return NS_ERROR_OUT_OF_MEMORY;
245 if (!mBatching)
246 return GatherRuleProcessors(aType);
248 mDirty |= 1 << aType;
249 return NS_OK;
252 nsresult
253 nsStyleSet::PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
255 NS_PRECONDITION(aSheet, "null arg");
256 NS_ASSERTION(aSheet->IsApplicable(),
257 "Inapplicable sheet being placed in style set");
258 mSheets[aType].RemoveObject(aSheet);
259 if (!mSheets[aType].InsertObjectAt(aSheet, 0))
260 return NS_ERROR_OUT_OF_MEMORY;
262 if (!mBatching)
263 return GatherRuleProcessors(aType);
265 mDirty |= 1 << aType;
266 return NS_OK;
269 nsresult
270 nsStyleSet::RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
272 NS_PRECONDITION(aSheet, "null arg");
273 NS_ASSERTION(aSheet->IsComplete(),
274 "Incomplete sheet being removed from style set");
275 mSheets[aType].RemoveObject(aSheet);
276 if (!mBatching)
277 return GatherRuleProcessors(aType);
279 mDirty |= 1 << aType;
280 return NS_OK;
283 nsresult
284 nsStyleSet::ReplaceSheets(sheetType aType,
285 const nsCOMArray<nsIStyleSheet> &aNewSheets)
287 mSheets[aType].Clear();
288 if (!mSheets[aType].AppendObjects(aNewSheets))
289 return NS_ERROR_OUT_OF_MEMORY;
291 if (!mBatching)
292 return GatherRuleProcessors(aType);
294 mDirty |= 1 << aType;
295 return NS_OK;
298 PRBool
299 nsStyleSet::GetAuthorStyleDisabled()
301 return mAuthorStyleDisabled;
304 nsresult
305 nsStyleSet::SetAuthorStyleDisabled(PRBool aStyleDisabled)
307 if (aStyleDisabled == !mAuthorStyleDisabled) {
308 mAuthorStyleDisabled = aStyleDisabled;
309 BeginUpdate();
310 mDirty |= 1 << eDocSheet |
311 1 << ePresHintSheet |
312 1 << eStyleAttrSheet;
313 return EndUpdate();
315 return NS_OK;
318 // -------- Doc Sheets
320 nsresult
321 nsStyleSet::AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument)
323 NS_PRECONDITION(aSheet && aDocument, "null arg");
324 NS_ASSERTION(aSheet->IsApplicable(),
325 "Inapplicable sheet being placed in style set");
327 nsCOMArray<nsIStyleSheet>& docSheets = mSheets[eDocSheet];
329 docSheets.RemoveObject(aSheet);
330 // lowest index first
331 PRInt32 newDocIndex = aDocument->GetIndexOfStyleSheet(aSheet);
332 PRInt32 count = docSheets.Count();
333 PRInt32 index;
334 for (index = 0; index < count; index++) {
335 nsIStyleSheet* sheet = docSheets.ObjectAt(index);
336 PRInt32 sheetDocIndex = aDocument->GetIndexOfStyleSheet(sheet);
337 if (sheetDocIndex > newDocIndex)
338 break;
340 if (!docSheets.InsertObjectAt(aSheet, index))
341 return NS_ERROR_OUT_OF_MEMORY;
342 if (!mBatching)
343 return GatherRuleProcessors(eDocSheet);
345 mDirty |= 1 << eDocSheet;
346 return NS_OK;
349 // Batching
350 void
351 nsStyleSet::BeginUpdate()
353 ++mBatching;
356 nsresult
357 nsStyleSet::EndUpdate()
359 NS_ASSERTION(mBatching > 0, "Unbalanced EndUpdate");
360 if (--mBatching) {
361 // We're not completely done yet.
362 return NS_OK;
365 for (int i = 0; i < eSheetTypeCount; ++i) {
366 if (mDirty & (1 << i)) {
367 nsresult rv = GatherRuleProcessors(sheetType(i));
368 NS_ENSURE_SUCCESS(rv, rv);
372 mDirty = 0;
373 return NS_OK;
376 void
377 nsStyleSet::EnableQuirkStyleSheet(PRBool aEnable)
379 #ifdef DEBUG
380 PRBool oldEnabled;
382 nsCOMPtr<nsIDOMCSSStyleSheet> domSheet =
383 do_QueryInterface(mQuirkStyleSheet);
384 domSheet->GetDisabled(&oldEnabled);
385 oldEnabled = !oldEnabled;
387 #endif
388 mQuirkStyleSheet->SetEnabled(aEnable);
389 #ifdef DEBUG
390 // This should always be OK, since SetEnabled should call
391 // ClearRuleCascades.
392 // Note that we can hit this codepath multiple times when document.open()
393 // (potentially implied) happens multiple times.
394 if (mRuleProcessors[eAgentSheet] && aEnable != oldEnabled) {
395 static_cast<nsCSSRuleProcessor*>(static_cast<nsIStyleRuleProcessor*>(
396 mRuleProcessors[eAgentSheet]))->AssertQuirksChangeOK();
398 #endif
401 template<class T>
402 static PRBool
403 EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
405 T* data = static_cast<T*>(aData);
406 aProcessor->RulesMatching(data);
407 return PR_TRUE;
411 * |GetContext| implements sharing of style contexts (not just the data
412 * on the rule nodes) between siblings and cousins of the same
413 * generation. (It works for cousins of the same generation since
414 * |aParentContext| could itself be a shared context.)
416 already_AddRefed<nsStyleContext>
417 nsStyleSet::GetContext(nsStyleContext* aParentContext,
418 nsRuleNode* aRuleNode,
419 // aVisitedRuleNode may be null; if it is null
420 // it means that we don't need to force creation
421 // of a StyleIfVisited. (But if we make one
422 // because aParentContext has one, then aRuleNode
423 // should be used.)
424 nsRuleNode* aVisitedRuleNode,
425 PRBool aIsLink,
426 PRBool aIsVisitedLink,
427 nsIAtom* aPseudoTag,
428 nsCSSPseudoElements::Type aPseudoType)
430 NS_PRECONDITION((!aPseudoTag &&
431 aPseudoType ==
432 nsCSSPseudoElements::ePseudo_NotPseudoElement) ||
433 (aPseudoTag &&
434 nsCSSPseudoElements::GetPseudoType(aPseudoTag) ==
435 aPseudoType),
436 "Pseudo mismatch");
438 if (aVisitedRuleNode == aRuleNode) {
439 // No need to force creation of a visited style in this case.
440 aVisitedRuleNode = nsnull;
443 // Ensure |aVisitedRuleNode != nsnull| corresponds to the need to
444 // create an if-visited style context, and that in that case, we have
445 // parentIfVisited set correctly.
446 nsStyleContext *parentIfVisited =
447 aParentContext ? aParentContext->GetStyleIfVisited() : nsnull;
448 if (parentIfVisited) {
449 if (!aVisitedRuleNode) {
450 aVisitedRuleNode = aRuleNode;
452 } else {
453 if (aVisitedRuleNode) {
454 parentIfVisited = aParentContext;
458 if (aIsLink) {
459 // If this node is a link, we want its visited's style context's
460 // parent to be the regular style context of its parent, because
461 // only the visitedness of the relevant link should influence style.
462 parentIfVisited = aParentContext;
465 nsRefPtr<nsStyleContext> result;
466 if (aParentContext)
467 result = aParentContext->FindChildWithRules(aPseudoTag, aRuleNode,
468 aVisitedRuleNode,
469 aIsVisitedLink);
471 #ifdef NOISY_DEBUG
472 if (result)
473 fprintf(stdout, "--- SharedSC %d ---\n", ++gSharedCount);
474 else
475 fprintf(stdout, "+++ NewSC %d +++\n", ++gNewCount);
476 #endif
478 if (!result) {
479 result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType,
480 aRuleNode, PresContext());
481 if (!result)
482 return nsnull;
483 if (aVisitedRuleNode) {
484 nsRefPtr<nsStyleContext> resultIfVisited =
485 NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType,
486 aVisitedRuleNode, PresContext());
487 if (!resultIfVisited) {
488 return nsnull;
490 if (!parentIfVisited) {
491 mRoots.AppendElement(resultIfVisited);
493 resultIfVisited->SetIsStyleIfVisited();
494 result->SetStyleIfVisited(resultIfVisited.forget());
496 PRBool relevantLinkVisited =
497 aIsLink ? aIsVisitedLink
498 : (aParentContext && aParentContext->RelevantLinkVisited());
499 if (relevantLinkVisited) {
500 result->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED);
503 if (!aParentContext)
504 mRoots.AppendElement(result);
506 else {
507 NS_ASSERTION(result->GetPseudoType() == aPseudoType, "Unexpected type");
508 NS_ASSERTION(result->GetPseudo() == aPseudoTag, "Unexpected pseudo");
511 return result.forget();
514 void
515 nsStyleSet::AddImportantRules(nsRuleNode* aCurrLevelNode,
516 nsRuleNode* aLastPrevLevelNode,
517 nsRuleWalker* aRuleWalker)
519 NS_ASSERTION(aCurrLevelNode &&
520 aCurrLevelNode != aLastPrevLevelNode, "How did we get here?");
522 nsAutoTArray<nsIStyleRule*, 16> importantRules;
523 for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
524 node = node->GetParent()) {
525 // We guarantee that we never walk the root node here, so no need
526 // to null-check GetRule().
527 nsIStyleRule* impRule = node->GetRule()->GetImportantRule();
528 if (impRule)
529 importantRules.AppendElement(impRule);
532 NS_ASSERTION(importantRules.Length() != 0,
533 "Why did we think there were important rules?");
535 for (PRUint32 i = importantRules.Length(); i-- != 0; ) {
536 aRuleWalker->Forward(importantRules[i]);
540 #ifdef DEBUG
541 void
542 nsStyleSet::AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
543 nsRuleNode* aLastPrevLevelNode)
545 if (!aCurrLevelNode)
546 return;
548 for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
549 node = node->GetParent()) {
550 nsIStyleRule* rule = node->GetRule();
551 if (rule) {
552 NS_ASSERTION(!rule->GetImportantRule(), "Unexpected important rule");
557 void
558 nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
559 nsRuleNode* aLastPrevLevelNode)
561 if (!aCurrLevelNode)
562 return;
564 for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
565 node = node->GetParent()) {
566 nsIStyleRule *rule = node->GetRule();
567 nsCOMPtr<nsICSSStyleRule> cssRule(do_QueryInterface(rule));
568 NS_ASSERTION(!cssRule || !cssRule->Selector(), "Unexpected CSS rule");
571 #endif
573 // Enumerate the rules in a way that cares about the order of the rules.
574 void
575 nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
576 void* aData, nsIContent* aContent,
577 nsRuleWalker* aRuleWalker)
579 // Cascading order:
580 // [least important]
581 // 1. UA normal rules = Agent normal
582 // 2. User normal rules = User normal
583 // 3. Presentation hints = PresHint normal
584 // 4. Author normal rules = Document normal
585 // 5. Override normal rules = Override normal
586 // 6. Author !important rules = Document !important
587 // 7. Override !important rules = Override !important
588 // 8. User !important rules = User !important
589 // 9. UA !important rules = Agent !important
590 // [most important]
592 aRuleWalker->SetLevel(eAgentSheet, PR_FALSE, PR_TRUE);
593 if (mRuleProcessors[eAgentSheet])
594 (*aCollectorFunc)(mRuleProcessors[eAgentSheet], aData);
595 nsRuleNode* lastAgentRN = aRuleWalker->CurrentNode();
596 PRBool haveImportantUARules = !aRuleWalker->GetCheckForImportantRules();
598 aRuleWalker->SetLevel(eUserSheet, PR_FALSE, PR_TRUE);
599 PRBool skipUserStyles =
600 aContent && aContent->IsInNativeAnonymousSubtree();
601 if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
602 (*aCollectorFunc)(mRuleProcessors[eUserSheet], aData);
603 nsRuleNode* lastUserRN = aRuleWalker->CurrentNode();
604 PRBool haveImportantUserRules = !aRuleWalker->GetCheckForImportantRules();
606 aRuleWalker->SetLevel(ePresHintSheet, PR_FALSE, PR_FALSE);
607 if (mRuleProcessors[ePresHintSheet])
608 (*aCollectorFunc)(mRuleProcessors[ePresHintSheet], aData);
609 nsRuleNode* lastPresHintRN = aRuleWalker->CurrentNode();
611 aRuleWalker->SetLevel(eDocSheet, PR_FALSE, PR_TRUE);
612 PRBool cutOffInheritance = PR_FALSE;
613 if (mBindingManager && aContent) {
614 // We can supply additional document-level sheets that should be walked.
615 mBindingManager->WalkRules(aCollectorFunc,
616 static_cast<RuleProcessorData*>(aData),
617 &cutOffInheritance);
619 if (!skipUserStyles && !cutOffInheritance &&
620 mRuleProcessors[eDocSheet]) // NOTE: different
621 (*aCollectorFunc)(mRuleProcessors[eDocSheet], aData);
622 aRuleWalker->SetLevel(eStyleAttrSheet, PR_FALSE,
623 aRuleWalker->GetCheckForImportantRules());
624 if (mRuleProcessors[eStyleAttrSheet])
625 (*aCollectorFunc)(mRuleProcessors[eStyleAttrSheet], aData);
626 nsRuleNode* lastDocRN = aRuleWalker->CurrentNode();
627 PRBool haveImportantDocRules = !aRuleWalker->GetCheckForImportantRules();
629 aRuleWalker->SetLevel(eOverrideSheet, PR_FALSE, PR_TRUE);
630 if (mRuleProcessors[eOverrideSheet])
631 (*aCollectorFunc)(mRuleProcessors[eOverrideSheet], aData);
632 nsRuleNode* lastOvrRN = aRuleWalker->CurrentNode();
633 PRBool haveImportantOverrideRules = !aRuleWalker->GetCheckForImportantRules();
635 if (haveImportantDocRules) {
636 aRuleWalker->SetLevel(eDocSheet, PR_TRUE, PR_FALSE);
637 AddImportantRules(lastDocRN, lastPresHintRN, aRuleWalker); // doc
639 #ifdef DEBUG
640 else {
641 AssertNoImportantRules(lastDocRN, lastPresHintRN);
643 #endif
645 if (haveImportantOverrideRules) {
646 aRuleWalker->SetLevel(eOverrideSheet, PR_TRUE, PR_FALSE);
647 AddImportantRules(lastOvrRN, lastDocRN, aRuleWalker); // override
649 #ifdef DEBUG
650 else {
651 AssertNoImportantRules(lastOvrRN, lastDocRN);
653 #endif
655 #ifdef DEBUG
656 AssertNoCSSRules(lastPresHintRN, lastUserRN);
657 AssertNoImportantRules(lastPresHintRN, lastUserRN); // preshints
658 #endif
660 if (haveImportantUserRules) {
661 aRuleWalker->SetLevel(eUserSheet, PR_TRUE, PR_FALSE);
662 AddImportantRules(lastUserRN, lastAgentRN, aRuleWalker); //user
664 #ifdef DEBUG
665 else {
666 AssertNoImportantRules(lastUserRN, lastAgentRN);
668 #endif
670 if (haveImportantUARules) {
671 aRuleWalker->SetLevel(eAgentSheet, PR_TRUE, PR_FALSE);
672 AddImportantRules(lastAgentRN, mRuleTree, aRuleWalker); //agent
674 #ifdef DEBUG
675 else {
676 AssertNoImportantRules(lastAgentRN, mRuleTree);
678 #endif
680 #ifdef DEBUG
681 nsRuleNode *lastImportantRN = aRuleWalker->CurrentNode();
682 #endif
683 aRuleWalker->SetLevel(eTransitionSheet, PR_FALSE, PR_FALSE);
684 (*aCollectorFunc)(mRuleProcessors[eTransitionSheet], aData);
685 #ifdef DEBUG
686 AssertNoCSSRules(aRuleWalker->CurrentNode(), lastImportantRN);
687 AssertNoImportantRules(aRuleWalker->CurrentNode(), lastImportantRN);
688 #endif
692 // Enumerate all the rules in a way that doesn't care about the order
693 // of the rules and doesn't walk !important-rules.
694 void
695 nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
696 RuleProcessorData* aData,
697 PRBool aWalkAllXBLStylesheets)
699 if (mRuleProcessors[eAgentSheet])
700 (*aFunc)(mRuleProcessors[eAgentSheet], aData);
702 PRBool skipUserStyles = aData->mElement->IsInNativeAnonymousSubtree();
703 if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
704 (*aFunc)(mRuleProcessors[eUserSheet], aData);
706 if (mRuleProcessors[ePresHintSheet])
707 (*aFunc)(mRuleProcessors[ePresHintSheet], aData);
709 PRBool cutOffInheritance = PR_FALSE;
710 if (mBindingManager) {
711 // We can supply additional document-level sheets that should be walked.
712 if (aWalkAllXBLStylesheets) {
713 mBindingManager->WalkAllRules(aFunc, aData);
714 } else {
715 mBindingManager->WalkRules(aFunc, aData, &cutOffInheritance);
718 if (!skipUserStyles && !cutOffInheritance &&
719 mRuleProcessors[eDocSheet]) // NOTE: different
720 (*aFunc)(mRuleProcessors[eDocSheet], aData);
721 if (mRuleProcessors[eStyleAttrSheet])
722 (*aFunc)(mRuleProcessors[eStyleAttrSheet], aData);
723 if (mRuleProcessors[eOverrideSheet])
724 (*aFunc)(mRuleProcessors[eOverrideSheet], aData);
725 (*aFunc)(mRuleProcessors[eTransitionSheet], aData);
728 PRBool nsStyleSet::BuildDefaultStyleData(nsPresContext* aPresContext)
730 NS_ASSERTION(!mDefaultStyleData.mResetData &&
731 !mDefaultStyleData.mInheritedData,
732 "leaking default style data");
733 mDefaultStyleData.mResetData = new (aPresContext) nsResetStyleData;
734 if (!mDefaultStyleData.mResetData)
735 return PR_FALSE;
736 mDefaultStyleData.mInheritedData = new (aPresContext) nsInheritedStyleData;
737 if (!mDefaultStyleData.mInheritedData)
738 return PR_FALSE;
740 #define SSARG_PRESCONTEXT aPresContext
742 #define CREATE_DATA(name, type, args) \
743 if (!(mDefaultStyleData.m##type##Data->m##name##Data = \
744 new (aPresContext) nsStyle##name args)) \
745 return PR_FALSE;
747 #define STYLE_STRUCT_INHERITED(name, checkdata_cb, ctor_args) \
748 CREATE_DATA(name, Inherited, ctor_args)
749 #define STYLE_STRUCT_RESET(name, checkdata_cb, ctor_args) \
750 CREATE_DATA(name, Reset, ctor_args)
752 #include "nsStyleStructList.h"
754 #undef STYLE_STRUCT_INHERITED
755 #undef STYLE_STRUCT_RESET
756 #undef SSARG_PRESCONTEXT
758 return PR_TRUE;
761 already_AddRefed<nsStyleContext>
762 nsStyleSet::ResolveStyleFor(Element* aElement,
763 nsStyleContext* aParentContext)
765 NS_ENSURE_FALSE(mInShutdown, nsnull);
766 NS_ASSERTION(aElement, "aElement must not be null");
768 nsRuleWalker ruleWalker(mRuleTree);
769 ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker);
770 FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
771 &ruleWalker);
773 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
774 nsRuleNode *visitedRuleNode = nsnull;
776 if (ruleWalker.HaveRelevantLink()) {
777 ruleWalker.ResetForVisitedMatching();
778 FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
779 &ruleWalker);
780 visitedRuleNode = ruleWalker.CurrentNode();
783 return GetContext(aParentContext, ruleNode, visitedRuleNode,
784 data.IsLink(),
785 data.ContentState().HasState(NS_EVENT_STATE_VISITED),
786 nsnull, nsCSSPseudoElements::ePseudo_NotPseudoElement);
789 already_AddRefed<nsStyleContext>
790 nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
791 const nsCOMArray<nsIStyleRule> &aRules)
793 NS_ENSURE_FALSE(mInShutdown, nsnull);
795 nsRuleWalker ruleWalker(mRuleTree);
796 // FIXME: Perhaps this should be passed in, but it probably doesn't
797 // matter.
798 ruleWalker.SetLevel(eDocSheet, PR_FALSE, PR_FALSE);
799 for (PRInt32 i = 0; i < aRules.Count(); i++) {
800 ruleWalker.Forward(aRules.ObjectAt(i));
803 return GetContext(aParentContext, ruleWalker.CurrentNode(), nsnull,
804 PR_FALSE, PR_FALSE,
805 nsnull, nsCSSPseudoElements::ePseudo_NotPseudoElement);
808 already_AddRefed<nsStyleContext>
809 nsStyleSet::ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
810 const nsCOMArray<nsIStyleRule> &aRules)
812 NS_ENSURE_FALSE(mInShutdown, nsnull);
814 nsRuleWalker ruleWalker(mRuleTree);
815 ruleWalker.SetCurrentNode(aBaseContext->GetRuleNode());
816 // FIXME: Perhaps this should be passed in, but it probably doesn't
817 // matter.
818 ruleWalker.SetLevel(eDocSheet, PR_FALSE, PR_FALSE);
819 for (PRInt32 i = 0; i < aRules.Count(); i++) {
820 ruleWalker.Forward(aRules.ObjectAt(i));
823 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
824 nsRuleNode *visitedRuleNode = nsnull;
826 if (aBaseContext->GetStyleIfVisited()) {
827 ruleWalker.SetCurrentNode(aBaseContext->GetStyleIfVisited()->GetRuleNode());
828 for (PRInt32 i = 0; i < aRules.Count(); i++) {
829 ruleWalker.Forward(aRules.ObjectAt(i));
831 visitedRuleNode = ruleWalker.CurrentNode();
834 return GetContext(aBaseContext->GetParent(), ruleNode, visitedRuleNode,
835 aBaseContext->IsLinkContext(),
836 aBaseContext->RelevantLinkVisited(),
837 aBaseContext->GetPseudo(),
838 aBaseContext->GetPseudoType());
841 already_AddRefed<nsStyleContext>
842 nsStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext)
844 return GetContext(aParentContext, mRuleTree, nsnull,
845 PR_FALSE, PR_FALSE,
846 nsCSSAnonBoxes::mozNonElement,
847 nsCSSPseudoElements::ePseudo_AnonBox);
850 void
851 nsStyleSet::WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType,
852 nsRuleWalker* aRuleWalker)
854 // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
855 aRuleWalker->SetLevel(eAgentSheet, PR_FALSE, PR_FALSE);
856 if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter)
857 aRuleWalker->Forward(mFirstLetterRule);
858 else if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLine)
859 aRuleWalker->Forward(mFirstLineRule);
862 already_AddRefed<nsStyleContext>
863 nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
864 nsCSSPseudoElements::Type aType,
865 nsStyleContext* aParentContext)
867 NS_ENSURE_FALSE(mInShutdown, nsnull);
869 NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
870 "must have pseudo element type");
871 NS_ASSERTION(aParentElement, "Must have parent element");
873 nsRuleWalker ruleWalker(mRuleTree);
874 PseudoElementRuleProcessorData data(PresContext(), aParentElement,
875 &ruleWalker, aType);
876 WalkRestrictionRule(aType, &ruleWalker);
877 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
878 aParentElement, &ruleWalker);
880 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
881 nsRuleNode *visitedRuleNode = nsnull;
883 if (ruleWalker.HaveRelevantLink()) {
884 ruleWalker.ResetForVisitedMatching();
885 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
886 aParentElement, &ruleWalker);
887 visitedRuleNode = ruleWalker.CurrentNode();
890 return GetContext(aParentContext, ruleNode, visitedRuleNode,
891 // For pseudos, |data.IsLink()| being true means that
892 // our parent node is a link.
893 PR_FALSE, PR_FALSE,
894 nsCSSPseudoElements::GetPseudoAtom(aType), aType);
897 already_AddRefed<nsStyleContext>
898 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
899 nsCSSPseudoElements::Type aType,
900 nsStyleContext* aParentContext)
902 NS_ENSURE_FALSE(mInShutdown, nsnull);
904 NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
905 "must have pseudo element type");
906 NS_ASSERTION(aParentElement, "aParentElement must not be null");
908 nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
909 nsRuleWalker ruleWalker(mRuleTree);
910 PseudoElementRuleProcessorData data(PresContext(), aParentElement,
911 &ruleWalker, aType);
912 WalkRestrictionRule(aType, &ruleWalker);
913 // not the root if there was a restriction rule
914 nsRuleNode *adjustedRoot = ruleWalker.CurrentNode();
915 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
916 aParentElement, &ruleWalker);
918 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
919 if (ruleNode == adjustedRoot) {
920 return nsnull;
923 nsRuleNode *visitedRuleNode = nsnull;
925 if (ruleWalker.HaveRelevantLink()) {
926 ruleWalker.ResetForVisitedMatching();
927 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
928 aParentElement, &ruleWalker);
929 visitedRuleNode = ruleWalker.CurrentNode();
932 nsRefPtr<nsStyleContext> result =
933 GetContext(aParentContext, ruleNode, visitedRuleNode,
934 // For pseudos, |data.IsLink()| being true means that
935 // our parent node is a link.
936 PR_FALSE, PR_FALSE,
937 pseudoTag, aType);
939 // For :before and :after pseudo-elements, having display: none or no
940 // 'content' property is equivalent to not having the pseudo-element
941 // at all.
942 if (result &&
943 (pseudoTag == nsCSSPseudoElements::before ||
944 pseudoTag == nsCSSPseudoElements::after)) {
945 const nsStyleDisplay *display = result->GetStyleDisplay();
946 const nsStyleContent *content = result->GetStyleContent();
947 // XXXldb What is contentCount for |content: ""|?
948 if (display->mDisplay == NS_STYLE_DISPLAY_NONE ||
949 content->ContentCount() == 0) {
950 result = nsnull;
954 return result.forget();
957 already_AddRefed<nsStyleContext>
958 nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
959 nsStyleContext* aParentContext)
961 NS_ENSURE_FALSE(mInShutdown, nsnull);
963 #ifdef DEBUG
964 PRBool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag)
965 #ifdef MOZ_XUL
966 && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
967 #endif
969 NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
970 #endif
972 nsRuleWalker ruleWalker(mRuleTree);
973 AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker);
974 FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nsnull,
975 &ruleWalker);
977 return GetContext(aParentContext, ruleWalker.CurrentNode(), nsnull,
978 PR_FALSE, PR_FALSE,
979 aPseudoTag, nsCSSPseudoElements::ePseudo_AnonBox);
982 #ifdef MOZ_XUL
983 already_AddRefed<nsStyleContext>
984 nsStyleSet::ResolveXULTreePseudoStyle(Element* aParentElement,
985 nsIAtom* aPseudoTag,
986 nsStyleContext* aParentContext,
987 nsICSSPseudoComparator* aComparator)
989 NS_ENSURE_FALSE(mInShutdown, nsnull);
991 NS_ASSERTION(aPseudoTag, "must have pseudo tag");
992 NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
993 "Unexpected pseudo");
995 nsRuleWalker ruleWalker(mRuleTree);
996 XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
997 aPseudoTag, aComparator);
998 FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
999 &ruleWalker);
1001 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1002 nsRuleNode *visitedRuleNode = nsnull;
1004 if (ruleWalker.HaveRelevantLink()) {
1005 ruleWalker.ResetForVisitedMatching();
1006 FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data,
1007 aParentElement, &ruleWalker);
1008 visitedRuleNode = ruleWalker.CurrentNode();
1011 return GetContext(aParentContext, ruleNode, visitedRuleNode,
1012 // For pseudos, |data.IsLink()| being true means that
1013 // our parent node is a link.
1014 PR_FALSE, PR_FALSE,
1015 aPseudoTag, nsCSSPseudoElements::ePseudo_XULTree);
1017 #endif
1019 PRBool
1020 nsStyleSet::AppendFontFaceRules(nsPresContext* aPresContext,
1021 nsTArray<nsFontFaceRuleContainer>& aArray)
1023 NS_ENSURE_FALSE(mInShutdown, PR_FALSE);
1025 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gCSSSheetTypes); ++i) {
1026 nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
1027 (mRuleProcessors[gCSSSheetTypes[i]].get());
1028 if (ruleProc && !ruleProc->AppendFontFaceRules(aPresContext, aArray))
1029 return PR_FALSE;
1031 return PR_TRUE;
1034 void
1035 nsStyleSet::BeginShutdown(nsPresContext* aPresContext)
1037 mInShutdown = 1;
1038 mRoots.Clear(); // no longer valid, since we won't keep it up to date
1041 void
1042 nsStyleSet::Shutdown(nsPresContext* aPresContext)
1044 mRuleTree->Destroy();
1045 mRuleTree = nsnull;
1047 // We can have old rule trees either because:
1048 // (1) we failed the assertions in EndReconstruct, or
1049 // (2) we're shutting down within a reconstruct (see bug 462392)
1050 for (PRUint32 i = mOldRuleTrees.Length(); i > 0; ) {
1051 --i;
1052 mOldRuleTrees[i]->Destroy();
1054 mOldRuleTrees.Clear();
1056 mDefaultStyleData.Destroy(0, aPresContext);
1059 static const PRUint32 kGCInterval = 300;
1061 void
1062 nsStyleSet::NotifyStyleContextDestroyed(nsPresContext* aPresContext,
1063 nsStyleContext* aStyleContext)
1065 if (mInShutdown)
1066 return;
1068 // Remove style contexts from mRoots even if mOldRuleTree is non-null. This
1069 // could be a style context from the new ruletree!
1070 if (!aStyleContext->GetParent()) {
1071 mRoots.RemoveElement(aStyleContext);
1074 if (mInReconstruct)
1075 return;
1077 if (mUnusedRuleNodeCount >= kGCInterval) {
1078 GCRuleTrees();
1082 void
1083 nsStyleSet::GCRuleTrees()
1085 mUnusedRuleNodeCount = 0;
1087 // Mark the style context tree by marking all style contexts which
1088 // have no parent, which will mark all descendants. This will reach
1089 // style contexts in the undisplayed map and "additional style
1090 // contexts" since they are descendants of the roots.
1091 for (PRInt32 i = mRoots.Length() - 1; i >= 0; --i) {
1092 mRoots[i]->Mark();
1095 // Sweep the rule tree.
1096 #ifdef DEBUG
1097 PRBool deleted =
1098 #endif
1099 mRuleTree->Sweep();
1100 NS_ASSERTION(!deleted, "Root node must not be gc'd");
1102 // Sweep the old rule trees.
1103 for (PRUint32 i = mOldRuleTrees.Length(); i > 0; ) {
1104 --i;
1105 if (mOldRuleTrees[i]->Sweep()) {
1106 // It was deleted, as it should be.
1107 mOldRuleTrees.RemoveElementAt(i);
1108 } else {
1109 NS_NOTREACHED("old rule tree still referenced");
1114 static inline nsRuleNode*
1115 SkipTransitionRules(nsRuleNode* aRuleNode, Element* aElement, PRBool isPseudo)
1117 nsRuleNode* ruleNode = aRuleNode;
1118 while (!ruleNode->IsRoot() &&
1119 ruleNode->GetLevel() == nsStyleSet::eTransitionSheet) {
1120 ruleNode = ruleNode->GetParent();
1122 if (ruleNode != aRuleNode) {
1123 NS_ASSERTION(aElement, "How can we have transition rules but no element?");
1124 // Need to do an animation restyle, just like
1125 // nsTransitionManager::WalkTransitionRule would.
1126 nsRestyleHint hint = isPseudo ? eRestyle_Subtree : eRestyle_Self;
1127 aRuleNode->GetPresContext()->PresShell()->RestyleForAnimation(aElement,
1128 hint);
1130 return ruleNode;
1133 already_AddRefed<nsStyleContext>
1134 nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
1135 nsStyleContext* aNewParentContext,
1136 Element* aElement)
1138 if (!aStyleContext) {
1139 NS_NOTREACHED("must have style context");
1140 return nsnull;
1143 // This short-circuit is OK because we don't call TryStartingTransition
1144 // during style reresolution if the style context pointer hasn't changed.
1145 if (aStyleContext->GetParent() == aNewParentContext) {
1146 aStyleContext->AddRef();
1147 return aStyleContext;
1150 nsIAtom* pseudoTag = aStyleContext->GetPseudo();
1151 nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType();
1152 nsRuleNode* ruleNode = aStyleContext->GetRuleNode();
1154 // Skip transition rules as needed just like
1155 // nsTransitionManager::WalkTransitionRule would.
1156 PRBool skipTransitionRules = PresContext()->IsProcessingRestyles() &&
1157 !PresContext()->IsProcessingAnimationStyleChange();
1158 if (skipTransitionRules) {
1159 // Make sure that we're not using transition rules for our new style
1160 // context. If we need them, an animation restyle will provide.
1161 ruleNode =
1162 SkipTransitionRules(ruleNode, aElement,
1163 pseudoType !=
1164 nsCSSPseudoElements::ePseudo_NotPseudoElement);
1167 nsRuleNode* visitedRuleNode = nsnull;
1168 nsStyleContext* visitedContext = aStyleContext->GetStyleIfVisited();
1169 // Reparenting a style context just changes where we inherit from,
1170 // not what rules we match or what our DOM looks like. In
1171 // particular, it doesn't change whether this is a style context for
1172 // a link.
1173 if (visitedContext) {
1174 visitedRuleNode = visitedContext->GetRuleNode();
1175 // Again, skip transition rules as needed
1176 if (skipTransitionRules) {
1177 visitedRuleNode =
1178 SkipTransitionRules(visitedRuleNode, aElement,
1179 pseudoType !=
1180 nsCSSPseudoElements::ePseudo_NotPseudoElement);
1184 return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
1185 aStyleContext->IsLinkContext(),
1186 aStyleContext->RelevantLinkVisited(),
1187 pseudoTag, pseudoType);
1190 struct StatefulData : public StateRuleProcessorData {
1191 StatefulData(nsPresContext* aPresContext,
1192 Element* aElement, nsEventStates aStateMask)
1193 : StateRuleProcessorData(aPresContext, aElement, aStateMask),
1194 mHint(nsRestyleHint(0))
1196 nsRestyleHint mHint;
1199 static PRBool SheetHasDocumentStateStyle(nsIStyleRuleProcessor* aProcessor,
1200 void *aData)
1202 StatefulData* data = (StatefulData*)aData;
1203 if (aProcessor->HasDocumentStateDependentStyle(data)) {
1204 data->mHint = eRestyle_Self;
1205 return PR_FALSE; // don't continue
1207 return PR_TRUE; // continue
1210 // Test if style is dependent on a document state.
1211 PRBool
1212 nsStyleSet::HasDocumentStateDependentStyle(nsPresContext* aPresContext,
1213 nsIContent* aContent,
1214 nsEventStates aStateMask)
1216 if (!aContent || !aContent->IsElement())
1217 return PR_FALSE;
1219 StatefulData data(aPresContext, aContent->AsElement(), aStateMask);
1220 WalkRuleProcessors(SheetHasDocumentStateStyle, &data, PR_TRUE);
1221 return data.mHint != 0;
1224 static PRBool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
1225 void *aData)
1227 StatefulData* data = (StatefulData*)aData;
1228 nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
1229 data->mHint = nsRestyleHint(data->mHint | hint);
1230 return PR_TRUE; // continue
1233 // Test if style is dependent on content state
1234 nsRestyleHint
1235 nsStyleSet::HasStateDependentStyle(nsPresContext* aPresContext,
1236 Element* aElement,
1237 nsEventStates aStateMask)
1239 StatefulData data(aPresContext, aElement, aStateMask);
1240 WalkRuleProcessors(SheetHasStatefulStyle, &data, PR_FALSE);
1241 return data.mHint;
1244 struct AttributeData : public AttributeRuleProcessorData {
1245 AttributeData(nsPresContext* aPresContext,
1246 Element* aElement, nsIAtom* aAttribute, PRInt32 aModType,
1247 PRBool aAttrHasChanged)
1248 : AttributeRuleProcessorData(aPresContext, aElement, aAttribute, aModType,
1249 aAttrHasChanged),
1250 mHint(nsRestyleHint(0))
1252 nsRestyleHint mHint;
1255 static PRBool
1256 SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
1258 AttributeData* data = (AttributeData*)aData;
1259 nsRestyleHint hint = aProcessor->HasAttributeDependentStyle(data);
1260 data->mHint = nsRestyleHint(data->mHint | hint);
1261 return PR_TRUE; // continue
1264 // Test if style is dependent on content state
1265 nsRestyleHint
1266 nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext,
1267 Element* aElement,
1268 nsIAtom* aAttribute,
1269 PRInt32 aModType,
1270 PRBool aAttrHasChanged)
1272 AttributeData data(aPresContext, aElement, aAttribute,
1273 aModType, aAttrHasChanged);
1274 WalkRuleProcessors(SheetHasAttributeStyle, &data, PR_FALSE);
1275 return data.mHint;
1278 PRBool
1279 nsStyleSet::MediumFeaturesChanged(nsPresContext* aPresContext)
1281 // We can't use WalkRuleProcessors without a content node.
1282 PRBool stylesChanged = PR_FALSE;
1283 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(mRuleProcessors); ++i) {
1284 nsIStyleRuleProcessor *processor = mRuleProcessors[i];
1285 if (!processor) {
1286 continue;
1288 PRBool thisChanged = processor->MediumFeaturesChanged(aPresContext);
1289 stylesChanged = stylesChanged || thisChanged;
1292 if (mBindingManager) {
1293 PRBool thisChanged = PR_FALSE;
1294 mBindingManager->MediumFeaturesChanged(aPresContext, &thisChanged);
1295 stylesChanged = stylesChanged || thisChanged;
1298 return stylesChanged;
1301 nsCSSStyleSheet::EnsureUniqueInnerResult
1302 nsStyleSet::EnsureUniqueInnerOnCSSSheets()
1304 nsAutoTArray<nsCSSStyleSheet*, 32> queue;
1305 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gCSSSheetTypes); ++i) {
1306 nsCOMArray<nsIStyleSheet> &sheets = mSheets[gCSSSheetTypes[i]];
1307 for (PRUint32 j = 0, j_end = sheets.Count(); j < j_end; ++j) {
1308 nsCSSStyleSheet *sheet = static_cast<nsCSSStyleSheet*>(sheets[j]);
1309 if (!queue.AppendElement(sheet)) {
1310 return nsCSSStyleSheet::eUniqueInner_CloneFailed;
1315 if (mBindingManager) {
1316 mBindingManager->AppendAllSheets(queue);
1319 nsCSSStyleSheet::EnsureUniqueInnerResult res =
1320 nsCSSStyleSheet::eUniqueInner_AlreadyUnique;
1321 while (!queue.IsEmpty()) {
1322 PRUint32 idx = queue.Length() - 1;
1323 nsCSSStyleSheet *sheet = queue[idx];
1324 queue.RemoveElementAt(idx);
1326 nsCSSStyleSheet::EnsureUniqueInnerResult sheetRes =
1327 sheet->EnsureUniqueInner();
1328 if (sheetRes == nsCSSStyleSheet::eUniqueInner_CloneFailed) {
1329 return sheetRes;
1331 if (sheetRes == nsCSSStyleSheet::eUniqueInner_ClonedInner) {
1332 res = sheetRes;
1335 // Enqueue all the sheet's children.
1336 if (!sheet->AppendAllChildSheets(queue)) {
1337 return nsCSSStyleSheet::eUniqueInner_CloneFailed;
1340 return res;