Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/style/ServoStyleSet.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "mozilla/ServoStyleSetInlines.h"
9
10
#include "gfxPlatformFontList.h"
11
#include "mozilla/AutoRestyleTimelineMarker.h"
12
#include "mozilla/DocumentStyleRootIterator.h"
13
#include "mozilla/IntegerRange.h"
14
#include "mozilla/LookAndFeel.h"
15
#include "mozilla/ServoBindings.h"
16
#include "mozilla/RestyleManager.h"
17
#include "mozilla/ServoStyleRuleMap.h"
18
#include "mozilla/ServoTypes.h"
19
#include "mozilla/StyleAnimationValue.h"
20
#include "mozilla/css/Loader.h"
21
#include "mozilla/dom/AnonymousContent.h"
22
#include "mozilla/dom/ChildIterator.h"
23
#include "mozilla/dom/FontFaceSet.h"
24
#include "mozilla/dom/Element.h"
25
#include "mozilla/dom/ElementInlines.h"
26
#include "nsCSSAnonBoxes.h"
27
#include "nsCSSFrameConstructor.h"
28
#include "nsCSSPseudoElements.h"
29
#include "nsDeviceContext.h"
30
#include "nsHTMLStyleSheet.h"
31
#include "nsIAnonymousContentCreator.h"
32
#include "nsIDocumentInlines.h"
33
#include "nsMediaFeatures.h"
34
#include "nsPrintfCString.h"
35
#include "nsSMILAnimationController.h"
36
#include "nsXBLPrototypeBinding.h"
37
#include "gfxUserFontSet.h"
38
#include "nsBindingManager.h"
39
#include "nsWindowSizes.h"
40
#include "GeckoProfiler.h"
41
42
using namespace mozilla;
43
using namespace mozilla::dom;
44
45
#ifdef DEBUG
46
bool
47
ServoStyleSet::IsCurrentThreadInServoTraversal()
48
{
49
  return sInServoTraversal && (NS_IsMainThread() || Servo_IsWorkerThread());
50
}
51
#endif
52
53
namespace mozilla {
54
ServoStyleSet* sInServoTraversal = nullptr;
55
56
57
// On construction, sets sInServoTraversal to the given ServoStyleSet.
58
// On destruction, clears sInServoTraversal and calls RunPostTraversalTasks.
59
class MOZ_RAII AutoSetInServoTraversal
60
{
61
public:
62
  explicit AutoSetInServoTraversal(ServoStyleSet* aSet)
63
    : mSet(aSet)
64
0
  {
65
0
    MOZ_ASSERT(!sInServoTraversal);
66
0
    MOZ_ASSERT(aSet);
67
0
    sInServoTraversal = aSet;
68
0
  }
69
70
  ~AutoSetInServoTraversal()
71
0
  {
72
0
    MOZ_ASSERT(sInServoTraversal);
73
0
    sInServoTraversal = nullptr;
74
0
    mSet->RunPostTraversalTasks();
75
0
  }
76
77
private:
78
  ServoStyleSet* mSet;
79
};
80
81
// Sets up for one or more calls to Servo_TraverseSubtree.
82
class MOZ_RAII AutoPrepareTraversal
83
{
84
public:
85
  explicit AutoPrepareTraversal(ServoStyleSet* aSet)
86
    // For markers for animations, we have already set the markers in
87
    // RestyleManager::PostRestyleEventForAnimations so that we don't need
88
    // to care about animation restyles here.
89
    : mTimelineMarker(aSet->mDocument->GetDocShell(), false)
90
    , mSetInServoTraversal(aSet)
91
0
  {
92
0
    MOZ_ASSERT(!aSet->StylistNeedsUpdate());
93
0
  }
94
95
private:
96
  AutoRestyleTimelineMarker mTimelineMarker;
97
  AutoSetInServoTraversal mSetInServoTraversal;
98
};
99
100
} // namespace mozilla
101
102
ServoStyleSet::ServoStyleSet()
103
  : mDocument(nullptr)
104
  , mAuthorStyleDisabled(false)
105
  , mStylistState(StylistState::NotDirty)
106
  , mUserFontSetUpdateGeneration(0)
107
  , mNeedsRestyleAfterEnsureUniqueInner(false)
108
0
{
109
0
}
110
111
ServoStyleSet::~ServoStyleSet()
112
0
{
113
0
  for (auto& sheetArray : mSheets) {
114
0
    for (auto& sheet : sheetArray) {
115
0
      sheet->DropStyleSet(this);
116
0
    }
117
0
  }
118
0
}
119
120
nsPresContext*
121
ServoStyleSet::GetPresContext()
122
0
{
123
0
  if (!mDocument) {
124
0
    return nullptr;
125
0
  }
126
0
127
0
  return mDocument->GetPresContext();
128
0
}
129
130
void
131
ServoStyleSet::Init(nsPresContext* aPresContext)
132
0
{
133
0
  mDocument = aPresContext->Document();
134
0
  MOZ_ASSERT(GetPresContext() == aPresContext);
135
0
136
0
  mRawSet.reset(Servo_StyleSet_Init(aPresContext));
137
0
138
0
  aPresContext->DeviceContext()->InitFontCache();
139
0
140
0
  // Now that we have an mRawSet, go ahead and notify about whatever stylesheets
141
0
  // we have so far.
142
0
  for (auto& sheetArray : mSheets) {
143
0
    for (auto& sheet : sheetArray) {
144
0
      // There's no guarantee this will create a list on the servo side whose
145
0
      // ordering matches the list that would have been created had all those
146
0
      // sheets been appended/prepended/etc after we had mRawSet. That's okay
147
0
      // because Servo only needs to maintain relative ordering within a sheet
148
0
      // type, which this preserves.
149
0
150
0
      MOZ_ASSERT(sheet->RawContents(),
151
0
                 "We should only append non-null raw sheets.");
152
0
      Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet);
153
0
    }
154
0
  }
155
0
156
0
  // We added prefilled stylesheets into mRawSet, so the stylist is dirty.
157
0
  // The Stylist should be updated later when necessary.
158
0
  SetStylistStyleSheetsDirty();
159
0
160
0
  // We may have Shadow DOM style changes that we weren't notified about because
161
0
  // the document didn't have a shell, if the ShadowRoot was created in a
162
0
  // display: none iframe.
163
0
  //
164
0
  // Now that we got a shell, we may need to get them up-to-date.
165
0
  //
166
0
  // TODO(emilio, bug 1418159): This wouldn't be needed if the StyleSet was
167
0
  // owned by the document.
168
0
  SetStylistXBLStyleSheetsDirty();
169
0
}
170
171
template<typename Functor>
172
void
173
EnumerateShadowRoots(const nsIDocument& aDoc, const Functor& aCb)
174
0
{
175
0
  const nsIDocument::ShadowRootSet& shadowRoots = aDoc.ComposedShadowRoots();
176
0
  for (auto iter = shadowRoots.ConstIter(); !iter.Done(); iter.Next()) {
177
0
    ShadowRoot* root = iter.Get()->GetKey();
178
0
    MOZ_ASSERT(root);
179
0
    MOZ_DIAGNOSTIC_ASSERT(root->IsInComposedDoc());
180
0
    aCb(*root);
181
0
  }
182
0
}
Unexecuted instantiation: Unified_cpp_layout_style2.cpp:void EnumerateShadowRoots<mozilla::ServoStyleSet::InvalidateStyleForDocumentStateChanges(mozilla::EventStates)::$_6>(nsIDocument const&, mozilla::ServoStyleSet::InvalidateStyleForDocumentStateChanges(mozilla::EventStates)::$_6 const&)
Unexecuted instantiation: Unified_cpp_layout_style2.cpp:void EnumerateShadowRoots<mozilla::ServoStyleSet::MediumFeaturesChanged(mozilla::MediaFeatureChangeReason)::$_8>(nsIDocument const&, mozilla::ServoStyleSet::MediumFeaturesChanged(mozilla::MediaFeatureChangeReason)::$_8 const&)
Unexecuted instantiation: Unified_cpp_layout_style2.cpp:void EnumerateShadowRoots<mozilla::ServoStyleSet::AppendAllNonDocumentAuthorSheets(nsTArray<mozilla::StyleSheet*>&) const::$_10>(nsIDocument const&, mozilla::ServoStyleSet::AppendAllNonDocumentAuthorSheets(nsTArray<mozilla::StyleSheet*>&) const::$_10 const&)
Unexecuted instantiation: Unified_cpp_layout_style2.cpp:void EnumerateShadowRoots<mozilla::ServoStyleSet::EnsureUniqueInnerOnCSSSheets()::$_11>(nsIDocument const&, mozilla::ServoStyleSet::EnsureUniqueInnerOnCSSSheets()::$_11 const&)
Unexecuted instantiation: Unified_cpp_layout_style2.cpp:void EnumerateShadowRoots<mozilla::ServoStyleSet::UpdateStylist()::$_13>(nsIDocument const&, mozilla::ServoStyleSet::UpdateStylist()::$_13 const&)
183
184
void
185
ServoStyleSet::Shutdown()
186
0
{
187
0
  // Make sure we drop our cached styles before the presshell arena starts going
188
0
  // away.
189
0
  ClearNonInheritingComputedStyles();
190
0
  mRawSet = nullptr;
191
0
  mStyleRuleMap = nullptr;
192
0
}
193
194
void
195
ServoStyleSet::RecordShadowStyleChange(ShadowRoot& aShadowRoot)
196
0
{
197
0
  // TODO(emilio): We could keep track of the actual shadow roots that need
198
0
  // their styles recomputed.
199
0
  SetStylistXBLStyleSheetsDirty();
200
0
201
0
  // FIXME(emilio): This should be done using stylesheet invalidation instead.
202
0
  if (nsPresContext* pc = GetPresContext()) {
203
0
    pc->RestyleManager()->PostRestyleEvent(
204
0
      aShadowRoot.Host(), eRestyle_Subtree, nsChangeHint(0));
205
0
  }
206
0
}
207
208
void
209
ServoStyleSet::InvalidateStyleForDocumentStateChanges(EventStates aStatesChanged)
210
0
{
211
0
  MOZ_ASSERT(mDocument);
212
0
  MOZ_ASSERT(!aStatesChanged.IsEmpty());
213
0
214
0
  nsPresContext* pc = GetPresContext();
215
0
  if (!pc) {
216
0
    return;
217
0
  }
218
0
219
0
  Element* root = mDocument->GetRootElement();
220
0
  if (!root) {
221
0
    return;
222
0
  }
223
0
224
0
  // TODO(emilio): It may be nicer to just invalidate stuff in a given subtree
225
0
  // for XBL sheets / Shadow DOM. Consider just enumerating bound content
226
0
  // instead and run invalidation individually, passing mRawSet for the UA /
227
0
  // User sheets.
228
0
  AutoTArray<RawServoAuthorStylesBorrowed, 20> nonDocumentStyles;
229
0
230
0
  EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
231
0
    if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
232
0
      nonDocumentStyles.AppendElement(authorStyles);
233
0
    }
234
0
  });
235
0
236
0
  mDocument->BindingManager()->EnumerateBoundContentProtoBindings(
237
0
    [&](nsXBLPrototypeBinding* aProto) {
238
0
      if (auto* authorStyles = aProto->GetServoStyles()) {
239
0
        nonDocumentStyles.AppendElement(authorStyles);
240
0
      }
241
0
      return true;
242
0
    });
243
0
244
0
  Servo_InvalidateStyleForDocStateChanges(
245
0
    root, mRawSet.get(), &nonDocumentStyles, aStatesChanged.ServoValue());
246
0
}
247
248
static const MediaFeatureChangeReason kMediaFeaturesAffectingDefaultStyle =
249
  // Zoom changes change the meaning of em units.
250
  MediaFeatureChangeReason::ZoomChange |
251
  // Changes the meaning of em units, depending on which one is the actual
252
  // min-font-size.
253
  MediaFeatureChangeReason::MinFontSizeChange |
254
  // A resolution change changes the app-units-per-dev-pixels ratio, which some
255
  // structs (Border, Outline, Column) store for clamping. We should arguably
256
  // not do that, maybe doing it on layout directly, to try to avoid relying on
257
  // the pres context (bug 1418159).
258
  MediaFeatureChangeReason::ResolutionChange;
259
260
nsRestyleHint
261
ServoStyleSet::MediumFeaturesChanged(MediaFeatureChangeReason aReason)
262
0
{
263
0
  AutoTArray<RawServoAuthorStylesBorrowedMut, 20> nonDocumentStyles;
264
0
265
0
  EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
266
0
    if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
267
0
      nonDocumentStyles.AppendElement(authorStyles);
268
0
    }
269
0
  });
270
0
271
0
  // FIXME(emilio): This is broken for XBL. See bug 1406875.
272
0
  mDocument->BindingManager()->EnumerateBoundContentProtoBindings(
273
0
    [&](nsXBLPrototypeBinding* aProto) {
274
0
      if (auto* authorStyles = aProto->GetServoStyles()) {
275
0
        nonDocumentStyles.AppendElement(authorStyles);
276
0
      }
277
0
      return true;
278
0
    });
279
0
280
0
  bool mayAffectDefaultStyle =
281
0
    bool(aReason & kMediaFeaturesAffectingDefaultStyle);
282
0
283
0
  const MediumFeaturesChangedResult result =
284
0
    Servo_StyleSet_MediumFeaturesChanged(
285
0
      mRawSet.get(), &nonDocumentStyles, mayAffectDefaultStyle);
286
0
287
0
  const bool rulesChanged =
288
0
    result.mAffectsDocumentRules || result.mAffectsNonDocumentRules;
289
0
290
0
  if (result.mAffectsDocumentRules) {
291
0
    SetStylistStyleSheetsDirty();
292
0
  }
293
0
294
0
  if (result.mAffectsNonDocumentRules) {
295
0
    SetStylistXBLStyleSheetsDirty();
296
0
  }
297
0
298
0
  if (rulesChanged) {
299
0
    return eRestyle_Subtree;
300
0
  }
301
0
302
0
  const bool viewportChanged =
303
0
    bool(aReason & MediaFeatureChangeReason::ViewportChange);
304
0
  if (result.mUsesViewportUnits && viewportChanged) {
305
0
    return eRestyle_ForceDescendants;
306
0
  }
307
0
308
0
  return nsRestyleHint(0);
309
0
}
310
311
MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSetMallocSizeOf)
312
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSetMallocEnclosingSizeOf)
313
314
void
315
ServoStyleSet::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
316
0
{
317
0
  MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
318
0
319
0
  aSizes.mLayoutStyleSetsOther += mallocSizeOf(this);
320
0
321
0
  if (mRawSet) {
322
0
    aSizes.mLayoutStyleSetsOther += mallocSizeOf(mRawSet.get());
323
0
    ServoStyleSetSizes sizes;
324
0
    // Measure mRawSet. We use ServoStyleSetMallocSizeOf rather than
325
0
    // aMallocSizeOf to distinguish in DMD's output the memory measured within
326
0
    // Servo code.
327
0
    Servo_StyleSet_AddSizeOfExcludingThis(ServoStyleSetMallocSizeOf,
328
0
                                          ServoStyleSetMallocEnclosingSizeOf,
329
0
                                          &sizes, mRawSet.get());
330
0
331
0
    // The StyleSet does not contain precomputed pseudos; they are in the UA
332
0
    // cache.
333
0
    MOZ_RELEASE_ASSERT(sizes.mPrecomputedPseudos == 0);
334
0
335
0
    aSizes.mLayoutStyleSetsStylistRuleTree += sizes.mRuleTree;
336
0
    aSizes.mLayoutStyleSetsStylistElementAndPseudosMaps +=
337
0
      sizes.mElementAndPseudosMaps;
338
0
    aSizes.mLayoutStyleSetsStylistInvalidationMap +=
339
0
      sizes.mInvalidationMap;
340
0
    aSizes.mLayoutStyleSetsStylistRevalidationSelectors +=
341
0
      sizes.mRevalidationSelectors;
342
0
    aSizes.mLayoutStyleSetsStylistOther += sizes.mOther;
343
0
  }
344
0
345
0
  if (mStyleRuleMap) {
346
0
    aSizes.mLayoutStyleSetsOther +=
347
0
      mStyleRuleMap->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
348
0
  }
349
0
350
0
  // Measurement of the following members may be added later if DMD finds it is
351
0
  // worthwhile:
352
0
  // - mSheets
353
0
  // - mNonInheritingComputedStyles
354
0
  //
355
0
  // The following members are not measured:
356
0
  // - mDocument, because it a non-owning pointer
357
0
}
358
359
void
360
ServoStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
361
0
{
362
0
  if (mAuthorStyleDisabled == aStyleDisabled) {
363
0
    return;
364
0
  }
365
0
366
0
  mAuthorStyleDisabled = aStyleDisabled;
367
0
  if (Element* root = mDocument->GetRootElement()) {
368
0
    if (nsPresContext* pc = GetPresContext()) {
369
0
      pc->RestyleManager()->PostRestyleEvent(root, eRestyle_Subtree, nsChangeHint(0));
370
0
    }
371
0
  }
372
0
  Servo_StyleSet_SetAuthorStyleDisabled(mRawSet.get(), mAuthorStyleDisabled);
373
0
  // XXX Workaround for the assertion in InvalidateStyleForDocumentStateChanges
374
0
  // which is called by nsIPresShell::SetAuthorStyleDisabled via nsIPresShell::
375
0
  // RestyleForCSSRuleChanges. It is not really necessary because we don't need
376
0
  // to rebuild stylist for this change. But we have bug around this, and we
377
0
  // may want to rethink how things should work. See bug 1437785.
378
0
  SetStylistStyleSheetsDirty();
379
0
}
380
381
already_AddRefed<ComputedStyle>
382
ServoStyleSet::ResolveStyleFor(Element* aElement,
383
                               LazyComputeBehavior aMayCompute)
384
0
{
385
0
  if (aMayCompute == LazyComputeBehavior::Allow) {
386
0
    PreTraverseSync();
387
0
    return ResolveStyleLazilyInternal(
388
0
        aElement, CSSPseudoElementType::NotPseudo);
389
0
  }
390
0
391
0
  return ResolveServoStyle(*aElement);
392
0
}
393
394
const ServoElementSnapshotTable&
395
ServoStyleSet::Snapshots()
396
0
{
397
0
  MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
398
0
  return GetPresContext()->RestyleManager()->Snapshots();
399
0
}
400
401
void
402
ServoStyleSet::ResolveMappedAttrDeclarationBlocks()
403
0
{
404
0
  if (nsHTMLStyleSheet* sheet = mDocument->GetAttributeStyleSheet()) {
405
0
    sheet->CalculateMappedServoDeclarations();
406
0
  }
407
0
408
0
  mDocument->ResolveScheduledSVGPresAttrs();
409
0
}
410
411
void
412
ServoStyleSet::PreTraverseSync()
413
0
{
414
0
  // Get the Document's root element to ensure that the cache is valid before
415
0
  // calling into the (potentially-parallel) Servo traversal, where a cache hit
416
0
  // is necessary to avoid a data race when updating the cache.
417
0
  mozilla::Unused << mDocument->GetRootElement();
418
0
419
0
  ResolveMappedAttrDeclarationBlocks();
420
0
421
0
  nsMediaFeatures::InitSystemMetrics();
422
0
423
0
  LookAndFeel::NativeInit();
424
0
425
0
  nsPresContext* presContext = GetPresContext();
426
0
  MOZ_ASSERT(presContext,
427
0
             "For now, we don't call into here without a pres context");
428
0
  if (gfxUserFontSet* userFontSet = mDocument->GetUserFontSet()) {
429
0
    // Ensure that the @font-face data is not stale
430
0
    uint64_t generation = userFontSet->GetGeneration();
431
0
    if (generation != mUserFontSetUpdateGeneration) {
432
0
      mDocument->GetFonts()->CacheFontLoadability();
433
0
      presContext->DeviceContext()->UpdateFontCacheUserFonts(userFontSet);
434
0
      mUserFontSetUpdateGeneration = generation;
435
0
    }
436
0
  }
437
0
438
0
  MOZ_ASSERT(!StylistNeedsUpdate());
439
0
  presContext->CacheAllLangs();
440
0
}
441
442
void
443
ServoStyleSet::PreTraverse(ServoTraversalFlags aFlags, Element* aRoot)
444
0
{
445
0
  PreTraverseSync();
446
0
447
0
  // Process animation stuff that we should avoid doing during the parallel
448
0
  // traversal.
449
0
  nsSMILAnimationController* smilController =
450
0
    mDocument->HasAnimationController()
451
0
    ? mDocument->GetAnimationController()
452
0
    : nullptr;
453
0
454
0
  MOZ_ASSERT(GetPresContext());
455
0
  if (aRoot) {
456
0
    GetPresContext()->EffectCompositor()->PreTraverseInSubtree(aFlags, aRoot);
457
0
    if (smilController) {
458
0
      smilController->PreTraverseInSubtree(aRoot);
459
0
    }
460
0
  } else {
461
0
    GetPresContext()->EffectCompositor()->PreTraverse(aFlags);
462
0
    if (smilController) {
463
0
      smilController->PreTraverse();
464
0
    }
465
0
  }
466
0
}
467
468
static inline already_AddRefed<ComputedStyle>
469
ResolveStyleForTextOrFirstLetterContinuation(
470
    RawServoStyleSetBorrowed aStyleSet,
471
    ComputedStyle& aParent,
472
    nsAtom* aAnonBox)
473
0
{
474
0
  MOZ_ASSERT(aAnonBox == nsCSSAnonBoxes::mozText() ||
475
0
             aAnonBox == nsCSSAnonBoxes::firstLetterContinuation());
476
0
  auto inheritTarget = aAnonBox == nsCSSAnonBoxes::mozText()
477
0
    ? InheritTarget::Text
478
0
    : InheritTarget::FirstLetterContinuation;
479
0
480
0
  RefPtr<ComputedStyle> style =
481
0
    aParent.GetCachedInheritingAnonBoxStyle(aAnonBox);
482
0
  if (!style) {
483
0
    style = Servo_ComputedValues_Inherit(aStyleSet,
484
0
                                         aAnonBox,
485
0
                                         &aParent,
486
0
                                         inheritTarget).Consume();
487
0
    MOZ_ASSERT(style);
488
0
    aParent.SetCachedInheritedAnonBoxStyle(aAnonBox, style);
489
0
  }
490
0
491
0
  return style.forget();
492
0
}
493
494
already_AddRefed<ComputedStyle>
495
ServoStyleSet::ResolveStyleForText(nsIContent* aTextNode,
496
                                   ComputedStyle* aParentContext)
497
0
{
498
0
  MOZ_ASSERT(aTextNode && aTextNode->IsText());
499
0
  MOZ_ASSERT(aTextNode->GetParent());
500
0
  MOZ_ASSERT(aParentContext);
501
0
502
0
  return ResolveStyleForTextOrFirstLetterContinuation(
503
0
      mRawSet.get(), *aParentContext, nsCSSAnonBoxes::mozText());
504
0
}
505
506
already_AddRefed<ComputedStyle>
507
ServoStyleSet::ResolveStyleForFirstLetterContinuation(ComputedStyle* aParentContext)
508
0
{
509
0
  MOZ_ASSERT(aParentContext);
510
0
511
0
  return ResolveStyleForTextOrFirstLetterContinuation(
512
0
      mRawSet.get(), *aParentContext, nsCSSAnonBoxes::firstLetterContinuation());
513
0
}
514
515
already_AddRefed<ComputedStyle>
516
ServoStyleSet::ResolveStyleForPlaceholder()
517
0
{
518
0
  RefPtr<ComputedStyle>& cache =
519
0
    mNonInheritingComputedStyles[nsCSSAnonBoxes::NonInheriting::oofPlaceholder];
520
0
  if (cache) {
521
0
    RefPtr<ComputedStyle> retval = cache;
522
0
    return retval.forget();
523
0
  }
524
0
525
0
  RefPtr<ComputedStyle> computedValues =
526
0
    Servo_ComputedValues_Inherit(mRawSet.get(),
527
0
                                 nsCSSAnonBoxes::oofPlaceholder(),
528
0
                                 nullptr,
529
0
                                 InheritTarget::PlaceholderFrame)
530
0
                                 .Consume();
531
0
  MOZ_ASSERT(computedValues);
532
0
533
0
  cache = computedValues;
534
0
  return computedValues.forget();
535
0
}
536
537
static inline bool
538
LazyPseudoIsCacheable(CSSPseudoElementType aType,
539
                      const Element& aOriginatingElement,
540
                      ComputedStyle* aParentContext)
541
0
{
542
0
  return aParentContext &&
543
0
         !nsCSSPseudoElements::IsEagerlyCascadedInServo(aType) &&
544
0
         aOriginatingElement.HasServoData() &&
545
0
         !Servo_Element_IsPrimaryStyleReusedViaRuleNode(&aOriginatingElement);
546
0
}
547
548
already_AddRefed<ComputedStyle>
549
ServoStyleSet::ResolvePseudoElementStyle(Element* aOriginatingElement,
550
                                         CSSPseudoElementType aType,
551
                                         ComputedStyle* aParentContext,
552
                                         Element* aPseudoElement)
553
0
{
554
0
  // Runs from frame construction, this should have clean styles already, except
555
0
  // with non-lazy FC...
556
0
  UpdateStylistIfNeeded();
557
0
  MOZ_ASSERT(aType < CSSPseudoElementType::Count);
558
0
559
0
  RefPtr<ComputedStyle> computedValues;
560
0
561
0
  if (aPseudoElement) {
562
0
    MOZ_ASSERT(aType == aPseudoElement->GetPseudoElementType());
563
0
    computedValues =
564
0
      Servo_ResolveStyle(aPseudoElement, mRawSet.get()).Consume();
565
0
  } else {
566
0
    bool cacheable =
567
0
      LazyPseudoIsCacheable(aType, *aOriginatingElement, aParentContext);
568
0
    computedValues =
569
0
      cacheable ? aParentContext->GetCachedLazyPseudoStyle(aType) : nullptr;
570
0
571
0
    if (!computedValues) {
572
0
      computedValues = Servo_ResolvePseudoStyle(aOriginatingElement,
573
0
                                                aType,
574
0
                                                /* is_probe = */ false,
575
0
                                                aParentContext,
576
0
                                                mRawSet.get()).Consume();
577
0
      if (cacheable) {
578
0
        aParentContext->SetCachedLazyPseudoStyle(computedValues);
579
0
      }
580
0
    }
581
0
  }
582
0
583
0
  MOZ_ASSERT(computedValues);
584
0
  return computedValues.forget();
585
0
}
586
587
already_AddRefed<ComputedStyle>
588
ServoStyleSet::ResolveStyleLazily(Element* aElement,
589
                                  CSSPseudoElementType aPseudoType,
590
                                  StyleRuleInclusion aRuleInclusion)
591
0
{
592
0
  PreTraverseSync();
593
0
594
0
  return ResolveStyleLazilyInternal(aElement, aPseudoType,
595
0
                                    aRuleInclusion);
596
0
}
597
598
already_AddRefed<ComputedStyle>
599
ServoStyleSet::ResolveInheritingAnonymousBoxStyle(nsAtom* aPseudoTag,
600
                                                  ComputedStyle* aParentContext)
601
0
{
602
0
  MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
603
0
             !nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag));
604
0
  MOZ_ASSERT_IF(aParentContext, !StylistNeedsUpdate());
605
0
606
0
  UpdateStylistIfNeeded();
607
0
608
0
  RefPtr<ComputedStyle> style = nullptr;
609
0
610
0
  if (aParentContext) {
611
0
    style = aParentContext->GetCachedInheritingAnonBoxStyle(aPseudoTag);
612
0
  }
613
0
614
0
  if (!style) {
615
0
    style =
616
0
      Servo_ComputedValues_GetForAnonymousBox(aParentContext,
617
0
                                              aPseudoTag,
618
0
                                              mRawSet.get()).Consume();
619
0
    MOZ_ASSERT(style);
620
0
    if (aParentContext) {
621
0
      aParentContext->SetCachedInheritedAnonBoxStyle(aPseudoTag, style);
622
0
    }
623
0
  }
624
0
625
0
  return style.forget();
626
0
}
627
628
already_AddRefed<ComputedStyle>
629
ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(nsAtom* aPseudoTag)
630
0
{
631
0
  MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
632
0
             nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag));
633
0
  MOZ_ASSERT(aPseudoTag != nsCSSAnonBoxes::pageContent(),
634
0
             "If nsCSSAnonBoxes::pageContent() ends up non-inheriting, check "
635
0
             "whether we need to do anything to move the "
636
0
             "@page handling from ResolveInheritingAnonymousBoxStyle to "
637
0
             "ResolveNonInheritingAnonymousBoxStyle");
638
0
639
0
  nsCSSAnonBoxes::NonInheriting type =
640
0
    nsCSSAnonBoxes::NonInheritingTypeForPseudoTag(aPseudoTag);
641
0
  RefPtr<ComputedStyle>& cache = mNonInheritingComputedStyles[type];
642
0
  if (cache) {
643
0
    RefPtr<ComputedStyle> retval = cache;
644
0
    return retval.forget();
645
0
  }
646
0
647
0
  UpdateStylistIfNeeded();
648
0
649
0
  // We always want to skip parent-based display fixup here.  It never makes
650
0
  // sense for non-inheriting anonymous boxes.  (Static assertions in
651
0
  // nsCSSAnonBoxes.cpp ensure that all non-inheriting non-anonymous boxes
652
0
  // are indeed annotated as skipping this fixup.)
653
0
  MOZ_ASSERT(!nsCSSAnonBoxes::IsNonInheritingAnonBox(nsCSSAnonBoxes::viewport()),
654
0
             "viewport needs fixup to handle blockifying it");
655
0
  RefPtr<ComputedStyle> computedValues =
656
0
    Servo_ComputedValues_GetForAnonymousBox(nullptr,
657
0
                                            aPseudoTag,
658
0
                                            mRawSet.get()).Consume();
659
#ifdef DEBUG
660
  if (!computedValues) {
661
    nsString pseudo;
662
    aPseudoTag->ToString(pseudo);
663
    NS_ERROR(nsPrintfCString("stylo: could not get anon-box: %s",
664
             NS_ConvertUTF16toUTF8(pseudo).get()).get());
665
    MOZ_CRASH();
666
  }
667
#endif
668
669
0
  cache = computedValues;
670
0
  return computedValues.forget();
671
0
}
672
673
#ifdef MOZ_XUL
674
already_AddRefed<ComputedStyle>
675
ServoStyleSet::ResolveXULTreePseudoStyle(dom::Element* aParentElement,
676
                                         nsICSSAnonBoxPseudo* aPseudoTag,
677
                                         ComputedStyle* aParentContext,
678
                                         const AtomArray& aInputWord)
679
0
{
680
0
  MOZ_ASSERT(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag));
681
0
  MOZ_ASSERT(aParentContext);
682
0
  MOZ_ASSERT(!StylistNeedsUpdate());
683
0
684
0
  return Servo_ComputedValues_ResolveXULTreePseudoStyle(
685
0
      aParentElement,
686
0
      aPseudoTag,
687
0
      aParentContext,
688
0
      &aInputWord,
689
0
      mRawSet.get()
690
0
  ).Consume();
691
0
}
692
#endif
693
694
// manage the set of style sheets in the style set
695
nsresult
696
ServoStyleSet::AppendStyleSheet(SheetType aType, StyleSheet* aSheet)
697
0
{
698
0
  MOZ_ASSERT(aSheet);
699
0
  MOZ_ASSERT(aSheet->IsApplicable());
700
0
  MOZ_ASSERT(IsCSSSheetType(aType));
701
0
  MOZ_ASSERT(aSheet->RawContents(), "Raw sheet should be in place before insertion.");
702
0
703
0
  RemoveSheetOfType(aType, aSheet);
704
0
  AppendSheetOfType(aType, aSheet);
705
0
706
0
  if (mRawSet) {
707
0
    // Maintain a mirrored list of sheets on the servo side.
708
0
    // Servo will remove aSheet from its original position as part of the call
709
0
    // to Servo_StyleSet_AppendStyleSheet.
710
0
    Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet);
711
0
    SetStylistStyleSheetsDirty();
712
0
  }
713
0
714
0
  if (mStyleRuleMap) {
715
0
    mStyleRuleMap->SheetAdded(*aSheet);
716
0
  }
717
0
718
0
  return NS_OK;
719
0
}
720
721
nsresult
722
ServoStyleSet::PrependStyleSheet(SheetType aType, StyleSheet* aSheet)
723
0
{
724
0
  MOZ_ASSERT(aSheet);
725
0
  MOZ_ASSERT(aSheet->IsApplicable());
726
0
  MOZ_ASSERT(IsCSSSheetType(aType));
727
0
  MOZ_ASSERT(aSheet->RawContents(),
728
0
             "Raw sheet should be in place before insertion.");
729
0
730
0
  RemoveSheetOfType(aType, aSheet);
731
0
  PrependSheetOfType(aType, aSheet);
732
0
733
0
  if (mRawSet) {
734
0
    // Maintain a mirrored list of sheets on the servo side.
735
0
    // Servo will remove aSheet from its original position as part of the call
736
0
    // to Servo_StyleSet_PrependStyleSheet.
737
0
    Servo_StyleSet_PrependStyleSheet(mRawSet.get(), aSheet);
738
0
    SetStylistStyleSheetsDirty();
739
0
  }
740
0
741
0
  if (mStyleRuleMap) {
742
0
    mStyleRuleMap->SheetAdded(*aSheet);
743
0
  }
744
0
745
0
  return NS_OK;
746
0
}
747
748
nsresult
749
ServoStyleSet::RemoveStyleSheet(SheetType aType, StyleSheet* aSheet)
750
0
{
751
0
  MOZ_ASSERT(aSheet);
752
0
  MOZ_ASSERT(IsCSSSheetType(aType));
753
0
754
0
  RemoveSheetOfType(aType, aSheet);
755
0
  if (mRawSet) {
756
0
    // Maintain a mirrored list of sheets on the servo side.
757
0
    Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), aSheet);
758
0
    SetStylistStyleSheetsDirty();
759
0
  }
760
0
761
0
  if (mStyleRuleMap) {
762
0
    mStyleRuleMap->SheetRemoved(*aSheet);
763
0
  }
764
0
765
0
  return NS_OK;
766
0
}
767
768
nsresult
769
ServoStyleSet::ReplaceSheets(SheetType aType,
770
                             const nsTArray<RefPtr<StyleSheet>>& aNewSheets)
771
0
{
772
0
  // Gecko uses a two-dimensional array keyed by sheet type, whereas Servo
773
0
  // stores a flattened list. This makes ReplaceSheets a pretty clunky thing
774
0
  // to express. If the need ever arises, we can easily make this more efficent,
775
0
  // probably by aligning the representations better between engines.
776
0
777
0
  SetStylistStyleSheetsDirty();
778
0
779
0
  // Remove all the existing sheets first.
780
0
  for (const auto& sheet : mSheets[aType]) {
781
0
    sheet->DropStyleSet(this);
782
0
    if (mRawSet) {
783
0
      Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), sheet);
784
0
    }
785
0
  }
786
0
  mSheets[aType].Clear();
787
0
788
0
  // Add in all the new sheets.
789
0
  for (auto& sheet : aNewSheets) {
790
0
    AppendSheetOfType(aType, sheet);
791
0
    if (mRawSet) {
792
0
      MOZ_ASSERT(sheet->RawContents(), "Raw sheet should be in place before replacement.");
793
0
      Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet);
794
0
    }
795
0
  }
796
0
797
0
  // Just don't bother calling SheetRemoved / SheetAdded, and recreate the rule
798
0
  // map when needed.
799
0
  mStyleRuleMap = nullptr;
800
0
  return NS_OK;
801
0
}
802
803
nsresult
804
ServoStyleSet::InsertStyleSheetBefore(SheetType aType,
805
                                      StyleSheet* aNewSheet,
806
                                      StyleSheet* aReferenceSheet)
807
0
{
808
0
  MOZ_ASSERT(aNewSheet);
809
0
  MOZ_ASSERT(aReferenceSheet);
810
0
  MOZ_ASSERT(aNewSheet->IsApplicable());
811
0
  MOZ_ASSERT(aNewSheet != aReferenceSheet, "Can't place sheet before itself.");
812
0
  MOZ_ASSERT(aNewSheet->RawContents(), "Raw sheet should be in place before insertion.");
813
0
  MOZ_ASSERT(aReferenceSheet->RawContents(), "Reference sheet should have a raw sheet.");
814
0
815
0
  // Servo will remove aNewSheet from its original position as part of the
816
0
  // call to Servo_StyleSet_InsertStyleSheetBefore.
817
0
  RemoveSheetOfType(aType, aNewSheet);
818
0
  InsertSheetOfType(aType, aNewSheet, aReferenceSheet);
819
0
820
0
  if (mRawSet) {
821
0
    // Maintain a mirrored list of sheets on the servo side.
822
0
    Servo_StyleSet_InsertStyleSheetBefore(
823
0
        mRawSet.get(), aNewSheet, aReferenceSheet);
824
0
    SetStylistStyleSheetsDirty();
825
0
  }
826
0
827
0
  if (mStyleRuleMap) {
828
0
    mStyleRuleMap->SheetAdded(*aNewSheet);
829
0
  }
830
0
831
0
  return NS_OK;
832
0
}
833
834
int32_t
835
ServoStyleSet::SheetCount(SheetType aType) const
836
0
{
837
0
  MOZ_ASSERT(IsCSSSheetType(aType));
838
0
  return mSheets[aType].Length();
839
0
}
840
841
StyleSheet*
842
ServoStyleSet::StyleSheetAt(SheetType aType, int32_t aIndex) const
843
0
{
844
0
  MOZ_ASSERT(IsCSSSheetType(aType));
845
0
  return mSheets[aType][aIndex];
846
0
}
847
848
void
849
ServoStyleSet::AppendAllNonDocumentAuthorSheets(nsTArray<StyleSheet*>& aArray) const
850
0
{
851
0
  if (mDocument) {
852
0
    mDocument->BindingManager()->AppendAllSheets(aArray);
853
0
    EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
854
0
      for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
855
0
        aArray.AppendElement(aShadowRoot.SheetAt(index));
856
0
      }
857
0
    });
858
0
  }
859
0
}
860
861
nsresult
862
ServoStyleSet::RemoveDocStyleSheet(StyleSheet* aSheet)
863
0
{
864
0
  return RemoveStyleSheet(SheetType::Doc, aSheet);
865
0
}
866
867
nsresult
868
ServoStyleSet::AddDocStyleSheet(StyleSheet* aSheet, nsIDocument* aDocument)
869
0
{
870
0
  MOZ_ASSERT(aSheet->IsApplicable());
871
0
  MOZ_ASSERT(aSheet->RawContents(), "Raw sheet should be in place by this point.");
872
0
873
0
  RefPtr<StyleSheet> strong(aSheet);
874
0
875
0
  RemoveSheetOfType(SheetType::Doc, aSheet);
876
0
877
0
  size_t index =
878
0
    aDocument->FindDocStyleSheetInsertionPoint(mSheets[SheetType::Doc], *aSheet);
879
0
880
0
  if (index < mSheets[SheetType::Doc].Length()) {
881
0
    // This case is insert before.
882
0
    StyleSheet *beforeSheet = mSheets[SheetType::Doc][index];
883
0
    InsertSheetOfType(SheetType::Doc, aSheet, beforeSheet);
884
0
885
0
    if (mRawSet) {
886
0
      // Maintain a mirrored list of sheets on the servo side.
887
0
      Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aSheet, beforeSheet);
888
0
      SetStylistStyleSheetsDirty();
889
0
    }
890
0
  } else {
891
0
    // This case is append.
892
0
    AppendSheetOfType(SheetType::Doc, aSheet);
893
0
894
0
    if (mRawSet) {
895
0
      // Maintain a mirrored list of sheets on the servo side.
896
0
      Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet);
897
0
      SetStylistStyleSheetsDirty();
898
0
    }
899
0
  }
900
0
901
0
  if (mStyleRuleMap) {
902
0
    mStyleRuleMap->SheetAdded(*aSheet);
903
0
  }
904
0
905
0
  return NS_OK;
906
0
}
907
908
already_AddRefed<ComputedStyle>
909
ServoStyleSet::ProbePseudoElementStyle(const Element& aOriginatingElement,
910
                                       CSSPseudoElementType aType,
911
                                       ComputedStyle* aParentContext)
912
0
{
913
0
  // Runs from frame construction, this should have clean styles already, except
914
0
  // with non-lazy FC...
915
0
  UpdateStylistIfNeeded();
916
0
917
0
  // NB: We ignore aParentContext, because in some cases
918
0
  // (first-line/first-letter on anonymous box blocks) Gecko passes something
919
0
  // nonsensical there.  In all other cases we want to inherit directly from
920
0
  // aOriginatingElement's styles anyway.
921
0
  MOZ_ASSERT(aType < CSSPseudoElementType::Count);
922
0
923
0
  bool cacheable =
924
0
    LazyPseudoIsCacheable(aType, aOriginatingElement, aParentContext);
925
0
926
0
  RefPtr<ComputedStyle> computedValues =
927
0
    cacheable ? aParentContext->GetCachedLazyPseudoStyle(aType) : nullptr;
928
0
  if (!computedValues) {
929
0
    computedValues = Servo_ResolvePseudoStyle(&aOriginatingElement,
930
0
                                              aType,
931
0
                                              /* is_probe = */ true,
932
0
                                              nullptr,
933
0
                                              mRawSet.get()).Consume();
934
0
    if (!computedValues) {
935
0
      return nullptr;
936
0
    }
937
0
938
0
    if (cacheable) {
939
0
      // NB: We don't need to worry about the before/after handling below
940
0
      // because those are eager and thus not |cacheable| anyway.
941
0
      aParentContext->SetCachedLazyPseudoStyle(computedValues);
942
0
    }
943
0
  }
944
0
945
0
  // For :before and :after pseudo-elements, having display: none or no
946
0
  // 'content' property is equivalent to not having the pseudo-element
947
0
  // at all.
948
0
  bool isBeforeOrAfter = aType == CSSPseudoElementType::before ||
949
0
                         aType == CSSPseudoElementType::after;
950
0
  if (isBeforeOrAfter) {
951
0
    const nsStyleDisplay* display = computedValues->ComputedData()->GetStyleDisplay();
952
0
    const nsStyleContent* content = computedValues->ComputedData()->GetStyleContent();
953
0
    if (display->mDisplay == StyleDisplay::None ||
954
0
        content->ContentCount() == 0) {
955
0
      return nullptr;
956
0
    }
957
0
  }
958
0
959
0
  return computedValues.forget();
960
0
}
961
962
bool
963
ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags)
964
0
{
965
0
  MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
966
0
967
0
  if (!mDocument->GetServoRestyleRoot()) {
968
0
    return false;
969
0
  }
970
0
971
0
  PreTraverse(aFlags);
972
0
  AutoPrepareTraversal guard(this);
973
0
  const SnapshotTable& snapshots = Snapshots();
974
0
975
0
  // Restyle the document from the root element and each of the document level
976
0
  // NAC subtree roots.
977
0
  bool postTraversalRequired = false;
978
0
979
0
  Element* rootElement = mDocument->GetRootElement();
980
0
  MOZ_ASSERT_IF(rootElement, rootElement->HasServoData());
981
0
982
0
  if (ShouldTraverseInParallel()) {
983
0
    aFlags |= ServoTraversalFlags::ParallelTraversal;
984
0
  }
985
0
986
0
  // Do the first traversal.
987
0
  DocumentStyleRootIterator iter(mDocument->GetServoRestyleRoot());
988
0
  while (Element* root = iter.GetNextStyleRoot()) {
989
0
    MOZ_ASSERT(MayTraverseFrom(root));
990
0
991
0
    Element* parent = root->GetFlattenedTreeParentElementForStyle();
992
0
    MOZ_ASSERT_IF(parent,
993
0
                  !parent->HasAnyOfFlags(Element::kAllServoDescendantBits));
994
0
995
0
    postTraversalRequired |=
996
0
      Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags);
997
0
    postTraversalRequired |=
998
0
      root->HasAnyOfFlags(Element::kAllServoDescendantBits | NODE_NEEDS_FRAME);
999
0
1000
0
    if (parent) {
1001
0
      MOZ_ASSERT(root == mDocument->GetServoRestyleRoot());
1002
0
      if (parent->HasDirtyDescendantsForServo()) {
1003
0
        // If any style invalidation was triggered in our siblings, then we may
1004
0
        // need to post-traverse them, even if the root wasn't restyled after
1005
0
        // all.
1006
0
        uint32_t existingBits = mDocument->GetServoRestyleRootDirtyBits();
1007
0
        // We need to propagate the existing bits to the parent.
1008
0
        parent->SetFlags(existingBits);
1009
0
        mDocument->SetServoRestyleRoot(
1010
0
            parent,
1011
0
            existingBits | ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
1012
0
        postTraversalRequired = true;
1013
0
      }
1014
0
    }
1015
0
  }
1016
0
1017
0
  // If there are still animation restyles needed, trigger a second traversal to
1018
0
  // update CSS animations or transitions' styles.
1019
0
  //
1020
0
  // Note that we need to check the style root again, because doing another
1021
0
  // PreTraverse on the EffectCompositor might alter the style root. But we
1022
0
  // don't need to worry about NAC, since document-level NAC shouldn't have
1023
0
  // animations.
1024
0
  //
1025
0
  // We don't need to do this for SMIL since SMIL only updates its animation
1026
0
  // values once at the begin of a tick. As a result, even if the previous
1027
0
  // traversal caused, for example, the font-size to change, the SMIL style
1028
0
  // won't be updated until the next tick anyway.
1029
0
  if (GetPresContext()->EffectCompositor()->PreTraverse(aFlags)) {
1030
0
    nsINode* styleRoot = mDocument->GetServoRestyleRoot();
1031
0
    Element* root = styleRoot->IsElement() ? styleRoot->AsElement() : rootElement;
1032
0
1033
0
    postTraversalRequired |=
1034
0
      Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags);
1035
0
    postTraversalRequired |=
1036
0
      root->HasAnyOfFlags(Element::kAllServoDescendantBits | NODE_NEEDS_FRAME);
1037
0
  }
1038
0
1039
0
  return postTraversalRequired;
1040
0
}
1041
1042
void
1043
ServoStyleSet::StyleNewSubtree(Element* aRoot)
1044
0
{
1045
0
  MOZ_ASSERT(GetPresContext());
1046
0
  MOZ_ASSERT(!aRoot->HasServoData());
1047
0
  MOZ_ASSERT(aRoot->GetFlattenedTreeParentNodeForStyle(),
1048
0
             "Not in the flat tree? Fishy!");
1049
0
  PreTraverseSync();
1050
0
  AutoPrepareTraversal guard(this);
1051
0
1052
0
  // Do the traversal. The snapshots will not be used.
1053
0
  const SnapshotTable& snapshots = Snapshots();
1054
0
  auto flags = ServoTraversalFlags::Empty;
1055
0
  if (ShouldTraverseInParallel()) {
1056
0
    flags |= ServoTraversalFlags::ParallelTraversal;
1057
0
  }
1058
0
1059
0
  DebugOnly<bool> postTraversalRequired =
1060
0
    Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots, flags);
1061
0
  MOZ_ASSERT(!postTraversalRequired);
1062
0
1063
0
  // Annoyingly, the newly-styled content may have animations that need
1064
0
  // starting, which requires traversing them again. Mark the elements
1065
0
  // that need animation processing, then do a forgetful traversal to
1066
0
  // update the styles and clear the animation bits.
1067
0
  if (GetPresContext()->EffectCompositor()->PreTraverseInSubtree(flags, aRoot)) {
1068
0
    postTraversalRequired =
1069
0
      Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots,
1070
0
                            ServoTraversalFlags::AnimationOnly |
1071
0
                            ServoTraversalFlags::Forgetful |
1072
0
                            ServoTraversalFlags::ClearAnimationOnlyDirtyDescendants);
1073
0
    MOZ_ASSERT(!postTraversalRequired);
1074
0
  }
1075
0
}
1076
1077
void
1078
ServoStyleSet::MarkOriginsDirty(OriginFlags aChangedOrigins)
1079
0
{
1080
0
  if (MOZ_UNLIKELY(!mRawSet)) {
1081
0
    return;
1082
0
  }
1083
0
1084
0
  SetStylistStyleSheetsDirty();
1085
0
  Servo_StyleSet_NoteStyleSheetsChanged(mRawSet.get(), aChangedOrigins);
1086
0
}
1087
1088
void
1089
ServoStyleSet::SetStylistStyleSheetsDirty()
1090
0
{
1091
0
  // Note that there's another hidden mutator of mStylistState for XBL style
1092
0
  // sets in MediumFeaturesChanged...
1093
0
  //
1094
0
  // We really need to stop using a full-blown StyleSet there...
1095
0
  mStylistState |= StylistState::StyleSheetsDirty;
1096
0
1097
0
  // We need to invalidate cached style in getComputedStyle for undisplayed
1098
0
  // elements, since we don't know if any of the style sheet change that we
1099
0
  // do would affect undisplayed elements.
1100
0
  if (nsPresContext* presContext = GetPresContext()) {
1101
0
    // XBL sheets don't have a pres context, but invalidating the restyle
1102
0
    // generation in that case is handled by SetXBLStyleSheetsDirty in the
1103
0
    // "master" stylist.
1104
0
    presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration();
1105
0
  }
1106
0
}
1107
1108
void
1109
ServoStyleSet::SetStylistXBLStyleSheetsDirty()
1110
0
{
1111
0
  mStylistState |= StylistState::XBLStyleSheetsDirty;
1112
0
1113
0
  // We need to invalidate cached style in getComputedStyle for undisplayed
1114
0
  // elements, since we don't know if any of the style sheet change that we
1115
0
  // do would affect undisplayed elements.
1116
0
  MOZ_ASSERT(GetPresContext());
1117
0
  GetPresContext()->RestyleManager()->IncrementUndisplayedRestyleGeneration();
1118
0
}
1119
1120
void
1121
ServoStyleSet::RuleAdded(StyleSheet& aSheet, css::Rule& aRule)
1122
0
{
1123
0
  if (mStyleRuleMap) {
1124
0
    mStyleRuleMap->RuleAdded(aSheet, aRule);
1125
0
  }
1126
0
1127
0
  // FIXME(emilio): Could be more granular based on aRule.
1128
0
  MarkOriginsDirty(aSheet.GetOrigin());
1129
0
}
1130
1131
void
1132
ServoStyleSet::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule)
1133
0
{
1134
0
  if (mStyleRuleMap) {
1135
0
    mStyleRuleMap->RuleRemoved(aSheet, aRule);
1136
0
  }
1137
0
1138
0
  // FIXME(emilio): Could be more granular based on aRule.
1139
0
  MarkOriginsDirty(aSheet.GetOrigin());
1140
0
}
1141
1142
void
1143
ServoStyleSet::RuleChanged(StyleSheet& aSheet, css::Rule* aRule)
1144
0
{
1145
0
  // FIXME(emilio): Could be more granular based on aRule.
1146
0
  MarkOriginsDirty(aSheet.GetOrigin());
1147
0
}
1148
1149
#ifdef DEBUG
1150
void
1151
ServoStyleSet::AssertTreeIsClean()
1152
{
1153
  DocumentStyleRootIterator iter(mDocument);
1154
  while (Element* root = iter.GetNextStyleRoot()) {
1155
    Servo_AssertTreeIsClean(root);
1156
  }
1157
}
1158
#endif
1159
1160
bool
1161
ServoStyleSet::GetKeyframesForName(const Element& aElement,
1162
                                   const ComputedStyle& aStyle,
1163
                                   nsAtom* aName,
1164
                                   const nsTimingFunction& aTimingFunction,
1165
                                   nsTArray<Keyframe>& aKeyframes)
1166
0
{
1167
0
  MOZ_ASSERT(!StylistNeedsUpdate());
1168
0
  return Servo_StyleSet_GetKeyframesForName(mRawSet.get(),
1169
0
                                            &aElement,
1170
0
                                            &aStyle,
1171
0
                                            aName,
1172
0
                                            &aTimingFunction,
1173
0
                                            &aKeyframes);
1174
0
}
1175
1176
nsTArray<ComputedKeyframeValues>
1177
ServoStyleSet::GetComputedKeyframeValuesFor(
1178
  const nsTArray<Keyframe>& aKeyframes,
1179
  Element* aElement,
1180
  const mozilla::ComputedStyle* aStyle)
1181
0
{
1182
0
  nsTArray<ComputedKeyframeValues> result(aKeyframes.Length());
1183
0
1184
0
  // Construct each nsTArray<PropertyStyleAnimationValuePair> here.
1185
0
  result.AppendElements(aKeyframes.Length());
1186
0
1187
0
  Servo_GetComputedKeyframeValues(&aKeyframes,
1188
0
                                  aElement,
1189
0
                                  aStyle,
1190
0
                                  mRawSet.get(),
1191
0
                                  &result);
1192
0
  return result;
1193
0
}
1194
1195
void
1196
ServoStyleSet::GetAnimationValues(
1197
  RawServoDeclarationBlock* aDeclarations,
1198
  Element* aElement,
1199
  const ComputedStyle* aComputedStyle,
1200
  nsTArray<RefPtr<RawServoAnimationValue>>& aAnimationValues)
1201
0
{
1202
0
  // Servo_GetAnimationValues below won't handle ignoring existing element
1203
0
  // data for bfcached documents. (See comment in ResolveStyleLazily
1204
0
  // about these bfcache issues.)
1205
0
  Servo_GetAnimationValues(aDeclarations,
1206
0
                           aElement,
1207
0
                           aComputedStyle,
1208
0
                           mRawSet.get(),
1209
0
                           &aAnimationValues);
1210
0
}
1211
1212
already_AddRefed<ComputedStyle>
1213
ServoStyleSet::GetBaseContextForElement(
1214
  Element* aElement,
1215
  const ComputedStyle* aStyle)
1216
0
{
1217
0
  return Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
1218
0
                                                        aElement,
1219
0
                                                        aStyle,
1220
0
                                                        &Snapshots()).Consume();
1221
0
}
1222
1223
already_AddRefed<ComputedStyle>
1224
ServoStyleSet::ResolveServoStyleByAddingAnimation(
1225
  Element* aElement,
1226
  const ComputedStyle* aStyle,
1227
  RawServoAnimationValue* aAnimationValue)
1228
0
{
1229
0
  return Servo_StyleSet_GetComputedValuesByAddingAnimation(
1230
0
    mRawSet.get(),
1231
0
    aElement,
1232
0
    aStyle,
1233
0
    &Snapshots(),
1234
0
    aAnimationValue).Consume();
1235
0
}
1236
1237
already_AddRefed<RawServoAnimationValue>
1238
ServoStyleSet::ComputeAnimationValue(
1239
  Element* aElement,
1240
  RawServoDeclarationBlock* aDeclarations,
1241
  const mozilla::ComputedStyle* aStyle)
1242
0
{
1243
0
  return Servo_AnimationValue_Compute(aElement,
1244
0
                                      aDeclarations,
1245
0
                                      aStyle,
1246
0
                                      mRawSet.get()).Consume();
1247
0
}
1248
1249
bool
1250
ServoStyleSet::EnsureUniqueInnerOnCSSSheets()
1251
0
{
1252
0
  using SheetOwner = Variant<ServoStyleSet*, nsXBLPrototypeBinding*, ShadowRoot*>;
1253
0
1254
0
  AutoTArray<Pair<StyleSheet*, SheetOwner>, 32> queue;
1255
0
  for (auto& entryArray : mSheets) {
1256
0
    for (auto& sheet : entryArray) {
1257
0
      StyleSheet* downcasted = sheet;
1258
0
      queue.AppendElement(MakePair(downcasted, SheetOwner { this }));
1259
0
    }
1260
0
  }
1261
0
1262
0
  EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
1263
0
    for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
1264
0
      queue.AppendElement(
1265
0
        MakePair(aShadowRoot.SheetAt(index), SheetOwner { &aShadowRoot }));
1266
0
    }
1267
0
  });
1268
0
1269
0
  mDocument->BindingManager()->EnumerateBoundContentProtoBindings(
1270
0
      [&](nsXBLPrototypeBinding* aProto) {
1271
0
        AutoTArray<StyleSheet*, 3> sheets;
1272
0
        aProto->AppendStyleSheetsTo(sheets);
1273
0
        for (auto* sheet : sheets) {
1274
0
          queue.AppendElement(MakePair(sheet, SheetOwner { aProto }));
1275
0
        }
1276
0
        return true;
1277
0
      });
1278
0
1279
0
  bool anyNonDocStyleChanged = false;
1280
0
  while (!queue.IsEmpty()) {
1281
0
    uint32_t idx = queue.Length() - 1;
1282
0
    auto* sheet = queue[idx].first();
1283
0
    SheetOwner owner = queue[idx].second();
1284
0
    queue.RemoveElementAt(idx);
1285
0
1286
0
    if (!sheet->HasUniqueInner()) {
1287
0
      RawServoAuthorStyles* authorStyles = nullptr;
1288
0
      if (owner.is<ShadowRoot*>()) {
1289
0
        authorStyles = owner.as<ShadowRoot*>()->GetServoStyles();
1290
0
      } else if (owner.is<nsXBLPrototypeBinding*>()) {
1291
0
        authorStyles = owner.as<nsXBLPrototypeBinding*>()->GetServoStyles();
1292
0
      }
1293
0
1294
0
      if (authorStyles) {
1295
0
        Servo_AuthorStyles_ForceDirty(authorStyles);
1296
0
        mNeedsRestyleAfterEnsureUniqueInner = true;
1297
0
        anyNonDocStyleChanged = true;
1298
0
      }
1299
0
    }
1300
0
1301
0
    // Only call EnsureUniqueInner for complete sheets. If we do call it on
1302
0
    // incomplete sheets, we'll cause problems when the sheet is actually
1303
0
    // loaded. We don't care about incomplete sheets here anyway, because this
1304
0
    // method is only invoked by nsPresContext::EnsureSafeToHandOutCSSRules.
1305
0
    // The CSSRule objects we are handing out won't contain any rules derived
1306
0
    // from incomplete sheets (because they aren't yet applied in styling).
1307
0
    if (sheet->IsComplete()) {
1308
0
      sheet->EnsureUniqueInner();
1309
0
    }
1310
0
1311
0
    // Enqueue all the sheet's children.
1312
0
    AutoTArray<StyleSheet*, 3> children;
1313
0
    sheet->AppendAllChildSheets(children);
1314
0
    for (auto* sheet : children) {
1315
0
      queue.AppendElement(MakePair(sheet, owner));
1316
0
    }
1317
0
  }
1318
0
1319
0
  if (anyNonDocStyleChanged) {
1320
0
    SetStylistXBLStyleSheetsDirty();
1321
0
  }
1322
0
1323
0
  if (mNeedsRestyleAfterEnsureUniqueInner) {
1324
0
    // TODO(emilio): We could make this faster if needed tracking the specific
1325
0
    // origins and all that, but the only caller of this doesn't seem to really
1326
0
    // care about perf.
1327
0
    MarkOriginsDirty(OriginFlags::All);
1328
0
  }
1329
0
  bool res = mNeedsRestyleAfterEnsureUniqueInner;
1330
0
  mNeedsRestyleAfterEnsureUniqueInner = false;
1331
0
  return res;
1332
0
}
1333
1334
void
1335
ServoStyleSet::ClearCachedStyleData()
1336
0
{
1337
0
  ClearNonInheritingComputedStyles();
1338
0
  Servo_StyleSet_RebuildCachedData(mRawSet.get());
1339
0
}
1340
1341
void
1342
ServoStyleSet::CompatibilityModeChanged()
1343
0
{
1344
0
  Servo_StyleSet_CompatModeChanged(mRawSet.get());
1345
0
  SetStylistStyleSheetsDirty();
1346
0
}
1347
1348
void
1349
ServoStyleSet::ClearNonInheritingComputedStyles()
1350
0
{
1351
0
  for (RefPtr<ComputedStyle>& ptr : mNonInheritingComputedStyles) {
1352
0
    ptr = nullptr;
1353
0
  }
1354
0
}
1355
1356
already_AddRefed<ComputedStyle>
1357
ServoStyleSet::ResolveStyleLazilyInternal(Element* aElement,
1358
                                          CSSPseudoElementType aPseudoType,
1359
                                          StyleRuleInclusion aRuleInclusion)
1360
0
{
1361
0
  MOZ_ASSERT(GetPresContext(),
1362
0
             "For now, no style resolution without a pres context");
1363
0
  GetPresContext()->EffectCompositor()->PreTraverse(aElement, aPseudoType);
1364
0
  MOZ_ASSERT(!StylistNeedsUpdate());
1365
0
1366
0
  AutoSetInServoTraversal guard(this);
1367
0
1368
0
  /**
1369
0
   * NB: This is needed because we process animations and transitions on the
1370
0
   * pseudo-elements themselves, not on the parent's EagerPseudoStyles.
1371
0
   *
1372
0
   * That means that that style doesn't account for animations, and we can't do
1373
0
   * that easily from the traversal without doing wasted work.
1374
0
   *
1375
0
   * As such, we just lie here a bit, which is the entrypoint of
1376
0
   * getComputedStyle, the only API where this can be observed, to look at the
1377
0
   * style of the pseudo-element if it exists instead.
1378
0
   */
1379
0
  Element* elementForStyleResolution = aElement;
1380
0
  CSSPseudoElementType pseudoTypeForStyleResolution = aPseudoType;
1381
0
  if (aPseudoType == CSSPseudoElementType::before) {
1382
0
    if (Element* pseudo = nsLayoutUtils::GetBeforePseudo(aElement)) {
1383
0
      elementForStyleResolution = pseudo;
1384
0
      pseudoTypeForStyleResolution = CSSPseudoElementType::NotPseudo;
1385
0
    }
1386
0
  } else if (aPseudoType == CSSPseudoElementType::after) {
1387
0
    if (Element* pseudo = nsLayoutUtils::GetAfterPseudo(aElement)) {
1388
0
      elementForStyleResolution = pseudo;
1389
0
      pseudoTypeForStyleResolution = CSSPseudoElementType::NotPseudo;
1390
0
    }
1391
0
  }
1392
0
1393
0
  RefPtr<ComputedStyle> computedValues =
1394
0
    Servo_ResolveStyleLazily(elementForStyleResolution,
1395
0
                             pseudoTypeForStyleResolution,
1396
0
                             aRuleInclusion,
1397
0
                             &Snapshots(),
1398
0
                             mRawSet.get()).Consume();
1399
0
1400
0
  if (GetPresContext()->EffectCompositor()->PreTraverse(aElement, aPseudoType)) {
1401
0
    computedValues =
1402
0
      Servo_ResolveStyleLazily(elementForStyleResolution,
1403
0
                               pseudoTypeForStyleResolution,
1404
0
                               aRuleInclusion,
1405
0
                               &Snapshots(),
1406
0
                               mRawSet.get()).Consume();
1407
0
  }
1408
0
1409
0
  MOZ_DIAGNOSTIC_ASSERT(computedValues->PresContextForFrame() == GetPresContext() ||
1410
0
                        aElement->OwnerDoc()->GetBFCacheEntry());
1411
0
1412
0
  return computedValues.forget();
1413
0
}
1414
1415
bool
1416
ServoStyleSet::AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray)
1417
0
{
1418
0
  // TODO(emilio): Can we make this so this asserts instead?
1419
0
  UpdateStylistIfNeeded();
1420
0
  Servo_StyleSet_GetFontFaceRules(mRawSet.get(), &aArray);
1421
0
  return true;
1422
0
}
1423
1424
const RawServoCounterStyleRule*
1425
ServoStyleSet::CounterStyleRuleForName(nsAtom* aName)
1426
0
{
1427
0
  MOZ_ASSERT(!StylistNeedsUpdate());
1428
0
  return Servo_StyleSet_GetCounterStyleRule(mRawSet.get(), aName);
1429
0
}
1430
1431
already_AddRefed<gfxFontFeatureValueSet>
1432
ServoStyleSet::BuildFontFeatureValueSet()
1433
0
{
1434
0
  MOZ_ASSERT(!StylistNeedsUpdate());
1435
0
  RefPtr<gfxFontFeatureValueSet> set =
1436
0
    Servo_StyleSet_BuildFontFeatureValueSet(mRawSet.get());
1437
0
  return set.forget();
1438
0
}
1439
1440
already_AddRefed<ComputedStyle>
1441
ServoStyleSet::ResolveForDeclarations(
1442
  const ComputedStyle* aParentOrNull,
1443
  RawServoDeclarationBlockBorrowed aDeclarations)
1444
0
{
1445
0
  // No need to update the stylist, we're only cascading aDeclarations.
1446
0
  return Servo_StyleSet_ResolveForDeclarations(mRawSet.get(),
1447
0
                                               aParentOrNull,
1448
0
                                               aDeclarations).Consume();
1449
0
}
1450
1451
void
1452
ServoStyleSet::UpdateStylist()
1453
0
{
1454
0
  MOZ_ASSERT(StylistNeedsUpdate());
1455
0
1456
0
  if (mStylistState & StylistState::StyleSheetsDirty) {
1457
0
    // There's no need to compute invalidations and such for an XBL styleset,
1458
0
    // since they are loaded and unloaded synchronously, and they don't have to
1459
0
    // deal with dynamic content changes.
1460
0
    Element* root = mDocument->GetRootElement();
1461
0
    const ServoElementSnapshotTable* snapshots = nullptr;
1462
0
    if (nsPresContext* pc = GetPresContext()) {
1463
0
      snapshots = &pc->RestyleManager()->Snapshots();
1464
0
    }
1465
0
    Servo_StyleSet_FlushStyleSheets(mRawSet.get(), root, snapshots);
1466
0
  }
1467
0
1468
0
  if (MOZ_UNLIKELY(mStylistState & StylistState::XBLStyleSheetsDirty)) {
1469
0
    MOZ_ASSERT(GetPresContext(), "How did they get dirty?");
1470
0
1471
0
    EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
1472
0
      if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
1473
0
        Servo_AuthorStyles_Flush(authorStyles, mRawSet.get());
1474
0
      }
1475
0
    });
1476
0
1477
0
    mDocument->BindingManager()->EnumerateBoundContentProtoBindings(
1478
0
      [&](nsXBLPrototypeBinding* aProto) {
1479
0
        if (auto* authorStyles = aProto->GetServoStyles()) {
1480
0
          Servo_AuthorStyles_Flush(authorStyles, mRawSet.get());
1481
0
        }
1482
0
        return true;
1483
0
      });
1484
0
  }
1485
0
1486
0
  mStylistState = StylistState::NotDirty;
1487
0
}
1488
1489
void
1490
ServoStyleSet::MaybeGCRuleTree()
1491
0
{
1492
0
  MOZ_ASSERT(NS_IsMainThread());
1493
0
  Servo_MaybeGCRuleTree(mRawSet.get());
1494
0
}
1495
1496
/* static */ bool
1497
ServoStyleSet::MayTraverseFrom(const Element* aElement)
1498
0
{
1499
0
  MOZ_ASSERT(aElement->IsInComposedDoc());
1500
0
  nsINode* parent = aElement->GetFlattenedTreeParentNodeForStyle();
1501
0
  if (!parent) {
1502
0
    return false;
1503
0
  }
1504
0
1505
0
  if (!parent->IsElement()) {
1506
0
    MOZ_ASSERT(parent->IsDocument());
1507
0
    return true;
1508
0
  }
1509
0
1510
0
  if (!parent->AsElement()->HasServoData()) {
1511
0
    return false;
1512
0
  }
1513
0
1514
0
  return !Servo_Element_IsDisplayNone(parent->AsElement());
1515
0
}
1516
1517
bool
1518
ServoStyleSet::ShouldTraverseInParallel() const
1519
0
{
1520
0
  MOZ_ASSERT(mDocument->GetShell(), "Styling a document without a shell?");
1521
0
  if (!mDocument->GetShell()->IsActive()) {
1522
0
    return false;
1523
0
  }
1524
0
#ifdef MOZ_GECKO_PROFILER
1525
0
  if (profiler_feature_active(ProfilerFeature::SequentialStyle)) {
1526
0
    return false;
1527
0
  }
1528
0
#endif
1529
0
  return true;
1530
0
}
1531
1532
void
1533
ServoStyleSet::PrependSheetOfType(SheetType aType, StyleSheet* aSheet)
1534
0
{
1535
0
  aSheet->AddStyleSet(this);
1536
0
  mSheets[aType].InsertElementAt(0, aSheet);
1537
0
}
1538
1539
void
1540
ServoStyleSet::AppendSheetOfType(SheetType aType, StyleSheet* aSheet)
1541
0
{
1542
0
  aSheet->AddStyleSet(this);
1543
0
  mSheets[aType].AppendElement(aSheet);
1544
0
}
1545
1546
void
1547
ServoStyleSet::InsertSheetOfType(SheetType aType,
1548
                                 StyleSheet* aSheet,
1549
                                 StyleSheet* aBeforeSheet)
1550
0
{
1551
0
  for (uint32_t i = 0; i < mSheets[aType].Length(); ++i) {
1552
0
    if (mSheets[aType][i] == aBeforeSheet) {
1553
0
      aSheet->AddStyleSet(this);
1554
0
      mSheets[aType].InsertElementAt(i, aSheet);
1555
0
      return;
1556
0
    }
1557
0
  }
1558
0
}
1559
1560
void
1561
ServoStyleSet::RemoveSheetOfType(SheetType aType, StyleSheet* aSheet)
1562
0
{
1563
0
  for (uint32_t i = 0; i < mSheets[aType].Length(); ++i) {
1564
0
    if (mSheets[aType][i] == aSheet) {
1565
0
      aSheet->DropStyleSet(this);
1566
0
      mSheets[aType].RemoveElementAt(i);
1567
0
    }
1568
0
  }
1569
0
}
1570
1571
void
1572
ServoStyleSet::RunPostTraversalTasks()
1573
0
{
1574
0
  MOZ_ASSERT(!IsInServoTraversal());
1575
0
1576
0
  if (mPostTraversalTasks.IsEmpty()) {
1577
0
    return;
1578
0
  }
1579
0
1580
0
  nsTArray<PostTraversalTask> tasks;
1581
0
  tasks.SwapElements(mPostTraversalTasks);
1582
0
1583
0
  for (auto& task : tasks) {
1584
0
    task.Run();
1585
0
  }
1586
0
}
1587
1588
ServoStyleRuleMap*
1589
ServoStyleSet::StyleRuleMap()
1590
0
{
1591
0
  if (!mStyleRuleMap) {
1592
0
    mStyleRuleMap = MakeUnique<ServoStyleRuleMap>();
1593
0
  }
1594
0
  mStyleRuleMap->EnsureTable(*this);
1595
0
  return mStyleRuleMap.get();
1596
0
}
1597
1598
bool
1599
ServoStyleSet::MightHaveAttributeDependency(const Element& aElement,
1600
                                            nsAtom* aAttribute) const
1601
0
{
1602
0
  return Servo_StyleSet_MightHaveAttributeDependency(
1603
0
      mRawSet.get(), &aElement, aAttribute);
1604
0
}
1605
1606
bool
1607
ServoStyleSet::HasStateDependency(const Element& aElement,
1608
                                  EventStates aState) const
1609
0
{
1610
0
  return Servo_StyleSet_HasStateDependency(
1611
0
      mRawSet.get(), &aElement, aState.ServoValue());
1612
0
}
1613
1614
bool
1615
ServoStyleSet::HasDocumentStateDependency(EventStates aState) const
1616
0
{
1617
0
  return Servo_StyleSet_HasDocumentStateDependency(
1618
0
      mRawSet.get(), aState.ServoValue());
1619
0
}
1620
1621
already_AddRefed<ComputedStyle>
1622
ServoStyleSet::ReparentComputedStyle(ComputedStyle* aComputedStyle,
1623
                                     ComputedStyle* aNewParent,
1624
                                     ComputedStyle* aNewParentIgnoringFirstLine,
1625
                                     ComputedStyle* aNewLayoutParent,
1626
                                     Element* aElement)
1627
0
{
1628
0
  return Servo_ReparentStyle(aComputedStyle, aNewParent,
1629
0
                             aNewParentIgnoringFirstLine, aNewLayoutParent,
1630
0
                             aElement, mRawSet.get()).Consume();
1631
0
}
1632
1633
NS_IMPL_ISUPPORTS(UACacheReporter, nsIMemoryReporter)
1634
1635
MOZ_DEFINE_MALLOC_SIZE_OF(ServoUACacheMallocSizeOf)
1636
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoUACacheMallocEnclosingSizeOf)
1637
1638
NS_IMETHODIMP
1639
UACacheReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
1640
                                nsISupports* aData, bool aAnonymize)
1641
0
{
1642
0
  ServoStyleSetSizes sizes;
1643
0
  Servo_UACache_AddSizeOf(ServoUACacheMallocSizeOf,
1644
0
                          ServoUACacheMallocEnclosingSizeOf, &sizes);
1645
0
1646
0
#define REPORT(_path, _amount, _desc) \
1647
0
  do { \
1648
0
    size_t __amount = _amount;  /* evaluate _amount only once */ \
1649
0
    if (__amount > 0) { \
1650
0
      MOZ_COLLECT_REPORT(_path, KIND_HEAP, UNITS_BYTES, __amount, _desc); \
1651
0
    } \
1652
0
  } while (0)
1653
0
1654
0
  // The UA cache does not contain the rule tree; that's in the StyleSet.
1655
0
  MOZ_RELEASE_ASSERT(sizes.mRuleTree == 0);
1656
0
1657
0
  REPORT("explicit/layout/servo-ua-cache/precomputed-pseudos",
1658
0
         sizes.mPrecomputedPseudos,
1659
0
         "Memory used by precomputed pseudo-element declarations within the "
1660
0
         "UA cache.");
1661
0
1662
0
  REPORT("explicit/layout/servo-ua-cache/element-and-pseudos-maps",
1663
0
         sizes.mElementAndPseudosMaps,
1664
0
         "Memory used by element and pseudos maps within the UA cache.");
1665
0
1666
0
  REPORT("explicit/layout/servo-ua-cache/invalidation-map",
1667
0
         sizes.mInvalidationMap,
1668
0
         "Memory used by invalidation maps within the UA cache.");
1669
0
1670
0
  REPORT("explicit/layout/servo-ua-cache/revalidation-selectors",
1671
0
         sizes.mRevalidationSelectors,
1672
0
         "Memory used by selectors for cache revalidation within the UA "
1673
0
         "cache.");
1674
0
1675
0
  REPORT("explicit/layout/servo-ua-cache/other",
1676
0
         sizes.mOther,
1677
0
         "Memory used by other data within the UA cache");
1678
0
1679
0
  return NS_OK;
1680
0
}