Line data Source code
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 "gfxPlatformFontList.h"
10 : #include "mozilla/AutoRestyleTimelineMarker.h"
11 : #include "mozilla/DocumentStyleRootIterator.h"
12 : #include "mozilla/ServoBindings.h"
13 : #include "mozilla/ServoRestyleManager.h"
14 : #include "mozilla/ServoStyleRuleMap.h"
15 : #include "mozilla/css/Loader.h"
16 : #include "mozilla/dom/AnonymousContent.h"
17 : #include "mozilla/dom/ChildIterator.h"
18 : #include "mozilla/dom/FontFaceSet.h"
19 : #include "mozilla/dom/Element.h"
20 : #include "mozilla/dom/ElementInlines.h"
21 : #include "mozilla/RestyleManagerInlines.h"
22 : #include "nsCSSAnonBoxes.h"
23 : #include "nsCSSFrameConstructor.h"
24 : #include "nsCSSPseudoElements.h"
25 : #include "nsCSSRuleProcessor.h"
26 : #include "nsDeviceContext.h"
27 : #include "nsHTMLStyleSheet.h"
28 : #include "nsIAnonymousContentCreator.h"
29 : #include "nsIDocumentInlines.h"
30 : #include "nsPrintfCString.h"
31 : #include "nsSMILAnimationController.h"
32 : #include "nsStyleContext.h"
33 : #include "nsStyleSet.h"
34 : #include "gfxUserFontSet.h"
35 :
36 : using namespace mozilla;
37 : using namespace mozilla::dom;
38 :
39 0 : ServoStyleSet::ServoStyleSet()
40 : : mPresContext(nullptr)
41 : , mAuthorStyleDisabled(false)
42 : , mStylistState(StylistState::NotDirty)
43 : , mUserFontSetUpdateGeneration(0)
44 : , mUserFontCacheUpdateGeneration(0)
45 0 : , mNeedsRestyleAfterEnsureUniqueInner(false)
46 : {
47 0 : }
48 :
49 0 : ServoStyleSet::~ServoStyleSet()
50 : {
51 0 : for (auto& sheetArray : mSheets) {
52 0 : for (auto& sheet : sheetArray) {
53 0 : sheet->DropStyleSet(this);
54 : }
55 : }
56 0 : }
57 :
58 : void
59 0 : ServoStyleSet::Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager)
60 : {
61 0 : mPresContext = aPresContext;
62 0 : mRawSet.reset(Servo_StyleSet_Init(aPresContext));
63 0 : mBindingManager = aBindingManager;
64 :
65 0 : mPresContext->DeviceContext()->InitFontCache();
66 :
67 : // Now that we have an mRawSet, go ahead and notify about whatever stylesheets
68 : // we have so far.
69 0 : for (auto& sheetArray : mSheets) {
70 0 : for (auto& sheet : sheetArray) {
71 : // There's no guarantee this will create a list on the servo side whose
72 : // ordering matches the list that would have been created had all those
73 : // sheets been appended/prepended/etc after we had mRawSet. That's okay
74 : // because Servo only needs to maintain relative ordering within a sheet
75 : // type, which this preserves.
76 :
77 0 : MOZ_ASSERT(sheet->RawContents(),
78 : "We should only append non-null raw sheets.");
79 0 : Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet);
80 : }
81 : }
82 :
83 : // No need to Servo_StyleSet_FlushStyleSheets because we just created the
84 : // mRawSet, so there was nothing to flush.
85 0 : }
86 :
87 : void
88 0 : ServoStyleSet::BeginShutdown()
89 : {
90 0 : nsIDocument* doc = mPresContext->Document();
91 :
92 : // Remove the style rule map from document's observer and drop it.
93 0 : if (mStyleRuleMap) {
94 0 : doc->RemoveObserver(mStyleRuleMap);
95 0 : doc->CSSLoader()->RemoveObserver(mStyleRuleMap);
96 0 : mStyleRuleMap = nullptr;
97 : }
98 0 : }
99 :
100 : void
101 0 : ServoStyleSet::Shutdown()
102 : {
103 : // Make sure we drop our cached style contexts before the presshell arena
104 : // starts going away.
105 0 : ClearNonInheritingStyleContexts();
106 0 : mRawSet = nullptr;
107 0 : }
108 :
109 : void
110 0 : ServoStyleSet::InvalidateStyleForCSSRuleChanges()
111 : {
112 0 : MOZ_ASSERT(StylistNeedsUpdate());
113 0 : mPresContext->RestyleManager()->AsServo()->PostRestyleEventForCSSRuleChanges();
114 0 : }
115 :
116 : bool
117 0 : ServoStyleSet::MediumFeaturesChanged() const
118 : {
119 0 : return Servo_StyleSet_MediumFeaturesChanged(mRawSet.get());
120 : }
121 :
122 : size_t
123 0 : ServoStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
124 : {
125 0 : size_t n = aMallocSizeOf(this);
126 :
127 0 : if (mStyleRuleMap) {
128 0 : n += mStyleRuleMap->SizeOfIncludingThis(aMallocSizeOf);
129 : }
130 :
131 : // Measurement of the following members may be added later if DMD finds it is
132 : // worthwhile:
133 : // - mRawSet
134 : // - mSheets
135 : // - mNonInheritingStyleContexts
136 : //
137 : // The following members are not measured:
138 : // - mPresContext, because it a non-owning pointer
139 :
140 0 : return n;
141 : }
142 :
143 : bool
144 0 : ServoStyleSet::GetAuthorStyleDisabled() const
145 : {
146 0 : return mAuthorStyleDisabled;
147 : }
148 :
149 : nsresult
150 0 : ServoStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
151 : {
152 0 : if (mAuthorStyleDisabled == aStyleDisabled) {
153 0 : return NS_OK;
154 : }
155 :
156 0 : mAuthorStyleDisabled = aStyleDisabled;
157 0 : ForceAllStyleDirty();
158 :
159 0 : return NS_OK;
160 : }
161 :
162 : void
163 0 : ServoStyleSet::BeginUpdate()
164 : {
165 0 : }
166 :
167 : nsresult
168 0 : ServoStyleSet::EndUpdate()
169 : {
170 0 : return NS_OK;
171 : }
172 :
173 : already_AddRefed<nsStyleContext>
174 0 : ServoStyleSet::ResolveStyleFor(Element* aElement,
175 : nsStyleContext* aParentContext,
176 : LazyComputeBehavior aMayCompute)
177 : {
178 0 : return GetContext(aElement, aParentContext, nullptr,
179 0 : CSSPseudoElementType::NotPseudo, aMayCompute);
180 : }
181 :
182 : already_AddRefed<ServoStyleContext>
183 0 : ServoStyleSet::GetContext(nsIContent* aContent,
184 : nsStyleContext* aParentContext,
185 : nsIAtom* aPseudoTag,
186 : CSSPseudoElementType aPseudoType,
187 : LazyComputeBehavior aMayCompute)
188 : {
189 0 : MOZ_ASSERT(aContent->IsElement());
190 0 : Element* element = aContent->AsElement();
191 :
192 0 : RefPtr<ServoComputedValues> computedValues;
193 0 : if (aMayCompute == LazyComputeBehavior::Allow) {
194 0 : PreTraverseSync();
195 : computedValues =
196 0 : ResolveStyleLazily(element, CSSPseudoElementType::NotPseudo);
197 : } else {
198 0 : computedValues = ResolveServoStyle(element);
199 : }
200 :
201 0 : MOZ_ASSERT(computedValues);
202 0 : return GetContext(computedValues.forget(), aParentContext, aPseudoTag, aPseudoType,
203 0 : element);
204 : }
205 :
206 : already_AddRefed<ServoStyleContext>
207 0 : ServoStyleSet::GetContext(already_AddRefed<ServoComputedValues> aComputedValues,
208 : nsStyleContext* aParentContext,
209 : nsIAtom* aPseudoTag,
210 : CSSPseudoElementType aPseudoType,
211 : Element* aElementForAnimation)
212 : {
213 0 : bool isLink = false;
214 0 : bool isVisitedLink = false;
215 : // If we need visited styles for callers where `aElementForAnimation` is null,
216 : // we can precompute these and pass them as flags, similar to nsStyleSet.cpp.
217 0 : if (aElementForAnimation) {
218 0 : isLink = nsCSSRuleProcessor::IsLink(aElementForAnimation);
219 0 : isVisitedLink = nsCSSRuleProcessor::GetContentState(aElementForAnimation)
220 0 : .HasState(NS_EVENT_STATE_VISITED);
221 : }
222 :
223 0 : RefPtr<ServoComputedValues> computedValues = Move(aComputedValues);
224 : RefPtr<ServoComputedValues> visitedComputedValues =
225 0 : Servo_ComputedValues_GetVisitedStyle(computedValues).Consume();
226 :
227 : // If `visitedComputedValues` is non-null, then there was a relevant link and
228 : // visited styles were computed. This corresponds to the cases where Gecko's
229 : // style system produces `aVisitedRuleNode`.
230 : // Set up `parentIfVisited` depending on whether our parent context has a
231 : // a visited style. If it doesn't but we do have visited styles, use the
232 : // regular parent context for visited.
233 : nsStyleContext *parentIfVisited =
234 0 : aParentContext ? aParentContext->GetStyleIfVisited() : nullptr;
235 0 : if (!parentIfVisited) {
236 0 : if (visitedComputedValues) {
237 0 : parentIfVisited = aParentContext;
238 : }
239 : }
240 :
241 : // The true visited state of the relevant link is used to decided whether
242 : // visited styles should be consulted for all visited dependent properties.
243 0 : bool relevantLinkVisited = isLink ? isVisitedLink :
244 0 : (aParentContext && aParentContext->RelevantLinkVisited());
245 :
246 : RefPtr<ServoStyleContext> result =
247 0 : ServoStyleContext::Create(aParentContext, mPresContext, aPseudoTag, aPseudoType,
248 0 : computedValues.forget());
249 :
250 0 : if (visitedComputedValues) {
251 : RefPtr<ServoStyleContext> resultIfVisited =
252 0 : ServoStyleContext::Create(parentIfVisited, mPresContext, aPseudoTag, aPseudoType,
253 0 : visitedComputedValues.forget());
254 0 : resultIfVisited->SetIsStyleIfVisited();
255 0 : result->SetStyleIfVisited(resultIfVisited.forget());
256 :
257 0 : if (relevantLinkVisited) {
258 0 : result->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED);
259 : }
260 : }
261 :
262 : // Set the body color on the pres context. See nsStyleSet::GetContext
263 0 : if (aElementForAnimation &&
264 0 : aElementForAnimation->IsHTMLElement(nsGkAtoms::body) &&
265 0 : aPseudoType == CSSPseudoElementType::NotPseudo &&
266 0 : mPresContext->CompatibilityMode() == eCompatibility_NavQuirks) {
267 0 : nsIDocument* doc = aElementForAnimation->GetUncomposedDoc();
268 0 : if (doc && doc->GetBodyElement() == aElementForAnimation) {
269 : // Update the prescontext's body color
270 0 : mPresContext->SetBodyTextColor(result->StyleColor()->mColor);
271 : }
272 : }
273 0 : return result.forget();
274 : }
275 :
276 : const ServoElementSnapshotTable&
277 0 : ServoStyleSet::Snapshots()
278 : {
279 0 : return mPresContext->RestyleManager()->AsServo()->Snapshots();
280 : }
281 :
282 : void
283 0 : ServoStyleSet::ResolveMappedAttrDeclarationBlocks()
284 : {
285 0 : if (nsHTMLStyleSheet* sheet = mPresContext->Document()->GetAttributeStyleSheet()) {
286 0 : sheet->CalculateMappedServoDeclarations(mPresContext);
287 : }
288 :
289 0 : mPresContext->Document()->ResolveScheduledSVGPresAttrs();
290 0 : }
291 :
292 : void
293 0 : ServoStyleSet::PreTraverseSync()
294 : {
295 0 : ResolveMappedAttrDeclarationBlocks();
296 :
297 0 : nsCSSRuleProcessor::InitSystemMetrics();
298 :
299 : // This is lazily computed and pseudo matching needs to access
300 : // it so force computation early.
301 0 : mPresContext->Document()->GetDocumentState();
302 :
303 0 : if (gfxUserFontSet* userFontSet = mPresContext->Document()->GetUserFontSet()) {
304 : // Ensure that the @font-face data is not stale
305 0 : uint64_t generation = userFontSet->GetGeneration();
306 0 : if (generation != mUserFontSetUpdateGeneration) {
307 0 : mPresContext->DeviceContext()->UpdateFontCacheUserFonts(userFontSet);
308 0 : mUserFontSetUpdateGeneration = generation;
309 : }
310 :
311 : // Ensure that the FontFaceSet's cached document principal is up to date.
312 : FontFaceSet* fontFaceSet =
313 0 : static_cast<FontFaceSet::UserFontSet*>(userFontSet)->GetFontFaceSet();
314 0 : fontFaceSet->UpdateStandardFontLoadPrincipal();
315 0 : bool principalChanged = fontFaceSet->HasStandardFontLoadPrincipalChanged();
316 :
317 : // Ensure that the user font cache holds up-to-date data on whether
318 : // our font set is allowed to re-use fonts from the cache.
319 0 : uint32_t cacheGeneration = gfxUserFontSet::UserFontCache::Generation();
320 0 : if (principalChanged) {
321 0 : gfxUserFontSet::UserFontCache::ClearAllowedFontSets(userFontSet);
322 : }
323 0 : if (cacheGeneration != mUserFontCacheUpdateGeneration || principalChanged) {
324 0 : gfxUserFontSet::UserFontCache::UpdateAllowedFontSets(userFontSet);
325 0 : mUserFontCacheUpdateGeneration = cacheGeneration;
326 : }
327 : }
328 :
329 0 : UpdateStylistIfNeeded();
330 0 : mPresContext->CacheAllLangs();
331 0 : }
332 :
333 : void
334 0 : ServoStyleSet::PreTraverse(Element* aRoot,
335 : EffectCompositor::AnimationRestyleType aRestyleType)
336 : {
337 0 : PreTraverseSync();
338 :
339 : // Process animation stuff that we should avoid doing during the parallel
340 : // traversal.
341 : nsSMILAnimationController* smilController =
342 0 : mPresContext->Document()->GetAnimationController();
343 0 : if (aRoot) {
344 0 : mPresContext->EffectCompositor()
345 0 : ->PreTraverseInSubtree(aRoot, aRestyleType);
346 0 : if (smilController) {
347 0 : smilController->PreTraverseInSubtree(aRoot);
348 : }
349 : } else {
350 0 : mPresContext->EffectCompositor()->PreTraverse(aRestyleType);
351 0 : if (smilController) {
352 0 : smilController->PreTraverse();
353 : }
354 : }
355 0 : }
356 :
357 : bool
358 0 : ServoStyleSet::PrepareAndTraverseSubtree(
359 : RawGeckoElementBorrowed aRoot,
360 : TraversalRootBehavior aRootBehavior,
361 : TraversalRestyleBehavior aRestyleBehavior)
362 : {
363 : bool forAnimationOnly =
364 0 : aRestyleBehavior == TraversalRestyleBehavior::ForAnimationOnly;
365 :
366 : AutoRestyleTimelineMarker marker(
367 0 : mPresContext->GetDocShell(), forAnimationOnly);
368 :
369 : // Get the Document's root element to ensure that the cache is valid before
370 : // calling into the (potentially-parallel) Servo traversal, where a cache hit
371 : // is necessary to avoid a data race when updating the cache.
372 0 : mozilla::Unused << aRoot->OwnerDoc()->GetRootElement();
373 :
374 0 : MOZ_ASSERT(!StylistNeedsUpdate());
375 0 : AutoSetInServoTraversal guard(this);
376 :
377 0 : const SnapshotTable& snapshots = Snapshots();
378 :
379 0 : bool isInitial = !aRoot->HasServoData();
380 : bool forReconstruct =
381 0 : aRestyleBehavior == TraversalRestyleBehavior::ForReconstruct;
382 : #ifdef DEBUG
383 : bool forNewlyBoundElement =
384 0 : aRestyleBehavior == TraversalRestyleBehavior::ForNewlyBoundElement;
385 : #endif
386 : bool postTraversalRequired = Servo_TraverseSubtree(
387 0 : aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior);
388 0 : MOZ_ASSERT(!(isInitial || forReconstruct || forNewlyBoundElement) ||
389 : !postTraversalRequired);
390 :
391 : // Don't need to trigger a second traversal if this restyle only needs
392 : // animation-only restyle.
393 0 : if (forAnimationOnly) {
394 0 : return postTraversalRequired;
395 : }
396 :
397 0 : auto root = const_cast<Element*>(aRoot);
398 :
399 : // If there are still animation restyles needed, trigger a second traversal to
400 : // update CSS animations or transitions' styles.
401 : //
402 : // We don't need to do this for SMIL since SMIL only updates its animation
403 : // values once at the begin of a tick. As a result, even if the previous
404 : // traversal caused, for example, the font-size to change, the SMIL style
405 : // won't be updated until the next tick anyway.
406 0 : EffectCompositor* compositor = mPresContext->EffectCompositor();
407 : EffectCompositor::AnimationRestyleType restyleType =
408 0 : EffectCompositor::AnimationRestyleType::Throttled;
409 0 : if (forReconstruct ? compositor->PreTraverseInSubtree(root, restyleType)
410 : : compositor->PreTraverse(restyleType)) {
411 0 : if (Servo_TraverseSubtree(
412 0 : aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior)) {
413 0 : MOZ_ASSERT(!forReconstruct);
414 0 : if (isInitial) {
415 : // We're doing initial styling, and the additional animation
416 : // traversal changed the styles that were set by the first traversal.
417 : // This would normally require a post-traversal to update the style
418 : // contexts, and the DOM now has dirty descendant bits and RestyleData
419 : // in expectation of that post-traversal. But since this is actually
420 : // the initial styling, there are no style contexts to update and no
421 : // frames to apply the change hints to, so we don't need to do that
422 : // post-traversal. Instead, just drop this state and tell the caller
423 : // that no post-traversal is required.
424 0 : MOZ_ASSERT(!postTraversalRequired);
425 0 : ServoRestyleManager::ClearRestyleStateFromSubtree(root);
426 : } else {
427 0 : postTraversalRequired = true;
428 : }
429 : }
430 : }
431 :
432 0 : return postTraversalRequired;
433 : }
434 :
435 : already_AddRefed<nsStyleContext>
436 0 : ServoStyleSet::ResolveStyleForText(nsIContent* aTextNode,
437 : nsStyleContext* aParentContext)
438 : {
439 0 : MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
440 0 : MOZ_ASSERT(aTextNode->GetParent());
441 0 : MOZ_ASSERT(aParentContext);
442 :
443 : // Gecko expects text node style contexts to be like elements that match no
444 : // rules: inherit the inherit structs, reset the reset structs. This is cheap
445 : // enough to do on the main thread, which means that the parallel style system
446 : // can avoid worrying about text nodes.
447 : const ServoComputedValues* parentComputedValues =
448 0 : aParentContext->ComputedValues();
449 : RefPtr<ServoComputedValues> computedValues =
450 0 : Servo_ComputedValues_Inherit(mRawSet.get(),
451 : parentComputedValues,
452 0 : InheritTarget::Text).Consume();
453 :
454 0 : return GetContext(computedValues.forget(), aParentContext,
455 : nsCSSAnonBoxes::mozText,
456 : CSSPseudoElementType::InheritingAnonBox,
457 0 : nullptr);
458 : }
459 :
460 : already_AddRefed<nsStyleContext>
461 0 : ServoStyleSet::ResolveStyleForFirstLetterContinuation(nsStyleContext* aParentContext)
462 : {
463 : const ServoComputedValues* parent =
464 0 : aParentContext->ComputedValues();
465 : RefPtr<ServoComputedValues> computedValues =
466 0 : Servo_ComputedValues_Inherit(mRawSet.get(),
467 : parent,
468 : InheritTarget::FirstLetterContinuation)
469 0 : .Consume();
470 0 : MOZ_ASSERT(computedValues);
471 :
472 0 : return GetContext(computedValues.forget(), aParentContext,
473 : nsCSSAnonBoxes::firstLetterContinuation,
474 : CSSPseudoElementType::InheritingAnonBox,
475 0 : nullptr);
476 : }
477 :
478 : already_AddRefed<nsStyleContext>
479 0 : ServoStyleSet::ResolveStyleForPlaceholder()
480 : {
481 : RefPtr<nsStyleContext>& cache =
482 0 : mNonInheritingStyleContexts[nsCSSAnonBoxes::NonInheriting::oofPlaceholder];
483 0 : if (cache) {
484 0 : RefPtr<nsStyleContext> retval = cache;
485 0 : return retval.forget();
486 : }
487 :
488 : RefPtr<ServoComputedValues> computedValues =
489 0 : Servo_ComputedValues_Inherit(mRawSet.get(),
490 : nullptr,
491 : InheritTarget::PlaceholderFrame)
492 0 : .Consume();
493 0 : MOZ_ASSERT(computedValues);
494 :
495 : RefPtr<nsStyleContext> retval =
496 0 : GetContext(computedValues.forget(), nullptr,
497 : nsCSSAnonBoxes::oofPlaceholder,
498 : CSSPseudoElementType::NonInheritingAnonBox,
499 0 : nullptr);
500 0 : cache = retval;
501 0 : return retval.forget();
502 : }
503 :
504 : already_AddRefed<nsStyleContext>
505 0 : ServoStyleSet::ResolvePseudoElementStyle(Element* aOriginatingElement,
506 : CSSPseudoElementType aType,
507 : nsStyleContext* aParentContext,
508 : Element* aPseudoElement)
509 : {
510 0 : UpdateStylistIfNeeded();
511 :
512 0 : MOZ_ASSERT(aType < CSSPseudoElementType::Count);
513 :
514 0 : RefPtr<ServoComputedValues> computedValues;
515 0 : if (aPseudoElement) {
516 0 : MOZ_ASSERT(aType == aPseudoElement->GetPseudoElementType());
517 0 : computedValues = Servo_ResolveStyle(aPseudoElement,
518 0 : mRawSet.get()).Consume();
519 : } else {
520 : const ServoComputedValues* parentStyle =
521 0 : aParentContext ? aParentContext->ComputedValues() : nullptr;
522 : computedValues =
523 0 : Servo_ResolvePseudoStyle(aOriginatingElement,
524 : aType,
525 : /* is_probe = */ false,
526 : parentStyle,
527 0 : mRawSet.get()).Consume();
528 : }
529 :
530 0 : MOZ_ASSERT(computedValues);
531 :
532 0 : bool isBeforeOrAfter = aType == CSSPseudoElementType::before ||
533 0 : aType == CSSPseudoElementType::after;
534 :
535 0 : nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
536 0 : return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType,
537 0 : isBeforeOrAfter ? aOriginatingElement : nullptr);
538 : }
539 :
540 : already_AddRefed<nsStyleContext>
541 0 : ServoStyleSet::ResolveTransientStyle(Element* aElement,
542 : nsIAtom* aPseudoTag,
543 : CSSPseudoElementType aPseudoType,
544 : StyleRuleInclusion aRuleInclusion)
545 : {
546 : RefPtr<ServoComputedValues> computedValues =
547 0 : ResolveTransientServoStyle(aElement, aPseudoType, aRuleInclusion);
548 :
549 0 : return GetContext(computedValues.forget(),
550 : nullptr,
551 : aPseudoTag,
552 0 : aPseudoType, nullptr);
553 : }
554 :
555 : already_AddRefed<ServoComputedValues>
556 0 : ServoStyleSet::ResolveTransientServoStyle(
557 : Element* aElement,
558 : CSSPseudoElementType aPseudoType,
559 : StyleRuleInclusion aRuleInclusion)
560 : {
561 0 : PreTraverseSync();
562 0 : return ResolveStyleLazily(aElement, aPseudoType, aRuleInclusion);
563 : }
564 :
565 : already_AddRefed<ServoStyleContext>
566 0 : ServoStyleSet::ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
567 : nsStyleContext* aParentContext)
568 : {
569 0 : MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
570 : !nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag));
571 :
572 0 : UpdateStylistIfNeeded();
573 :
574 : bool skipFixup =
575 0 : nsCSSAnonBoxes::AnonBoxSkipsParentDisplayBasedStyleFixup(aPseudoTag);
576 :
577 : const ServoComputedValues* parentStyle =
578 0 : aParentContext ? aParentContext->ComputedValues()
579 0 : : nullptr;
580 : RefPtr<ServoComputedValues> computedValues =
581 0 : Servo_ComputedValues_GetForAnonymousBox(parentStyle, aPseudoTag, skipFixup,
582 0 : mRawSet.get()).Consume();
583 : #ifdef DEBUG
584 0 : if (!computedValues) {
585 0 : nsString pseudo;
586 0 : aPseudoTag->ToString(pseudo);
587 0 : NS_ERROR(nsPrintfCString("stylo: could not get anon-box: %s",
588 : NS_ConvertUTF16toUTF8(pseudo).get()).get());
589 0 : MOZ_CRASH();
590 : }
591 : #endif
592 :
593 0 : return GetContext(computedValues.forget(), aParentContext, aPseudoTag,
594 0 : CSSPseudoElementType::InheritingAnonBox, nullptr);
595 : }
596 :
597 : already_AddRefed<nsStyleContext>
598 0 : ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag)
599 : {
600 0 : MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
601 : nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag));
602 0 : MOZ_ASSERT(aPseudoTag != nsCSSAnonBoxes::pageContent,
603 : "If nsCSSAnonBoxes::pageContent ends up non-inheriting, check "
604 : "whether we need to do anything to move the "
605 : "@page handling from ResolveInheritingAnonymousBoxStyle to "
606 : "ResolveNonInheritingAnonymousBoxStyle");
607 :
608 : nsCSSAnonBoxes::NonInheriting type =
609 0 : nsCSSAnonBoxes::NonInheritingTypeForPseudoTag(aPseudoTag);
610 0 : RefPtr<nsStyleContext>& cache = mNonInheritingStyleContexts[type];
611 0 : if (cache) {
612 0 : RefPtr<nsStyleContext> retval = cache;
613 0 : return retval.forget();
614 : }
615 :
616 0 : UpdateStylistIfNeeded();
617 :
618 : // We always want to skip parent-based display fixup here. It never makes
619 : // sense for non-inheriting anonymous boxes. (Static assertions in
620 : // nsCSSAnonBoxes.cpp ensure that all non-inheriting non-anonymous boxes
621 : // are indeed annotated as skipping this fixup.)
622 0 : MOZ_ASSERT(!nsCSSAnonBoxes::IsNonInheritingAnonBox(nsCSSAnonBoxes::viewport),
623 : "viewport needs fixup to handle blockifying it");
624 : RefPtr<ServoComputedValues> computedValues =
625 0 : Servo_ComputedValues_GetForAnonymousBox(nullptr, aPseudoTag, true,
626 0 : mRawSet.get()).Consume();
627 : #ifdef DEBUG
628 0 : if (!computedValues) {
629 0 : nsString pseudo;
630 0 : aPseudoTag->ToString(pseudo);
631 0 : NS_ERROR(nsPrintfCString("stylo: could not get anon-box: %s",
632 : NS_ConvertUTF16toUTF8(pseudo).get()).get());
633 0 : MOZ_CRASH();
634 : }
635 : #endif
636 :
637 : RefPtr<nsStyleContext> retval =
638 0 : GetContext(computedValues.forget(), nullptr, aPseudoTag,
639 0 : CSSPseudoElementType::NonInheritingAnonBox, nullptr);
640 0 : cache = retval;
641 0 : return retval.forget();
642 : }
643 :
644 : // manage the set of style sheets in the style set
645 : nsresult
646 0 : ServoStyleSet::AppendStyleSheet(SheetType aType,
647 : ServoStyleSheet* aSheet)
648 : {
649 0 : MOZ_ASSERT(aSheet);
650 0 : MOZ_ASSERT(aSheet->IsApplicable());
651 0 : MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
652 0 : MOZ_ASSERT(aSheet->RawContents(), "Raw sheet should be in place before insertion.");
653 :
654 0 : RemoveSheetOfType(aType, aSheet);
655 0 : AppendSheetOfType(aType, aSheet);
656 :
657 0 : if (mRawSet) {
658 : // Maintain a mirrored list of sheets on the servo side.
659 : // Servo will remove aSheet from its original position as part of the call
660 : // to Servo_StyleSet_AppendStyleSheet.
661 0 : Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet);
662 0 : SetStylistStyleSheetsDirty();
663 : }
664 :
665 0 : return NS_OK;
666 : }
667 :
668 : nsresult
669 0 : ServoStyleSet::PrependStyleSheet(SheetType aType,
670 : ServoStyleSheet* aSheet)
671 : {
672 0 : MOZ_ASSERT(aSheet);
673 0 : MOZ_ASSERT(aSheet->IsApplicable());
674 0 : MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
675 0 : MOZ_ASSERT(aSheet->RawContents(),
676 : "Raw sheet should be in place before insertion.");
677 :
678 0 : RemoveSheetOfType(aType, aSheet);
679 0 : PrependSheetOfType(aType, aSheet);
680 :
681 0 : if (mRawSet) {
682 : // Maintain a mirrored list of sheets on the servo side.
683 : // Servo will remove aSheet from its original position as part of the call
684 : // to Servo_StyleSet_PrependStyleSheet.
685 0 : Servo_StyleSet_PrependStyleSheet(mRawSet.get(), aSheet);
686 0 : SetStylistStyleSheetsDirty();
687 : }
688 :
689 0 : return NS_OK;
690 : }
691 :
692 : nsresult
693 0 : ServoStyleSet::RemoveStyleSheet(SheetType aType,
694 : ServoStyleSheet* aSheet)
695 : {
696 0 : MOZ_ASSERT(aSheet);
697 0 : MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
698 :
699 0 : RemoveSheetOfType(aType, aSheet);
700 0 : if (mRawSet) {
701 : // Maintain a mirrored list of sheets on the servo side.
702 0 : Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), aSheet);
703 0 : SetStylistStyleSheetsDirty();
704 : }
705 :
706 0 : return NS_OK;
707 : }
708 :
709 : nsresult
710 0 : ServoStyleSet::ReplaceSheets(SheetType aType,
711 : const nsTArray<RefPtr<ServoStyleSheet>>& aNewSheets)
712 : {
713 : // Gecko uses a two-dimensional array keyed by sheet type, whereas Servo
714 : // stores a flattened list. This makes ReplaceSheets a pretty clunky thing
715 : // to express. If the need ever arises, we can easily make this more efficent,
716 : // probably by aligning the representations better between engines.
717 :
718 0 : SetStylistStyleSheetsDirty();
719 :
720 : // Remove all the existing sheets first.
721 0 : for (const auto& sheet : mSheets[aType]) {
722 0 : sheet->DropStyleSet(this);
723 0 : if (mRawSet) {
724 0 : Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), sheet);
725 : }
726 : }
727 0 : mSheets[aType].Clear();
728 :
729 : // Add in all the new sheets.
730 0 : for (auto& sheet : aNewSheets) {
731 0 : AppendSheetOfType(aType, sheet);
732 0 : if (mRawSet) {
733 0 : MOZ_ASSERT(sheet->RawContents(), "Raw sheet should be in place before replacement.");
734 0 : Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet);
735 : }
736 : }
737 :
738 0 : return NS_OK;
739 : }
740 :
741 : nsresult
742 0 : ServoStyleSet::InsertStyleSheetBefore(SheetType aType,
743 : ServoStyleSheet* aNewSheet,
744 : ServoStyleSheet* aReferenceSheet)
745 : {
746 0 : MOZ_ASSERT(aNewSheet);
747 0 : MOZ_ASSERT(aReferenceSheet);
748 0 : MOZ_ASSERT(aNewSheet->IsApplicable());
749 0 : MOZ_ASSERT(aNewSheet != aReferenceSheet, "Can't place sheet before itself.");
750 0 : MOZ_ASSERT(aNewSheet->RawContents(), "Raw sheet should be in place before insertion.");
751 0 : MOZ_ASSERT(aReferenceSheet->RawContents(), "Reference sheet should have a raw sheet.");
752 :
753 : // Servo will remove aNewSheet from its original position as part of the
754 : // call to Servo_StyleSet_InsertStyleSheetBefore.
755 0 : RemoveSheetOfType(aType, aNewSheet);
756 0 : InsertSheetOfType(aType, aNewSheet, aReferenceSheet);
757 :
758 0 : if (mRawSet) {
759 : // Maintain a mirrored list of sheets on the servo side.
760 : Servo_StyleSet_InsertStyleSheetBefore(
761 0 : mRawSet.get(), aNewSheet, aReferenceSheet);
762 0 : SetStylistStyleSheetsDirty();
763 : }
764 :
765 0 : return NS_OK;
766 : }
767 :
768 : void
769 0 : ServoStyleSet::UpdateStyleSheet(ServoStyleSheet* aSheet)
770 : {
771 0 : MOZ_ASSERT(aSheet);
772 : // TODO(emilio): Get rid of this.
773 0 : }
774 :
775 : int32_t
776 0 : ServoStyleSet::SheetCount(SheetType aType) const
777 : {
778 0 : MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
779 0 : return mSheets[aType].Length();
780 : }
781 :
782 : ServoStyleSheet*
783 0 : ServoStyleSet::StyleSheetAt(SheetType aType, int32_t aIndex) const
784 : {
785 0 : MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
786 0 : return mSheets[aType][aIndex];
787 : }
788 :
789 : void
790 0 : ServoStyleSet::AppendAllXBLStyleSheets(nsTArray<StyleSheet*>& aArray) const
791 : {
792 0 : if (mBindingManager) {
793 0 : mBindingManager->AppendAllSheets(aArray);
794 : }
795 0 : }
796 :
797 : nsresult
798 0 : ServoStyleSet::RemoveDocStyleSheet(ServoStyleSheet* aSheet)
799 : {
800 0 : return RemoveStyleSheet(SheetType::Doc, aSheet);
801 : }
802 :
803 : nsresult
804 0 : ServoStyleSet::AddDocStyleSheet(ServoStyleSheet* aSheet,
805 : nsIDocument* aDocument)
806 : {
807 0 : MOZ_ASSERT(aSheet->IsApplicable());
808 0 : MOZ_ASSERT(aSheet->RawContents(), "Raw sheet should be in place by this point.");
809 :
810 0 : RefPtr<StyleSheet> strong(aSheet);
811 :
812 0 : RemoveSheetOfType(SheetType::Doc, aSheet);
813 :
814 : size_t index =
815 0 : aDocument->FindDocStyleSheetInsertionPoint(mSheets[SheetType::Doc], aSheet);
816 :
817 0 : if (index < mSheets[SheetType::Doc].Length()) {
818 : // This case is insert before.
819 0 : ServoStyleSheet *beforeSheet = mSheets[SheetType::Doc][index];
820 0 : InsertSheetOfType(SheetType::Doc, aSheet, beforeSheet);
821 :
822 0 : if (mRawSet) {
823 : // Maintain a mirrored list of sheets on the servo side.
824 0 : Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aSheet, beforeSheet);
825 0 : SetStylistStyleSheetsDirty();
826 : }
827 : } else {
828 : // This case is append.
829 0 : AppendSheetOfType(SheetType::Doc, aSheet);
830 :
831 0 : if (mRawSet) {
832 : // Maintain a mirrored list of sheets on the servo side.
833 0 : Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet);
834 0 : SetStylistStyleSheetsDirty();
835 : }
836 : }
837 :
838 0 : return NS_OK;
839 : }
840 :
841 : already_AddRefed<nsStyleContext>
842 0 : ServoStyleSet::ProbePseudoElementStyle(Element* aOriginatingElement,
843 : CSSPseudoElementType aType,
844 : nsStyleContext* aParentContext)
845 : {
846 0 : UpdateStylistIfNeeded();
847 :
848 : // NB: We ignore aParentContext, because in some cases
849 : // (first-line/first-letter on anonymous box blocks) Gecko passes something
850 : // nonsensical there. In all other cases we want to inherit directly from
851 : // aOriginatingElement's styles anyway.
852 0 : MOZ_ASSERT(aType < CSSPseudoElementType::Count);
853 :
854 : RefPtr<ServoComputedValues> computedValues =
855 0 : Servo_ResolvePseudoStyle(aOriginatingElement, aType,
856 : /* is_probe = */ true,
857 : nullptr,
858 0 : mRawSet.get()).Consume();
859 0 : if (!computedValues) {
860 0 : return nullptr;
861 : }
862 :
863 : // For :before and :after pseudo-elements, having display: none or no
864 : // 'content' property is equivalent to not having the pseudo-element
865 : // at all.
866 0 : bool isBeforeOrAfter = aType == CSSPseudoElementType::before ||
867 0 : aType == CSSPseudoElementType::after;
868 0 : if (isBeforeOrAfter) {
869 0 : const nsStyleDisplay* display = Servo_GetStyleDisplay(computedValues);
870 0 : const nsStyleContent* content = Servo_GetStyleContent(computedValues);
871 : // XXXldb What is contentCount for |content: ""|?
872 0 : if (display->mDisplay == StyleDisplay::None ||
873 0 : content->ContentCount() == 0) {
874 0 : return nullptr;
875 : }
876 : }
877 :
878 0 : nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
879 0 : return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType,
880 0 : isBeforeOrAfter ? aOriginatingElement : nullptr);
881 : }
882 :
883 : nsRestyleHint
884 0 : ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
885 : EventStates aStateMask)
886 : {
887 0 : NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
888 0 : return nsRestyleHint(0);
889 : }
890 :
891 : nsRestyleHint
892 0 : ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
893 : CSSPseudoElementType aPseudoType,
894 : dom::Element* aPseudoElement,
895 : EventStates aStateMask)
896 : {
897 0 : NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
898 0 : return nsRestyleHint(0);
899 : }
900 :
901 : bool
902 0 : ServoStyleSet::StyleDocument(TraversalRestyleBehavior aRestyleBehavior)
903 : {
904 0 : MOZ_ASSERT(
905 : aRestyleBehavior == TraversalRestyleBehavior::Normal ||
906 : aRestyleBehavior == TraversalRestyleBehavior::ForCSSRuleChanges,
907 : "StyleDocument() should be only called for normal traversal or CSS rule "
908 : "changes");
909 :
910 0 : PreTraverse();
911 :
912 : // Restyle the document from the root element and each of the document level
913 : // NAC subtree roots.
914 0 : bool postTraversalRequired = false;
915 0 : DocumentStyleRootIterator iter(mPresContext->Document());
916 0 : while (Element* root = iter.GetNextStyleRoot()) {
917 0 : if (PrepareAndTraverseSubtree(root,
918 : TraversalRootBehavior::Normal,
919 : aRestyleBehavior)) {
920 0 : postTraversalRequired = true;
921 : }
922 0 : }
923 0 : return postTraversalRequired;
924 : }
925 :
926 : bool
927 0 : ServoStyleSet::StyleDocumentForAnimationOnly()
928 : {
929 0 : PreTraverse(nullptr, EffectCompositor::AnimationRestyleType::Full);
930 :
931 0 : bool postTraversalRequired = false;
932 0 : DocumentStyleRootIterator iter(mPresContext->Document());
933 0 : while (Element* root = iter.GetNextStyleRoot()) {
934 0 : if (PrepareAndTraverseSubtree(root,
935 : TraversalRootBehavior::Normal,
936 : TraversalRestyleBehavior::ForAnimationOnly)) {
937 0 : postTraversalRequired = true;
938 : }
939 0 : }
940 0 : return postTraversalRequired;
941 : }
942 :
943 : void
944 0 : ServoStyleSet::StyleNewSubtree(Element* aRoot)
945 : {
946 0 : MOZ_ASSERT(!aRoot->HasServoData());
947 :
948 0 : PreTraverse();
949 :
950 : DebugOnly<bool> postTraversalRequired =
951 0 : PrepareAndTraverseSubtree(aRoot,
952 : TraversalRootBehavior::Normal,
953 0 : TraversalRestyleBehavior::Normal);
954 0 : MOZ_ASSERT(!postTraversalRequired);
955 0 : }
956 :
957 : void
958 0 : ServoStyleSet::StyleNewChildren(Element* aParent)
959 : {
960 0 : PreTraverse();
961 :
962 : PrepareAndTraverseSubtree(aParent,
963 : TraversalRootBehavior::UnstyledChildrenOnly,
964 0 : TraversalRestyleBehavior::Normal);
965 : // We can't assert that Servo_TraverseSubtree returns false, since aParent
966 : // or some of its other children might have pending restyles.
967 0 : }
968 :
969 : void
970 0 : ServoStyleSet::StyleNewlyBoundElement(Element* aElement)
971 : {
972 0 : PreTraverse();
973 :
974 : // In general the element is always styled by the time we're applying XBL
975 : // bindings, because we need to style the element to know what the binding
976 : // URI is. However, programmatic consumers of the XBL service (like the
977 : // XML pretty printer) _can_ apply bindings without having styled the bound
978 : // element. We could assert against this and require the callers manually
979 : // resolve the style first, but it's easy enough to just handle here.
980 : //
981 : // Also, when applying XBL bindings to elements within a display:none or
982 : // unstyled subtree (for example, when <object> elements are wrapped to be
983 : // exposed to JS), we need to tell the traversal that it is OK to
984 : // skip restyling, rather than panic when trying to unwrap the styles
985 : // it expects to have just computed.
986 :
987 : TraversalRootBehavior rootBehavior =
988 0 : MOZ_UNLIKELY(!aElement->HasServoData())
989 0 : ? TraversalRootBehavior::Normal
990 0 : : TraversalRootBehavior::UnstyledChildrenOnly;
991 :
992 : PrepareAndTraverseSubtree(aElement,
993 : rootBehavior,
994 0 : TraversalRestyleBehavior::ForNewlyBoundElement);
995 0 : }
996 :
997 : void
998 0 : ServoStyleSet::StyleSubtreeForReconstruct(Element* aRoot)
999 : {
1000 0 : PreTraverse(aRoot);
1001 :
1002 : DebugOnly<bool> postTraversalRequired =
1003 0 : PrepareAndTraverseSubtree(aRoot,
1004 : TraversalRootBehavior::Normal,
1005 0 : TraversalRestyleBehavior::ForReconstruct);
1006 0 : MOZ_ASSERT(!postTraversalRequired);
1007 0 : }
1008 :
1009 : void
1010 0 : ServoStyleSet::ForceAllStyleDirty()
1011 : {
1012 0 : SetStylistStyleSheetsDirty();
1013 0 : Servo_StyleSet_NoteStyleSheetsChanged(mRawSet.get(), mAuthorStyleDisabled);
1014 0 : }
1015 :
1016 : void
1017 0 : ServoStyleSet::RecordStyleSheetChange(
1018 : ServoStyleSheet* aSheet,
1019 : StyleSheet::ChangeType aChangeType)
1020 : {
1021 0 : SetStylistStyleSheetsDirty();
1022 0 : switch (aChangeType) {
1023 : case StyleSheet::ChangeType::RuleAdded:
1024 : case StyleSheet::ChangeType::RuleRemoved:
1025 : case StyleSheet::ChangeType::RuleChanged:
1026 : // FIXME(emilio): We can presumably do better in a bunch of these.
1027 0 : return ForceAllStyleDirty();
1028 : case StyleSheet::ChangeType::ApplicableStateChanged:
1029 : case StyleSheet::ChangeType::Added:
1030 : case StyleSheet::ChangeType::Removed:
1031 : // Do nothing, we've already recorded the change in the
1032 : // Append/Remove/Replace methods, etc, and will act consequently.
1033 0 : return;
1034 : }
1035 : }
1036 :
1037 : #ifdef DEBUG
1038 : void
1039 0 : ServoStyleSet::AssertTreeIsClean()
1040 : {
1041 0 : DocumentStyleRootIterator iter(mPresContext->Document());
1042 0 : while (Element* root = iter.GetNextStyleRoot()) {
1043 0 : Servo_AssertTreeIsClean(root);
1044 0 : }
1045 0 : }
1046 : #endif
1047 :
1048 : bool
1049 0 : ServoStyleSet::GetKeyframesForName(const nsString& aName,
1050 : const nsTimingFunction& aTimingFunction,
1051 : nsTArray<Keyframe>& aKeyframes)
1052 : {
1053 0 : UpdateStylistIfNeeded();
1054 :
1055 0 : NS_ConvertUTF16toUTF8 name(aName);
1056 0 : return Servo_StyleSet_GetKeyframesForName(mRawSet.get(),
1057 : &name,
1058 : &aTimingFunction,
1059 0 : &aKeyframes);
1060 : }
1061 :
1062 : nsTArray<ComputedKeyframeValues>
1063 0 : ServoStyleSet::GetComputedKeyframeValuesFor(
1064 : const nsTArray<Keyframe>& aKeyframes,
1065 : Element* aElement,
1066 : ServoComputedValuesBorrowed aComputedValues)
1067 : {
1068 0 : nsTArray<ComputedKeyframeValues> result(aKeyframes.Length());
1069 :
1070 : // Construct each nsTArray<PropertyStyleAnimationValuePair> here.
1071 0 : result.AppendElements(aKeyframes.Length());
1072 :
1073 : Servo_GetComputedKeyframeValues(&aKeyframes,
1074 : aElement,
1075 : aComputedValues,
1076 0 : mRawSet.get(),
1077 0 : &result);
1078 0 : return result;
1079 : }
1080 :
1081 : void
1082 0 : ServoStyleSet::GetAnimationValues(
1083 : RawServoDeclarationBlock* aDeclarations,
1084 : Element* aElement,
1085 : ServoComputedValuesBorrowed aComputedValues,
1086 : nsTArray<RefPtr<RawServoAnimationValue>>& aAnimationValues)
1087 : {
1088 : Servo_GetAnimationValues(aDeclarations,
1089 : aElement,
1090 : aComputedValues,
1091 0 : mRawSet.get(),
1092 0 : &aAnimationValues);
1093 0 : }
1094 :
1095 : already_AddRefed<ServoComputedValues>
1096 0 : ServoStyleSet::GetBaseComputedValuesForElement(
1097 : Element* aElement,
1098 : CSSPseudoElementType aPseudoType,
1099 : ServoComputedValuesBorrowed aStyle)
1100 : {
1101 0 : return Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
1102 : aElement,
1103 : aStyle,
1104 0 : &Snapshots(),
1105 0 : aPseudoType).Consume();
1106 : }
1107 :
1108 : already_AddRefed<RawServoAnimationValue>
1109 0 : ServoStyleSet::ComputeAnimationValue(
1110 : Element* aElement,
1111 : RawServoDeclarationBlock* aDeclarations,
1112 : ServoComputedValuesBorrowed aComputedValues)
1113 : {
1114 0 : return Servo_AnimationValue_Compute(aElement,
1115 : aDeclarations,
1116 : aComputedValues,
1117 0 : mRawSet.get()).Consume();
1118 : }
1119 :
1120 : bool
1121 0 : ServoStyleSet::EnsureUniqueInnerOnCSSSheets()
1122 : {
1123 0 : AutoTArray<StyleSheet*, 32> queue;
1124 0 : for (auto& entryArray : mSheets) {
1125 0 : for (auto& sheet : entryArray) {
1126 0 : queue.AppendElement(sheet);
1127 : }
1128 : }
1129 : // This is a stub until more of the functionality of nsStyleSet is
1130 : // replicated for Servo here.
1131 :
1132 : // Bug 1290276 will replicate the nsStyleSet work of checking
1133 : // a nsBindingManager
1134 :
1135 0 : while (!queue.IsEmpty()) {
1136 0 : uint32_t idx = queue.Length() - 1;
1137 0 : StyleSheet* sheet = queue[idx];
1138 0 : queue.RemoveElementAt(idx);
1139 :
1140 0 : sheet->EnsureUniqueInner();
1141 :
1142 : // Enqueue all the sheet's children.
1143 0 : sheet->AppendAllChildSheets(queue);
1144 : }
1145 :
1146 0 : bool res = mNeedsRestyleAfterEnsureUniqueInner;
1147 0 : mNeedsRestyleAfterEnsureUniqueInner = false;
1148 0 : return res;
1149 : }
1150 :
1151 : void
1152 0 : ServoStyleSet::RebuildData()
1153 : {
1154 0 : ClearNonInheritingStyleContexts();
1155 0 : Servo_StyleSet_RebuildData(mRawSet.get());
1156 0 : }
1157 :
1158 : void
1159 0 : ServoStyleSet::ClearDataAndMarkDeviceDirty()
1160 : {
1161 0 : ClearNonInheritingStyleContexts();
1162 0 : Servo_StyleSet_Clear(mRawSet.get());
1163 0 : mStylistState |= StylistState::FullyDirty;
1164 0 : }
1165 :
1166 : void
1167 0 : ServoStyleSet::CompatibilityModeChanged()
1168 : {
1169 0 : Servo_StyleSet_CompatModeChanged(mRawSet.get());
1170 0 : }
1171 :
1172 : already_AddRefed<ServoComputedValues>
1173 0 : ServoStyleSet::ResolveServoStyle(Element* aElement)
1174 : {
1175 0 : UpdateStylistIfNeeded();
1176 0 : return Servo_ResolveStyle(aElement, mRawSet.get()).Consume();
1177 : }
1178 :
1179 : void
1180 0 : ServoStyleSet::ClearNonInheritingStyleContexts()
1181 : {
1182 0 : for (RefPtr<nsStyleContext>& ptr : mNonInheritingStyleContexts) {
1183 0 : ptr = nullptr;
1184 : }
1185 0 : }
1186 :
1187 : already_AddRefed<ServoComputedValues>
1188 0 : ServoStyleSet::ResolveStyleLazily(Element* aElement,
1189 : CSSPseudoElementType aPseudoType,
1190 : StyleRuleInclusion aRuleInclusion)
1191 : {
1192 0 : mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType);
1193 0 : MOZ_ASSERT(!StylistNeedsUpdate());
1194 :
1195 0 : AutoSetInServoTraversal guard(this);
1196 :
1197 : /**
1198 : * NB: This is needed because we process animations and transitions on the
1199 : * pseudo-elements themselves, not on the parent's EagerPseudoStyles.
1200 : *
1201 : * That means that that style doesn't account for animations, and we can't do
1202 : * that easily from the traversal without doing wasted work.
1203 : *
1204 : * As such, we just lie here a bit, which is the entrypoint of
1205 : * getComputedStyle, the only API where this can be observed, to look at the
1206 : * style of the pseudo-element if it exists instead.
1207 : */
1208 0 : Element* elementForStyleResolution = aElement;
1209 0 : CSSPseudoElementType pseudoTypeForStyleResolution = aPseudoType;
1210 0 : if (aPseudoType == CSSPseudoElementType::before) {
1211 0 : if (Element* pseudo = nsLayoutUtils::GetBeforePseudo(aElement)) {
1212 0 : elementForStyleResolution = pseudo;
1213 0 : pseudoTypeForStyleResolution = CSSPseudoElementType::NotPseudo;
1214 : }
1215 0 : } else if (aPseudoType == CSSPseudoElementType::after) {
1216 0 : if (Element* pseudo = nsLayoutUtils::GetAfterPseudo(aElement)) {
1217 0 : elementForStyleResolution = pseudo;
1218 0 : pseudoTypeForStyleResolution = CSSPseudoElementType::NotPseudo;
1219 : }
1220 : }
1221 :
1222 : RefPtr<ServoComputedValues> computedValues =
1223 0 : Servo_ResolveStyleLazily(elementForStyleResolution,
1224 : pseudoTypeForStyleResolution,
1225 : aRuleInclusion,
1226 0 : &Snapshots(),
1227 0 : mRawSet.get()).Consume();
1228 :
1229 0 : if (mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType)) {
1230 : computedValues =
1231 0 : Servo_ResolveStyleLazily(elementForStyleResolution,
1232 : pseudoTypeForStyleResolution,
1233 : aRuleInclusion,
1234 0 : &Snapshots(),
1235 0 : mRawSet.get()).Consume();
1236 : }
1237 :
1238 0 : return computedValues.forget();
1239 : }
1240 :
1241 : bool
1242 0 : ServoStyleSet::AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray)
1243 : {
1244 0 : UpdateStylistIfNeeded();
1245 0 : Servo_StyleSet_GetFontFaceRules(mRawSet.get(), &aArray);
1246 0 : return true;
1247 : }
1248 :
1249 : nsCSSCounterStyleRule*
1250 0 : ServoStyleSet::CounterStyleRuleForName(nsIAtom* aName)
1251 : {
1252 0 : return Servo_StyleSet_GetCounterStyleRule(mRawSet.get(), aName);
1253 : }
1254 :
1255 : already_AddRefed<ServoComputedValues>
1256 0 : ServoStyleSet::ResolveForDeclarations(
1257 : ServoComputedValuesBorrowedOrNull aParentOrNull,
1258 : RawServoDeclarationBlockBorrowed aDeclarations)
1259 : {
1260 0 : UpdateStylistIfNeeded();
1261 0 : return Servo_StyleSet_ResolveForDeclarations(mRawSet.get(),
1262 : aParentOrNull,
1263 0 : aDeclarations).Consume();
1264 : }
1265 :
1266 : void
1267 0 : ServoStyleSet::UpdateStylist()
1268 : {
1269 0 : MOZ_ASSERT(StylistNeedsUpdate());
1270 0 : if (mStylistState & StylistState::FullyDirty) {
1271 0 : RebuildData();
1272 :
1273 0 : if (mStylistState & StylistState::StyleSheetsDirty) {
1274 : // Normally, whoever was in charge of posting a RebuildAllStyleDataEvent,
1275 : // would also be in charge of posting a restyle/change hint according to
1276 : // it.
1277 : //
1278 : // However, other stylesheets may have been added to the document in the
1279 : // same period, so when both bits are set, we need to do a full subtree
1280 : // update, because we can no longer reason about the state of the style
1281 : // data.
1282 : //
1283 : // We could not clear the invalidations when rebuilding the data and
1284 : // process them here... But it's not clear if that complexity is worth
1285 : // to handle this edge case more efficiently.
1286 0 : if (Element* root = mPresContext->Document()->GetDocumentElement()) {
1287 0 : Servo_NoteExplicitHints(root, eRestyle_Subtree, nsChangeHint(0));
1288 : }
1289 : }
1290 : } else {
1291 0 : MOZ_ASSERT(mStylistState & StylistState::StyleSheetsDirty);
1292 0 : Element* root = mPresContext->Document()->GetDocumentElement();
1293 0 : Servo_StyleSet_FlushStyleSheets(mRawSet.get(), root);
1294 : }
1295 0 : mStylistState = StylistState::NotDirty;
1296 0 : }
1297 :
1298 : void
1299 0 : ServoStyleSet::MaybeGCRuleTree()
1300 : {
1301 0 : MOZ_ASSERT(NS_IsMainThread());
1302 0 : Servo_MaybeGCRuleTree(mRawSet.get());
1303 0 : }
1304 :
1305 : void
1306 0 : ServoStyleSet::PrependSheetOfType(SheetType aType,
1307 : ServoStyleSheet* aSheet)
1308 : {
1309 0 : aSheet->AddStyleSet(this);
1310 0 : mSheets[aType].InsertElementAt(0, aSheet);
1311 0 : }
1312 :
1313 : void
1314 0 : ServoStyleSet::AppendSheetOfType(SheetType aType,
1315 : ServoStyleSheet* aSheet)
1316 : {
1317 0 : aSheet->AddStyleSet(this);
1318 0 : mSheets[aType].AppendElement(aSheet);
1319 0 : }
1320 :
1321 : void
1322 0 : ServoStyleSet::InsertSheetOfType(SheetType aType,
1323 : ServoStyleSheet* aSheet,
1324 : ServoStyleSheet* aBeforeSheet)
1325 : {
1326 0 : for (uint32_t i = 0; i < mSheets[aType].Length(); ++i) {
1327 0 : if (mSheets[aType][i] == aBeforeSheet) {
1328 0 : aSheet->AddStyleSet(this);
1329 0 : mSheets[aType].InsertElementAt(i, aSheet);
1330 0 : return;
1331 : }
1332 : }
1333 : }
1334 :
1335 : void
1336 0 : ServoStyleSet::RemoveSheetOfType(SheetType aType,
1337 : ServoStyleSheet* aSheet)
1338 : {
1339 0 : for (uint32_t i = 0; i < mSheets[aType].Length(); ++i) {
1340 0 : if (mSheets[aType][i] == aSheet) {
1341 0 : aSheet->DropStyleSet(this);
1342 0 : mSheets[aType].RemoveElementAt(i);
1343 : }
1344 : }
1345 0 : }
1346 :
1347 : void
1348 0 : ServoStyleSet::RunPostTraversalTasks()
1349 : {
1350 0 : MOZ_ASSERT(!IsInServoTraversal());
1351 :
1352 0 : if (mPostTraversalTasks.IsEmpty()) {
1353 0 : return;
1354 : }
1355 :
1356 0 : nsTArray<PostTraversalTask> tasks;
1357 0 : tasks.SwapElements(mPostTraversalTasks);
1358 :
1359 0 : for (auto& task : tasks) {
1360 0 : task.Run();
1361 : }
1362 : }
1363 :
1364 : ServoStyleRuleMap*
1365 0 : ServoStyleSet::StyleRuleMap()
1366 : {
1367 0 : if (!mStyleRuleMap) {
1368 0 : mStyleRuleMap = new ServoStyleRuleMap(this);
1369 0 : nsIDocument* doc = mPresContext->Document();
1370 0 : doc->AddObserver(mStyleRuleMap);
1371 0 : doc->CSSLoader()->AddObserver(mStyleRuleMap);
1372 : }
1373 0 : return mStyleRuleMap;
1374 : }
1375 :
1376 : bool
1377 0 : ServoStyleSet::MightHaveAttributeDependency(const Element& aElement,
1378 : nsIAtom* aAttribute) const
1379 : {
1380 : return Servo_StyleSet_MightHaveAttributeDependency(
1381 0 : mRawSet.get(), &aElement, aAttribute);
1382 : }
1383 :
1384 : bool
1385 0 : ServoStyleSet::HasStateDependency(const Element& aElement,
1386 : EventStates aState) const
1387 : {
1388 0 : return Servo_StyleSet_HasStateDependency(
1389 0 : mRawSet.get(), &aElement, aState.ServoValue());
1390 : }
1391 :
1392 : ServoStyleSet* ServoStyleSet::sInServoTraversal = nullptr;
|