Bug 1921551 - React to sync sign in flow correctly r=android-reviewers,matt-tighe
[gecko.git] / layout / style / ServoStyleSet.cpp
blobc1e1c48f8a6cf9a90520de352abf3e8257afa415
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 "mozilla/DocumentStyleRootIterator.h"
11 #include "mozilla/AttributeStyles.h"
12 #include "mozilla/EffectCompositor.h"
13 #include "mozilla/IntegerRange.h"
14 #include "mozilla/Keyframe.h"
15 #include "mozilla/LookAndFeel.h"
16 #include "mozilla/PresShell.h"
17 #include "mozilla/ProfilerLabels.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/CSSBinding.h"
28 #include "mozilla/dom/CSSCounterStyleRule.h"
29 #include "mozilla/dom/CSSFontFaceRule.h"
30 #include "mozilla/dom/CSSFontFeatureValuesRule.h"
31 #include "mozilla/dom/CSSFontPaletteValuesRule.h"
32 #include "mozilla/dom/CSSImportRule.h"
33 #include "mozilla/dom/CSSContainerRule.h"
34 #include "mozilla/dom/CSSLayerBlockRule.h"
35 #include "mozilla/dom/CSSLayerStatementRule.h"
36 #include "mozilla/dom/CSSMarginRule.h"
37 #include "mozilla/dom/CSSMediaRule.h"
38 #include "mozilla/dom/CSSMozDocumentRule.h"
39 #include "mozilla/dom/CSSKeyframesRule.h"
40 #include "mozilla/dom/CSSKeyframeRule.h"
41 #include "mozilla/dom/CSSNamespaceRule.h"
42 #include "mozilla/dom/CSSNestedDeclarations.h"
43 #include "mozilla/dom/CSSPageRule.h"
44 #include "mozilla/dom/CSSPropertyRule.h"
45 #include "mozilla/dom/CSSPositionTryRule.h"
46 #include "mozilla/dom/CSSScopeRule.h"
47 #include "mozilla/dom/CSSSupportsRule.h"
48 #include "mozilla/dom/CSSStartingStyleRule.h"
49 #include "mozilla/dom/CSSStyleRule.h"
50 #include "mozilla/dom/FontFaceSet.h"
51 #include "mozilla/dom/Element.h"
52 #include "mozilla/dom/ElementInlines.h"
53 #include "nsCSSAnonBoxes.h"
54 #include "nsCSSFrameConstructor.h"
55 #include "nsCSSPseudoElements.h"
56 #include "nsDeviceContext.h"
57 #include "nsIAnonymousContentCreator.h"
58 #include "nsLayoutUtils.h"
59 #include "mozilla/dom/DocumentInlines.h"
60 #include "nsPrintfCString.h"
61 #include "gfxUserFontSet.h"
62 #include "nsWindowSizes.h"
64 namespace mozilla {
66 using namespace dom;
68 #ifdef DEBUG
69 bool ServoStyleSet::IsCurrentThreadInServoTraversal() {
70 return sInServoTraversal && (NS_IsMainThread() || Servo_IsWorkerThread());
72 #endif
74 // The definition of kOrigins relies on this.
75 static_assert(static_cast<uint8_t>(StyleOrigin::UserAgent) ==
76 static_cast<uint8_t>(OriginFlags::UserAgent));
77 static_assert(static_cast<uint8_t>(StyleOrigin::User) ==
78 static_cast<uint8_t>(OriginFlags::User));
79 static_assert(static_cast<uint8_t>(StyleOrigin::Author) ==
80 static_cast<uint8_t>(OriginFlags::Author));
82 constexpr const StyleOrigin ServoStyleSet::kOrigins[];
84 ServoStyleSet* sInServoTraversal = nullptr;
86 // On construction, sets sInServoTraversal to the given ServoStyleSet.
87 // On destruction, clears sInServoTraversal and calls RunPostTraversalTasks.
88 class MOZ_RAII AutoSetInServoTraversal {
89 public:
90 explicit AutoSetInServoTraversal(ServoStyleSet* aSet) : mSet(aSet) {
91 MOZ_ASSERT(!sInServoTraversal);
92 MOZ_ASSERT(aSet);
93 sInServoTraversal = aSet;
96 ~AutoSetInServoTraversal() {
97 MOZ_ASSERT(sInServoTraversal);
98 sInServoTraversal = nullptr;
99 mSet->RunPostTraversalTasks();
102 private:
103 ServoStyleSet* mSet;
106 // Sets up for one or more calls to Servo_TraverseSubtree.
107 class MOZ_RAII AutoPrepareTraversal {
108 public:
109 explicit AutoPrepareTraversal(ServoStyleSet* aSet)
110 : mSetInServoTraversal(aSet) {
111 MOZ_ASSERT(!aSet->StylistNeedsUpdate());
114 private:
115 AutoSetInServoTraversal mSetInServoTraversal;
118 ServoStyleSet::ServoStyleSet(Document& aDocument) : mDocument(&aDocument) {
119 PreferenceSheet::EnsureInitialized();
120 PodArrayZero(mCachedAnonymousContentStyleIndexes);
121 mRawData.reset(Servo_StyleSet_Init(&aDocument));
124 ServoStyleSet::~ServoStyleSet() {
125 MOZ_ASSERT(!IsInServoTraversal());
126 EnumerateStyleSheets([&](StyleSheet& aSheet) { aSheet.DropStyleSet(this); });
129 nsPresContext* ServoStyleSet::GetPresContext() {
130 return mDocument->GetPresContext();
133 template <typename Functor>
134 static void EnumerateShadowRoots(const Document& aDoc, const Functor& aCb) {
135 const Document::ShadowRootSet& shadowRoots = aDoc.ComposedShadowRoots();
136 for (ShadowRoot* root : shadowRoots) {
137 MOZ_ASSERT(root);
138 MOZ_DIAGNOSTIC_ASSERT(root->IsInComposedDoc());
139 aCb(*root);
143 void ServoStyleSet::ShellDetachedFromDocument() {
144 ClearNonInheritingComputedStyles();
145 mCachedAnonymousContentStyles.Clear();
146 PodArrayZero(mCachedAnonymousContentStyleIndexes);
147 mStyleRuleMap = nullptr;
149 // Remove all our stylesheets...
150 for (auto origin : kOrigins) {
151 for (size_t count = SheetCount(origin); count--;) {
152 RemoveStyleSheet(*SheetAt(origin, count));
156 // And remove all the CascadeDatas from memory.
157 UpdateStylistIfNeeded();
159 // Also GC the ruletree if it got big now that the DOM no longer has
160 // references to styles around anymore.
161 MaybeGCRuleTree();
164 void ServoStyleSet::RecordShadowStyleChange(ShadowRoot& aShadowRoot) {
165 // TODO(emilio): We could keep track of the actual shadow roots that need
166 // their styles recomputed.
167 SetStylistShadowDOMStyleSheetsDirty();
169 // FIXME(emilio): This should be done using stylesheet invalidation instead.
170 if (nsPresContext* pc = GetPresContext()) {
171 pc->RestyleManager()->PostRestyleEvent(
172 aShadowRoot.Host(), RestyleHint::RestyleSubtree(), nsChangeHint(0));
176 void ServoStyleSet::InvalidateStyleForDocumentStateChanges(
177 DocumentState aStatesChanged) {
178 MOZ_ASSERT(mDocument);
179 MOZ_ASSERT(!aStatesChanged.IsEmpty());
181 nsPresContext* pc = GetPresContext();
182 if (!pc) {
183 return;
186 Element* root = mDocument->GetRootElement();
187 if (!root) {
188 return;
191 // TODO(emilio): It may be nicer to just invalidate stuff in a given subtree
192 // for Shadow DOM. Consider just enumerating shadow roots instead and run
193 // invalidation individually, passing mRawData for the UA / User sheets.
194 AutoTArray<const StyleAuthorStyles*, 20> nonDocumentStyles;
196 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
197 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
198 nonDocumentStyles.AppendElement(authorStyles);
202 Servo_InvalidateStyleForDocStateChanges(root, mRawData.get(),
203 &nonDocumentStyles,
204 aStatesChanged.GetInternalValue());
207 static const MediaFeatureChangeReason kMediaFeaturesAffectingDefaultStyle =
208 // Zoom changes change the meaning of em units.
209 MediaFeatureChangeReason::ZoomChange |
210 // A resolution change changes the app-units-per-dev-pixels ratio, which
211 // some structs (Border, Outline, Column) store for clamping. We should
212 // arguably not do that, maybe doing it on layout directly, to try to avoid
213 // relying on the pres context (bug 1418159).
214 MediaFeatureChangeReason::ResolutionChange;
216 RestyleHint ServoStyleSet::MediumFeaturesChanged(
217 MediaFeatureChangeReason aReason) {
218 AutoTArray<StyleAuthorStyles*, 20> nonDocumentStyles;
220 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
221 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
222 nonDocumentStyles.AppendElement(authorStyles);
226 const bool mayAffectDefaultStyle =
227 bool(aReason & kMediaFeaturesAffectingDefaultStyle);
228 const MediumFeaturesChangedResult result =
229 Servo_StyleSet_MediumFeaturesChanged(mRawData.get(), &nonDocumentStyles,
230 mayAffectDefaultStyle);
232 const bool viewportChanged =
233 bool(aReason & MediaFeatureChangeReason::ViewportChange);
234 if (viewportChanged) {
235 InvalidateForViewportUnits(OnlyDynamic::No);
238 const bool rulesChanged =
239 result.mAffectsDocumentRules || result.mAffectsNonDocumentRules;
241 if (result.mAffectsDocumentRules) {
242 SetStylistStyleSheetsDirty();
245 if (result.mAffectsNonDocumentRules) {
246 SetStylistShadowDOMStyleSheetsDirty();
249 if (rulesChanged) {
250 // TODO(emilio): This could be more granular.
251 return RestyleHint::RestyleSubtree();
254 return RestyleHint{0};
257 MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSetMallocSizeOf)
258 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSetMallocEnclosingSizeOf)
260 void ServoStyleSet::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const {
261 MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
263 aSizes.mLayoutStyleSetsOther += mallocSizeOf(this);
265 if (mRawData) {
266 aSizes.mLayoutStyleSetsOther += mallocSizeOf(mRawData.get());
267 ServoStyleSetSizes sizes;
268 // Measure mRawData. We use ServoStyleSetMallocSizeOf rather than
269 // aMallocSizeOf to distinguish in DMD's output the memory measured within
270 // Servo code.
271 Servo_StyleSet_AddSizeOfExcludingThis(ServoStyleSetMallocSizeOf,
272 ServoStyleSetMallocEnclosingSizeOf,
273 &sizes, mRawData.get());
275 // The StyleSet does not contain precomputed pseudos; they are in the UA
276 // cache.
277 MOZ_RELEASE_ASSERT(sizes.mPrecomputedPseudos == 0);
279 aSizes.mLayoutStyleSetsStylistRuleTree += sizes.mRuleTree;
280 aSizes.mLayoutStyleSetsStylistElementAndPseudosMaps +=
281 sizes.mElementAndPseudosMaps;
282 aSizes.mLayoutStyleSetsStylistInvalidationMap += sizes.mInvalidationMap;
283 aSizes.mLayoutStyleSetsStylistRevalidationSelectors +=
284 sizes.mRevalidationSelectors;
285 aSizes.mLayoutStyleSetsStylistOther += sizes.mOther;
288 if (mStyleRuleMap) {
289 aSizes.mLayoutStyleSetsOther +=
290 mStyleRuleMap->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
293 // Measurement of the following members may be added later if DMD finds it is
294 // worthwhile:
295 // - mSheets
296 // - mNonInheritingComputedStyles
298 // The following members are not measured:
299 // - mDocument, because it a non-owning pointer
302 void ServoStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled) {
303 if (mAuthorStyleDisabled == aStyleDisabled) {
304 return;
307 mAuthorStyleDisabled = aStyleDisabled;
308 if (Element* root = mDocument->GetRootElement()) {
309 if (nsPresContext* pc = GetPresContext()) {
310 pc->RestyleManager()->PostRestyleEvent(
311 root, RestyleHint::RestyleSubtree(), nsChangeHint(0));
314 Servo_StyleSet_SetAuthorStyleDisabled(mRawData.get(), mAuthorStyleDisabled);
315 // XXX Workaround for bug 1437785.
316 SetStylistStyleSheetsDirty();
319 const ServoElementSnapshotTable& ServoStyleSet::Snapshots() {
320 MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
321 return GetPresContext()->RestyleManager()->Snapshots();
324 void ServoStyleSet::PreTraverseSync() {
325 // Get the Document's root element to ensure that the cache is valid before
326 // calling into the (potentially-parallel) Servo traversal, where a cache hit
327 // is necessary to avoid a data race when updating the cache.
328 Unused << mDocument->GetRootElement();
330 // FIXME(emilio): These two shouldn't be needed in theory, the call to the
331 // same function in PresShell should do the work, but as it turns out we
332 // ProcessPendingRestyles() twice, and runnables from frames just constructed
333 // can end up doing editing stuff, which adds stylesheets etc...
334 mDocument->FlushUserFontSet();
335 UpdateStylistIfNeeded();
337 mDocument->ResolveScheduledPresAttrs();
339 LookAndFeel::NativeInit();
341 mDocument->CacheAllKnownLangPrefs();
343 if (gfxUserFontSet* userFontSet = mDocument->GetUserFontSet()) {
344 nsPresContext* presContext = GetPresContext();
345 MOZ_ASSERT(presContext,
346 "For now, we don't call into here without a pres context");
348 // Ensure that the @font-face data is not stale
349 uint64_t generation = userFontSet->GetGeneration();
350 if (generation != mUserFontSetUpdateGeneration) {
351 mDocument->GetFonts()->CacheFontLoadability();
352 presContext->UpdateFontCacheUserFonts(userFontSet);
353 mUserFontSetUpdateGeneration = generation;
357 MOZ_ASSERT(!StylistNeedsUpdate());
360 void ServoStyleSet::PreTraverse(ServoTraversalFlags aFlags, Element* aRoot) {
361 PreTraverseSync();
363 // Process animation stuff that we should avoid doing during the parallel
364 // traversal.
365 SMILAnimationController* smilController =
366 mDocument->HasAnimationController() ? mDocument->GetAnimationController()
367 : nullptr;
369 MOZ_ASSERT(GetPresContext());
370 if (aRoot) {
371 GetPresContext()->EffectCompositor()->PreTraverseInSubtree(aFlags, aRoot);
372 if (smilController) {
373 smilController->PreTraverseInSubtree(aRoot);
375 } else {
376 GetPresContext()->EffectCompositor()->PreTraverse(aFlags);
377 if (smilController) {
378 smilController->PreTraverse();
383 static inline already_AddRefed<ComputedStyle>
384 ResolveStyleForTextOrFirstLetterContinuation(
385 const StylePerDocumentStyleData* aRawData, ComputedStyle& aParent,
386 PseudoStyleType aType) {
387 MOZ_ASSERT(aType == PseudoStyleType::mozText ||
388 aType == PseudoStyleType::firstLetterContinuation);
389 auto inheritTarget = aType == PseudoStyleType::mozText
390 ? InheritTarget::Text
391 : InheritTarget::FirstLetterContinuation;
393 RefPtr<ComputedStyle> style = aParent.GetCachedInheritingAnonBoxStyle(aType);
394 if (!style) {
395 style =
396 Servo_ComputedValues_Inherit(aRawData, aType, &aParent, inheritTarget)
397 .Consume();
398 MOZ_ASSERT(style);
399 aParent.SetCachedInheritedAnonBoxStyle(style);
402 return style.forget();
405 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleForText(
406 nsIContent* aTextNode, ComputedStyle* aParentStyle) {
407 MOZ_ASSERT(aTextNode && aTextNode->IsText());
408 MOZ_ASSERT(aTextNode->GetParent());
409 MOZ_ASSERT(aParentStyle);
411 return ResolveStyleForTextOrFirstLetterContinuation(
412 mRawData.get(), *aParentStyle, PseudoStyleType::mozText);
415 already_AddRefed<ComputedStyle>
416 ServoStyleSet::ResolveStyleForFirstLetterContinuation(
417 ComputedStyle* aParentStyle) {
418 MOZ_ASSERT(aParentStyle);
420 return ResolveStyleForTextOrFirstLetterContinuation(
421 mRawData.get(), *aParentStyle, PseudoStyleType::firstLetterContinuation);
424 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleForPlaceholder() {
425 RefPtr<ComputedStyle>& cache = mNonInheritingComputedStyles
426 [nsCSSAnonBoxes::NonInheriting::oofPlaceholder];
427 if (cache) {
428 RefPtr<ComputedStyle> retval = cache;
429 return retval.forget();
432 RefPtr<ComputedStyle> computedValues =
433 Servo_ComputedValues_Inherit(mRawData.get(),
434 PseudoStyleType::oofPlaceholder, nullptr,
435 InheritTarget::PlaceholderFrame)
436 .Consume();
437 MOZ_ASSERT(computedValues);
439 cache = computedValues;
440 return computedValues.forget();
443 static inline bool LazyPseudoIsCacheable(PseudoStyleType aType,
444 const Element& aOriginatingElement,
445 ComputedStyle* aParentStyle) {
446 return aParentStyle &&
447 !nsCSSPseudoElements::IsEagerlyCascadedInServo(aType) &&
448 aOriginatingElement.HasServoData() &&
449 !Servo_Element_IsPrimaryStyleReusedViaRuleNode(&aOriginatingElement);
452 already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePseudoElementStyle(
453 const Element& aOriginatingElement, PseudoStyleType aType,
454 nsAtom* aFunctionalPseudoParameter, ComputedStyle* aParentStyle,
455 IsProbe aIsProbe) {
456 // Runs from frame construction, this should have clean styles already, except
457 // with non-lazy FC...
458 UpdateStylistIfNeeded();
459 MOZ_ASSERT(PseudoStyle::IsPseudoElement(aType));
461 // caching is done using `aType` only, therefore results would be wrong for
462 // pseudos with functional parameters (e.g. `::highlight(foo)`).
463 const bool cacheable =
464 !aFunctionalPseudoParameter &&
465 LazyPseudoIsCacheable(aType, aOriginatingElement, aParentStyle);
466 RefPtr<ComputedStyle> style =
467 cacheable ? aParentStyle->GetCachedLazyPseudoStyle(aType) : nullptr;
469 const bool isProbe = aIsProbe == IsProbe::Yes;
471 if (!style) {
472 // FIXME(emilio): Why passing null for probing as the parent style?
474 // There are callers which do pass the wrong parent style and it would
475 // assert (like ComputeSelectionStyle()). That's messy!
476 style = Servo_ResolvePseudoStyle(
477 &aOriginatingElement, aType, aFunctionalPseudoParameter,
478 isProbe, isProbe ? nullptr : aParentStyle, mRawData.get())
479 .Consume();
480 if (!style) {
481 MOZ_ASSERT(isProbe);
482 return nullptr;
484 if (cacheable) {
485 aParentStyle->SetCachedLazyPseudoStyle(style);
489 MOZ_ASSERT(style);
491 if (isProbe && !GeneratedContentPseudoExists(*aParentStyle, *style)) {
492 return nullptr;
495 return style.forget();
498 already_AddRefed<ComputedStyle>
499 ServoStyleSet::ResolveInheritingAnonymousBoxStyle(PseudoStyleType aType,
500 ComputedStyle* aParentStyle) {
501 MOZ_ASSERT(PseudoStyle::IsInheritingAnonBox(aType));
502 MOZ_ASSERT_IF(aParentStyle, !StylistNeedsUpdate());
504 UpdateStylistIfNeeded();
506 RefPtr<ComputedStyle> style = nullptr;
508 if (aParentStyle) {
509 style = aParentStyle->GetCachedInheritingAnonBoxStyle(aType);
512 if (!style) {
513 style = Servo_ComputedValues_GetForAnonymousBox(aParentStyle, aType,
514 mRawData.get())
515 .Consume();
516 MOZ_ASSERT(style);
517 if (aParentStyle) {
518 aParentStyle->SetCachedInheritedAnonBoxStyle(style);
522 return style.forget();
525 already_AddRefed<ComputedStyle>
526 ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType aType) {
527 MOZ_ASSERT(aType != PseudoStyleType::pageContent,
528 "Use ResolvePageContentStyle for page content");
529 MOZ_ASSERT(PseudoStyle::IsNonInheritingAnonBox(aType));
531 nsCSSAnonBoxes::NonInheriting type =
532 nsCSSAnonBoxes::NonInheritingTypeForPseudoType(aType);
533 RefPtr<ComputedStyle>& cache = mNonInheritingComputedStyles[type];
534 if (cache) {
535 RefPtr<ComputedStyle> retval = cache;
536 return retval.forget();
539 UpdateStylistIfNeeded();
541 // We always want to skip parent-based display fixup here. It never makes
542 // sense for non-inheriting anonymous boxes. (Static assertions in
543 // nsCSSAnonBoxes.cpp ensure that all non-inheriting non-anonymous boxes
544 // are indeed annotated as skipping this fixup.)
545 MOZ_ASSERT(!PseudoStyle::IsNonInheritingAnonBox(PseudoStyleType::viewport),
546 "viewport needs fixup to handle blockifying it");
548 RefPtr<ComputedStyle> computedValues =
549 Servo_ComputedValues_GetForAnonymousBox(nullptr, aType, mRawData.get())
550 .Consume();
551 MOZ_ASSERT(computedValues);
553 cache = computedValues;
554 return computedValues.forget();
557 already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePageContentStyle(
558 const nsAtom* aPageName, const StylePagePseudoClassFlags& aPseudo) {
559 // The empty atom is used to indicate no specified page name, and is not
560 // usable as a page-rule selector. Changing this to null is a slight
561 // optimization to avoid the Servo code from doing an unnecessary hashtable
562 // lookup, and still use the style cache in this case.
563 if (aPageName == nsGkAtoms::_empty) {
564 aPageName = nullptr;
566 // Only use the cache when we are doing a lookup for page styles without a
567 // page-name or any pseudo classes.
568 const bool useCache = !aPageName && !aPseudo;
569 RefPtr<ComputedStyle>& cache =
570 mNonInheritingComputedStyles[nsCSSAnonBoxes::NonInheriting::pageContent];
571 if (useCache && cache) {
572 RefPtr<ComputedStyle> retval = cache;
573 return retval.forget();
576 UpdateStylistIfNeeded();
578 RefPtr<ComputedStyle> computedValues =
579 Servo_ComputedValues_GetForPageContent(mRawData.get(), aPageName, aPseudo)
580 .Consume();
581 MOZ_ASSERT(computedValues);
583 if (useCache) {
584 cache = computedValues;
586 return computedValues.forget();
589 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveXULTreePseudoStyle(
590 dom::Element* aParentElement, nsCSSAnonBoxPseudoStaticAtom* aPseudoTag,
591 ComputedStyle* aParentStyle, const AtomArray& aInputWord) {
592 MOZ_ASSERT(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag));
593 MOZ_ASSERT(aParentStyle);
594 NS_ASSERTION(!StylistNeedsUpdate(),
595 "Stylesheets modified when resolving XUL tree pseudo");
597 return Servo_ComputedValues_ResolveXULTreePseudoStyle(
598 aParentElement, aPseudoTag, aParentStyle, &aInputWord,
599 mRawData.get())
600 .Consume();
603 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStartingStyle(
604 dom::Element& aElement) {
605 nsPresContext* pc = GetPresContext();
606 if (!pc) {
607 return nullptr;
610 return Servo_ResolveStartingStyle(
611 &aElement, &pc->RestyleManager()->Snapshots(), mRawData.get())
612 .Consume();
615 // manage the set of style sheets in the style set
616 void ServoStyleSet::AppendStyleSheet(StyleSheet& aSheet) {
617 MOZ_ASSERT(aSheet.IsApplicable());
618 MOZ_ASSERT(aSheet.RawContents(),
619 "Raw sheet should be in place before insertion.");
621 aSheet.AddStyleSet(this);
623 // Maintain a mirrored list of sheets on the servo side.
624 // Servo will remove aSheet from its original position as part of the call
625 // to Servo_StyleSet_AppendStyleSheet.
626 Servo_StyleSet_AppendStyleSheet(mRawData.get(), &aSheet);
627 SetStylistStyleSheetsDirty();
629 if (mStyleRuleMap) {
630 mStyleRuleMap->SheetAdded(aSheet);
634 void ServoStyleSet::RemoveStyleSheet(StyleSheet& aSheet) {
635 aSheet.DropStyleSet(this);
637 // Maintain a mirrored list of sheets on the servo side.
638 Servo_StyleSet_RemoveStyleSheet(mRawData.get(), &aSheet);
639 SetStylistStyleSheetsDirty();
641 if (mStyleRuleMap) {
642 mStyleRuleMap->SheetRemoved(aSheet);
646 void ServoStyleSet::InsertStyleSheetBefore(StyleSheet& aNewSheet,
647 StyleSheet& aReferenceSheet) {
648 MOZ_ASSERT(aNewSheet.IsApplicable());
649 MOZ_ASSERT(aReferenceSheet.IsApplicable());
650 MOZ_ASSERT(&aNewSheet != &aReferenceSheet,
651 "Can't place sheet before itself.");
652 MOZ_ASSERT(aNewSheet.GetOrigin() == aReferenceSheet.GetOrigin(),
653 "Sheets should be in the same origin");
654 MOZ_ASSERT(aNewSheet.RawContents(),
655 "Raw sheet should be in place before insertion.");
656 MOZ_ASSERT(aReferenceSheet.RawContents(),
657 "Reference sheet should have a raw sheet.");
659 // Servo will remove aNewSheet from its original position as part of the
660 // call to Servo_StyleSet_InsertStyleSheetBefore.
661 aNewSheet.AddStyleSet(this);
663 // Maintain a mirrored list of sheets on the servo side.
664 Servo_StyleSet_InsertStyleSheetBefore(mRawData.get(), &aNewSheet,
665 &aReferenceSheet);
666 SetStylistStyleSheetsDirty();
668 if (mStyleRuleMap) {
669 mStyleRuleMap->SheetAdded(aNewSheet);
673 size_t ServoStyleSet::SheetCount(Origin aOrigin) const {
674 return Servo_StyleSet_GetSheetCount(mRawData.get(), aOrigin);
677 StyleSheet* ServoStyleSet::SheetAt(Origin aOrigin, size_t aIndex) const {
678 return const_cast<StyleSheet*>(
679 Servo_StyleSet_GetSheetAt(mRawData.get(), aOrigin, aIndex));
682 ServoStyleSet::PageSizeAndOrientation
683 ServoStyleSet::GetDefaultPageSizeAndOrientation() {
684 PageSizeAndOrientation retval;
685 const RefPtr<ComputedStyle> style =
686 ResolvePageContentStyle(nullptr, StylePagePseudoClassFlags::NONE);
687 const StylePageSize& pageSize = style->StylePage()->mSize;
689 if (pageSize.IsSize()) {
690 const nscoord w = pageSize.AsSize().width.ToAppUnits();
691 const nscoord h = pageSize.AsSize().height.ToAppUnits();
692 // Ignoring sizes that include a zero width or height.
693 // These are also ignored in nsPageFrame::ComputePageSize()
694 // when calculating the scaling for a page size.
695 // In bug 1807985, we might add similar handling for @page margin/size
696 // combinations that produce a zero-sized page-content box.
697 if (w > 0 && h > 0) {
698 retval.size.emplace(w, h);
699 if (w > h) {
700 retval.orientation.emplace(StylePageSizeOrientation::Landscape);
701 } else if (w < h) {
702 retval.orientation.emplace(StylePageSizeOrientation::Portrait);
705 } else if (pageSize.IsOrientation()) {
706 retval.orientation.emplace(pageSize.AsOrientation());
707 } else {
708 MOZ_ASSERT(pageSize.IsAuto(), "Impossible page size");
710 return retval;
713 void ServoStyleSet::AppendAllNonDocumentAuthorSheets(
714 nsTArray<StyleSheet*>& aArray) const {
715 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
716 for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
717 aArray.AppendElement(aShadowRoot.SheetAt(index));
719 aArray.AppendElements(aShadowRoot.AdoptedStyleSheets());
723 void ServoStyleSet::AddDocStyleSheet(StyleSheet& aSheet) {
724 MOZ_ASSERT(aSheet.IsApplicable());
725 MOZ_ASSERT(aSheet.RawContents(),
726 "Raw sheet should be in place by this point.");
728 size_t index = mDocument->FindDocStyleSheetInsertionPoint(aSheet);
729 aSheet.AddStyleSet(this);
731 if (index < SheetCount(Origin::Author)) {
732 // This case is insert before.
733 StyleSheet* beforeSheet = SheetAt(Origin::Author, index);
735 // Maintain a mirrored list of sheets on the servo side.
736 Servo_StyleSet_InsertStyleSheetBefore(mRawData.get(), &aSheet, beforeSheet);
737 SetStylistStyleSheetsDirty();
738 } else {
739 // Maintain a mirrored list of sheets on the servo side.
740 Servo_StyleSet_AppendStyleSheet(mRawData.get(), &aSheet);
741 SetStylistStyleSheetsDirty();
744 if (mStyleRuleMap) {
745 mStyleRuleMap->SheetAdded(aSheet);
749 bool ServoStyleSet::GeneratedContentPseudoExists(
750 const ComputedStyle& aParentStyle, const ComputedStyle& aPseudoStyle) {
751 auto type = aPseudoStyle.GetPseudoType();
752 MOZ_ASSERT(type != PseudoStyleType::NotPseudo);
754 if (type == PseudoStyleType::marker) {
755 // ::marker only exist for list items (for now).
756 if (!aParentStyle.StyleDisplay()->IsListItem()) {
757 return false;
759 const auto& content = aPseudoStyle.StyleContent()->mContent;
760 // ::marker does not exist if 'content' is 'none' (this trumps
761 // any 'list-style-type' or 'list-style-image' values).
762 if (content.IsNone()) {
763 return false;
765 // ::marker only exist if we have 'content' or at least one of
766 // 'list-style-type' or 'list-style-image'.
767 if (aPseudoStyle.StyleList()->mListStyleType.IsNone() &&
768 aPseudoStyle.StyleList()->mListStyleImage.IsNone() &&
769 content.IsNormal()) {
770 return false;
772 // display:none is equivalent to not having a pseudo at all.
773 if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) {
774 return false;
778 // For ::before and ::after pseudo-elements, no 'content' items is
779 // equivalent to not having the pseudo-element at all.
780 if (type == PseudoStyleType::before || type == PseudoStyleType::after) {
781 if (!aPseudoStyle.StyleContent()->mContent.IsItems()) {
782 return false;
784 MOZ_ASSERT(!aPseudoStyle.StyleContent()->NonAltContentItems().IsEmpty(),
785 "IsItems() implies we have at least one item");
786 // display:none is equivalent to not having a pseudo at all.
787 if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) {
788 return false;
792 return true;
795 bool ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags) {
796 AUTO_PROFILER_LABEL_CATEGORY_PAIR_RELEVANT_FOR_JS(LAYOUT_StyleComputation);
797 MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
799 if (!mDocument->GetServoRestyleRoot()) {
800 return false;
803 Element* rootElement = mDocument->GetRootElement();
804 if (rootElement && MOZ_UNLIKELY(!rootElement->HasServoData())) {
805 StyleNewSubtree(rootElement);
806 return true;
809 PreTraverse(aFlags);
810 AutoPrepareTraversal guard(this);
811 const SnapshotTable& snapshots = Snapshots();
813 // Restyle the document from the root element and each of the document level
814 // NAC subtree roots.
815 bool postTraversalRequired = false;
817 if (ShouldTraverseInParallel()) {
818 aFlags |= ServoTraversalFlags::ParallelTraversal;
821 // Do the first traversal.
822 DocumentStyleRootIterator iter(mDocument->GetServoRestyleRoot());
823 while (Element* root = iter.GetNextStyleRoot()) {
824 MOZ_ASSERT(MayTraverseFrom(root));
826 Element* parent = root->GetFlattenedTreeParentElementForStyle();
827 MOZ_ASSERT_IF(parent,
828 !parent->HasAnyOfFlags(Element::kAllServoDescendantBits));
830 postTraversalRequired |=
831 Servo_TraverseSubtree(root, mRawData.get(), &snapshots, aFlags) ||
832 root->HasAnyOfFlags(Element::kAllServoDescendantBits |
833 NODE_NEEDS_FRAME);
836 uint32_t existingBits = mDocument->GetServoRestyleRootDirtyBits();
837 Element* newRoot = nullptr;
838 while (parent && parent->HasDirtyDescendantsForServo()) {
839 MOZ_ASSERT(root == mDocument->GetServoRestyleRoot(),
840 "Restyle root shouldn't have magically changed");
841 // If any style invalidation was triggered in our siblings, then we may
842 // need to post-traverse them, even if the root wasn't restyled after
843 // all.
844 // We need to propagate the existing bits to the ancestor.
845 parent->SetFlags(existingBits);
846 newRoot = parent;
847 parent = parent->GetFlattenedTreeParentElementForStyle();
850 if (newRoot) {
851 mDocument->SetServoRestyleRoot(
852 newRoot, existingBits | ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
853 postTraversalRequired = true;
858 // If there are still animation restyles needed, trigger a second traversal to
859 // update CSS animations or transitions' styles.
861 // Note that we need to check the style root again, because doing another
862 // PreTraverse on the EffectCompositor might alter the style root. But we
863 // don't need to worry about NAC, since document-level NAC shouldn't have
864 // animations.
866 // We don't need to do this for SMIL since SMIL only updates its animation
867 // values once at the begin of a tick. As a result, even if the previous
868 // traversal caused, for example, the font-size to change, the SMIL style
869 // won't be updated until the next tick anyway.
870 if (GetPresContext()->EffectCompositor()->PreTraverse(aFlags)) {
871 DocumentStyleRootIterator iter(mDocument->GetServoRestyleRoot());
872 while (Element* root = iter.GetNextStyleRoot()) {
873 postTraversalRequired |=
874 Servo_TraverseSubtree(root, mRawData.get(), &snapshots, aFlags) ||
875 root->HasAnyOfFlags(Element::kAllServoDescendantBits |
876 NODE_NEEDS_FRAME);
880 return postTraversalRequired;
883 void ServoStyleSet::StyleNewSubtree(Element* aRoot) {
884 MOZ_ASSERT(GetPresContext());
885 MOZ_ASSERT(!aRoot->HasServoData());
886 MOZ_ASSERT(aRoot->GetFlattenedTreeParentNodeForStyle(),
887 "Not in the flat tree? Fishy!");
888 PreTraverseSync();
889 AutoPrepareTraversal guard(this);
891 // Do the traversal. The snapshots will not be used.
892 const SnapshotTable& snapshots = Snapshots();
893 auto flags = ServoTraversalFlags::Empty;
894 if (ShouldTraverseInParallel()) {
895 flags |= ServoTraversalFlags::ParallelTraversal;
898 DebugOnly<bool> postTraversalRequired =
899 Servo_TraverseSubtree(aRoot, mRawData.get(), &snapshots, flags);
900 MOZ_ASSERT(!postTraversalRequired);
902 // Annoyingly, the newly-styled content may have animations that need
903 // starting, which requires traversing them again. Mark the elements
904 // that need animation processing, then do a forgetful traversal to
905 // update the styles and clear the animation bits.
906 if (GetPresContext()->EffectCompositor()->PreTraverseInSubtree(flags,
907 aRoot)) {
908 postTraversalRequired =
909 Servo_TraverseSubtree(aRoot, mRawData.get(), &snapshots,
910 ServoTraversalFlags::AnimationOnly |
911 ServoTraversalFlags::FinalAnimationTraversal);
912 MOZ_ASSERT(!postTraversalRequired);
916 void ServoStyleSet::MarkOriginsDirty(OriginFlags aChangedOrigins) {
917 SetStylistStyleSheetsDirty();
918 Servo_StyleSet_NoteStyleSheetsChanged(mRawData.get(), aChangedOrigins);
921 void ServoStyleSet::SetStylistStyleSheetsDirty() {
922 mStylistState |= StylistState::StyleSheetsDirty;
924 // We need to invalidate cached style in getComputedStyle for undisplayed
925 // elements, since we don't know if any of the style sheet change that we do
926 // would affect undisplayed elements.
928 // We don't allow to call getComputedStyle in elements without a pres shell
929 // yet, so it is fine if there's no pres context here.
930 if (nsPresContext* presContext = GetPresContext()) {
931 presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration();
935 void ServoStyleSet::SetStylistShadowDOMStyleSheetsDirty() {
936 mStylistState |= StylistState::ShadowDOMStyleSheetsDirty;
937 if (nsPresContext* presContext = GetPresContext()) {
938 presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration();
942 static OriginFlags ToOriginFlags(StyleOrigin aOrigin) {
943 switch (aOrigin) {
944 case StyleOrigin::UserAgent:
945 return OriginFlags::UserAgent;
946 case StyleOrigin::User:
947 return OriginFlags::User;
948 default:
949 MOZ_FALLTHROUGH_ASSERT("Unknown origin?");
950 case StyleOrigin::Author:
951 return OriginFlags::Author;
955 void ServoStyleSet::ImportRuleLoaded(StyleSheet& aSheet) {
956 if (mStyleRuleMap) {
957 mStyleRuleMap->SheetAdded(aSheet);
960 // TODO: Should probably consider ancestor sheets too.
961 if (!aSheet.IsApplicable()) {
962 return;
965 // TODO(emilio): Could handle it better given we know it is an insertion, and
966 // use the style invalidation machinery stuff that we do for regular sheet
967 // insertions.
968 MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
971 void ServoStyleSet::RuleAdded(StyleSheet& aSheet, css::Rule& aRule) {
972 if (mStyleRuleMap) {
973 mStyleRuleMap->RuleAdded(aSheet, aRule);
976 if (!aSheet.IsApplicable() || aRule.IsIncompleteImportRule()) {
977 return;
980 RuleChangedInternal(aSheet, aRule, StyleRuleChangeKind::Insertion);
983 void ServoStyleSet::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule) {
984 if (mStyleRuleMap) {
985 mStyleRuleMap->RuleRemoved(aSheet, aRule);
988 if (!aSheet.IsApplicable()) {
989 return;
992 RuleChangedInternal(aSheet, aRule, StyleRuleChangeKind::Removal);
995 void ServoStyleSet::RuleChangedInternal(StyleSheet& aSheet, css::Rule& aRule,
996 StyleRuleChangeKind aKind) {
997 MOZ_ASSERT(aSheet.IsApplicable());
998 SetStylistStyleSheetsDirty();
1000 #define CASE_FOR(constant_, type_) \
1001 case StyleCssRuleType::constant_: \
1002 return Servo_StyleSet_##constant_##RuleChanged( \
1003 mRawData.get(), static_cast<dom::CSS##type_##Rule&>(aRule).Raw(), \
1004 &aSheet, aKind);
1005 switch (aRule.Type()) {
1006 CASE_FOR(CounterStyle, CounterStyle)
1007 CASE_FOR(Style, Style)
1008 CASE_FOR(Import, Import)
1009 CASE_FOR(Media, Media)
1010 CASE_FOR(Keyframes, Keyframes)
1011 CASE_FOR(Margin, Margin)
1012 CASE_FOR(FontFeatureValues, FontFeatureValues)
1013 CASE_FOR(FontPaletteValues, FontPaletteValues)
1014 CASE_FOR(FontFace, FontFace)
1015 CASE_FOR(Page, Page)
1016 CASE_FOR(Property, Property)
1017 CASE_FOR(Document, MozDocument)
1018 CASE_FOR(Supports, Supports)
1019 CASE_FOR(LayerBlock, LayerBlock)
1020 CASE_FOR(LayerStatement, LayerStatement)
1021 CASE_FOR(Container, Container)
1022 CASE_FOR(Scope, Scope)
1023 CASE_FOR(StartingStyle, StartingStyle)
1024 CASE_FOR(PositionTry, PositionTry)
1025 CASE_FOR(NestedDeclarations, NestedDeclarations)
1026 // @namespace can only be inserted / removed when there are only other
1027 // @namespace and @import rules, and can't be mutated.
1028 case StyleCssRuleType::Namespace:
1029 break;
1030 case StyleCssRuleType::Keyframe:
1031 // FIXME: We should probably just forward to the parent @keyframes rule? I
1032 // think that'd do the right thing, but meanwhile...
1033 return MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
1036 #undef CASE_FOR
1039 void ServoStyleSet::RuleChanged(StyleSheet& aSheet, css::Rule* aRule,
1040 StyleRuleChangeKind aKind) {
1041 if (!aSheet.IsApplicable()) {
1042 return;
1045 if (!aRule) {
1046 // FIXME: This is done for StyleSheet.media attribute changes and such
1047 MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
1048 } else {
1049 RuleChangedInternal(aSheet, *aRule, aKind);
1053 void ServoStyleSet::SheetCloned(StyleSheet& aSheet) {
1054 mNeedsRestyleAfterEnsureUniqueInner = true;
1055 if (mStyleRuleMap) {
1056 mStyleRuleMap->SheetCloned(aSheet);
1060 #ifdef DEBUG
1061 void ServoStyleSet::AssertTreeIsClean() {
1062 DocumentStyleRootIterator iter(mDocument);
1063 while (Element* root = iter.GetNextStyleRoot()) {
1064 Servo_AssertTreeIsClean(root);
1067 #endif
1069 bool ServoStyleSet::GetKeyframesForName(
1070 const Element& aElement, const ComputedStyle& aStyle, nsAtom* aName,
1071 const StyleComputedTimingFunction& aTimingFunction,
1072 nsTArray<Keyframe>& aKeyframes) {
1073 MOZ_ASSERT(!StylistNeedsUpdate());
1074 return Servo_StyleSet_GetKeyframesForName(
1075 mRawData.get(), &aElement, &aStyle, aName, &aTimingFunction, &aKeyframes);
1078 nsTArray<ComputedKeyframeValues> ServoStyleSet::GetComputedKeyframeValuesFor(
1079 const nsTArray<Keyframe>& aKeyframes, Element* aElement,
1080 PseudoStyleType aPseudoType, const ComputedStyle* aStyle) {
1081 nsTArray<ComputedKeyframeValues> result(aKeyframes.Length());
1083 // Construct each nsTArray<PropertyStyleAnimationValuePair> here.
1084 result.AppendElements(aKeyframes.Length());
1086 Servo_GetComputedKeyframeValues(&aKeyframes, aElement, aPseudoType, aStyle,
1087 mRawData.get(), &result);
1088 return result;
1091 void ServoStyleSet::GetAnimationValues(
1092 StyleLockedDeclarationBlock* aDeclarations, Element* aElement,
1093 const ComputedStyle* aComputedStyle,
1094 nsTArray<RefPtr<StyleAnimationValue>>& aAnimationValues) {
1095 // Servo_GetAnimationValues below won't handle ignoring existing element
1096 // data for bfcached documents. (See comment in ResolveStyleLazily
1097 // about these bfcache issues.)
1098 Servo_GetAnimationValues(aDeclarations, aElement, aComputedStyle,
1099 mRawData.get(), &aAnimationValues);
1102 already_AddRefed<ComputedStyle> ServoStyleSet::GetBaseContextForElement(
1103 Element* aElement, const ComputedStyle* aStyle) {
1104 return Servo_StyleSet_GetBaseComputedValuesForElement(
1105 mRawData.get(), aElement, aStyle, &Snapshots())
1106 .Consume();
1109 already_AddRefed<StyleAnimationValue> ServoStyleSet::ComputeAnimationValue(
1110 Element* aElement, StyleLockedDeclarationBlock* aDeclarations,
1111 const ComputedStyle* aStyle) {
1112 return Servo_AnimationValue_Compute(aElement, aDeclarations, aStyle,
1113 mRawData.get())
1114 .Consume();
1117 bool ServoStyleSet::UsesFontMetrics() const {
1118 return Servo_StyleSet_UsesFontMetrics(mRawData.get());
1121 bool ServoStyleSet::EnsureUniqueInnerOnCSSSheets() {
1122 using SheetOwner = Variant<ServoStyleSet*, ShadowRoot*>;
1124 AutoTArray<std::pair<StyleSheet*, SheetOwner>, 32> queue;
1125 EnumerateStyleSheets([&](StyleSheet& aSheet) {
1126 queue.AppendElement(std::make_pair(&aSheet, SheetOwner{this}));
1129 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
1130 for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
1131 queue.AppendElement(
1132 std::make_pair(aShadowRoot.SheetAt(index), SheetOwner{&aShadowRoot}));
1134 for (const auto& adopted : aShadowRoot.AdoptedStyleSheets()) {
1135 queue.AppendElement(
1136 std::make_pair(adopted.get(), SheetOwner{&aShadowRoot}));
1140 while (!queue.IsEmpty()) {
1141 auto [sheet, owner] = queue.PopLastElement();
1143 if (sheet->HasForcedUniqueInner()) {
1144 // We already processed this sheet and its children.
1145 // Normally we don't hit this but adopted stylesheets can have dupes so we
1146 // can save some work here.
1147 continue;
1150 // Only call EnsureUniqueInner for complete sheets. If we do call it on
1151 // incomplete sheets, we'll cause problems when the sheet is actually
1152 // loaded. We don't care about incomplete sheets here anyway, because this
1153 // method is only invoked by nsPresContext::EnsureSafeToHandOutCSSRules.
1154 // The CSSRule objects we are handing out won't contain any rules derived
1155 // from incomplete sheets (because they aren't yet applied in styling).
1156 if (sheet->IsComplete()) {
1157 sheet->EnsureUniqueInner();
1160 // Enqueue all the sheet's children.
1161 for (StyleSheet* child : sheet->ChildSheets()) {
1162 queue.AppendElement(std::make_pair(child, owner));
1166 if (mNeedsRestyleAfterEnsureUniqueInner) {
1167 // TODO(emilio): We could make this faster if needed tracking the specific
1168 // origins and sheets that have been cloned. But the only caller of this
1169 // doesn't seem to really care about perf.
1170 MarkOriginsDirty(OriginFlags::All);
1171 ForceDirtyAllShadowStyles();
1173 bool res = mNeedsRestyleAfterEnsureUniqueInner;
1174 mNeedsRestyleAfterEnsureUniqueInner = false;
1175 return res;
1178 void ServoStyleSet::ClearCachedStyleData() {
1179 ClearNonInheritingComputedStyles();
1180 Servo_StyleSet_RebuildCachedData(mRawData.get());
1181 mCachedAnonymousContentStyles.Clear();
1182 PodArrayZero(mCachedAnonymousContentStyleIndexes);
1185 void ServoStyleSet::ForceDirtyAllShadowStyles() {
1186 bool anyShadow = false;
1187 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
1188 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
1189 anyShadow = true;
1190 Servo_AuthorStyles_ForceDirty(authorStyles);
1193 if (anyShadow) {
1194 SetStylistShadowDOMStyleSheetsDirty();
1198 void ServoStyleSet::CompatibilityModeChanged() {
1199 Servo_StyleSet_CompatModeChanged(mRawData.get());
1200 SetStylistStyleSheetsDirty();
1201 ForceDirtyAllShadowStyles();
1204 void ServoStyleSet::ClearNonInheritingComputedStyles() {
1205 for (RefPtr<ComputedStyle>& ptr : mNonInheritingComputedStyles) {
1206 ptr = nullptr;
1210 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleLazily(
1211 const Element& aElement, PseudoStyleType aPseudoType,
1212 nsAtom* aFunctionalPseudoParameter, StyleRuleInclusion aRuleInclusion) {
1213 PreTraverseSync();
1214 MOZ_ASSERT(!StylistNeedsUpdate());
1216 AutoSetInServoTraversal guard(this);
1219 * NB: This is needed because we process animations and transitions on the
1220 * pseudo-elements themselves, not on the parent's EagerPseudoStyles.
1222 * That means that that style doesn't account for animations, and we can't do
1223 * that easily from the traversal without doing wasted work.
1225 * As such, we just lie here a bit, which is the entrypoint of
1226 * getComputedStyle, the only API where this can be observed, to look at the
1227 * style of the pseudo-element if it exists instead.
1229 const Element* elementForStyleResolution = &aElement;
1230 PseudoStyleType pseudoTypeForStyleResolution = aPseudoType;
1231 if (aPseudoType == PseudoStyleType::before) {
1232 if (Element* pseudo = nsLayoutUtils::GetBeforePseudo(&aElement)) {
1233 elementForStyleResolution = pseudo;
1234 pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
1236 } else if (aPseudoType == PseudoStyleType::after) {
1237 if (Element* pseudo = nsLayoutUtils::GetAfterPseudo(&aElement)) {
1238 elementForStyleResolution = pseudo;
1239 pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
1241 } else if (aPseudoType == PseudoStyleType::marker) {
1242 if (Element* pseudo = nsLayoutUtils::GetMarkerPseudo(&aElement)) {
1243 elementForStyleResolution = pseudo;
1244 pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
1248 nsPresContext* pc = GetPresContext();
1249 MOZ_ASSERT(pc, "For now, no style resolution without a pres context");
1250 auto* restyleManager = pc->RestyleManager();
1251 const bool canUseCache = aRuleInclusion == StyleRuleInclusion::All &&
1252 aElement.OwnerDoc() == mDocument &&
1253 pc->PresShell()->DidInitialize();
1254 return Servo_ResolveStyleLazily(
1255 elementForStyleResolution, pseudoTypeForStyleResolution,
1256 aFunctionalPseudoParameter, aRuleInclusion,
1257 &restyleManager->Snapshots(),
1258 restyleManager->GetUndisplayedRestyleGeneration(), canUseCache,
1259 mRawData.get())
1260 .Consume();
1263 void ServoStyleSet::AppendFontFaceRules(
1264 nsTArray<nsFontFaceRuleContainer>& aArray) {
1265 // TODO(emilio): Can we make this so this asserts instead?
1266 UpdateStylistIfNeeded();
1267 Servo_StyleSet_GetFontFaceRules(mRawData.get(), &aArray);
1270 const StyleLockedCounterStyleRule* ServoStyleSet::CounterStyleRuleForName(
1271 nsAtom* aName) {
1272 MOZ_ASSERT(!StylistNeedsUpdate());
1273 return Servo_StyleSet_GetCounterStyleRule(mRawData.get(), aName);
1276 already_AddRefed<gfxFontFeatureValueSet>
1277 ServoStyleSet::BuildFontFeatureValueSet() {
1278 MOZ_ASSERT(!StylistNeedsUpdate());
1279 RefPtr<gfxFontFeatureValueSet> set =
1280 Servo_StyleSet_BuildFontFeatureValueSet(mRawData.get());
1281 return set.forget();
1284 already_AddRefed<gfx::FontPaletteValueSet>
1285 ServoStyleSet::BuildFontPaletteValueSet() {
1286 MOZ_ASSERT(!StylistNeedsUpdate());
1287 RefPtr<gfx::FontPaletteValueSet> set =
1288 Servo_StyleSet_BuildFontPaletteValueSet(mRawData.get());
1289 return set.forget();
1292 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveForDeclarations(
1293 const ComputedStyle* aParentOrNull,
1294 const StyleLockedDeclarationBlock* aDeclarations) {
1295 // No need to update the stylist, we're only cascading aDeclarations.
1296 return Servo_StyleSet_ResolveForDeclarations(mRawData.get(), aParentOrNull,
1297 aDeclarations)
1298 .Consume();
1301 void ServoStyleSet::UpdateStylist() {
1302 AUTO_PROFILER_LABEL_RELEVANT_FOR_JS("Update stylesheet information", LAYOUT);
1303 MOZ_ASSERT(StylistNeedsUpdate());
1305 if (mStylistState & StylistState::StyleSheetsDirty) {
1306 Element* root = mDocument->GetRootElement();
1307 const ServoElementSnapshotTable* snapshots = nullptr;
1308 if (nsPresContext* pc = GetPresContext()) {
1309 snapshots = &pc->RestyleManager()->Snapshots();
1311 Servo_StyleSet_FlushStyleSheets(mRawData.get(), root, snapshots);
1314 if (MOZ_UNLIKELY(mStylistState & StylistState::ShadowDOMStyleSheetsDirty)) {
1315 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
1316 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
1317 Servo_AuthorStyles_Flush(authorStyles, mRawData.get());
1320 Servo_StyleSet_RemoveUniqueEntriesFromAuthorStylesCache(mRawData.get());
1323 mStylistState = StylistState::NotDirty;
1326 void ServoStyleSet::MaybeGCRuleTree() {
1327 MOZ_ASSERT(NS_IsMainThread());
1328 Servo_MaybeGCRuleTree(mRawData.get());
1331 /* static */
1332 bool ServoStyleSet::MayTraverseFrom(const Element* aElement) {
1333 MOZ_ASSERT(aElement->IsInComposedDoc());
1334 nsINode* parent = aElement->GetFlattenedTreeParentNodeForStyle();
1335 if (!parent) {
1336 return false;
1339 if (!parent->IsElement()) {
1340 MOZ_ASSERT(parent->IsDocument());
1341 return true;
1344 if (!parent->AsElement()->HasServoData()) {
1345 return false;
1348 return !Servo_Element_IsDisplayNone(parent->AsElement());
1351 bool ServoStyleSet::ShouldTraverseInParallel() const {
1352 MOZ_ASSERT(mDocument->GetPresShell(), "Styling a document without a shell?");
1353 if (!mDocument->GetPresShell()->IsActive()) {
1354 return false;
1356 if (profiler_feature_active(ProfilerFeature::SequentialStyle)) {
1357 return false;
1359 return true;
1362 void ServoStyleSet::RunPostTraversalTasks() {
1363 MOZ_ASSERT(!IsInServoTraversal());
1365 if (mPostTraversalTasks.IsEmpty()) {
1366 return;
1369 nsTArray<PostTraversalTask> tasks = std::move(mPostTraversalTasks);
1371 for (auto& task : tasks) {
1372 task.Run();
1376 ServoStyleRuleMap* ServoStyleSet::StyleRuleMap() {
1377 if (!mStyleRuleMap) {
1378 mStyleRuleMap = MakeUnique<ServoStyleRuleMap>();
1380 mStyleRuleMap->EnsureTable(*this);
1381 return mStyleRuleMap.get();
1384 bool ServoStyleSet::MightHaveAttributeDependency(const Element& aElement,
1385 nsAtom* aAttribute) const {
1386 return Servo_StyleSet_MightHaveAttributeDependency(mRawData.get(), &aElement,
1387 aAttribute);
1390 bool ServoStyleSet::MightHaveNthOfIDDependency(const Element& aElement,
1391 nsAtom* aOldID,
1392 nsAtom* aNewID) const {
1393 return Servo_StyleSet_MightHaveNthOfIDDependency(mRawData.get(), &aElement,
1394 aOldID, aNewID);
1397 bool ServoStyleSet::MightHaveNthOfClassDependency(const Element& aElement) {
1398 return Servo_StyleSet_MightHaveNthOfClassDependency(mRawData.get(), &aElement,
1399 &Snapshots());
1402 void ServoStyleSet::MaybeInvalidateRelativeSelectorIDDependency(
1403 const Element& aElement, nsAtom* aOldID, nsAtom* aNewID,
1404 const ServoElementSnapshotTable& aSnapshots) {
1405 Servo_StyleSet_MaybeInvalidateRelativeSelectorIDDependency(
1406 mRawData.get(), &aElement, aOldID, aNewID, &aSnapshots);
1409 void ServoStyleSet::MaybeInvalidateRelativeSelectorClassDependency(
1410 const Element& aElement, const ServoElementSnapshotTable& aSnapshots) {
1411 Servo_StyleSet_MaybeInvalidateRelativeSelectorClassDependency(
1412 mRawData.get(), &aElement, &aSnapshots);
1415 void ServoStyleSet::MaybeInvalidateRelativeSelectorCustomStateDependency(
1416 const Element& aElement, nsAtom* state,
1417 const ServoElementSnapshotTable& aSnapshots) {
1418 Servo_StyleSet_MaybeInvalidateRelativeSelectorCustomStateDependency(
1419 mRawData.get(), &aElement, state, &aSnapshots);
1422 void ServoStyleSet::MaybeInvalidateRelativeSelectorAttributeDependency(
1423 const Element& aElement, nsAtom* aAttribute,
1424 const ServoElementSnapshotTable& aSnapshots) {
1425 Servo_StyleSet_MaybeInvalidateRelativeSelectorAttributeDependency(
1426 mRawData.get(), &aElement, aAttribute, &aSnapshots);
1429 void ServoStyleSet::MaybeInvalidateRelativeSelectorStateDependency(
1430 const Element& aElement, ElementState aState,
1431 const ServoElementSnapshotTable& aSnapshots) {
1432 Servo_StyleSet_MaybeInvalidateRelativeSelectorStateDependency(
1433 mRawData.get(), &aElement, aState.GetInternalValue(), &aSnapshots);
1436 void ServoStyleSet::MaybeInvalidateRelativeSelectorForEmptyDependency(
1437 const Element& aElement) {
1438 Servo_StyleSet_MaybeInvalidateRelativeSelectorEmptyDependency(mRawData.get(),
1439 &aElement);
1442 void ServoStyleSet::MaybeInvalidateRelativeSelectorForNthEdgeDependency(
1443 const Element& aElement) {
1444 Servo_StyleSet_MaybeInvalidateRelativeSelectorNthEdgeDependency(
1445 mRawData.get(), &aElement);
1448 void ServoStyleSet::MaybeInvalidateRelativeSelectorForNthDependencyFromSibling(
1449 const Element* aFromSibling, bool aForceRestyleSiblings) {
1450 if (!aFromSibling) {
1451 return;
1453 Servo_StyleSet_MaybeInvalidateRelativeSelectorNthDependencyFromSibling(
1454 mRawData.get(), aFromSibling, aForceRestyleSiblings);
1457 void ServoStyleSet::MaybeInvalidateForElementInsertion(
1458 const Element& aElement) {
1459 Servo_StyleSet_MaybeInvalidateRelativeSelectorForInsertion(mRawData.get(),
1460 &aElement);
1463 void ServoStyleSet::MaybeInvalidateForElementAppend(
1464 const nsIContent& aFirstContent) {
1465 Servo_StyleSet_MaybeInvalidateRelativeSelectorForAppend(mRawData.get(),
1466 &aFirstContent);
1469 void ServoStyleSet::MaybeInvalidateForElementRemove(
1470 const Element& aElement, const nsIContent* aFollowingSibling) {
1471 Servo_StyleSet_MaybeInvalidateRelativeSelectorForRemoval(
1472 mRawData.get(), &aElement, aFollowingSibling);
1475 bool ServoStyleSet::MightHaveNthOfAttributeDependency(
1476 const Element& aElement, nsAtom* aAttribute) const {
1477 return Servo_StyleSet_MightHaveNthOfAttributeDependency(
1478 mRawData.get(), &aElement, aAttribute);
1481 bool ServoStyleSet::HasStateDependency(const Element& aElement,
1482 dom::ElementState aState) const {
1483 return Servo_StyleSet_HasStateDependency(mRawData.get(), &aElement,
1484 aState.GetInternalValue());
1487 bool ServoStyleSet::HasNthOfStateDependency(const Element& aElement,
1488 dom::ElementState aState) const {
1489 return Servo_StyleSet_HasNthOfStateDependency(mRawData.get(), &aElement,
1490 aState.GetInternalValue());
1493 bool ServoStyleSet::HasNthOfCustomStateDependency(const Element& aElement,
1494 nsAtom* aState) const {
1495 return Servo_StyleSet_HasNthOfCustomStateDependency(mRawData.get(), &aElement,
1496 aState);
1499 void ServoStyleSet::RestyleSiblingsForNthOf(const Element& aElement,
1500 uint32_t aFlags) const {
1501 Servo_StyleSet_RestyleSiblingsForNthOf(&aElement, aFlags);
1504 bool ServoStyleSet::HasDocumentStateDependency(
1505 dom::DocumentState aState) const {
1506 return Servo_StyleSet_HasDocumentStateDependency(mRawData.get(),
1507 aState.GetInternalValue());
1510 already_AddRefed<ComputedStyle> ServoStyleSet::ReparentComputedStyle(
1511 ComputedStyle* aComputedStyle, ComputedStyle* aNewParent,
1512 ComputedStyle* aNewLayoutParent, Element* aElement) {
1513 return Servo_ReparentStyle(aComputedStyle, aNewParent, aNewLayoutParent,
1514 aElement, mRawData.get())
1515 .Consume();
1518 void ServoStyleSet::InvalidateForViewportUnits(OnlyDynamic aOnlyDynamic) {
1519 dom::Element* root = mDocument->GetRootElement();
1520 if (!root) {
1521 return;
1524 Servo_InvalidateForViewportUnits(mRawData.get(), root,
1525 aOnlyDynamic == OnlyDynamic::Yes);
1528 void ServoStyleSet::RegisterProperty(const PropertyDefinition& aDefinition,
1529 ErrorResult& aRv) {
1530 using Result = StyleRegisterCustomPropertyResult;
1531 auto result = Servo_RegisterCustomProperty(
1532 RawData(), mDocument->DefaultStyleAttrURLData(), &aDefinition.mName,
1533 &aDefinition.mSyntax, aDefinition.mInherits,
1534 aDefinition.mInitialValue.WasPassed() ? &aDefinition.mInitialValue.Value()
1535 : nullptr);
1536 switch (result) {
1537 case Result::SuccessfullyRegistered:
1538 if (Element* root = mDocument->GetRootElement()) {
1539 if (nsPresContext* pc = GetPresContext()) {
1540 pc->RestyleManager()->PostRestyleEvent(
1541 root, RestyleHint::RecascadeSubtree(), nsChangeHint(0));
1544 mDocument->PostCustomPropertyRegistered(aDefinition);
1545 break;
1546 case Result::InvalidName:
1547 return aRv.ThrowSyntaxError("Invalid name");
1548 case Result::InvalidSyntax:
1549 return aRv.ThrowSyntaxError("Invalid syntax descriptor");
1550 case Result::InvalidInitialValue:
1551 return aRv.ThrowSyntaxError("Invalid initial value syntax");
1552 case Result::NoInitialValue:
1553 return aRv.ThrowSyntaxError(
1554 "Initial value is required when syntax is not universal");
1555 case Result::InitialValueNotComputationallyIndependent:
1556 return aRv.ThrowSyntaxError(
1557 "Initial value is required when syntax is not universal");
1558 case Result::AlreadyRegistered:
1559 return aRv.ThrowInvalidModificationError("Property already registered");
1563 NS_IMPL_ISUPPORTS(UACacheReporter, nsIMemoryReporter)
1565 MOZ_DEFINE_MALLOC_SIZE_OF(ServoUACacheMallocSizeOf)
1566 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoUACacheMallocEnclosingSizeOf)
1568 NS_IMETHODIMP
1569 UACacheReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
1570 nsISupports* aData, bool aAnonymize) {
1571 ServoStyleSetSizes sizes;
1572 Servo_UACache_AddSizeOf(ServoUACacheMallocSizeOf,
1573 ServoUACacheMallocEnclosingSizeOf, &sizes);
1575 #define REPORT(_path, _amount, _desc) \
1576 do { \
1577 size_t __amount = _amount; /* evaluate _amount only once */ \
1578 if (__amount > 0) { \
1579 MOZ_COLLECT_REPORT(_path, KIND_HEAP, UNITS_BYTES, __amount, _desc); \
1581 } while (0)
1583 // The UA cache does not contain the rule tree; that's in the StyleSet.
1584 MOZ_RELEASE_ASSERT(sizes.mRuleTree == 0);
1586 REPORT("explicit/layout/servo-ua-cache/precomputed-pseudos",
1587 sizes.mPrecomputedPseudos,
1588 "Memory used by precomputed pseudo-element declarations within the "
1589 "UA cache.");
1591 REPORT("explicit/layout/servo-ua-cache/element-and-pseudos-maps",
1592 sizes.mElementAndPseudosMaps,
1593 "Memory used by element and pseudos maps within the UA cache.");
1595 REPORT("explicit/layout/servo-ua-cache/invalidation-map",
1596 sizes.mInvalidationMap,
1597 "Memory used by invalidation maps within the UA cache.");
1599 REPORT("explicit/layout/servo-ua-cache/revalidation-selectors",
1600 sizes.mRevalidationSelectors,
1601 "Memory used by selectors for cache revalidation within the UA "
1602 "cache.");
1604 REPORT("explicit/layout/servo-ua-cache/other", sizes.mOther,
1605 "Memory used by other data within the UA cache");
1607 return NS_OK;
1610 } // namespace mozilla