Bug 1833466 - Implement CSSMarginRule and the corresponding DOM API. r=webidl,firefox...
[gecko.git] / layout / style / ServoStyleSet.cpp
blob14e5d066b0683a9904084bb0384f03533c3cbac5
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/DocumentStyleRootIterator.h"
12 #include "mozilla/AttributeStyles.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/ProfilerLabels.h"
19 #include "mozilla/ServoBindings.h"
20 #include "mozilla/RestyleManager.h"
21 #include "mozilla/ServoStyleRuleMap.h"
22 #include "mozilla/ServoTypes.h"
23 #include "mozilla/SMILAnimationController.h"
24 #include "mozilla/MediaFeatureChange.h"
25 #include "mozilla/StyleAnimationValue.h"
26 #include "mozilla/css/Loader.h"
27 #include "mozilla/dom/AnonymousContent.h"
28 #include "mozilla/dom/CSSBinding.h"
29 #include "mozilla/dom/CSSCounterStyleRule.h"
30 #include "mozilla/dom/CSSFontFaceRule.h"
31 #include "mozilla/dom/CSSFontFeatureValuesRule.h"
32 #include "mozilla/dom/CSSFontPaletteValuesRule.h"
33 #include "mozilla/dom/CSSImportRule.h"
34 #include "mozilla/dom/CSSContainerRule.h"
35 #include "mozilla/dom/CSSLayerBlockRule.h"
36 #include "mozilla/dom/CSSLayerStatementRule.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/CSSPageRule.h"
43 #include "mozilla/dom/CSSPropertyRule.h"
44 #include "mozilla/dom/CSSScopeRule.h"
45 #include "mozilla/dom/CSSSupportsRule.h"
46 #include "mozilla/dom/CSSStartingStyleRule.h"
47 #include "mozilla/dom/FontFaceSet.h"
48 #include "mozilla/dom/Element.h"
49 #include "mozilla/dom/ElementInlines.h"
50 #include "nsCSSAnonBoxes.h"
51 #include "nsCSSFrameConstructor.h"
52 #include "nsCSSPseudoElements.h"
53 #include "nsDeviceContext.h"
54 #include "nsIAnonymousContentCreator.h"
55 #include "nsLayoutUtils.h"
56 #include "mozilla/dom/DocumentInlines.h"
57 #include "nsPrintfCString.h"
58 #include "gfxUserFontSet.h"
59 #include "nsWindowSizes.h"
61 namespace mozilla {
63 using namespace dom;
65 #ifdef DEBUG
66 bool ServoStyleSet::IsCurrentThreadInServoTraversal() {
67 return sInServoTraversal && (NS_IsMainThread() || Servo_IsWorkerThread());
69 #endif
71 // The definition of kOrigins relies on this.
72 static_assert(static_cast<uint8_t>(StyleOrigin::UserAgent) ==
73 static_cast<uint8_t>(OriginFlags::UserAgent));
74 static_assert(static_cast<uint8_t>(StyleOrigin::User) ==
75 static_cast<uint8_t>(OriginFlags::User));
76 static_assert(static_cast<uint8_t>(StyleOrigin::Author) ==
77 static_cast<uint8_t>(OriginFlags::Author));
79 constexpr const StyleOrigin ServoStyleSet::kOrigins[];
81 ServoStyleSet* sInServoTraversal = nullptr;
83 // On construction, sets sInServoTraversal to the given ServoStyleSet.
84 // On destruction, clears sInServoTraversal and calls RunPostTraversalTasks.
85 class MOZ_RAII AutoSetInServoTraversal {
86 public:
87 explicit AutoSetInServoTraversal(ServoStyleSet* aSet) : mSet(aSet) {
88 MOZ_ASSERT(!sInServoTraversal);
89 MOZ_ASSERT(aSet);
90 sInServoTraversal = aSet;
93 ~AutoSetInServoTraversal() {
94 MOZ_ASSERT(sInServoTraversal);
95 sInServoTraversal = nullptr;
96 mSet->RunPostTraversalTasks();
99 private:
100 ServoStyleSet* mSet;
103 // Sets up for one or more calls to Servo_TraverseSubtree.
104 class MOZ_RAII AutoPrepareTraversal {
105 public:
106 explicit AutoPrepareTraversal(ServoStyleSet* aSet)
107 : mSetInServoTraversal(aSet) {
108 MOZ_ASSERT(!aSet->StylistNeedsUpdate());
111 private:
112 AutoSetInServoTraversal mSetInServoTraversal;
115 ServoStyleSet::ServoStyleSet(Document& aDocument) : mDocument(&aDocument) {
116 PreferenceSheet::EnsureInitialized();
117 PodArrayZero(mCachedAnonymousContentStyleIndexes);
118 mRawData.reset(Servo_StyleSet_Init(&aDocument));
121 ServoStyleSet::~ServoStyleSet() {
122 MOZ_ASSERT(!IsInServoTraversal());
123 EnumerateStyleSheets([&](StyleSheet& aSheet) { aSheet.DropStyleSet(this); });
126 nsPresContext* ServoStyleSet::GetPresContext() {
127 return mDocument->GetPresContext();
130 template <typename Functor>
131 static void EnumerateShadowRoots(const Document& aDoc, const Functor& aCb) {
132 const Document::ShadowRootSet& shadowRoots = aDoc.ComposedShadowRoots();
133 for (ShadowRoot* root : shadowRoots) {
134 MOZ_ASSERT(root);
135 MOZ_DIAGNOSTIC_ASSERT(root->IsInComposedDoc());
136 aCb(*root);
140 void ServoStyleSet::ShellDetachedFromDocument() {
141 ClearNonInheritingComputedStyles();
142 mCachedAnonymousContentStyles.Clear();
143 PodArrayZero(mCachedAnonymousContentStyleIndexes);
144 mStyleRuleMap = nullptr;
146 // Remove all our stylesheets...
147 for (auto origin : kOrigins) {
148 for (size_t count = SheetCount(origin); count--;) {
149 RemoveStyleSheet(*SheetAt(origin, count));
153 // And remove all the CascadeDatas from memory.
154 UpdateStylistIfNeeded();
156 // Also GC the ruletree if it got big now that the DOM no longer has
157 // references to styles around anymore.
158 MaybeGCRuleTree();
161 void ServoStyleSet::RecordShadowStyleChange(ShadowRoot& aShadowRoot) {
162 // TODO(emilio): We could keep track of the actual shadow roots that need
163 // their styles recomputed.
164 SetStylistShadowDOMStyleSheetsDirty();
166 // FIXME(emilio): This should be done using stylesheet invalidation instead.
167 if (nsPresContext* pc = GetPresContext()) {
168 pc->RestyleManager()->PostRestyleEvent(
169 aShadowRoot.Host(), RestyleHint::RestyleSubtree(), nsChangeHint(0));
173 void ServoStyleSet::InvalidateStyleForDocumentStateChanges(
174 DocumentState aStatesChanged) {
175 MOZ_ASSERT(mDocument);
176 MOZ_ASSERT(!aStatesChanged.IsEmpty());
178 nsPresContext* pc = GetPresContext();
179 if (!pc) {
180 return;
183 Element* root = mDocument->GetRootElement();
184 if (!root) {
185 return;
188 // TODO(emilio): It may be nicer to just invalidate stuff in a given subtree
189 // for Shadow DOM. Consider just enumerating shadow roots instead and run
190 // invalidation individually, passing mRawData for the UA / User sheets.
191 AutoTArray<const StyleAuthorStyles*, 20> nonDocumentStyles;
193 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
194 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
195 nonDocumentStyles.AppendElement(authorStyles);
199 Servo_InvalidateStyleForDocStateChanges(root, mRawData.get(),
200 &nonDocumentStyles,
201 aStatesChanged.GetInternalValue());
204 static const MediaFeatureChangeReason kMediaFeaturesAffectingDefaultStyle =
205 // Zoom changes change the meaning of em units.
206 MediaFeatureChangeReason::ZoomChange |
207 // A resolution change changes the app-units-per-dev-pixels ratio, which
208 // some structs (Border, Outline, Column) store for clamping. We should
209 // arguably not do that, maybe doing it on layout directly, to try to avoid
210 // relying on the pres context (bug 1418159).
211 MediaFeatureChangeReason::ResolutionChange;
213 RestyleHint ServoStyleSet::MediumFeaturesChanged(
214 MediaFeatureChangeReason aReason) {
215 AutoTArray<StyleAuthorStyles*, 20> nonDocumentStyles;
217 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
218 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
219 nonDocumentStyles.AppendElement(authorStyles);
223 const bool mayAffectDefaultStyle =
224 bool(aReason & kMediaFeaturesAffectingDefaultStyle);
225 const MediumFeaturesChangedResult result =
226 Servo_StyleSet_MediumFeaturesChanged(mRawData.get(), &nonDocumentStyles,
227 mayAffectDefaultStyle);
229 const bool viewportChanged =
230 bool(aReason & MediaFeatureChangeReason::ViewportChange);
231 if (viewportChanged) {
232 InvalidateForViewportUnits(OnlyDynamic::No);
235 const bool rulesChanged =
236 result.mAffectsDocumentRules || result.mAffectsNonDocumentRules;
238 if (result.mAffectsDocumentRules) {
239 SetStylistStyleSheetsDirty();
242 if (result.mAffectsNonDocumentRules) {
243 SetStylistShadowDOMStyleSheetsDirty();
246 if (rulesChanged) {
247 // TODO(emilio): This could be more granular.
248 return RestyleHint::RestyleSubtree();
251 return RestyleHint{0};
254 MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSetMallocSizeOf)
255 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSetMallocEnclosingSizeOf)
257 void ServoStyleSet::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const {
258 MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
260 aSizes.mLayoutStyleSetsOther += mallocSizeOf(this);
262 if (mRawData) {
263 aSizes.mLayoutStyleSetsOther += mallocSizeOf(mRawData.get());
264 ServoStyleSetSizes sizes;
265 // Measure mRawData. We use ServoStyleSetMallocSizeOf rather than
266 // aMallocSizeOf to distinguish in DMD's output the memory measured within
267 // Servo code.
268 Servo_StyleSet_AddSizeOfExcludingThis(ServoStyleSetMallocSizeOf,
269 ServoStyleSetMallocEnclosingSizeOf,
270 &sizes, mRawData.get());
272 // The StyleSet does not contain precomputed pseudos; they are in the UA
273 // cache.
274 MOZ_RELEASE_ASSERT(sizes.mPrecomputedPseudos == 0);
276 aSizes.mLayoutStyleSetsStylistRuleTree += sizes.mRuleTree;
277 aSizes.mLayoutStyleSetsStylistElementAndPseudosMaps +=
278 sizes.mElementAndPseudosMaps;
279 aSizes.mLayoutStyleSetsStylistInvalidationMap += sizes.mInvalidationMap;
280 aSizes.mLayoutStyleSetsStylistRevalidationSelectors +=
281 sizes.mRevalidationSelectors;
282 aSizes.mLayoutStyleSetsStylistOther += sizes.mOther;
285 if (mStyleRuleMap) {
286 aSizes.mLayoutStyleSetsOther +=
287 mStyleRuleMap->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
290 // Measurement of the following members may be added later if DMD finds it is
291 // worthwhile:
292 // - mSheets
293 // - mNonInheritingComputedStyles
295 // The following members are not measured:
296 // - mDocument, because it a non-owning pointer
299 void ServoStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled) {
300 if (mAuthorStyleDisabled == aStyleDisabled) {
301 return;
304 mAuthorStyleDisabled = aStyleDisabled;
305 if (Element* root = mDocument->GetRootElement()) {
306 if (nsPresContext* pc = GetPresContext()) {
307 pc->RestyleManager()->PostRestyleEvent(
308 root, RestyleHint::RestyleSubtree(), nsChangeHint(0));
311 Servo_StyleSet_SetAuthorStyleDisabled(mRawData.get(), mAuthorStyleDisabled);
312 // XXX Workaround for bug 1437785.
313 SetStylistStyleSheetsDirty();
316 const ServoElementSnapshotTable& ServoStyleSet::Snapshots() {
317 MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
318 return GetPresContext()->RestyleManager()->Snapshots();
321 void ServoStyleSet::PreTraverseSync() {
322 // Get the Document's root element to ensure that the cache is valid before
323 // calling into the (potentially-parallel) Servo traversal, where a cache hit
324 // is necessary to avoid a data race when updating the cache.
325 Unused << mDocument->GetRootElement();
327 // FIXME(emilio): These two shouldn't be needed in theory, the call to the
328 // same function in PresShell should do the work, but as it turns out we
329 // ProcessPendingRestyles() twice, and runnables from frames just constructed
330 // can end up doing editing stuff, which adds stylesheets etc...
331 mDocument->FlushUserFontSet();
332 UpdateStylistIfNeeded();
334 mDocument->ResolveScheduledPresAttrs();
336 LookAndFeel::NativeInit();
338 mDocument->CacheAllKnownLangPrefs();
340 if (gfxUserFontSet* userFontSet = mDocument->GetUserFontSet()) {
341 nsPresContext* presContext = GetPresContext();
342 MOZ_ASSERT(presContext,
343 "For now, we don't call into here without a pres context");
345 // Ensure that the @font-face data is not stale
346 uint64_t generation = userFontSet->GetGeneration();
347 if (generation != mUserFontSetUpdateGeneration) {
348 mDocument->GetFonts()->CacheFontLoadability();
349 presContext->UpdateFontCacheUserFonts(userFontSet);
350 mUserFontSetUpdateGeneration = generation;
354 MOZ_ASSERT(!StylistNeedsUpdate());
357 void ServoStyleSet::PreTraverse(ServoTraversalFlags aFlags, Element* aRoot) {
358 PreTraverseSync();
360 // Process animation stuff that we should avoid doing during the parallel
361 // traversal.
362 SMILAnimationController* smilController =
363 mDocument->HasAnimationController() ? mDocument->GetAnimationController()
364 : nullptr;
366 MOZ_ASSERT(GetPresContext());
367 if (aRoot) {
368 GetPresContext()->EffectCompositor()->PreTraverseInSubtree(aFlags, aRoot);
369 if (smilController) {
370 smilController->PreTraverseInSubtree(aRoot);
372 } else {
373 GetPresContext()->EffectCompositor()->PreTraverse(aFlags);
374 if (smilController) {
375 smilController->PreTraverse();
380 static inline already_AddRefed<ComputedStyle>
381 ResolveStyleForTextOrFirstLetterContinuation(
382 const StylePerDocumentStyleData* aRawData, ComputedStyle& aParent,
383 PseudoStyleType aType) {
384 MOZ_ASSERT(aType == PseudoStyleType::mozText ||
385 aType == PseudoStyleType::firstLetterContinuation);
386 auto inheritTarget = aType == PseudoStyleType::mozText
387 ? InheritTarget::Text
388 : InheritTarget::FirstLetterContinuation;
390 RefPtr<ComputedStyle> style = aParent.GetCachedInheritingAnonBoxStyle(aType);
391 if (!style) {
392 style =
393 Servo_ComputedValues_Inherit(aRawData, aType, &aParent, inheritTarget)
394 .Consume();
395 MOZ_ASSERT(style);
396 aParent.SetCachedInheritedAnonBoxStyle(style);
399 return style.forget();
402 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleForText(
403 nsIContent* aTextNode, ComputedStyle* aParentStyle) {
404 MOZ_ASSERT(aTextNode && aTextNode->IsText());
405 MOZ_ASSERT(aTextNode->GetParent());
406 MOZ_ASSERT(aParentStyle);
408 return ResolveStyleForTextOrFirstLetterContinuation(
409 mRawData.get(), *aParentStyle, PseudoStyleType::mozText);
412 already_AddRefed<ComputedStyle>
413 ServoStyleSet::ResolveStyleForFirstLetterContinuation(
414 ComputedStyle* aParentStyle) {
415 MOZ_ASSERT(aParentStyle);
417 return ResolveStyleForTextOrFirstLetterContinuation(
418 mRawData.get(), *aParentStyle, PseudoStyleType::firstLetterContinuation);
421 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleForPlaceholder() {
422 RefPtr<ComputedStyle>& cache = mNonInheritingComputedStyles
423 [nsCSSAnonBoxes::NonInheriting::oofPlaceholder];
424 if (cache) {
425 RefPtr<ComputedStyle> retval = cache;
426 return retval.forget();
429 RefPtr<ComputedStyle> computedValues =
430 Servo_ComputedValues_Inherit(mRawData.get(),
431 PseudoStyleType::oofPlaceholder, nullptr,
432 InheritTarget::PlaceholderFrame)
433 .Consume();
434 MOZ_ASSERT(computedValues);
436 cache = computedValues;
437 return computedValues.forget();
440 static inline bool LazyPseudoIsCacheable(PseudoStyleType aType,
441 const Element& aOriginatingElement,
442 ComputedStyle* aParentStyle) {
443 return aParentStyle &&
444 !nsCSSPseudoElements::IsEagerlyCascadedInServo(aType) &&
445 aOriginatingElement.HasServoData() &&
446 !Servo_Element_IsPrimaryStyleReusedViaRuleNode(&aOriginatingElement);
449 already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePseudoElementStyle(
450 const Element& aOriginatingElement, PseudoStyleType aType,
451 nsAtom* aFunctionalPseudoParameter, ComputedStyle* aParentStyle,
452 IsProbe aIsProbe) {
453 // Runs from frame construction, this should have clean styles already, except
454 // with non-lazy FC...
455 UpdateStylistIfNeeded();
456 MOZ_ASSERT(PseudoStyle::IsPseudoElement(aType));
458 // caching is done using `aType` only, therefore results would be wrong for
459 // pseudos with functional parameters (e.g. `::highlight(foo)`).
460 const bool cacheable =
461 !aFunctionalPseudoParameter &&
462 LazyPseudoIsCacheable(aType, aOriginatingElement, aParentStyle);
463 RefPtr<ComputedStyle> style =
464 cacheable ? aParentStyle->GetCachedLazyPseudoStyle(aType) : nullptr;
466 const bool isProbe = aIsProbe == IsProbe::Yes;
468 if (!style) {
469 // FIXME(emilio): Why passing null for probing as the parent style?
471 // There are callers which do pass the wrong parent style and it would
472 // assert (like ComputeSelectionStyle()). That's messy!
473 style = Servo_ResolvePseudoStyle(
474 &aOriginatingElement, aType, aFunctionalPseudoParameter,
475 isProbe, isProbe ? nullptr : aParentStyle, mRawData.get())
476 .Consume();
477 if (!style) {
478 MOZ_ASSERT(isProbe);
479 return nullptr;
481 if (cacheable) {
482 aParentStyle->SetCachedLazyPseudoStyle(style);
486 MOZ_ASSERT(style);
488 if (isProbe && !GeneratedContentPseudoExists(*aParentStyle, *style)) {
489 return nullptr;
492 return style.forget();
495 already_AddRefed<ComputedStyle>
496 ServoStyleSet::ResolveInheritingAnonymousBoxStyle(PseudoStyleType aType,
497 ComputedStyle* aParentStyle) {
498 MOZ_ASSERT(PseudoStyle::IsInheritingAnonBox(aType));
499 MOZ_ASSERT_IF(aParentStyle, !StylistNeedsUpdate());
501 UpdateStylistIfNeeded();
503 RefPtr<ComputedStyle> style = nullptr;
505 if (aParentStyle) {
506 style = aParentStyle->GetCachedInheritingAnonBoxStyle(aType);
509 if (!style) {
510 style = Servo_ComputedValues_GetForAnonymousBox(aParentStyle, aType,
511 mRawData.get())
512 .Consume();
513 MOZ_ASSERT(style);
514 if (aParentStyle) {
515 aParentStyle->SetCachedInheritedAnonBoxStyle(style);
519 return style.forget();
522 already_AddRefed<ComputedStyle>
523 ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType aType) {
524 MOZ_ASSERT(aType != PseudoStyleType::pageContent,
525 "Use ResolvePageContentStyle for page content");
526 MOZ_ASSERT(PseudoStyle::IsNonInheritingAnonBox(aType));
528 nsCSSAnonBoxes::NonInheriting type =
529 nsCSSAnonBoxes::NonInheritingTypeForPseudoType(aType);
530 RefPtr<ComputedStyle>& cache = mNonInheritingComputedStyles[type];
531 if (cache) {
532 RefPtr<ComputedStyle> retval = cache;
533 return retval.forget();
536 UpdateStylistIfNeeded();
538 // We always want to skip parent-based display fixup here. It never makes
539 // sense for non-inheriting anonymous boxes. (Static assertions in
540 // nsCSSAnonBoxes.cpp ensure that all non-inheriting non-anonymous boxes
541 // are indeed annotated as skipping this fixup.)
542 MOZ_ASSERT(!PseudoStyle::IsNonInheritingAnonBox(PseudoStyleType::viewport),
543 "viewport needs fixup to handle blockifying it");
545 RefPtr<ComputedStyle> computedValues =
546 Servo_ComputedValues_GetForAnonymousBox(nullptr, aType, mRawData.get())
547 .Consume();
548 MOZ_ASSERT(computedValues);
550 cache = computedValues;
551 return computedValues.forget();
554 already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePageContentStyle(
555 const nsAtom* aPageName, const StylePagePseudoClassFlags& aPseudo) {
556 // The empty atom is used to indicate no specified page name, and is not
557 // usable as a page-rule selector. Changing this to null is a slight
558 // optimization to avoid the Servo code from doing an unnecessary hashtable
559 // lookup, and still use the style cache in this case.
560 if (aPageName == nsGkAtoms::_empty) {
561 aPageName = nullptr;
563 // Only use the cache when we are doing a lookup for page styles without a
564 // page-name or any pseudo classes.
565 const bool useCache = !aPageName && !aPseudo;
566 RefPtr<ComputedStyle>& cache =
567 mNonInheritingComputedStyles[nsCSSAnonBoxes::NonInheriting::pageContent];
568 if (useCache && cache) {
569 RefPtr<ComputedStyle> retval = cache;
570 return retval.forget();
573 UpdateStylistIfNeeded();
575 RefPtr<ComputedStyle> computedValues =
576 Servo_ComputedValues_GetForPageContent(mRawData.get(), aPageName, aPseudo)
577 .Consume();
578 MOZ_ASSERT(computedValues);
580 if (useCache) {
581 cache = computedValues;
583 return computedValues.forget();
586 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveXULTreePseudoStyle(
587 dom::Element* aParentElement, nsCSSAnonBoxPseudoStaticAtom* aPseudoTag,
588 ComputedStyle* aParentStyle, const AtomArray& aInputWord) {
589 MOZ_ASSERT(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag));
590 MOZ_ASSERT(aParentStyle);
591 NS_ASSERTION(!StylistNeedsUpdate(),
592 "Stylesheets modified when resolving XUL tree pseudo");
594 return Servo_ComputedValues_ResolveXULTreePseudoStyle(
595 aParentElement, aPseudoTag, aParentStyle, &aInputWord,
596 mRawData.get())
597 .Consume();
600 // manage the set of style sheets in the style set
601 void ServoStyleSet::AppendStyleSheet(StyleSheet& aSheet) {
602 MOZ_ASSERT(aSheet.IsApplicable());
603 MOZ_ASSERT(aSheet.RawContents(),
604 "Raw sheet should be in place before insertion.");
606 aSheet.AddStyleSet(this);
608 // Maintain a mirrored list of sheets on the servo side.
609 // Servo will remove aSheet from its original position as part of the call
610 // to Servo_StyleSet_AppendStyleSheet.
611 Servo_StyleSet_AppendStyleSheet(mRawData.get(), &aSheet);
612 SetStylistStyleSheetsDirty();
614 if (mStyleRuleMap) {
615 mStyleRuleMap->SheetAdded(aSheet);
619 void ServoStyleSet::RemoveStyleSheet(StyleSheet& aSheet) {
620 aSheet.DropStyleSet(this);
622 // Maintain a mirrored list of sheets on the servo side.
623 Servo_StyleSet_RemoveStyleSheet(mRawData.get(), &aSheet);
624 SetStylistStyleSheetsDirty();
626 if (mStyleRuleMap) {
627 mStyleRuleMap->SheetRemoved(aSheet);
631 void ServoStyleSet::InsertStyleSheetBefore(StyleSheet& aNewSheet,
632 StyleSheet& aReferenceSheet) {
633 MOZ_ASSERT(aNewSheet.IsApplicable());
634 MOZ_ASSERT(aReferenceSheet.IsApplicable());
635 MOZ_ASSERT(&aNewSheet != &aReferenceSheet,
636 "Can't place sheet before itself.");
637 MOZ_ASSERT(aNewSheet.GetOrigin() == aReferenceSheet.GetOrigin(),
638 "Sheets should be in the same origin");
639 MOZ_ASSERT(aNewSheet.RawContents(),
640 "Raw sheet should be in place before insertion.");
641 MOZ_ASSERT(aReferenceSheet.RawContents(),
642 "Reference sheet should have a raw sheet.");
644 // Servo will remove aNewSheet from its original position as part of the
645 // call to Servo_StyleSet_InsertStyleSheetBefore.
646 aNewSheet.AddStyleSet(this);
648 // Maintain a mirrored list of sheets on the servo side.
649 Servo_StyleSet_InsertStyleSheetBefore(mRawData.get(), &aNewSheet,
650 &aReferenceSheet);
651 SetStylistStyleSheetsDirty();
653 if (mStyleRuleMap) {
654 mStyleRuleMap->SheetAdded(aNewSheet);
658 size_t ServoStyleSet::SheetCount(Origin aOrigin) const {
659 return Servo_StyleSet_GetSheetCount(mRawData.get(), aOrigin);
662 StyleSheet* ServoStyleSet::SheetAt(Origin aOrigin, size_t aIndex) const {
663 return const_cast<StyleSheet*>(
664 Servo_StyleSet_GetSheetAt(mRawData.get(), aOrigin, aIndex));
667 ServoStyleSet::PageSizeAndOrientation
668 ServoStyleSet::GetDefaultPageSizeAndOrientation() {
669 PageSizeAndOrientation retval;
670 const RefPtr<ComputedStyle> style =
671 ResolvePageContentStyle(nullptr, StylePagePseudoClassFlags::NONE);
672 const StylePageSize& pageSize = style->StylePage()->mSize;
674 if (pageSize.IsSize()) {
675 const nscoord w = pageSize.AsSize().width.ToAppUnits();
676 const nscoord h = pageSize.AsSize().height.ToAppUnits();
677 // Ignoring sizes that include a zero width or height.
678 // These are also ignored in nsPageFrame::ComputePageSize()
679 // when calculating the scaling for a page size.
680 // In bug 1807985, we might add similar handling for @page margin/size
681 // combinations that produce a zero-sized page-content box.
682 if (w > 0 && h > 0) {
683 retval.size.emplace(w, h);
684 if (w > h) {
685 retval.orientation.emplace(StylePageSizeOrientation::Landscape);
686 } else if (w < h) {
687 retval.orientation.emplace(StylePageSizeOrientation::Portrait);
690 } else if (pageSize.IsOrientation()) {
691 retval.orientation.emplace(pageSize.AsOrientation());
692 } else {
693 MOZ_ASSERT(pageSize.IsAuto(), "Impossible page size");
695 return retval;
698 void ServoStyleSet::AppendAllNonDocumentAuthorSheets(
699 nsTArray<StyleSheet*>& aArray) const {
700 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
701 for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
702 aArray.AppendElement(aShadowRoot.SheetAt(index));
704 aArray.AppendElements(aShadowRoot.AdoptedStyleSheets());
708 void ServoStyleSet::AddDocStyleSheet(StyleSheet& aSheet) {
709 MOZ_ASSERT(aSheet.IsApplicable());
710 MOZ_ASSERT(aSheet.RawContents(),
711 "Raw sheet should be in place by this point.");
713 size_t index = mDocument->FindDocStyleSheetInsertionPoint(aSheet);
714 aSheet.AddStyleSet(this);
716 if (index < SheetCount(Origin::Author)) {
717 // This case is insert before.
718 StyleSheet* beforeSheet = SheetAt(Origin::Author, index);
720 // Maintain a mirrored list of sheets on the servo side.
721 Servo_StyleSet_InsertStyleSheetBefore(mRawData.get(), &aSheet, beforeSheet);
722 SetStylistStyleSheetsDirty();
723 } else {
724 // Maintain a mirrored list of sheets on the servo side.
725 Servo_StyleSet_AppendStyleSheet(mRawData.get(), &aSheet);
726 SetStylistStyleSheetsDirty();
729 if (mStyleRuleMap) {
730 mStyleRuleMap->SheetAdded(aSheet);
734 bool ServoStyleSet::GeneratedContentPseudoExists(
735 const ComputedStyle& aParentStyle, const ComputedStyle& aPseudoStyle) {
736 auto type = aPseudoStyle.GetPseudoType();
737 MOZ_ASSERT(type != PseudoStyleType::NotPseudo);
739 if (type == PseudoStyleType::marker) {
740 // ::marker only exist for list items (for now).
741 if (!aParentStyle.StyleDisplay()->IsListItem()) {
742 return false;
744 const auto& content = aPseudoStyle.StyleContent()->mContent;
745 // ::marker does not exist if 'content' is 'none' (this trumps
746 // any 'list-style-type' or 'list-style-image' values).
747 if (content.IsNone()) {
748 return false;
750 // ::marker only exist if we have 'content' or at least one of
751 // 'list-style-type' or 'list-style-image'.
752 if (aPseudoStyle.StyleList()->mCounterStyle.IsNone() &&
753 aPseudoStyle.StyleList()->mListStyleImage.IsNone() &&
754 content.IsNormal()) {
755 return false;
757 // display:none is equivalent to not having a pseudo at all.
758 if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) {
759 return false;
763 // For ::before and ::after pseudo-elements, no 'content' items is
764 // equivalent to not having the pseudo-element at all.
765 if (type == PseudoStyleType::before || type == PseudoStyleType::after) {
766 if (!aPseudoStyle.StyleContent()->mContent.IsItems()) {
767 return false;
769 MOZ_ASSERT(aPseudoStyle.StyleContent()->ContentCount() > 0,
770 "IsItems() implies we have at least one item");
771 // display:none is equivalent to not having a pseudo at all.
772 if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) {
773 return false;
777 return true;
780 bool ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags) {
781 AUTO_PROFILER_LABEL_CATEGORY_PAIR_RELEVANT_FOR_JS(LAYOUT_StyleComputation);
782 MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
784 if (!mDocument->GetServoRestyleRoot()) {
785 return false;
788 Element* rootElement = mDocument->GetRootElement();
789 if (rootElement && MOZ_UNLIKELY(!rootElement->HasServoData())) {
790 StyleNewSubtree(rootElement);
791 return true;
794 PreTraverse(aFlags);
795 AutoPrepareTraversal guard(this);
796 const SnapshotTable& snapshots = Snapshots();
798 // Restyle the document from the root element and each of the document level
799 // NAC subtree roots.
800 bool postTraversalRequired = false;
802 if (ShouldTraverseInParallel()) {
803 aFlags |= ServoTraversalFlags::ParallelTraversal;
806 // Do the first traversal.
807 DocumentStyleRootIterator iter(mDocument->GetServoRestyleRoot());
808 while (Element* root = iter.GetNextStyleRoot()) {
809 MOZ_ASSERT(MayTraverseFrom(root));
811 Element* parent = root->GetFlattenedTreeParentElementForStyle();
812 MOZ_ASSERT_IF(parent,
813 !parent->HasAnyOfFlags(Element::kAllServoDescendantBits));
815 postTraversalRequired |=
816 Servo_TraverseSubtree(root, mRawData.get(), &snapshots, aFlags) ||
817 root->HasAnyOfFlags(Element::kAllServoDescendantBits |
818 NODE_NEEDS_FRAME);
821 uint32_t existingBits = mDocument->GetServoRestyleRootDirtyBits();
822 Element* newRoot = nullptr;
823 while (parent && parent->HasDirtyDescendantsForServo()) {
824 MOZ_ASSERT(root == mDocument->GetServoRestyleRoot(),
825 "Restyle root shouldn't have magically changed");
826 // If any style invalidation was triggered in our siblings, then we may
827 // need to post-traverse them, even if the root wasn't restyled after
828 // all.
829 // We need to propagate the existing bits to the ancestor.
830 parent->SetFlags(existingBits);
831 newRoot = parent;
832 parent = parent->GetFlattenedTreeParentElementForStyle();
835 if (newRoot) {
836 mDocument->SetServoRestyleRoot(
837 newRoot, existingBits | ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
838 postTraversalRequired = true;
843 // If there are still animation restyles needed, trigger a second traversal to
844 // update CSS animations or transitions' styles.
846 // Note that we need to check the style root again, because doing another
847 // PreTraverse on the EffectCompositor might alter the style root. But we
848 // don't need to worry about NAC, since document-level NAC shouldn't have
849 // animations.
851 // We don't need to do this for SMIL since SMIL only updates its animation
852 // values once at the begin of a tick. As a result, even if the previous
853 // traversal caused, for example, the font-size to change, the SMIL style
854 // won't be updated until the next tick anyway.
855 if (GetPresContext()->EffectCompositor()->PreTraverse(aFlags)) {
856 DocumentStyleRootIterator iter(mDocument->GetServoRestyleRoot());
857 while (Element* root = iter.GetNextStyleRoot()) {
858 postTraversalRequired |=
859 Servo_TraverseSubtree(root, mRawData.get(), &snapshots, aFlags) ||
860 root->HasAnyOfFlags(Element::kAllServoDescendantBits |
861 NODE_NEEDS_FRAME);
865 return postTraversalRequired;
868 void ServoStyleSet::StyleNewSubtree(Element* aRoot) {
869 MOZ_ASSERT(GetPresContext());
870 MOZ_ASSERT(!aRoot->HasServoData());
871 MOZ_ASSERT(aRoot->GetFlattenedTreeParentNodeForStyle(),
872 "Not in the flat tree? Fishy!");
873 PreTraverseSync();
874 AutoPrepareTraversal guard(this);
876 // Do the traversal. The snapshots will not be used.
877 const SnapshotTable& snapshots = Snapshots();
878 auto flags = ServoTraversalFlags::Empty;
879 if (ShouldTraverseInParallel()) {
880 flags |= ServoTraversalFlags::ParallelTraversal;
883 DebugOnly<bool> postTraversalRequired =
884 Servo_TraverseSubtree(aRoot, mRawData.get(), &snapshots, flags);
885 MOZ_ASSERT(!postTraversalRequired);
887 // Annoyingly, the newly-styled content may have animations that need
888 // starting, which requires traversing them again. Mark the elements
889 // that need animation processing, then do a forgetful traversal to
890 // update the styles and clear the animation bits.
891 if (GetPresContext()->EffectCompositor()->PreTraverseInSubtree(flags,
892 aRoot)) {
893 postTraversalRequired =
894 Servo_TraverseSubtree(aRoot, mRawData.get(), &snapshots,
895 ServoTraversalFlags::AnimationOnly |
896 ServoTraversalFlags::FinalAnimationTraversal);
897 MOZ_ASSERT(!postTraversalRequired);
901 void ServoStyleSet::MarkOriginsDirty(OriginFlags aChangedOrigins) {
902 SetStylistStyleSheetsDirty();
903 Servo_StyleSet_NoteStyleSheetsChanged(mRawData.get(), aChangedOrigins);
906 void ServoStyleSet::SetStylistStyleSheetsDirty() {
907 mStylistState |= StylistState::StyleSheetsDirty;
909 // We need to invalidate cached style in getComputedStyle for undisplayed
910 // elements, since we don't know if any of the style sheet change that we do
911 // would affect undisplayed elements.
913 // We don't allow to call getComputedStyle in elements without a pres shell
914 // yet, so it is fine if there's no pres context here.
915 if (nsPresContext* presContext = GetPresContext()) {
916 presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration();
920 void ServoStyleSet::SetStylistShadowDOMStyleSheetsDirty() {
921 mStylistState |= StylistState::ShadowDOMStyleSheetsDirty;
922 if (nsPresContext* presContext = GetPresContext()) {
923 presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration();
927 static OriginFlags ToOriginFlags(StyleOrigin aOrigin) {
928 switch (aOrigin) {
929 case StyleOrigin::UserAgent:
930 return OriginFlags::UserAgent;
931 case StyleOrigin::User:
932 return OriginFlags::User;
933 default:
934 MOZ_FALLTHROUGH_ASSERT("Unknown origin?");
935 case StyleOrigin::Author:
936 return OriginFlags::Author;
940 void ServoStyleSet::ImportRuleLoaded(dom::CSSImportRule&, StyleSheet& aSheet) {
941 if (mStyleRuleMap) {
942 mStyleRuleMap->SheetAdded(aSheet);
945 // TODO: Should probably consider ancestor sheets too.
946 if (!aSheet.IsApplicable()) {
947 return;
950 // TODO(emilio): Could handle it better given we know it is an insertion, and
951 // use the style invalidation machinery stuff that we do for regular sheet
952 // insertions.
953 MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
956 void ServoStyleSet::RuleAdded(StyleSheet& aSheet, css::Rule& aRule) {
957 if (mStyleRuleMap) {
958 mStyleRuleMap->RuleAdded(aSheet, aRule);
961 if (!aSheet.IsApplicable() || aRule.IsIncompleteImportRule()) {
962 return;
965 RuleChangedInternal(aSheet, aRule, StyleRuleChangeKind::Insertion);
968 void ServoStyleSet::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule) {
969 if (mStyleRuleMap) {
970 mStyleRuleMap->RuleRemoved(aSheet, aRule);
973 if (!aSheet.IsApplicable()) {
974 return;
977 RuleChangedInternal(aSheet, aRule, StyleRuleChangeKind::Removal);
980 void ServoStyleSet::RuleChangedInternal(StyleSheet& aSheet, css::Rule& aRule,
981 StyleRuleChangeKind aKind) {
982 MOZ_ASSERT(aSheet.IsApplicable());
983 SetStylistStyleSheetsDirty();
985 #define CASE_FOR(constant_, type_) \
986 case StyleCssRuleType::constant_: \
987 return Servo_StyleSet_##constant_##RuleChanged( \
988 mRawData.get(), static_cast<dom::CSS##type_##Rule&>(aRule).Raw(), \
989 &aSheet, aKind);
991 switch (aRule.Type()) {
992 CASE_FOR(CounterStyle, CounterStyle)
993 CASE_FOR(Style, Style)
994 CASE_FOR(Import, Import)
995 CASE_FOR(Media, Media)
996 CASE_FOR(Keyframes, Keyframes)
997 CASE_FOR(Margin, Margin)
998 CASE_FOR(FontFeatureValues, FontFeatureValues)
999 CASE_FOR(FontPaletteValues, FontPaletteValues)
1000 CASE_FOR(FontFace, FontFace)
1001 CASE_FOR(Page, Page)
1002 CASE_FOR(Property, Property)
1003 CASE_FOR(Document, MozDocument)
1004 CASE_FOR(Supports, Supports)
1005 CASE_FOR(LayerBlock, LayerBlock)
1006 CASE_FOR(LayerStatement, LayerStatement)
1007 CASE_FOR(Container, Container)
1008 CASE_FOR(Scope, Scope)
1009 CASE_FOR(StartingStyle, StartingStyle)
1010 // @namespace can only be inserted / removed when there are only other
1011 // @namespace and @import rules, and can't be mutated.
1012 case StyleCssRuleType::Namespace:
1013 break;
1014 case StyleCssRuleType::Keyframe:
1015 // FIXME: We should probably just forward to the parent @keyframes rule? I
1016 // think that'd do the right thing, but meanwhile...
1017 return MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
1020 #undef CASE_FOR
1023 void ServoStyleSet::RuleChanged(StyleSheet& aSheet, css::Rule* aRule,
1024 StyleRuleChangeKind aKind) {
1025 if (!aSheet.IsApplicable()) {
1026 return;
1029 if (!aRule) {
1030 // FIXME: This is done for StyleSheet.media attribute changes and such
1031 MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
1032 } else {
1033 RuleChangedInternal(aSheet, *aRule, aKind);
1037 void ServoStyleSet::SheetCloned(StyleSheet& aSheet) {
1038 mNeedsRestyleAfterEnsureUniqueInner = true;
1039 if (mStyleRuleMap) {
1040 mStyleRuleMap->SheetCloned(aSheet);
1044 #ifdef DEBUG
1045 void ServoStyleSet::AssertTreeIsClean() {
1046 DocumentStyleRootIterator iter(mDocument);
1047 while (Element* root = iter.GetNextStyleRoot()) {
1048 Servo_AssertTreeIsClean(root);
1051 #endif
1053 bool ServoStyleSet::GetKeyframesForName(
1054 const Element& aElement, const ComputedStyle& aStyle, nsAtom* aName,
1055 const StyleComputedTimingFunction& aTimingFunction,
1056 nsTArray<Keyframe>& aKeyframes) {
1057 MOZ_ASSERT(!StylistNeedsUpdate());
1058 return Servo_StyleSet_GetKeyframesForName(
1059 mRawData.get(), &aElement, &aStyle, aName, &aTimingFunction, &aKeyframes);
1062 nsTArray<ComputedKeyframeValues> ServoStyleSet::GetComputedKeyframeValuesFor(
1063 const nsTArray<Keyframe>& aKeyframes, Element* aElement,
1064 PseudoStyleType aPseudoType, const ComputedStyle* aStyle) {
1065 nsTArray<ComputedKeyframeValues> result(aKeyframes.Length());
1067 // Construct each nsTArray<PropertyStyleAnimationValuePair> here.
1068 result.AppendElements(aKeyframes.Length());
1070 Servo_GetComputedKeyframeValues(&aKeyframes, aElement, aPseudoType, aStyle,
1071 mRawData.get(), &result);
1072 return result;
1075 void ServoStyleSet::GetAnimationValues(
1076 StyleLockedDeclarationBlock* aDeclarations, Element* aElement,
1077 const ComputedStyle* aComputedStyle,
1078 nsTArray<RefPtr<StyleAnimationValue>>& aAnimationValues) {
1079 // Servo_GetAnimationValues below won't handle ignoring existing element
1080 // data for bfcached documents. (See comment in ResolveStyleLazily
1081 // about these bfcache issues.)
1082 Servo_GetAnimationValues(aDeclarations, aElement, aComputedStyle,
1083 mRawData.get(), &aAnimationValues);
1086 already_AddRefed<ComputedStyle> ServoStyleSet::GetBaseContextForElement(
1087 Element* aElement, const ComputedStyle* aStyle) {
1088 return Servo_StyleSet_GetBaseComputedValuesForElement(
1089 mRawData.get(), aElement, aStyle, &Snapshots())
1090 .Consume();
1093 already_AddRefed<StyleAnimationValue> ServoStyleSet::ComputeAnimationValue(
1094 Element* aElement, StyleLockedDeclarationBlock* aDeclarations,
1095 const ComputedStyle* aStyle) {
1096 return Servo_AnimationValue_Compute(aElement, aDeclarations, aStyle,
1097 mRawData.get())
1098 .Consume();
1101 bool ServoStyleSet::UsesFontMetrics() const {
1102 return Servo_StyleSet_UsesFontMetrics(mRawData.get());
1105 bool ServoStyleSet::EnsureUniqueInnerOnCSSSheets() {
1106 using SheetOwner = Variant<ServoStyleSet*, ShadowRoot*>;
1108 AutoTArray<std::pair<StyleSheet*, SheetOwner>, 32> queue;
1109 EnumerateStyleSheets([&](StyleSheet& aSheet) {
1110 queue.AppendElement(std::make_pair(&aSheet, SheetOwner{this}));
1113 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
1114 for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
1115 queue.AppendElement(
1116 std::make_pair(aShadowRoot.SheetAt(index), SheetOwner{&aShadowRoot}));
1118 for (const auto& adopted : aShadowRoot.AdoptedStyleSheets()) {
1119 queue.AppendElement(
1120 std::make_pair(adopted.get(), SheetOwner{&aShadowRoot}));
1124 while (!queue.IsEmpty()) {
1125 auto [sheet, owner] = queue.PopLastElement();
1127 if (sheet->HasForcedUniqueInner()) {
1128 // We already processed this sheet and its children.
1129 // Normally we don't hit this but adopted stylesheets can have dupes so we
1130 // can save some work here.
1131 continue;
1134 // Only call EnsureUniqueInner for complete sheets. If we do call it on
1135 // incomplete sheets, we'll cause problems when the sheet is actually
1136 // loaded. We don't care about incomplete sheets here anyway, because this
1137 // method is only invoked by nsPresContext::EnsureSafeToHandOutCSSRules.
1138 // The CSSRule objects we are handing out won't contain any rules derived
1139 // from incomplete sheets (because they aren't yet applied in styling).
1140 if (sheet->IsComplete()) {
1141 sheet->EnsureUniqueInner();
1144 // Enqueue all the sheet's children.
1145 for (StyleSheet* child : sheet->ChildSheets()) {
1146 queue.AppendElement(std::make_pair(child, owner));
1150 if (mNeedsRestyleAfterEnsureUniqueInner) {
1151 // TODO(emilio): We could make this faster if needed tracking the specific
1152 // origins and sheets that have been cloned. But the only caller of this
1153 // doesn't seem to really care about perf.
1154 MarkOriginsDirty(OriginFlags::All);
1155 ForceDirtyAllShadowStyles();
1157 bool res = mNeedsRestyleAfterEnsureUniqueInner;
1158 mNeedsRestyleAfterEnsureUniqueInner = false;
1159 return res;
1162 void ServoStyleSet::ClearCachedStyleData() {
1163 ClearNonInheritingComputedStyles();
1164 Servo_StyleSet_RebuildCachedData(mRawData.get());
1165 mCachedAnonymousContentStyles.Clear();
1166 PodArrayZero(mCachedAnonymousContentStyleIndexes);
1169 void ServoStyleSet::ForceDirtyAllShadowStyles() {
1170 bool anyShadow = false;
1171 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
1172 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
1173 anyShadow = true;
1174 Servo_AuthorStyles_ForceDirty(authorStyles);
1177 if (anyShadow) {
1178 SetStylistShadowDOMStyleSheetsDirty();
1182 void ServoStyleSet::CompatibilityModeChanged() {
1183 Servo_StyleSet_CompatModeChanged(mRawData.get());
1184 SetStylistStyleSheetsDirty();
1185 ForceDirtyAllShadowStyles();
1188 void ServoStyleSet::ClearNonInheritingComputedStyles() {
1189 for (RefPtr<ComputedStyle>& ptr : mNonInheritingComputedStyles) {
1190 ptr = nullptr;
1194 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleLazily(
1195 const Element& aElement, PseudoStyleType aPseudoType,
1196 nsAtom* aFunctionalPseudoParameter, StyleRuleInclusion aRuleInclusion) {
1197 PreTraverseSync();
1198 MOZ_ASSERT(!StylistNeedsUpdate());
1200 AutoSetInServoTraversal guard(this);
1203 * NB: This is needed because we process animations and transitions on the
1204 * pseudo-elements themselves, not on the parent's EagerPseudoStyles.
1206 * That means that that style doesn't account for animations, and we can't do
1207 * that easily from the traversal without doing wasted work.
1209 * As such, we just lie here a bit, which is the entrypoint of
1210 * getComputedStyle, the only API where this can be observed, to look at the
1211 * style of the pseudo-element if it exists instead.
1213 const Element* elementForStyleResolution = &aElement;
1214 PseudoStyleType pseudoTypeForStyleResolution = aPseudoType;
1215 if (aPseudoType == PseudoStyleType::before) {
1216 if (Element* pseudo = nsLayoutUtils::GetBeforePseudo(&aElement)) {
1217 elementForStyleResolution = pseudo;
1218 pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
1220 } else if (aPseudoType == PseudoStyleType::after) {
1221 if (Element* pseudo = nsLayoutUtils::GetAfterPseudo(&aElement)) {
1222 elementForStyleResolution = pseudo;
1223 pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
1225 } else if (aPseudoType == PseudoStyleType::marker) {
1226 if (Element* pseudo = nsLayoutUtils::GetMarkerPseudo(&aElement)) {
1227 elementForStyleResolution = pseudo;
1228 pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
1232 nsPresContext* pc = GetPresContext();
1233 MOZ_ASSERT(pc, "For now, no style resolution without a pres context");
1234 auto* restyleManager = pc->RestyleManager();
1235 const bool canUseCache = aRuleInclusion == StyleRuleInclusion::All &&
1236 aElement.OwnerDoc() == mDocument &&
1237 pc->PresShell()->DidInitialize();
1238 return Servo_ResolveStyleLazily(
1239 elementForStyleResolution, pseudoTypeForStyleResolution,
1240 aFunctionalPseudoParameter, aRuleInclusion,
1241 &restyleManager->Snapshots(),
1242 restyleManager->GetUndisplayedRestyleGeneration(), canUseCache,
1243 mRawData.get())
1244 .Consume();
1247 void ServoStyleSet::AppendFontFaceRules(
1248 nsTArray<nsFontFaceRuleContainer>& aArray) {
1249 // TODO(emilio): Can we make this so this asserts instead?
1250 UpdateStylistIfNeeded();
1251 Servo_StyleSet_GetFontFaceRules(mRawData.get(), &aArray);
1254 const StyleLockedCounterStyleRule* ServoStyleSet::CounterStyleRuleForName(
1255 nsAtom* aName) {
1256 MOZ_ASSERT(!StylistNeedsUpdate());
1257 return Servo_StyleSet_GetCounterStyleRule(mRawData.get(), aName);
1260 already_AddRefed<gfxFontFeatureValueSet>
1261 ServoStyleSet::BuildFontFeatureValueSet() {
1262 MOZ_ASSERT(!StylistNeedsUpdate());
1263 RefPtr<gfxFontFeatureValueSet> set =
1264 Servo_StyleSet_BuildFontFeatureValueSet(mRawData.get());
1265 return set.forget();
1268 already_AddRefed<gfx::FontPaletteValueSet>
1269 ServoStyleSet::BuildFontPaletteValueSet() {
1270 MOZ_ASSERT(!StylistNeedsUpdate());
1271 RefPtr<gfx::FontPaletteValueSet> set =
1272 Servo_StyleSet_BuildFontPaletteValueSet(mRawData.get());
1273 return set.forget();
1276 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveForDeclarations(
1277 const ComputedStyle* aParentOrNull,
1278 const StyleLockedDeclarationBlock* aDeclarations) {
1279 // No need to update the stylist, we're only cascading aDeclarations.
1280 return Servo_StyleSet_ResolveForDeclarations(mRawData.get(), aParentOrNull,
1281 aDeclarations)
1282 .Consume();
1285 void ServoStyleSet::UpdateStylist() {
1286 AUTO_PROFILER_LABEL_RELEVANT_FOR_JS("Update stylesheet information", LAYOUT);
1287 MOZ_ASSERT(StylistNeedsUpdate());
1289 if (mStylistState & StylistState::StyleSheetsDirty) {
1290 Element* root = mDocument->GetRootElement();
1291 const ServoElementSnapshotTable* snapshots = nullptr;
1292 if (nsPresContext* pc = GetPresContext()) {
1293 snapshots = &pc->RestyleManager()->Snapshots();
1295 Servo_StyleSet_FlushStyleSheets(mRawData.get(), root, snapshots);
1298 if (MOZ_UNLIKELY(mStylistState & StylistState::ShadowDOMStyleSheetsDirty)) {
1299 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
1300 if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
1301 Servo_AuthorStyles_Flush(authorStyles, mRawData.get());
1304 Servo_StyleSet_RemoveUniqueEntriesFromAuthorStylesCache(mRawData.get());
1307 mStylistState = StylistState::NotDirty;
1310 void ServoStyleSet::MaybeGCRuleTree() {
1311 MOZ_ASSERT(NS_IsMainThread());
1312 Servo_MaybeGCRuleTree(mRawData.get());
1315 /* static */
1316 bool ServoStyleSet::MayTraverseFrom(const Element* aElement) {
1317 MOZ_ASSERT(aElement->IsInComposedDoc());
1318 nsINode* parent = aElement->GetFlattenedTreeParentNodeForStyle();
1319 if (!parent) {
1320 return false;
1323 if (!parent->IsElement()) {
1324 MOZ_ASSERT(parent->IsDocument());
1325 return true;
1328 if (!parent->AsElement()->HasServoData()) {
1329 return false;
1332 return !Servo_Element_IsDisplayNone(parent->AsElement());
1335 bool ServoStyleSet::ShouldTraverseInParallel() const {
1336 MOZ_ASSERT(mDocument->GetPresShell(), "Styling a document without a shell?");
1337 if (!mDocument->GetPresShell()->IsActive()) {
1338 return false;
1340 if (profiler_feature_active(ProfilerFeature::SequentialStyle)) {
1341 return false;
1343 return true;
1346 void ServoStyleSet::RunPostTraversalTasks() {
1347 MOZ_ASSERT(!IsInServoTraversal());
1349 if (mPostTraversalTasks.IsEmpty()) {
1350 return;
1353 nsTArray<PostTraversalTask> tasks = std::move(mPostTraversalTasks);
1355 for (auto& task : tasks) {
1356 task.Run();
1360 ServoStyleRuleMap* ServoStyleSet::StyleRuleMap() {
1361 if (!mStyleRuleMap) {
1362 mStyleRuleMap = MakeUnique<ServoStyleRuleMap>();
1364 mStyleRuleMap->EnsureTable(*this);
1365 return mStyleRuleMap.get();
1368 bool ServoStyleSet::MightHaveAttributeDependency(const Element& aElement,
1369 nsAtom* aAttribute) const {
1370 return Servo_StyleSet_MightHaveAttributeDependency(mRawData.get(), &aElement,
1371 aAttribute);
1374 bool ServoStyleSet::MightHaveNthOfIDDependency(const Element& aElement,
1375 nsAtom* aOldID,
1376 nsAtom* aNewID) const {
1377 return Servo_StyleSet_MightHaveNthOfIDDependency(mRawData.get(), &aElement,
1378 aOldID, aNewID);
1381 bool ServoStyleSet::MightHaveNthOfClassDependency(const Element& aElement) {
1382 return Servo_StyleSet_MightHaveNthOfClassDependency(mRawData.get(), &aElement,
1383 &Snapshots());
1386 void ServoStyleSet::MaybeInvalidateRelativeSelectorIDDependency(
1387 const Element& aElement, nsAtom* aOldID, nsAtom* aNewID,
1388 const ServoElementSnapshotTable& aSnapshots) {
1389 Servo_StyleSet_MaybeInvalidateRelativeSelectorIDDependency(
1390 mRawData.get(), &aElement, aOldID, aNewID, &aSnapshots);
1393 void ServoStyleSet::MaybeInvalidateRelativeSelectorClassDependency(
1394 const Element& aElement, const ServoElementSnapshotTable& aSnapshots) {
1395 Servo_StyleSet_MaybeInvalidateRelativeSelectorClassDependency(
1396 mRawData.get(), &aElement, &aSnapshots);
1399 void ServoStyleSet::MaybeInvalidateRelativeSelectorCustomStateDependency(
1400 const Element& aElement, nsAtom* state,
1401 const ServoElementSnapshotTable& aSnapshots) {
1402 Servo_StyleSet_MaybeInvalidateRelativeSelectorCustomStateDependency(
1403 mRawData.get(), &aElement, state, &aSnapshots);
1406 void ServoStyleSet::MaybeInvalidateRelativeSelectorAttributeDependency(
1407 const Element& aElement, nsAtom* aAttribute,
1408 const ServoElementSnapshotTable& aSnapshots) {
1409 Servo_StyleSet_MaybeInvalidateRelativeSelectorAttributeDependency(
1410 mRawData.get(), &aElement, aAttribute, &aSnapshots);
1413 void ServoStyleSet::MaybeInvalidateRelativeSelectorStateDependency(
1414 const Element& aElement, ElementState aState,
1415 const ServoElementSnapshotTable& aSnapshots) {
1416 Servo_StyleSet_MaybeInvalidateRelativeSelectorStateDependency(
1417 mRawData.get(), &aElement, aState.GetInternalValue(), &aSnapshots);
1420 void ServoStyleSet::MaybeInvalidateRelativeSelectorForEmptyDependency(
1421 const Element& aElement) {
1422 Servo_StyleSet_MaybeInvalidateRelativeSelectorEmptyDependency(mRawData.get(),
1423 &aElement);
1426 void ServoStyleSet::MaybeInvalidateRelativeSelectorForNthEdgeDependency(
1427 const Element& aElement) {
1428 Servo_StyleSet_MaybeInvalidateRelativeSelectorNthEdgeDependency(
1429 mRawData.get(), &aElement);
1432 void ServoStyleSet::MaybeInvalidateRelativeSelectorForNthDependencyFromSibling(
1433 const Element* aFromSibling) {
1434 if (aFromSibling == nullptr) {
1435 return;
1437 Servo_StyleSet_MaybeInvalidateRelativeSelectorNthDependencyFromSibling(
1438 mRawData.get(), aFromSibling);
1441 void ServoStyleSet::MaybeInvalidateForElementInsertion(
1442 const Element& aElement) {
1443 Servo_StyleSet_MaybeInvalidateRelativeSelectorForInsertion(mRawData.get(),
1444 &aElement);
1447 void ServoStyleSet::MaybeInvalidateForElementAppend(
1448 const nsIContent& aFirstContent) {
1449 Servo_StyleSet_MaybeInvalidateRelativeSelectorForAppend(mRawData.get(),
1450 &aFirstContent);
1453 void ServoStyleSet::MaybeInvalidateForElementRemove(
1454 const Element& aElement, const nsIContent* aFollowingSibling) {
1455 Servo_StyleSet_MaybeInvalidateRelativeSelectorForRemoval(
1456 mRawData.get(), &aElement, aFollowingSibling);
1459 bool ServoStyleSet::MightHaveNthOfAttributeDependency(
1460 const Element& aElement, nsAtom* aAttribute) const {
1461 return Servo_StyleSet_MightHaveNthOfAttributeDependency(
1462 mRawData.get(), &aElement, aAttribute);
1465 bool ServoStyleSet::HasStateDependency(const Element& aElement,
1466 dom::ElementState aState) const {
1467 return Servo_StyleSet_HasStateDependency(mRawData.get(), &aElement,
1468 aState.GetInternalValue());
1471 bool ServoStyleSet::HasNthOfStateDependency(const Element& aElement,
1472 dom::ElementState aState) const {
1473 return Servo_StyleSet_HasNthOfStateDependency(mRawData.get(), &aElement,
1474 aState.GetInternalValue());
1477 bool ServoStyleSet::HasNthOfCustomStateDependency(const Element& aElement,
1478 nsAtom* aState) const {
1479 return Servo_StyleSet_HasNthOfCustomStateDependency(mRawData.get(), &aElement,
1480 aState);
1483 void ServoStyleSet::RestyleSiblingsForNthOf(const Element& aElement,
1484 uint32_t aFlags) const {
1485 Servo_StyleSet_RestyleSiblingsForNthOf(&aElement, aFlags);
1488 bool ServoStyleSet::HasDocumentStateDependency(
1489 dom::DocumentState aState) const {
1490 return Servo_StyleSet_HasDocumentStateDependency(mRawData.get(),
1491 aState.GetInternalValue());
1494 already_AddRefed<ComputedStyle> ServoStyleSet::ReparentComputedStyle(
1495 ComputedStyle* aComputedStyle, ComputedStyle* aNewParent,
1496 ComputedStyle* aNewLayoutParent, Element* aElement) {
1497 return Servo_ReparentStyle(aComputedStyle, aNewParent, aNewLayoutParent,
1498 aElement, mRawData.get())
1499 .Consume();
1502 void ServoStyleSet::InvalidateForViewportUnits(OnlyDynamic aOnlyDynamic) {
1503 dom::Element* root = mDocument->GetRootElement();
1504 if (!root) {
1505 return;
1508 Servo_InvalidateForViewportUnits(mRawData.get(), root,
1509 aOnlyDynamic == OnlyDynamic::Yes);
1512 void ServoStyleSet::RegisterProperty(const PropertyDefinition& aDefinition,
1513 ErrorResult& aRv) {
1514 using Result = StyleRegisterCustomPropertyResult;
1515 auto result = Servo_RegisterCustomProperty(
1516 RawData(), mDocument->DefaultStyleAttrURLData(), &aDefinition.mName,
1517 &aDefinition.mSyntax, aDefinition.mInherits,
1518 aDefinition.mInitialValue.WasPassed() ? &aDefinition.mInitialValue.Value()
1519 : nullptr);
1520 switch (result) {
1521 case Result::SuccessfullyRegistered:
1522 if (Element* root = mDocument->GetRootElement()) {
1523 if (nsPresContext* pc = GetPresContext()) {
1524 pc->RestyleManager()->PostRestyleEvent(
1525 root, RestyleHint::RecascadeSubtree(), nsChangeHint(0));
1528 mDocument->PostCustomPropertyRegistered(aDefinition);
1529 break;
1530 case Result::InvalidName:
1531 return aRv.ThrowSyntaxError("Invalid name");
1532 case Result::InvalidSyntax:
1533 return aRv.ThrowSyntaxError("Invalid syntax descriptor");
1534 case Result::InvalidInitialValue:
1535 return aRv.ThrowSyntaxError("Invalid initial value syntax");
1536 case Result::NoInitialValue:
1537 return aRv.ThrowSyntaxError(
1538 "Initial value is required when syntax is not universal");
1539 case Result::InitialValueNotComputationallyIndependent:
1540 return aRv.ThrowSyntaxError(
1541 "Initial value is required when syntax is not universal");
1542 case Result::AlreadyRegistered:
1543 return aRv.ThrowInvalidModificationError("Property already registered");
1547 NS_IMPL_ISUPPORTS(UACacheReporter, nsIMemoryReporter)
1549 MOZ_DEFINE_MALLOC_SIZE_OF(ServoUACacheMallocSizeOf)
1550 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoUACacheMallocEnclosingSizeOf)
1552 NS_IMETHODIMP
1553 UACacheReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
1554 nsISupports* aData, bool aAnonymize) {
1555 ServoStyleSetSizes sizes;
1556 Servo_UACache_AddSizeOf(ServoUACacheMallocSizeOf,
1557 ServoUACacheMallocEnclosingSizeOf, &sizes);
1559 #define REPORT(_path, _amount, _desc) \
1560 do { \
1561 size_t __amount = _amount; /* evaluate _amount only once */ \
1562 if (__amount > 0) { \
1563 MOZ_COLLECT_REPORT(_path, KIND_HEAP, UNITS_BYTES, __amount, _desc); \
1565 } while (0)
1567 // The UA cache does not contain the rule tree; that's in the StyleSet.
1568 MOZ_RELEASE_ASSERT(sizes.mRuleTree == 0);
1570 REPORT("explicit/layout/servo-ua-cache/precomputed-pseudos",
1571 sizes.mPrecomputedPseudos,
1572 "Memory used by precomputed pseudo-element declarations within the "
1573 "UA cache.");
1575 REPORT("explicit/layout/servo-ua-cache/element-and-pseudos-maps",
1576 sizes.mElementAndPseudosMaps,
1577 "Memory used by element and pseudos maps within the UA cache.");
1579 REPORT("explicit/layout/servo-ua-cache/invalidation-map",
1580 sizes.mInvalidationMap,
1581 "Memory used by invalidation maps within the UA cache.");
1583 REPORT("explicit/layout/servo-ua-cache/revalidation-selectors",
1584 sizes.mRevalidationSelectors,
1585 "Memory used by selectors for cache revalidation within the UA "
1586 "cache.");
1588 REPORT("explicit/layout/servo-ua-cache/other", sizes.mOther,
1589 "Memory used by other data within the UA cache");
1591 return NS_OK;
1594 } // namespace mozilla