Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /*
7 : * the container for the style sheets that apply to a presentation, and
8 : * the internal API that the style system exposes for creating (and
9 : * potentially re-creating) style contexts
10 : */
11 :
12 : #include "nsStyleSet.h"
13 :
14 : #include "mozilla/ArrayUtils.h"
15 : #include "mozilla/StyleSheetInlines.h"
16 : #include "mozilla/EffectCompositor.h"
17 : #include "mozilla/EnumeratedRange.h"
18 : #include "mozilla/EventStates.h"
19 : #include "mozilla/MemoryReporting.h"
20 : #include "mozilla/RuleProcessorCache.h"
21 : #include "mozilla/StyleSheetInlines.h"
22 : #include "nsIDocumentInlines.h"
23 : #include "nsRuleWalker.h"
24 : #include "nsStyleContext.h"
25 : #include "mozilla/css/StyleRule.h"
26 : #include "nsCSSAnonBoxes.h"
27 : #include "nsCSSPseudoElements.h"
28 : #include "nsCSSRuleProcessor.h"
29 : #include "nsDataHashtable.h"
30 : #include "nsIContent.h"
31 : #include "nsRuleData.h"
32 : #include "nsRuleProcessorData.h"
33 : #include "nsAnimationManager.h"
34 : #include "nsStyleSheetService.h"
35 : #include "mozilla/dom/Element.h"
36 : #include "mozilla/dom/ShadowRoot.h"
37 : #include "GeckoProfiler.h"
38 : #include "nsHTMLCSSStyleSheet.h"
39 : #include "nsHTMLStyleSheet.h"
40 : #include "nsCSSRules.h"
41 : #include "nsPrintfCString.h"
42 : #include "nsIFrame.h"
43 : #include "mozilla/RestyleManager.h"
44 : #include "mozilla/RestyleManagerInlines.h"
45 : #include "nsQueryObject.h"
46 : #include "nsStyleContextInlines.h"
47 :
48 : #include <inttypes.h>
49 :
50 : using namespace mozilla;
51 : using namespace mozilla::dom;
52 :
53 430 : NS_IMPL_ISUPPORTS(nsEmptyStyleRule, nsIStyleRule)
54 :
55 : /* virtual */ void
56 46 : nsEmptyStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
57 : {
58 46 : }
59 :
60 : /* virtual */ bool
61 0 : nsEmptyStyleRule::MightMapInheritedStyleData()
62 : {
63 0 : return false;
64 : }
65 :
66 : /* virtual */ bool
67 0 : nsEmptyStyleRule::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
68 : nsCSSValue* aValue)
69 : {
70 0 : MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
71 : return false;
72 : }
73 :
74 : #ifdef DEBUG
75 : /* virtual */ void
76 0 : nsEmptyStyleRule::List(FILE* out, int32_t aIndent) const
77 : {
78 0 : nsAutoCString indentStr;
79 0 : for (int32_t index = aIndent; --index >= 0; ) {
80 0 : indentStr.AppendLiteral(" ");
81 : }
82 0 : fprintf_stderr(out, "%s[empty style rule] {}\n", indentStr.get());
83 0 : }
84 : #endif
85 :
86 0 : NS_IMPL_ISUPPORTS(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 0 : 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 0 : 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__moz_script_level) ||
108 0 : index == nsCSSProps::PropertyIndexInStruct(
109 0 : eCSSProperty__moz_script_size_multiplier) ||
110 0 : index == nsCSSProps::PropertyIndexInStruct(
111 0 : eCSSProperty__moz_script_min_size) ||
112 0 : index == nsCSSProps::PropertyIndexInStruct(
113 0 : eCSSProperty__moz_math_variant) ||
114 0 : index == nsCSSProps::PropertyIndexInStruct(
115 : eCSSProperty__moz_math_display)) {
116 0 : continue;
117 : }
118 : }
119 0 : if (value->GetUnit() == eCSSUnit_Null) {
120 0 : value->SetInitialValue();
121 : }
122 : }
123 : }
124 : }
125 0 : }
126 :
127 : /* virtual */ bool
128 0 : nsInitialStyleRule::MightMapInheritedStyleData()
129 : {
130 0 : return true;
131 : }
132 :
133 : /* virtual */ bool
134 0 : nsInitialStyleRule::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
135 : nsCSSValue* aValue)
136 : {
137 0 : MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
138 : return false;
139 : }
140 :
141 : #ifdef DEBUG
142 : /* virtual */ void
143 0 : nsInitialStyleRule::List(FILE* out, int32_t aIndent) const
144 : {
145 0 : nsAutoCString indentStr;
146 0 : for (int32_t index = aIndent; --index >= 0; ) {
147 0 : indentStr.AppendLiteral(" ");
148 : }
149 0 : fprintf_stderr(out, "%s[initial style rule] {}\n", indentStr.get());
150 0 : }
151 : #endif
152 :
153 36 : NS_IMPL_ISUPPORTS(nsDisableTextZoomStyleRule, nsIStyleRule)
154 :
155 : /* virtual */ void
156 0 : nsDisableTextZoomStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
157 : {
158 0 : if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Font)))
159 0 : return;
160 :
161 0 : nsCSSValue* value = aRuleData->ValueForTextZoom();
162 0 : if (value->GetUnit() == eCSSUnit_Null)
163 0 : value->SetNoneValue();
164 : }
165 :
166 : /* virtual */ bool
167 0 : nsDisableTextZoomStyleRule::MightMapInheritedStyleData()
168 : {
169 0 : return true;
170 : }
171 :
172 : /* virtual */ bool
173 0 : nsDisableTextZoomStyleRule::
174 : GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty, nsCSSValue* aValue)
175 : {
176 0 : MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
177 : return false;
178 : }
179 :
180 : #ifdef DEBUG
181 : /* virtual */ void
182 0 : nsDisableTextZoomStyleRule::List(FILE* out, int32_t aIndent) const
183 : {
184 0 : nsAutoCString indentStr;
185 0 : for (int32_t index = aIndent; --index >= 0; ) {
186 0 : indentStr.AppendLiteral(" ");
187 : }
188 0 : fprintf_stderr(out, "%s[disable text zoom style rule] {}\n", indentStr.get());
189 0 : }
190 : #endif
191 :
192 : static const SheetType gCSSSheetTypes[] = {
193 : // From lowest to highest in cascading order.
194 : SheetType::Agent,
195 : SheetType::User,
196 : SheetType::Doc,
197 : SheetType::ScopedDoc,
198 : SheetType::Override
199 : };
200 :
201 : /* static */ bool
202 320 : nsStyleSet::IsCSSSheetType(SheetType aSheetType)
203 : {
204 945 : for (SheetType type : gCSSSheetTypes) {
205 833 : if (type == aSheetType) {
206 208 : return true;
207 : }
208 : }
209 112 : return false;
210 : }
211 :
212 28 : nsStyleSet::nsStyleSet()
213 : : mRuleTree(nullptr),
214 : mBatching(0),
215 : mStylesHaveChanged(0),
216 : mInShutdown(false),
217 : mInGC(false),
218 : mAuthorStyleDisabled(false),
219 : mInReconstruct(false),
220 : mInitFontFeatureValuesLookup(true),
221 : mNeedsRestyleAfterEnsureUniqueInner(false),
222 : mDirty(0),
223 : mRootStyleContextCount(0),
224 : #ifdef DEBUG
225 : mOldRootNode(nullptr),
226 : #endif
227 28 : mUnusedRuleNodeCount(0)
228 : {
229 28 : }
230 :
231 8 : nsStyleSet::~nsStyleSet()
232 : {
233 24 : for (SheetType type : gCSSSheetTypes) {
234 62 : for (CSSStyleSheet* sheet : mSheets[type]) {
235 42 : sheet->DropStyleSet(this);
236 : }
237 : }
238 :
239 : // drop reference to cached rule processors
240 : nsCSSRuleProcessor* rp;
241 4 : rp = static_cast<nsCSSRuleProcessor*>(mRuleProcessors[SheetType::Agent].get());
242 4 : if (rp) {
243 4 : MOZ_ASSERT(rp->IsShared());
244 4 : rp->ReleaseStyleSetRef();
245 : }
246 4 : rp = static_cast<nsCSSRuleProcessor*>(mRuleProcessors[SheetType::User].get());
247 4 : if (rp) {
248 0 : MOZ_ASSERT(rp->IsShared());
249 0 : rp->ReleaseStyleSetRef();
250 : }
251 4 : }
252 :
253 : size_t
254 21 : nsStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
255 : {
256 21 : size_t n = aMallocSizeOf(this);
257 :
258 210 : for (SheetType type : MakeEnumeratedRange(SheetType::Count)) {
259 189 : if (mRuleProcessors[type]) {
260 110 : bool shared = false;
261 110 : if (type == SheetType::Agent || type == SheetType::User) {
262 : // The only two origins we consider caching rule processors for.
263 : nsCSSRuleProcessor* rp =
264 21 : static_cast<nsCSSRuleProcessor*>(mRuleProcessors[type].get());
265 21 : shared = rp->IsShared();
266 : }
267 110 : if (!shared) {
268 89 : n += mRuleProcessors[type]->SizeOfIncludingThis(aMallocSizeOf);
269 : }
270 : }
271 : // We don't own the sheets (either the nsLayoutStyleSheetCache singleton
272 : // or our document owns them).
273 189 : n += mSheets[type].ShallowSizeOfExcludingThis(aMallocSizeOf);
274 : }
275 :
276 21 : for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
277 0 : n += mScopedDocSheetRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
278 : }
279 21 : n += mScopedDocSheetRuleProcessors.ShallowSizeOfExcludingThis(aMallocSizeOf);
280 :
281 21 : return n;
282 : }
283 :
284 : void
285 28 : nsStyleSet::Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager)
286 : {
287 28 : mFirstLineRule = new nsEmptyStyleRule;
288 28 : mFirstLetterRule = new nsEmptyStyleRule;
289 28 : mPlaceholderRule = new nsEmptyStyleRule;
290 28 : mDisableTextZoomStyleRule = new nsDisableTextZoomStyleRule;
291 :
292 28 : mRuleTree = nsRuleNode::CreateRootNode(aPresContext);
293 28 : mBindingManager = aBindingManager;
294 :
295 : // Make an explicit GatherRuleProcessors call for the levels that
296 : // don't have style sheets. The other levels will have their calls
297 : // triggered by DirtyRuleProcessors.
298 28 : GatherRuleProcessors(SheetType::PresHint);
299 28 : GatherRuleProcessors(SheetType::StyleAttr);
300 28 : GatherRuleProcessors(SheetType::Animation);
301 28 : GatherRuleProcessors(SheetType::Transition);
302 28 : }
303 :
304 : nsresult
305 2 : nsStyleSet::BeginReconstruct()
306 : {
307 2 : NS_ASSERTION(!mInReconstruct, "Unmatched begin/end?");
308 2 : NS_ASSERTION(mRuleTree, "Reconstructing before first construction?");
309 2 : mInReconstruct = true;
310 :
311 : // Clear any ArenaRefPtr-managed style contexts, as we don't want them
312 : // held on to after the rule tree has been reconstructed.
313 2 : PresContext()->PresShell()->ClearArenaRefPtrs(eArenaObjectID_GeckoStyleContext);
314 :
315 : // Clear our cached style contexts for non-inheriting anonymous boxes.
316 2 : ClearNonInheritingStyleContexts();
317 :
318 : #ifdef DEBUG
319 2 : MOZ_ASSERT(!mOldRootNode);
320 2 : mOldRootNode = mRuleTree;
321 : #endif
322 :
323 : // Create a new rule tree root, dropping the reference to our old rule tree.
324 : // After reconstruction, we will re-enable GC, and allow everything to be
325 : // collected.
326 2 : mRuleTree = nsRuleNode::CreateRootNode(mRuleTree->PresContext());
327 :
328 2 : return NS_OK;
329 : }
330 :
331 : void
332 2 : nsStyleSet::EndReconstruct()
333 : {
334 2 : NS_ASSERTION(mInReconstruct, "Unmatched begin/end?");
335 2 : mInReconstruct = false;
336 2 : GCRuleTrees();
337 2 : }
338 :
339 : typedef nsDataHashtable<nsPtrHashKey<nsINode>, uint32_t> ScopeDepthCache;
340 :
341 : // Returns the depth of a style scope element, with 1 being the depth of
342 : // a style scope element that has no ancestor style scope elements. The
343 : // depth does not count intervening non-scope elements.
344 : static uint32_t
345 0 : GetScopeDepth(nsINode* aScopeElement, ScopeDepthCache& aCache)
346 : {
347 0 : nsINode* parent = aScopeElement->GetParent();
348 0 : if (!parent || !parent->IsElementInStyleScope()) {
349 0 : return 1;
350 : }
351 :
352 0 : uint32_t depth = aCache.Get(aScopeElement);
353 0 : if (!depth) {
354 0 : for (nsINode* n = parent; n; n = n->GetParent()) {
355 0 : if (n->IsScopedStyleRoot()) {
356 0 : depth = GetScopeDepth(n, aCache) + 1;
357 0 : aCache.Put(aScopeElement, depth);
358 0 : break;
359 : }
360 : }
361 : }
362 0 : return depth;
363 : }
364 :
365 : struct ScopedSheetOrder
366 : {
367 : CSSStyleSheet* mSheet;
368 : uint32_t mDepth;
369 : uint32_t mOrder;
370 :
371 0 : bool operator==(const ScopedSheetOrder& aRHS) const
372 : {
373 0 : return mDepth == aRHS.mDepth &&
374 0 : mOrder == aRHS.mOrder;
375 : }
376 :
377 0 : bool operator<(const ScopedSheetOrder& aRHS) const
378 : {
379 0 : if (mDepth != aRHS.mDepth) {
380 0 : return mDepth < aRHS.mDepth;
381 : }
382 0 : return mOrder < aRHS.mOrder;
383 : }
384 : };
385 :
386 : // Sorts aSheets such that style sheets for ancestor scopes come
387 : // before those for descendant scopes, and with sheets for a single
388 : // scope in document order.
389 : static void
390 0 : SortStyleSheetsByScope(nsTArray<CSSStyleSheet*>& aSheets)
391 : {
392 0 : uint32_t n = aSheets.Length();
393 0 : if (n == 1) {
394 0 : return;
395 : }
396 :
397 0 : ScopeDepthCache cache;
398 :
399 0 : nsTArray<ScopedSheetOrder> sheets;
400 0 : sheets.SetLength(n);
401 :
402 : // For each sheet, record the depth of its scope element and its original
403 : // document order.
404 0 : for (uint32_t i = 0; i < n; i++) {
405 0 : sheets[i].mSheet = aSheets[i];
406 0 : sheets[i].mDepth = GetScopeDepth(aSheets[i]->GetScopeElement(), cache);
407 0 : sheets[i].mOrder = i;
408 : }
409 :
410 : // Sort by depth first, then document order.
411 0 : sheets.Sort();
412 :
413 0 : for (uint32_t i = 0; i < n; i++) {
414 0 : aSheets[i] = sheets[i].mSheet;
415 : }
416 : }
417 :
418 : nsresult
419 160 : nsStyleSet::GatherRuleProcessors(SheetType aType)
420 : {
421 160 : NS_ENSURE_FALSE(mInShutdown, NS_ERROR_FAILURE);
422 :
423 : // We might be in GatherRuleProcessors because we are dropping a sheet,
424 : // resulting in an nsCSSSelector being destroyed. Tell the
425 : // RestyleManager for each document we're used in so that they can
426 : // drop any nsCSSSelector pointers (used for eRestyle_SomeDescendants)
427 : // in their mPendingRestyles.
428 160 : if (IsCSSSheetType(aType)) {
429 48 : ClearSelectors();
430 : }
431 320 : nsCOMPtr<nsIStyleRuleProcessor> oldRuleProcessor(mRuleProcessors[aType]);
432 320 : nsTArray<nsCOMPtr<nsIStyleRuleProcessor>> oldScopedDocRuleProcessors;
433 160 : if (aType == SheetType::Agent || aType == SheetType::User) {
434 : // drop reference to cached rule processor
435 : nsCSSRuleProcessor* rp =
436 36 : static_cast<nsCSSRuleProcessor*>(mRuleProcessors[aType].get());
437 36 : if (rp) {
438 5 : MOZ_ASSERT(rp->IsShared());
439 5 : rp->ReleaseStyleSetRef();
440 : }
441 : }
442 160 : mRuleProcessors[aType] = nullptr;
443 160 : if (aType == SheetType::ScopedDoc) {
444 0 : for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
445 0 : nsIStyleRuleProcessor* processor = mScopedDocSheetRuleProcessors[i].get();
446 : Element* scope =
447 0 : static_cast<nsCSSRuleProcessor*>(processor)->GetScopeElement();
448 0 : scope->ClearIsScopedStyleRoot();
449 : }
450 :
451 : // Clear mScopedDocSheetRuleProcessors, but save it.
452 0 : oldScopedDocRuleProcessors.SwapElements(mScopedDocSheetRuleProcessors);
453 : }
454 160 : if (mAuthorStyleDisabled && (aType == SheetType::Doc ||
455 0 : aType == SheetType::ScopedDoc ||
456 160 : aType == SheetType::StyleAttr)) {
457 : // Don't regather if this level is disabled. Note that we gather
458 : // preshint sheets no matter what, but then skip them for some
459 : // elements later if mAuthorStyleDisabled.
460 0 : return NS_OK;
461 : }
462 160 : switch (aType) {
463 : // levels that do not contain CSS style sheets
464 : case SheetType::Animation:
465 28 : MOZ_ASSERT(mSheets[aType].IsEmpty());
466 28 : mRuleProcessors[aType] = PresContext()->EffectCompositor()->
467 56 : RuleProcessor(EffectCompositor::CascadeLevel::Animations);
468 28 : return NS_OK;
469 : case SheetType::Transition:
470 28 : MOZ_ASSERT(mSheets[aType].IsEmpty());
471 28 : mRuleProcessors[aType] = PresContext()->EffectCompositor()->
472 56 : RuleProcessor(EffectCompositor::CascadeLevel::Transitions);
473 28 : return NS_OK;
474 : case SheetType::StyleAttr:
475 28 : MOZ_ASSERT(mSheets[aType].IsEmpty());
476 28 : mRuleProcessors[aType] = PresContext()->Document()->GetInlineStyleSheet();
477 28 : return NS_OK;
478 : case SheetType::PresHint:
479 28 : MOZ_ASSERT(mSheets[aType].IsEmpty());
480 28 : mRuleProcessors[aType] =
481 56 : PresContext()->Document()->GetAttributeStyleSheet();
482 28 : return NS_OK;
483 : default:
484 : // keep going
485 48 : break;
486 : }
487 48 : MOZ_ASSERT(IsCSSSheetType(aType));
488 48 : if (aType == SheetType::ScopedDoc) {
489 : // Create a rule processor for each scope.
490 0 : uint32_t count = mSheets[SheetType::ScopedDoc].Length();
491 0 : if (count) {
492 : // Gather the scoped style sheets into an array as
493 : // CSSStyleSheets, and mark all of their scope elements
494 : // as scoped style roots.
495 0 : nsTArray<CSSStyleSheet*> sheets(count);
496 0 : for (CSSStyleSheet* sheet : mSheets[SheetType::ScopedDoc]) {
497 0 : sheets.AppendElement(sheet);
498 :
499 0 : Element* scope = sheet->GetScopeElement();
500 0 : scope->SetIsScopedStyleRoot();
501 : }
502 :
503 : // Sort the scoped style sheets so that those for the same scope are
504 : // adjacent and that ancestor scopes come before descendent scopes.
505 0 : SortStyleSheetsByScope(sheets);
506 :
507 : // Put the old scoped rule processors in a hashtable so that we
508 : // can retrieve them efficiently, even in edge cases like the
509 : // simultaneous removal and addition of a large number of elements
510 : // with scoped sheets.
511 : nsDataHashtable<nsPtrHashKey<Element>,
512 0 : nsCSSRuleProcessor*> oldScopedRuleProcessorHash;
513 0 : for (size_t i = oldScopedDocRuleProcessors.Length(); i-- != 0; ) {
514 : nsCSSRuleProcessor* oldRP =
515 0 : static_cast<nsCSSRuleProcessor*>(oldScopedDocRuleProcessors[i].get());
516 0 : Element* scope = oldRP->GetScopeElement();
517 0 : MOZ_ASSERT(!oldScopedRuleProcessorHash.Get(scope),
518 : "duplicate rule processors for same scope element?");
519 0 : oldScopedRuleProcessorHash.Put(scope, oldRP);
520 : }
521 :
522 0 : uint32_t start = 0, end;
523 0 : do {
524 : // Find the range of style sheets with the same scope.
525 0 : Element* scope = sheets[start]->GetScopeElement();
526 0 : end = start + 1;
527 0 : while (end < count && sheets[end]->GetScopeElement() == scope) {
528 0 : end++;
529 : }
530 :
531 0 : scope->SetIsScopedStyleRoot();
532 :
533 : // Create a rule processor for the scope.
534 0 : nsTArray<RefPtr<CSSStyleSheet>> sheetsForScope;
535 0 : sheetsForScope.AppendElements(sheets.Elements() + start, end - start);
536 0 : nsCSSRuleProcessor* oldRP = oldScopedRuleProcessorHash.Get(scope);
537 : mScopedDocSheetRuleProcessors.AppendElement
538 0 : (new nsCSSRuleProcessor(Move(sheetsForScope), aType, scope, oldRP));
539 :
540 0 : start = end;
541 0 : } while (start < count);
542 : }
543 0 : return NS_OK;
544 : }
545 48 : if (!mSheets[aType].IsEmpty()) {
546 46 : switch (aType) {
547 : case SheetType::Agent:
548 : case SheetType::User: {
549 : // levels containing non-scoped CSS style sheets whose rule processors
550 : // we want to re-use
551 68 : nsTArray<CSSStyleSheet*> sheets(mSheets[aType].Length());
552 155 : for (CSSStyleSheet* sheet : mSheets[aType]) {
553 121 : sheets.AppendElement(sheet);
554 : }
555 : nsCSSRuleProcessor* rp =
556 34 : RuleProcessorCache::GetRuleProcessor(sheets, PresContext());
557 34 : if (!rp) {
558 20 : rp = new nsCSSRuleProcessor(mSheets[aType], aType, nullptr,
559 10 : static_cast<nsCSSRuleProcessor*>(
560 : oldRuleProcessor.get()),
561 20 : true /* aIsShared */);
562 20 : nsTArray<css::DocumentRule*> documentRules;
563 20 : nsDocumentRuleResultCacheKey cacheKey;
564 10 : rp->TakeDocumentRulesAndCacheKey(PresContext(),
565 10 : documentRules, cacheKey);
566 : RuleProcessorCache::PutRuleProcessor(sheets,
567 10 : Move(documentRules),
568 10 : cacheKey, rp);
569 : }
570 34 : mRuleProcessors[aType] = rp;
571 34 : rp->AddStyleSetRef();
572 34 : break;
573 : }
574 : case SheetType::Doc:
575 : case SheetType::Override: {
576 : // levels containing non-scoped CSS stylesheets whose rule processors
577 : // we don't want to re-use
578 12 : mRuleProcessors[aType] =
579 12 : new nsCSSRuleProcessor(mSheets[aType], aType, nullptr,
580 12 : static_cast<nsCSSRuleProcessor*>(
581 36 : oldRuleProcessor.get()));
582 12 : } break;
583 :
584 : default:
585 0 : MOZ_ASSERT_UNREACHABLE("non-CSS sheet types should be handled above");
586 : break;
587 : }
588 : }
589 :
590 48 : return NS_OK;
591 : }
592 :
593 : nsresult
594 17 : nsStyleSet::AppendStyleSheet(SheetType aType, CSSStyleSheet* aSheet)
595 : {
596 17 : NS_PRECONDITION(aSheet, "null arg");
597 17 : NS_ASSERTION(aSheet->IsApplicable(),
598 : "Inapplicable sheet being placed in style set");
599 17 : bool present = mSheets[aType].RemoveElement(aSheet);
600 17 : mSheets[aType].AppendElement(aSheet);
601 :
602 17 : if (!present && IsCSSSheetType(aType)) {
603 17 : aSheet->AddStyleSet(StyleSetHandle(this));
604 : }
605 :
606 17 : return DirtyRuleProcessors(aType);
607 : }
608 :
609 : nsresult
610 93 : nsStyleSet::PrependStyleSheet(SheetType aType, CSSStyleSheet* aSheet)
611 : {
612 93 : NS_PRECONDITION(aSheet, "null arg");
613 93 : NS_ASSERTION(aSheet->IsApplicable(),
614 : "Inapplicable sheet being placed in style set");
615 93 : bool present = mSheets[aType].RemoveElement(aSheet);
616 93 : mSheets[aType].InsertElementAt(0, aSheet);
617 :
618 93 : if (!present && IsCSSSheetType(aType)) {
619 93 : aSheet->AddStyleSet(StyleSetHandle(this));
620 : }
621 :
622 93 : return DirtyRuleProcessors(aType);
623 : }
624 :
625 : nsresult
626 2 : nsStyleSet::RemoveStyleSheet(SheetType aType, CSSStyleSheet* aSheet)
627 : {
628 2 : NS_PRECONDITION(aSheet, "null arg");
629 2 : NS_ASSERTION(aSheet->IsComplete(),
630 : "Incomplete sheet being removed from style set");
631 2 : if (mSheets[aType].RemoveElement(aSheet)) {
632 2 : if (IsCSSSheetType(aType)) {
633 2 : aSheet->DropStyleSet(StyleSetHandle(this));
634 : }
635 : }
636 :
637 2 : return DirtyRuleProcessors(aType);
638 : }
639 :
640 : nsresult
641 0 : nsStyleSet::ReplaceSheets(SheetType aType,
642 : const nsTArray<RefPtr<CSSStyleSheet>>& aNewSheets)
643 : {
644 0 : bool cssSheetType = IsCSSSheetType(aType);
645 0 : if (cssSheetType) {
646 0 : for (CSSStyleSheet* sheet : mSheets[aType]) {
647 0 : sheet->DropStyleSet(StyleSetHandle(this));
648 : }
649 : }
650 :
651 0 : mSheets[aType].Clear();
652 0 : mSheets[aType].AppendElements(aNewSheets);
653 :
654 0 : if (cssSheetType) {
655 0 : for (CSSStyleSheet* sheet : mSheets[aType]) {
656 0 : sheet->AddStyleSet(StyleSetHandle(this));
657 : }
658 : }
659 :
660 0 : return DirtyRuleProcessors(aType);
661 : }
662 :
663 : nsresult
664 0 : nsStyleSet::InsertStyleSheetBefore(SheetType aType, CSSStyleSheet* aNewSheet,
665 : CSSStyleSheet* aReferenceSheet)
666 : {
667 0 : NS_PRECONDITION(aNewSheet && aReferenceSheet, "null arg");
668 0 : NS_ASSERTION(aNewSheet->IsApplicable(),
669 : "Inapplicable sheet being placed in style set");
670 :
671 0 : bool present = mSheets[aType].RemoveElement(aNewSheet);
672 0 : int32_t idx = mSheets[aType].IndexOf(aReferenceSheet);
673 0 : if (idx < 0)
674 0 : return NS_ERROR_INVALID_ARG;
675 :
676 0 : mSheets[aType].InsertElementAt(idx, aNewSheet);
677 :
678 0 : if (!present && IsCSSSheetType(aType)) {
679 0 : aNewSheet->AddStyleSet(StyleSetHandle(this));
680 : }
681 :
682 0 : return DirtyRuleProcessors(aType);
683 : }
684 :
685 : static inline uint32_t
686 823 : DirtyBit(SheetType aType)
687 : {
688 823 : return 1 << uint32_t(aType);
689 : }
690 :
691 : nsresult
692 123 : nsStyleSet::DirtyRuleProcessors(SheetType aType)
693 : {
694 123 : if (!mBatching)
695 2 : return GatherRuleProcessors(aType);
696 :
697 121 : mDirty |= DirtyBit(aType);
698 121 : return NS_OK;
699 : }
700 :
701 : bool
702 10 : nsStyleSet::GetAuthorStyleDisabled() const
703 : {
704 10 : return mAuthorStyleDisabled;
705 : }
706 :
707 : nsresult
708 0 : nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
709 : {
710 0 : if (aStyleDisabled == !mAuthorStyleDisabled) {
711 0 : mAuthorStyleDisabled = aStyleDisabled;
712 0 : BeginUpdate();
713 0 : mDirty |= DirtyBit(SheetType::Doc) |
714 0 : DirtyBit(SheetType::ScopedDoc) |
715 0 : DirtyBit(SheetType::StyleAttr);
716 0 : return EndUpdate();
717 : }
718 0 : return NS_OK;
719 : }
720 :
721 : // -------- Doc Sheets
722 :
723 : nsresult
724 11 : nsStyleSet::AddDocStyleSheet(CSSStyleSheet* aSheet, nsIDocument* aDocument)
725 : {
726 11 : NS_PRECONDITION(aSheet && aDocument, "null arg");
727 11 : NS_ASSERTION(aSheet->IsApplicable(),
728 : "Inapplicable sheet being placed in style set");
729 :
730 11 : SheetType type = aSheet->GetScopeElement() ?
731 : SheetType::ScopedDoc :
732 11 : SheetType::Doc;
733 11 : nsTArray<RefPtr<CSSStyleSheet>>& sheets = mSheets[type];
734 :
735 11 : bool present = sheets.RemoveElement(aSheet);
736 :
737 11 : size_t index = aDocument->FindDocStyleSheetInsertionPoint(sheets, aSheet);
738 11 : sheets.InsertElementAt(index, aSheet);
739 :
740 11 : if (!present) {
741 11 : aSheet->AddStyleSet(StyleSetHandle(this));
742 : }
743 :
744 11 : return DirtyRuleProcessors(type);
745 : }
746 :
747 : void
748 0 : nsStyleSet::AppendAllXBLStyleSheets(nsTArray<StyleSheet*>& aArray) const
749 : {
750 0 : if (mBindingManager) {
751 0 : mBindingManager->AppendAllSheets(aArray);
752 : }
753 0 : }
754 :
755 : nsresult
756 0 : nsStyleSet::RemoveDocStyleSheet(CSSStyleSheet* aSheet)
757 : {
758 0 : bool isScoped = aSheet->GetScopeElement();
759 0 : return RemoveStyleSheet(isScoped ? SheetType::ScopedDoc : SheetType::Doc,
760 0 : aSheet);
761 : }
762 :
763 : // Batching
764 : void
765 93 : nsStyleSet::BeginUpdate()
766 : {
767 93 : ++mBatching;
768 93 : }
769 :
770 : nsresult
771 93 : nsStyleSet::EndUpdate()
772 : {
773 93 : NS_ASSERTION(mBatching > 0, "Unbalanced EndUpdate");
774 93 : if (--mBatching) {
775 : // We're not completely done yet.
776 15 : return NS_OK;
777 : }
778 :
779 780 : for (SheetType type : MakeEnumeratedRange(SheetType::Count)) {
780 702 : if (mDirty & DirtyBit(type)) {
781 46 : nsresult rv = GatherRuleProcessors(type);
782 46 : NS_ENSURE_SUCCESS(rv, rv);
783 : }
784 : }
785 :
786 78 : mDirty = 0;
787 78 : return NS_OK;
788 : }
789 :
790 : template<class T>
791 : static bool
792 26482 : EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
793 : {
794 26482 : T* data = static_cast<T*>(aData);
795 26482 : aProcessor->RulesMatching(data);
796 26482 : return true;
797 : }
798 :
799 : static inline bool
800 3201 : IsMoreSpecificThanAnimation(nsRuleNode *aRuleNode)
801 : {
802 6759 : return !aRuleNode->IsRoot() &&
803 6380 : (aRuleNode->GetLevel() == SheetType::Transition ||
804 6388 : aRuleNode->IsImportantRule());
805 : }
806 :
807 : static nsIStyleRule*
808 2836 : GetAnimationRule(nsRuleNode *aRuleNode)
809 : {
810 2836 : nsRuleNode *n = aRuleNode;
811 3566 : while (IsMoreSpecificThanAnimation(n)) {
812 365 : n = n->GetParent();
813 : }
814 :
815 2836 : if (n->IsRoot() || n->GetLevel() != SheetType::Animation) {
816 2836 : return nullptr;
817 : }
818 :
819 0 : return n->GetRule();
820 : }
821 :
822 : static nsRuleNode*
823 0 : ReplaceAnimationRule(nsRuleNode *aOldRuleNode,
824 : nsIStyleRule *aOldAnimRule,
825 : nsIStyleRule *aNewAnimRule)
826 : {
827 0 : nsTArray<nsRuleNode*> moreSpecificNodes;
828 :
829 0 : nsRuleNode *n = aOldRuleNode;
830 0 : while (IsMoreSpecificThanAnimation(n)) {
831 0 : moreSpecificNodes.AppendElement(n);
832 0 : n = n->GetParent();
833 : }
834 :
835 0 : if (aOldAnimRule) {
836 0 : MOZ_ASSERT(n->GetRule() == aOldAnimRule, "wrong rule");
837 0 : MOZ_ASSERT(n->GetLevel() == SheetType::Animation,
838 : "wrong level");
839 0 : n = n->GetParent();
840 : }
841 :
842 0 : MOZ_ASSERT(!IsMoreSpecificThanAnimation(n) &&
843 : (n->IsRoot() || n->GetLevel() != SheetType::Animation),
844 : "wrong level");
845 :
846 0 : if (aNewAnimRule) {
847 0 : n = n->Transition(aNewAnimRule, SheetType::Animation, false);
848 0 : n->SetIsAnimationRule();
849 : }
850 :
851 0 : for (uint32_t i = moreSpecificNodes.Length(); i-- != 0; ) {
852 0 : nsRuleNode *oldNode = moreSpecificNodes[i];
853 0 : n = n->Transition(oldNode->GetRule(), oldNode->GetLevel(),
854 0 : oldNode->IsImportantRule());
855 : }
856 :
857 0 : return n;
858 : }
859 :
860 : /**
861 : * |GetContext| implements sharing of style contexts (not just the data
862 : * on the rule nodes) between siblings and cousins of the same
863 : * generation. (It works for cousins of the same generation since
864 : * |aParentContext| could itself be a shared context.)
865 : */
866 : already_AddRefed<nsStyleContext>
867 3340 : nsStyleSet::GetContext(nsStyleContext* aParentContext,
868 : nsRuleNode* aRuleNode,
869 : // aVisitedRuleNode may be null; if it is null
870 : // it means that we don't need to force creation
871 : // of a StyleIfVisited. (But if we make one
872 : // because aParentContext has one, then aRuleNode
873 : // should be used.)
874 : nsRuleNode* aVisitedRuleNode,
875 : nsIAtom* aPseudoTag,
876 : CSSPseudoElementType aPseudoType,
877 : Element* aElementForAnimation,
878 : uint32_t aFlags)
879 : {
880 3340 : NS_PRECONDITION((!aPseudoTag &&
881 : aPseudoType ==
882 : CSSPseudoElementType::NotPseudo) ||
883 : (aPseudoTag &&
884 : nsCSSPseudoElements::GetPseudoType(
885 : aPseudoTag, CSSEnabledState::eIgnoreEnabledState) ==
886 : aPseudoType),
887 : "Pseudo mismatch");
888 :
889 3340 : if (aVisitedRuleNode == aRuleNode) {
890 : // No need to force creation of a visited style in this case.
891 0 : aVisitedRuleNode = nullptr;
892 : }
893 :
894 : // Ensure |aVisitedRuleNode != nullptr| corresponds to the need to
895 : // create an if-visited style context, and that in that case, we have
896 : // parentIfVisited set correctly.
897 : nsStyleContext *parentIfVisited =
898 3340 : aParentContext ? aParentContext->GetStyleIfVisited() : nullptr;
899 3340 : if (parentIfVisited) {
900 0 : if (!aVisitedRuleNode) {
901 0 : aVisitedRuleNode = aRuleNode;
902 : }
903 : } else {
904 3340 : if (aVisitedRuleNode) {
905 0 : parentIfVisited = aParentContext;
906 : }
907 : }
908 :
909 3340 : if (aFlags & eIsLink) {
910 : // If this node is a link, we want its visited's style context's
911 : // parent to be the regular style context of its parent, because
912 : // only the visitedness of the relevant link should influence style.
913 0 : parentIfVisited = aParentContext;
914 : }
915 :
916 3340 : bool relevantLinkVisited = (aFlags & eIsLink) ?
917 0 : (aFlags & eIsVisitedLink) :
918 3340 : (aParentContext && aParentContext->RelevantLinkVisited());
919 :
920 6680 : RefPtr<nsStyleContext> result;
921 3340 : if (aParentContext)
922 6306 : result = aParentContext->AsGecko()->FindChildWithRules(aPseudoTag, aRuleNode,
923 : aVisitedRuleNode,
924 3153 : relevantLinkVisited);
925 :
926 3340 : if (!result) {
927 : // |aVisitedRuleNode| may have a ref-count of zero since we are yet
928 : // to create the style context that will hold an owning reference to it.
929 : // As a result, we need to make sure it stays alive until that point
930 : // in case something in the first call to NS_NewStyleContext triggers a
931 : // GC sweep of rule nodes.
932 4406 : RefPtr<nsRuleNode> kungFuDeathGrip{aVisitedRuleNode};
933 :
934 4406 : result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType,
935 : aRuleNode,
936 4406 : aFlags & eSkipParentDisplayBasedStyleFixup);
937 2203 : if (aVisitedRuleNode) {
938 : RefPtr<nsStyleContext> resultIfVisited =
939 0 : NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType,
940 : aVisitedRuleNode,
941 0 : aFlags & eSkipParentDisplayBasedStyleFixup);
942 0 : resultIfVisited->SetIsStyleIfVisited();
943 0 : result->SetStyleIfVisited(resultIfVisited.forget());
944 :
945 0 : if (relevantLinkVisited) {
946 0 : result->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED);
947 : }
948 : }
949 : }
950 : else {
951 1137 : NS_ASSERTION(result->GetPseudoType() == aPseudoType, "Unexpected type");
952 1137 : NS_ASSERTION(result->GetPseudo() == aPseudoTag, "Unexpected pseudo");
953 : }
954 :
955 3340 : if (aFlags & eDoAnimation) {
956 :
957 2836 : nsIStyleRule *oldAnimRule = GetAnimationRule(aRuleNode);
958 2836 : nsIStyleRule *animRule = nullptr;
959 :
960 : // Ignore animations for print or print preview, and for elements
961 : // that are not attached to the document tree.
962 5672 : if (PresContext()->IsDynamic() &&
963 2836 : aElementForAnimation->IsInComposedDoc()) {
964 : // Update CSS animations in case the animation-name has just changed.
965 2834 : PresContext()->AnimationManager()->UpdateAnimations(result,
966 2834 : aElementForAnimation);
967 2834 : PresContext()->EffectCompositor()->UpdateEffectProperties(
968 2834 : result.get(), aElementForAnimation, result->GetPseudoType());
969 :
970 : animRule = PresContext()->EffectCompositor()->
971 2834 : GetAnimationRule(aElementForAnimation,
972 : result->GetPseudoType(),
973 : EffectCompositor::CascadeLevel::Animations,
974 2834 : result);
975 : }
976 :
977 2836 : MOZ_ASSERT(result->RuleNode() == aRuleNode,
978 : "unexpected rule node");
979 2836 : MOZ_ASSERT(!result->GetStyleIfVisited() == !aVisitedRuleNode,
980 : "unexpected visited rule node");
981 2836 : MOZ_ASSERT(!aVisitedRuleNode ||
982 : result->GetStyleIfVisited()->RuleNode() == aVisitedRuleNode,
983 : "unexpected visited rule node");
984 2836 : MOZ_ASSERT(!aVisitedRuleNode ||
985 : oldAnimRule == GetAnimationRule(aVisitedRuleNode),
986 : "animation rule mismatch between rule nodes");
987 2836 : if (oldAnimRule != animRule) {
988 : // FIXME: This should use ResolveStyleWithReplacement instead (and
989 : // we can remove ReplaceAnimationRule), since
990 : // ResolveStyleWithReplacement should now be equally efficient
991 : // (except for the extra code complexity to be more general).
992 : nsRuleNode *ruleNode =
993 0 : ReplaceAnimationRule(aRuleNode, oldAnimRule, animRule);
994 : nsRuleNode *visitedRuleNode = aVisitedRuleNode
995 0 : ? ReplaceAnimationRule(aVisitedRuleNode, oldAnimRule, animRule)
996 0 : : nullptr;
997 0 : MOZ_ASSERT(!visitedRuleNode ||
998 : GetAnimationRule(ruleNode) ==
999 : GetAnimationRule(visitedRuleNode),
1000 : "animation rule mismatch between rule nodes");
1001 0 : result = GetContext(aParentContext, ruleNode, visitedRuleNode,
1002 : aPseudoTag, aPseudoType, nullptr,
1003 0 : aFlags & ~eDoAnimation);
1004 : }
1005 : }
1006 :
1007 6200 : if (aElementForAnimation &&
1008 2867 : aElementForAnimation->IsHTMLElement(nsGkAtoms::body) &&
1009 3347 : aPseudoType == CSSPseudoElementType::NotPseudo &&
1010 7 : PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
1011 7 : nsIDocument* doc = aElementForAnimation->GetUncomposedDoc();
1012 7 : if (doc && doc->GetBodyElement() == aElementForAnimation) {
1013 : // Update the prescontext's body color
1014 7 : PresContext()->SetBodyTextColor(result->StyleColor()->mColor);
1015 : }
1016 : }
1017 :
1018 6680 : return result.forget();
1019 : }
1020 :
1021 : void
1022 479 : nsStyleSet::AddImportantRules(nsRuleNode* aCurrLevelNode,
1023 : nsRuleNode* aLastPrevLevelNode,
1024 : nsRuleWalker* aRuleWalker)
1025 : {
1026 479 : NS_ASSERTION(aCurrLevelNode &&
1027 : aCurrLevelNode != aLastPrevLevelNode, "How did we get here?");
1028 :
1029 958 : AutoTArray<nsIStyleRule*, 16> importantRules;
1030 1660 : for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
1031 : node = node->GetParent()) {
1032 : // We guarantee that we never walk the root node here, so no need
1033 : // to null-check GetRule(). Furthermore, it must be a CSS rule.
1034 1181 : NS_ASSERTION(RefPtr<css::Declaration>(do_QueryObject(node->GetRule())),
1035 : "Unexpected non-CSS rule");
1036 :
1037 : nsIStyleRule* impRule =
1038 1181 : static_cast<css::Declaration*>(node->GetRule())->GetImportantStyleData();
1039 1181 : if (impRule)
1040 524 : importantRules.AppendElement(impRule);
1041 : }
1042 :
1043 479 : NS_ASSERTION(importantRules.Length() != 0,
1044 : "Why did we think there were important rules?");
1045 :
1046 1003 : for (uint32_t i = importantRules.Length(); i-- != 0; ) {
1047 524 : aRuleWalker->Forward(importantRules[i]);
1048 : }
1049 479 : }
1050 :
1051 : #ifdef DEBUG
1052 : void
1053 23515 : nsStyleSet::AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
1054 : nsRuleNode* aLastPrevLevelNode)
1055 : {
1056 23515 : if (!aCurrLevelNode)
1057 0 : return;
1058 :
1059 33025 : for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
1060 : node = node->GetParent()) {
1061 19020 : RefPtr<css::Declaration> declaration(do_QueryObject(node->GetRule()));
1062 9510 : NS_ASSERTION(declaration, "Unexpected non-CSS rule");
1063 :
1064 9510 : NS_ASSERTION(!declaration->GetImportantStyleData(),
1065 : "Unexpected important style source");
1066 : }
1067 : }
1068 :
1069 : void
1070 11997 : nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
1071 : nsRuleNode* aLastPrevLevelNode)
1072 : {
1073 11997 : if (!aCurrLevelNode)
1074 0 : return;
1075 :
1076 12286 : for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
1077 : node = node->GetParent()) {
1078 289 : nsIStyleRule *rule = node->GetRule();
1079 578 : RefPtr<css::Declaration> declaration(do_QueryObject(rule));
1080 289 : if (declaration) {
1081 : RefPtr<css::StyleRule> cssRule =
1082 300 : do_QueryObject(declaration->GetOwningRule());
1083 150 : NS_ASSERTION(!cssRule || !cssRule->Selector(),
1084 : "Unexpected CSS rule");
1085 : }
1086 : }
1087 : }
1088 : #endif
1089 :
1090 : // Enumerate the rules in a way that cares about the order of the rules.
1091 : void
1092 3999 : nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
1093 : RuleProcessorData* aData, Element* aElement,
1094 : nsRuleWalker* aRuleWalker)
1095 : {
1096 7998 : AUTO_PROFILER_LABEL("nsStyleSet::FileRules", CSS);
1097 :
1098 3999 : NS_ASSERTION(mBatching == 0, "rule processors out of date");
1099 :
1100 : // Cascading order:
1101 : // [least important]
1102 : // - UA normal rules = Agent normal
1103 : // - User normal rules = User normal
1104 : // - Presentation hints = PresHint normal
1105 : // - Author normal rules = Document normal
1106 : // - Override normal rules = Override normal
1107 : // - animation rules = Animation normal
1108 : // - Author !important rules = Document !important
1109 : // - Override !important rules = Override !important
1110 : // - User !important rules = User !important
1111 : // - UA !important rules = Agent !important
1112 : // - transition rules = Transition normal
1113 : // [most important]
1114 :
1115 : // Save off the last rule before we start walking our agent sheets;
1116 : // this will be either the root or one of the restriction rules.
1117 3999 : nsRuleNode* lastRestrictionRN = aRuleWalker->CurrentNode();
1118 :
1119 3999 : aRuleWalker->SetLevel(SheetType::Agent, false, true);
1120 3999 : if (mRuleProcessors[SheetType::Agent])
1121 3999 : (*aCollectorFunc)(mRuleProcessors[SheetType::Agent], aData);
1122 3999 : nsRuleNode* lastAgentRN = aRuleWalker->CurrentNode();
1123 3999 : bool haveImportantUARules = !aRuleWalker->GetCheckForImportantRules();
1124 :
1125 3999 : aRuleWalker->SetLevel(SheetType::User, false, true);
1126 : bool skipUserStyles =
1127 3999 : aElement && aElement->IsInNativeAnonymousSubtree();
1128 3999 : if (!skipUserStyles && mRuleProcessors[SheetType::User]) // NOTE: different
1129 27 : (*aCollectorFunc)(mRuleProcessors[SheetType::User], aData);
1130 3999 : nsRuleNode* lastUserRN = aRuleWalker->CurrentNode();
1131 3999 : bool haveImportantUserRules = !aRuleWalker->GetCheckForImportantRules();
1132 :
1133 3999 : aRuleWalker->SetLevel(SheetType::PresHint, false, false);
1134 3999 : if (mRuleProcessors[SheetType::PresHint])
1135 3999 : (*aCollectorFunc)(mRuleProcessors[SheetType::PresHint], aData);
1136 3999 : nsRuleNode* lastPresHintRN = aRuleWalker->CurrentNode();
1137 :
1138 3999 : aRuleWalker->SetLevel(SheetType::Doc, false, true);
1139 3999 : bool cutOffInheritance = false;
1140 3999 : if (mBindingManager && aElement) {
1141 : // We can supply additional document-level sheets that should be walked.
1142 3789 : mBindingManager->WalkRules(aCollectorFunc,
1143 : static_cast<ElementDependentRuleProcessorData*>(aData),
1144 3789 : &cutOffInheritance);
1145 : }
1146 7811 : if (!skipUserStyles && !cutOffInheritance && // NOTE: different
1147 3812 : mRuleProcessors[SheetType::Doc])
1148 3474 : (*aCollectorFunc)(mRuleProcessors[SheetType::Doc], aData);
1149 3999 : nsRuleNode* lastDocRN = aRuleWalker->CurrentNode();
1150 3999 : bool haveImportantDocRules = !aRuleWalker->GetCheckForImportantRules();
1151 7998 : nsTArray<nsRuleNode*> lastScopedRNs;
1152 7998 : nsTArray<bool> haveImportantScopedRules;
1153 3999 : bool haveAnyImportantScopedRules = false;
1154 11810 : if (!skipUserStyles && !cutOffInheritance &&
1155 7601 : aElement && aElement->IsElementInStyleScope()) {
1156 0 : lastScopedRNs.SetLength(mScopedDocSheetRuleProcessors.Length());
1157 0 : haveImportantScopedRules.SetLength(mScopedDocSheetRuleProcessors.Length());
1158 0 : for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
1159 0 : aRuleWalker->SetLevel(SheetType::ScopedDoc, false, true);
1160 : nsCSSRuleProcessor* processor =
1161 0 : static_cast<nsCSSRuleProcessor*>(mScopedDocSheetRuleProcessors[i].get());
1162 0 : aData->mScope = processor->GetScopeElement();
1163 0 : (*aCollectorFunc)(mScopedDocSheetRuleProcessors[i], aData);
1164 0 : lastScopedRNs[i] = aRuleWalker->CurrentNode();
1165 0 : haveImportantScopedRules[i] = !aRuleWalker->GetCheckForImportantRules();
1166 0 : haveAnyImportantScopedRules = haveAnyImportantScopedRules || haveImportantScopedRules[i];
1167 : }
1168 0 : aData->mScope = nullptr;
1169 : }
1170 3999 : nsRuleNode* lastScopedRN = aRuleWalker->CurrentNode();
1171 3999 : aRuleWalker->SetLevel(SheetType::StyleAttr, false, true);
1172 3999 : if (mRuleProcessors[SheetType::StyleAttr])
1173 3999 : (*aCollectorFunc)(mRuleProcessors[SheetType::StyleAttr], aData);
1174 3999 : nsRuleNode* lastStyleAttrRN = aRuleWalker->CurrentNode();
1175 3999 : bool haveImportantStyleAttrRules = !aRuleWalker->GetCheckForImportantRules();
1176 :
1177 3999 : aRuleWalker->SetLevel(SheetType::Override, false, true);
1178 3999 : if (mRuleProcessors[SheetType::Override])
1179 0 : (*aCollectorFunc)(mRuleProcessors[SheetType::Override], aData);
1180 3999 : nsRuleNode* lastOvrRN = aRuleWalker->CurrentNode();
1181 3999 : bool haveImportantOverrideRules = !aRuleWalker->GetCheckForImportantRules();
1182 :
1183 : // This needs to match IsMoreSpecificThanAnimation() above.
1184 3999 : aRuleWalker->SetLevel(SheetType::Animation, false, false);
1185 3999 : (*aCollectorFunc)(mRuleProcessors[SheetType::Animation], aData);
1186 :
1187 3999 : if (haveAnyImportantScopedRules) {
1188 0 : for (uint32_t i = lastScopedRNs.Length(); i-- != 0; ) {
1189 0 : aRuleWalker->SetLevel(SheetType::ScopedDoc, true, false);
1190 0 : nsRuleNode* startRN = lastScopedRNs[i];
1191 0 : nsRuleNode* endRN = i == 0 ? lastDocRN : lastScopedRNs[i - 1];
1192 0 : if (haveImportantScopedRules[i]) {
1193 0 : AddImportantRules(startRN, endRN, aRuleWalker); // scoped
1194 : }
1195 : #ifdef DEBUG
1196 : else {
1197 0 : AssertNoImportantRules(startRN, endRN);
1198 : }
1199 : #endif
1200 : }
1201 : }
1202 : #ifdef DEBUG
1203 : else {
1204 3999 : AssertNoImportantRules(lastScopedRN, lastDocRN);
1205 : }
1206 : #endif
1207 :
1208 3999 : if (haveImportantDocRules) {
1209 238 : aRuleWalker->SetLevel(SheetType::Doc, true, false);
1210 238 : AddImportantRules(lastDocRN, lastPresHintRN, aRuleWalker); // doc
1211 : }
1212 : #ifdef DEBUG
1213 : else {
1214 3761 : AssertNoImportantRules(lastDocRN, lastPresHintRN);
1215 : }
1216 : #endif
1217 :
1218 3999 : if (haveImportantStyleAttrRules) {
1219 0 : aRuleWalker->SetLevel(SheetType::StyleAttr, true, false);
1220 0 : AddImportantRules(lastStyleAttrRN, lastScopedRN, aRuleWalker); // style attr
1221 : }
1222 : #ifdef DEBUG
1223 : else {
1224 3999 : AssertNoImportantRules(lastStyleAttrRN, lastScopedRN);
1225 : }
1226 : #endif
1227 :
1228 3999 : if (haveImportantOverrideRules) {
1229 0 : aRuleWalker->SetLevel(SheetType::Override, true, false);
1230 0 : AddImportantRules(lastOvrRN, lastStyleAttrRN, aRuleWalker); // override
1231 : }
1232 : #ifdef DEBUG
1233 : else {
1234 3999 : AssertNoImportantRules(lastOvrRN, lastStyleAttrRN);
1235 : }
1236 : #endif
1237 :
1238 : #ifdef DEBUG
1239 3999 : AssertNoCSSRules(lastPresHintRN, lastUserRN);
1240 : #endif
1241 :
1242 3999 : if (haveImportantUserRules) {
1243 0 : aRuleWalker->SetLevel(SheetType::User, true, false);
1244 0 : AddImportantRules(lastUserRN, lastAgentRN, aRuleWalker); //user
1245 : }
1246 : #ifdef DEBUG
1247 : else {
1248 3999 : AssertNoImportantRules(lastUserRN, lastAgentRN);
1249 : }
1250 : #endif
1251 :
1252 3999 : if (haveImportantUARules) {
1253 241 : aRuleWalker->SetLevel(SheetType::Agent, true, false);
1254 241 : AddImportantRules(lastAgentRN, lastRestrictionRN, aRuleWalker); //agent
1255 : }
1256 : #ifdef DEBUG
1257 : else {
1258 3758 : AssertNoImportantRules(lastAgentRN, lastRestrictionRN);
1259 : }
1260 : #endif
1261 :
1262 : #ifdef DEBUG
1263 3999 : AssertNoCSSRules(lastRestrictionRN, mRuleTree);
1264 : #endif
1265 :
1266 : #ifdef DEBUG
1267 3999 : nsRuleNode *lastImportantRN = aRuleWalker->CurrentNode();
1268 : #endif
1269 3999 : aRuleWalker->SetLevel(SheetType::Transition, false, false);
1270 3999 : (*aCollectorFunc)(mRuleProcessors[SheetType::Transition], aData);
1271 : #ifdef DEBUG
1272 3999 : AssertNoCSSRules(aRuleWalker->CurrentNode(), lastImportantRN);
1273 : #endif
1274 :
1275 3999 : }
1276 :
1277 : // Enumerate all the rules in a way that doesn't care about the order
1278 : // of the rules and doesn't walk !important-rules.
1279 : void
1280 701 : nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
1281 : ElementDependentRuleProcessorData* aData,
1282 : bool aWalkAllXBLStylesheets)
1283 : {
1284 701 : NS_ASSERTION(mBatching == 0, "rule processors out of date");
1285 :
1286 701 : if (mRuleProcessors[SheetType::Agent])
1287 701 : (*aFunc)(mRuleProcessors[SheetType::Agent], aData);
1288 :
1289 701 : bool skipUserStyles = aData->mElement->IsInNativeAnonymousSubtree();
1290 701 : if (!skipUserStyles && mRuleProcessors[SheetType::User]) // NOTE: different
1291 1 : (*aFunc)(mRuleProcessors[SheetType::User], aData);
1292 :
1293 701 : if (mRuleProcessors[SheetType::PresHint])
1294 701 : (*aFunc)(mRuleProcessors[SheetType::PresHint], aData);
1295 :
1296 701 : bool cutOffInheritance = false;
1297 701 : if (mBindingManager) {
1298 : // We can supply additional document-level sheets that should be walked.
1299 701 : if (aWalkAllXBLStylesheets) {
1300 2 : mBindingManager->WalkAllRules(aFunc, aData);
1301 : } else {
1302 699 : mBindingManager->WalkRules(aFunc, aData, &cutOffInheritance);
1303 : }
1304 : }
1305 701 : if (!skipUserStyles && !cutOffInheritance) {
1306 517 : if (mRuleProcessors[SheetType::Doc]) // NOTE: different
1307 514 : (*aFunc)(mRuleProcessors[SheetType::Doc], aData);
1308 517 : if (aData->mElement->IsElementInStyleScope()) {
1309 0 : for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++)
1310 0 : (*aFunc)(mScopedDocSheetRuleProcessors[i], aData);
1311 : }
1312 : }
1313 701 : if (mRuleProcessors[SheetType::StyleAttr])
1314 701 : (*aFunc)(mRuleProcessors[SheetType::StyleAttr], aData);
1315 701 : if (mRuleProcessors[SheetType::Override])
1316 0 : (*aFunc)(mRuleProcessors[SheetType::Override], aData);
1317 701 : (*aFunc)(mRuleProcessors[SheetType::Animation], aData);
1318 701 : (*aFunc)(mRuleProcessors[SheetType::Transition], aData);
1319 701 : }
1320 :
1321 : static void
1322 1855 : InitStyleScopes(TreeMatchContext& aTreeContext, Element* aElement)
1323 : {
1324 1855 : if (aElement->IsElementInStyleScope()) {
1325 0 : aTreeContext.InitStyleScopes(aElement->GetParentElementCrossingShadowRoot());
1326 : }
1327 1855 : }
1328 :
1329 : already_AddRefed<nsStyleContext>
1330 349 : nsStyleSet::ResolveStyleFor(Element* aElement,
1331 : nsStyleContext* aParentContext)
1332 : {
1333 : TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
1334 698 : aElement->OwnerDoc());
1335 349 : InitStyleScopes(treeContext, aElement);
1336 698 : return ResolveStyleFor(aElement, aParentContext, treeContext);
1337 : }
1338 :
1339 : already_AddRefed<nsStyleContext>
1340 2501 : nsStyleSet::ResolveStyleForInternal(Element* aElement,
1341 : nsStyleContext* aParentContext,
1342 : TreeMatchContext& aTreeMatchContext,
1343 : AnimationFlag aAnimationFlag)
1344 : {
1345 2501 : NS_ENSURE_FALSE(mInShutdown, nullptr);
1346 2501 : NS_ASSERTION(aElement, "aElement must not be null");
1347 :
1348 5002 : nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1349 2501 : aTreeMatchContext.ResetForUnvisitedMatching();
1350 : ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker,
1351 2501 : aTreeMatchContext);
1352 2501 : WalkDisableTextZoomRule(aElement, &ruleWalker);
1353 : FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
1354 2501 : &ruleWalker);
1355 :
1356 2501 : nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1357 2501 : nsRuleNode *visitedRuleNode = nullptr;
1358 :
1359 2501 : if (aTreeMatchContext.HaveRelevantLink()) {
1360 0 : aTreeMatchContext.ResetForVisitedMatching();
1361 0 : ruleWalker.Reset();
1362 : FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
1363 0 : &ruleWalker);
1364 0 : visitedRuleNode = ruleWalker.CurrentNode();
1365 : }
1366 :
1367 2501 : uint32_t flags = (aAnimationFlag == eWithAnimation) ? eDoAnimation : eNoFlags;
1368 2501 : if (nsCSSRuleProcessor::IsLink(aElement)) {
1369 0 : flags |= eIsLink;
1370 : }
1371 5002 : if (nsCSSRuleProcessor::GetContentState(aElement, aTreeMatchContext).
1372 5002 : HasState(NS_EVENT_STATE_VISITED)) {
1373 0 : flags |= eIsVisitedLink;
1374 : }
1375 2501 : if (aTreeMatchContext.mSkippingParentDisplayBasedStyleFixup) {
1376 807 : flags |= eSkipParentDisplayBasedStyleFixup;
1377 : }
1378 :
1379 : return GetContext(aParentContext, ruleNode, visitedRuleNode,
1380 : nullptr, CSSPseudoElementType::NotPseudo,
1381 2501 : aElement, flags);
1382 : }
1383 :
1384 : already_AddRefed<nsStyleContext>
1385 2501 : nsStyleSet::ResolveStyleFor(Element* aElement,
1386 : nsStyleContext* aParentContext,
1387 : TreeMatchContext& aTreeMatchContext)
1388 : {
1389 : return ResolveStyleForInternal(aElement,
1390 : aParentContext,
1391 : aTreeMatchContext,
1392 2501 : eWithAnimation);
1393 : }
1394 :
1395 : already_AddRefed<nsStyleContext>
1396 0 : nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
1397 : const nsTArray< nsCOMPtr<nsIStyleRule> > &aRules)
1398 : {
1399 0 : NS_ENSURE_FALSE(mInShutdown, nullptr);
1400 :
1401 0 : nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1402 : // FIXME: Perhaps this should be passed in, but it probably doesn't
1403 : // matter.
1404 0 : ruleWalker.SetLevel(SheetType::Doc, false, false);
1405 0 : for (uint32_t i = 0; i < aRules.Length(); i++) {
1406 0 : ruleWalker.ForwardOnPossiblyCSSRule(aRules.ElementAt(i));
1407 : }
1408 :
1409 : return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
1410 : nullptr, CSSPseudoElementType::NotPseudo,
1411 0 : nullptr, eNoFlags);
1412 : }
1413 :
1414 : already_AddRefed<nsStyleContext>
1415 20 : nsStyleSet::ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
1416 : const nsCOMArray<nsIStyleRule> &aRules)
1417 : {
1418 20 : NS_ENSURE_FALSE(mInShutdown, nullptr);
1419 :
1420 40 : nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1421 20 : ruleWalker.SetCurrentNode(aBaseContext->RuleNode());
1422 : // This needs to be the transition sheet because that is the highest
1423 : // level of the cascade, and thus the only thing that makes sense if
1424 : // we are ever going to call ResolveStyleWithReplacement on the
1425 : // resulting context. It's also the right thing for the one case (the
1426 : // transition manager's cover rule) where we put the result of this
1427 : // function in the style context tree.
1428 20 : ruleWalker.SetLevel(SheetType::Transition, false, false);
1429 40 : for (int32_t i = 0; i < aRules.Count(); i++) {
1430 20 : ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
1431 : }
1432 :
1433 20 : nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1434 20 : nsRuleNode *visitedRuleNode = nullptr;
1435 :
1436 20 : if (aBaseContext->GetStyleIfVisited()) {
1437 0 : ruleWalker.SetCurrentNode(aBaseContext->GetStyleIfVisited()->RuleNode());
1438 0 : for (int32_t i = 0; i < aRules.Count(); i++) {
1439 0 : ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
1440 : }
1441 0 : visitedRuleNode = ruleWalker.CurrentNode();
1442 : }
1443 :
1444 20 : uint32_t flags = eNoFlags;
1445 20 : if (aBaseContext->IsLinkContext()) {
1446 0 : flags |= eIsLink;
1447 :
1448 : // GetContext handles propagating RelevantLinkVisited state from the
1449 : // parent in non-link cases; all we need to pass in is if this link
1450 : // is visited.
1451 0 : if (aBaseContext->RelevantLinkVisited()) {
1452 0 : flags |= eIsVisitedLink;
1453 : }
1454 : }
1455 20 : return GetContext(aBaseContext->GetParent(), ruleNode, visitedRuleNode,
1456 : aBaseContext->GetPseudo(),
1457 : aBaseContext->GetPseudoType(),
1458 40 : nullptr, flags);
1459 : }
1460 :
1461 : struct RuleNodeInfo {
1462 : nsIStyleRule* mRule;
1463 : SheetType mLevel;
1464 : bool mIsImportant;
1465 : bool mIsAnimationRule;
1466 : };
1467 :
1468 : struct CascadeLevel {
1469 : SheetType mLevel;
1470 : bool mIsImportant;
1471 : bool mCheckForImportantRules;
1472 : nsRestyleHint mLevelReplacementHint;
1473 : };
1474 :
1475 : static const CascadeLevel gCascadeLevels[] = {
1476 : { SheetType::Agent, false, false, nsRestyleHint(0) },
1477 : { SheetType::User, false, false, nsRestyleHint(0) },
1478 : { SheetType::PresHint, false, false, nsRestyleHint(0) },
1479 : { SheetType::Doc, false, false, nsRestyleHint(0) },
1480 : { SheetType::ScopedDoc, false, false, nsRestyleHint(0) },
1481 : { SheetType::StyleAttr, false, true, eRestyle_StyleAttribute |
1482 : eRestyle_StyleAttribute_Animations },
1483 : { SheetType::Override, false, false, nsRestyleHint(0) },
1484 : { SheetType::Animation, false, false, eRestyle_CSSAnimations },
1485 : { SheetType::ScopedDoc, true, false, nsRestyleHint(0) },
1486 : { SheetType::Doc, true, false, nsRestyleHint(0) },
1487 : { SheetType::StyleAttr, true, false, eRestyle_StyleAttribute |
1488 : eRestyle_StyleAttribute_Animations },
1489 : { SheetType::Override, true, false, nsRestyleHint(0) },
1490 : { SheetType::User, true, false, nsRestyleHint(0) },
1491 : { SheetType::Agent, true, false, nsRestyleHint(0) },
1492 : { SheetType::Transition, false, false, eRestyle_CSSTransitions },
1493 : };
1494 :
1495 : nsRuleNode*
1496 49 : nsStyleSet::RuleNodeWithReplacement(Element* aElement,
1497 : Element* aPseudoElement,
1498 : nsRuleNode* aOldRuleNode,
1499 : CSSPseudoElementType aPseudoType,
1500 : nsRestyleHint aReplacements)
1501 : {
1502 49 : NS_ASSERTION(mBatching == 0, "rule processors out of date");
1503 :
1504 49 : MOZ_ASSERT(!aPseudoElement ==
1505 : (aPseudoType >= CSSPseudoElementType::Count ||
1506 : !(nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(aPseudoType) ||
1507 : nsCSSPseudoElements::PseudoElementSupportsUserActionState(aPseudoType))),
1508 : "should have aPseudoElement only for certain pseudo elements");
1509 :
1510 : // Remove the Force bits, which we don't need and which could confuse
1511 : // the remainingReplacements code below.
1512 49 : aReplacements &= ~(eRestyle_Force | eRestyle_ForceDescendants);
1513 :
1514 49 : MOZ_ASSERT(!(aReplacements & ~(eRestyle_CSSTransitions |
1515 : eRestyle_CSSAnimations |
1516 : eRestyle_StyleAttribute |
1517 : eRestyle_StyleAttribute_Animations)),
1518 : "unexpected replacement bits");
1519 :
1520 : // This array can be hot and often grows to ~20 elements, so inline storage
1521 : // is best.
1522 98 : AutoTArray<RuleNodeInfo, 30> rules;
1523 :
1524 49 : const CascadeLevel* startingLevel = gCascadeLevels;
1525 49 : nsRuleNode* startingNode = mRuleTree;
1526 49 : if (mInReconstruct) {
1527 : // Replace the entire path in the rule tree, since the rule tree has
1528 : // a new root.
1529 :
1530 144 : for (nsRuleNode* ruleNode = aOldRuleNode; !ruleNode->IsRoot();
1531 : ruleNode = ruleNode->GetParent()) {
1532 118 : RuleNodeInfo* curRule = rules.AppendElement();
1533 118 : curRule->mRule = ruleNode->GetRule();
1534 118 : curRule->mLevel = ruleNode->GetLevel();
1535 118 : curRule->mIsImportant = ruleNode->IsImportantRule();
1536 118 : curRule->mIsAnimationRule = ruleNode->IsAnimationRule();
1537 : }
1538 : } else {
1539 23 : if (aReplacements == nsRestyleHint(0)) {
1540 : // Nothing to do.
1541 0 : return aOldRuleNode;
1542 : }
1543 :
1544 : // Walk up the rule tree from aOldNode to figure out the *part* of
1545 : // the path in the rule tree that we need to replace.
1546 :
1547 23 : nsRestyleHint remainingReplacements = aReplacements;
1548 23 : nsRuleNode* ruleNode = aOldRuleNode;
1549 100 : for (const CascadeLevel *level = ArrayEnd(gCascadeLevels);
1550 50 : level-- != gCascadeLevels; ) {
1551 : SheetType nodeLevel;
1552 : bool nodeIsImportant;
1553 240 : while (!ruleNode->IsRoot() &&
1554 138 : (nodeLevel = ruleNode->GetLevel()) == level->mLevel &&
1555 : (nodeIsImportant = ruleNode->IsImportantRule()) ==
1556 11 : level->mIsImportant) {
1557 8 : if (!(level->mLevelReplacementHint & aReplacements)) {
1558 0 : RuleNodeInfo* curRule = rules.AppendElement();
1559 0 : curRule->mRule = ruleNode->GetRule();
1560 0 : curRule->mLevel = nodeLevel;
1561 0 : curRule->mIsImportant = nodeIsImportant;
1562 0 : curRule->mIsAnimationRule = ruleNode->IsAnimationRule();
1563 : }
1564 :
1565 8 : ruleNode = ruleNode->GetParent();
1566 : }
1567 82 : if (!level->mIsImportant &&
1568 32 : (level->mLevelReplacementHint & aReplacements)) {
1569 23 : remainingReplacements &= ~level->mLevelReplacementHint;
1570 23 : if (remainingReplacements == nsRestyleHint(0)) {
1571 : // We've found the part of the path in the rule tree we
1572 : // need to replace.
1573 23 : startingLevel = level;
1574 23 : startingNode = ruleNode;
1575 23 : break;
1576 : }
1577 : }
1578 : }
1579 23 : MOZ_ASSERT(remainingReplacements == nsRestyleHint(0),
1580 : "unexpected replacements (but we safely handle this case by "
1581 : "falling through to replacing the whole path");
1582 : }
1583 :
1584 98 : nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1585 49 : ruleWalker.SetCurrentNode(startingNode);
1586 49 : auto rulesIndex = rules.Length();
1587 :
1588 : // We need to transfer this information between the non-!important and
1589 : // !important phases for the style attribute level.
1590 49 : nsRuleNode* lastScopedRN = nullptr;
1591 49 : nsRuleNode* lastStyleAttrRN = nullptr;
1592 49 : bool haveImportantStyleAttrRules = false;
1593 :
1594 489 : for (const CascadeLevel *level = startingLevel,
1595 49 : *levelEnd = ArrayEnd(gCascadeLevels);
1596 489 : level != levelEnd; ++level) {
1597 :
1598 440 : bool doReplace = level->mLevelReplacementHint & aReplacements;
1599 :
1600 440 : ruleWalker.SetLevel(level->mLevel, level->mIsImportant,
1601 880 : level->mCheckForImportantRules && doReplace);
1602 :
1603 440 : if (doReplace) {
1604 30 : switch (level->mLevel) {
1605 : case SheetType::Animation: {
1606 0 : if (aPseudoType == CSSPseudoElementType::NotPseudo ||
1607 0 : aPseudoType == CSSPseudoElementType::before ||
1608 : aPseudoType == CSSPseudoElementType::after) {
1609 : nsIStyleRule* rule = PresContext()->EffectCompositor()->
1610 0 : GetAnimationRule(aElement, aPseudoType,
1611 : EffectCompositor::CascadeLevel::Animations,
1612 0 : nullptr);
1613 0 : if (rule) {
1614 0 : ruleWalker.ForwardOnPossiblyCSSRule(rule);
1615 0 : ruleWalker.CurrentNode()->SetIsAnimationRule();
1616 : }
1617 : }
1618 0 : break;
1619 : }
1620 : case SheetType::Transition: {
1621 24 : if (aPseudoType == CSSPseudoElementType::NotPseudo ||
1622 0 : aPseudoType == CSSPseudoElementType::before ||
1623 : aPseudoType == CSSPseudoElementType::after) {
1624 : nsIStyleRule* rule = PresContext()->EffectCompositor()->
1625 24 : GetAnimationRule(aElement, aPseudoType,
1626 : EffectCompositor::CascadeLevel::Transitions,
1627 24 : nullptr);
1628 24 : if (rule) {
1629 8 : ruleWalker.ForwardOnPossiblyCSSRule(rule);
1630 8 : ruleWalker.CurrentNode()->SetIsAnimationRule();
1631 : }
1632 : }
1633 24 : break;
1634 : }
1635 : case SheetType::StyleAttr: {
1636 6 : if (!level->mIsImportant) {
1637 : // First time through, we handle the non-!important rule.
1638 : nsHTMLCSSStyleSheet* ruleProcessor =
1639 : static_cast<nsHTMLCSSStyleSheet*>(
1640 3 : mRuleProcessors[SheetType::StyleAttr].get());
1641 3 : if (ruleProcessor) {
1642 3 : lastScopedRN = ruleWalker.CurrentNode();
1643 3 : if (aPseudoType ==
1644 : CSSPseudoElementType::NotPseudo) {
1645 3 : ruleProcessor->ElementRulesMatching(PresContext(),
1646 : aElement,
1647 3 : &ruleWalker);
1648 0 : } else if (aPseudoType <
1649 0 : CSSPseudoElementType::Count &&
1650 : nsCSSPseudoElements::
1651 0 : PseudoElementSupportsStyleAttribute(aPseudoType)) {
1652 : ruleProcessor->PseudoElementRulesMatching(aPseudoElement,
1653 : aPseudoType,
1654 0 : &ruleWalker);
1655 : }
1656 3 : lastStyleAttrRN = ruleWalker.CurrentNode();
1657 3 : haveImportantStyleAttrRules =
1658 3 : !ruleWalker.GetCheckForImportantRules();
1659 : }
1660 : } else {
1661 : // Second time through, we handle the !important rule(s).
1662 3 : if (haveImportantStyleAttrRules) {
1663 0 : AddImportantRules(lastStyleAttrRN, lastScopedRN, &ruleWalker);
1664 : }
1665 : }
1666 6 : break;
1667 : }
1668 : default:
1669 0 : MOZ_ASSERT(false, "unexpected result from gCascadeLevels lookup");
1670 : break;
1671 : }
1672 : }
1673 :
1674 676 : while (rulesIndex != 0) {
1675 234 : --rulesIndex;
1676 234 : const RuleNodeInfo& ruleInfo = rules[rulesIndex];
1677 :
1678 358 : if (ruleInfo.mLevel != level->mLevel ||
1679 124 : ruleInfo.mIsImportant != level->mIsImportant) {
1680 116 : ++rulesIndex;
1681 116 : break;
1682 : }
1683 :
1684 : // When mIsReconstruct is true, we have rules we need to skip in
1685 : // the array, so we need to test !doReplace here.
1686 118 : if (!doReplace) {
1687 116 : ruleWalker.ForwardOnPossiblyCSSRule(ruleInfo.mRule);
1688 116 : if (ruleInfo.mIsAnimationRule) {
1689 0 : ruleWalker.CurrentNode()->SetIsAnimationRule();
1690 : }
1691 : }
1692 : }
1693 : }
1694 :
1695 49 : NS_ASSERTION(rulesIndex == 0,
1696 : "rules are in incorrect cascading order, "
1697 : "which means we replaced them incorrectly");
1698 :
1699 49 : return ruleWalker.CurrentNode();
1700 : }
1701 :
1702 : static bool
1703 231 : SkipsParentDisplayBasedStyleFixup(nsStyleContext* aStyleContext)
1704 : {
1705 231 : CSSPseudoElementType type = aStyleContext->GetPseudoType();
1706 231 : switch (type) {
1707 : case CSSPseudoElementType::InheritingAnonBox:
1708 19 : return nsCSSAnonBoxes::AnonBoxSkipsParentDisplayBasedStyleFixup(
1709 19 : aStyleContext->GetPseudo());
1710 : case CSSPseudoElementType::NonInheritingAnonBox:
1711 0 : return true;
1712 : case CSSPseudoElementType::NotPseudo:
1713 206 : return false;
1714 : default:
1715 6 : return !nsCSSPseudoElements::PseudoElementIsFlexOrGridItem(type);
1716 : }
1717 : }
1718 :
1719 : already_AddRefed<nsStyleContext>
1720 49 : nsStyleSet::ResolveStyleWithReplacement(Element* aElement,
1721 : Element* aPseudoElement,
1722 : nsStyleContext* aNewParentContext,
1723 : nsStyleContext* aOldStyleContext,
1724 : nsRestyleHint aReplacements,
1725 : uint32_t aFlags)
1726 : {
1727 : nsRuleNode* ruleNode =
1728 49 : RuleNodeWithReplacement(aElement, aPseudoElement,
1729 : aOldStyleContext->RuleNode(),
1730 49 : aOldStyleContext->GetPseudoType(), aReplacements);
1731 :
1732 49 : nsRuleNode* visitedRuleNode = nullptr;
1733 49 : nsStyleContext* oldStyleIfVisited = aOldStyleContext->GetStyleIfVisited();
1734 49 : if (oldStyleIfVisited) {
1735 0 : if (oldStyleIfVisited->RuleNode() == aOldStyleContext->RuleNode()) {
1736 0 : visitedRuleNode = ruleNode;
1737 : } else {
1738 : visitedRuleNode =
1739 0 : RuleNodeWithReplacement(aElement, aPseudoElement,
1740 : oldStyleIfVisited->RuleNode(),
1741 : oldStyleIfVisited->GetPseudoType(),
1742 0 : aReplacements);
1743 : }
1744 : }
1745 :
1746 49 : uint32_t flags = eNoFlags;
1747 49 : if (aOldStyleContext->IsLinkContext()) {
1748 0 : flags |= eIsLink;
1749 :
1750 : // GetContext handles propagating RelevantLinkVisited state from the
1751 : // parent in non-link cases; all we need to pass in is if this link
1752 : // is visited.
1753 0 : if (aOldStyleContext->RelevantLinkVisited()) {
1754 0 : flags |= eIsVisitedLink;
1755 : }
1756 : }
1757 :
1758 49 : CSSPseudoElementType pseudoType = aOldStyleContext->GetPseudoType();
1759 49 : Element* elementForAnimation = nullptr;
1760 49 : if (!(aFlags & eSkipStartingAnimations) &&
1761 3 : (pseudoType == CSSPseudoElementType::NotPseudo ||
1762 3 : pseudoType == CSSPseudoElementType::before ||
1763 : pseudoType == CSSPseudoElementType::after)) {
1764 : // We want to compute a correct elementForAnimation to pass in
1765 : // because at this point the parameter is more than just the element
1766 : // for animation; it's also used for the SetBodyTextColor call when
1767 : // it's the body element.
1768 : // However, we only want to set the flag to call UpdateAnimations
1769 : // if we're dealing with a replacement (such as style attribute
1770 : // replacement) that could lead to the animation property changing,
1771 : // and we explicitly do NOT want to call UpdateAnimations when
1772 : // we're trying to do an animation-only update.
1773 38 : if (aReplacements & ~(eRestyle_CSSTransitions | eRestyle_CSSAnimations)) {
1774 22 : flags |= eDoAnimation;
1775 : }
1776 38 : elementForAnimation = aElement;
1777 : #ifdef DEBUG
1778 : {
1779 38 : nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(elementForAnimation);
1780 38 : NS_ASSERTION(pseudoType == CSSPseudoElementType::NotPseudo ||
1781 : !styleFrame ||
1782 : styleFrame->StyleContext()->GetPseudoType() ==
1783 : CSSPseudoElementType::NotPseudo,
1784 : "aElement should be the element and not the pseudo-element");
1785 : }
1786 : #endif
1787 : }
1788 :
1789 60 : if ((aElement && aElement->IsRootOfAnonymousSubtree()) ||
1790 11 : SkipsParentDisplayBasedStyleFixup(aOldStyleContext)) {
1791 : // For anonymous subtree roots, don't tweak "display" value based on whether
1792 : // or not the parent is styled as a flex/grid container. (If the parent
1793 : // has anonymous-subtree kids, then we know it's not actually going to get
1794 : // a flex/grid container frame, anyway.) Same for certain anonymous boxes
1795 : // and most pseudos.
1796 38 : flags |= eSkipParentDisplayBasedStyleFixup;
1797 : }
1798 :
1799 : return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
1800 : aOldStyleContext->GetPseudo(), pseudoType,
1801 49 : elementForAnimation, flags);
1802 : }
1803 :
1804 : already_AddRefed<nsStyleContext>
1805 8 : nsStyleSet::ResolveStyleByRemovingAnimation(dom::Element* aTarget,
1806 : nsStyleContext* aStyleContext,
1807 : nsRestyleHint aWhichToRemove)
1808 : {
1809 : #ifdef DEBUG
1810 8 : CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
1811 : #endif
1812 8 : MOZ_ASSERT(pseudoType == CSSPseudoElementType::NotPseudo ||
1813 : pseudoType == CSSPseudoElementType::before ||
1814 : pseudoType == CSSPseudoElementType::after,
1815 : "unexpected type for animations");
1816 8 : MOZ_ASSERT(PresContext()->RestyleManager()->IsGecko(),
1817 : "stylo: the style set and restyle manager must have the same "
1818 : "StyleBackendType");
1819 : GeckoRestyleManager* restyleManager =
1820 8 : PresContext()->RestyleManager()->AsGecko();
1821 :
1822 8 : bool oldSkipAnimationRules = restyleManager->SkipAnimationRules();
1823 8 : restyleManager->SetSkipAnimationRules(true);
1824 :
1825 : RefPtr<nsStyleContext> result =
1826 16 : ResolveStyleWithReplacement(aTarget, nullptr, aStyleContext->GetParent(),
1827 : aStyleContext, aWhichToRemove,
1828 16 : eSkipStartingAnimations);
1829 :
1830 8 : restyleManager->SetSkipAnimationRules(oldSkipAnimationRules);
1831 :
1832 16 : return result.forget();
1833 : }
1834 :
1835 : already_AddRefed<nsStyleContext>
1836 0 : nsStyleSet::ResolveStyleWithoutAnimation(Element* aTarget,
1837 : nsStyleContext* aParentContext)
1838 : {
1839 : GeckoRestyleManager* restyleManager =
1840 0 : PresContext()->RestyleManager()->AsGecko();
1841 :
1842 : TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
1843 0 : aTarget->OwnerDoc());
1844 0 : InitStyleScopes(treeContext, aTarget);
1845 :
1846 0 : bool oldSkipAnimationRules = restyleManager->SkipAnimationRules();
1847 0 : restyleManager->SetSkipAnimationRules(true);
1848 :
1849 : // Here we can call ResolveStyleForInternal() instead of
1850 : // ResolveStyleWithReplacement() since we don't need any animation rules
1851 : // (CSS Animations, Transitions and script animations). That's because
1852 : // EffectCompositor::GetAnimationRule() skips all of animations rules if
1853 : // SkipAnimationRules flag is true.
1854 0 : RefPtr<nsStyleContext> result = ResolveStyleForInternal(aTarget,
1855 : aParentContext,
1856 : treeContext,
1857 0 : eWithoutAnimation);
1858 :
1859 0 : restyleManager->SetSkipAnimationRules(oldSkipAnimationRules);
1860 :
1861 0 : return result.forget();
1862 : }
1863 :
1864 : already_AddRefed<nsStyleContext>
1865 221 : nsStyleSet::ResolveStyleForText(nsIContent* aTextNode,
1866 : nsStyleContext* aParentContext)
1867 : {
1868 221 : MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
1869 : return GetContext(aParentContext, mRuleTree, nullptr,
1870 : nsCSSAnonBoxes::mozText,
1871 221 : CSSPseudoElementType::InheritingAnonBox, nullptr, eNoFlags);
1872 : }
1873 :
1874 : already_AddRefed<nsStyleContext>
1875 0 : nsStyleSet::ResolveStyleForFirstLetterContinuation(nsStyleContext* aParentContext)
1876 : {
1877 : return GetContext(aParentContext, mRuleTree, nullptr,
1878 : nsCSSAnonBoxes::firstLetterContinuation,
1879 0 : CSSPseudoElementType::InheritingAnonBox, nullptr, eNoFlags);
1880 : }
1881 :
1882 : already_AddRefed<nsStyleContext>
1883 139 : nsStyleSet::ResolveStyleForPlaceholder()
1884 : {
1885 : RefPtr<nsStyleContext>& cache =
1886 139 : mNonInheritingStyleContexts[nsCSSAnonBoxes::NonInheriting::oofPlaceholder];
1887 139 : if (cache) {
1888 274 : RefPtr<nsStyleContext> retval = cache;
1889 137 : return retval.forget();
1890 : }
1891 :
1892 : RefPtr<nsStyleContext> retval =
1893 4 : GetContext(nullptr, mRuleTree, nullptr,
1894 : nsCSSAnonBoxes::oofPlaceholder,
1895 4 : CSSPseudoElementType::NonInheritingAnonBox, nullptr, eNoFlags);
1896 2 : cache = retval;
1897 2 : return retval.forget();
1898 : }
1899 :
1900 : void
1901 1288 : nsStyleSet::WalkRestrictionRule(CSSPseudoElementType aPseudoType,
1902 : nsRuleWalker* aRuleWalker)
1903 : {
1904 : // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
1905 1288 : aRuleWalker->SetLevel(SheetType::Agent, false, false);
1906 1288 : if (aPseudoType == CSSPseudoElementType::firstLetter)
1907 48 : aRuleWalker->Forward(mFirstLetterRule);
1908 1240 : else if (aPseudoType == CSSPseudoElementType::firstLine)
1909 31 : aRuleWalker->Forward(mFirstLineRule);
1910 1209 : else if (aPseudoType == CSSPseudoElementType::placeholder)
1911 8 : aRuleWalker->Forward(mPlaceholderRule);
1912 1288 : }
1913 :
1914 : void
1915 2501 : nsStyleSet::WalkDisableTextZoomRule(Element* aElement, nsRuleWalker* aRuleWalker)
1916 : {
1917 2501 : aRuleWalker->SetLevel(SheetType::Agent, false, false);
1918 2501 : if (aElement->IsSVGElement(nsGkAtoms::text))
1919 0 : aRuleWalker->Forward(mDisableTextZoomStyleRule);
1920 2501 : }
1921 :
1922 : already_AddRefed<nsStyleContext>
1923 8 : nsStyleSet::ResolvePseudoElementStyleInternal(
1924 : Element* aParentElement,
1925 : CSSPseudoElementType aType,
1926 : nsStyleContext* aParentContext,
1927 : Element* aPseudoElement,
1928 : AnimationFlag aAnimationFlag)
1929 : {
1930 8 : NS_ENSURE_FALSE(mInShutdown, nullptr);
1931 :
1932 8 : NS_ASSERTION(aType < CSSPseudoElementType::Count,
1933 : "must have pseudo element type");
1934 8 : NS_ASSERTION(aParentElement, "Must have parent element");
1935 :
1936 16 : nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1937 : TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
1938 16 : aParentElement->OwnerDoc());
1939 8 : InitStyleScopes(treeContext, aParentElement);
1940 : PseudoElementRuleProcessorData data(PresContext(), aParentElement,
1941 : &ruleWalker, aType, treeContext,
1942 8 : aPseudoElement);
1943 8 : WalkRestrictionRule(aType, &ruleWalker);
1944 : FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
1945 8 : aParentElement, &ruleWalker);
1946 :
1947 8 : nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1948 8 : nsRuleNode *visitedRuleNode = nullptr;
1949 :
1950 8 : if (treeContext.HaveRelevantLink()) {
1951 0 : treeContext.ResetForVisitedMatching();
1952 0 : ruleWalker.Reset();
1953 0 : WalkRestrictionRule(aType, &ruleWalker);
1954 : FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
1955 0 : aParentElement, &ruleWalker);
1956 0 : visitedRuleNode = ruleWalker.CurrentNode();
1957 : }
1958 :
1959 : // For pseudos, |data.IsLink()| being true means that
1960 : // our parent node is a link.
1961 8 : uint32_t flags = eNoFlags;
1962 8 : if (aType == CSSPseudoElementType::before ||
1963 : aType == CSSPseudoElementType::after) {
1964 0 : if (aAnimationFlag == eWithAnimation) {
1965 0 : flags |= eDoAnimation;
1966 : }
1967 : }
1968 :
1969 8 : if (!nsCSSPseudoElements::PseudoElementIsFlexOrGridItem(aType)) {
1970 : // Only pseudo-elements that act as items in flex and grid containers
1971 : // have parent display-based style fixup.
1972 8 : flags |= eSkipParentDisplayBasedStyleFixup;
1973 : }
1974 :
1975 : return GetContext(aParentContext, ruleNode, visitedRuleNode,
1976 : nsCSSPseudoElements::GetPseudoAtom(aType), aType,
1977 8 : aParentElement, flags);
1978 : }
1979 :
1980 : already_AddRefed<nsStyleContext>
1981 8 : nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
1982 : CSSPseudoElementType aType,
1983 : nsStyleContext* aParentContext,
1984 : Element* aPseudoElement)
1985 : {
1986 : return ResolvePseudoElementStyleInternal(aParentElement,
1987 : aType,
1988 : aParentContext,
1989 : aPseudoElement,
1990 8 : eWithAnimation);
1991 : }
1992 :
1993 : already_AddRefed<nsStyleContext>
1994 0 : nsStyleSet::ResolvePseudoElementStyleWithoutAnimation(
1995 : Element* aParentElement,
1996 : CSSPseudoElementType aType,
1997 : nsStyleContext* aParentContext,
1998 : Element* aPseudoElement)
1999 : {
2000 : return ResolvePseudoElementStyleInternal(aParentElement,
2001 : aType,
2002 : aParentContext,
2003 : aPseudoElement,
2004 0 : eWithoutAnimation);
2005 : }
2006 :
2007 : already_AddRefed<nsStyleContext>
2008 797 : nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
2009 : CSSPseudoElementType aType,
2010 : nsStyleContext* aParentContext)
2011 : {
2012 : TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
2013 1594 : aParentElement->OwnerDoc());
2014 797 : InitStyleScopes(treeContext, aParentElement);
2015 : return ProbePseudoElementStyle(aParentElement, aType, aParentContext,
2016 1594 : treeContext);
2017 : }
2018 :
2019 : already_AddRefed<nsStyleContext>
2020 1280 : nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
2021 : CSSPseudoElementType aType,
2022 : nsStyleContext* aParentContext,
2023 : TreeMatchContext& aTreeMatchContext)
2024 : {
2025 1280 : NS_ENSURE_FALSE(mInShutdown, nullptr);
2026 :
2027 1280 : NS_ASSERTION(aType < CSSPseudoElementType::Count,
2028 : "must have pseudo element type");
2029 1280 : NS_ASSERTION(aParentElement, "aParentElement must not be null");
2030 :
2031 1280 : nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
2032 2560 : nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
2033 1280 : aTreeMatchContext.ResetForUnvisitedMatching();
2034 : PseudoElementRuleProcessorData data(PresContext(), aParentElement,
2035 : &ruleWalker, aType, aTreeMatchContext,
2036 1280 : /* aPseudoElement = */ nullptr);
2037 1280 : WalkRestrictionRule(aType, &ruleWalker);
2038 : // not the root if there was a restriction rule
2039 1280 : nsRuleNode *adjustedRoot = ruleWalker.CurrentNode();
2040 : FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
2041 1280 : aParentElement, &ruleWalker);
2042 :
2043 1280 : nsRuleNode *ruleNode = ruleWalker.CurrentNode();
2044 1280 : if (ruleNode == adjustedRoot) {
2045 1241 : return nullptr;
2046 : }
2047 :
2048 39 : nsRuleNode *visitedRuleNode = nullptr;
2049 :
2050 39 : if (aTreeMatchContext.HaveRelevantLink()) {
2051 0 : aTreeMatchContext.ResetForVisitedMatching();
2052 0 : ruleWalker.Reset();
2053 0 : WalkRestrictionRule(aType, &ruleWalker);
2054 : FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
2055 0 : aParentElement, &ruleWalker);
2056 0 : visitedRuleNode = ruleWalker.CurrentNode();
2057 : }
2058 :
2059 : // For pseudos, |data.IsLink()| being true means that
2060 : // our parent node is a link.
2061 39 : uint32_t flags = eNoFlags;
2062 39 : if (aType == CSSPseudoElementType::before ||
2063 : aType == CSSPseudoElementType::after) {
2064 39 : flags |= eDoAnimation;
2065 : }
2066 :
2067 39 : if (!nsCSSPseudoElements::PseudoElementIsFlexOrGridItem(aType)) {
2068 : // Only pseudo-elements that act as items in flex and grid containers
2069 : // have parent display-based style fixup.
2070 0 : flags |= eSkipParentDisplayBasedStyleFixup;
2071 : }
2072 :
2073 : RefPtr<nsStyleContext> result =
2074 78 : GetContext(aParentContext, ruleNode, visitedRuleNode,
2075 : pseudoTag, aType,
2076 78 : aParentElement, flags);
2077 :
2078 : // For :before and :after pseudo-elements, having display: none or no
2079 : // 'content' property is equivalent to not having the pseudo-element
2080 : // at all.
2081 117 : if (result &&
2082 58 : (pseudoTag == nsCSSPseudoElements::before ||
2083 58 : pseudoTag == nsCSSPseudoElements::after)) {
2084 39 : const nsStyleDisplay *display = result->StyleDisplay();
2085 39 : const nsStyleContent *content = result->StyleContent();
2086 : // XXXldb What is contentCount for |content: ""|?
2087 78 : if (display->mDisplay == StyleDisplay::None ||
2088 39 : content->ContentCount() == 0) {
2089 10 : result = nullptr;
2090 : }
2091 : }
2092 :
2093 39 : return result.forget();
2094 : }
2095 :
2096 : already_AddRefed<nsStyleContext>
2097 210 : nsStyleSet::ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
2098 : nsStyleContext* aParentContext)
2099 : {
2100 210 : NS_ENSURE_FALSE(mInShutdown, nullptr);
2101 :
2102 : #ifdef DEBUG
2103 420 : bool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
2104 210 : !nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag)
2105 : #ifdef MOZ_XUL
2106 420 : && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
2107 : #endif
2108 : ;
2109 210 : NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
2110 : #endif
2111 :
2112 420 : nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
2113 210 : AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker);
2114 : FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nullptr,
2115 210 : &ruleWalker);
2116 :
2117 210 : if (aPseudoTag == nsCSSAnonBoxes::pageContent) {
2118 : // Add any @page rules that are specified.
2119 0 : nsTArray<nsCSSPageRule*> rules;
2120 0 : nsTArray<css::ImportantStyleData*> importantRules;
2121 0 : AppendPageRules(rules);
2122 0 : for (uint32_t i = 0, i_end = rules.Length(); i != i_end; ++i) {
2123 0 : css::Declaration* declaration = rules[i]->Declaration();
2124 0 : declaration->SetImmutable();
2125 0 : ruleWalker.Forward(declaration);
2126 : css::ImportantStyleData* importantRule =
2127 0 : declaration->GetImportantStyleData();
2128 0 : if (importantRule) {
2129 0 : importantRules.AppendElement(importantRule);
2130 : }
2131 : }
2132 0 : for (uint32_t i = 0, i_end = importantRules.Length(); i != i_end; ++i) {
2133 0 : ruleWalker.Forward(importantRules[i]);
2134 : }
2135 : }
2136 :
2137 210 : uint32_t flags = eNoFlags;
2138 210 : if (nsCSSAnonBoxes::AnonBoxSkipsParentDisplayBasedStyleFixup(aPseudoTag)) {
2139 0 : flags |= eSkipParentDisplayBasedStyleFixup;
2140 : }
2141 :
2142 : return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
2143 : aPseudoTag, CSSPseudoElementType::InheritingAnonBox,
2144 210 : nullptr, flags);
2145 : }
2146 :
2147 : already_AddRefed<nsStyleContext>
2148 0 : nsStyleSet::ResolveNonInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag)
2149 : {
2150 0 : NS_ENSURE_FALSE(mInShutdown, nullptr);
2151 :
2152 : #ifdef DEBUG
2153 0 : bool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
2154 0 : nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag)
2155 : #ifdef MOZ_XUL
2156 0 : && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
2157 : #endif
2158 : ;
2159 0 : NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
2160 : #endif
2161 :
2162 : nsCSSAnonBoxes::NonInheriting type =
2163 0 : nsCSSAnonBoxes::NonInheritingTypeForPseudoTag(aPseudoTag);
2164 0 : RefPtr<nsStyleContext>& cache = mNonInheritingStyleContexts[type];
2165 0 : if (cache) {
2166 0 : RefPtr<nsStyleContext> retval = cache;
2167 0 : return retval.forget();
2168 : }
2169 :
2170 0 : nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
2171 0 : AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker);
2172 : FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nullptr,
2173 0 : &ruleWalker);
2174 :
2175 0 : MOZ_ASSERT(aPseudoTag != nsCSSAnonBoxes::pageContent,
2176 : "If nsCSSAnonBoxes::pageContent ends up non-inheriting, move the "
2177 : "@page handling from ResolveInheritingAnonymousBoxStyle to "
2178 : "ResolveNonInheritingAnonymousBoxStyle");
2179 :
2180 : RefPtr<nsStyleContext> retval =
2181 0 : GetContext(nullptr, ruleWalker.CurrentNode(), nullptr,
2182 : aPseudoTag, CSSPseudoElementType::NonInheritingAnonBox,
2183 0 : nullptr, eNoFlags);
2184 0 : cache = retval;
2185 0 : return retval.forget();
2186 : }
2187 :
2188 : #ifdef MOZ_XUL
2189 : already_AddRefed<nsStyleContext>
2190 0 : nsStyleSet::ResolveXULTreePseudoStyle(Element* aParentElement,
2191 : nsICSSAnonBoxPseudo* aPseudoTag,
2192 : nsStyleContext* aParentContext,
2193 : nsICSSPseudoComparator* aComparator)
2194 : {
2195 0 : NS_ENSURE_FALSE(mInShutdown, nullptr);
2196 :
2197 0 : NS_ASSERTION(aPseudoTag, "must have pseudo tag");
2198 0 : NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
2199 : "Unexpected pseudo");
2200 :
2201 0 : nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
2202 : TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
2203 0 : aParentElement->OwnerDoc());
2204 0 : InitStyleScopes(treeContext, aParentElement);
2205 : XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
2206 0 : aPseudoTag, aComparator, treeContext);
2207 : FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
2208 0 : &ruleWalker);
2209 :
2210 0 : nsRuleNode *ruleNode = ruleWalker.CurrentNode();
2211 0 : nsRuleNode *visitedRuleNode = nullptr;
2212 :
2213 0 : if (treeContext.HaveRelevantLink()) {
2214 0 : treeContext.ResetForVisitedMatching();
2215 0 : ruleWalker.Reset();
2216 : FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data,
2217 0 : aParentElement, &ruleWalker);
2218 0 : visitedRuleNode = ruleWalker.CurrentNode();
2219 : }
2220 :
2221 : return GetContext(aParentContext, ruleNode, visitedRuleNode,
2222 : // For pseudos, |data.IsLink()| being true means that
2223 : // our parent node is a link.
2224 : aPseudoTag, CSSPseudoElementType::XULTree,
2225 0 : nullptr, eNoFlags);
2226 : }
2227 : #endif
2228 :
2229 : bool
2230 9 : nsStyleSet::AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray)
2231 : {
2232 9 : NS_ENSURE_FALSE(mInShutdown, false);
2233 9 : NS_ASSERTION(mBatching == 0, "rule processors out of date");
2234 :
2235 9 : nsPresContext* presContext = PresContext();
2236 54 : for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
2237 45 : if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
2238 9 : continue;
2239 : nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
2240 36 : (mRuleProcessors[gCSSSheetTypes[i]].get());
2241 36 : if (ruleProc && !ruleProc->AppendFontFaceRules(presContext, aArray))
2242 0 : return false;
2243 : }
2244 9 : return true;
2245 : }
2246 :
2247 : nsCSSKeyframesRule*
2248 0 : nsStyleSet::KeyframesRuleForName(const nsString& aName)
2249 : {
2250 0 : NS_ENSURE_FALSE(mInShutdown, nullptr);
2251 0 : NS_ASSERTION(mBatching == 0, "rule processors out of date");
2252 :
2253 0 : nsPresContext* presContext = PresContext();
2254 0 : for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
2255 0 : if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
2256 0 : continue;
2257 : nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
2258 0 : (mRuleProcessors[gCSSSheetTypes[i]].get());
2259 0 : if (!ruleProc)
2260 0 : continue;
2261 : nsCSSKeyframesRule* result =
2262 0 : ruleProc->KeyframesRuleForName(presContext, aName);
2263 0 : if (result)
2264 0 : return result;
2265 : }
2266 0 : return nullptr;
2267 : }
2268 :
2269 : nsCSSCounterStyleRule*
2270 0 : nsStyleSet::CounterStyleRuleForName(nsIAtom* aName)
2271 : {
2272 0 : NS_ENSURE_FALSE(mInShutdown, nullptr);
2273 0 : NS_ASSERTION(mBatching == 0, "rule processors out of date");
2274 :
2275 0 : nsPresContext* presContext = PresContext();
2276 0 : for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
2277 0 : if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
2278 0 : continue;
2279 : nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
2280 0 : (mRuleProcessors[gCSSSheetTypes[i]].get());
2281 0 : if (!ruleProc)
2282 0 : continue;
2283 : nsCSSCounterStyleRule *result =
2284 0 : ruleProc->CounterStyleRuleForName(presContext, aName);
2285 0 : if (result)
2286 0 : return result;
2287 : }
2288 0 : return nullptr;
2289 : }
2290 :
2291 : bool
2292 0 : nsStyleSet::AppendFontFeatureValuesRules(
2293 : nsTArray<nsCSSFontFeatureValuesRule*>& aArray)
2294 : {
2295 0 : NS_ENSURE_FALSE(mInShutdown, false);
2296 0 : NS_ASSERTION(mBatching == 0, "rule processors out of date");
2297 :
2298 0 : nsPresContext* presContext = PresContext();
2299 0 : for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
2300 : nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
2301 0 : (mRuleProcessors[gCSSSheetTypes[i]].get());
2302 0 : if (ruleProc &&
2303 0 : !ruleProc->AppendFontFeatureValuesRules(presContext, aArray))
2304 : {
2305 0 : return false;
2306 : }
2307 : }
2308 0 : return true;
2309 : }
2310 :
2311 : already_AddRefed<gfxFontFeatureValueSet>
2312 0 : nsStyleSet::GetFontFeatureValuesLookup()
2313 : {
2314 0 : if (mInitFontFeatureValuesLookup) {
2315 0 : mInitFontFeatureValuesLookup = false;
2316 :
2317 0 : nsTArray<nsCSSFontFeatureValuesRule*> rules;
2318 0 : AppendFontFeatureValuesRules(rules);
2319 :
2320 0 : mFontFeatureValuesLookup = new gfxFontFeatureValueSet();
2321 :
2322 0 : uint32_t i, numRules = rules.Length();
2323 0 : for (i = 0; i < numRules; i++) {
2324 0 : nsCSSFontFeatureValuesRule *rule = rules[i];
2325 :
2326 0 : const nsTArray<FontFamilyName>& familyList = rule->GetFamilyList().GetFontlist();
2327 : const nsTArray<gfxFontFeatureValueSet::FeatureValues>&
2328 0 : featureValues = rule->GetFeatureValues();
2329 :
2330 : // for each family
2331 : size_t f, numFam;
2332 :
2333 0 : numFam = familyList.Length();
2334 0 : for (f = 0; f < numFam; f++) {
2335 0 : mFontFeatureValuesLookup->AddFontFeatureValues(familyList[f].mName,
2336 0 : featureValues);
2337 : }
2338 : }
2339 : }
2340 :
2341 0 : RefPtr<gfxFontFeatureValueSet> lookup = mFontFeatureValuesLookup;
2342 0 : return lookup.forget();
2343 : }
2344 :
2345 : bool
2346 0 : nsStyleSet::AppendPageRules(nsTArray<nsCSSPageRule*>& aArray)
2347 : {
2348 0 : NS_ENSURE_FALSE(mInShutdown, false);
2349 0 : NS_ASSERTION(mBatching == 0, "rule processors out of date");
2350 :
2351 0 : nsPresContext* presContext = PresContext();
2352 0 : for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
2353 0 : if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
2354 0 : continue;
2355 : nsCSSRuleProcessor* ruleProc = static_cast<nsCSSRuleProcessor*>
2356 0 : (mRuleProcessors[gCSSSheetTypes[i]].get());
2357 0 : if (ruleProc && !ruleProc->AppendPageRules(presContext, aArray))
2358 0 : return false;
2359 : }
2360 0 : return true;
2361 : }
2362 :
2363 : void
2364 4 : nsStyleSet::BeginShutdown()
2365 : {
2366 4 : mInShutdown = 1;
2367 4 : }
2368 :
2369 : void
2370 4 : nsStyleSet::Shutdown()
2371 : {
2372 : // Make sure we drop our cached style contexts before the presshell arena
2373 : // starts going away.
2374 4 : ClearNonInheritingStyleContexts();
2375 4 : mRuleTree = nullptr;
2376 4 : GCRuleTrees();
2377 4 : MOZ_ASSERT(mUnusedRuleNodeList.isEmpty());
2378 4 : MOZ_ASSERT(mUnusedRuleNodeCount == 0);
2379 4 : }
2380 :
2381 : void
2382 48 : nsStyleSet::RecordStyleSheetChange(CSSStyleSheet* aStyleSheet,
2383 : StyleSheet::ChangeType)
2384 : {
2385 48 : MOZ_ASSERT(mBatching != 0, "Should be in an update");
2386 :
2387 48 : if (mStylesHaveChanged) {
2388 9 : return;
2389 : }
2390 :
2391 39 : if (Element* scopeElement = aStyleSheet->GetScopeElement()) {
2392 0 : mChangedScopeStyleRoots.AppendElement(scopeElement);
2393 0 : return;
2394 : }
2395 :
2396 39 : mStylesHaveChanged = true;
2397 : // If we need to restyle everything, no need to restyle individual
2398 : // scoped style roots.
2399 39 : mChangedScopeStyleRoots.Clear();
2400 : }
2401 :
2402 : void
2403 0 : nsStyleSet::RecordShadowStyleChange(ShadowRoot* aShadowRoot)
2404 : {
2405 0 : if (mStylesHaveChanged) {
2406 0 : return;
2407 : }
2408 :
2409 0 : mChangedScopeStyleRoots.AppendElement(aShadowRoot->GetHost()->AsElement());
2410 : }
2411 :
2412 : void
2413 23 : nsStyleSet::InvalidateStyleForCSSRuleChanges()
2414 : {
2415 23 : MOZ_ASSERT(!mStylesHaveChanged || mChangedScopeStyleRoots.IsEmpty());
2416 :
2417 46 : AutoTArray<RefPtr<mozilla::dom::Element>, 1> scopeRoots;
2418 23 : mChangedScopeStyleRoots.SwapElements(scopeRoots);
2419 23 : mStylesHaveChanged = false;
2420 :
2421 23 : nsPresContext* presContext = PresContext();
2422 23 : RestyleManager* restyleManager = presContext->RestyleManager()->AsGecko();
2423 23 : Element* root = presContext->Document()->GetRootElement();
2424 23 : if (!root) {
2425 : // No content to restyle
2426 0 : return;
2427 : }
2428 :
2429 23 : if (scopeRoots.IsEmpty()) {
2430 : // If scopeRoots is empty, we know that mStylesHaveChanged was true at
2431 : // the beginning of this function, and that we need to restyle the whole
2432 : // document.
2433 : restyleManager->PostRestyleEvent(root,
2434 : eRestyle_Subtree,
2435 23 : nsChangeHint(0));
2436 : } else {
2437 0 : for (Element* scopeRoot : scopeRoots) {
2438 : restyleManager->PostRestyleEvent(scopeRoot,
2439 : eRestyle_Subtree,
2440 0 : nsChangeHint(0));
2441 : }
2442 : }
2443 : }
2444 :
2445 : void
2446 6 : nsStyleSet::GCRuleTrees()
2447 : {
2448 6 : MOZ_ASSERT(!mInReconstruct);
2449 6 : MOZ_ASSERT(!mInGC);
2450 6 : mInGC = true;
2451 :
2452 1898 : while (!mUnusedRuleNodeList.isEmpty()) {
2453 946 : nsRuleNode* node = mUnusedRuleNodeList.popFirst();
2454 : #ifdef DEBUG
2455 946 : if (node == mOldRootNode) {
2456 : // Flag that we've GCed the old root, if any.
2457 2 : mOldRootNode = nullptr;
2458 : }
2459 : #endif
2460 946 : node->Destroy();
2461 : }
2462 :
2463 : #ifdef DEBUG
2464 6 : NS_ASSERTION(!mOldRootNode, "Should have GCed old root node");
2465 6 : mOldRootNode = nullptr;
2466 : #endif
2467 6 : mUnusedRuleNodeCount = 0;
2468 6 : mInGC = false;
2469 6 : }
2470 :
2471 : already_AddRefed<nsStyleContext>
2472 303 : nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
2473 : nsStyleContext* aNewParentContext,
2474 : Element* aElement)
2475 : {
2476 303 : MOZ_ASSERT(aStyleContext, "aStyleContext must not be null");
2477 :
2478 : // This short-circuit is OK because we don't call TryInitatingTransition
2479 : // during style reresolution if the style context pointer hasn't changed.
2480 303 : if (aStyleContext->GetParent() == aNewParentContext) {
2481 26 : RefPtr<nsStyleContext> ret = aStyleContext;
2482 13 : return ret.forget();
2483 : }
2484 :
2485 290 : nsIAtom* pseudoTag = aStyleContext->GetPseudo();
2486 290 : CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
2487 290 : nsRuleNode* ruleNode = aStyleContext->RuleNode();
2488 :
2489 290 : MOZ_ASSERT(PresContext()->RestyleManager()->IsGecko(),
2490 : "stylo: the style set and restyle manager must have the same "
2491 : "StyleBackendType");
2492 290 : NS_ASSERTION(!PresContext()->RestyleManager()->AsGecko()->SkipAnimationRules(),
2493 : "we no longer handle SkipAnimationRules()");
2494 :
2495 290 : nsRuleNode* visitedRuleNode = nullptr;
2496 290 : nsStyleContext* visitedContext = aStyleContext->GetStyleIfVisited();
2497 : // Reparenting a style context just changes where we inherit from,
2498 : // not what rules we match or what our DOM looks like. In
2499 : // particular, it doesn't change whether this is a style context for
2500 : // a link.
2501 290 : if (visitedContext) {
2502 0 : visitedRuleNode = visitedContext->RuleNode();
2503 : }
2504 :
2505 290 : uint32_t flags = eNoFlags;
2506 290 : if (aStyleContext->IsLinkContext()) {
2507 0 : flags |= eIsLink;
2508 :
2509 : // GetContext handles propagating RelevantLinkVisited state from the
2510 : // parent in non-link cases; all we need to pass in is if this link
2511 : // is visited.
2512 0 : if (aStyleContext->RelevantLinkVisited()) {
2513 0 : flags |= eIsVisitedLink;
2514 : }
2515 : }
2516 :
2517 290 : if (pseudoType == CSSPseudoElementType::NotPseudo ||
2518 19 : pseudoType == CSSPseudoElementType::before ||
2519 : pseudoType == CSSPseudoElementType::after) {
2520 274 : flags |= eDoAnimation;
2521 : }
2522 :
2523 510 : if ((aElement && aElement->IsRootOfAnonymousSubtree()) ||
2524 220 : SkipsParentDisplayBasedStyleFixup(aStyleContext)) {
2525 : // For anonymous subtree roots, don't tweak "display" value based on whether
2526 : // or not the parent is styled as a flex/grid container. (If the parent
2527 : // has anonymous-subtree kids, then we know it's not actually going to get
2528 : // a flex/grid container frame, anyway.) Same for certain anonymous boxes
2529 : // and most pseudos.
2530 70 : flags |= eSkipParentDisplayBasedStyleFixup;
2531 : }
2532 :
2533 : return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
2534 : pseudoTag, pseudoType,
2535 290 : aElement, flags);
2536 : }
2537 :
2538 : struct MOZ_STACK_CLASS StatefulData : public StateRuleProcessorData {
2539 53 : StatefulData(nsPresContext* aPresContext, Element* aElement,
2540 : EventStates aStateMask, TreeMatchContext& aTreeMatchContext)
2541 53 : : StateRuleProcessorData(aPresContext, aElement, aStateMask,
2542 : aTreeMatchContext),
2543 53 : mHint(nsRestyleHint(0))
2544 53 : {}
2545 : nsRestyleHint mHint;
2546 : };
2547 :
2548 : struct MOZ_STACK_CLASS StatefulPseudoElementData : public PseudoElementStateRuleProcessorData {
2549 0 : StatefulPseudoElementData(nsPresContext* aPresContext, Element* aElement,
2550 : EventStates aStateMask, CSSPseudoElementType aPseudoType,
2551 : TreeMatchContext& aTreeMatchContext, Element* aPseudoElement)
2552 0 : : PseudoElementStateRuleProcessorData(aPresContext, aElement, aStateMask,
2553 : aPseudoType, aTreeMatchContext,
2554 : aPseudoElement),
2555 0 : mHint(nsRestyleHint(0))
2556 0 : {}
2557 : nsRestyleHint mHint;
2558 : };
2559 :
2560 35 : static bool SheetHasDocumentStateStyle(nsIStyleRuleProcessor* aProcessor,
2561 : void *aData)
2562 : {
2563 35 : StatefulData* data = (StatefulData*)aData;
2564 35 : if (aProcessor->HasDocumentStateDependentStyle(data)) {
2565 1 : data->mHint = eRestyle_Self;
2566 1 : return false; // don't continue
2567 : }
2568 34 : return true; // continue
2569 : }
2570 :
2571 : // Test if style is dependent on a document state.
2572 : bool
2573 2 : nsStyleSet::HasDocumentStateDependentStyle(nsIContent* aContent,
2574 : EventStates aStateMask)
2575 : {
2576 2 : if (!aContent || !aContent->IsElement())
2577 0 : return false;
2578 :
2579 : TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
2580 4 : aContent->OwnerDoc());
2581 2 : InitStyleScopes(treeContext, aContent->AsElement());
2582 : StatefulData data(PresContext(), aContent->AsElement(), aStateMask,
2583 2 : treeContext);
2584 2 : WalkRuleProcessors(SheetHasDocumentStateStyle, &data, true);
2585 2 : return data.mHint != 0;
2586 : }
2587 :
2588 341 : static bool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
2589 : void *aData)
2590 : {
2591 341 : StatefulData* data = (StatefulData*)aData;
2592 341 : nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
2593 341 : data->mHint = nsRestyleHint(data->mHint | hint);
2594 341 : return true; // continue
2595 : }
2596 :
2597 0 : static bool SheetHasStatefulPseudoElementStyle(nsIStyleRuleProcessor* aProcessor,
2598 : void *aData)
2599 : {
2600 0 : StatefulPseudoElementData* data = (StatefulPseudoElementData*)aData;
2601 0 : nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
2602 0 : data->mHint = nsRestyleHint(data->mHint | hint);
2603 0 : return true; // continue
2604 : }
2605 :
2606 : // Test if style is dependent on content state
2607 : nsRestyleHint
2608 51 : nsStyleSet::HasStateDependentStyle(Element* aElement,
2609 : EventStates aStateMask)
2610 : {
2611 : TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
2612 102 : aElement->OwnerDoc());
2613 51 : InitStyleScopes(treeContext, aElement);
2614 51 : StatefulData data(PresContext(), aElement, aStateMask, treeContext);
2615 51 : WalkRuleProcessors(SheetHasStatefulStyle, &data, false);
2616 102 : return data.mHint;
2617 : }
2618 :
2619 : nsRestyleHint
2620 0 : nsStyleSet::HasStateDependentStyle(Element* aElement,
2621 : CSSPseudoElementType aPseudoType,
2622 : Element* aPseudoElement,
2623 : EventStates aStateMask)
2624 : {
2625 : TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
2626 0 : aElement->OwnerDoc());
2627 0 : InitStyleScopes(treeContext, aElement);
2628 : StatefulPseudoElementData data(PresContext(), aElement, aStateMask,
2629 0 : aPseudoType, treeContext, aPseudoElement);
2630 0 : WalkRuleProcessors(SheetHasStatefulPseudoElementStyle, &data, false);
2631 0 : return data.mHint;
2632 : }
2633 :
2634 648 : struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData {
2635 648 : AttributeData(nsPresContext* aPresContext, Element* aElement,
2636 : int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType,
2637 : bool aAttrHasChanged, const nsAttrValue* aOtherValue,
2638 : TreeMatchContext& aTreeMatchContext)
2639 648 : : AttributeRuleProcessorData(aPresContext, aElement, aNameSpaceID,
2640 : aAttribute, aModType, aAttrHasChanged,
2641 : aOtherValue, aTreeMatchContext),
2642 648 : mHint(nsRestyleHint(0))
2643 648 : {}
2644 : nsRestyleHint mHint;
2645 : RestyleHintData mHintData;
2646 : };
2647 :
2648 : static bool
2649 4117 : SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
2650 : {
2651 4117 : AttributeData* data = (AttributeData*)aData;
2652 : nsRestyleHint hint =
2653 4117 : aProcessor->HasAttributeDependentStyle(data, data->mHintData);
2654 4117 : data->mHint = nsRestyleHint(data->mHint | hint);
2655 4117 : return true; // continue
2656 : }
2657 :
2658 : // Test if style is dependent on content state
2659 : nsRestyleHint
2660 648 : nsStyleSet::HasAttributeDependentStyle(Element* aElement,
2661 : int32_t aNameSpaceID,
2662 : nsIAtom* aAttribute,
2663 : int32_t aModType,
2664 : bool aAttrHasChanged,
2665 : const nsAttrValue* aOtherValue,
2666 : mozilla::RestyleHintData&
2667 : aRestyleHintDataResult)
2668 : {
2669 : TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
2670 1296 : aElement->OwnerDoc());
2671 648 : InitStyleScopes(treeContext, aElement);
2672 : AttributeData data(PresContext(), aElement, aNameSpaceID, aAttribute,
2673 1296 : aModType, aAttrHasChanged, aOtherValue, treeContext);
2674 648 : WalkRuleProcessors(SheetHasAttributeStyle, &data, false);
2675 648 : if (!(data.mHint & eRestyle_Subtree)) {
2676 : // No point keeping the list of selectors around if we are going to
2677 : // restyle the whole subtree unconditionally.
2678 636 : aRestyleHintDataResult = Move(data.mHintData);
2679 : }
2680 1296 : return data.mHint;
2681 : }
2682 :
2683 : bool
2684 21 : nsStyleSet::MediumFeaturesChanged()
2685 : {
2686 21 : NS_ASSERTION(mBatching == 0, "rule processors out of date");
2687 :
2688 : // We can't use WalkRuleProcessors without a content node.
2689 21 : nsPresContext* presContext = PresContext();
2690 21 : bool stylesChanged = false;
2691 210 : for (nsIStyleRuleProcessor* processor : mRuleProcessors) {
2692 189 : if (!processor) {
2693 77 : continue;
2694 : }
2695 112 : bool thisChanged = processor->MediumFeaturesChanged(presContext);
2696 112 : stylesChanged = stylesChanged || thisChanged;
2697 : }
2698 21 : for (nsIStyleRuleProcessor* processor : mScopedDocSheetRuleProcessors) {
2699 0 : bool thisChanged = processor->MediumFeaturesChanged(presContext);
2700 0 : stylesChanged = stylesChanged || thisChanged;
2701 : }
2702 :
2703 21 : if (mBindingManager) {
2704 21 : bool thisChanged = false;
2705 21 : mBindingManager->MediumFeaturesChanged(presContext, &thisChanged);
2706 21 : stylesChanged = stylesChanged || thisChanged;
2707 : }
2708 :
2709 21 : return stylesChanged;
2710 : }
2711 :
2712 : bool
2713 0 : nsStyleSet::EnsureUniqueInnerOnCSSSheets()
2714 : {
2715 0 : AutoTArray<StyleSheet*, 32> queue;
2716 0 : for (SheetType type : gCSSSheetTypes) {
2717 0 : for (StyleSheet* sheet : mSheets[type]) {
2718 0 : queue.AppendElement(sheet);
2719 : }
2720 : }
2721 :
2722 0 : if (mBindingManager) {
2723 0 : AutoTArray<StyleSheet*, 32> sheets;
2724 : // XXXheycam stylo: AppendAllSheets will need to be able to return either
2725 : // CSSStyleSheets or ServoStyleSheets, on request (and then here requesting
2726 : // CSSStyleSheets).
2727 0 : mBindingManager->AppendAllSheets(sheets);
2728 0 : for (StyleSheet* sheet : sheets) {
2729 0 : MOZ_ASSERT(sheet->IsGecko(), "stylo: AppendAllSheets shouldn't give us "
2730 : "ServoStyleSheets yet");
2731 0 : queue.AppendElement(sheet->AsGecko());
2732 : }
2733 : }
2734 :
2735 0 : while (!queue.IsEmpty()) {
2736 0 : uint32_t idx = queue.Length() - 1;
2737 0 : StyleSheet* sheet = queue[idx];
2738 0 : queue.RemoveElementAt(idx);
2739 :
2740 0 : sheet->EnsureUniqueInner();
2741 :
2742 : // Enqueue all the sheet's children.
2743 0 : sheet->AppendAllChildSheets(queue);
2744 : }
2745 :
2746 0 : bool res = mNeedsRestyleAfterEnsureUniqueInner;
2747 0 : mNeedsRestyleAfterEnsureUniqueInner = false;
2748 0 : return res;
2749 : }
2750 :
2751 : nsIStyleRule*
2752 0 : nsStyleSet::InitialStyleRule()
2753 : {
2754 0 : if (!mInitialStyleRule) {
2755 0 : mInitialStyleRule = new nsInitialStyleRule;
2756 : }
2757 0 : return mInitialStyleRule;
2758 : }
2759 :
2760 : bool
2761 0 : nsStyleSet::HasRuleProcessorUsedByMultipleStyleSets(SheetType aSheetType)
2762 : {
2763 0 : MOZ_ASSERT(size_t(aSheetType) < ArrayLength(mRuleProcessors));
2764 0 : if (!IsCSSSheetType(aSheetType) || !mRuleProcessors[aSheetType]) {
2765 0 : return false;
2766 : }
2767 : nsCSSRuleProcessor* rp =
2768 0 : static_cast<nsCSSRuleProcessor*>(mRuleProcessors[aSheetType].get());
2769 0 : return rp->IsUsedByMultipleStyleSets();
2770 : }
2771 :
2772 : void
2773 48 : nsStyleSet::ClearSelectors()
2774 : {
2775 : // We might be called before we've done our first rule tree construction.
2776 48 : if (!mRuleTree) {
2777 0 : return;
2778 : }
2779 48 : MOZ_ASSERT(PresContext()->RestyleManager()->IsGecko(),
2780 : "stylo: the style set and restyle manager must have the same "
2781 : "StyleBackendType");
2782 48 : PresContext()->RestyleManager()->AsGecko()->ClearSelectors();
2783 : }
2784 :
2785 : void
2786 6 : nsStyleSet::ClearNonInheritingStyleContexts()
2787 : {
2788 36 : for (RefPtr<nsStyleContext>& ptr : mNonInheritingStyleContexts) {
2789 30 : ptr = nullptr;
2790 : }
2791 6 : }
|