ServoStyleSet.cpp (60356B)
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/. */ 6 7 #include "mozilla/ServoStyleSet.h" 8 9 #include "gfxUserFontSet.h" 10 #include "mozilla/AttributeStyles.h" 11 #include "mozilla/DeclarationBlock.h" 12 #include "mozilla/DocumentStyleRootIterator.h" 13 #include "mozilla/EffectCompositor.h" 14 #include "mozilla/IntegerRange.h" 15 #include "mozilla/Keyframe.h" 16 #include "mozilla/LookAndFeel.h" 17 #include "mozilla/MediaFeatureChange.h" 18 #include "mozilla/PresShell.h" 19 #include "mozilla/ProfilerLabels.h" 20 #include "mozilla/RestyleManager.h" 21 #include "mozilla/SMILAnimationController.h" 22 #include "mozilla/ServoBindings.h" 23 #include "mozilla/ServoStyleRuleMap.h" 24 #include "mozilla/ServoStyleSetInlines.h" 25 #include "mozilla/ServoTypes.h" 26 #include "mozilla/StyleAnimationValue.h" 27 #include "mozilla/css/Loader.h" 28 #include "mozilla/dom/AnonymousContent.h" 29 #include "mozilla/dom/CSSBinding.h" 30 #include "mozilla/dom/CSSContainerRule.h" 31 #include "mozilla/dom/CSSCounterStyleRule.h" 32 #include "mozilla/dom/CSSCustomMediaRule.h" 33 #include "mozilla/dom/CSSFontFaceRule.h" 34 #include "mozilla/dom/CSSFontFeatureValuesRule.h" 35 #include "mozilla/dom/CSSFontPaletteValuesRule.h" 36 #include "mozilla/dom/CSSImportRule.h" 37 #include "mozilla/dom/CSSKeyframeRule.h" 38 #include "mozilla/dom/CSSKeyframesRule.h" 39 #include "mozilla/dom/CSSLayerBlockRule.h" 40 #include "mozilla/dom/CSSLayerStatementRule.h" 41 #include "mozilla/dom/CSSMarginRule.h" 42 #include "mozilla/dom/CSSMediaRule.h" 43 #include "mozilla/dom/CSSMozDocumentRule.h" 44 #include "mozilla/dom/CSSNamespaceRule.h" 45 #include "mozilla/dom/CSSNestedDeclarations.h" 46 #include "mozilla/dom/CSSPageRule.h" 47 #include "mozilla/dom/CSSPositionTryRule.h" 48 #include "mozilla/dom/CSSPropertyRule.h" 49 #include "mozilla/dom/CSSScopeRule.h" 50 #include "mozilla/dom/CSSStartingStyleRule.h" 51 #include "mozilla/dom/CSSStyleRule.h" 52 #include "mozilla/dom/CSSSupportsRule.h" 53 #include "mozilla/dom/DocumentInlines.h" 54 #include "mozilla/dom/Element.h" 55 #include "mozilla/dom/ElementInlines.h" 56 #include "mozilla/dom/FontFaceSet.h" 57 #include "mozilla/dom/ViewTransition.h" 58 #include "nsCSSAnonBoxes.h" 59 #include "nsCSSFrameConstructor.h" 60 #include "nsCSSPseudoElements.h" 61 #include "nsDeviceContext.h" 62 #include "nsIAnonymousContentCreator.h" 63 #include "nsLayoutUtils.h" 64 #include "nsPrintfCString.h" 65 #include "nsWindowSizes.h" 66 67 namespace mozilla { 68 69 using namespace dom; 70 71 #ifdef DEBUG 72 bool ServoStyleSet::IsCurrentThreadInServoTraversal() { 73 return sInServoTraversal && (NS_IsMainThread() || Servo_IsWorkerThread()); 74 } 75 #endif 76 77 // The definition of kOrigins relies on this. 78 static_assert(static_cast<uint8_t>(StyleOrigin::UserAgent) == 79 static_cast<uint8_t>(OriginFlags::UserAgent)); 80 static_assert(static_cast<uint8_t>(StyleOrigin::User) == 81 static_cast<uint8_t>(OriginFlags::User)); 82 static_assert(static_cast<uint8_t>(StyleOrigin::Author) == 83 static_cast<uint8_t>(OriginFlags::Author)); 84 85 constexpr const StyleOrigin ServoStyleSet::kOrigins[]; 86 87 ServoStyleSet* sInServoTraversal = nullptr; 88 89 // On construction, sets sInServoTraversal to the given ServoStyleSet. 90 // On destruction, clears sInServoTraversal and calls RunPostTraversalTasks. 91 class MOZ_RAII AutoSetInServoTraversal { 92 public: 93 explicit AutoSetInServoTraversal(ServoStyleSet* aSet) : mSet(aSet) { 94 MOZ_ASSERT(!sInServoTraversal); 95 MOZ_ASSERT(aSet); 96 sInServoTraversal = aSet; 97 } 98 99 ~AutoSetInServoTraversal() { 100 MOZ_ASSERT(sInServoTraversal); 101 sInServoTraversal = nullptr; 102 mSet->RunPostTraversalTasks(); 103 } 104 105 private: 106 ServoStyleSet* mSet; 107 }; 108 109 // Sets up for one or more calls to Servo_TraverseSubtree. 110 class MOZ_RAII AutoPrepareTraversal : public AutoSetInServoTraversal { 111 public: 112 explicit AutoPrepareTraversal(ServoStyleSet* aSet) 113 : AutoSetInServoTraversal(aSet) { 114 MOZ_ASSERT(!aSet->StylistNeedsUpdate()); 115 } 116 }; 117 118 ServoStyleSet::ServoStyleSet(Document& aDocument) : mDocument(&aDocument) { 119 PodArrayZero(mCachedAnonymousContentStyleIndexes); 120 mRawData.reset(Servo_StyleSet_Init(&aDocument)); 121 } 122 123 ServoStyleSet::~ServoStyleSet() { 124 MOZ_ASSERT(!IsInServoTraversal()); 125 EnumerateStyleSheets([&](StyleSheet& aSheet) { aSheet.DropStyleSet(this); }); 126 } 127 128 nsPresContext* ServoStyleSet::GetPresContext() { 129 return mDocument->GetPresContext(); 130 } 131 132 template <typename Functor> 133 static void EnumerateShadowRoots(const Document& aDoc, const Functor& aCb) { 134 const Document::ShadowRootSet& shadowRoots = aDoc.ComposedShadowRoots(); 135 for (ShadowRoot* root : shadowRoots) { 136 MOZ_ASSERT(root); 137 MOZ_DIAGNOSTIC_ASSERT(root->IsInComposedDoc()); 138 aCb(*root); 139 } 140 } 141 142 void ServoStyleSet::ShellDetachedFromDocument() { 143 ClearNonInheritingComputedStyles(); 144 mCachedAnonymousContentStyles.Clear(); 145 PodArrayZero(mCachedAnonymousContentStyleIndexes); 146 mStyleRuleMap = nullptr; 147 148 // Remove all our stylesheets... 149 for (auto origin : kOrigins) { 150 for (size_t count = SheetCount(origin); count--;) { 151 RemoveStyleSheet(*SheetAt(origin, count)); 152 } 153 } 154 155 // And remove all the CascadeDatas from memory. 156 UpdateStylistIfNeeded(); 157 158 // Also GC the ruletree if it got big now that the DOM no longer has 159 // references to styles around anymore. 160 MaybeGCRuleTree(); 161 } 162 163 void ServoStyleSet::RecordShadowStyleChange(ShadowRoot& aShadowRoot) { 164 // TODO(emilio): We could keep track of the actual shadow roots that need 165 // their styles recomputed. 166 SetStylistShadowDOMStyleSheetsDirty(); 167 168 // FIXME(emilio): This should be done using stylesheet invalidation instead. 169 if (nsPresContext* pc = GetPresContext()) { 170 pc->RestyleManager()->PostRestyleEvent( 171 aShadowRoot.Host(), RestyleHint::RestyleSubtree(), nsChangeHint(0)); 172 } 173 } 174 175 void ServoStyleSet::InvalidateStyleForDocumentStateChanges( 176 DocumentState aStatesChanged) { 177 MOZ_ASSERT(mDocument); 178 MOZ_ASSERT(!aStatesChanged.IsEmpty()); 179 180 nsPresContext* pc = GetPresContext(); 181 if (!pc) { 182 return; 183 } 184 185 Element* root = mDocument->GetRootElement(); 186 if (!root) { 187 return; 188 } 189 190 // TODO(emilio): It may be nicer to just invalidate stuff in a given subtree 191 // for Shadow DOM. Consider just enumerating shadow roots instead and run 192 // invalidation individually, passing mRawData for the UA / User sheets. 193 AutoTArray<const StyleAuthorStyles*, 20> nonDocumentStyles; 194 195 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) { 196 if (auto* authorStyles = aShadowRoot.GetServoStyles()) { 197 nonDocumentStyles.AppendElement(authorStyles); 198 } 199 }); 200 201 Servo_InvalidateStyleForDocStateChanges(root, mRawData.get(), 202 &nonDocumentStyles, 203 aStatesChanged.GetInternalValue()); 204 } 205 206 static const MediaFeatureChangeReason kMediaFeaturesAffectingDefaultStyle = 207 // Zoom changes change the meaning of em units. 208 MediaFeatureChangeReason::ZoomChange | 209 // A resolution change changes the app-units-per-dev-pixels ratio, which 210 // some structs (Border, Outline, Column) store for clamping. We should 211 // arguably not do that, maybe doing it on layout directly, to try to avoid 212 // relying on the pres context (bug 1418159). 213 MediaFeatureChangeReason::ResolutionChange; 214 215 RestyleHint ServoStyleSet::MediumFeaturesChanged( 216 MediaFeatureChangeReason aReason) { 217 AutoTArray<StyleAuthorStyles*, 20> nonDocumentStyles; 218 219 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) { 220 if (auto* authorStyles = aShadowRoot.GetServoStyles()) { 221 nonDocumentStyles.AppendElement(authorStyles); 222 } 223 }); 224 225 const bool mayAffectDefaultStyle = 226 bool(aReason & kMediaFeaturesAffectingDefaultStyle); 227 const MediumFeaturesChangedResult result = 228 Servo_StyleSet_MediumFeaturesChanged(mRawData.get(), &nonDocumentStyles, 229 mayAffectDefaultStyle); 230 231 const bool viewportChanged = 232 bool(aReason & MediaFeatureChangeReason::ViewportChange); 233 if (viewportChanged) { 234 InvalidateForViewportUnits(OnlyDynamic::No); 235 } 236 237 const bool rulesChanged = 238 result.mAffectsDocumentRules || result.mAffectsNonDocumentRules; 239 240 if (result.mAffectsDocumentRules) { 241 SetStylistStyleSheetsDirty(); 242 } 243 244 if (result.mAffectsNonDocumentRules) { 245 SetStylistShadowDOMStyleSheetsDirty(); 246 } 247 248 if (rulesChanged) { 249 // TODO(emilio): This could be more granular. 250 return RestyleHint::RestyleSubtree(); 251 } 252 253 return RestyleHint{0}; 254 } 255 256 MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSetMallocSizeOf) 257 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSetMallocEnclosingSizeOf) 258 259 void ServoStyleSet::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const { 260 MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf; 261 262 aSizes.mLayoutStyleSetsOther += mallocSizeOf(this); 263 264 if (mRawData) { 265 aSizes.mLayoutStyleSetsOther += mallocSizeOf(mRawData.get()); 266 ServoStyleSetSizes sizes; 267 // Measure mRawData. We use ServoStyleSetMallocSizeOf rather than 268 // aMallocSizeOf to distinguish in DMD's output the memory measured within 269 // Servo code. 270 Servo_StyleSet_AddSizeOfExcludingThis(ServoStyleSetMallocSizeOf, 271 ServoStyleSetMallocEnclosingSizeOf, 272 &sizes, mRawData.get()); 273 274 // The StyleSet does not contain precomputed pseudos; they are in the UA 275 // cache. 276 MOZ_RELEASE_ASSERT(sizes.mPrecomputedPseudos == 0); 277 278 aSizes.mLayoutStyleSetsStylistRuleTree += sizes.mRuleTree; 279 aSizes.mLayoutStyleSetsStylistElementAndPseudosMaps += 280 sizes.mElementAndPseudosMaps; 281 aSizes.mLayoutStyleSetsStylistInvalidationMap += sizes.mInvalidationMap; 282 aSizes.mLayoutStyleSetsStylistRevalidationSelectors += 283 sizes.mRevalidationSelectors; 284 aSizes.mLayoutStyleSetsStylistOther += sizes.mOther; 285 } 286 287 if (mStyleRuleMap) { 288 aSizes.mLayoutStyleSetsOther += 289 mStyleRuleMap->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf); 290 } 291 292 // Measurement of the following members may be added later if DMD finds it is 293 // worthwhile: 294 // - mSheets 295 // - mNonInheritingComputedStyles 296 // 297 // The following members are not measured: 298 // - mDocument, because it a non-owning pointer 299 } 300 301 void ServoStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled) { 302 if (mAuthorStyleDisabled == aStyleDisabled) { 303 return; 304 } 305 306 mAuthorStyleDisabled = aStyleDisabled; 307 if (Element* root = mDocument->GetRootElement()) { 308 if (nsPresContext* pc = GetPresContext()) { 309 pc->RestyleManager()->PostRestyleEvent( 310 root, RestyleHint::RestyleSubtree(), nsChangeHint(0)); 311 } 312 } 313 Servo_StyleSet_SetAuthorStyleDisabled(mRawData.get(), mAuthorStyleDisabled); 314 // XXX Workaround for bug 1437785. 315 SetStylistStyleSheetsDirty(); 316 } 317 318 const ServoElementSnapshotTable& ServoStyleSet::Snapshots() { 319 MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?"); 320 return GetPresContext()->RestyleManager()->Snapshots(); 321 } 322 323 void ServoStyleSet::PreTraverseSync() { 324 // Get the Document's root element to ensure that the cache is valid before 325 // calling into the (potentially-parallel) Servo traversal, where a cache hit 326 // is necessary to avoid a data race when updating the cache. 327 (void)mDocument->GetRootElement(); 328 329 // FIXME(emilio): These two shouldn't be needed in theory, the call to the 330 // same function in PresShell should do the work, but as it turns out we 331 // ProcessPendingRestyles() twice, and runnables from frames just constructed 332 // can end up doing editing stuff, which adds stylesheets etc... 333 mDocument->FlushUserFontSet(); 334 UpdateStylistIfNeeded(); 335 336 mDocument->ResolveScheduledPresAttrs(); 337 338 mDocument->CacheAllKnownLangPrefs(); 339 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"); 344 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; 351 } 352 } 353 354 MOZ_ASSERT(!StylistNeedsUpdate()); 355 } 356 357 void ServoStyleSet::PreTraverse(ServoTraversalFlags aFlags, Element* aRoot) { 358 PreTraverseSync(); 359 360 // Process animation stuff that we should avoid doing during the parallel 361 // traversal. 362 SMILAnimationController* smilController = 363 mDocument->HasAnimationController() ? mDocument->GetAnimationController() 364 : nullptr; 365 366 MOZ_ASSERT(GetPresContext()); 367 if (aRoot) { 368 GetPresContext()->EffectCompositor()->PreTraverseInSubtree(aFlags, aRoot); 369 if (smilController) { 370 smilController->PreTraverseInSubtree(aRoot); 371 } 372 } else { 373 GetPresContext()->EffectCompositor()->PreTraverse(aFlags); 374 if (smilController) { 375 smilController->PreTraverse(); 376 } 377 } 378 } 379 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; 389 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); 397 } 398 399 return style.forget(); 400 } 401 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); 407 408 return ResolveStyleForTextOrFirstLetterContinuation( 409 mRawData.get(), *aParentStyle, PseudoStyleType::mozText); 410 } 411 412 already_AddRefed<ComputedStyle> 413 ServoStyleSet::ResolveStyleForFirstLetterContinuation( 414 ComputedStyle* aParentStyle) { 415 MOZ_ASSERT(aParentStyle); 416 417 return ResolveStyleForTextOrFirstLetterContinuation( 418 mRawData.get(), *aParentStyle, PseudoStyleType::firstLetterContinuation); 419 } 420 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(); 427 } 428 429 RefPtr<ComputedStyle> computedValues = 430 Servo_ComputedValues_Inherit(mRawData.get(), 431 PseudoStyleType::oofPlaceholder, nullptr, 432 InheritTarget::PlaceholderFrame) 433 .Consume(); 434 MOZ_ASSERT(computedValues); 435 436 cache = computedValues; 437 return computedValues.forget(); 438 } 439 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); 447 } 448 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)); 457 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; 465 466 const bool isProbe = aIsProbe == IsProbe::Yes; 467 468 if (!style) { 469 // FIXME(emilio): Why passing null for probing as the parent style? 470 // 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; 480 } 481 if (cacheable) { 482 aParentStyle->SetCachedLazyPseudoStyle(style); 483 } 484 } 485 486 MOZ_ASSERT(style); 487 488 if (isProbe && !GeneratedContentPseudoExists(*aParentStyle, *style)) { 489 return nullptr; 490 } 491 492 return style.forget(); 493 } 494 495 already_AddRefed<ComputedStyle> 496 ServoStyleSet::ResolveInheritingAnonymousBoxStyle(PseudoStyleType aType, 497 ComputedStyle* aParentStyle) { 498 MOZ_ASSERT(PseudoStyle::IsInheritingAnonBox(aType)); 499 MOZ_ASSERT_IF(aParentStyle, !StylistNeedsUpdate()); 500 501 UpdateStylistIfNeeded(); 502 503 RefPtr<ComputedStyle> style = nullptr; 504 505 if (aParentStyle) { 506 style = aParentStyle->GetCachedInheritingAnonBoxStyle(aType); 507 } 508 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); 516 } 517 } 518 519 return style.forget(); 520 } 521 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)); 527 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(); 534 } 535 536 UpdateStylistIfNeeded(); 537 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"); 544 545 RefPtr<ComputedStyle> computedValues = 546 Servo_ComputedValues_GetForAnonymousBox(nullptr, aType, mRawData.get()) 547 .Consume(); 548 MOZ_ASSERT(computedValues); 549 550 cache = computedValues; 551 return computedValues.forget(); 552 } 553 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; 562 } 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(); 571 } 572 573 UpdateStylistIfNeeded(); 574 575 RefPtr<ComputedStyle> computedValues = 576 Servo_ComputedValues_GetForPageContent(mRawData.get(), aPageName, aPseudo) 577 .Consume(); 578 MOZ_ASSERT(computedValues); 579 580 if (useCache) { 581 cache = computedValues; 582 } 583 return computedValues.forget(); 584 } 585 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"); 593 594 return Servo_ComputedValues_ResolveXULTreePseudoStyle( 595 aParentElement, aPseudoTag, aParentStyle, &aInputWord, 596 mRawData.get()) 597 .Consume(); 598 } 599 600 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStartingStyle( 601 dom::Element& aElement) { 602 nsPresContext* pc = GetPresContext(); 603 if (!pc) { 604 return nullptr; 605 } 606 607 return Servo_ResolveStartingStyle( 608 &aElement, &pc->RestyleManager()->Snapshots(), mRawData.get()) 609 .Consume(); 610 } 611 612 already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePositionTry( 613 dom::Element& aElement, ComputedStyle& aStyle, 614 const StylePositionTryFallbacksItem& aFallback) { 615 return Servo_ComputedValues_GetForPositionTry(mRawData.get(), &aStyle, 616 &aElement, &aFallback) 617 .Consume(); 618 } 619 620 // manage the set of style sheets in the style set 621 void ServoStyleSet::AppendStyleSheet(StyleSheet& aSheet) { 622 MOZ_ASSERT(aSheet.IsApplicable()); 623 MOZ_ASSERT(aSheet.RawContents(), 624 "Raw sheet should be in place before insertion."); 625 626 aSheet.AddStyleSet(this); 627 628 // Maintain a mirrored list of sheets on the servo side. 629 // Servo will remove aSheet from its original position as part of the call 630 // to Servo_StyleSet_AppendStyleSheet. 631 Servo_StyleSet_AppendStyleSheet(mRawData.get(), &aSheet); 632 SetStylistStyleSheetsDirty(); 633 634 if (mStyleRuleMap) { 635 mStyleRuleMap->SheetAdded(aSheet); 636 } 637 } 638 639 void ServoStyleSet::RemoveStyleSheet(StyleSheet& aSheet) { 640 aSheet.DropStyleSet(this); 641 642 // Maintain a mirrored list of sheets on the servo side. 643 Servo_StyleSet_RemoveStyleSheet(mRawData.get(), &aSheet); 644 SetStylistStyleSheetsDirty(); 645 646 if (mStyleRuleMap) { 647 mStyleRuleMap->SheetRemoved(aSheet); 648 } 649 } 650 651 void ServoStyleSet::InsertStyleSheetBefore(StyleSheet& aNewSheet, 652 StyleSheet& aReferenceSheet) { 653 MOZ_ASSERT(aNewSheet.IsApplicable()); 654 MOZ_ASSERT(aReferenceSheet.IsApplicable()); 655 MOZ_ASSERT(&aNewSheet != &aReferenceSheet, 656 "Can't place sheet before itself."); 657 MOZ_ASSERT(aNewSheet.GetOrigin() == aReferenceSheet.GetOrigin(), 658 "Sheets should be in the same origin"); 659 MOZ_ASSERT(aNewSheet.RawContents(), 660 "Raw sheet should be in place before insertion."); 661 MOZ_ASSERT(aReferenceSheet.RawContents(), 662 "Reference sheet should have a raw sheet."); 663 664 // Servo will remove aNewSheet from its original position as part of the 665 // call to Servo_StyleSet_InsertStyleSheetBefore. 666 aNewSheet.AddStyleSet(this); 667 668 // Maintain a mirrored list of sheets on the servo side. 669 Servo_StyleSet_InsertStyleSheetBefore(mRawData.get(), &aNewSheet, 670 &aReferenceSheet); 671 SetStylistStyleSheetsDirty(); 672 673 if (mStyleRuleMap) { 674 mStyleRuleMap->SheetAdded(aNewSheet); 675 } 676 } 677 678 size_t ServoStyleSet::SheetCount(Origin aOrigin) const { 679 return Servo_StyleSet_GetSheetCount(mRawData.get(), aOrigin); 680 } 681 682 StyleSheet* ServoStyleSet::SheetAt(Origin aOrigin, size_t aIndex) const { 683 return const_cast<StyleSheet*>( 684 Servo_StyleSet_GetSheetAt(mRawData.get(), aOrigin, aIndex)); 685 } 686 687 ServoStyleSet::PageSizeAndOrientation 688 ServoStyleSet::GetDefaultPageSizeAndOrientation() { 689 PageSizeAndOrientation retval; 690 const RefPtr<ComputedStyle> style = 691 ResolvePageContentStyle(nullptr, StylePagePseudoClassFlags::NONE); 692 const StylePageSize& pageSize = style->StylePage()->mSize; 693 694 if (pageSize.IsSize()) { 695 const nscoord w = pageSize.AsSize().width.ToAppUnits(); 696 const nscoord h = pageSize.AsSize().height.ToAppUnits(); 697 // Ignoring sizes that include a zero width or height. 698 // These are also ignored in nsPageFrame::ComputePageSize() 699 // when calculating the scaling for a page size. 700 // In bug 1807985, we might add similar handling for @page margin/size 701 // combinations that produce a zero-sized page-content box. 702 if (w > 0 && h > 0) { 703 retval.size.emplace(w, h); 704 if (w > h) { 705 retval.orientation.emplace(StylePageSizeOrientation::Landscape); 706 } else if (w < h) { 707 retval.orientation.emplace(StylePageSizeOrientation::Portrait); 708 } 709 } 710 } else if (pageSize.IsOrientation()) { 711 retval.orientation.emplace(pageSize.AsOrientation()); 712 } else { 713 MOZ_ASSERT(pageSize.IsAuto(), "Impossible page size"); 714 } 715 return retval; 716 } 717 718 void ServoStyleSet::AppendAllNonDocumentAuthorSheets( 719 nsTArray<StyleSheet*>& aArray) const { 720 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) { 721 for (auto index : IntegerRange(aShadowRoot.SheetCount())) { 722 aArray.AppendElement(aShadowRoot.SheetAt(index)); 723 } 724 aArray.AppendElements(aShadowRoot.AdoptedStyleSheets()); 725 }); 726 } 727 728 void ServoStyleSet::AddDocStyleSheet(StyleSheet& aSheet) { 729 MOZ_ASSERT(aSheet.IsApplicable()); 730 MOZ_ASSERT(aSheet.RawContents(), 731 "Raw sheet should be in place by this point."); 732 733 size_t index = mDocument->FindDocStyleSheetInsertionPoint(aSheet); 734 aSheet.AddStyleSet(this); 735 736 if (index < SheetCount(Origin::Author)) { 737 // This case is insert before. 738 StyleSheet* beforeSheet = SheetAt(Origin::Author, index); 739 Servo_StyleSet_InsertStyleSheetBefore(mRawData.get(), &aSheet, beforeSheet); 740 } else { 741 Servo_StyleSet_AppendStyleSheet(mRawData.get(), &aSheet); 742 } 743 SetStylistStyleSheetsDirty(); 744 745 if (mStyleRuleMap) { 746 mStyleRuleMap->SheetAdded(aSheet); 747 } 748 } 749 750 bool ServoStyleSet::GeneratedContentPseudoExists( 751 const ComputedStyle& aParentStyle, const ComputedStyle& aPseudoStyle) { 752 auto type = aPseudoStyle.GetPseudoType(); 753 MOZ_ASSERT(type != PseudoStyleType::NotPseudo); 754 755 if (type == PseudoStyleType::marker) { 756 // ::marker only exist for list items (for now). 757 if (!aParentStyle.StyleDisplay()->IsListItem()) { 758 return false; 759 } 760 const auto& content = aPseudoStyle.StyleContent()->mContent; 761 // ::marker does not exist if 'content' is 'none' (this trumps 762 // any 'list-style-type' or 'list-style-image' values). 763 if (content.IsNone()) { 764 return false; 765 } 766 // ::marker only exist if we have 'content' or at least one of 767 // 'list-style-type' or 'list-style-image'. 768 if (aPseudoStyle.StyleList()->mListStyleType.IsNone() && 769 aPseudoStyle.StyleList()->mListStyleImage.IsNone() && 770 content.IsNormal()) { 771 return false; 772 } 773 } 774 // For ::before and ::after pseudo-elements, no 'content' items is 775 // equivalent to not having the pseudo-element at all. 776 if (type == PseudoStyleType::before || type == PseudoStyleType::after) { 777 if (!aPseudoStyle.StyleContent()->mContent.IsItems()) { 778 return false; 779 } 780 MOZ_ASSERT(!aPseudoStyle.StyleContent()->NonAltContentItems().IsEmpty(), 781 "IsItems() implies we have at least one item"); 782 } 783 if (type == PseudoStyleType::before || type == PseudoStyleType::after || 784 type == PseudoStyleType::marker || type == PseudoStyleType::backdrop) { 785 // display:none is equivalent to not having a pseudo at all. 786 if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) { 787 return false; 788 } 789 } 790 return true; 791 } 792 793 bool ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags) { 794 AUTO_PROFILER_LABEL_CATEGORY_PAIR_RELEVANT_FOR_JS(LAYOUT_StyleComputation); 795 MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?"); 796 797 if (!mDocument->GetServoRestyleRoot()) { 798 return false; 799 } 800 801 PreTraverse(aFlags); 802 const SnapshotTable& snapshots = Snapshots(); 803 804 // Restyle the document from the root element and each of the document level 805 // NAC subtree roots. 806 bool postTraversalRequired = false; 807 808 if (ShouldTraverseInParallel()) { 809 aFlags |= ServoTraversalFlags::ParallelTraversal; 810 } 811 812 // Do the first traversal. 813 DocumentStyleRootIterator iter(mDocument->GetServoRestyleRoot()); 814 while (Element* root = iter.GetNextStyleRoot()) { 815 MOZ_ASSERT(MayTraverseFrom(root)); 816 817 Element* parent = root->GetFlattenedTreeParentElementForStyle(); 818 MOZ_ASSERT_IF(parent, 819 !parent->HasAnyOfFlags(Element::kAllServoDescendantBits)); 820 821 if (MOZ_UNLIKELY(!root->HasServoData()) && !parent) { 822 StyleNewSubtree(root); 823 postTraversalRequired = true; 824 continue; 825 } 826 827 AutoPrepareTraversal guard(this); 828 829 postTraversalRequired |= 830 Servo_TraverseSubtree(root, mRawData.get(), &snapshots, aFlags) || 831 root->HasAnyOfFlags(Element::kAllServoDescendantBits | 832 NODE_NEEDS_FRAME); 833 834 uint32_t existingBits = mDocument->GetServoRestyleRootDirtyBits(); 835 Element* newRoot = nullptr; 836 while (parent && parent->HasDirtyDescendantsForServo()) { 837 MOZ_ASSERT(root == mDocument->GetServoRestyleRoot(), 838 "Restyle root shouldn't have magically changed"); 839 // If any style invalidation was triggered in our siblings, then we may 840 // need to post-traverse them, even if the root wasn't restyled after 841 // all. 842 // We need to propagate the existing bits to the ancestor. 843 parent->SetFlags(existingBits); 844 newRoot = parent; 845 parent = parent->GetFlattenedTreeParentElementForStyle(); 846 } 847 848 if (newRoot) { 849 mDocument->SetServoRestyleRoot( 850 newRoot, existingBits | ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO); 851 postTraversalRequired = true; 852 } 853 } 854 855 // If there are still animation restyles needed, trigger a second traversal to 856 // update CSS animations or transitions' styles. 857 // 858 // Note that we need to check the style root again, because doing another 859 // PreTraverse on the EffectCompositor might alter the style root. But we 860 // don't need to worry about NAC, since document-level NAC shouldn't have 861 // animations. 862 // 863 // We don't need to do this for SMIL since SMIL only updates its animation 864 // values once at the begin of a tick. As a result, even if the previous 865 // traversal caused, for example, the font-size to change, the SMIL style 866 // won't be updated until the next tick anyway. 867 if (GetPresContext()->EffectCompositor()->PreTraverse(aFlags)) { 868 DocumentStyleRootIterator iter(mDocument->GetServoRestyleRoot()); 869 while (Element* root = iter.GetNextStyleRoot()) { 870 AutoPrepareTraversal guard(this); 871 postTraversalRequired |= 872 Servo_TraverseSubtree(root, mRawData.get(), &snapshots, aFlags) || 873 root->HasAnyOfFlags(Element::kAllServoDescendantBits | 874 NODE_NEEDS_FRAME); 875 } 876 } 877 878 return postTraversalRequired; 879 } 880 881 void ServoStyleSet::StyleNewSubtree(Element* aRoot) { 882 MOZ_ASSERT(GetPresContext()); 883 MOZ_ASSERT(!aRoot->HasServoData()); 884 MOZ_ASSERT(aRoot->GetFlattenedTreeParentNodeForStyle(), 885 "Not in the flat tree? Fishy!"); 886 PreTraverseSync(); 887 AutoPrepareTraversal guard(this); 888 889 // Do the traversal. The snapshots will not be used. 890 const SnapshotTable& snapshots = Snapshots(); 891 auto flags = ServoTraversalFlags::Empty; 892 if (ShouldTraverseInParallel()) { 893 flags |= ServoTraversalFlags::ParallelTraversal; 894 } 895 896 DebugOnly<bool> postTraversalRequired = 897 Servo_TraverseSubtree(aRoot, mRawData.get(), &snapshots, flags); 898 MOZ_ASSERT(!postTraversalRequired); 899 900 // Annoyingly, the newly-styled content may have animations that need 901 // starting, which requires traversing them again. Mark the elements 902 // that need animation processing, then do a forgetful traversal to 903 // update the styles and clear the animation bits. 904 if (GetPresContext()->EffectCompositor()->PreTraverseInSubtree(flags, 905 aRoot)) { 906 postTraversalRequired = 907 Servo_TraverseSubtree(aRoot, mRawData.get(), &snapshots, 908 ServoTraversalFlags::AnimationOnly | 909 ServoTraversalFlags::FinalAnimationTraversal); 910 MOZ_ASSERT(!postTraversalRequired); 911 } 912 } 913 914 void ServoStyleSet::MarkOriginsDirty(OriginFlags aChangedOrigins) { 915 SetStylistStyleSheetsDirty(); 916 Servo_StyleSet_NoteStyleSheetsChanged(mRawData.get(), aChangedOrigins); 917 } 918 919 void ServoStyleSet::SetStylistStyleSheetsDirty() { 920 mStylistState |= StylistState::StyleSheetsDirty; 921 922 // We need to invalidate cached style in getComputedStyle for undisplayed 923 // elements, since we don't know if any of the style sheet change that we do 924 // would affect undisplayed elements. 925 // 926 // We don't allow to call getComputedStyle in elements without a pres shell 927 // yet, so it is fine if there's no pres context here. 928 if (nsPresContext* presContext = GetPresContext()) { 929 presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration(); 930 } 931 } 932 933 void ServoStyleSet::SetStylistShadowDOMStyleSheetsDirty() { 934 mStylistState |= StylistState::ShadowDOMStyleSheetsDirty; 935 if (nsPresContext* presContext = GetPresContext()) { 936 presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration(); 937 } 938 } 939 940 static OriginFlags ToOriginFlags(StyleOrigin aOrigin) { 941 switch (aOrigin) { 942 case StyleOrigin::UserAgent: 943 return OriginFlags::UserAgent; 944 case StyleOrigin::User: 945 return OriginFlags::User; 946 default: 947 MOZ_FALLTHROUGH_ASSERT("Unknown origin?"); 948 case StyleOrigin::Author: 949 return OriginFlags::Author; 950 } 951 } 952 953 void ServoStyleSet::ImportRuleLoaded(StyleSheet& aSheet) { 954 if (mStyleRuleMap) { 955 mStyleRuleMap->SheetAdded(aSheet); 956 } 957 958 // TODO: Should probably consider ancestor sheets too. 959 if (!aSheet.IsApplicable()) { 960 return; 961 } 962 963 // TODO(emilio): Could handle it better given we know it is an insertion, and 964 // use the style invalidation machinery stuff that we do for regular sheet 965 // insertions. 966 MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin())); 967 } 968 969 void ServoStyleSet::RuleAdded(StyleSheet& aSheet, css::Rule& aRule) { 970 if (mStyleRuleMap) { 971 mStyleRuleMap->RuleAdded(aSheet, aRule); 972 } 973 974 if (!aSheet.IsApplicable() || aRule.IsIncompleteImportRule()) { 975 return; 976 } 977 978 RuleChangedInternal(aSheet, aRule, StyleRuleChangeKind::Insertion); 979 } 980 981 void ServoStyleSet::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule) { 982 if (mStyleRuleMap) { 983 mStyleRuleMap->RuleRemoved(aSheet, aRule); 984 } 985 986 if (!aSheet.IsApplicable()) { 987 return; 988 } 989 990 RuleChangedInternal(aSheet, aRule, StyleRuleChangeKind::Removal); 991 } 992 993 static Maybe<StyleCssRuleRef> ToRuleRef(css::Rule& aRule) { 994 switch (aRule.Type()) { 995 #define CASE_FOR(constant_, type_) \ 996 case StyleCssRuleType::constant_: \ 997 return Some(StyleCssRuleRef::constant_( \ 998 static_cast<dom::CSS##type_##Rule&>(aRule).Raw())); \ 999 break; 1000 CASE_FOR(CounterStyle, CounterStyle) 1001 CASE_FOR(Style, Style) 1002 CASE_FOR(Import, Import) 1003 CASE_FOR(Media, Media) 1004 CASE_FOR(Keyframes, Keyframes) 1005 CASE_FOR(Margin, Margin) 1006 CASE_FOR(CustomMedia, CustomMedia) 1007 CASE_FOR(FontFeatureValues, FontFeatureValues) 1008 CASE_FOR(FontPaletteValues, FontPaletteValues) 1009 CASE_FOR(FontFace, FontFace) 1010 CASE_FOR(Page, Page) 1011 CASE_FOR(Property, Property) 1012 CASE_FOR(Document, MozDocument) 1013 CASE_FOR(Supports, Supports) 1014 CASE_FOR(LayerBlock, LayerBlock) 1015 CASE_FOR(LayerStatement, LayerStatement) 1016 CASE_FOR(Container, Container) 1017 CASE_FOR(Scope, Scope) 1018 CASE_FOR(StartingStyle, StartingStyle) 1019 CASE_FOR(PositionTry, PositionTry) 1020 CASE_FOR(NestedDeclarations, NestedDeclarations) 1021 CASE_FOR(Namespace, Namespace) 1022 #undef CASE_FOR 1023 case StyleCssRuleType::Keyframe: 1024 // No equivalent. 1025 break; 1026 } 1027 return Nothing{}; 1028 } 1029 1030 void ServoStyleSet::RuleChangedInternal(StyleSheet& aSheet, css::Rule& aRule, 1031 const StyleRuleChange& aChange) { 1032 MOZ_ASSERT(aSheet.IsApplicable()); 1033 SetStylistStyleSheetsDirty(); 1034 1035 nsTArray<StyleCssRuleRef> ancestors; 1036 1037 auto* parent = aRule.GetParentRule(); 1038 while (parent) { 1039 if (const auto ref = ToRuleRef(*parent)) { 1040 ancestors.AppendElement(*ref); 1041 } 1042 parent = parent->GetParentRule(); 1043 } 1044 #define CASE_FOR(constant_, type_) \ 1045 case StyleCssRuleType::constant_: \ 1046 return Servo_StyleSet_##constant_##RuleChanged( \ 1047 mRawData.get(), static_cast<dom::CSS##type_##Rule&>(aRule).Raw(), \ 1048 &aSheet, aChange.mKind, &ancestors); 1049 switch (aRule.Type()) { 1050 CASE_FOR(CounterStyle, CounterStyle) 1051 CASE_FOR(Style, Style) 1052 CASE_FOR(Import, Import) 1053 CASE_FOR(CustomMedia, CustomMedia) 1054 CASE_FOR(Media, Media) 1055 CASE_FOR(Keyframes, Keyframes) 1056 CASE_FOR(Margin, Margin) 1057 CASE_FOR(FontFeatureValues, FontFeatureValues) 1058 CASE_FOR(FontPaletteValues, FontPaletteValues) 1059 CASE_FOR(FontFace, FontFace) 1060 CASE_FOR(Page, Page) 1061 CASE_FOR(Property, Property) 1062 CASE_FOR(Document, MozDocument) 1063 CASE_FOR(Supports, Supports) 1064 CASE_FOR(LayerBlock, LayerBlock) 1065 CASE_FOR(LayerStatement, LayerStatement) 1066 CASE_FOR(Container, Container) 1067 CASE_FOR(Scope, Scope) 1068 CASE_FOR(StartingStyle, StartingStyle) 1069 CASE_FOR(PositionTry, PositionTry) 1070 CASE_FOR(NestedDeclarations, NestedDeclarations) 1071 // @namespace can only be inserted / removed when there are only other 1072 // @namespace and @import rules, and can't be mutated. 1073 case StyleCssRuleType::Namespace: 1074 break; 1075 case StyleCssRuleType::Keyframe: 1076 // FIXME: We should probably just forward to the parent @keyframes rule? I 1077 // think that'd do the right thing, but meanwhile... 1078 return MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin())); 1079 } 1080 1081 #undef CASE_FOR 1082 } 1083 1084 void ServoStyleSet::RuleChanged(StyleSheet& aSheet, css::Rule* aRule, 1085 const StyleRuleChange& aChange) { 1086 if (!aSheet.IsApplicable()) { 1087 return; 1088 } 1089 1090 if (!aRule) { 1091 MOZ_ASSERT(!aChange.mOldBlock); 1092 MOZ_ASSERT(!aChange.mNewBlock); 1093 // FIXME: This is done for StyleSheet.media attribute changes and such 1094 MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin())); 1095 } else { 1096 if (mStyleRuleMap && aChange.mOldBlock != aChange.mNewBlock) { 1097 mStyleRuleMap->RuleDeclarationsChanged(*aRule, aChange.mOldBlock->Raw(), 1098 aChange.mNewBlock->Raw()); 1099 } 1100 RuleChangedInternal(aSheet, *aRule, aChange); 1101 } 1102 } 1103 1104 void ServoStyleSet::SheetCloned(StyleSheet& aSheet) { 1105 mNeedsRestyleAfterEnsureUniqueInner = true; 1106 if (mStyleRuleMap) { 1107 mStyleRuleMap->SheetCloned(aSheet); 1108 } 1109 } 1110 1111 #ifdef DEBUG 1112 void ServoStyleSet::AssertTreeIsClean() { 1113 DocumentStyleRootIterator iter(mDocument); 1114 while (Element* root = iter.GetNextStyleRoot()) { 1115 Servo_AssertTreeIsClean(root); 1116 } 1117 } 1118 #endif 1119 1120 bool ServoStyleSet::GetKeyframesForName( 1121 const Element& aElement, const ComputedStyle& aStyle, nsAtom* aName, 1122 const StyleComputedTimingFunction& aTimingFunction, 1123 nsTArray<Keyframe>& aKeyframes) { 1124 MOZ_ASSERT(!StylistNeedsUpdate()); 1125 if (Servo_StyleSet_GetKeyframesForName(mRawData.get(), &aElement, &aStyle, 1126 aName, &aTimingFunction, 1127 &aKeyframes)) { 1128 return true; 1129 } 1130 if (StringBeginsWith(nsDependentAtomString(aName), 1131 ViewTransition::kGroupAnimPrefix)) { 1132 if (auto* vt = mDocument->GetActiveViewTransition()) { 1133 if (vt->GetGroupKeyframes(aName, aTimingFunction, aKeyframes)) { 1134 return true; 1135 } 1136 } 1137 } 1138 return false; 1139 } 1140 1141 nsTArray<ComputedKeyframeValues> ServoStyleSet::GetComputedKeyframeValuesFor( 1142 const nsTArray<Keyframe>& aKeyframes, Element* aElement, 1143 const PseudoStyleRequest& aPseudo, const ComputedStyle* aStyle) { 1144 nsTArray<ComputedKeyframeValues> result(aKeyframes.Length()); 1145 1146 // Construct each nsTArray<PropertyStyleAnimationValuePair> here. 1147 result.AppendElements(aKeyframes.Length()); 1148 1149 // FIXME: Bug 1922095. For view transition pseudo-element, we should just 1150 // use the pseudo-element here. 1151 Servo_GetComputedKeyframeValues(&aKeyframes, aElement, aPseudo.mType, aStyle, 1152 mRawData.get(), &result); 1153 return result; 1154 } 1155 1156 void ServoStyleSet::GetAnimationValues( 1157 StyleLockedDeclarationBlock* aDeclarations, Element* aElement, 1158 const ComputedStyle* aComputedStyle, 1159 nsTArray<RefPtr<StyleAnimationValue>>& aAnimationValues) { 1160 // Servo_GetAnimationValues below won't handle ignoring existing element 1161 // data for bfcached documents. (See comment in ResolveStyleLazily 1162 // about these bfcache issues.) 1163 Servo_GetAnimationValues(aDeclarations, aElement, aComputedStyle, 1164 mRawData.get(), &aAnimationValues); 1165 } 1166 1167 already_AddRefed<ComputedStyle> ServoStyleSet::GetBaseContextForElement( 1168 Element* aElement, const ComputedStyle* aStyle) { 1169 return Servo_StyleSet_GetBaseComputedValuesForElement( 1170 mRawData.get(), aElement, aStyle, &Snapshots()) 1171 .Consume(); 1172 } 1173 1174 already_AddRefed<StyleAnimationValue> ServoStyleSet::ComputeAnimationValue( 1175 Element* aElement, StyleLockedDeclarationBlock* aDeclarations, 1176 const ComputedStyle* aStyle) { 1177 return Servo_AnimationValue_Compute(aElement, aDeclarations, aStyle, 1178 mRawData.get()) 1179 .Consume(); 1180 } 1181 1182 bool ServoStyleSet::UsesFontMetrics() const { 1183 return Servo_StyleSet_UsesFontMetrics(mRawData.get()); 1184 } 1185 1186 bool ServoStyleSet::UsesRootFontMetrics() const { 1187 return Servo_StyleSet_UsesRootFontMetrics(mRawData.get()); 1188 } 1189 1190 bool ServoStyleSet::EnsureUniqueInnerOnCSSSheets() { 1191 using SheetOwner = Variant<ServoStyleSet*, ShadowRoot*>; 1192 1193 AutoTArray<std::pair<StyleSheet*, SheetOwner>, 32> queue; 1194 EnumerateStyleSheets([&](StyleSheet& aSheet) { 1195 queue.AppendElement(std::make_pair(&aSheet, SheetOwner{this})); 1196 }); 1197 1198 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) { 1199 for (auto index : IntegerRange(aShadowRoot.SheetCount())) { 1200 queue.AppendElement( 1201 std::make_pair(aShadowRoot.SheetAt(index), SheetOwner{&aShadowRoot})); 1202 } 1203 for (const auto& adopted : aShadowRoot.AdoptedStyleSheets()) { 1204 queue.AppendElement( 1205 std::make_pair(adopted.get(), SheetOwner{&aShadowRoot})); 1206 } 1207 }); 1208 1209 while (!queue.IsEmpty()) { 1210 auto [sheet, owner] = queue.PopLastElement(); 1211 1212 if (sheet->HasForcedUniqueInner()) { 1213 // We already processed this sheet and its children. 1214 // Normally we don't hit this but adopted stylesheets can have dupes so we 1215 // can save some work here. 1216 continue; 1217 } 1218 1219 // Only call EnsureUniqueInner for complete sheets. If we do call it on 1220 // incomplete sheets, we'll cause problems when the sheet is actually 1221 // loaded. We don't care about incomplete sheets here anyway, because this 1222 // method is only invoked by nsPresContext::EnsureSafeToHandOutCSSRules. 1223 // The CSSRule objects we are handing out won't contain any rules derived 1224 // from incomplete sheets (because they aren't yet applied in styling). 1225 if (sheet->IsComplete()) { 1226 sheet->EnsureUniqueInner(); 1227 } 1228 1229 // Enqueue all the sheet's children. 1230 for (StyleSheet* child : sheet->ChildSheets()) { 1231 queue.AppendElement(std::make_pair(child, owner)); 1232 } 1233 } 1234 1235 if (mNeedsRestyleAfterEnsureUniqueInner) { 1236 // TODO(emilio): We could make this faster if needed tracking the specific 1237 // origins and sheets that have been cloned. But the only caller of this 1238 // doesn't seem to really care about perf. 1239 MarkOriginsDirty(OriginFlags::All); 1240 ForceDirtyAllShadowStyles(); 1241 } 1242 bool res = mNeedsRestyleAfterEnsureUniqueInner; 1243 mNeedsRestyleAfterEnsureUniqueInner = false; 1244 return res; 1245 } 1246 1247 void ServoStyleSet::ClearCachedStyleData() { 1248 ClearNonInheritingComputedStyles(); 1249 Servo_StyleSet_RebuildCachedData(mRawData.get()); 1250 mCachedAnonymousContentStyles.Clear(); 1251 PodArrayZero(mCachedAnonymousContentStyleIndexes); 1252 } 1253 1254 void ServoStyleSet::ForceDirtyAllShadowStyles() { 1255 bool anyShadow = false; 1256 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) { 1257 if (auto* authorStyles = aShadowRoot.GetServoStyles()) { 1258 anyShadow = true; 1259 Servo_AuthorStyles_ForceDirty(authorStyles); 1260 } 1261 }); 1262 if (anyShadow) { 1263 SetStylistShadowDOMStyleSheetsDirty(); 1264 } 1265 } 1266 1267 void ServoStyleSet::CompatibilityModeChanged() { 1268 Servo_StyleSet_CompatModeChanged(mRawData.get()); 1269 SetStylistStyleSheetsDirty(); 1270 ForceDirtyAllShadowStyles(); 1271 } 1272 1273 void ServoStyleSet::ClearNonInheritingComputedStyles() { 1274 for (RefPtr<ComputedStyle>& ptr : mNonInheritingComputedStyles) { 1275 ptr = nullptr; 1276 } 1277 } 1278 1279 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleLazily( 1280 const Element& aElement, const PseudoStyleRequest& aPseudoRequest, 1281 StyleRuleInclusion aRuleInclusion) { 1282 PreTraverseSync(); 1283 MOZ_ASSERT(!StylistNeedsUpdate()); 1284 1285 AutoSetInServoTraversal guard(this); 1286 1287 /** 1288 * NB: This is needed because we process animations and transitions on the 1289 * pseudo-elements themselves, not on the parent's EagerPseudoStyles. 1290 * 1291 * That means that that style doesn't account for animations, and we can't do 1292 * that easily from the traversal without doing wasted work. 1293 * 1294 * As such, we just lie here a bit, which is the entrypoint of 1295 * getComputedStyle, the only API where this can be observed, to look at the 1296 * style of the pseudo-element if it exists instead. 1297 */ 1298 const Element* elementForStyleResolution = &aElement; 1299 PseudoStyleType pseudoTypeForStyleResolution = aPseudoRequest.mType; 1300 if (auto* pseudo = aElement.GetPseudoElement(aPseudoRequest)) { 1301 elementForStyleResolution = pseudo; 1302 pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo; 1303 } 1304 1305 nsPresContext* pc = GetPresContext(); 1306 MOZ_ASSERT(pc, "For now, no style resolution without a pres context"); 1307 auto* restyleManager = pc->RestyleManager(); 1308 const bool canUseCache = aRuleInclusion == StyleRuleInclusion::All && 1309 aElement.OwnerDoc() == mDocument && 1310 pc->PresShell()->DidInitialize(); 1311 return Servo_ResolveStyleLazily( 1312 elementForStyleResolution, pseudoTypeForStyleResolution, 1313 aPseudoRequest.mIdentifier.get(), aRuleInclusion, 1314 &restyleManager->Snapshots(), 1315 restyleManager->GetUndisplayedRestyleGeneration(), canUseCache, 1316 mRawData.get()) 1317 .Consume(); 1318 } 1319 1320 void ServoStyleSet::AppendFontFaceRules( 1321 nsTArray<nsFontFaceRuleContainer>& aArray) { 1322 // TODO(emilio): Can we make this so this asserts instead? 1323 UpdateStylistIfNeeded(); 1324 Servo_StyleSet_GetFontFaceRules(mRawData.get(), &aArray); 1325 } 1326 1327 const StyleLockedCounterStyleRule* ServoStyleSet::CounterStyleRuleForName( 1328 nsAtom* aName) { 1329 MOZ_ASSERT(!StylistNeedsUpdate()); 1330 return Servo_StyleSet_GetCounterStyleRule(mRawData.get(), aName); 1331 } 1332 1333 already_AddRefed<gfxFontFeatureValueSet> 1334 ServoStyleSet::BuildFontFeatureValueSet() { 1335 MOZ_ASSERT(!StylistNeedsUpdate()); 1336 RefPtr<gfxFontFeatureValueSet> set = 1337 Servo_StyleSet_BuildFontFeatureValueSet(mRawData.get()); 1338 return set.forget(); 1339 } 1340 1341 already_AddRefed<gfx::FontPaletteValueSet> 1342 ServoStyleSet::BuildFontPaletteValueSet() { 1343 MOZ_ASSERT(!StylistNeedsUpdate()); 1344 RefPtr<gfx::FontPaletteValueSet> set = 1345 Servo_StyleSet_BuildFontPaletteValueSet(mRawData.get()); 1346 return set.forget(); 1347 } 1348 1349 already_AddRefed<ComputedStyle> ServoStyleSet::ResolveForDeclarations( 1350 const ComputedStyle* aParentOrNull, 1351 const StyleLockedDeclarationBlock* aDeclarations) { 1352 // No need to update the stylist, we're only cascading aDeclarations. 1353 return Servo_StyleSet_ResolveForDeclarations(mRawData.get(), aParentOrNull, 1354 aDeclarations) 1355 .Consume(); 1356 } 1357 1358 void ServoStyleSet::UpdateStylist() { 1359 AUTO_PROFILER_LABEL_RELEVANT_FOR_JS("Update stylesheet information", LAYOUT); 1360 MOZ_ASSERT(StylistNeedsUpdate()); 1361 1362 AutoTArray<StyleAuthorStyles*, 20> nonDocumentStyles; 1363 Element* root = mDocument->GetRootElement(); 1364 const ServoElementSnapshotTable* snapshots = nullptr; 1365 if (nsPresContext* pc = GetPresContext()) { 1366 snapshots = &pc->RestyleManager()->Snapshots(); 1367 } 1368 1369 if (MOZ_UNLIKELY(mStylistState & StylistState::ShadowDOMStyleSheetsDirty)) { 1370 EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) { 1371 if (auto* authorStyles = aShadowRoot.GetServoStyles()) { 1372 nonDocumentStyles.AppendElement(authorStyles); 1373 } 1374 }); 1375 } 1376 Servo_StyleSet_FlushStyleSheets(mRawData.get(), root, snapshots, 1377 &nonDocumentStyles); 1378 mStylistState = StylistState::NotDirty; 1379 } 1380 1381 void ServoStyleSet::MaybeGCRuleTree() { 1382 MOZ_ASSERT(NS_IsMainThread()); 1383 Servo_MaybeGCRuleTree(mRawData.get()); 1384 } 1385 1386 /* static */ 1387 bool ServoStyleSet::MayTraverseFrom(const Element* aElement) { 1388 MOZ_ASSERT(aElement->IsInComposedDoc()); 1389 nsINode* parent = aElement->GetFlattenedTreeParentNodeForStyle(); 1390 if (!parent) { 1391 return false; 1392 } 1393 1394 if (!parent->IsElement()) { 1395 MOZ_ASSERT(parent->IsDocument()); 1396 return true; 1397 } 1398 1399 if (!parent->AsElement()->HasServoData()) { 1400 return false; 1401 } 1402 1403 return !Servo_Element_IsDisplayNone(parent->AsElement()); 1404 } 1405 1406 bool ServoStyleSet::ShouldTraverseInParallel() const { 1407 MOZ_ASSERT(mDocument->GetPresShell(), "Styling a document without a shell?"); 1408 if (!mDocument->GetPresShell()->IsActive()) { 1409 return false; 1410 } 1411 if (profiler_feature_active(ProfilerFeature::SequentialStyle)) { 1412 return false; 1413 } 1414 return true; 1415 } 1416 1417 void ServoStyleSet::RunPostTraversalTasks() { 1418 MOZ_ASSERT(!IsInServoTraversal()); 1419 1420 if (mPostTraversalTasks.IsEmpty()) { 1421 return; 1422 } 1423 1424 nsTArray<PostTraversalTask> tasks = std::move(mPostTraversalTasks); 1425 1426 for (auto& task : tasks) { 1427 task.Run(); 1428 } 1429 } 1430 1431 ServoStyleRuleMap* ServoStyleSet::StyleRuleMap() { 1432 if (!mStyleRuleMap) { 1433 mStyleRuleMap = MakeUnique<ServoStyleRuleMap>(); 1434 } 1435 mStyleRuleMap->EnsureTable(*this); 1436 return mStyleRuleMap.get(); 1437 } 1438 1439 bool ServoStyleSet::MightHaveAttributeDependency(const Element& aElement, 1440 nsAtom* aAttribute) const { 1441 return Servo_StyleSet_MightHaveAttributeDependency(mRawData.get(), &aElement, 1442 aAttribute); 1443 } 1444 1445 bool ServoStyleSet::MightHaveNthOfIDDependency(const Element& aElement, 1446 nsAtom* aOldID, 1447 nsAtom* aNewID) const { 1448 return Servo_StyleSet_MightHaveNthOfIDDependency(mRawData.get(), &aElement, 1449 aOldID, aNewID); 1450 } 1451 1452 bool ServoStyleSet::MightHaveNthOfClassDependency(const Element& aElement) { 1453 return Servo_StyleSet_MightHaveNthOfClassDependency(mRawData.get(), &aElement, 1454 &Snapshots()); 1455 } 1456 1457 void ServoStyleSet::MaybeInvalidateRelativeSelectorIDDependency( 1458 const Element& aElement, nsAtom* aOldID, nsAtom* aNewID, 1459 const ServoElementSnapshotTable& aSnapshots) { 1460 Servo_StyleSet_MaybeInvalidateRelativeSelectorIDDependency( 1461 mRawData.get(), &aElement, aOldID, aNewID, &aSnapshots); 1462 } 1463 1464 void ServoStyleSet::MaybeInvalidateRelativeSelectorClassDependency( 1465 const Element& aElement, const ServoElementSnapshotTable& aSnapshots) { 1466 Servo_StyleSet_MaybeInvalidateRelativeSelectorClassDependency( 1467 mRawData.get(), &aElement, &aSnapshots); 1468 } 1469 1470 void ServoStyleSet::MaybeInvalidateRelativeSelectorCustomStateDependency( 1471 const Element& aElement, nsAtom* state, 1472 const ServoElementSnapshotTable& aSnapshots) { 1473 Servo_StyleSet_MaybeInvalidateRelativeSelectorCustomStateDependency( 1474 mRawData.get(), &aElement, state, &aSnapshots); 1475 } 1476 1477 void ServoStyleSet::MaybeInvalidateRelativeSelectorAttributeDependency( 1478 const Element& aElement, nsAtom* aAttribute, 1479 const ServoElementSnapshotTable& aSnapshots) { 1480 Servo_StyleSet_MaybeInvalidateRelativeSelectorAttributeDependency( 1481 mRawData.get(), &aElement, aAttribute, &aSnapshots); 1482 } 1483 1484 void ServoStyleSet::MaybeInvalidateRelativeSelectorStateDependency( 1485 const Element& aElement, ElementState aState, 1486 const ServoElementSnapshotTable& aSnapshots) { 1487 Servo_StyleSet_MaybeInvalidateRelativeSelectorStateDependency( 1488 mRawData.get(), &aElement, aState.GetInternalValue(), &aSnapshots); 1489 } 1490 1491 void ServoStyleSet::MaybeInvalidateRelativeSelectorForEmptyDependency( 1492 const Element& aElement) { 1493 Servo_StyleSet_MaybeInvalidateRelativeSelectorEmptyDependency(mRawData.get(), 1494 &aElement); 1495 } 1496 1497 void ServoStyleSet::MaybeInvalidateRelativeSelectorForNthEdgeDependency( 1498 const Element& aElement, 1499 StyleRelativeSelectorNthEdgeInvalidateFor aInvalidateFor) { 1500 Servo_StyleSet_MaybeInvalidateRelativeSelectorNthEdgeDependency( 1501 mRawData.get(), &aElement, aInvalidateFor); 1502 } 1503 1504 void ServoStyleSet::MaybeInvalidateRelativeSelectorForNthDependencyFromSibling( 1505 const Element* aFromSibling, bool aForceRestyleSiblings) { 1506 if (!aFromSibling) { 1507 return; 1508 } 1509 Servo_StyleSet_MaybeInvalidateRelativeSelectorNthDependencyFromSibling( 1510 mRawData.get(), aFromSibling, aForceRestyleSiblings); 1511 } 1512 1513 void ServoStyleSet::MaybeInvalidateForElementInsertion( 1514 const Element& aElement) { 1515 Servo_StyleSet_MaybeInvalidateRelativeSelectorForInsertion(mRawData.get(), 1516 &aElement); 1517 } 1518 1519 void ServoStyleSet::MaybeInvalidateForElementAppend( 1520 const nsIContent& aFirstContent) { 1521 Servo_StyleSet_MaybeInvalidateRelativeSelectorForAppend(mRawData.get(), 1522 &aFirstContent); 1523 } 1524 1525 void ServoStyleSet::MaybeInvalidateForElementRemove(const Element& aElement) { 1526 Servo_StyleSet_MaybeInvalidateRelativeSelectorForRemoval(mRawData.get(), 1527 &aElement); 1528 } 1529 1530 bool ServoStyleSet::MightHaveNthOfAttributeDependency( 1531 const Element& aElement, nsAtom* aAttribute) const { 1532 return Servo_StyleSet_MightHaveNthOfAttributeDependency( 1533 mRawData.get(), &aElement, aAttribute); 1534 } 1535 1536 bool ServoStyleSet::HasStateDependency(const Element& aElement, 1537 dom::ElementState aState) const { 1538 return Servo_StyleSet_HasStateDependency(mRawData.get(), &aElement, 1539 aState.GetInternalValue()); 1540 } 1541 1542 bool ServoStyleSet::HasNthOfStateDependency(const Element& aElement, 1543 dom::ElementState aState) const { 1544 return Servo_StyleSet_HasNthOfStateDependency(mRawData.get(), &aElement, 1545 aState.GetInternalValue()); 1546 } 1547 1548 bool ServoStyleSet::HasNthOfCustomStateDependency(const Element& aElement, 1549 nsAtom* aState) const { 1550 return Servo_StyleSet_HasNthOfCustomStateDependency(mRawData.get(), &aElement, 1551 aState); 1552 } 1553 1554 void ServoStyleSet::RestyleSiblingsForNthOf(const Element& aElement, 1555 uint32_t aFlags) const { 1556 Servo_StyleSet_RestyleSiblingsForNthOf(&aElement, aFlags); 1557 } 1558 1559 bool ServoStyleSet::HasDocumentStateDependency( 1560 dom::DocumentState aState) const { 1561 return Servo_StyleSet_HasDocumentStateDependency(mRawData.get(), 1562 aState.GetInternalValue()); 1563 } 1564 1565 already_AddRefed<ComputedStyle> ServoStyleSet::ReparentComputedStyle( 1566 ComputedStyle* aComputedStyle, ComputedStyle* aNewParent, 1567 ComputedStyle* aNewLayoutParent, Element* aElement) { 1568 return Servo_ReparentStyle(aComputedStyle, aNewParent, aNewLayoutParent, 1569 aElement, mRawData.get()) 1570 .Consume(); 1571 } 1572 1573 void ServoStyleSet::InvalidateForViewportUnits(OnlyDynamic aOnlyDynamic) { 1574 dom::Element* root = mDocument->GetRootElement(); 1575 if (!root) { 1576 return; 1577 } 1578 1579 Servo_InvalidateForViewportUnits(mRawData.get(), root, 1580 aOnlyDynamic == OnlyDynamic::Yes); 1581 } 1582 1583 void ServoStyleSet::RegisterProperty(const PropertyDefinition& aDefinition, 1584 ErrorResult& aRv) { 1585 using Result = StyleRegisterCustomPropertyResult; 1586 auto result = Servo_RegisterCustomProperty( 1587 RawData(), mDocument->DefaultStyleAttrURLData(), &aDefinition.mName, 1588 &aDefinition.mSyntax, aDefinition.mInherits, 1589 aDefinition.mInitialValue.WasPassed() ? &aDefinition.mInitialValue.Value() 1590 : nullptr); 1591 switch (result) { 1592 case Result::SuccessfullyRegistered: 1593 if (Element* root = mDocument->GetRootElement()) { 1594 if (nsPresContext* pc = GetPresContext()) { 1595 pc->RestyleManager()->PostRestyleEvent( 1596 root, RestyleHint::RecascadeSubtree(), nsChangeHint(0)); 1597 } 1598 } 1599 mDocument->PostCustomPropertyRegistered(aDefinition); 1600 break; 1601 case Result::InvalidName: 1602 return aRv.ThrowSyntaxError("Invalid name"); 1603 case Result::InvalidSyntax: 1604 return aRv.ThrowSyntaxError("Invalid syntax descriptor"); 1605 case Result::InvalidInitialValue: 1606 return aRv.ThrowSyntaxError("Invalid initial value syntax"); 1607 case Result::NoInitialValue: 1608 return aRv.ThrowSyntaxError( 1609 "Initial value is required when syntax is not universal"); 1610 case Result::InitialValueNotComputationallyIndependent: 1611 return aRv.ThrowSyntaxError( 1612 "Initial value is required when syntax is not universal"); 1613 case Result::AlreadyRegistered: 1614 return aRv.ThrowInvalidModificationError("Property already registered"); 1615 } 1616 } 1617 1618 NS_IMPL_ISUPPORTS(UACacheReporter, nsIMemoryReporter) 1619 1620 MOZ_DEFINE_MALLOC_SIZE_OF(ServoUACacheMallocSizeOf) 1621 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoUACacheMallocEnclosingSizeOf) 1622 1623 NS_IMETHODIMP 1624 UACacheReporter::CollectReports(nsIHandleReportCallback* aHandleReport, 1625 nsISupports* aData, bool aAnonymize) { 1626 ServoStyleSetSizes sizes; 1627 Servo_UACache_AddSizeOf(ServoUACacheMallocSizeOf, 1628 ServoUACacheMallocEnclosingSizeOf, &sizes); 1629 1630 #define REPORT(_path, _amount, _desc) \ 1631 do { \ 1632 size_t __amount = _amount; /* evaluate _amount only once */ \ 1633 if (__amount > 0) { \ 1634 MOZ_COLLECT_REPORT(_path, KIND_HEAP, UNITS_BYTES, __amount, _desc); \ 1635 } \ 1636 } while (0) 1637 1638 // The UA cache does not contain the rule tree; that's in the StyleSet. 1639 MOZ_RELEASE_ASSERT(sizes.mRuleTree == 0); 1640 1641 REPORT("explicit/layout/servo-ua-cache/precomputed-pseudos", 1642 sizes.mPrecomputedPseudos, 1643 "Memory used by precomputed pseudo-element declarations within the " 1644 "UA cache."); 1645 1646 REPORT("explicit/layout/servo-ua-cache/element-and-pseudos-maps", 1647 sizes.mElementAndPseudosMaps, 1648 "Memory used by element and pseudos maps within the UA cache."); 1649 1650 REPORT("explicit/layout/servo-ua-cache/invalidation-map", 1651 sizes.mInvalidationMap, 1652 "Memory used by invalidation maps within the UA cache."); 1653 1654 REPORT("explicit/layout/servo-ua-cache/revalidation-selectors", 1655 sizes.mRevalidationSelectors, 1656 "Memory used by selectors for cache revalidation within the UA " 1657 "cache."); 1658 1659 REPORT("explicit/layout/servo-ua-cache/other", sizes.mOther, 1660 "Memory used by other data within the UA cache"); 1661 1662 return NS_OK; 1663 } 1664 1665 } // namespace mozilla