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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : * Daniel Glazman <glazman@netscape.com>
24 : * Brian Ryner <bryner@brianryner.com>
25 : * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
26 : *
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.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : /*
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
45 : */
46 :
47 : #include "mozilla/Util.h"
48 :
49 : #include "nsStyleSet.h"
50 : #include "nsNetUtil.h"
51 : #include "nsCSSStyleSheet.h"
52 : #include "nsIDocument.h"
53 : #include "nsRuleWalker.h"
54 : #include "nsStyleContext.h"
55 : #include "mozilla/css/StyleRule.h"
56 : #include "nsCSSAnonBoxes.h"
57 : #include "nsCSSPseudoElements.h"
58 : #include "nsCSSRuleProcessor.h"
59 : #include "nsIContent.h"
60 : #include "nsIFrame.h"
61 : #include "nsContentUtils.h"
62 : #include "nsRuleData.h"
63 : #include "nsRuleProcessorData.h"
64 : #include "nsTransitionManager.h"
65 : #include "nsAnimationManager.h"
66 : #include "nsEventStates.h"
67 : #include "mozilla/dom/Element.h"
68 :
69 : using namespace mozilla;
70 : using namespace mozilla::dom;
71 :
72 0 : NS_IMPL_ISUPPORTS1(nsEmptyStyleRule, nsIStyleRule)
73 :
74 : /* virtual */ void
75 0 : nsEmptyStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
76 : {
77 0 : }
78 :
79 : #ifdef DEBUG
80 : /* virtual */ void
81 0 : nsEmptyStyleRule::List(FILE* out, PRInt32 aIndent) const
82 : {
83 0 : }
84 : #endif
85 :
86 0 : NS_IMPL_ISUPPORTS1(nsInitialStyleRule, nsIStyleRule)
87 :
88 : /* virtual */ void
89 0 : nsInitialStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
90 : {
91 : // Iterate over the property groups
92 0 : for (nsStyleStructID sid = nsStyleStructID(0);
93 : sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
94 0 : if (aRuleData->mSIDs & (1 << sid)) {
95 : // Iterate over nsCSSValues within the property group
96 : nsCSSValue * const value_start =
97 0 : aRuleData->mValueStorage + aRuleData->mValueOffsets[sid];
98 0 : for (nsCSSValue *value = value_start,
99 0 : *value_end = value + nsCSSProps::PropertyCountInStruct(sid);
100 : value != value_end; ++value) {
101 : // If MathML is disabled take care not to set MathML properties (or we
102 : // will trigger assertions in nsRuleNode)
103 0 : if (sid == eStyleStruct_Font &&
104 0 : !aRuleData->mPresContext->Document()->GetMathMLEnabled()) {
105 0 : size_t index = value - value_start;
106 0 : if (index == nsCSSProps::PropertyIndexInStruct(
107 0 : eCSSProperty_script_level) ||
108 : index == nsCSSProps::PropertyIndexInStruct(
109 0 : eCSSProperty_script_size_multiplier) ||
110 : index == nsCSSProps::PropertyIndexInStruct(
111 0 : eCSSProperty_script_min_size)) {
112 0 : continue;
113 : }
114 : }
115 0 : if (value->GetUnit() == eCSSUnit_Null) {
116 0 : value->SetInitialValue();
117 : }
118 : }
119 : }
120 : }
121 0 : }
122 :
123 : #ifdef DEBUG
124 : /* virtual */ void
125 0 : nsInitialStyleRule::List(FILE* out, PRInt32 aIndent) const
126 : {
127 0 : }
128 : #endif
129 :
130 : static const nsStyleSet::sheetType gCSSSheetTypes[] = {
131 : nsStyleSet::eAgentSheet,
132 : nsStyleSet::eUserSheet,
133 : nsStyleSet::eDocSheet,
134 : nsStyleSet::eOverrideSheet
135 : };
136 :
137 0 : nsStyleSet::nsStyleSet()
138 : : mRuleTree(nsnull),
139 : mUnusedRuleNodeCount(0),
140 : mBatching(0),
141 : mInShutdown(false),
142 : mAuthorStyleDisabled(false),
143 : mInReconstruct(false),
144 0 : mDirty(0)
145 : {
146 0 : }
147 :
148 : size_t
149 0 : nsStyleSet::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
150 : {
151 0 : size_t n = aMallocSizeOf(this);
152 :
153 0 : for (int i = 0; i < eSheetTypeCount; i++) {
154 0 : if (mRuleProcessors[i]) {
155 0 : n += mRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
156 : }
157 : }
158 :
159 0 : return n;
160 : }
161 :
162 : nsresult
163 0 : nsStyleSet::Init(nsPresContext *aPresContext)
164 : {
165 0 : mFirstLineRule = new nsEmptyStyleRule;
166 0 : mFirstLetterRule = new nsEmptyStyleRule;
167 0 : if (!mFirstLineRule || !mFirstLetterRule) {
168 0 : return NS_ERROR_OUT_OF_MEMORY;
169 : }
170 :
171 0 : if (!BuildDefaultStyleData(aPresContext)) {
172 0 : mDefaultStyleData.Destroy(0, aPresContext);
173 0 : return NS_ERROR_OUT_OF_MEMORY;
174 : }
175 :
176 0 : mRuleTree = nsRuleNode::CreateRootNode(aPresContext);
177 0 : if (!mRuleTree) {
178 0 : mDefaultStyleData.Destroy(0, aPresContext);
179 0 : return NS_ERROR_OUT_OF_MEMORY;
180 : }
181 :
182 0 : GatherRuleProcessors(eAnimationSheet);
183 0 : GatherRuleProcessors(eTransitionSheet);
184 :
185 0 : return NS_OK;
186 : }
187 :
188 : nsresult
189 0 : nsStyleSet::BeginReconstruct()
190 : {
191 0 : NS_ASSERTION(!mInReconstruct, "Unmatched begin/end?");
192 0 : NS_ASSERTION(mRuleTree, "Reconstructing before first construction?");
193 :
194 : // Create a new rule tree root
195 : nsRuleNode* newTree =
196 0 : nsRuleNode::CreateRootNode(mRuleTree->GetPresContext());
197 0 : if (!newTree)
198 0 : return NS_ERROR_OUT_OF_MEMORY;
199 :
200 : // Save the old rule tree so we can destroy it later
201 0 : if (!mOldRuleTrees.AppendElement(mRuleTree)) {
202 0 : newTree->Destroy();
203 0 : return NS_ERROR_OUT_OF_MEMORY;
204 : }
205 :
206 : // We need to keep mRoots so that the rule tree GC will only free the
207 : // rule trees that really aren't referenced anymore (which should be
208 : // all of them, if there are no bugs in reresolution code).
209 :
210 0 : mInReconstruct = true;
211 0 : mRuleTree = newTree;
212 :
213 0 : return NS_OK;
214 : }
215 :
216 : void
217 0 : nsStyleSet::EndReconstruct()
218 : {
219 0 : NS_ASSERTION(mInReconstruct, "Unmatched begin/end?");
220 0 : mInReconstruct = false;
221 : #ifdef DEBUG
222 0 : for (PRInt32 i = mRoots.Length() - 1; i >= 0; --i) {
223 0 : nsRuleNode *n = mRoots[i]->GetRuleNode();
224 0 : while (n->GetParent()) {
225 0 : n = n->GetParent();
226 : }
227 : // Since nsStyleContext's mParent and mRuleNode are immutable, and
228 : // style contexts own their parents, and nsStyleContext asserts in
229 : // its constructor that the style context and its parent are in the
230 : // same rule tree, we don't need to check any of the children of
231 : // mRoots; we only need to check the rule nodes of mRoots
232 : // themselves.
233 :
234 0 : NS_ASSERTION(n == mRuleTree, "style context has old rule node");
235 : }
236 : #endif
237 : // This *should* destroy the only element of mOldRuleTrees, but in
238 : // case of some bugs (which would trigger the above assertions), it
239 : // won't.
240 0 : GCRuleTrees();
241 0 : }
242 :
243 : void
244 0 : nsStyleSet::SetQuirkStyleSheet(nsIStyleSheet* aQuirkStyleSheet)
245 : {
246 0 : NS_ASSERTION(aQuirkStyleSheet, "Must have quirk sheet if this is called");
247 0 : NS_ASSERTION(!mQuirkStyleSheet, "Multiple calls to SetQuirkStyleSheet?");
248 0 : NS_ASSERTION(mSheets[eAgentSheet].IndexOf(aQuirkStyleSheet) != -1,
249 : "Quirk style sheet not one of our agent sheets?");
250 0 : mQuirkStyleSheet = aQuirkStyleSheet;
251 0 : }
252 :
253 : nsresult
254 0 : nsStyleSet::GatherRuleProcessors(sheetType aType)
255 : {
256 0 : mRuleProcessors[aType] = nsnull;
257 0 : if (mAuthorStyleDisabled && (aType == eDocSheet ||
258 : aType == ePresHintSheet ||
259 : aType == eStyleAttrSheet)) {
260 : //don't regather if this level is disabled
261 0 : return NS_OK;
262 : }
263 0 : if (aType == eAnimationSheet) {
264 : // We have no sheet for the animations level; just a rule
265 : // processor. (XXX: We should probably do this for the other
266 : // non-CSS levels too!)
267 0 : mRuleProcessors[aType] = PresContext()->AnimationManager();
268 0 : return NS_OK;
269 : }
270 0 : if (aType == eTransitionSheet) {
271 : // We have no sheet for the transitions level; just a rule
272 : // processor. (XXX: We should probably do this for the other
273 : // non-CSS levels too!)
274 0 : mRuleProcessors[aType] = PresContext()->TransitionManager();
275 0 : return NS_OK;
276 : }
277 0 : if (mSheets[aType].Count()) {
278 0 : switch (aType) {
279 : case eAgentSheet:
280 : case eUserSheet:
281 : case eDocSheet:
282 : case eOverrideSheet: {
283 : // levels containing CSS stylesheets
284 0 : nsCOMArray<nsIStyleSheet>& sheets = mSheets[aType];
285 0 : nsTArray<nsRefPtr<nsCSSStyleSheet> > cssSheets(sheets.Count());
286 0 : for (PRInt32 i = 0, i_end = sheets.Count(); i < i_end; ++i) {
287 0 : nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(sheets[i]);
288 0 : NS_ASSERTION(cssSheet, "not a CSS sheet");
289 0 : cssSheets.AppendElement(cssSheet);
290 : }
291 0 : mRuleProcessors[aType] = new nsCSSRuleProcessor(cssSheets,
292 0 : PRUint8(aType));
293 0 : } break;
294 :
295 : default:
296 : // levels containing non-CSS stylesheets
297 0 : NS_ASSERTION(mSheets[aType].Count() == 1, "only one sheet per level");
298 0 : mRuleProcessors[aType] = do_QueryInterface(mSheets[aType][0]);
299 0 : break;
300 : }
301 : }
302 :
303 0 : return NS_OK;
304 : }
305 :
306 : nsresult
307 0 : nsStyleSet::AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
308 : {
309 0 : NS_PRECONDITION(aSheet, "null arg");
310 0 : NS_ASSERTION(aSheet->IsApplicable(),
311 : "Inapplicable sheet being placed in style set");
312 0 : mSheets[aType].RemoveObject(aSheet);
313 0 : if (!mSheets[aType].AppendObject(aSheet))
314 0 : return NS_ERROR_OUT_OF_MEMORY;
315 :
316 0 : if (!mBatching)
317 0 : return GatherRuleProcessors(aType);
318 :
319 0 : mDirty |= 1 << aType;
320 0 : return NS_OK;
321 : }
322 :
323 : nsresult
324 0 : nsStyleSet::PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
325 : {
326 0 : NS_PRECONDITION(aSheet, "null arg");
327 0 : NS_ASSERTION(aSheet->IsApplicable(),
328 : "Inapplicable sheet being placed in style set");
329 0 : mSheets[aType].RemoveObject(aSheet);
330 0 : if (!mSheets[aType].InsertObjectAt(aSheet, 0))
331 0 : return NS_ERROR_OUT_OF_MEMORY;
332 :
333 0 : if (!mBatching)
334 0 : return GatherRuleProcessors(aType);
335 :
336 0 : mDirty |= 1 << aType;
337 0 : return NS_OK;
338 : }
339 :
340 : nsresult
341 0 : nsStyleSet::RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
342 : {
343 0 : NS_PRECONDITION(aSheet, "null arg");
344 0 : NS_ASSERTION(aSheet->IsComplete(),
345 : "Incomplete sheet being removed from style set");
346 0 : mSheets[aType].RemoveObject(aSheet);
347 0 : if (!mBatching)
348 0 : return GatherRuleProcessors(aType);
349 :
350 0 : mDirty |= 1 << aType;
351 0 : return NS_OK;
352 : }
353 :
354 : nsresult
355 0 : nsStyleSet::ReplaceSheets(sheetType aType,
356 : const nsCOMArray<nsIStyleSheet> &aNewSheets)
357 : {
358 0 : mSheets[aType].Clear();
359 0 : if (!mSheets[aType].AppendObjects(aNewSheets))
360 0 : return NS_ERROR_OUT_OF_MEMORY;
361 :
362 0 : if (!mBatching)
363 0 : return GatherRuleProcessors(aType);
364 :
365 0 : mDirty |= 1 << aType;
366 0 : return NS_OK;
367 : }
368 :
369 : bool
370 0 : nsStyleSet::GetAuthorStyleDisabled()
371 : {
372 0 : return mAuthorStyleDisabled;
373 : }
374 :
375 : nsresult
376 0 : nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
377 : {
378 0 : if (aStyleDisabled == !mAuthorStyleDisabled) {
379 0 : mAuthorStyleDisabled = aStyleDisabled;
380 0 : BeginUpdate();
381 : mDirty |= 1 << eDocSheet |
382 : 1 << ePresHintSheet |
383 0 : 1 << eStyleAttrSheet;
384 0 : return EndUpdate();
385 : }
386 0 : return NS_OK;
387 : }
388 :
389 : // -------- Doc Sheets
390 :
391 : nsresult
392 0 : nsStyleSet::AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument)
393 : {
394 0 : NS_PRECONDITION(aSheet && aDocument, "null arg");
395 0 : NS_ASSERTION(aSheet->IsApplicable(),
396 : "Inapplicable sheet being placed in style set");
397 :
398 0 : nsCOMArray<nsIStyleSheet>& docSheets = mSheets[eDocSheet];
399 :
400 0 : docSheets.RemoveObject(aSheet);
401 : // lowest index first
402 0 : PRInt32 newDocIndex = aDocument->GetIndexOfStyleSheet(aSheet);
403 0 : PRInt32 count = docSheets.Count();
404 : PRInt32 index;
405 0 : for (index = 0; index < count; index++) {
406 0 : nsIStyleSheet* sheet = docSheets.ObjectAt(index);
407 0 : PRInt32 sheetDocIndex = aDocument->GetIndexOfStyleSheet(sheet);
408 0 : if (sheetDocIndex > newDocIndex)
409 0 : break;
410 : }
411 0 : if (!docSheets.InsertObjectAt(aSheet, index))
412 0 : return NS_ERROR_OUT_OF_MEMORY;
413 0 : if (!mBatching)
414 0 : return GatherRuleProcessors(eDocSheet);
415 :
416 0 : mDirty |= 1 << eDocSheet;
417 0 : return NS_OK;
418 : }
419 :
420 : // Batching
421 : void
422 0 : nsStyleSet::BeginUpdate()
423 : {
424 0 : ++mBatching;
425 0 : }
426 :
427 : nsresult
428 0 : nsStyleSet::EndUpdate()
429 : {
430 0 : NS_ASSERTION(mBatching > 0, "Unbalanced EndUpdate");
431 0 : if (--mBatching) {
432 : // We're not completely done yet.
433 0 : return NS_OK;
434 : }
435 :
436 0 : for (int i = 0; i < eSheetTypeCount; ++i) {
437 0 : if (mDirty & (1 << i)) {
438 0 : nsresult rv = GatherRuleProcessors(sheetType(i));
439 0 : NS_ENSURE_SUCCESS(rv, rv);
440 : }
441 : }
442 :
443 0 : mDirty = 0;
444 0 : return NS_OK;
445 : }
446 :
447 : void
448 0 : nsStyleSet::EnableQuirkStyleSheet(bool aEnable)
449 : {
450 : #ifdef DEBUG
451 : bool oldEnabled;
452 : {
453 : nsCOMPtr<nsIDOMCSSStyleSheet> domSheet =
454 0 : do_QueryInterface(mQuirkStyleSheet);
455 0 : domSheet->GetDisabled(&oldEnabled);
456 0 : oldEnabled = !oldEnabled;
457 : }
458 : #endif
459 0 : mQuirkStyleSheet->SetEnabled(aEnable);
460 : #ifdef DEBUG
461 : // This should always be OK, since SetEnabled should call
462 : // ClearRuleCascades.
463 : // Note that we can hit this codepath multiple times when document.open()
464 : // (potentially implied) happens multiple times.
465 0 : if (mRuleProcessors[eAgentSheet] && aEnable != oldEnabled) {
466 : static_cast<nsCSSRuleProcessor*>(static_cast<nsIStyleRuleProcessor*>(
467 0 : mRuleProcessors[eAgentSheet]))->AssertQuirksChangeOK();
468 : }
469 : #endif
470 0 : }
471 :
472 : template<class T>
473 : static bool
474 0 : EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
475 : {
476 0 : T* data = static_cast<T*>(aData);
477 0 : aProcessor->RulesMatching(data);
478 0 : return true;
479 : }
480 :
481 : static inline bool
482 0 : IsMoreSpecificThanAnimation(nsRuleNode *aRuleNode)
483 : {
484 0 : return !aRuleNode->IsRoot() &&
485 0 : (aRuleNode->GetLevel() == nsStyleSet::eTransitionSheet ||
486 0 : (aRuleNode->IsImportantRule() &&
487 0 : (aRuleNode->GetLevel() == nsStyleSet::eAgentSheet ||
488 0 : aRuleNode->GetLevel() == nsStyleSet::eUserSheet)));
489 : }
490 :
491 : static nsIStyleRule*
492 0 : GetAnimationRule(nsRuleNode *aRuleNode)
493 : {
494 0 : nsRuleNode *n = aRuleNode;
495 0 : while (IsMoreSpecificThanAnimation(n)) {
496 0 : n = n->GetParent();
497 : }
498 :
499 0 : if (n->IsRoot() || n->GetLevel() != nsStyleSet::eAnimationSheet) {
500 0 : return nsnull;
501 : }
502 :
503 0 : return n->GetRule();
504 : }
505 :
506 : static nsRuleNode*
507 0 : ReplaceAnimationRule(nsRuleNode *aOldRuleNode,
508 : nsIStyleRule *aOldAnimRule,
509 : nsIStyleRule *aNewAnimRule)
510 : {
511 0 : nsTArray<nsRuleNode*> moreSpecificNodes;
512 :
513 0 : nsRuleNode *n = aOldRuleNode;
514 0 : while (IsMoreSpecificThanAnimation(n)) {
515 0 : moreSpecificNodes.AppendElement(n);
516 0 : n = n->GetParent();
517 : }
518 :
519 0 : if (aOldAnimRule) {
520 0 : NS_ABORT_IF_FALSE(n->GetRule() == aOldAnimRule, "wrong rule");
521 0 : NS_ABORT_IF_FALSE(n->GetLevel() == nsStyleSet::eAnimationSheet,
522 : "wrong level");
523 0 : n = n->GetParent();
524 : }
525 :
526 0 : NS_ABORT_IF_FALSE(!IsMoreSpecificThanAnimation(n) &&
527 : n->GetLevel() != nsStyleSet::eAnimationSheet,
528 : "wrong level");
529 :
530 0 : if (aNewAnimRule) {
531 0 : n = n->Transition(aNewAnimRule, nsStyleSet::eAnimationSheet, false);
532 : }
533 :
534 0 : for (PRUint32 i = moreSpecificNodes.Length(); i-- != 0; ) {
535 0 : nsRuleNode *oldNode = moreSpecificNodes[i];
536 0 : n = n->Transition(oldNode->GetRule(), oldNode->GetLevel(),
537 0 : oldNode->IsImportantRule());
538 : }
539 :
540 0 : return n;
541 : }
542 :
543 : /**
544 : * |GetContext| implements sharing of style contexts (not just the data
545 : * on the rule nodes) between siblings and cousins of the same
546 : * generation. (It works for cousins of the same generation since
547 : * |aParentContext| could itself be a shared context.)
548 : */
549 : already_AddRefed<nsStyleContext>
550 0 : nsStyleSet::GetContext(nsStyleContext* aParentContext,
551 : nsRuleNode* aRuleNode,
552 : // aVisitedRuleNode may be null; if it is null
553 : // it means that we don't need to force creation
554 : // of a StyleIfVisited. (But if we make one
555 : // because aParentContext has one, then aRuleNode
556 : // should be used.)
557 : nsRuleNode* aVisitedRuleNode,
558 : bool aIsLink,
559 : bool aIsVisitedLink,
560 : nsIAtom* aPseudoTag,
561 : nsCSSPseudoElements::Type aPseudoType,
562 : bool aDoAnimations,
563 : Element* aElementForAnimation)
564 : {
565 0 : NS_PRECONDITION((!aPseudoTag &&
566 : aPseudoType ==
567 : nsCSSPseudoElements::ePseudo_NotPseudoElement) ||
568 : (aPseudoTag &&
569 : nsCSSPseudoElements::GetPseudoType(aPseudoTag) ==
570 : aPseudoType),
571 : "Pseudo mismatch");
572 :
573 0 : if (aVisitedRuleNode == aRuleNode) {
574 : // No need to force creation of a visited style in this case.
575 0 : aVisitedRuleNode = nsnull;
576 : }
577 :
578 : // Ensure |aVisitedRuleNode != nsnull| corresponds to the need to
579 : // create an if-visited style context, and that in that case, we have
580 : // parentIfVisited set correctly.
581 : nsStyleContext *parentIfVisited =
582 0 : aParentContext ? aParentContext->GetStyleIfVisited() : nsnull;
583 0 : if (parentIfVisited) {
584 0 : if (!aVisitedRuleNode) {
585 0 : aVisitedRuleNode = aRuleNode;
586 : }
587 : } else {
588 0 : if (aVisitedRuleNode) {
589 0 : parentIfVisited = aParentContext;
590 : }
591 : }
592 :
593 0 : if (aIsLink) {
594 : // If this node is a link, we want its visited's style context's
595 : // parent to be the regular style context of its parent, because
596 : // only the visitedness of the relevant link should influence style.
597 0 : parentIfVisited = aParentContext;
598 : }
599 :
600 0 : nsRefPtr<nsStyleContext> result;
601 0 : if (aParentContext)
602 : result = aParentContext->FindChildWithRules(aPseudoTag, aRuleNode,
603 : aVisitedRuleNode,
604 0 : aIsVisitedLink);
605 :
606 : #ifdef NOISY_DEBUG
607 : if (result)
608 : fprintf(stdout, "--- SharedSC %d ---\n", ++gSharedCount);
609 : else
610 : fprintf(stdout, "+++ NewSC %d +++\n", ++gNewCount);
611 : #endif
612 :
613 0 : if (!result) {
614 : result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType,
615 0 : aRuleNode, PresContext());
616 0 : if (!result)
617 0 : return nsnull;
618 0 : if (aVisitedRuleNode) {
619 : nsRefPtr<nsStyleContext> resultIfVisited =
620 : NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType,
621 0 : aVisitedRuleNode, PresContext());
622 0 : if (!resultIfVisited) {
623 0 : return nsnull;
624 : }
625 0 : if (!parentIfVisited) {
626 0 : mRoots.AppendElement(resultIfVisited);
627 : }
628 0 : resultIfVisited->SetIsStyleIfVisited();
629 0 : result->SetStyleIfVisited(resultIfVisited.forget());
630 :
631 : bool relevantLinkVisited =
632 : aIsLink ? aIsVisitedLink
633 0 : : (aParentContext && aParentContext->RelevantLinkVisited());
634 0 : if (relevantLinkVisited) {
635 0 : result->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED);
636 : }
637 : }
638 0 : if (!aParentContext)
639 0 : mRoots.AppendElement(result);
640 : }
641 : else {
642 0 : NS_ASSERTION(result->GetPseudoType() == aPseudoType, "Unexpected type");
643 0 : NS_ASSERTION(result->GetPseudo() == aPseudoTag, "Unexpected pseudo");
644 : }
645 :
646 0 : if (aDoAnimations) {
647 : // Normally the animation manager has already added the correct
648 : // style rule. However, if the animation-name just changed, it
649 : // might have been wrong. So ask it to double-check based on the
650 : // resulting style context.
651 0 : nsIStyleRule *oldAnimRule = GetAnimationRule(aRuleNode);
652 : nsIStyleRule *animRule = PresContext()->AnimationManager()->
653 0 : CheckAnimationRule(result, aElementForAnimation);
654 0 : NS_ABORT_IF_FALSE(result->GetRuleNode() == aRuleNode,
655 : "unexpected rule node");
656 0 : NS_ABORT_IF_FALSE(!result->GetStyleIfVisited() == !aVisitedRuleNode,
657 : "unexpected visited rule node");
658 0 : NS_ABORT_IF_FALSE(!aVisitedRuleNode ||
659 : result->GetStyleIfVisited()->GetRuleNode() ==
660 : aVisitedRuleNode,
661 : "unexpected visited rule node");
662 0 : if (oldAnimRule != animRule) {
663 : nsRuleNode *ruleNode =
664 0 : ReplaceAnimationRule(aRuleNode, oldAnimRule, animRule);
665 : nsRuleNode *visitedRuleNode = aVisitedRuleNode
666 : ? ReplaceAnimationRule(aVisitedRuleNode, oldAnimRule, animRule)
667 0 : : nsnull;
668 : result = GetContext(aParentContext, ruleNode, visitedRuleNode,
669 : aIsLink, aIsVisitedLink,
670 0 : aPseudoTag, aPseudoType, false, nsnull);
671 : }
672 : }
673 :
674 0 : if (aElementForAnimation && aElementForAnimation->IsHTML(nsGkAtoms::body) &&
675 : aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement &&
676 0 : PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
677 0 : nsIDocument* doc = aElementForAnimation->GetCurrentDoc();
678 0 : if (doc && doc->GetBodyElement() == aElementForAnimation) {
679 : // Update the prescontext's body color
680 0 : PresContext()->SetBodyTextColor(result->GetStyleColor()->mColor);
681 : }
682 : }
683 :
684 0 : return result.forget();
685 : }
686 :
687 : void
688 0 : nsStyleSet::AddImportantRules(nsRuleNode* aCurrLevelNode,
689 : nsRuleNode* aLastPrevLevelNode,
690 : nsRuleWalker* aRuleWalker)
691 : {
692 0 : NS_ASSERTION(aCurrLevelNode &&
693 : aCurrLevelNode != aLastPrevLevelNode, "How did we get here?");
694 :
695 0 : nsAutoTArray<nsIStyleRule*, 16> importantRules;
696 0 : for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
697 : node = node->GetParent()) {
698 : // We guarantee that we never walk the root node here, so no need
699 : // to null-check GetRule(). Furthermore, it must be a CSS rule.
700 0 : NS_ASSERTION(nsRefPtr<css::StyleRule>(do_QueryObject(node->GetRule())),
701 : "Unexpected non-CSS rule");
702 :
703 : nsIStyleRule* impRule =
704 0 : static_cast<css::StyleRule*>(node->GetRule())->GetImportantRule();
705 0 : if (impRule)
706 0 : importantRules.AppendElement(impRule);
707 : }
708 :
709 0 : NS_ASSERTION(importantRules.Length() != 0,
710 : "Why did we think there were important rules?");
711 :
712 0 : for (PRUint32 i = importantRules.Length(); i-- != 0; ) {
713 0 : aRuleWalker->Forward(importantRules[i]);
714 : }
715 0 : }
716 :
717 : #ifdef DEBUG
718 : void
719 0 : nsStyleSet::AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
720 : nsRuleNode* aLastPrevLevelNode)
721 : {
722 0 : if (!aCurrLevelNode)
723 0 : return;
724 :
725 0 : for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
726 : node = node->GetParent()) {
727 0 : nsRefPtr<css::StyleRule> rule(do_QueryObject(node->GetRule()));
728 0 : NS_ASSERTION(rule, "Unexpected non-CSS rule");
729 :
730 0 : NS_ASSERTION(!rule->GetImportantRule(), "Unexpected important rule");
731 : }
732 : }
733 :
734 : void
735 0 : nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
736 : nsRuleNode* aLastPrevLevelNode)
737 : {
738 0 : if (!aCurrLevelNode)
739 0 : return;
740 :
741 0 : for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
742 : node = node->GetParent()) {
743 0 : nsIStyleRule *rule = node->GetRule();
744 0 : nsRefPtr<css::StyleRule> cssRule(do_QueryObject(rule));
745 0 : NS_ASSERTION(!cssRule || !cssRule->Selector(), "Unexpected CSS rule");
746 : }
747 : }
748 : #endif
749 :
750 : // Enumerate the rules in a way that cares about the order of the rules.
751 : void
752 0 : nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
753 : void* aData, nsIContent* aContent,
754 : nsRuleWalker* aRuleWalker)
755 : {
756 : // Cascading order:
757 : // [least important]
758 : // 1. UA normal rules = Agent normal
759 : // 2. User normal rules = User normal
760 : // 3. Presentation hints = PresHint normal
761 : // 4. Author normal rules = Document normal
762 : // 5. Override normal rules = Override normal
763 : // 6. Author !important rules = Document !important
764 : // 7. Override !important rules = Override !important
765 : // -. animation rules = Animation normal
766 : // 8. User !important rules = User !important
767 : // 9. UA !important rules = Agent !important
768 : // -. transition rules = Transition normal
769 : // [most important]
770 :
771 : // Save off the last rule before we start walking our agent sheets;
772 : // this will be either the root or one of the restriction rules.
773 0 : nsRuleNode* lastRestrictionRN = aRuleWalker->CurrentNode();
774 :
775 0 : aRuleWalker->SetLevel(eAgentSheet, false, true);
776 0 : if (mRuleProcessors[eAgentSheet])
777 0 : (*aCollectorFunc)(mRuleProcessors[eAgentSheet], aData);
778 0 : nsRuleNode* lastAgentRN = aRuleWalker->CurrentNode();
779 0 : bool haveImportantUARules = !aRuleWalker->GetCheckForImportantRules();
780 :
781 0 : aRuleWalker->SetLevel(eUserSheet, false, true);
782 : bool skipUserStyles =
783 0 : aContent && aContent->IsInNativeAnonymousSubtree();
784 0 : if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
785 0 : (*aCollectorFunc)(mRuleProcessors[eUserSheet], aData);
786 0 : nsRuleNode* lastUserRN = aRuleWalker->CurrentNode();
787 0 : bool haveImportantUserRules = !aRuleWalker->GetCheckForImportantRules();
788 :
789 0 : aRuleWalker->SetLevel(ePresHintSheet, false, false);
790 0 : if (mRuleProcessors[ePresHintSheet])
791 0 : (*aCollectorFunc)(mRuleProcessors[ePresHintSheet], aData);
792 0 : nsRuleNode* lastPresHintRN = aRuleWalker->CurrentNode();
793 :
794 0 : aRuleWalker->SetLevel(eDocSheet, false, true);
795 0 : bool cutOffInheritance = false;
796 0 : if (mBindingManager && aContent) {
797 : // We can supply additional document-level sheets that should be walked.
798 : mBindingManager->WalkRules(aCollectorFunc,
799 : static_cast<RuleProcessorData*>(aData),
800 0 : &cutOffInheritance);
801 : }
802 0 : if (!skipUserStyles && !cutOffInheritance &&
803 0 : mRuleProcessors[eDocSheet]) // NOTE: different
804 0 : (*aCollectorFunc)(mRuleProcessors[eDocSheet], aData);
805 : aRuleWalker->SetLevel(eStyleAttrSheet, false,
806 0 : aRuleWalker->GetCheckForImportantRules());
807 0 : if (mRuleProcessors[eStyleAttrSheet])
808 0 : (*aCollectorFunc)(mRuleProcessors[eStyleAttrSheet], aData);
809 0 : nsRuleNode* lastDocRN = aRuleWalker->CurrentNode();
810 0 : bool haveImportantDocRules = !aRuleWalker->GetCheckForImportantRules();
811 :
812 0 : aRuleWalker->SetLevel(eOverrideSheet, false, true);
813 0 : if (mRuleProcessors[eOverrideSheet])
814 0 : (*aCollectorFunc)(mRuleProcessors[eOverrideSheet], aData);
815 0 : nsRuleNode* lastOvrRN = aRuleWalker->CurrentNode();
816 0 : bool haveImportantOverrideRules = !aRuleWalker->GetCheckForImportantRules();
817 :
818 0 : if (haveImportantDocRules) {
819 0 : aRuleWalker->SetLevel(eDocSheet, true, false);
820 0 : AddImportantRules(lastDocRN, lastPresHintRN, aRuleWalker); // doc
821 : }
822 : #ifdef DEBUG
823 : else {
824 0 : AssertNoImportantRules(lastDocRN, lastPresHintRN);
825 : }
826 : #endif
827 :
828 0 : if (haveImportantOverrideRules) {
829 0 : aRuleWalker->SetLevel(eOverrideSheet, true, false);
830 0 : AddImportantRules(lastOvrRN, lastDocRN, aRuleWalker); // override
831 : }
832 : #ifdef DEBUG
833 : else {
834 0 : AssertNoImportantRules(lastOvrRN, lastDocRN);
835 : }
836 : #endif
837 :
838 : // This needs to match IsMoreSpecificThanAnimation() above.
839 0 : aRuleWalker->SetLevel(eAnimationSheet, false, false);
840 0 : (*aCollectorFunc)(mRuleProcessors[eAnimationSheet], aData);
841 :
842 : #ifdef DEBUG
843 0 : AssertNoCSSRules(lastPresHintRN, lastUserRN);
844 : #endif
845 :
846 0 : if (haveImportantUserRules) {
847 0 : aRuleWalker->SetLevel(eUserSheet, true, false);
848 0 : AddImportantRules(lastUserRN, lastAgentRN, aRuleWalker); //user
849 : }
850 : #ifdef DEBUG
851 : else {
852 0 : AssertNoImportantRules(lastUserRN, lastAgentRN);
853 : }
854 : #endif
855 :
856 0 : if (haveImportantUARules) {
857 0 : aRuleWalker->SetLevel(eAgentSheet, true, false);
858 0 : AddImportantRules(lastAgentRN, lastRestrictionRN, aRuleWalker); //agent
859 : }
860 : #ifdef DEBUG
861 : else {
862 0 : AssertNoImportantRules(lastAgentRN, lastRestrictionRN);
863 : }
864 : #endif
865 :
866 : #ifdef DEBUG
867 0 : AssertNoCSSRules(lastRestrictionRN, mRuleTree);
868 : #endif
869 :
870 : #ifdef DEBUG
871 0 : nsRuleNode *lastImportantRN = aRuleWalker->CurrentNode();
872 : #endif
873 0 : aRuleWalker->SetLevel(eTransitionSheet, false, false);
874 0 : (*aCollectorFunc)(mRuleProcessors[eTransitionSheet], aData);
875 : #ifdef DEBUG
876 0 : AssertNoCSSRules(aRuleWalker->CurrentNode(), lastImportantRN);
877 : #endif
878 :
879 0 : }
880 :
881 : // Enumerate all the rules in a way that doesn't care about the order
882 : // of the rules and doesn't walk !important-rules.
883 : void
884 0 : nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
885 : RuleProcessorData* aData,
886 : bool aWalkAllXBLStylesheets)
887 : {
888 0 : if (mRuleProcessors[eAgentSheet])
889 0 : (*aFunc)(mRuleProcessors[eAgentSheet], aData);
890 :
891 0 : bool skipUserStyles = aData->mElement->IsInNativeAnonymousSubtree();
892 0 : if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
893 0 : (*aFunc)(mRuleProcessors[eUserSheet], aData);
894 :
895 0 : if (mRuleProcessors[ePresHintSheet])
896 0 : (*aFunc)(mRuleProcessors[ePresHintSheet], aData);
897 :
898 0 : bool cutOffInheritance = false;
899 0 : if (mBindingManager) {
900 : // We can supply additional document-level sheets that should be walked.
901 0 : if (aWalkAllXBLStylesheets) {
902 0 : mBindingManager->WalkAllRules(aFunc, aData);
903 : } else {
904 0 : mBindingManager->WalkRules(aFunc, aData, &cutOffInheritance);
905 : }
906 : }
907 0 : if (!skipUserStyles && !cutOffInheritance &&
908 0 : mRuleProcessors[eDocSheet]) // NOTE: different
909 0 : (*aFunc)(mRuleProcessors[eDocSheet], aData);
910 0 : if (mRuleProcessors[eStyleAttrSheet])
911 0 : (*aFunc)(mRuleProcessors[eStyleAttrSheet], aData);
912 0 : if (mRuleProcessors[eOverrideSheet])
913 0 : (*aFunc)(mRuleProcessors[eOverrideSheet], aData);
914 0 : (*aFunc)(mRuleProcessors[eAnimationSheet], aData);
915 0 : (*aFunc)(mRuleProcessors[eTransitionSheet], aData);
916 0 : }
917 :
918 0 : bool nsStyleSet::BuildDefaultStyleData(nsPresContext* aPresContext)
919 : {
920 0 : NS_ASSERTION(!mDefaultStyleData.mResetData &&
921 : !mDefaultStyleData.mInheritedData,
922 : "leaking default style data");
923 0 : mDefaultStyleData.mResetData = new (aPresContext) nsResetStyleData;
924 0 : if (!mDefaultStyleData.mResetData)
925 0 : return false;
926 0 : mDefaultStyleData.mInheritedData = new (aPresContext) nsInheritedStyleData;
927 0 : if (!mDefaultStyleData.mInheritedData)
928 0 : return false;
929 :
930 : #define SSARG_PRESCONTEXT aPresContext
931 :
932 : #define CREATE_DATA(name, type, args) \
933 : if (!(mDefaultStyleData.m##type##Data->mStyleStructs[eStyleStruct_##name] = \
934 : new (aPresContext) nsStyle##name args)) \
935 : return false;
936 :
937 : #define STYLE_STRUCT_INHERITED(name, checkdata_cb, ctor_args) \
938 : CREATE_DATA(name, Inherited, ctor_args)
939 : #define STYLE_STRUCT_RESET(name, checkdata_cb, ctor_args) \
940 : CREATE_DATA(name, Reset, ctor_args)
941 :
942 : #include "nsStyleStructList.h"
943 :
944 : #undef STYLE_STRUCT_INHERITED
945 : #undef STYLE_STRUCT_RESET
946 : #undef SSARG_PRESCONTEXT
947 :
948 0 : return true;
949 : }
950 :
951 : already_AddRefed<nsStyleContext>
952 0 : nsStyleSet::ResolveStyleFor(Element* aElement,
953 : nsStyleContext* aParentContext)
954 : {
955 : TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
956 0 : aElement->OwnerDoc());
957 0 : return ResolveStyleFor(aElement, aParentContext, treeContext);
958 : }
959 :
960 : already_AddRefed<nsStyleContext>
961 0 : nsStyleSet::ResolveStyleFor(Element* aElement,
962 : nsStyleContext* aParentContext,
963 : TreeMatchContext& aTreeMatchContext)
964 : {
965 0 : NS_ENSURE_FALSE(mInShutdown, nsnull);
966 0 : NS_ASSERTION(aElement, "aElement must not be null");
967 :
968 0 : nsRuleWalker ruleWalker(mRuleTree);
969 0 : aTreeMatchContext.ResetForUnvisitedMatching();
970 : ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker,
971 0 : aTreeMatchContext);
972 : FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
973 0 : &ruleWalker);
974 :
975 0 : nsRuleNode *ruleNode = ruleWalker.CurrentNode();
976 0 : nsRuleNode *visitedRuleNode = nsnull;
977 :
978 0 : if (aTreeMatchContext.HaveRelevantLink()) {
979 0 : aTreeMatchContext.ResetForVisitedMatching();
980 0 : ruleWalker.Reset();
981 : FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
982 0 : &ruleWalker);
983 0 : visitedRuleNode = ruleWalker.CurrentNode();
984 : }
985 :
986 : return GetContext(aParentContext, ruleNode, visitedRuleNode,
987 0 : nsCSSRuleProcessor::IsLink(aElement),
988 : nsCSSRuleProcessor::GetContentState(aElement).
989 0 : HasState(NS_EVENT_STATE_VISITED),
990 : nsnull, nsCSSPseudoElements::ePseudo_NotPseudoElement,
991 0 : true, aElement);
992 : }
993 :
994 : already_AddRefed<nsStyleContext>
995 0 : nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
996 : const nsCOMArray<nsIStyleRule> &aRules)
997 : {
998 0 : NS_ENSURE_FALSE(mInShutdown, nsnull);
999 :
1000 0 : nsRuleWalker ruleWalker(mRuleTree);
1001 : // FIXME: Perhaps this should be passed in, but it probably doesn't
1002 : // matter.
1003 0 : ruleWalker.SetLevel(eDocSheet, false, false);
1004 0 : for (PRInt32 i = 0; i < aRules.Count(); i++) {
1005 0 : ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
1006 : }
1007 :
1008 : return GetContext(aParentContext, ruleWalker.CurrentNode(), nsnull,
1009 : false, false,
1010 : nsnull, nsCSSPseudoElements::ePseudo_NotPseudoElement,
1011 0 : false, nsnull);
1012 : }
1013 :
1014 : already_AddRefed<nsStyleContext>
1015 0 : nsStyleSet::ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
1016 : const nsCOMArray<nsIStyleRule> &aRules)
1017 : {
1018 0 : NS_ENSURE_FALSE(mInShutdown, nsnull);
1019 :
1020 0 : nsRuleWalker ruleWalker(mRuleTree);
1021 0 : ruleWalker.SetCurrentNode(aBaseContext->GetRuleNode());
1022 : // FIXME: Perhaps this should be passed in, but it probably doesn't
1023 : // matter.
1024 0 : ruleWalker.SetLevel(eDocSheet, false, false);
1025 0 : for (PRInt32 i = 0; i < aRules.Count(); i++) {
1026 0 : ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
1027 : }
1028 :
1029 0 : nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1030 0 : nsRuleNode *visitedRuleNode = nsnull;
1031 :
1032 0 : if (aBaseContext->GetStyleIfVisited()) {
1033 0 : ruleWalker.SetCurrentNode(aBaseContext->GetStyleIfVisited()->GetRuleNode());
1034 0 : for (PRInt32 i = 0; i < aRules.Count(); i++) {
1035 0 : ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
1036 : }
1037 0 : visitedRuleNode = ruleWalker.CurrentNode();
1038 : }
1039 :
1040 : return GetContext(aBaseContext->GetParent(), ruleNode, visitedRuleNode,
1041 0 : aBaseContext->IsLinkContext(),
1042 0 : aBaseContext->RelevantLinkVisited(),
1043 : aBaseContext->GetPseudo(),
1044 : aBaseContext->GetPseudoType(),
1045 0 : false, nsnull);
1046 : }
1047 :
1048 : already_AddRefed<nsStyleContext>
1049 0 : nsStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext)
1050 : {
1051 : return GetContext(aParentContext, mRuleTree, nsnull,
1052 : false, false,
1053 : nsCSSAnonBoxes::mozNonElement,
1054 0 : nsCSSPseudoElements::ePseudo_AnonBox, false, nsnull);
1055 : }
1056 :
1057 : void
1058 0 : nsStyleSet::WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType,
1059 : nsRuleWalker* aRuleWalker)
1060 : {
1061 : // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
1062 0 : aRuleWalker->SetLevel(eAgentSheet, false, false);
1063 0 : if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter)
1064 0 : aRuleWalker->Forward(mFirstLetterRule);
1065 0 : else if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLine)
1066 0 : aRuleWalker->Forward(mFirstLineRule);
1067 0 : }
1068 :
1069 : already_AddRefed<nsStyleContext>
1070 0 : nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
1071 : nsCSSPseudoElements::Type aType,
1072 : nsStyleContext* aParentContext)
1073 : {
1074 0 : NS_ENSURE_FALSE(mInShutdown, nsnull);
1075 :
1076 0 : NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
1077 : "must have pseudo element type");
1078 0 : NS_ASSERTION(aParentElement, "Must have parent element");
1079 :
1080 0 : nsRuleWalker ruleWalker(mRuleTree);
1081 : TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
1082 0 : aParentElement->OwnerDoc());
1083 : PseudoElementRuleProcessorData data(PresContext(), aParentElement,
1084 0 : &ruleWalker, aType, treeContext);
1085 0 : WalkRestrictionRule(aType, &ruleWalker);
1086 : FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
1087 0 : aParentElement, &ruleWalker);
1088 :
1089 0 : nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1090 0 : nsRuleNode *visitedRuleNode = nsnull;
1091 :
1092 0 : if (treeContext.HaveRelevantLink()) {
1093 0 : treeContext.ResetForVisitedMatching();
1094 0 : ruleWalker.Reset();
1095 0 : WalkRestrictionRule(aType, &ruleWalker);
1096 : FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
1097 0 : aParentElement, &ruleWalker);
1098 0 : visitedRuleNode = ruleWalker.CurrentNode();
1099 : }
1100 :
1101 : return GetContext(aParentContext, ruleNode, visitedRuleNode,
1102 : // For pseudos, |data.IsLink()| being true means that
1103 : // our parent node is a link.
1104 : false, false,
1105 : nsCSSPseudoElements::GetPseudoAtom(aType), aType,
1106 : aType == nsCSSPseudoElements::ePseudo_before ||
1107 : aType == nsCSSPseudoElements::ePseudo_after,
1108 0 : aParentElement);
1109 : }
1110 :
1111 : already_AddRefed<nsStyleContext>
1112 0 : nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
1113 : nsCSSPseudoElements::Type aType,
1114 : nsStyleContext* aParentContext)
1115 : {
1116 : TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
1117 0 : aParentElement->OwnerDoc());
1118 : return ProbePseudoElementStyle(aParentElement, aType, aParentContext,
1119 0 : treeContext);
1120 : }
1121 :
1122 : already_AddRefed<nsStyleContext>
1123 0 : nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
1124 : nsCSSPseudoElements::Type aType,
1125 : nsStyleContext* aParentContext,
1126 : TreeMatchContext& aTreeMatchContext)
1127 : {
1128 0 : NS_ENSURE_FALSE(mInShutdown, nsnull);
1129 :
1130 0 : NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
1131 : "must have pseudo element type");
1132 0 : NS_ASSERTION(aParentElement, "aParentElement must not be null");
1133 :
1134 0 : nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
1135 0 : nsRuleWalker ruleWalker(mRuleTree);
1136 0 : aTreeMatchContext.ResetForUnvisitedMatching();
1137 : PseudoElementRuleProcessorData data(PresContext(), aParentElement,
1138 0 : &ruleWalker, aType, aTreeMatchContext);
1139 0 : WalkRestrictionRule(aType, &ruleWalker);
1140 : // not the root if there was a restriction rule
1141 0 : nsRuleNode *adjustedRoot = ruleWalker.CurrentNode();
1142 : FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
1143 0 : aParentElement, &ruleWalker);
1144 :
1145 0 : nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1146 0 : if (ruleNode == adjustedRoot) {
1147 0 : return nsnull;
1148 : }
1149 :
1150 0 : nsRuleNode *visitedRuleNode = nsnull;
1151 :
1152 0 : if (aTreeMatchContext.HaveRelevantLink()) {
1153 0 : aTreeMatchContext.ResetForVisitedMatching();
1154 0 : ruleWalker.Reset();
1155 0 : WalkRestrictionRule(aType, &ruleWalker);
1156 : FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
1157 0 : aParentElement, &ruleWalker);
1158 0 : visitedRuleNode = ruleWalker.CurrentNode();
1159 : }
1160 :
1161 : nsRefPtr<nsStyleContext> result =
1162 : GetContext(aParentContext, ruleNode, visitedRuleNode,
1163 : // For pseudos, |data.IsLink()| being true means that
1164 : // our parent node is a link.
1165 : false, false,
1166 : pseudoTag, aType,
1167 : aType == nsCSSPseudoElements::ePseudo_before ||
1168 : aType == nsCSSPseudoElements::ePseudo_after,
1169 0 : aParentElement);
1170 :
1171 : // For :before and :after pseudo-elements, having display: none or no
1172 : // 'content' property is equivalent to not having the pseudo-element
1173 : // at all.
1174 0 : if (result &&
1175 : (pseudoTag == nsCSSPseudoElements::before ||
1176 0 : pseudoTag == nsCSSPseudoElements::after)) {
1177 0 : const nsStyleDisplay *display = result->GetStyleDisplay();
1178 0 : const nsStyleContent *content = result->GetStyleContent();
1179 : // XXXldb What is contentCount for |content: ""|?
1180 0 : if (display->mDisplay == NS_STYLE_DISPLAY_NONE ||
1181 0 : content->ContentCount() == 0) {
1182 0 : result = nsnull;
1183 : }
1184 : }
1185 :
1186 0 : return result.forget();
1187 : }
1188 :
1189 : already_AddRefed<nsStyleContext>
1190 0 : nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
1191 : nsStyleContext* aParentContext)
1192 : {
1193 0 : NS_ENSURE_FALSE(mInShutdown, nsnull);
1194 :
1195 : #ifdef DEBUG
1196 0 : bool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag)
1197 : #ifdef MOZ_XUL
1198 0 : && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
1199 : #endif
1200 : ;
1201 0 : NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
1202 : #endif
1203 :
1204 0 : nsRuleWalker ruleWalker(mRuleTree);
1205 0 : AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker);
1206 : FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nsnull,
1207 0 : &ruleWalker);
1208 :
1209 : return GetContext(aParentContext, ruleWalker.CurrentNode(), nsnull,
1210 : false, false,
1211 : aPseudoTag, nsCSSPseudoElements::ePseudo_AnonBox,
1212 0 : false, nsnull);
1213 : }
1214 :
1215 : #ifdef MOZ_XUL
1216 : already_AddRefed<nsStyleContext>
1217 0 : nsStyleSet::ResolveXULTreePseudoStyle(Element* aParentElement,
1218 : nsIAtom* aPseudoTag,
1219 : nsStyleContext* aParentContext,
1220 : nsICSSPseudoComparator* aComparator)
1221 : {
1222 0 : NS_ENSURE_FALSE(mInShutdown, nsnull);
1223 :
1224 0 : NS_ASSERTION(aPseudoTag, "must have pseudo tag");
1225 0 : NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
1226 : "Unexpected pseudo");
1227 :
1228 0 : nsRuleWalker ruleWalker(mRuleTree);
1229 : TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
1230 0 : aParentElement->OwnerDoc());
1231 : XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
1232 0 : aPseudoTag, aComparator, treeContext);
1233 : FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
1234 0 : &ruleWalker);
1235 :
1236 0 : nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1237 0 : nsRuleNode *visitedRuleNode = nsnull;
1238 :
1239 0 : if (treeContext.HaveRelevantLink()) {
1240 0 : treeContext.ResetForVisitedMatching();
1241 0 : ruleWalker.Reset();
1242 : FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data,
1243 0 : aParentElement, &ruleWalker);
1244 0 : visitedRuleNode = ruleWalker.CurrentNode();
1245 : }
1246 :
1247 : return GetContext(aParentContext, ruleNode, visitedRuleNode,
1248 : // For pseudos, |data.IsLink()| being true means that
1249 : // our parent node is a link.
1250 : false, false,
1251 : aPseudoTag, nsCSSPseudoElements::ePseudo_XULTree,
1252 0 : false, nsnull);
1253 : }
1254 : #endif
1255 :
1256 : bool
1257 0 : nsStyleSet::AppendFontFaceRules(nsPresContext* aPresContext,
1258 : nsTArray<nsFontFaceRuleContainer>& aArray)
1259 : {
1260 0 : NS_ENSURE_FALSE(mInShutdown, false);
1261 :
1262 0 : for (PRUint32 i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
1263 : nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
1264 0 : (mRuleProcessors[gCSSSheetTypes[i]].get());
1265 0 : if (ruleProc && !ruleProc->AppendFontFaceRules(aPresContext, aArray))
1266 0 : return false;
1267 : }
1268 0 : return true;
1269 : }
1270 :
1271 : bool
1272 0 : nsStyleSet::AppendKeyframesRules(nsPresContext* aPresContext,
1273 : nsTArray<nsCSSKeyframesRule*>& aArray)
1274 : {
1275 0 : NS_ENSURE_FALSE(mInShutdown, false);
1276 :
1277 0 : for (PRUint32 i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
1278 : nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
1279 0 : (mRuleProcessors[gCSSSheetTypes[i]].get());
1280 0 : if (ruleProc && !ruleProc->AppendKeyframesRules(aPresContext, aArray))
1281 0 : return false;
1282 : }
1283 0 : return true;
1284 : }
1285 :
1286 : void
1287 0 : nsStyleSet::BeginShutdown(nsPresContext* aPresContext)
1288 : {
1289 0 : mInShutdown = 1;
1290 0 : mRoots.Clear(); // no longer valid, since we won't keep it up to date
1291 0 : }
1292 :
1293 : void
1294 0 : nsStyleSet::Shutdown(nsPresContext* aPresContext)
1295 : {
1296 0 : mRuleTree->Destroy();
1297 0 : mRuleTree = nsnull;
1298 :
1299 : // We can have old rule trees either because:
1300 : // (1) we failed the assertions in EndReconstruct, or
1301 : // (2) we're shutting down within a reconstruct (see bug 462392)
1302 0 : for (PRUint32 i = mOldRuleTrees.Length(); i > 0; ) {
1303 0 : --i;
1304 0 : mOldRuleTrees[i]->Destroy();
1305 : }
1306 0 : mOldRuleTrees.Clear();
1307 :
1308 0 : mDefaultStyleData.Destroy(0, aPresContext);
1309 0 : }
1310 :
1311 : static const PRUint32 kGCInterval = 300;
1312 :
1313 : void
1314 0 : nsStyleSet::NotifyStyleContextDestroyed(nsPresContext* aPresContext,
1315 : nsStyleContext* aStyleContext)
1316 : {
1317 0 : if (mInShutdown)
1318 0 : return;
1319 :
1320 : // Remove style contexts from mRoots even if mOldRuleTree is non-null. This
1321 : // could be a style context from the new ruletree!
1322 0 : if (!aStyleContext->GetParent()) {
1323 0 : mRoots.RemoveElement(aStyleContext);
1324 : }
1325 :
1326 0 : if (mInReconstruct)
1327 0 : return;
1328 :
1329 0 : if (mUnusedRuleNodeCount >= kGCInterval) {
1330 0 : GCRuleTrees();
1331 : }
1332 : }
1333 :
1334 : void
1335 0 : nsStyleSet::GCRuleTrees()
1336 : {
1337 0 : mUnusedRuleNodeCount = 0;
1338 :
1339 : // Mark the style context tree by marking all style contexts which
1340 : // have no parent, which will mark all descendants. This will reach
1341 : // style contexts in the undisplayed map and "additional style
1342 : // contexts" since they are descendants of the roots.
1343 0 : for (PRInt32 i = mRoots.Length() - 1; i >= 0; --i) {
1344 0 : mRoots[i]->Mark();
1345 : }
1346 :
1347 : // Sweep the rule tree.
1348 : #ifdef DEBUG
1349 : bool deleted =
1350 : #endif
1351 0 : mRuleTree->Sweep();
1352 0 : NS_ASSERTION(!deleted, "Root node must not be gc'd");
1353 :
1354 : // Sweep the old rule trees.
1355 0 : for (PRUint32 i = mOldRuleTrees.Length(); i > 0; ) {
1356 0 : --i;
1357 0 : if (mOldRuleTrees[i]->Sweep()) {
1358 : // It was deleted, as it should be.
1359 0 : mOldRuleTrees.RemoveElementAt(i);
1360 : } else {
1361 0 : NS_NOTREACHED("old rule tree still referenced");
1362 : }
1363 : }
1364 0 : }
1365 :
1366 : static inline nsRuleNode*
1367 0 : SkipAnimationRules(nsRuleNode* aRuleNode, Element* aElement, bool isPseudo)
1368 : {
1369 0 : nsRuleNode* ruleNode = aRuleNode;
1370 0 : while (!ruleNode->IsRoot() &&
1371 0 : (ruleNode->GetLevel() == nsStyleSet::eTransitionSheet ||
1372 0 : ruleNode->GetLevel() == nsStyleSet::eAnimationSheet)) {
1373 0 : ruleNode = ruleNode->GetParent();
1374 : }
1375 0 : if (ruleNode != aRuleNode) {
1376 0 : NS_ASSERTION(aElement, "How can we have transition rules but no element?");
1377 : // Need to do an animation restyle, just like
1378 : // nsTransitionManager::WalkTransitionRule and
1379 : // nsAnimationManager::GetAnimationRule would.
1380 0 : nsRestyleHint hint = isPseudo ? eRestyle_Subtree : eRestyle_Self;
1381 : aRuleNode->GetPresContext()->PresShell()->RestyleForAnimation(aElement,
1382 0 : hint);
1383 : }
1384 0 : return ruleNode;
1385 : }
1386 :
1387 : already_AddRefed<nsStyleContext>
1388 0 : nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
1389 : nsStyleContext* aNewParentContext,
1390 : Element* aElement)
1391 : {
1392 0 : if (!aStyleContext) {
1393 0 : NS_NOTREACHED("must have style context");
1394 0 : return nsnull;
1395 : }
1396 :
1397 : // This short-circuit is OK because we don't call TryStartingTransition
1398 : // during style reresolution if the style context pointer hasn't changed.
1399 0 : if (aStyleContext->GetParent() == aNewParentContext) {
1400 0 : aStyleContext->AddRef();
1401 0 : return aStyleContext;
1402 : }
1403 :
1404 0 : nsIAtom* pseudoTag = aStyleContext->GetPseudo();
1405 0 : nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType();
1406 0 : nsRuleNode* ruleNode = aStyleContext->GetRuleNode();
1407 :
1408 : // Skip transition rules as needed just like
1409 : // nsTransitionManager::WalkTransitionRule would.
1410 0 : bool skipAnimationRules = PresContext()->IsProcessingRestyles() &&
1411 0 : !PresContext()->IsProcessingAnimationStyleChange();
1412 0 : if (skipAnimationRules) {
1413 : // Make sure that we're not using transition rules or animation rules for
1414 : // our new style context. If we need them, an animation restyle will
1415 : // provide.
1416 : ruleNode =
1417 : SkipAnimationRules(ruleNode, aElement,
1418 : pseudoType !=
1419 0 : nsCSSPseudoElements::ePseudo_NotPseudoElement);
1420 : }
1421 :
1422 0 : nsRuleNode* visitedRuleNode = nsnull;
1423 0 : nsStyleContext* visitedContext = aStyleContext->GetStyleIfVisited();
1424 : // Reparenting a style context just changes where we inherit from,
1425 : // not what rules we match or what our DOM looks like. In
1426 : // particular, it doesn't change whether this is a style context for
1427 : // a link.
1428 0 : if (visitedContext) {
1429 0 : visitedRuleNode = visitedContext->GetRuleNode();
1430 : // Again, skip transition rules as needed
1431 0 : if (skipAnimationRules) {
1432 : // FIXME do something here for animations?
1433 : visitedRuleNode =
1434 : SkipAnimationRules(visitedRuleNode, aElement,
1435 : pseudoType !=
1436 0 : nsCSSPseudoElements::ePseudo_NotPseudoElement);
1437 : }
1438 : }
1439 :
1440 : // If we're a style context for a link, then we already know whether
1441 : // our relevant link is visited, since that does not depend on our
1442 : // parent. Otherwise, we need to match aNewParentContext.
1443 0 : bool relevantLinkVisited = aStyleContext->IsLinkContext() ?
1444 : aStyleContext->RelevantLinkVisited() :
1445 0 : aNewParentContext->RelevantLinkVisited();
1446 :
1447 : return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
1448 0 : aStyleContext->IsLinkContext(),
1449 : relevantLinkVisited,
1450 : pseudoTag, pseudoType,
1451 : pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
1452 : pseudoType == nsCSSPseudoElements::ePseudo_before ||
1453 : pseudoType == nsCSSPseudoElements::ePseudo_after,
1454 0 : aElement);
1455 : }
1456 :
1457 : struct StatefulData : public StateRuleProcessorData {
1458 0 : StatefulData(nsPresContext* aPresContext, Element* aElement,
1459 : nsEventStates aStateMask, TreeMatchContext& aTreeMatchContext)
1460 : : StateRuleProcessorData(aPresContext, aElement, aStateMask,
1461 : aTreeMatchContext),
1462 0 : mHint(nsRestyleHint(0))
1463 0 : {}
1464 : nsRestyleHint mHint;
1465 : };
1466 :
1467 0 : static bool SheetHasDocumentStateStyle(nsIStyleRuleProcessor* aProcessor,
1468 : void *aData)
1469 : {
1470 0 : StatefulData* data = (StatefulData*)aData;
1471 0 : if (aProcessor->HasDocumentStateDependentStyle(data)) {
1472 0 : data->mHint = eRestyle_Self;
1473 0 : return false; // don't continue
1474 : }
1475 0 : return true; // continue
1476 : }
1477 :
1478 : // Test if style is dependent on a document state.
1479 : bool
1480 0 : nsStyleSet::HasDocumentStateDependentStyle(nsPresContext* aPresContext,
1481 : nsIContent* aContent,
1482 : nsEventStates aStateMask)
1483 : {
1484 0 : if (!aContent || !aContent->IsElement())
1485 0 : return false;
1486 :
1487 : TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
1488 0 : aContent->OwnerDoc());
1489 : StatefulData data(aPresContext, aContent->AsElement(), aStateMask,
1490 0 : treeContext);
1491 0 : WalkRuleProcessors(SheetHasDocumentStateStyle, &data, true);
1492 0 : return data.mHint != 0;
1493 : }
1494 :
1495 0 : static bool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
1496 : void *aData)
1497 : {
1498 0 : StatefulData* data = (StatefulData*)aData;
1499 0 : nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
1500 0 : data->mHint = nsRestyleHint(data->mHint | hint);
1501 0 : return true; // continue
1502 : }
1503 :
1504 : // Test if style is dependent on content state
1505 : nsRestyleHint
1506 0 : nsStyleSet::HasStateDependentStyle(nsPresContext* aPresContext,
1507 : Element* aElement,
1508 : nsEventStates aStateMask)
1509 : {
1510 : TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
1511 0 : aElement->OwnerDoc());
1512 0 : StatefulData data(aPresContext, aElement, aStateMask, treeContext);
1513 0 : WalkRuleProcessors(SheetHasStatefulStyle, &data, false);
1514 0 : return data.mHint;
1515 : }
1516 :
1517 : struct AttributeData : public AttributeRuleProcessorData {
1518 0 : AttributeData(nsPresContext* aPresContext,
1519 : Element* aElement, nsIAtom* aAttribute, PRInt32 aModType,
1520 : bool aAttrHasChanged, TreeMatchContext& aTreeMatchContext)
1521 : : AttributeRuleProcessorData(aPresContext, aElement, aAttribute, aModType,
1522 : aAttrHasChanged, aTreeMatchContext),
1523 0 : mHint(nsRestyleHint(0))
1524 0 : {}
1525 : nsRestyleHint mHint;
1526 : };
1527 :
1528 : static bool
1529 0 : SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
1530 : {
1531 0 : AttributeData* data = (AttributeData*)aData;
1532 0 : nsRestyleHint hint = aProcessor->HasAttributeDependentStyle(data);
1533 0 : data->mHint = nsRestyleHint(data->mHint | hint);
1534 0 : return true; // continue
1535 : }
1536 :
1537 : // Test if style is dependent on content state
1538 : nsRestyleHint
1539 0 : nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext,
1540 : Element* aElement,
1541 : nsIAtom* aAttribute,
1542 : PRInt32 aModType,
1543 : bool aAttrHasChanged)
1544 : {
1545 : TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
1546 0 : aElement->OwnerDoc());
1547 : AttributeData data(aPresContext, aElement, aAttribute,
1548 0 : aModType, aAttrHasChanged, treeContext);
1549 0 : WalkRuleProcessors(SheetHasAttributeStyle, &data, false);
1550 0 : return data.mHint;
1551 : }
1552 :
1553 : bool
1554 0 : nsStyleSet::MediumFeaturesChanged(nsPresContext* aPresContext)
1555 : {
1556 : // We can't use WalkRuleProcessors without a content node.
1557 0 : bool stylesChanged = false;
1558 0 : for (PRUint32 i = 0; i < ArrayLength(mRuleProcessors); ++i) {
1559 0 : nsIStyleRuleProcessor *processor = mRuleProcessors[i];
1560 0 : if (!processor) {
1561 0 : continue;
1562 : }
1563 0 : bool thisChanged = processor->MediumFeaturesChanged(aPresContext);
1564 0 : stylesChanged = stylesChanged || thisChanged;
1565 : }
1566 :
1567 0 : if (mBindingManager) {
1568 0 : bool thisChanged = false;
1569 0 : mBindingManager->MediumFeaturesChanged(aPresContext, &thisChanged);
1570 0 : stylesChanged = stylesChanged || thisChanged;
1571 : }
1572 :
1573 0 : return stylesChanged;
1574 : }
1575 :
1576 : nsCSSStyleSheet::EnsureUniqueInnerResult
1577 0 : nsStyleSet::EnsureUniqueInnerOnCSSSheets()
1578 : {
1579 0 : nsAutoTArray<nsCSSStyleSheet*, 32> queue;
1580 0 : for (PRUint32 i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
1581 0 : nsCOMArray<nsIStyleSheet> &sheets = mSheets[gCSSSheetTypes[i]];
1582 0 : for (PRUint32 j = 0, j_end = sheets.Count(); j < j_end; ++j) {
1583 0 : nsCSSStyleSheet *sheet = static_cast<nsCSSStyleSheet*>(sheets[j]);
1584 0 : if (!queue.AppendElement(sheet)) {
1585 0 : return nsCSSStyleSheet::eUniqueInner_CloneFailed;
1586 : }
1587 : }
1588 : }
1589 :
1590 0 : if (mBindingManager) {
1591 0 : mBindingManager->AppendAllSheets(queue);
1592 : }
1593 :
1594 : nsCSSStyleSheet::EnsureUniqueInnerResult res =
1595 0 : nsCSSStyleSheet::eUniqueInner_AlreadyUnique;
1596 0 : while (!queue.IsEmpty()) {
1597 0 : PRUint32 idx = queue.Length() - 1;
1598 0 : nsCSSStyleSheet *sheet = queue[idx];
1599 0 : queue.RemoveElementAt(idx);
1600 :
1601 : nsCSSStyleSheet::EnsureUniqueInnerResult sheetRes =
1602 0 : sheet->EnsureUniqueInner();
1603 0 : if (sheetRes == nsCSSStyleSheet::eUniqueInner_CloneFailed) {
1604 0 : return sheetRes;
1605 : }
1606 0 : if (sheetRes == nsCSSStyleSheet::eUniqueInner_ClonedInner) {
1607 0 : res = sheetRes;
1608 : }
1609 :
1610 : // Enqueue all the sheet's children.
1611 0 : if (!sheet->AppendAllChildSheets(queue)) {
1612 0 : return nsCSSStyleSheet::eUniqueInner_CloneFailed;
1613 : }
1614 : }
1615 0 : return res;
1616 : }
1617 :
1618 : nsIStyleRule*
1619 0 : nsStyleSet::InitialStyleRule()
1620 : {
1621 0 : if (!mInitialStyleRule) {
1622 0 : mInitialStyleRule = new nsInitialStyleRule;
1623 : }
1624 0 : return mInitialStyleRule;
1625 : }
|