Bug 1635702 [wpt PR 23413] - Move some internal scroll anchoring tests to wpt, a...
[gecko.git] / layout / style / ServoStyleSet.cpp
blobf4f8dd4c8a5edcb4c690ba9cf70cc504af6c9673
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ServoStyleSet.h"
8 #include "mozilla/ServoStyleSetInlines.h"
10 #include "gfxPlatformFontList.h"
11 #include "mozilla/AutoRestyleTimelineMarker.h"
12 #include "mozilla/DocumentStyleRootIterator.h"
13 #include "mozilla/EffectCompositor.h"
14 #include "mozilla/IntegerRange.h"
15 #include "mozilla/Keyframe.h"
16 #include "mozilla/LookAndFeel.h"
17 #include "mozilla/PresShell.h"
18 #include "mozilla/ServoBindings.h"
19 #include "mozilla/RestyleManager.h"
20 #include "mozilla/ServoStyleRuleMap.h"
21 #include "mozilla/ServoTypes.h"
22 #include "mozilla/SMILAnimationController.h"
23 #include "mozilla/MediaFeatureChange.h"
24 #include "mozilla/StyleAnimationValue.h"
25 #include "mozilla/css/Loader.h"
26 #include "mozilla/dom/AnonymousContent.h"
27 #include "mozilla/dom/ChildIterator.h"
28 #include "mozilla/dom/FontFaceSet.h"
29 #include "mozilla/dom/Element.h"
30 #include "mozilla/dom/ElementInlines.h"
31 #include "nsCSSAnonBoxes.h"
32 #include "nsCSSFrameConstructor.h"
33 #include "nsCSSPseudoElements.h"
34 #include "nsDeviceContext.h"
35 #include "nsHTMLStyleSheet.h"
36 #include "nsIAnonymousContentCreator.h"
37 #include "mozilla/dom/DocumentInlines.h"
38 #include "nsMediaFeatures.h"
39 #include "nsPrintfCString.h"
40 #include "gfxUserFontSet.h"
41 #include "nsWindowSizes.h"
42 #include "GeckoProfiler.h"
44 namespace mozilla {
46 using namespace dom;
48 #ifdef DEBUG
49 bool ServoStyleSet::IsCurrentThreadInServoTraversal() {
50 return sInServoTraversal && (NS_IsMainThread() || Servo_IsWorkerThread());
52 #endif
54 // The definition of kOrigins relies on this.
55 static_assert(static_cast<uint8_t>(StyleOrigin::UserAgent) ==
56 static_cast<uint8_t>(OriginFlags::UserAgent));
57 static_assert(static_cast<uint8_t>(StyleOrigin::User) ==
58 static_cast<uint8_t>(OriginFlags::User));
59 static_assert(static_cast<uint8_t>(StyleOrigin::Author) ==
60 static_cast<uint8_t>(OriginFlags::Author));
62 constexpr const StyleOrigin ServoStyleSet::kOrigins[];
64 ServoStyleSet* sInServoTraversal = nullptr;
66 // On construction, sets sInServoTraversal to the given ServoStyleSet.
67 // On destruction, clears sInServoTraversal and calls RunPostTraversalTasks.
68 class MOZ_RAII AutoSetInServoTraversal {
69 public:
70 explicit AutoSetInServoTraversal(ServoStyleSet* aSet) : mSet(aSet) {
71 MOZ_ASSERT(!sInServoTraversal);
72 MOZ_ASSERT(aSet);
73 sInServoTraversal = aSet;
76 ~AutoSetInServoTraversal() {
77 MOZ_ASSERT(sInServoTraversal);
78 sInServoTraversal = nullptr;
79 mSet->RunPostTraversalTasks();
82 private:
83 ServoStyleSet* mSet;
86 // Sets up for one or more calls to Servo_TraverseSubtree.
87 class MOZ_RAII AutoPrepareTraversal {
88 public:
89 explicit AutoPrepareTraversal(ServoStyleSet* aSet)
90 // For markers for animations, we have already set the markers in
91 // RestyleManager::PostRestyleEventForAnimations so that we don't need
92 // to care about animation restyles here.
93 : mTimelineMarker(aSet->mDocument->GetDocShell(), false),
94 mSetInServoTraversal(aSet) {
95 MOZ_ASSERT(!aSet->StylistNeedsUpdate());
98 private:
99 AutoRestyleTimelineMarker mTimelineMarker;
100 AutoSetInServoTraversal mSetInServoTraversal;
103 ServoStyleSet::ServoStyleSet(Document& aDocument) : mDocument(&aDocument) {
104 PreferenceSheet::EnsureInitialized();
105 PodArrayZero(mCachedAnonymousContentStyleIndexes);
106 mRawSet.reset(Servo_StyleSet_Init(&aDocument));
109 ServoStyleSet::~ServoStyleSet() {
110 MOZ_ASSERT(!IsInServoTraversal());
111 EnumerateStyleSheets([&](StyleSheet& aSheet) { aSheet.DropStyleSet(this); });
114 nsPresContext* ServoStyleSet::GetPresContext() {
115 return mDocument->GetPresContext();
118 template <typename Functor>
119 static void EnumerateShadowRoots(const Document& aDoc, const Functor& aCb) {
120 const Document::ShadowRootSet& shadowRoots = aDoc.ComposedShadowRoots();
121 for (auto iter = shadowRoots.ConstIter(); !iter.Done(); iter.Next()) {
122 ShadowRoot* root = iter.Get()->GetKey();
123 MOZ_ASSERT(root);
124 MOZ_DIAGNOSTIC_ASSERT(root->IsInComposedDoc());
125 aCb(*root);
129 void ServoStyleSet::ShellDetachedFromDocument() {
130 ClearNonInheritingComputedStyles();
131 mCachedAnonymousContentStyles.Clear();
132 PodArrayZero(mCachedAnonymousContentStyleIndexes);
133 mStyleRuleMap = nullptr;
135 // Remove all our stylesheets...
136 for (auto origin : kOrigins) {
137 for (size_t count = SheetCount(origin); count--;) {
138 RemoveStyleSheet(*SheetAt(origin, count));
142 // And remove all the CascadeDatas from memory.
143 UpdateStylistIfNeeded();
145 // Also GC the ruletree if it got big now that the DOM no longer has
146 // references to styles around anymore.
147 MaybeGCRuleTree();
150 void ServoStyleSet::RecordShadowStyleChange(ShadowRoot& aShadowRoot) {
151 // TODO(emilio): We could keep track of the actual shadow roots that need
152 // their styles recomputed.
153 SetStylistShadowDOMStyleSheetsDirty();
155 // FIXME(emilio): This should be done using stylesheet invalidation instead.
156 if (nsPresContext* pc = GetPresContext()) {
157 pc->RestyleManager()->PostRestyleEvent(
158 aShadowRoot.Host(), RestyleHint::RestyleSubtree(), nsChangeHint(0));
162 void ServoStyleSet::InvalidateStyleForDocumentStateChanges(
163 EventStates aStatesChanged) {
164 MOZ_ASSERT(mDocument);
165 MOZ_ASSERT(!aStatesChanged.IsEmpty());
167 nsPresContext* pc = GetPresContext();
168 if (!pc) {
169 return;
172 Element* root = mDocument->GetRootElement();
173 if (!root) {
174 return;
177 // TODO(emilio): It may be nicer to just invalidate stuff in a given subtree
178 // for Shadow DOM. Consider just enumerating shadow roots instead and run
179 // invalidation individually, passing mRawSet for the UA / User sheets.
180 AutoTArray<const RawServoAuthorStyles*, 20> nonDocumentStyles;
182 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
183 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
184 nonDocumentStyles.AppendElement(authorStyles);
188 Servo_InvalidateStyleForDocStateChanges(
189 root, mRawSet.get(), &nonDocumentStyles, aStatesChanged.ServoValue());
192 static const MediaFeatureChangeReason kMediaFeaturesAffectingDefaultStyle =
193 // Zoom changes change the meaning of em units.
194 MediaFeatureChangeReason::ZoomChange |
195 // A resolution change changes the app-units-per-dev-pixels ratio, which
196 // some structs (Border, Outline, Column) store for clamping. We should
197 // arguably not do that, maybe doing it on layout directly, to try to avoid
198 // relying on the pres context (bug 1418159).
199 MediaFeatureChangeReason::ResolutionChange;
201 RestyleHint ServoStyleSet::MediumFeaturesChanged(
202 MediaFeatureChangeReason aReason) {
203 AutoTArray<RawServoAuthorStyles*, 20> nonDocumentStyles;
205 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
206 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
207 nonDocumentStyles.AppendElement(authorStyles);
211 bool mayAffectDefaultStyle =
212 bool(aReason & kMediaFeaturesAffectingDefaultStyle);
214 const MediumFeaturesChangedResult result =
215 Servo_StyleSet_MediumFeaturesChanged(mRawSet.get(), &nonDocumentStyles,
216 mayAffectDefaultStyle);
218 const bool rulesChanged =
219 result.mAffectsDocumentRules || result.mAffectsNonDocumentRules;
221 if (result.mAffectsDocumentRules) {
222 SetStylistStyleSheetsDirty();
225 if (result.mAffectsNonDocumentRules) {
226 SetStylistShadowDOMStyleSheetsDirty();
229 if (rulesChanged) {
230 // TODO(emilio): This could be more granular.
231 return RestyleHint::RestyleSubtree();
234 const bool viewportChanged =
235 bool(aReason & MediaFeatureChangeReason::ViewportChange);
236 if (result.mUsesViewportUnits && viewportChanged) {
237 return RestyleHint::RecascadeSubtree();
240 return RestyleHint{0};
243 MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSetMallocSizeOf)
244 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSetMallocEnclosingSizeOf)
246 void ServoStyleSet::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const {
247 MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
249 aSizes.mLayoutStyleSetsOther += mallocSizeOf(this);
251 if (mRawSet) {
252 aSizes.mLayoutStyleSetsOther += mallocSizeOf(mRawSet.get());
253 ServoStyleSetSizes sizes;
254 // Measure mRawSet. We use ServoStyleSetMallocSizeOf rather than
255 // aMallocSizeOf to distinguish in DMD's output the memory measured within
256 // Servo code.
257 Servo_StyleSet_AddSizeOfExcludingThis(ServoStyleSetMallocSizeOf,
258 ServoStyleSetMallocEnclosingSizeOf,
259 &sizes, mRawSet.get());
261 // The StyleSet does not contain precomputed pseudos; they are in the UA
262 // cache.
263 MOZ_RELEASE_ASSERT(sizes.mPrecomputedPseudos == 0);
265 aSizes.mLayoutStyleSetsStylistRuleTree += sizes.mRuleTree;
266 aSizes.mLayoutStyleSetsStylistElementAndPseudosMaps +=
267 sizes.mElementAndPseudosMaps;
268 aSizes.mLayoutStyleSetsStylistInvalidationMap += sizes.mInvalidationMap;
269 aSizes.mLayoutStyleSetsStylistRevalidationSelectors +=
270 sizes.mRevalidationSelectors;
271 aSizes.mLayoutStyleSetsStylistOther += sizes.mOther;
274 if (mStyleRuleMap) {
275 aSizes.mLayoutStyleSetsOther +=
276 mStyleRuleMap->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
279 // Measurement of the following members may be added later if DMD finds it is
280 // worthwhile:
281 // - mSheets
282 // - mNonInheritingComputedStyles
284 // The following members are not measured:
285 // - mDocument, because it a non-owning pointer
288 void ServoStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled) {
289 if (mAuthorStyleDisabled == aStyleDisabled) {
290 return;
293 mAuthorStyleDisabled = aStyleDisabled;
294 if (Element* root = mDocument->GetRootElement()) {
295 if (nsPresContext* pc = GetPresContext()) {
296 pc->RestyleManager()->PostRestyleEvent(
297 root, RestyleHint::RestyleSubtree(), nsChangeHint(0));
300 Servo_StyleSet_SetAuthorStyleDisabled(mRawSet.get(), mAuthorStyleDisabled);
301 // XXX Workaround for bug 1437785.
302 SetStylistStyleSheetsDirty();
305 const ServoElementSnapshotTable& ServoStyleSet::Snapshots() {
306 MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
307 return GetPresContext()->RestyleManager()->Snapshots();
310 void ServoStyleSet::ResolveMappedAttrDeclarationBlocks() {
311 if (nsHTMLStyleSheet* sheet = mDocument->GetAttributeStyleSheet()) {
312 sheet->CalculateMappedServoDeclarations();
315 mDocument->ResolveScheduledSVGPresAttrs();
318 void ServoStyleSet::PreTraverseSync() {
319 // Get the Document's root element to ensure that the cache is valid before
320 // calling into the (potentially-parallel) Servo traversal, where a cache hit
321 // is necessary to avoid a data race when updating the cache.
322 Unused << mDocument->GetRootElement();
324 // FIXME(emilio): This shouldn't be needed in theory, the call to the same
325 // function in PresShell should do the work, but as it turns out we
326 // ProcessPendingRestyles() twice, and runnables from frames just constructed
327 // can end up doing editing stuff, which adds stylesheets etc...
328 mDocument->FlushUserFontSet();
330 ResolveMappedAttrDeclarationBlocks();
332 nsMediaFeatures::InitSystemMetrics();
334 LookAndFeel::NativeInit();
336 mDocument->CacheAllKnownLangPrefs();
338 if (gfxUserFontSet* userFontSet = mDocument->GetUserFontSet()) {
339 nsPresContext* presContext = GetPresContext();
340 MOZ_ASSERT(presContext,
341 "For now, we don't call into here without a pres context");
343 // Ensure that the @font-face data is not stale
344 uint64_t generation = userFontSet->GetGeneration();
345 if (generation != mUserFontSetUpdateGeneration) {
346 mDocument->GetFonts()->CacheFontLoadability();
347 presContext->DeviceContext()->UpdateFontCacheUserFonts(userFontSet);
348 mUserFontSetUpdateGeneration = generation;
352 MOZ_ASSERT(!StylistNeedsUpdate());
355 void ServoStyleSet::PreTraverse(ServoTraversalFlags aFlags, Element* aRoot) {
356 PreTraverseSync();
358 // Process animation stuff that we should avoid doing during the parallel
359 // traversal.
360 SMILAnimationController* smilController =
361 mDocument->HasAnimationController() ? mDocument->GetAnimationController()
362 : nullptr;
364 MOZ_ASSERT(GetPresContext());
365 if (aRoot) {
366 GetPresContext()->EffectCompositor()->PreTraverseInSubtree(aFlags, aRoot);
367 if (smilController) {
368 smilController->PreTraverseInSubtree(aRoot);
370 } else {
371 GetPresContext()->EffectCompositor()->PreTraverse(aFlags);
372 if (smilController) {
373 smilController->PreTraverse();
378 static inline already_AddRefed<ComputedStyle>
379 ResolveStyleForTextOrFirstLetterContinuation(const RawServoStyleSet* aStyleSet,
380 ComputedStyle& aParent,
381 PseudoStyleType aType) {
382 MOZ_ASSERT(aType == PseudoStyleType::mozText ||
383 aType == PseudoStyleType::firstLetterContinuation);
384 auto inheritTarget = aType == PseudoStyleType::mozText
385 ? InheritTarget::Text
386 : InheritTarget::FirstLetterContinuation;
388 RefPtr<ComputedStyle> style = aParent.GetCachedInheritingAnonBoxStyle(aType);
389 if (!style) {
390 style =
391 Servo_ComputedValues_Inherit(aStyleSet, aType, &aParent, inheritTarget)
392 .Consume();
393 MOZ_ASSERT(style);
394 aParent.SetCachedInheritedAnonBoxStyle(style);
397 return style.forget();
400 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleForText(
401 nsIContent* aTextNode, ComputedStyle* aParentStyle) {
402 MOZ_ASSERT(aTextNode && aTextNode->IsText());
403 MOZ_ASSERT(aTextNode->GetParent());
404 MOZ_ASSERT(aParentStyle);
406 return ResolveStyleForTextOrFirstLetterContinuation(
407 mRawSet.get(), *aParentStyle, PseudoStyleType::mozText);
410 already_AddRefed<ComputedStyle>
411 ServoStyleSet::ResolveStyleForFirstLetterContinuation(
412 ComputedStyle* aParentStyle) {
413 MOZ_ASSERT(aParentStyle);
415 return ResolveStyleForTextOrFirstLetterContinuation(
416 mRawSet.get(), *aParentStyle, PseudoStyleType::firstLetterContinuation);
419 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleForPlaceholder() {
420 RefPtr<ComputedStyle>& cache = mNonInheritingComputedStyles
421 [nsCSSAnonBoxes::NonInheriting::oofPlaceholder];
422 if (cache) {
423 RefPtr<ComputedStyle> retval = cache;
424 return retval.forget();
427 RefPtr<ComputedStyle> computedValues =
428 Servo_ComputedValues_Inherit(mRawSet.get(),
429 PseudoStyleType::oofPlaceholder, nullptr,
430 InheritTarget::PlaceholderFrame)
431 .Consume();
432 MOZ_ASSERT(computedValues);
434 cache = computedValues;
435 return computedValues.forget();
438 static inline bool LazyPseudoIsCacheable(PseudoStyleType aType,
439 const Element& aOriginatingElement,
440 ComputedStyle* aParentStyle) {
441 return aParentStyle &&
442 !nsCSSPseudoElements::IsEagerlyCascadedInServo(aType) &&
443 aOriginatingElement.HasServoData() &&
444 !Servo_Element_IsPrimaryStyleReusedViaRuleNode(&aOriginatingElement);
447 already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePseudoElementStyle(
448 const Element& aOriginatingElement, PseudoStyleType aType,
449 ComputedStyle* aParentStyle, IsProbe aIsProbe) {
450 // Runs from frame construction, this should have clean styles already, except
451 // with non-lazy FC...
452 UpdateStylistIfNeeded();
453 MOZ_ASSERT(PseudoStyle::IsPseudoElement(aType));
455 const bool cacheable =
456 LazyPseudoIsCacheable(aType, aOriginatingElement, aParentStyle);
457 RefPtr<ComputedStyle> style =
458 cacheable ? aParentStyle->GetCachedLazyPseudoStyle(aType) : nullptr;
460 const bool isProbe = aIsProbe == IsProbe::Yes;
462 if (!style) {
463 // FIXME(emilio): Why passing null for probing as the parent style?
465 // There are callers which do pass the wrong parent style and it would
466 // assert (like ComputeSelectionStyle()). That's messy!
467 style = Servo_ResolvePseudoStyle(&aOriginatingElement, aType, isProbe,
468 isProbe ? nullptr : aParentStyle,
469 mRawSet.get())
470 .Consume();
471 if (!style) {
472 MOZ_ASSERT(isProbe);
473 return nullptr;
475 if (cacheable) {
476 aParentStyle->SetCachedLazyPseudoStyle(style);
480 MOZ_ASSERT(style);
482 if (isProbe && !GeneratedContentPseudoExists(*aParentStyle, *style)) {
483 return nullptr;
486 return style.forget();
489 already_AddRefed<ComputedStyle>
490 ServoStyleSet::ResolveInheritingAnonymousBoxStyle(PseudoStyleType aType,
491 ComputedStyle* aParentStyle) {
492 MOZ_ASSERT(PseudoStyle::IsInheritingAnonBox(aType));
493 MOZ_ASSERT_IF(aParentStyle, !StylistNeedsUpdate());
495 UpdateStylistIfNeeded();
497 RefPtr<ComputedStyle> style = nullptr;
499 if (aParentStyle) {
500 style = aParentStyle->GetCachedInheritingAnonBoxStyle(aType);
503 if (!style) {
504 style = Servo_ComputedValues_GetForAnonymousBox(aParentStyle, aType,
505 mRawSet.get())
506 .Consume();
507 MOZ_ASSERT(style);
508 if (aParentStyle) {
509 aParentStyle->SetCachedInheritedAnonBoxStyle(style);
513 return style.forget();
516 already_AddRefed<ComputedStyle>
517 ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType aType) {
518 MOZ_ASSERT(PseudoStyle::IsNonInheritingAnonBox(aType));
519 MOZ_ASSERT(aType != PseudoStyleType::pageContent,
520 "If pageContent ends up non-inheriting, check "
521 "whether we need to do anything to move the "
522 "@page handling from ResolveInheritingAnonymousBoxStyle to "
523 "ResolveNonInheritingAnonymousBoxStyle");
525 nsCSSAnonBoxes::NonInheriting type =
526 nsCSSAnonBoxes::NonInheritingTypeForPseudoType(aType);
527 RefPtr<ComputedStyle>& cache = mNonInheritingComputedStyles[type];
528 if (cache) {
529 RefPtr<ComputedStyle> retval = cache;
530 return retval.forget();
533 UpdateStylistIfNeeded();
535 // We always want to skip parent-based display fixup here. It never makes
536 // sense for non-inheriting anonymous boxes. (Static assertions in
537 // nsCSSAnonBoxes.cpp ensure that all non-inheriting non-anonymous boxes
538 // are indeed annotated as skipping this fixup.)
539 MOZ_ASSERT(!PseudoStyle::IsNonInheritingAnonBox(PseudoStyleType::viewport),
540 "viewport needs fixup to handle blockifying it");
542 RefPtr<ComputedStyle> computedValues =
543 Servo_ComputedValues_GetForAnonymousBox(nullptr, aType, mRawSet.get())
544 .Consume();
545 MOZ_ASSERT(computedValues);
547 cache = computedValues;
548 return computedValues.forget();
551 #ifdef MOZ_XUL
552 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveXULTreePseudoStyle(
553 dom::Element* aParentElement, nsCSSAnonBoxPseudoStaticAtom* aPseudoTag,
554 ComputedStyle* aParentStyle, const AtomArray& aInputWord) {
555 MOZ_ASSERT(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag));
556 MOZ_ASSERT(aParentStyle);
557 MOZ_ASSERT(!StylistNeedsUpdate());
559 return Servo_ComputedValues_ResolveXULTreePseudoStyle(
560 aParentElement, aPseudoTag, aParentStyle, &aInputWord,
561 mRawSet.get())
562 .Consume();
564 #endif
566 // manage the set of style sheets in the style set
567 void ServoStyleSet::AppendStyleSheet(StyleSheet& aSheet) {
568 MOZ_ASSERT(aSheet.IsApplicable());
569 MOZ_ASSERT(aSheet.RawContents(),
570 "Raw sheet should be in place before insertion.");
572 aSheet.AddStyleSet(this);
574 // Maintain a mirrored list of sheets on the servo side.
575 // Servo will remove aSheet from its original position as part of the call
576 // to Servo_StyleSet_AppendStyleSheet.
577 Servo_StyleSet_AppendStyleSheet(mRawSet.get(), &aSheet);
578 SetStylistStyleSheetsDirty();
580 if (mStyleRuleMap) {
581 mStyleRuleMap->SheetAdded(aSheet);
585 void ServoStyleSet::RemoveStyleSheet(StyleSheet& aSheet) {
586 aSheet.DropStyleSet(this);
588 // Maintain a mirrored list of sheets on the servo side.
589 Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), &aSheet);
590 SetStylistStyleSheetsDirty();
592 if (mStyleRuleMap) {
593 mStyleRuleMap->SheetRemoved(aSheet);
597 void ServoStyleSet::InsertStyleSheetBefore(StyleSheet& aNewSheet,
598 StyleSheet& aReferenceSheet) {
599 MOZ_ASSERT(aNewSheet.IsApplicable());
600 MOZ_ASSERT(aReferenceSheet.IsApplicable());
601 MOZ_ASSERT(&aNewSheet != &aReferenceSheet,
602 "Can't place sheet before itself.");
603 MOZ_ASSERT(aNewSheet.GetOrigin() == aReferenceSheet.GetOrigin(),
604 "Sheets should be in the same origin");
605 MOZ_ASSERT(aNewSheet.RawContents(),
606 "Raw sheet should be in place before insertion.");
607 MOZ_ASSERT(aReferenceSheet.RawContents(),
608 "Reference sheet should have a raw sheet.");
610 // Servo will remove aNewSheet from its original position as part of the
611 // call to Servo_StyleSet_InsertStyleSheetBefore.
612 aNewSheet.AddStyleSet(this);
614 // Maintain a mirrored list of sheets on the servo side.
615 Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), &aNewSheet,
616 &aReferenceSheet);
617 SetStylistStyleSheetsDirty();
619 if (mStyleRuleMap) {
620 mStyleRuleMap->SheetAdded(aNewSheet);
624 size_t ServoStyleSet::SheetCount(Origin aOrigin) const {
625 return Servo_StyleSet_GetSheetCount(mRawSet.get(), aOrigin);
628 StyleSheet* ServoStyleSet::SheetAt(Origin aOrigin, size_t aIndex) const {
629 return const_cast<StyleSheet*>(
630 Servo_StyleSet_GetSheetAt(mRawSet.get(), aOrigin, aIndex));
633 void ServoStyleSet::AppendAllNonDocumentAuthorSheets(
634 nsTArray<StyleSheet*>& aArray) const {
635 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
636 for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
637 aArray.AppendElement(aShadowRoot.SheetAt(index));
642 void ServoStyleSet::AddDocStyleSheet(StyleSheet& aSheet) {
643 MOZ_ASSERT(aSheet.IsApplicable());
644 MOZ_ASSERT(aSheet.RawContents(),
645 "Raw sheet should be in place by this point.");
647 size_t index = mDocument->FindDocStyleSheetInsertionPoint(aSheet);
648 aSheet.AddStyleSet(this);
650 if (index < SheetCount(Origin::Author)) {
651 // This case is insert before.
652 StyleSheet* beforeSheet = SheetAt(Origin::Author, index);
654 // Maintain a mirrored list of sheets on the servo side.
655 Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), &aSheet, beforeSheet);
656 SetStylistStyleSheetsDirty();
657 } else {
658 // Maintain a mirrored list of sheets on the servo side.
659 Servo_StyleSet_AppendStyleSheet(mRawSet.get(), &aSheet);
660 SetStylistStyleSheetsDirty();
663 if (mStyleRuleMap) {
664 mStyleRuleMap->SheetAdded(aSheet);
668 bool ServoStyleSet::GeneratedContentPseudoExists(
669 const ComputedStyle& aParentStyle, const ComputedStyle& aPseudoStyle) {
670 auto type = aPseudoStyle.GetPseudoType();
671 MOZ_ASSERT(type != PseudoStyleType::NotPseudo);
673 if (type == PseudoStyleType::marker) {
674 // ::marker only exist for list items (for now).
675 if (!aParentStyle.StyleDisplay()->IsListItem()) {
676 return false;
678 // display:none is equivalent to not having the pseudo-element at all.
679 if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) {
680 return false;
684 // For :before and :after pseudo-elements, having display: none or no
685 // 'content' property is equivalent to not having the pseudo-element
686 // at all.
687 if (type == PseudoStyleType::before || type == PseudoStyleType::after) {
688 if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) {
689 return false;
691 if (!aPseudoStyle.StyleContent()->ContentCount()) {
692 return false;
696 return true;
699 bool ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags) {
700 AUTO_PROFILER_LABEL_CATEGORY_PAIR(LAYOUT_StyleComputation);
701 MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
703 if (!mDocument->GetServoRestyleRoot()) {
704 return false;
707 PreTraverse(aFlags);
708 AutoPrepareTraversal guard(this);
709 const SnapshotTable& snapshots = Snapshots();
711 // Restyle the document from the root element and each of the document level
712 // NAC subtree roots.
713 bool postTraversalRequired = false;
715 Element* rootElement = mDocument->GetRootElement();
716 MOZ_ASSERT_IF(rootElement, rootElement->HasServoData());
718 if (ShouldTraverseInParallel()) {
719 aFlags |= ServoTraversalFlags::ParallelTraversal;
722 // Do the first traversal.
723 DocumentStyleRootIterator iter(mDocument->GetServoRestyleRoot());
724 while (Element* root = iter.GetNextStyleRoot()) {
725 MOZ_ASSERT(MayTraverseFrom(root));
727 Element* parent = root->GetFlattenedTreeParentElementForStyle();
728 MOZ_ASSERT_IF(parent,
729 !parent->HasAnyOfFlags(Element::kAllServoDescendantBits));
731 postTraversalRequired |=
732 Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags);
733 postTraversalRequired |= root->HasAnyOfFlags(
734 Element::kAllServoDescendantBits | NODE_NEEDS_FRAME);
736 if (parent) {
737 MOZ_ASSERT(root == mDocument->GetServoRestyleRoot());
738 if (parent->HasDirtyDescendantsForServo()) {
739 // If any style invalidation was triggered in our siblings, then we may
740 // need to post-traverse them, even if the root wasn't restyled after
741 // all.
742 uint32_t existingBits = mDocument->GetServoRestyleRootDirtyBits();
743 // We need to propagate the existing bits to the parent.
744 parent->SetFlags(existingBits);
745 mDocument->SetServoRestyleRoot(
746 parent, existingBits | ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
747 postTraversalRequired = true;
752 // If there are still animation restyles needed, trigger a second traversal to
753 // update CSS animations or transitions' styles.
755 // Note that we need to check the style root again, because doing another
756 // PreTraverse on the EffectCompositor might alter the style root. But we
757 // don't need to worry about NAC, since document-level NAC shouldn't have
758 // animations.
760 // We don't need to do this for SMIL since SMIL only updates its animation
761 // values once at the begin of a tick. As a result, even if the previous
762 // traversal caused, for example, the font-size to change, the SMIL style
763 // won't be updated until the next tick anyway.
764 if (GetPresContext()->EffectCompositor()->PreTraverse(aFlags)) {
765 nsINode* styleRoot = mDocument->GetServoRestyleRoot();
766 Element* root =
767 styleRoot->IsElement() ? styleRoot->AsElement() : rootElement;
769 postTraversalRequired |=
770 Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags);
771 postTraversalRequired |= root->HasAnyOfFlags(
772 Element::kAllServoDescendantBits | NODE_NEEDS_FRAME);
775 return postTraversalRequired;
778 void ServoStyleSet::StyleNewSubtree(Element* aRoot) {
779 MOZ_ASSERT(GetPresContext());
780 MOZ_ASSERT(!aRoot->HasServoData());
781 MOZ_ASSERT(aRoot->GetFlattenedTreeParentNodeForStyle(),
782 "Not in the flat tree? Fishy!");
783 PreTraverseSync();
784 AutoPrepareTraversal guard(this);
786 // Do the traversal. The snapshots will not be used.
787 const SnapshotTable& snapshots = Snapshots();
788 auto flags = ServoTraversalFlags::Empty;
789 if (ShouldTraverseInParallel()) {
790 flags |= ServoTraversalFlags::ParallelTraversal;
793 DebugOnly<bool> postTraversalRequired =
794 Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots, flags);
795 MOZ_ASSERT(!postTraversalRequired);
797 // Annoyingly, the newly-styled content may have animations that need
798 // starting, which requires traversing them again. Mark the elements
799 // that need animation processing, then do a forgetful traversal to
800 // update the styles and clear the animation bits.
801 if (GetPresContext()->EffectCompositor()->PreTraverseInSubtree(flags,
802 aRoot)) {
803 postTraversalRequired =
804 Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots,
805 ServoTraversalFlags::AnimationOnly |
806 ServoTraversalFlags::FinalAnimationTraversal);
807 MOZ_ASSERT(!postTraversalRequired);
811 void ServoStyleSet::MarkOriginsDirty(OriginFlags aChangedOrigins) {
812 SetStylistStyleSheetsDirty();
813 Servo_StyleSet_NoteStyleSheetsChanged(mRawSet.get(), aChangedOrigins);
816 void ServoStyleSet::SetStylistStyleSheetsDirty() {
817 mStylistState |= StylistState::StyleSheetsDirty;
819 // We need to invalidate cached style in getComputedStyle for undisplayed
820 // elements, since we don't know if any of the style sheet change that we do
821 // would affect undisplayed elements.
823 // We don't allow to call getComputedStyle in elements without a pres shell
824 // yet, so it is fine if there's no pres context here.
825 if (nsPresContext* presContext = GetPresContext()) {
826 presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration();
830 void ServoStyleSet::SetStylistShadowDOMStyleSheetsDirty() {
831 mStylistState |= StylistState::ShadowDOMStyleSheetsDirty;
832 if (nsPresContext* presContext = GetPresContext()) {
833 presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration();
837 static OriginFlags ToOriginFlags(StyleOrigin aOrigin) {
838 switch (aOrigin) {
839 case StyleOrigin::UserAgent:
840 return OriginFlags::UserAgent;
841 case StyleOrigin::User:
842 return OriginFlags::User;
843 default:
844 MOZ_FALLTHROUGH_ASSERT("Unknown origin?");
845 case StyleOrigin::Author:
846 return OriginFlags::Author;
850 void ServoStyleSet::ImportRuleLoaded(dom::CSSImportRule&, StyleSheet& aSheet) {
851 if (mStyleRuleMap) {
852 mStyleRuleMap->SheetAdded(aSheet);
855 // TODO: Should probably consider ancestor sheets too.
856 if (!aSheet.IsApplicable()) {
857 return;
860 // TODO(emilio): Could handle it better given we know it is an insertion, and
861 // use the style invalidation machinery stuff that we do for regular sheet
862 // insertions.
863 MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
866 void ServoStyleSet::RuleAdded(StyleSheet& aSheet, css::Rule& aRule) {
867 if (mStyleRuleMap) {
868 mStyleRuleMap->RuleAdded(aSheet, aRule);
871 if (!aSheet.IsApplicable() || aRule.IsIncompleteImportRule()) {
872 return;
875 // FIXME(emilio): Could be more granular based on aRule.
876 MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
879 void ServoStyleSet::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule) {
880 if (mStyleRuleMap) {
881 mStyleRuleMap->RuleRemoved(aSheet, aRule);
884 if (!aSheet.IsApplicable()) {
885 return;
888 // FIXME(emilio): Could be more granular based on aRule.
889 MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
892 void ServoStyleSet::RuleChanged(StyleSheet& aSheet, css::Rule* aRule) {
893 if (!aSheet.IsApplicable()) {
894 return;
897 // FIXME(emilio): Could be more granular based on aRule.
898 MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
901 #ifdef DEBUG
902 void ServoStyleSet::AssertTreeIsClean() {
903 DocumentStyleRootIterator iter(mDocument);
904 while (Element* root = iter.GetNextStyleRoot()) {
905 Servo_AssertTreeIsClean(root);
908 #endif
910 bool ServoStyleSet::GetKeyframesForName(const Element& aElement,
911 const ComputedStyle& aStyle,
912 nsAtom* aName,
913 const nsTimingFunction& aTimingFunction,
914 nsTArray<Keyframe>& aKeyframes) {
915 MOZ_ASSERT(!StylistNeedsUpdate());
916 return Servo_StyleSet_GetKeyframesForName(
917 mRawSet.get(), &aElement, &aStyle, aName, &aTimingFunction, &aKeyframes);
920 nsTArray<ComputedKeyframeValues> ServoStyleSet::GetComputedKeyframeValuesFor(
921 const nsTArray<Keyframe>& aKeyframes, Element* aElement,
922 const ComputedStyle* aStyle) {
923 nsTArray<ComputedKeyframeValues> result(aKeyframes.Length());
925 // Construct each nsTArray<PropertyStyleAnimationValuePair> here.
926 result.AppendElements(aKeyframes.Length());
928 Servo_GetComputedKeyframeValues(&aKeyframes, aElement, aStyle, mRawSet.get(),
929 &result);
930 return result;
933 void ServoStyleSet::GetAnimationValues(
934 RawServoDeclarationBlock* aDeclarations, Element* aElement,
935 const ComputedStyle* aComputedStyle,
936 nsTArray<RefPtr<RawServoAnimationValue>>& aAnimationValues) {
937 // Servo_GetAnimationValues below won't handle ignoring existing element
938 // data for bfcached documents. (See comment in ResolveStyleLazily
939 // about these bfcache issues.)
940 Servo_GetAnimationValues(aDeclarations, aElement, aComputedStyle,
941 mRawSet.get(), &aAnimationValues);
944 already_AddRefed<ComputedStyle> ServoStyleSet::GetBaseContextForElement(
945 Element* aElement, const ComputedStyle* aStyle) {
946 return Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(), aElement,
947 aStyle, &Snapshots())
948 .Consume();
951 already_AddRefed<ComputedStyle>
952 ServoStyleSet::ResolveServoStyleByAddingAnimation(
953 Element* aElement, const ComputedStyle* aStyle,
954 RawServoAnimationValue* aAnimationValue) {
955 return Servo_StyleSet_GetComputedValuesByAddingAnimation(
956 mRawSet.get(), aElement, aStyle, &Snapshots(), aAnimationValue)
957 .Consume();
960 already_AddRefed<RawServoAnimationValue> ServoStyleSet::ComputeAnimationValue(
961 Element* aElement, RawServoDeclarationBlock* aDeclarations,
962 const ComputedStyle* aStyle) {
963 return Servo_AnimationValue_Compute(aElement, aDeclarations, aStyle,
964 mRawSet.get())
965 .Consume();
968 bool ServoStyleSet::EnsureUniqueInnerOnCSSSheets() {
969 using SheetOwner = Variant<ServoStyleSet*, ShadowRoot*>;
971 AutoTArray<std::pair<StyleSheet*, SheetOwner>, 32> queue;
972 EnumerateStyleSheets([&](StyleSheet& aSheet) {
973 queue.AppendElement(std::make_pair(&aSheet, SheetOwner{this}));
976 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
977 for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
978 queue.AppendElement(
979 std::make_pair(aShadowRoot.SheetAt(index), SheetOwner{&aShadowRoot}));
983 while (!queue.IsEmpty()) {
984 uint32_t idx = queue.Length() - 1;
985 auto* sheet = queue[idx].first;
986 SheetOwner owner = queue[idx].second;
987 queue.RemoveElementAt(idx);
989 // Only call EnsureUniqueInner for complete sheets. If we do call it on
990 // incomplete sheets, we'll cause problems when the sheet is actually
991 // loaded. We don't care about incomplete sheets here anyway, because this
992 // method is only invoked by nsPresContext::EnsureSafeToHandOutCSSRules.
993 // The CSSRule objects we are handing out won't contain any rules derived
994 // from incomplete sheets (because they aren't yet applied in styling).
995 if (sheet->IsComplete()) {
996 sheet->EnsureUniqueInner();
999 // Enqueue all the sheet's children.
1000 for (StyleSheet* child : sheet->ChildSheets()) {
1001 queue.AppendElement(std::make_pair(child, owner));
1005 if (mNeedsRestyleAfterEnsureUniqueInner) {
1006 // TODO(emilio): We could make this faster if needed tracking the specific
1007 // origins and sheets that have been cloned. But the only caller of this
1008 // doesn't seem to really care about perf.
1009 MarkOriginsDirty(OriginFlags::All);
1010 ForceDirtyAllShadowStyles();
1012 bool res = mNeedsRestyleAfterEnsureUniqueInner;
1013 mNeedsRestyleAfterEnsureUniqueInner = false;
1014 return res;
1017 void ServoStyleSet::ClearCachedStyleData() {
1018 ClearNonInheritingComputedStyles();
1019 Servo_StyleSet_RebuildCachedData(mRawSet.get());
1020 mCachedAnonymousContentStyles.Clear();
1021 PodArrayZero(mCachedAnonymousContentStyleIndexes);
1024 void ServoStyleSet::ForceDirtyAllShadowStyles() {
1025 bool anyShadow = false;
1026 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
1027 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
1028 anyShadow = true;
1029 Servo_AuthorStyles_ForceDirty(authorStyles);
1032 if (anyShadow) {
1033 SetStylistShadowDOMStyleSheetsDirty();
1037 void ServoStyleSet::CompatibilityModeChanged() {
1038 Servo_StyleSet_CompatModeChanged(mRawSet.get());
1039 SetStylistStyleSheetsDirty();
1040 ForceDirtyAllShadowStyles();
1043 void ServoStyleSet::ClearNonInheritingComputedStyles() {
1044 for (RefPtr<ComputedStyle>& ptr : mNonInheritingComputedStyles) {
1045 ptr = nullptr;
1049 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleLazily(
1050 Element& aElement, PseudoStyleType aPseudoType,
1051 StyleRuleInclusion aRuleInclusion) {
1052 PreTraverseSync();
1053 MOZ_ASSERT(GetPresContext(),
1054 "For now, no style resolution without a pres context");
1055 MOZ_ASSERT(!StylistNeedsUpdate());
1057 AutoSetInServoTraversal guard(this);
1060 * NB: This is needed because we process animations and transitions on the
1061 * pseudo-elements themselves, not on the parent's EagerPseudoStyles.
1063 * That means that that style doesn't account for animations, and we can't do
1064 * that easily from the traversal without doing wasted work.
1066 * As such, we just lie here a bit, which is the entrypoint of
1067 * getComputedStyle, the only API where this can be observed, to look at the
1068 * style of the pseudo-element if it exists instead.
1070 Element* elementForStyleResolution = &aElement;
1071 PseudoStyleType pseudoTypeForStyleResolution = aPseudoType;
1072 if (aPseudoType == PseudoStyleType::before) {
1073 if (Element* pseudo = nsLayoutUtils::GetBeforePseudo(&aElement)) {
1074 elementForStyleResolution = pseudo;
1075 pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
1077 } else if (aPseudoType == PseudoStyleType::after) {
1078 if (Element* pseudo = nsLayoutUtils::GetAfterPseudo(&aElement)) {
1079 elementForStyleResolution = pseudo;
1080 pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
1082 } else if (aPseudoType == PseudoStyleType::marker) {
1083 if (Element* pseudo = nsLayoutUtils::GetMarkerPseudo(&aElement)) {
1084 elementForStyleResolution = pseudo;
1085 pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
1089 return Servo_ResolveStyleLazily(elementForStyleResolution,
1090 pseudoTypeForStyleResolution, aRuleInclusion,
1091 &Snapshots(), mRawSet.get())
1092 .Consume();
1095 void ServoStyleSet::AppendFontFaceRules(
1096 nsTArray<nsFontFaceRuleContainer>& aArray) {
1097 // TODO(emilio): Can we make this so this asserts instead?
1098 UpdateStylistIfNeeded();
1099 Servo_StyleSet_GetFontFaceRules(mRawSet.get(), &aArray);
1102 const RawServoCounterStyleRule* ServoStyleSet::CounterStyleRuleForName(
1103 nsAtom* aName) {
1104 MOZ_ASSERT(!StylistNeedsUpdate());
1105 return Servo_StyleSet_GetCounterStyleRule(mRawSet.get(), aName);
1108 already_AddRefed<gfxFontFeatureValueSet>
1109 ServoStyleSet::BuildFontFeatureValueSet() {
1110 MOZ_ASSERT(!StylistNeedsUpdate());
1111 RefPtr<gfxFontFeatureValueSet> set =
1112 Servo_StyleSet_BuildFontFeatureValueSet(mRawSet.get());
1113 return set.forget();
1116 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveForDeclarations(
1117 const ComputedStyle* aParentOrNull,
1118 const RawServoDeclarationBlock* aDeclarations) {
1119 // No need to update the stylist, we're only cascading aDeclarations.
1120 return Servo_StyleSet_ResolveForDeclarations(mRawSet.get(), aParentOrNull,
1121 aDeclarations)
1122 .Consume();
1125 void ServoStyleSet::UpdateStylist() {
1126 MOZ_ASSERT(StylistNeedsUpdate());
1128 if (mStylistState & StylistState::StyleSheetsDirty) {
1129 Element* root = mDocument->GetRootElement();
1130 const ServoElementSnapshotTable* snapshots = nullptr;
1131 if (nsPresContext* pc = GetPresContext()) {
1132 snapshots = &pc->RestyleManager()->Snapshots();
1134 Servo_StyleSet_FlushStyleSheets(mRawSet.get(), root, snapshots);
1137 if (MOZ_UNLIKELY(mStylistState & StylistState::ShadowDOMStyleSheetsDirty)) {
1138 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
1139 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
1140 Servo_AuthorStyles_Flush(authorStyles, mRawSet.get());
1145 mStylistState = StylistState::NotDirty;
1148 void ServoStyleSet::MaybeGCRuleTree() {
1149 MOZ_ASSERT(NS_IsMainThread());
1150 Servo_MaybeGCRuleTree(mRawSet.get());
1153 /* static */
1154 bool ServoStyleSet::MayTraverseFrom(const Element* aElement) {
1155 MOZ_ASSERT(aElement->IsInComposedDoc());
1156 nsINode* parent = aElement->GetFlattenedTreeParentNodeForStyle();
1157 if (!parent) {
1158 return false;
1161 if (!parent->IsElement()) {
1162 MOZ_ASSERT(parent->IsDocument());
1163 return true;
1166 if (!parent->AsElement()->HasServoData()) {
1167 return false;
1170 return !Servo_Element_IsDisplayNone(parent->AsElement());
1173 bool ServoStyleSet::ShouldTraverseInParallel() const {
1174 MOZ_ASSERT(mDocument->GetPresShell(), "Styling a document without a shell?");
1175 if (!mDocument->GetPresShell()->IsActive()) {
1176 return false;
1178 #ifdef MOZ_GECKO_PROFILER
1179 if (profiler_feature_active(ProfilerFeature::SequentialStyle)) {
1180 return false;
1182 #endif
1183 return true;
1186 void ServoStyleSet::RunPostTraversalTasks() {
1187 MOZ_ASSERT(!IsInServoTraversal());
1189 if (mPostTraversalTasks.IsEmpty()) {
1190 return;
1193 nsTArray<PostTraversalTask> tasks;
1194 tasks.SwapElements(mPostTraversalTasks);
1196 for (auto& task : tasks) {
1197 task.Run();
1201 ServoStyleRuleMap* ServoStyleSet::StyleRuleMap() {
1202 if (!mStyleRuleMap) {
1203 mStyleRuleMap = MakeUnique<ServoStyleRuleMap>();
1205 mStyleRuleMap->EnsureTable(*this);
1206 return mStyleRuleMap.get();
1209 bool ServoStyleSet::MightHaveAttributeDependency(const Element& aElement,
1210 nsAtom* aAttribute) const {
1211 return Servo_StyleSet_MightHaveAttributeDependency(mRawSet.get(), &aElement,
1212 aAttribute);
1215 bool ServoStyleSet::HasStateDependency(const Element& aElement,
1216 EventStates aState) const {
1217 return Servo_StyleSet_HasStateDependency(mRawSet.get(), &aElement,
1218 aState.ServoValue());
1221 bool ServoStyleSet::HasDocumentStateDependency(EventStates aState) const {
1222 return Servo_StyleSet_HasDocumentStateDependency(mRawSet.get(),
1223 aState.ServoValue());
1226 already_AddRefed<ComputedStyle> ServoStyleSet::ReparentComputedStyle(
1227 ComputedStyle* aComputedStyle, ComputedStyle* aNewParent,
1228 ComputedStyle* aNewParentIgnoringFirstLine, ComputedStyle* aNewLayoutParent,
1229 Element* aElement) {
1230 return Servo_ReparentStyle(aComputedStyle, aNewParent,
1231 aNewParentIgnoringFirstLine, aNewLayoutParent,
1232 aElement, mRawSet.get())
1233 .Consume();
1236 NS_IMPL_ISUPPORTS(UACacheReporter, nsIMemoryReporter)
1238 MOZ_DEFINE_MALLOC_SIZE_OF(ServoUACacheMallocSizeOf)
1239 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoUACacheMallocEnclosingSizeOf)
1241 NS_IMETHODIMP
1242 UACacheReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
1243 nsISupports* aData, bool aAnonymize) {
1244 ServoStyleSetSizes sizes;
1245 Servo_UACache_AddSizeOf(ServoUACacheMallocSizeOf,
1246 ServoUACacheMallocEnclosingSizeOf, &sizes);
1248 #define REPORT(_path, _amount, _desc) \
1249 do { \
1250 size_t __amount = _amount; /* evaluate _amount only once */ \
1251 if (__amount > 0) { \
1252 MOZ_COLLECT_REPORT(_path, KIND_HEAP, UNITS_BYTES, __amount, _desc); \
1254 } while (0)
1256 // The UA cache does not contain the rule tree; that's in the StyleSet.
1257 MOZ_RELEASE_ASSERT(sizes.mRuleTree == 0);
1259 REPORT("explicit/layout/servo-ua-cache/precomputed-pseudos",
1260 sizes.mPrecomputedPseudos,
1261 "Memory used by precomputed pseudo-element declarations within the "
1262 "UA cache.");
1264 REPORT("explicit/layout/servo-ua-cache/element-and-pseudos-maps",
1265 sizes.mElementAndPseudosMaps,
1266 "Memory used by element and pseudos maps within the UA cache.");
1268 REPORT("explicit/layout/servo-ua-cache/invalidation-map",
1269 sizes.mInvalidationMap,
1270 "Memory used by invalidation maps within the UA cache.");
1272 REPORT("explicit/layout/servo-ua-cache/revalidation-selectors",
1273 sizes.mRevalidationSelectors,
1274 "Memory used by selectors for cache revalidation within the UA "
1275 "cache.");
1277 REPORT("explicit/layout/servo-ua-cache/other", sizes.mOther,
1278 "Memory used by other data within the UA cache");
1280 return NS_OK;
1283 } // namespace mozilla