tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsPresContext.cpp (104494B)


      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 /* a presentation of a document, part 1 */
      8 
      9 #include "nsPresContext.h"
     10 
     11 #include "nsPresContextInlines.h"
     12 #if defined(MOZ_WIDGET_ANDROID)
     13 #  include "mozilla/AsyncEventDispatcher.h"
     14 #endif
     15 #include "COLRFonts.h"
     16 #include "CounterStyleManager.h"
     17 #include "LayerUserData.h"
     18 #include "MobileViewportManager.h"
     19 #include "base/basictypes.h"
     20 #include "gfxPlatform.h"
     21 #include "gfxTextRun.h"
     22 #include "mozilla/AnimationEventDispatcher.h"
     23 #include "mozilla/ContentBlockingAllowList.h"
     24 #include "mozilla/CycleCollectedJSContext.h"
     25 #include "mozilla/DebugOnly.h"
     26 #include "mozilla/EffectCompositor.h"
     27 #include "mozilla/Encoding.h"
     28 #include "mozilla/EventDispatcher.h"
     29 #include "mozilla/EventListenerManager.h"
     30 #include "mozilla/EventStateManager.h"
     31 #include "mozilla/GlobalStyleSheetCache.h"
     32 #include "mozilla/LookAndFeel.h"
     33 #include "mozilla/MediaFeatureChange.h"
     34 #include "mozilla/MemoryReporting.h"
     35 #include "mozilla/Preferences.h"
     36 #include "mozilla/PresShell.h"
     37 #include "mozilla/PresShellInlines.h"
     38 #include "mozilla/RestyleManager.h"
     39 #include "mozilla/SMILAnimationController.h"
     40 #include "mozilla/ServoBindings.h"
     41 #include "mozilla/ServoStyleSet.h"
     42 #include "mozilla/StaticPrefs_bidi.h"
     43 #include "mozilla/StaticPrefs_layout.h"
     44 #include "mozilla/StaticPrefs_widget.h"
     45 #include "mozilla/StaticPrefs_zoom.h"
     46 #include "mozilla/StaticPresData.h"
     47 #include "mozilla/StyleSheet.h"
     48 #include "mozilla/StyleSheetInlines.h"
     49 #include "mozilla/Telemetry.h"
     50 #include "mozilla/TimelineManager.h"
     51 #include "mozilla/css/ImageLoader.h"
     52 #include "mozilla/dom/BrowserChild.h"
     53 #include "mozilla/dom/BrowserParent.h"
     54 #include "mozilla/dom/BrowsingContext.h"
     55 #include "mozilla/dom/Document.h"
     56 #include "mozilla/dom/DocumentInlines.h"
     57 #include "mozilla/dom/Element.h"
     58 #include "mozilla/dom/FontFaceSet.h"
     59 #include "mozilla/dom/HTMLBodyElement.h"
     60 #include "mozilla/dom/InteractiveWidget.h"
     61 #include "mozilla/dom/MediaQueryList.h"
     62 #include "mozilla/dom/NotifyPaintEvent.h"
     63 #include "mozilla/dom/PBrowserParent.h"
     64 #include "mozilla/dom/Performance.h"
     65 #include "mozilla/dom/PerformanceMainThread.h"
     66 #include "mozilla/dom/PerformancePaintTiming.h"
     67 #include "mozilla/dom/PerformanceTiming.h"
     68 #include "mozilla/glean/LayoutMetrics.h"
     69 #include "mozilla/layers/APZThreadUtils.h"
     70 #include "nsAnimationManager.h"
     71 #include "nsCOMPtr.h"
     72 #include "nsCRT.h"
     73 #include "nsCSSFrameConstructor.h"
     74 #include "nsContentUtils.h"
     75 #include "nsDeviceContext.h"
     76 #include "nsDocShell.h"
     77 #include "nsFontCache.h"
     78 #include "nsFontFaceLoader.h"
     79 #include "nsFontFaceUtils.h"
     80 #include "nsFrameLoader.h"
     81 #include "nsHTMLDocument.h"
     82 #include "nsIConsoleService.h"
     83 #include "nsIContent.h"
     84 #include "nsIDocumentViewer.h"
     85 #include "nsIFrame.h"
     86 #include "nsIInterfaceRequestorUtils.h"
     87 #include "nsIMessageManager.h"
     88 #include "nsIPrintSettings.h"
     89 #include "nsIWeakReferenceUtils.h"
     90 #include "nsLanguageAtomService.h"
     91 #include "nsLayoutUtils.h"
     92 #include "nsPIDOMWindow.h"
     93 #include "nsPIWindowRoot.h"
     94 #include "nsRefreshDriver.h"
     95 #include "nsSubDocumentFrame.h"
     96 #include "nsThreadUtils.h"
     97 #include "nsTransitionManager.h"
     98 #include "prenv.h"
     99 #ifdef ACCESSIBILITY
    100 #  include "mozilla/a11y/DocAccessible.h"
    101 #endif
    102 
    103 // Needed for Start/Stop of Image Animation
    104 #include "imgIContainer.h"
    105 #include "mozilla/ServoCSSParser.h"
    106 #include "mozilla/dom/URL.h"
    107 #include "nsBidiUtils.h"
    108 #include "nsIImageLoadingContent.h"
    109 #include "nsServiceManagerUtils.h"
    110 
    111 using namespace mozilla;
    112 using namespace mozilla::dom;
    113 using namespace mozilla::gfx;
    114 using namespace mozilla::layers;
    115 
    116 static LazyLogModule gFingerprinterDetection("FingerprinterDetection");
    117 
    118 /**
    119 * Layer UserData for ContainerLayers that want to be notified
    120 * of local invalidations of them and their descendant layers.
    121 * Pass a callback to ComputeDifferences to have these called.
    122 */
    123 class ContainerLayerPresContext : public LayerUserData {
    124 public:
    125  nsPresContext* mPresContext;
    126 };
    127 
    128 bool nsPresContext::IsDOMPaintEventPending() {
    129  if (!mTransactions.IsEmpty()) {
    130    return true;
    131  }
    132 
    133  nsRootPresContext* drpc = GetRootPresContext();
    134  if (drpc && drpc->mRefreshDriver->IsPaintPending()) {
    135    // Since we're promising that there will be a MozAfterPaint event fired, we
    136    // record an empty invalidation in case display list invalidation doesn't
    137    // invalidate anything further.
    138    NotifyInvalidation(drpc->mRefreshDriver->LastTransactionId().Next(),
    139                       nsRect());
    140    return true;
    141  }
    142  return false;
    143 }
    144 
    145 struct WeakRunnableMethod : Runnable {
    146  using Method = void (nsPresContext::*)();
    147 
    148  WeakRunnableMethod(const char* aName, nsPresContext* aPc, Method aMethod)
    149      : Runnable(aName), mPresContext(aPc), mMethod(aMethod) {}
    150 
    151  NS_IMETHOD Run() override {
    152    if (nsPresContext* pc = mPresContext.get()) {
    153      (pc->*mMethod)();
    154    }
    155    return NS_OK;
    156  }
    157 
    158 private:
    159  WeakPtr<nsPresContext> mPresContext;
    160  Method mMethod;
    161 };
    162 
    163 // When forcing a font-info-update reflow from style, we don't need to reframe,
    164 // but we'll need to restyle to pick up updated font metrics. In order to avoid
    165 // synchronously having to deal with multiple restyles, we use an early refresh
    166 // driver runner, which should prevent flashing for users.
    167 //
    168 // We might do a bit of extra work if the page flushes layout between the
    169 // restyle and when this happens, which is a bit unfortunate, but not worse than
    170 // what we used to do...
    171 //
    172 // A better solution would be to be able to synchronously initialize font
    173 // information from style worker threads, perhaps...
    174 void nsPresContext::ForceReflowForFontInfoUpdateFromStyle() {
    175  if (mPendingFontInfoUpdateReflowFromStyle) {
    176    return;
    177  }
    178 
    179  mPendingFontInfoUpdateReflowFromStyle = true;
    180  nsCOMPtr<nsIRunnable> ev = new WeakRunnableMethod(
    181      "nsPresContext::DoForceReflowForFontInfoUpdateFromStyle", this,
    182      &nsPresContext::DoForceReflowForFontInfoUpdateFromStyle);
    183  RefreshDriver()->AddEarlyRunner(ev);
    184 }
    185 
    186 void nsPresContext::DoForceReflowForFontInfoUpdateFromStyle() {
    187  mPendingFontInfoUpdateReflowFromStyle = false;
    188  ForceReflowForFontInfoUpdate(false);
    189 }
    190 
    191 void nsPresContext::ForceReflowForFontInfoUpdate(bool aNeedsReframe) {
    192  // In the case of a static-clone document used for printing or print-preview,
    193  // this is undesirable because the nsPrintJob is holding weak refs to frames
    194  // that will get blown away unexpectedly by this reconstruction. So the
    195  // prescontext for a print/preview doc ignores the font-list update.
    196  //
    197  // This means the print document may still be using cached fonts that are no
    198  // longer present in the font list, but that should be safe given that all the
    199  // required font instances have already been created, so it won't be depending
    200  // on access to the font-list entries.
    201  //
    202  // XXX Actually, I think it's probably a bad idea to do *any* restyling of
    203  // print documents in response to pref changes. We could be in the middle
    204  // of printing the document, and reflowing all the frames might cause some
    205  // kind of unwanted mid-document discontinuity.
    206  if (IsPrintingOrPrintPreview()) {
    207    return;
    208  }
    209 
    210  // If there's a user font set, discard any src:local() faces it may have
    211  // loaded because their font entries may no longer be valid.
    212  if (auto* fonts = Document()->GetFonts()) {
    213    fonts->GetImpl()->ForgetLocalFaces();
    214  }
    215 
    216  FlushFontCache();
    217 
    218  if (!mPresShell) {
    219    // RebuildAllStyleData won't do anything without mPresShell.
    220    return;
    221  }
    222 
    223  nsChangeHint changeHint =
    224      aNeedsReframe ? nsChangeHint_ReconstructFrame : NS_STYLE_HINT_REFLOW;
    225 
    226  // We also need to trigger restyling for ex/ch units changes to take effect,
    227  // if needed.
    228  auto restyleHint = StyleSet()->UsesFontMetrics()
    229                         ? RestyleHint::RecascadeSubtree()
    230                         : RestyleHint{0};
    231 
    232  RebuildAllStyleData(changeHint, restyleHint);
    233 }
    234 
    235 static bool IsVisualCharset(NotNull<const Encoding*> aCharset) {
    236  return aCharset == ISO_8859_8_ENCODING;
    237 }
    238 
    239 nsPresContext::nsPresContext(dom::Document* aDocument, nsPresContextType aType)
    240    : mPresShell(nullptr),
    241      mDocument(aDocument),
    242      mMedium(aType == eContext_Galley ? nsGkAtoms::screen : nsGkAtoms::print),
    243      mTextZoom(1.0),
    244      mFullZoom(1.0),
    245      mLastFontInflationScreenSize(gfxSize(-1.0, -1.0)),
    246      mCurAppUnitsPerDevPixel(0),
    247      mDynamicToolbarMaxHeight(0),
    248      mDynamicToolbarHeight(0),
    249      mPageSize(-1, -1),
    250      mPageScale(0.0),
    251      mPPScale(1.0f),
    252      mViewportScrollOverrideElement(nullptr),
    253      mElementsRestyled(0),
    254      mFramesConstructed(0),
    255      mFramesReflowed(0),
    256      mAnimationTriggeredRestyles(0),
    257      mInterruptChecksToSkip(0),
    258      mNextFrameRateMultiplier(0),
    259      mMeasuredTicksSinceLoading(0),
    260      mViewportScrollStyles(StyleOverflow::Auto, StyleOverflow::Auto),
    261      // mImageAnimationMode is initialised below, in constructor body
    262      mImageAnimationModePref(imgIContainer::kNormalAnimMode),
    263      mType(aType),
    264      mInflationDisabledForShrinkWrap(false),
    265      mInteractionTimeEnabled(true),
    266      mHasPendingInterrupt(false),
    267      mHasEverBuiltInvisibleText(false),
    268      mPendingInterruptFromTest(false),
    269      mInterruptsEnabled(false),
    270      mDrawImageBackground(true),  // always draw the background
    271      mDrawColorBackground(true),
    272      // mNeverAnimate is initialised below, in constructor body
    273      mPaginated(aType != eContext_Galley),
    274      mCanPaginatedScroll(false),
    275      mDoScaledTwips(true),
    276      mIsRootPaginatedDocument(false),
    277      mPendingThemeChanged(false),
    278      mPendingThemeChangeKind(0),
    279      mPendingUIResolutionChanged(false),
    280      mPendingFontInfoUpdateReflowFromStyle(false),
    281      mIsGlyph(false),
    282      mCounterStylesDirty(true),
    283      mFontFeatureValuesDirty(true),
    284      mFontPaletteValuesDirty(true),
    285      mIsVisual(false),
    286      mInRDMPane(false),
    287      mHasWarnedAboutTooLargeDashedOrDottedRadius(false),
    288      mQuirkSheetAdded(false),
    289      mHadNonBlankPaint(false),
    290      mHadFirstContentfulPaint(false),
    291      mHadNonTickContentfulPaint(false),
    292      mHadContentfulPaintComposite(false),
    293      mNeedsToUpdateHiddenByContentVisibilityForAnimations(false),
    294      mUserInputEventsAllowed(false),
    295 #ifdef DEBUG
    296      mInitialized(false),
    297 #endif
    298      mOverriddenOrEmbedderColorScheme(dom::PrefersColorSchemeOverride::None),
    299      mForcedColors(StyleForcedColors::None) {
    300 #ifdef DEBUG
    301  PodZero(&mLayoutPhaseCount);
    302 #endif
    303 
    304  if (!IsDynamic()) {
    305    mImageAnimationMode = imgIContainer::kDontAnimMode;
    306    mNeverAnimate = true;
    307  } else {
    308    mImageAnimationMode = imgIContainer::kNormalAnimMode;
    309    mNeverAnimate = false;
    310  }
    311  NS_ASSERTION(mDocument, "Null document");
    312 
    313  // if text perf logging enabled, init stats struct
    314  if (MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_textperf), LogLevel::Warning)) {
    315    mTextPerf = MakeUnique<gfxTextPerfMetrics>();
    316  }
    317 
    318  if (StaticPrefs::gfx_missing_fonts_notify()) {
    319    mMissingFonts = MakeUnique<gfxMissingFontRecorder>();
    320  }
    321 
    322  if (StaticPrefs::layout_dynamic_toolbar_max_height() > 0 &&
    323      IsRootContentDocumentCrossProcess()) {
    324    // The pref for dynamic toolbar max height is only used in reftests so it's
    325    // fine to set here.
    326    mDynamicToolbarMaxHeight = StaticPrefs::layout_dynamic_toolbar_max_height();
    327  }
    328 
    329  UpdateFontVisibility();
    330  UpdateForcedColors(/* aNotify = */ false);
    331 }
    332 
    333 static const char* gExactCallbackPrefs[] = {
    334    "dom.meta-viewport.enabled",
    335    "image.animation_mode",
    336    "intl.accept_languages",
    337    "layout.css.devPixelsPerPx",
    338    "layout.css.dpi",
    339    "layout.css.letter-spacing.model",
    340    "layout.css.ruby.normalize-metrics-factor",
    341    "layout.css.text-autospace.enabled",
    342    "layout.css.text-transform.uppercase-eszett.enabled",
    343    "privacy.trackingprotection.enabled",
    344    nullptr,
    345 };
    346 
    347 static const char* gPrefixCallbackPrefs[] = {
    348    "bidi.",
    349    "browser.viewport.",
    350    "font.",
    351    "gfx.font_rendering.",
    352    "layout.css.font-visibility.",
    353    nullptr,
    354 };
    355 
    356 void nsPresContext::Destroy() {
    357  if (mEventManager) {
    358    // unclear if these are needed, but can't hurt
    359    mEventManager->NotifyDestroyPresContext(this);
    360    mEventManager->SetPresContext(nullptr);
    361    mEventManager = nullptr;
    362  }
    363 
    364  if (mFontCache) {
    365    mFontCache->Destroy();
    366    mFontCache = nullptr;
    367  }
    368 
    369  // Unregister preference callbacks
    370  Preferences::UnregisterPrefixCallbacks(nsPresContext::PreferenceChanged,
    371                                         gPrefixCallbackPrefs, this);
    372  Preferences::UnregisterCallbacks(nsPresContext::PreferenceChanged,
    373                                   gExactCallbackPrefs, this);
    374 
    375  mRefreshDriver = nullptr;
    376  MOZ_ASSERT(mManagedPostRefreshObservers.IsEmpty());
    377 }
    378 
    379 nsPresContext::~nsPresContext() {
    380  MOZ_ASSERT(!mPresShell, "Presshell forgot to clear our mPresShell pointer");
    381  DetachPresShell();
    382 
    383  Destroy();
    384 }
    385 
    386 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPresContext)
    387  NS_INTERFACE_MAP_ENTRY(nsISupports)
    388 NS_INTERFACE_MAP_END
    389 
    390 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPresContext)
    391 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsPresContext, LastRelease())
    392 
    393 void nsPresContext::LastRelease() {
    394  if (mMissingFonts) {
    395    mMissingFonts->Clear();
    396  }
    397 }
    398 
    399 NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
    400 
    401 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
    402  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnimationEventDispatcher);
    403  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
    404  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDeviceContext); // not xpcom
    405  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEffectCompositor);
    406  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventManager);
    407  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLanguage); // an atom
    408 
    409  // NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTheme); // a service
    410  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrintSettings);
    411 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    412 
    413 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
    414  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnimationEventDispatcher);
    415  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
    416  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeviceContext);  // worth bothering?
    417  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEffectCompositor);
    418  // NS_RELEASE(tmp->mLanguage); // an atom
    419  // NS_IMPL_CYCLE_COLLECTION_UNLINK(mTheme); // a service
    420  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrintSettings);
    421  NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
    422 
    423  tmp->Destroy();
    424 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    425 
    426 bool nsPresContext::IsChrome() const {
    427  return Document()->IsInChromeDocShell();
    428 }
    429 
    430 void nsPresContext::GetUserPreferences() {
    431  if (!GetPresShell()) {
    432    // No presshell means nothing to do here.  We'll do this when we
    433    // get a presshell.
    434    return;
    435  }
    436 
    437  Document()->SetMayNeedFontPrefsUpdate();
    438 
    439  // * image animation
    440  nsAutoCString animatePref;
    441  Preferences::GetCString("image.animation_mode", animatePref);
    442  if (animatePref.EqualsLiteral("normal")) {
    443    mImageAnimationModePref = imgIContainer::kNormalAnimMode;
    444  } else if (animatePref.EqualsLiteral("none")) {
    445    mImageAnimationModePref = imgIContainer::kDontAnimMode;
    446  } else if (animatePref.EqualsLiteral("once")) {
    447    mImageAnimationModePref = imgIContainer::kLoopOnceAnimMode;
    448  } else {  // dynamic change to invalid value should act like it does initially
    449    mImageAnimationModePref = imgIContainer::kNormalAnimMode;
    450  }
    451 
    452  uint32_t bidiOptions = GetBidi();
    453 
    454  SET_BIDI_OPTION_DIRECTION(bidiOptions, StaticPrefs::bidi_direction());
    455  SET_BIDI_OPTION_TEXTTYPE(bidiOptions, StaticPrefs::bidi_texttype());
    456  SET_BIDI_OPTION_NUMERAL(bidiOptions, StaticPrefs::bidi_numeral());
    457 
    458  // We don't need to force reflow: either we are initializing a new
    459  // prescontext or we are being called from PreferenceChanged()
    460  // which triggers a reflow anyway.
    461  SetBidi(bidiOptions);
    462 }
    463 
    464 void nsPresContext::InvalidatePaintedLayers() {
    465  if (!mPresShell) {
    466    return;
    467  }
    468  if (nsIFrame* rootFrame = mPresShell->GetRootFrame()) {
    469    // FrameLayerBuilder caches invalidation-related values that depend on the
    470    // appunits-per-dev-pixel ratio, so ensure that all PaintedLayer drawing
    471    // is completely flushed.
    472    rootFrame->InvalidateFrameSubtree();
    473  }
    474 }
    475 
    476 void nsPresContext::AppUnitsPerDevPixelChanged() {
    477  int32_t oldAppUnitsPerDevPixel = mCurAppUnitsPerDevPixel;
    478 
    479  InvalidatePaintedLayers();
    480 
    481  FlushFontCache();
    482 
    483  mCurAppUnitsPerDevPixel = mDeviceContext->AppUnitsPerDevPixel();
    484 
    485 #ifdef ACCESSIBILITY
    486  if (mCurAppUnitsPerDevPixel != oldAppUnitsPerDevPixel) {
    487    if (nsAccessibilityService* accService = GetAccService()) {
    488      accService->NotifyOfDevPixelRatioChange(mPresShell,
    489                                              mCurAppUnitsPerDevPixel);
    490    }
    491  }
    492 #endif
    493 
    494  // Recompute the size for vh units since it's changed by the dynamic toolbar
    495  // max height which is stored in screen coord.
    496  if (IsRootContentDocumentCrossProcess()) {
    497    AdjustSizeForViewportUnits();
    498  }
    499 
    500  // nsSubDocumentFrame uses a AppUnitsPerDevPixel difference between parent and
    501  // child document to determine if it needs to build a nsDisplayZoom item. So
    502  // if we that changes then we need to invalidate the subdoc frame so that
    503  // item gets created/removed.
    504  if (mPresShell) {
    505    if (nsIFrame* frame = mPresShell->GetRootFrame()) {
    506      frame = nsLayoutUtils::GetCrossDocParentFrameInProcess(frame);
    507      if (frame) {
    508        int32_t parentAPD = frame->PresContext()->AppUnitsPerDevPixel();
    509        if ((parentAPD == oldAppUnitsPerDevPixel) !=
    510            (parentAPD == mCurAppUnitsPerDevPixel)) {
    511          frame->InvalidateFrame();
    512        }
    513      }
    514    }
    515  }
    516 
    517  MediaFeatureValuesChanged(
    518      {RestyleHint::RecascadeSubtree(), NS_STYLE_HINT_REFLOW,
    519       MediaFeatureChangeReason::ResolutionChange},
    520      MediaFeatureChangePropagation::JustThisDocument);
    521 
    522  // We would also have to look at all of our child subdocuments but the
    523  // InvalidatePaintedLayers call above calls InvalidateFrameSubtree which
    524  // would invalidate all subdocument frames already.
    525 }
    526 
    527 // static
    528 void nsPresContext::PreferenceChanged(const char* aPrefName, void* aSelf) {
    529  static_cast<nsPresContext*>(aSelf)->PreferenceChanged(aPrefName);
    530 }
    531 
    532 void nsPresContext::PreferenceChanged(const char* aPrefName) {
    533  if (!mPresShell) {
    534    return;
    535  }
    536 
    537  nsDependentCString prefName(aPrefName);
    538  if (prefName.EqualsLiteral("layout.css.dpi") ||
    539      prefName.EqualsLiteral("layout.css.devPixelsPerPx")) {
    540    int32_t oldAppUnitsPerDevPixel = mDeviceContext->AppUnitsPerDevPixel();
    541    // We need to assume the DPI changes, since `mDeviceContext` is shared with
    542    // other documents, and we'd need to save the return value of the first call
    543    // for all of them.
    544    (void)mDeviceContext->CheckDPIChange();
    545    RefPtr ps = mPresShell;
    546    // Use the maybe-pending size from presshell in case there's a
    547    // deferred resize which hasn't affected our visible area yet.
    548    auto oldSizeDevPixels = LayoutDeviceSize::FromAppUnits(
    549        ps->MaybePendingLayoutViewportSize(), oldAppUnitsPerDevPixel);
    550 
    551    UIResolutionChangedInternal();
    552    ps->SetLayoutViewportSize(
    553        LayoutDeviceSize::ToAppUnits(oldSizeDevPixels, AppUnitsPerDevPixel()),
    554        /* aDelay = */ false);
    555    return;
    556  }
    557 
    558  if (StringBeginsWith(prefName, "browser.viewport."_ns) ||
    559      StringBeginsWith(prefName, "font.size.inflation."_ns) ||
    560      prefName.EqualsLiteral("dom.meta-viewport.enabled")) {
    561    mPresShell->MaybeReflowForInflationScreenSizeChange();
    562  }
    563 
    564  auto changeHint = nsChangeHint{0};
    565  auto restyleHint = RestyleHint{0};
    566  if (prefName.EqualsLiteral(GFX_MISSING_FONTS_NOTIFY_PREF)) {
    567    if (StaticPrefs::gfx_missing_fonts_notify()) {
    568      if (!mMissingFonts) {
    569        mMissingFonts = MakeUnique<gfxMissingFontRecorder>();
    570        // trigger reflow to detect missing fonts on the current page
    571        changeHint |= NS_STYLE_HINT_REFLOW;
    572      }
    573    } else {
    574      if (mMissingFonts) {
    575        mMissingFonts->Clear();
    576      }
    577      mMissingFonts = nullptr;
    578    }
    579  }
    580 
    581  if (StringBeginsWith(prefName, "font."_ns) ||
    582      // Changes to font family preferences don't change anything in the
    583      // computed style data, so the style system won't generate a reflow hint
    584      // for us.  We need to do that manually.
    585      prefName.EqualsLiteral("intl.accept_languages") ||
    586      // Changes to bidi prefs need to trigger a reflow (see bug 443629)
    587      StringBeginsWith(prefName, "bidi."_ns) ||
    588      // Changes to font_rendering prefs need to trigger a reflow
    589      StringBeginsWith(prefName, "gfx.font_rendering."_ns)) {
    590    changeHint |= NS_STYLE_HINT_REFLOW;
    591    if (StyleSet()->UsesFontMetrics()) {
    592      restyleHint |= RestyleHint::RecascadeSubtree();
    593    }
    594  }
    595 
    596  if (prefName.EqualsLiteral(
    597          "layout.css.text-transform.uppercase-eszett.enabled") ||
    598      prefName.EqualsLiteral("layout.css.text-autospace.enabled") ||
    599      prefName.EqualsLiteral("layout.css.letter-spacing.model")) {
    600    changeHint |= NS_STYLE_HINT_REFLOW;
    601  }
    602 
    603  if (prefName.EqualsLiteral("layout.css.ruby.normalize-metrics-factor")) {
    604    mRubyPositioningFactor = -1;  // mark as uninitialized
    605    changeHint |= NS_STYLE_HINT_REFLOW;
    606  }
    607 
    608  // Same, this just frees a bunch of memory.
    609  StaticPresData::Get()->InvalidateFontPrefs();
    610  Document()->SetMayNeedFontPrefsUpdate();
    611 
    612  // Initialize our state from the user preferences.
    613  GetUserPreferences();
    614 
    615  FlushFontCache();
    616  if (UpdateFontVisibility()) {
    617    changeHint |= NS_STYLE_HINT_REFLOW;
    618  }
    619 
    620  // Preferences require rerunning selector matching because we rebuild
    621  // the pref style sheet for some preference changes.
    622  if (changeHint || restyleHint) {
    623    RebuildAllStyleData(changeHint, restyleHint);
    624  }
    625 
    626  InvalidatePaintedLayers();
    627 }
    628 
    629 bool nsPresContext::NormalizeRubyMetrics() {
    630  if (mRubyPositioningFactor < 0.0f) {
    631    // Expected pref values are 0 or [100..200], treated as a percentage.
    632    // We store the value divided by 100, to use as a scaling factor.
    633    mRubyPositioningFactor =
    634        StaticPrefs::layout_css_ruby_normalize_metrics_factor() / 100.0f;
    635    // Clamp to the range of reasonable values.
    636    if (mRubyPositioningFactor <= 0.0f) {
    637      mRubyPositioningFactor = 0.0f;
    638    } else {
    639      mRubyPositioningFactor =
    640          std::max(1.0f, std::min(2.0f, mRubyPositioningFactor));
    641    }
    642  }
    643  return mRubyPositioningFactor > 0.0f;
    644 }
    645 
    646 nsresult nsPresContext::Init(nsDeviceContext* aDeviceContext) {
    647  NS_ASSERTION(!mInitialized, "attempt to reinit pres context");
    648  NS_ENSURE_ARG(aDeviceContext);
    649 
    650  mDeviceContext = aDeviceContext;
    651 
    652  // In certain rare cases (such as changing page mode), we tear down layout
    653  // state and re-initialize a new prescontext for a document. Given that we
    654  // hang style state off the DOM, we detect that re-initialization case and
    655  // lazily drop the servo data. We don't do this eagerly during layout teardown
    656  // because that would incur an extra whole-tree traversal that's unnecessary
    657  // most of the time.
    658  //
    659  // FIXME(emilio): I'm pretty sure this doesn't happen after bug 1414999.
    660  Element* root = mDocument->GetRootElement();
    661  if (root && root->HasServoData()) {
    662    RestyleManager::ClearServoDataFromSubtree(root);
    663  }
    664 
    665  if (mDeviceContext->SetFullZoom(mFullZoom)) {
    666    FlushFontCache();
    667  }
    668  mCurAppUnitsPerDevPixel = mDeviceContext->AppUnitsPerDevPixel();
    669 
    670  mEventManager = new mozilla::EventStateManager();
    671 
    672  mAnimationEventDispatcher = new mozilla::AnimationEventDispatcher(this);
    673  mEffectCompositor = new mozilla::EffectCompositor(this);
    674  mTransitionManager = MakeUnique<nsTransitionManager>(this);
    675  mAnimationManager = MakeUnique<nsAnimationManager>(this);
    676  mTimelineManager = MakeUnique<mozilla::TimelineManager>(this);
    677 
    678  if (mDocument->GetDisplayDocument()) {
    679    NS_ASSERTION(mDocument->GetDisplayDocument()->GetPresContext(),
    680                 "Why are we being initialized?");
    681    mRefreshDriver =
    682        mDocument->GetDisplayDocument()->GetPresContext()->RefreshDriver();
    683  } else {
    684    dom::Document* parent = mDocument->GetInProcessParentDocument();
    685    // Unfortunately, sometimes |parent| here has no presshell because
    686    // printing screws up things.  Assert that in other cases it does,
    687    // but whenever the shell is null just fall back on using our own
    688    // refresh driver.
    689    NS_ASSERTION(
    690        !parent || mDocument->IsStaticDocument() || parent->GetPresShell(),
    691        "How did we end up with a presshell if our parent doesn't "
    692        "have one?");
    693    if (parent && parent->GetPresContext()) {
    694      // XXX the document can change in AttachPresShell, does this work?
    695      dom::BrowsingContext* browsingContext = mDocument->GetBrowsingContext();
    696      if (browsingContext && !browsingContext->IsTop()) {
    697        Element* containingElement = mDocument->GetEmbedderElement();
    698        if (!containingElement->IsXULElement() ||
    699            !containingElement->HasAttr(nsGkAtoms::forceOwnRefreshDriver)) {
    700          mRefreshDriver = parent->GetPresContext()->RefreshDriver();
    701        }
    702      }
    703    }
    704 
    705    if (!mRefreshDriver) {
    706      mRefreshDriver = new nsRefreshDriver(this);
    707    }
    708  }
    709 
    710  mFragmentainerAwarePositioningEnabled =
    711      StaticPrefs::layout_abspos_fragmentainer_aware_positioning_enabled();
    712 
    713  // Register callbacks so we're notified when the preferences change
    714  Preferences::RegisterPrefixCallbacks(nsPresContext::PreferenceChanged,
    715                                       gPrefixCallbackPrefs, this);
    716  Preferences::RegisterCallbacks(nsPresContext::PreferenceChanged,
    717                                 gExactCallbackPrefs, this);
    718 
    719  nsresult rv = mEventManager->Init();
    720  NS_ENSURE_SUCCESS(rv, rv);
    721 
    722  mEventManager->SetPresContext(this);
    723 
    724 #if defined(MOZ_WIDGET_ANDROID)
    725  if (IsRootContentDocumentCrossProcess()) {
    726    if (BrowserChild* browserChild = BrowserChild::GetFrom(GetDocShell())) {
    727      if (MOZ_LIKELY(!Preferences::HasUserValue(
    728              "layout.dynamic-toolbar-max-height"))) {
    729        mDynamicToolbarMaxHeight = browserChild->GetDynamicToolbarMaxHeight();
    730        mDynamicToolbarHeight = mDynamicToolbarMaxHeight;
    731      }
    732    }
    733  }
    734 #endif
    735 
    736 #ifdef DEBUG
    737  mInitialized = true;
    738 #endif
    739 
    740  return NS_OK;
    741 }
    742 
    743 void nsPresContext::UpdateForcedColors(bool aNotify) {
    744  auto old = mForcedColors;
    745  mForcedColors = [&] {
    746    if (Document()->IsBeingUsedAsImage()) {
    747      return StyleForcedColors::None;
    748    }
    749 
    750    // Handle BrowsingContext override.
    751    if (auto* bc = mDocument->GetBrowsingContext();
    752        bc &&
    753        bc->Top()->ForcedColorsOverride() == ForcedColorsOverride::Active) {
    754      return StyleForcedColors::Active;
    755    }
    756 
    757    const auto& prefs = PrefSheetPrefs();
    758    if (!prefs.mUseDocumentColors) {
    759      return StyleForcedColors::Active;
    760    }
    761    // On Windows, having a high contrast theme also means that the OS is
    762    // requesting the colors to be forced. This is mostly convenience for the
    763    // front-end, which wants to reuse the forced-colors styles for chrome in
    764    // this case as well, and it's a lot more convenient to use
    765    // `(forced-colors)` than `(forced-colors) or ((-moz-platform: windows) and
    766    // (prefers-contrast))`.
    767    //
    768    // TODO(emilio): We might want to factor in here the lwtheme attribute in
    769    // the root element and so on.
    770 #ifdef XP_WIN
    771    if (prefs.mUseAccessibilityTheme && prefs.mIsChrome) {
    772      return StyleForcedColors::Requested;
    773    }
    774 #endif
    775    return StyleForcedColors::None;
    776  }();
    777  if (aNotify && mForcedColors != old) {
    778    MediaFeatureValuesChanged(
    779        MediaFeatureChange::ForPreferredColorSchemeOrForcedColorsChange(),
    780        MediaFeatureChangePropagation::JustThisDocument);
    781  }
    782 }
    783 
    784 bool nsPresContext::ForcingColors() const {
    785  return mForcedColors == StyleForcedColors::Active;
    786 }
    787 
    788 bool nsPresContext::UpdateFontVisibility() {
    789  FontVisibility oldValue = mFontVisibility;
    790  mFontVisibility = ComputeFontVisibility();
    791  return mFontVisibility != oldValue;
    792 }
    793 
    794 void nsPresContext::InitFontCache() {
    795  if (!mFontCache) {
    796    mFontCache = new nsFontCache();
    797    mFontCache->Init(this);
    798  }
    799 }
    800 
    801 void nsPresContext::UpdateFontCacheUserFonts(gfxUserFontSet* aUserFontSet) {
    802  if (mFontCache) {
    803    mFontCache->UpdateUserFonts(aUserFontSet);
    804  }
    805 }
    806 
    807 already_AddRefed<nsFontMetrics> nsPresContext::GetMetricsFor(
    808    const nsFont& aFont, const nsFontMetrics::Params& aParams) {
    809  InitFontCache();
    810  return mFontCache->GetMetricsFor(aFont, aParams);
    811 }
    812 
    813 nsresult nsPresContext::FlushFontCache() {
    814  if (mFontCache) {
    815    mFontCache->Flush();
    816  }
    817  return NS_OK;
    818 }
    819 
    820 nsresult nsPresContext::FontMetricsDeleted(const nsFontMetrics* aFontMetrics) {
    821  if (mFontCache) {
    822    mFontCache->FontMetricsDeleted(aFontMetrics);
    823  }
    824  return NS_OK;
    825 }
    826 
    827 // Note: We don't hold a reference on the shell; it has a reference to
    828 // us
    829 void nsPresContext::AttachPresShell(mozilla::PresShell* aPresShell) {
    830  MOZ_ASSERT(!mPresShell);
    831  mPresShell = aPresShell;
    832 
    833  mRestyleManager = MakeUnique<mozilla::RestyleManager>(this);
    834 
    835  // Since CounterStyleManager is also the name of a method of
    836  // nsPresContext, it is necessary to prefix the class with the mozilla
    837  // namespace here.
    838  mCounterStyleManager = new mozilla::CounterStyleManager(this);
    839 
    840  dom::Document* doc = mPresShell->GetDocument();
    841  MOZ_ASSERT(doc);
    842  // Have to update PresContext's mDocument before calling any other methods.
    843  mDocument = doc;
    844 
    845  LookAndFeel::HandleGlobalThemeChange();
    846 
    847  // Initialize our state from the user preferences, now that we
    848  // have a presshell, and hence a document.
    849  GetUserPreferences();
    850 
    851  EnsureTheme();
    852 
    853  nsIURI* docURI = doc->GetDocumentURI();
    854 
    855  if (IsDynamic() && docURI) {
    856    if (!docURI->SchemeIs("chrome") && !docURI->SchemeIs("resource")) {
    857      mImageAnimationMode = mImageAnimationModePref;
    858    } else {
    859      mImageAnimationMode = imgIContainer::kNormalAnimMode;
    860    }
    861  }
    862 
    863  UpdateCharSet(doc->GetDocumentCharacterSet());
    864 }
    865 
    866 Maybe<ColorScheme> nsPresContext::GetOverriddenOrEmbedderColorScheme() const {
    867  if (Medium() == nsGkAtoms::print) {
    868    return Some(ColorScheme::Light);
    869  }
    870 
    871  switch (mOverriddenOrEmbedderColorScheme) {
    872    case dom::PrefersColorSchemeOverride::Dark:
    873      return Some(ColorScheme::Dark);
    874    case dom::PrefersColorSchemeOverride::Light:
    875      return Some(ColorScheme::Light);
    876    case dom::PrefersColorSchemeOverride::None:
    877      break;
    878  }
    879 
    880  return Nothing();
    881 }
    882 
    883 void nsPresContext::SetColorSchemeOverride(
    884    PrefersColorSchemeOverride aOverride) {
    885  auto oldScheme = mDocument->PreferredColorScheme();
    886 
    887  mOverriddenOrEmbedderColorScheme = aOverride;
    888 
    889  if (mDocument->PreferredColorScheme() != oldScheme) {
    890    MediaFeatureValuesChanged(
    891        MediaFeatureChange::ForPreferredColorSchemeOrForcedColorsChange(),
    892        MediaFeatureChangePropagation::JustThisDocument);
    893  }
    894 }
    895 
    896 void nsPresContext::RecomputeBrowsingContextDependentData() {
    897  MOZ_ASSERT(mDocument);
    898  dom::Document* doc = mDocument;
    899  // Resource documents inherit all this state from their display document.
    900  while (dom::Document* outer = doc->GetDisplayDocument()) {
    901    doc = outer;
    902  }
    903  auto* browsingContext = doc->GetBrowsingContext();
    904  if (!browsingContext) {
    905    // This can legitimately happen for e.g. SVG images. Those just get scaled
    906    // as a result of the zoom on the embedder document so it doesn't really
    907    // matter... Medium also doesn't affect those.
    908    return;
    909  }
    910  if (!IsPrintingOrPrintPreview()) {
    911    auto systemZoom = LookAndFeel::SystemZoomSettings();
    912    SetFullZoom(browsingContext->FullZoom() * systemZoom.mFullZoom);
    913    SetTextZoom(browsingContext->TextZoom() * systemZoom.mTextZoom);
    914    SetOverrideDPPX(browsingContext->OverrideDPPX());
    915  }
    916 
    917  auto* top = browsingContext->Top();
    918  SetColorSchemeOverride([&] {
    919    auto overriden = top->PrefersColorSchemeOverride();
    920    if (browsingContext == top &&
    921        overriden != PrefersColorSchemeOverride::None) {
    922      return overriden;
    923    }
    924    return browsingContext->GetEmbedderColorSchemes().mPreferred;
    925  }());
    926 
    927  UpdateForcedColors();
    928 
    929  SetInRDMPane(top->GetInRDMPane());
    930 
    931  if (doc == mDocument) {
    932    // Medium doesn't apply to resource documents, etc.
    933    RefPtr<nsAtom> mediumToEmulate;
    934    if (MOZ_UNLIKELY(!top->GetMediumOverride().IsEmpty())) {
    935      nsAutoString lower;
    936      nsContentUtils::ASCIIToLower(top->GetMediumOverride(), lower);
    937      mediumToEmulate = NS_Atomize(lower);
    938    }
    939    EmulateMedium(mediumToEmulate);
    940  }
    941 
    942  mDocument->EnumerateExternalResources([](dom::Document& aSubResource) {
    943    if (nsPresContext* subResourcePc = aSubResource.GetPresContext()) {
    944      subResourcePc->RecomputeBrowsingContextDependentData();
    945    }
    946    return CallState::Continue;
    947  });
    948 }
    949 
    950 void nsPresContext::DetachPresShell() {
    951  // The counter style manager's destructor needs to deallocate with the
    952  // presshell arena. Disconnect it before nulling out the shell.
    953  //
    954  // XXXbholley: Given recent refactorings, it probably makes more sense to
    955  // just null our mPresShell at the bottom of this function. I'm leaving it
    956  // this way to preserve the old ordering, but I doubt anything would break.
    957  if (mCounterStyleManager) {
    958    mCounterStyleManager->Disconnect();
    959    mCounterStyleManager = nullptr;
    960  }
    961 
    962  mPresShell = nullptr;
    963 
    964  CancelManagedPostRefreshObservers();
    965 
    966  if (mAnimationEventDispatcher) {
    967    mAnimationEventDispatcher->Disconnect();
    968    mAnimationEventDispatcher = nullptr;
    969  }
    970  if (mEffectCompositor) {
    971    mEffectCompositor->Disconnect();
    972    mEffectCompositor = nullptr;
    973  }
    974  if (mTransitionManager) {
    975    mTransitionManager->Disconnect();
    976    mTransitionManager = nullptr;
    977  }
    978  if (mAnimationManager) {
    979    mAnimationManager->Disconnect();
    980    mAnimationManager = nullptr;
    981  }
    982  if (mTimelineManager) {
    983    mTimelineManager->Disconnect();
    984    mTimelineManager = nullptr;
    985  }
    986  if (mRestyleManager) {
    987    mRestyleManager->Disconnect();
    988    mRestyleManager = nullptr;
    989  }
    990  if (mRefreshDriver && mRefreshDriver->GetPresContext() == this) {
    991    mRefreshDriver->Disconnect();
    992    // Can't null out the refresh driver here.
    993  }
    994 }
    995 
    996 struct QueryContainerState {
    997  nsSize mSize;
    998  WritingMode mWm;
    999  StyleContainerType mType;
   1000 
   1001  nscoord GetInlineSize() const { return LogicalSize(mWm, mSize).ISize(mWm); }
   1002 
   1003  bool Changed(const QueryContainerState& aNewState) {
   1004    if (mType != aNewState.mType) {
   1005      return true;
   1006    }
   1007    if (mType & StyleContainerType::SIZE) {
   1008      return mSize != aNewState.mSize;
   1009    }
   1010    if (mType & StyleContainerType::INLINE_SIZE) {
   1011      return GetInlineSize() != aNewState.GetInlineSize();
   1012    }
   1013    return false;
   1014  }
   1015 };
   1016 NS_DECLARE_FRAME_PROPERTY_DELETABLE(ContainerState, QueryContainerState);
   1017 
   1018 void nsPresContext::RegisterContainerQueryFrame(nsIFrame* aFrame) {
   1019  mContainerQueryFrames.Add(aFrame);
   1020 }
   1021 
   1022 void nsPresContext::UnregisterContainerQueryFrame(nsIFrame* aFrame) {
   1023  mContainerQueryFrames.Remove(aFrame);
   1024 }
   1025 
   1026 void nsPresContext::FinishedContainerQueryUpdate() {
   1027  mUpdatedContainerQueryContents.Clear();
   1028 }
   1029 
   1030 void nsPresContext::UpdateContainerQueryStylesAndAnchorPosLayout() {
   1031  const auto result = PresShell()->UpdateAnchorPosLayout();
   1032  if (mContainerQueryFrames.IsEmpty()) {
   1033    return;
   1034  }
   1035 
   1036  AUTO_PROFILER_LABEL_RELEVANT_FOR_JS("Container Query Styles Update", LAYOUT);
   1037  AUTO_PROFILER_MARKER_UNTYPED("UpdateContainerQueryStyles", LAYOUT, {});
   1038 
   1039  using AnchorPosUpdateResult = PresShell::AnchorPosUpdateResult;
   1040  if (result == AnchorPosUpdateResult::NotApplicable ||
   1041      result == AnchorPosUpdateResult::NeedReflow) {
   1042    PresShell()->DoFlushLayout(/* aInterruptible = */ false);
   1043  }
   1044 
   1045  AutoTArray<nsIFrame*, 8> framesToUpdate;
   1046 
   1047  for (nsIFrame* frame : mContainerQueryFrames.IterFromShallowest()) {
   1048    MOZ_ASSERT(frame->IsPrimaryFrame());
   1049 
   1050    auto type = frame->StyleDisplay()->mContainerType;
   1051    MOZ_ASSERT(type != StyleContainerType::NORMAL,
   1052               "Non-container frames shouldn't be in this set");
   1053 
   1054    const QueryContainerState newState{frame->GetSize(),
   1055                                       frame->GetWritingMode(), type};
   1056    QueryContainerState* oldState = frame->GetProperty(ContainerState());
   1057 
   1058    const bool changed = !oldState || oldState->Changed(newState);
   1059 
   1060    // Make sure to update the state regardless. It's cheap and it keeps tracks
   1061    // of both axes correctly even if only one axis is contained.
   1062    if (oldState) {
   1063      *oldState = newState;
   1064    } else {
   1065      frame->SetProperty(ContainerState(), new QueryContainerState(newState));
   1066    }
   1067 
   1068    if (!changed) {
   1069      continue;
   1070    }
   1071 
   1072    const bool updatingAncestor = [&] {
   1073      for (nsIFrame* f : framesToUpdate) {
   1074        if (nsLayoutUtils::IsProperAncestorFrame(f, frame)) {
   1075          return true;
   1076        }
   1077      }
   1078      return false;
   1079    }();
   1080 
   1081    if (updatingAncestor) {
   1082      // We're going to update an ancestor container of this frame already,
   1083      // avoid updating this one too until all our ancestor containers are
   1084      // updated.
   1085      continue;
   1086    }
   1087 
   1088    // To prevent unstable layout, only update once per-element per-flush.
   1089    if (NS_WARN_IF(!mUpdatedContainerQueryContents.EnsureInserted(
   1090            frame->GetContent()))) {
   1091      continue;
   1092    }
   1093 
   1094    framesToUpdate.AppendElement(frame);
   1095 
   1096    // TODO(emilio): More fine-grained invalidation rather than invalidating the
   1097    // whole subtree, probably!
   1098    RestyleManager()->PostRestyleEvent(frame->GetContent()->AsElement(),
   1099                                       RestyleHint::RestyleSubtree(),
   1100                                       nsChangeHint(0));
   1101  }
   1102 }
   1103 
   1104 void nsPresContext::DocumentCharSetChanged(NotNull<const Encoding*> aCharSet) {
   1105  UpdateCharSet(aCharSet);
   1106  FlushFontCache();
   1107 
   1108  // If a document contains one or more <script> elements, frame construction
   1109  // might happen earlier than the UpdateCharSet(), so we need to restyle
   1110  // descendants to make their style data up-to-date.
   1111  //
   1112  // FIXME(emilio): Revisit whether this is true after bug 1438911.
   1113  RebuildAllStyleData(NS_STYLE_HINT_REFLOW, RestyleHint::RecascadeSubtree());
   1114 }
   1115 
   1116 void nsPresContext::UpdateCharSet(NotNull<const Encoding*> aCharSet) {
   1117  switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
   1118    case IBMBIDI_TEXTTYPE_LOGICAL:
   1119      SetVisualMode(false);
   1120      break;
   1121 
   1122    case IBMBIDI_TEXTTYPE_VISUAL:
   1123      SetVisualMode(true);
   1124      break;
   1125 
   1126    case IBMBIDI_TEXTTYPE_CHARSET:
   1127    default:
   1128      SetVisualMode(IsVisualCharset(aCharSet));
   1129  }
   1130 }
   1131 
   1132 nsPresContext* nsPresContext::GetParentPresContext() const {
   1133  mozilla::PresShell* ps = GetPresShell();
   1134  if (!ps) {
   1135    return nullptr;
   1136  }
   1137  auto* embedder = ps->GetInProcessEmbedderFrame();
   1138  return embedder ? embedder->PresContext() : nullptr;
   1139 }
   1140 
   1141 nsPresContext* nsPresContext::GetInProcessRootContentDocumentPresContext() {
   1142  if (IsChrome()) {
   1143    return nullptr;
   1144  }
   1145  nsPresContext* pc = this;
   1146  for (;;) {
   1147    nsPresContext* parent = pc->GetParentPresContext();
   1148    if (!parent || parent->IsChrome()) {
   1149      return pc;
   1150    }
   1151    pc = parent;
   1152  }
   1153 }
   1154 
   1155 nsIWidget* nsPresContext::GetNearestWidget() const {
   1156  return mPresShell ? mPresShell->GetNearestWidget() : nullptr;
   1157 }
   1158 
   1159 nsIWidget* nsPresContext::GetRootWidget() const {
   1160  return mPresShell ? mPresShell->GetRootWidget() : nullptr;
   1161 }
   1162 
   1163 // We may want to replace this with something faster, maybe caching the root
   1164 // prescontext
   1165 nsRootPresContext* nsPresContext::GetRootPresContext() const {
   1166  nsPresContext* pc = const_cast<nsPresContext*>(this);
   1167  for (;;) {
   1168    nsPresContext* parent = pc->GetParentPresContext();
   1169    if (!parent) {
   1170      break;
   1171    }
   1172    pc = parent;
   1173  }
   1174  return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nullptr;
   1175 }
   1176 
   1177 bool nsPresContext::UserInputEventsAllowed() {
   1178  MOZ_ASSERT(IsRoot());
   1179  if (mUserInputEventsAllowed) {
   1180    return true;
   1181  }
   1182 
   1183  // Special document
   1184  if (Document()->IsEverInitialDocument() || Document()->IsStaticDocument()) {
   1185    return true;
   1186  }
   1187 
   1188  if (mRefreshDriver->IsThrottled()) {
   1189    MOZ_ASSERT(!mPresShell->IsVisible());
   1190    // This implies that the BC is not visibile and users can't
   1191    // interact with it, so we are okay with handling user inputs here.
   1192    return true;
   1193  }
   1194 
   1195  if (mMeasuredTicksSinceLoading <
   1196      StaticPrefs::dom_input_events_security_minNumTicks()) {
   1197    return false;
   1198  }
   1199 
   1200  if (!StaticPrefs::dom_input_events_security_minTimeElapsedInMS()) {
   1201    return true;
   1202  }
   1203 
   1204  dom::Document* doc = Document();
   1205 
   1206  MOZ_ASSERT_IF(StaticPrefs::dom_input_events_security_minNumTicks(),
   1207                doc->GetReadyStateEnum() >= Document::READYSTATE_LOADING);
   1208 
   1209  TimeStamp loadingOrRestoredFromBFCacheTime =
   1210      doc->GetLoadingOrRestoredFromBFCacheTimeStamp();
   1211  MOZ_ASSERT(!loadingOrRestoredFromBFCacheTime.IsNull());
   1212 
   1213  TimeDuration elapsed = TimeStamp::Now() - loadingOrRestoredFromBFCacheTime;
   1214  if (elapsed.ToMilliseconds() >=
   1215      StaticPrefs::dom_input_events_security_minTimeElapsedInMS()) {
   1216    mUserInputEventsAllowed = true;
   1217    return true;
   1218  }
   1219 
   1220  return false;
   1221 }
   1222 
   1223 void nsPresContext::MaybeIncreaseMeasuredTicksSinceLoading() {
   1224  MOZ_ASSERT(IsRoot());
   1225  if (mMeasuredTicksSinceLoading >=
   1226          StaticPrefs::dom_input_events_security_minNumTicks() ||
   1227      Document()->IsStaticDocument()) {
   1228    return;
   1229  }
   1230 
   1231  // We consider READYSTATE_LOADING is the point when the page
   1232  // becomes interactive
   1233  if (Document()->GetReadyStateEnum() >= Document::READYSTATE_LOADING ||
   1234      Document()->IsInitialDocument()) {
   1235    ++mMeasuredTicksSinceLoading;
   1236  }
   1237 
   1238  if (mMeasuredTicksSinceLoading <
   1239      StaticPrefs::dom_input_events_security_minNumTicks()) {
   1240    // Here we are forcing refresh driver to run because we can't always
   1241    // guarantee refresh driver will run enough times to meet the minNumTicks
   1242    // requirement. i.e. about:blank.
   1243    if (!RefreshDriver()->HasPendingTick()) {
   1244      RefreshDriver()->InitializeTimer();
   1245    }
   1246  }
   1247 }
   1248 
   1249 bool nsPresContext::NeedsMoreTicksForUserInput() const {
   1250  MOZ_ASSERT(IsRoot());
   1251  return mMeasuredTicksSinceLoading <
   1252         StaticPrefs::dom_input_events_security_minNumTicks();
   1253 }
   1254 
   1255 // Helper function for setting Anim Mode on image
   1256 static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, uint16_t aMode) {
   1257  if (aImgReq) {
   1258    nsCOMPtr<imgIContainer> imgCon;
   1259    aImgReq->GetImage(getter_AddRefs(imgCon));
   1260    if (imgCon) {
   1261      imgCon->SetAnimationMode(aMode);
   1262    }
   1263  }
   1264 }
   1265 
   1266 // IMPORTANT: Assumption is that all images for a Presentation
   1267 // have the same Animation Mode (pavlov said this was OK)
   1268 //
   1269 // Walks content and set the animation mode
   1270 // this is a way to turn on/off image animations
   1271 void nsPresContext::SetImgAnimations(nsIContent* aParent, uint16_t aMode) {
   1272  nsCOMPtr<nsIImageLoadingContent> imgContent(do_QueryInterface(aParent));
   1273  if (imgContent) {
   1274    nsCOMPtr<imgIRequest> imgReq;
   1275    imgContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
   1276                           getter_AddRefs(imgReq));
   1277    SetImgAnimModeOnImgReq(imgReq, aMode);
   1278  }
   1279 
   1280  for (nsIContent* childContent = aParent->GetFirstChild(); childContent;
   1281       childContent = childContent->GetNextSibling()) {
   1282    SetImgAnimations(childContent, aMode);
   1283  }
   1284 }
   1285 
   1286 void nsPresContext::SetSMILAnimations(dom::Document* aDoc, uint16_t aNewMode,
   1287                                      uint16_t aOldMode) {
   1288  if (aDoc->HasAnimationController()) {
   1289    SMILAnimationController* controller = aDoc->GetAnimationController();
   1290    switch (aNewMode) {
   1291      case imgIContainer::kNormalAnimMode:
   1292      case imgIContainer::kLoopOnceAnimMode:
   1293        if (aOldMode == imgIContainer::kDontAnimMode) {
   1294          controller->Resume(SMILTimeContainer::PAUSE_USERPREF);
   1295        }
   1296        break;
   1297 
   1298      case imgIContainer::kDontAnimMode:
   1299        if (aOldMode != imgIContainer::kDontAnimMode) {
   1300          controller->Pause(SMILTimeContainer::PAUSE_USERPREF);
   1301        }
   1302        break;
   1303    }
   1304  }
   1305 }
   1306 
   1307 void nsPresContext::SetImageAnimationMode(uint16_t aMode) {
   1308  NS_ASSERTION(aMode == imgIContainer::kNormalAnimMode ||
   1309                   aMode == imgIContainer::kDontAnimMode ||
   1310                   aMode == imgIContainer::kLoopOnceAnimMode,
   1311               "Wrong Animation Mode is being set!");
   1312 
   1313  // Image animation mode cannot be changed when rendering to a printer.
   1314  if (!IsDynamic()) {
   1315    return;
   1316  }
   1317 
   1318  // Now walk the content tree and set the animation mode
   1319  // on all the images.
   1320  if (mPresShell) {
   1321    dom::Document* doc = mPresShell->GetDocument();
   1322    if (doc) {
   1323      doc->EnsureStyleImageLoader().SetAnimationMode(aMode);
   1324 
   1325      Element* rootElement = doc->GetRootElement();
   1326      if (rootElement) {
   1327        SetImgAnimations(rootElement, aMode);
   1328      }
   1329      SetSMILAnimations(doc, aMode, mImageAnimationMode);
   1330    }
   1331  }
   1332 
   1333  mImageAnimationMode = aMode;
   1334 }
   1335 
   1336 void nsPresContext::SetTextZoom(float aTextZoom) {
   1337  float newZoom = aTextZoom;
   1338  float minZoom = StaticPrefs::zoom_minPercent() / 100.0f;
   1339  float maxZoom = StaticPrefs::zoom_maxPercent() / 100.0f;
   1340 
   1341  if (newZoom < minZoom) {
   1342    newZoom = minZoom;
   1343  } else if (newZoom > maxZoom) {
   1344    newZoom = maxZoom;
   1345  }
   1346 
   1347  if (newZoom == mTextZoom) {
   1348    return;
   1349  }
   1350 
   1351  mTextZoom = newZoom;
   1352 
   1353  // Media queries could have changed, since we changed the meaning
   1354  // of 'em' units in them.
   1355  MediaFeatureValuesChanged(
   1356      {RestyleHint::RecascadeSubtree(), NS_STYLE_HINT_REFLOW,
   1357       MediaFeatureChangeReason::ZoomChange},
   1358      MediaFeatureChangePropagation::JustThisDocument);
   1359 }
   1360 
   1361 void nsPresContext::SetInRDMPane(bool aInRDMPane) {
   1362  if (mInRDMPane == aInRDMPane) {
   1363    return;
   1364  }
   1365  mInRDMPane = aInRDMPane;
   1366  RecomputeTheme();
   1367  if (mPresShell) {
   1368    nsContentUtils::AddScriptRunner(NewRunnableMethod<bool>(
   1369        "PresShell::MaybeRecreateMobileViewportManager", mPresShell,
   1370        &PresShell::MaybeRecreateMobileViewportManager, true));
   1371  }
   1372 }
   1373 
   1374 float nsPresContext::GetDeviceFullZoom() {
   1375  return mDeviceContext->GetFullZoom();
   1376 }
   1377 
   1378 void nsPresContext::SetFullZoom(float aZoom) {
   1379  if (!mPresShell) {
   1380    return;
   1381  }
   1382 
   1383  // Sanitize aZoom to check for bogus values. (Outer iframes with small or
   1384  // huge css 'zoom' can end up stacking to propagate an extremely small/huge
   1385  // full-zoom value to inner iframes, possibly reaching 0 or infinity. We
   1386  // handle that edge case by just falling back to 1.0f here, so we can render
   1387  // something, and particularly so we don't do something invalid like trying
   1388  // to allocate a zero-sized or infinite-sized surface.)
   1389  if (MOZ_UNLIKELY(!std::isfinite(aZoom) || aZoom < 1e-6f)) {
   1390    aZoom = 1.0f;
   1391  }
   1392 
   1393  if (mFullZoom == aZoom) {
   1394    return;
   1395  }
   1396 
   1397  // Use the maybe-pending size from presshell in case there's a
   1398  // deferred resize which hasn't affected our visible area yet.
   1399  RefPtr ps = mPresShell;
   1400  const auto oldSizeDevPixels = LayoutDeviceSize::FromAppUnits(
   1401      ps->MaybePendingLayoutViewportSize(), mCurAppUnitsPerDevPixel);
   1402  mDeviceContext->SetFullZoom(aZoom);
   1403 
   1404  mFullZoom = aZoom;
   1405 
   1406  AppUnitsPerDevPixelChanged();
   1407 
   1408  ps->SetLayoutViewportSize(
   1409      LayoutDeviceSize::ToAppUnits(oldSizeDevPixels, AppUnitsPerDevPixel()),
   1410      /* aDelay = */ false);
   1411 }
   1412 
   1413 void nsPresContext::SetOverrideDPPX(float aDPPX) {
   1414  // SetOverrideDPPX is called during navigations, including history
   1415  // traversals.  In that case, it's typically called with our current value,
   1416  // and we don't need to actually do anything.
   1417  if (aDPPX == GetOverrideDPPX()) {
   1418    return;
   1419  }
   1420 
   1421  mMediaEmulationData.mDPPX = aDPPX;
   1422  MediaFeatureValuesChanged({MediaFeatureChangeReason::ResolutionChange},
   1423                            MediaFeatureChangePropagation::JustThisDocument);
   1424 }
   1425 
   1426 void nsPresContext::UpdateTopInnerSizeForRFP() {
   1427  if (!mDocument->ShouldResistFingerprinting(RFPTarget::WindowOuterSize) ||
   1428      !mDocument->GetBrowsingContext() ||
   1429      !mDocument->GetBrowsingContext()->IsTop()) {
   1430    return;
   1431  }
   1432 
   1433  CSSSize size = CSSPixel::FromAppUnits(GetVisibleArea().Size());
   1434 
   1435  switch (StaticPrefs::dom_innerSize_rounding()) {
   1436    case 1:
   1437      size.width = std::roundf(size.width);
   1438      size.height = std::roundf(size.height);
   1439      break;
   1440    case 2:
   1441      size.width = std::truncf(size.width);
   1442      size.height = std::truncf(size.height);
   1443      break;
   1444    default:
   1445      break;
   1446  }
   1447 
   1448  (void)mDocument->GetBrowsingContext()->SetTopInnerSizeForRFP(
   1449      CSSIntSize{(int)size.width, (int)size.height});
   1450 }
   1451 
   1452 gfxSize nsPresContext::ScreenSizeInchesForFontInflation(bool* aChanged) {
   1453  if (aChanged) {
   1454    *aChanged = false;
   1455  }
   1456 
   1457  nsDeviceContext* dx = DeviceContext();
   1458  float unitsPerInch = dx->AppUnitsPerPhysicalInch();
   1459  nsRect clientRect = dx->GetClientRect();
   1460  gfxSize deviceSizeInches(float(clientRect.width) / unitsPerInch,
   1461                           float(clientRect.height) / unitsPerInch);
   1462 
   1463  if (mLastFontInflationScreenSize == gfxSize(-1.0, -1.0)) {
   1464    mLastFontInflationScreenSize = deviceSizeInches;
   1465  }
   1466 
   1467  if (deviceSizeInches != mLastFontInflationScreenSize && aChanged) {
   1468    *aChanged = true;
   1469    mLastFontInflationScreenSize = deviceSizeInches;
   1470  }
   1471 
   1472  return deviceSizeInches;
   1473 }
   1474 
   1475 static bool CheckOverflow(const ComputedStyle* aComputedStyle,
   1476                          ScrollStyles* aStyles) {
   1477  // If they're not styled yet, we'll get around to it when constructing frames
   1478  // for the element.
   1479  if (!aComputedStyle) {
   1480    return false;
   1481  }
   1482  const nsStyleDisplay* display = aComputedStyle->StyleDisplay();
   1483 
   1484  // If they will generate no box, just don't.
   1485  if (display->mDisplay == StyleDisplay::None ||
   1486      display->mDisplay == StyleDisplay::Contents) {
   1487    return false;
   1488  }
   1489 
   1490  // NOTE(emilio): This check needs to match the one in
   1491  // Document::IsPotentiallyScrollable.
   1492  if (display->OverflowIsVisibleInBothAxis()) {
   1493    return false;
   1494  }
   1495 
   1496  *aStyles =
   1497      ScrollStyles(*display, ScrollStyles::MapOverflowToValidScrollStyle);
   1498  return true;
   1499 }
   1500 
   1501 // https://drafts.csswg.org/css-overflow/#overflow-propagation
   1502 //
   1503 // NOTE(emilio): We may need to use out-of-date styles for this, since this is
   1504 // called from nsCSSFrameConstructor::ContentRemoved. We could refactor this a
   1505 // bit to avoid doing that, and also fix correctness issues (we don't invalidate
   1506 // properly when we insert a body element and there is a previous one, for
   1507 // example).
   1508 static Element* GetPropagatedScrollStylesForViewport(
   1509    nsPresContext* aPresContext, const Element* aRemovedChild,
   1510    ScrollStyles* aStyles) {
   1511  Document* document = aPresContext->Document();
   1512  Element* docElement = document->GetRootElement();
   1513  // docElement might be null if we're doing this after removing it.
   1514  if (!docElement || docElement == aRemovedChild) {
   1515    return nullptr;
   1516  }
   1517 
   1518  // Check the style on the document root element
   1519  const auto* rootStyle = Servo_Element_GetMaybeOutOfDateStyle(docElement);
   1520  if (CheckOverflow(rootStyle, aStyles)) {
   1521    // tell caller we stole the overflow style from the root element
   1522    return docElement;
   1523  }
   1524 
   1525  if (rootStyle && rootStyle->StyleDisplay()->IsContainAny()) {
   1526    return nullptr;
   1527  }
   1528 
   1529  // Don't look in the BODY for non-HTML documents or HTML documents
   1530  // with non-HTML roots.
   1531  // XXX this should be earlier; we shouldn't even look at the document root
   1532  // for non-HTML documents. Fix this once we support explicit CSS styling
   1533  // of the viewport
   1534  if (!document->IsHTMLOrXHTML() ||
   1535      !docElement->IsHTMLElement(nsGkAtoms::html)) {
   1536    return nullptr;
   1537  }
   1538 
   1539  Element* bodyElement = document->GetBodyElement(aRemovedChild);
   1540  if (!bodyElement) {
   1541    return nullptr;
   1542  }
   1543 
   1544  const auto* bodyStyle = Servo_Element_GetMaybeOutOfDateStyle(bodyElement);
   1545  if (bodyStyle && bodyStyle->StyleDisplay()->IsContainAny()) {
   1546    return nullptr;
   1547  }
   1548 
   1549  if (CheckOverflow(bodyStyle, aStyles)) {
   1550    // tell caller we stole the overflow style from the body element
   1551    return bodyElement;
   1552  }
   1553 
   1554  return nullptr;
   1555 }
   1556 
   1557 Element* nsPresContext::UpdateViewportScrollStylesOverride(
   1558    const Element* aRemovedChild) {
   1559  ScrollStyles oldViewportScrollStyles = mViewportScrollStyles;
   1560 
   1561  // Start off with our default styles, and then update them as needed.
   1562  mViewportScrollStyles =
   1563      ScrollStyles(StyleOverflow::Auto, StyleOverflow::Auto);
   1564  mViewportScrollOverrideElement = nullptr;
   1565  // Don't propagate the scrollbar state in printing or print preview.
   1566  if (!IsPaginated()) {
   1567    mViewportScrollOverrideElement = GetPropagatedScrollStylesForViewport(
   1568        this, aRemovedChild, &mViewportScrollStyles);
   1569  }
   1570 
   1571  dom::Document* document = Document();
   1572  if (Element* fsElement = document->GetUnretargetedFullscreenElement()) {
   1573    // If the document is in fullscreen, but the fullscreen element is
   1574    // not the root element, we should explicitly suppress the scrollbar
   1575    // here. Note that, we still need to return the original element
   1576    // the styles are from, so that the state of those elements is not
   1577    // affected across fullscreen change.
   1578    if (fsElement != document->GetRootElement() &&
   1579        fsElement != mViewportScrollOverrideElement) {
   1580      mViewportScrollStyles =
   1581          ScrollStyles(StyleOverflow::Hidden, StyleOverflow::Hidden);
   1582    }
   1583  }
   1584 
   1585  if (mViewportScrollStyles != oldViewportScrollStyles) {
   1586    if (mPresShell) {
   1587      if (nsIFrame* frame = mPresShell->GetRootFrame()) {
   1588        frame->SchedulePaint();
   1589      }
   1590    }
   1591  }
   1592 
   1593  return mViewportScrollOverrideElement;
   1594 }
   1595 
   1596 bool nsPresContext::ElementWouldPropagateScrollStyles(const Element& aElement) {
   1597  if (aElement.GetParent() && !aElement.IsHTMLElement(nsGkAtoms::body)) {
   1598    // We certainly won't be propagating from this element.
   1599    return false;
   1600  }
   1601 
   1602  // Go ahead and just call GetPropagatedScrollStylesForViewport, but update
   1603  // a dummy ScrollStyles we don't care about.  It'll do a bit of extra work,
   1604  // but saves us having to have more complicated code or more code duplication;
   1605  // in practice we will make this call quite rarely, because we checked for all
   1606  // the common cases above.
   1607  ScrollStyles dummy(StyleOverflow::Auto, StyleOverflow::Auto);
   1608  return GetPropagatedScrollStylesForViewport(this, nullptr, &dummy) ==
   1609         &aElement;
   1610 }
   1611 
   1612 nsISupports* nsPresContext::GetContainerWeak() const {
   1613  return mDocument->GetDocShell();
   1614 }
   1615 
   1616 ColorScheme nsPresContext::DefaultBackgroundColorScheme() const {
   1617  dom::Document* doc = Document();
   1618  // Use a dark background for top-level about:blank that is inaccessible to
   1619  // content JS.
   1620  if (doc->IsLikelyContentInaccessibleTopLevelAboutBlank()) {
   1621    return doc->PreferredColorScheme(Document::IgnoreRFP::Yes);
   1622  }
   1623  // Prefer the root color-scheme (since generally the default canvas
   1624  // background comes from the root element's background-color), and fall back
   1625  // to the default color-scheme if not available.
   1626  if (auto* frame = FrameConstructor()->GetRootElementStyleFrame()) {
   1627    return LookAndFeel::ColorSchemeForFrame(frame);
   1628  }
   1629  return doc->DefaultColorScheme();
   1630 }
   1631 
   1632 nscolor nsPresContext::DefaultBackgroundColor() const {
   1633  if (!GetBackgroundColorDraw()) {
   1634    return NS_RGB(255, 255, 255);
   1635  }
   1636  return PrefSheetPrefs()
   1637      .ColorsFor(DefaultBackgroundColorScheme())
   1638      .mDefaultBackground;
   1639 }
   1640 
   1641 nsDocShell* nsPresContext::GetDocShell() const {
   1642  return nsDocShell::Cast(mDocument->GetDocShell());
   1643 }
   1644 
   1645 bool nsPresContext::BidiEnabled() const { return Document()->GetBidiEnabled(); }
   1646 
   1647 void nsPresContext::SetBidiEnabled() const { Document()->SetBidiEnabled(); }
   1648 
   1649 void nsPresContext::SetBidi(uint32_t aSource) {
   1650  // Don't do all this stuff unless the options have changed.
   1651  if (aSource == GetBidi()) {
   1652    return;
   1653  }
   1654 
   1655  Document()->SetBidiOptions(aSource);
   1656  if (IBMBIDI_TEXTDIRECTION_RTL == GET_BIDI_OPTION_DIRECTION(aSource) ||
   1657      IBMBIDI_NUMERAL_HINDI == GET_BIDI_OPTION_NUMERAL(aSource)) {
   1658    SetBidiEnabled();
   1659  }
   1660  if (IBMBIDI_TEXTTYPE_VISUAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
   1661    SetVisualMode(true);
   1662  } else if (IBMBIDI_TEXTTYPE_LOGICAL == GET_BIDI_OPTION_TEXTTYPE(aSource)) {
   1663    SetVisualMode(false);
   1664  } else {
   1665    SetVisualMode(IsVisualCharset(Document()->GetDocumentCharacterSet()));
   1666  }
   1667 }
   1668 
   1669 uint32_t nsPresContext::GetBidi() const { return Document()->GetBidiOptions(); }
   1670 
   1671 void nsPresContext::RecordInteractionTime(InteractionType aType,
   1672                                          const TimeStamp& aTimeStamp) {
   1673  if (!mInteractionTimeEnabled || aTimeStamp.IsNull()) {
   1674    return;
   1675  }
   1676 
   1677  // Array of references to the member variable of each time stamp
   1678  // for the different interaction types, keyed by InteractionType.
   1679  TimeStamp nsPresContext::* interactionTimes[] = {
   1680      &nsPresContext::mFirstClickTime, &nsPresContext::mFirstKeyTime,
   1681      &nsPresContext::mFirstMouseMoveTime, &nsPresContext::mFirstScrollTime};
   1682 
   1683  TimeStamp& interactionTime =
   1684      this->*(interactionTimes[static_cast<uint32_t>(aType)]);
   1685  if (!interactionTime.IsNull()) {
   1686    // We have already recorded an interaction time.
   1687    return;
   1688  }
   1689 
   1690  // Record the interaction time if it occurs after the first paint
   1691  // of the top level content document.
   1692  nsPresContext* inProcessRootPresContext =
   1693      GetInProcessRootContentDocumentPresContext();
   1694 
   1695  if (!inProcessRootPresContext ||
   1696      !inProcessRootPresContext->IsRootContentDocumentCrossProcess()) {
   1697    // There is no top content pres context, or we are in a cross process
   1698    // document so we don't care about the interaction time. Record a value
   1699    // anyways to avoid trying to find the top content pres context in future
   1700    // interactions.
   1701    interactionTime = TimeStamp::Now();
   1702    return;
   1703  }
   1704 
   1705  if (inProcessRootPresContext->mFirstNonBlankPaintTime.IsNull() ||
   1706      inProcessRootPresContext->mFirstNonBlankPaintTime > aTimeStamp) {
   1707    // Top content pres context has not had a non-blank paint yet
   1708    // or the event timestamp is before the first non-blank paint,
   1709    // so don't record interaction time.
   1710    return;
   1711  }
   1712 
   1713  // Check if we are recording the first of any of the interaction types.
   1714  bool isFirstInteraction = true;
   1715  for (TimeStamp nsPresContext::* memberPtr : interactionTimes) {
   1716    TimeStamp& timeStamp = this->*(memberPtr);
   1717    if (!timeStamp.IsNull()) {
   1718      isFirstInteraction = false;
   1719      break;
   1720    }
   1721  }
   1722 
   1723  interactionTime = TimeStamp::Now();
   1724  // Only the top level content pres context reports first interaction
   1725  // time to telemetry (if it hasn't already done so).
   1726  if (this == inProcessRootPresContext) {
   1727    if (Telemetry::CanRecordExtended() && isFirstInteraction) {
   1728      glean::layout::time_to_first_interaction.AccumulateRawDuration(
   1729          interactionTime - mFirstNonBlankPaintTime);
   1730    }
   1731  } else {
   1732    inProcessRootPresContext->RecordInteractionTime(aType, aTimeStamp);
   1733  }
   1734 }
   1735 
   1736 nsITheme* nsPresContext::Theme() const {
   1737  MOZ_ASSERT(mTheme);
   1738  return mTheme;
   1739 }
   1740 
   1741 void nsPresContext::EnsureTheme() {
   1742  MOZ_ASSERT(!mTheme);
   1743  if (Document()->ShouldAvoidNativeTheme()) {
   1744    if (mInRDMPane) {
   1745      mTheme = do_GetRDMThemeDoNotUseDirectly();
   1746    } else {
   1747      mTheme = do_GetBasicNativeThemeDoNotUseDirectly();
   1748    }
   1749  } else {
   1750    mTheme = do_GetNativeThemeDoNotUseDirectly();
   1751  }
   1752  MOZ_RELEASE_ASSERT(mTheme);
   1753 }
   1754 
   1755 void nsPresContext::RecomputeTheme() {
   1756  if (!mTheme) {
   1757    return;
   1758  }
   1759  nsCOMPtr<nsITheme> oldTheme = std::move(mTheme);
   1760  EnsureTheme();
   1761  if (oldTheme == mTheme) {
   1762    return;
   1763  }
   1764  // Theme affects layout information (as it affects whether we create
   1765  // scrollbar buttons for example) and also style (affects the
   1766  // scrollbar-inline-size env var).
   1767  RebuildAllStyleData(nsChangeHint_ReconstructFrame,
   1768                      RestyleHint::RecascadeSubtree());
   1769  // This is a bit of a lie, but this affects the overlay-scrollbars
   1770  // media query and it's the code-path that gets taken for regular system
   1771  // metrics changes via ThemeChanged().
   1772  MediaFeatureValuesChanged({MediaFeatureChangeReason::SystemMetricsChange},
   1773                            MediaFeatureChangePropagation::JustThisDocument);
   1774 }
   1775 
   1776 bool nsPresContext::UseOverlayScrollbars() const {
   1777  return LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars) ||
   1778         mInRDMPane;
   1779 }
   1780 
   1781 void nsPresContext::ThemeChanged(widget::ThemeChangeKind aKind) {
   1782  PROFILER_MARKER_UNTYPED("ThemeChanged", LAYOUT, MarkerStack::Capture());
   1783 
   1784  mPendingThemeChangeKind |= unsigned(aKind);
   1785 
   1786  if (!mPendingThemeChanged) {
   1787    nsCOMPtr<nsIRunnable> ev =
   1788        new WeakRunnableMethod("nsPresContext::ThemeChangedInternal", this,
   1789                               &nsPresContext::ThemeChangedInternal);
   1790    RefreshDriver()->AddEarlyRunner(ev);
   1791    mPendingThemeChanged = true;
   1792  }
   1793  MOZ_ASSERT(LookAndFeel::HasPendingGlobalThemeChange());
   1794 }
   1795 
   1796 void nsPresContext::ThemeChangedInternal() {
   1797  MOZ_ASSERT(mPendingThemeChanged);
   1798 
   1799  mPendingThemeChanged = false;
   1800 
   1801  const auto kind = widget::ThemeChangeKind(mPendingThemeChangeKind);
   1802  mPendingThemeChangeKind = 0;
   1803 
   1804  LookAndFeel::HandleGlobalThemeChange();
   1805 
   1806  // Full zoom might have changed as a result of the text scale factor.
   1807  // Forced colors might also have changed.
   1808  RecomputeBrowsingContextDependentData();
   1809 
   1810  // Changes to system metrics and other look and feel values can change media
   1811  // queries on them.
   1812  //
   1813  // Changes in theme can change system colors (whose changes are properly
   1814  // reflected in computed style data), system fonts (whose changes are
   1815  // some reflected (like sizes and such) and some not), and -moz-appearance
   1816  // (whose changes are not), so we need to recascade for the first, and reflow
   1817  // for the rest.
   1818  auto restyleHint = (kind & widget::ThemeChangeKind::Style)
   1819                         ? RestyleHint::RecascadeSubtree()
   1820                         : RestyleHint{0};
   1821  auto changeHint = (kind & widget::ThemeChangeKind::Layout)
   1822                        ? NS_STYLE_HINT_REFLOW
   1823                        : nsChangeHint(0);
   1824  MediaFeatureValuesChanged(
   1825      {restyleHint, changeHint, MediaFeatureChangeReason::SystemMetricsChange},
   1826      MediaFeatureChangePropagation::All);
   1827 
   1828  if (Document()->IsInChromeDocShell()) {
   1829    if (RefPtr<nsPIDOMWindowInner> win = Document()->GetInnerWindow()) {
   1830      nsContentUtils::DispatchEventOnlyToChrome(
   1831          Document(), nsGlobalWindowInner::Cast(win), u"nativethemechange"_ns,
   1832          CanBubble::eYes, Cancelable::eYes, nullptr);
   1833    }
   1834  }
   1835 }
   1836 
   1837 void nsPresContext::UIResolutionChanged() {
   1838  if (!mPendingUIResolutionChanged) {
   1839    nsCOMPtr<nsIRunnable> ev =
   1840        NewRunnableMethod("nsPresContext::UIResolutionChangedInternal", this,
   1841                          &nsPresContext::UIResolutionChangedInternal);
   1842    nsresult rv = Document()->Dispatch(ev.forget());
   1843    if (NS_SUCCEEDED(rv)) {
   1844      mPendingUIResolutionChanged = true;
   1845    }
   1846  }
   1847 }
   1848 
   1849 void nsPresContext::UIResolutionChangedSync() {
   1850  if (!mPendingUIResolutionChanged) {
   1851    mPendingUIResolutionChanged = true;
   1852    UIResolutionChangedInternal();
   1853  }
   1854 }
   1855 
   1856 static void NotifyTabUIResolutionChanged(nsIRemoteTab* aTab, void* aArg) {
   1857  aTab->NotifyResolutionChanged();
   1858 }
   1859 
   1860 static void NotifyChildrenUIResolutionChanged(nsPIDOMWindowOuter* aWindow) {
   1861  nsCOMPtr<Document> doc = aWindow->GetExtantDoc();
   1862  RefPtr<nsPIWindowRoot> topLevelWin = nsContentUtils::GetWindowRoot(doc);
   1863  if (!topLevelWin) {
   1864    return;
   1865  }
   1866  topLevelWin->EnumerateBrowsers(NotifyTabUIResolutionChanged, nullptr);
   1867 }
   1868 
   1869 void nsPresContext::UIResolutionChangedInternal() {
   1870  mPendingUIResolutionChanged = false;
   1871 
   1872  mDeviceContext->CheckDPIChange();
   1873  if (mCurAppUnitsPerDevPixel != mDeviceContext->AppUnitsPerDevPixel()) {
   1874    AppUnitsPerDevPixelChanged();
   1875  }
   1876 
   1877  if (mPresShell) {
   1878    mPresShell->RefreshZoomConstraintsForScreenSizeChange();
   1879    if (RefPtr<MobileViewportManager> mvm =
   1880            mPresShell->GetMobileViewportManager()) {
   1881      mvm->UpdateSizesBeforeReflow();
   1882    }
   1883  }
   1884 
   1885  // Recursively notify all remote leaf descendants of the change.
   1886  if (nsPIDOMWindowOuter* window = mDocument->GetWindow()) {
   1887    NotifyChildrenUIResolutionChanged(window);
   1888  }
   1889 
   1890  mDocument->EnumerateSubDocuments([](dom::Document& aSubDoc) {
   1891    if (nsPresContext* pc = aSubDoc.GetPresContext()) {
   1892      pc->UIResolutionChangedInternal();
   1893    }
   1894    return CallState::Continue;
   1895  });
   1896 }
   1897 
   1898 void nsPresContext::EmulateMedium(nsAtom* aMediaType) {
   1899  MOZ_ASSERT(!aMediaType || aMediaType->IsAsciiLowercase());
   1900 
   1901  RefPtr<const nsAtom> oldMedium = Medium();
   1902  auto oldScheme = mDocument->PreferredColorScheme();
   1903 
   1904  mMediaEmulationData.mMedium = aMediaType;
   1905 
   1906  if (Medium() == oldMedium) {
   1907    return;
   1908  }
   1909 
   1910  MediaFeatureChange change(MediaFeatureChangeReason::MediumChange);
   1911  if (oldScheme != mDocument->PreferredColorScheme()) {
   1912    change |= MediaFeatureChange::ForPreferredColorSchemeOrForcedColorsChange();
   1913  }
   1914  MediaFeatureValuesChanged(change,
   1915                            MediaFeatureChangePropagation::JustThisDocument);
   1916 }
   1917 
   1918 void nsPresContext::ContentLanguageChanged() {
   1919  PostRebuildAllStyleDataEvent(nsChangeHint(0),
   1920                               RestyleHint::RecascadeSubtree());
   1921 }
   1922 
   1923 void nsPresContext::RegisterManagedPostRefreshObserver(
   1924    ManagedPostRefreshObserver* aObserver) {
   1925  if (MOZ_UNLIKELY(!mPresShell)) {
   1926    // If we're detached from our pres shell already, refuse to keep observer
   1927    // around, as that'd create a cycle.
   1928    RefPtr<ManagedPostRefreshObserver> obs = aObserver;
   1929    obs->Cancel();
   1930    return;
   1931  }
   1932 
   1933  RefreshDriver()->AddPostRefreshObserver(
   1934      static_cast<nsAPostRefreshObserver*>(aObserver));
   1935  mManagedPostRefreshObservers.AppendElement(aObserver);
   1936 }
   1937 
   1938 void nsPresContext::UnregisterManagedPostRefreshObserver(
   1939    ManagedPostRefreshObserver* aObserver) {
   1940  RefreshDriver()->RemovePostRefreshObserver(
   1941      static_cast<nsAPostRefreshObserver*>(aObserver));
   1942  DebugOnly<bool> removed =
   1943      mManagedPostRefreshObservers.RemoveElement(aObserver);
   1944  MOZ_ASSERT(removed,
   1945             "ManagedPostRefreshObserver should be owned by PresContext");
   1946 }
   1947 
   1948 void nsPresContext::CancelManagedPostRefreshObservers() {
   1949  auto observers = std::move(mManagedPostRefreshObservers);
   1950  nsRefreshDriver* driver = RefreshDriver();
   1951  for (const auto& observer : observers) {
   1952    observer->Cancel();
   1953    driver->RemovePostRefreshObserver(
   1954        static_cast<nsAPostRefreshObserver*>(observer));
   1955  }
   1956 }
   1957 
   1958 void nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint,
   1959                                        const RestyleHint& aRestyleHint) {
   1960  if (!mPresShell) {
   1961    // We must have been torn down. Nothing to do here.
   1962    return;
   1963  }
   1964 
   1965  // TODO(emilio): It's unclear to me why would these three calls below be
   1966  // needed. In particular, RebuildAllStyleData doesn't rebuild rules or
   1967  // specified style information and such (note the comment in
   1968  // RestyleManager::RebuildAllStyleData re. the funny semantics), so I
   1969  // don't know why should we rebuild the user font set / counter styles /
   1970  // etc...
   1971  mDocument->MarkUserFontSetDirty();
   1972  MarkCounterStylesDirty();
   1973  MarkFontFeatureValuesDirty();
   1974  MarkFontPaletteValuesDirty();
   1975  PostRebuildAllStyleDataEvent(aExtraHint, aRestyleHint);
   1976 }
   1977 
   1978 void nsPresContext::PostRebuildAllStyleDataEvent(
   1979    nsChangeHint aExtraHint, const RestyleHint& aRestyleHint) {
   1980  if (!mPresShell) {
   1981    // We must have been torn down. Nothing to do here.
   1982    return;
   1983  }
   1984  RestyleManager()->RebuildAllStyleData(aExtraHint, aRestyleHint);
   1985 }
   1986 
   1987 void nsPresContext::MediaFeatureValuesChanged(
   1988    const MediaFeatureChange& aChange,
   1989    MediaFeatureChangePropagation aPropagation) {
   1990  if (mPresShell) {
   1991    mPresShell->EnsureStyleFlush();
   1992  }
   1993 
   1994  if (!mDocument->MediaQueryLists().isEmpty()) {
   1995    RefreshDriver()->ScheduleMediaQueryListenerUpdate();
   1996  }
   1997 
   1998  if (!mPendingMediaFeatureValuesChange) {
   1999    mPendingMediaFeatureValuesChange = MakeUnique<MediaFeatureChange>(aChange);
   2000  } else {
   2001    *mPendingMediaFeatureValuesChange |= aChange;
   2002  }
   2003 
   2004  if (aPropagation & MediaFeatureChangePropagation::Images) {
   2005    // Propagate the media feature value change down to any SVG images the
   2006    // document is using.
   2007    mDocument->PropagateMediaFeatureChangeToTrackedImages(aChange);
   2008  }
   2009 
   2010  if (aPropagation & MediaFeatureChangePropagation::SubDocuments) {
   2011    // And then into any subdocuments.
   2012    mDocument->EnumerateSubDocuments(
   2013        [&aChange, aPropagation](dom::Document& aSubDoc) {
   2014          if (nsPresContext* pc = aSubDoc.GetPresContext()) {
   2015            pc->MediaFeatureValuesChanged(aChange, aPropagation);
   2016          }
   2017          return CallState::Continue;
   2018        });
   2019  }
   2020 
   2021  // We notify the media feature values changed for the responsive content of
   2022  // HTMLImageElements synchronously, so their image sources are always
   2023  // up-to-date when running the image load tasks in the microtasks.
   2024  mDocument->NotifyMediaFeatureValuesChanged();
   2025 }
   2026 
   2027 bool nsPresContext::FlushPendingMediaFeatureValuesChanged() {
   2028  if (!mPendingMediaFeatureValuesChange) {
   2029    return false;
   2030  }
   2031 
   2032  MediaFeatureChange change = *mPendingMediaFeatureValuesChange;
   2033  mPendingMediaFeatureValuesChange.reset();
   2034 
   2035  // MediumFeaturesChanged updates the applied rules, so it always gets called.
   2036  if (mPresShell) {
   2037    change.mRestyleHint |=
   2038        mPresShell->StyleSet()->MediumFeaturesChanged(change.mReason);
   2039  }
   2040 
   2041  const bool changedStyle = change.mRestyleHint || change.mChangeHint;
   2042  if (changedStyle) {
   2043    RebuildAllStyleData(change.mChangeHint, change.mRestyleHint);
   2044  }
   2045 
   2046  for (MediaQueryList* mql : mDocument->MediaQueryLists()) {
   2047    mql->MediaFeatureValuesChanged();
   2048  }
   2049 
   2050  return changedStyle;
   2051 }
   2052 
   2053 void nsPresContext::SizeModeChanged(nsSizeMode aSizeMode) {
   2054  if (nsPIDOMWindowOuter* window = mDocument->GetWindow()) {
   2055    nsContentUtils::CallOnAllRemoteChildren(
   2056        window, [&aSizeMode](BrowserParent* aBrowserParent) -> CallState {
   2057          aBrowserParent->SizeModeChanged(aSizeMode);
   2058          return CallState::Continue;
   2059        });
   2060  }
   2061  MediaFeatureValuesChanged({MediaFeatureChangeReason::SizeModeChange},
   2062                            MediaFeatureChangePropagation::SubDocuments);
   2063 }
   2064 
   2065 nsCompatibility nsPresContext::CompatibilityMode() const {
   2066  return Document()->GetCompatibilityMode();
   2067 }
   2068 
   2069 void nsPresContext::SetPaginatedScrolling(bool aPaginated) {
   2070  if (mType == eContext_PrintPreview || mType == eContext_PageLayout) {
   2071    mCanPaginatedScroll = aPaginated;
   2072  }
   2073 }
   2074 
   2075 void nsPresContext::SetPrintSettings(nsIPrintSettings* aPrintSettings) {
   2076  if (mMedium != nsGkAtoms::print) {
   2077    return;
   2078  }
   2079 
   2080  mPrintSettings = aPrintSettings;
   2081  mDefaultPageMargin = nsMargin();
   2082  if (!mPrintSettings) {
   2083    return;
   2084  }
   2085 
   2086  // Set the presentation context to the value in the print settings.
   2087  mDrawColorBackground = mPrintSettings->GetPrintBGColors();
   2088  mDrawImageBackground = mPrintSettings->GetPrintBGImages();
   2089 
   2090  nsIntMargin marginTwips = mPrintSettings->GetMarginInTwips();
   2091  if (!mPrintSettings->GetIgnoreUnwriteableMargins()) {
   2092    nsIntMargin unwriteableTwips =
   2093        mPrintSettings->GetUnwriteableMarginInTwips();
   2094    NS_ASSERTION(unwriteableTwips.top >= 0 && unwriteableTwips.right >= 0 &&
   2095                     unwriteableTwips.bottom >= 0 && unwriteableTwips.left >= 0,
   2096                 "Unwriteable twips should be non-negative");
   2097    marginTwips.EnsureAtLeast(unwriteableTwips);
   2098  }
   2099  mDefaultPageMargin = nsPresContext::CSSTwipsToAppUnits(marginTwips);
   2100 }
   2101 
   2102 bool nsPresContext::EnsureVisible() {
   2103  BrowsingContext* browsingContext =
   2104      mDocument ? mDocument->GetBrowsingContext() : nullptr;
   2105  if (!browsingContext || browsingContext->IsInBFCache()) {
   2106    return false;
   2107  }
   2108 
   2109  nsCOMPtr<nsIDocShell> docShell(GetDocShell());
   2110  if (!docShell) {
   2111    return false;
   2112  }
   2113  nsCOMPtr<nsIDocumentViewer> viewer;
   2114  docShell->GetDocViewer(getter_AddRefs(viewer));
   2115  // Make sure this is the content viewer we belong with
   2116  if (!viewer || viewer->GetPresContext() != this) {
   2117    return false;
   2118  }
   2119  // OK, this is us.  We want to call Show() on the content viewer.
   2120  nsresult result = viewer->Show();
   2121  return NS_SUCCEEDED(result);
   2122 }
   2123 
   2124 #ifdef MOZ_REFLOW_PERF
   2125 void nsPresContext::CountReflows(const char* aName, nsIFrame* aFrame) {
   2126  if (mPresShell) {
   2127    mPresShell->CountReflows(aName, aFrame);
   2128  }
   2129 }
   2130 #endif
   2131 
   2132 gfxUserFontSet* nsPresContext::GetUserFontSet() {
   2133  return mDocument->GetUserFontSet();
   2134 }
   2135 
   2136 void nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont) {
   2137  if (!mPresShell) {
   2138    return;
   2139  }
   2140 
   2141  // Note: this method is called without a font when rules in the userfont set
   2142  // are updated.
   2143  //
   2144  // We can avoid a full restyle if font-metric-dependent units are not in use,
   2145  // since we know there's no style resolution that would depend on this font
   2146  // and trigger its load.
   2147  //
   2148  // TODO(emilio): We could be more granular if we knew which families have
   2149  // potentially changed.
   2150  if (!aUpdatedFont) {
   2151    auto hint =
   2152        (StyleSet()->UsesFontMetrics() || StyleSet()->UsesRootFontMetrics())
   2153            ? RestyleHint::RecascadeSubtree()
   2154            : RestyleHint{0};
   2155    PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, hint);
   2156    return;
   2157  }
   2158 
   2159  // Iterate over the frame tree looking for frames associated with the
   2160  // downloadable font family in question. If a frame's nsStyleFont has
   2161  // the name, check the font group associated with the metrics to see if
   2162  // it contains that specific font (i.e. the one chosen within the family
   2163  // given the weight, width, and slant from the nsStyleFont). If it does,
   2164  // mark that frame dirty and skip inspecting its descendants.
   2165  if (nsIFrame* root = mPresShell->GetRootFrame()) {
   2166    nsFontFaceUtils::MarkDirtyForFontChange(root, aUpdatedFont);
   2167  }
   2168 }
   2169 
   2170 class CounterStyleCleaner final : public nsAPostRefreshObserver {
   2171 public:
   2172  CounterStyleCleaner(nsRefreshDriver* aRefreshDriver,
   2173                      CounterStyleManager* aCounterStyleManager)
   2174      : mRefreshDriver(aRefreshDriver),
   2175        mCounterStyleManager(aCounterStyleManager) {}
   2176  virtual ~CounterStyleCleaner() = default;
   2177 
   2178  void DidRefresh() final {
   2179    mRefreshDriver->RemovePostRefreshObserver(this);
   2180    mCounterStyleManager->CleanRetiredStyles();
   2181    delete this;
   2182  }
   2183 
   2184 private:
   2185  RefPtr<nsRefreshDriver> mRefreshDriver;
   2186  RefPtr<CounterStyleManager> mCounterStyleManager;
   2187 };
   2188 
   2189 void nsPresContext::FlushCounterStyles() {
   2190  if (!mPresShell) {
   2191    return;  // we've been torn down
   2192  }
   2193  if (mCounterStyleManager->IsInitial()) {
   2194    // Still in its initial state, no need to clean.
   2195    return;
   2196  }
   2197 
   2198  if (mCounterStylesDirty) {
   2199    bool changed = mCounterStyleManager->NotifyRuleChanged();
   2200    if (changed) {
   2201      PresShell()->NotifyCounterStylesAreDirty();
   2202      PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, RestyleHint{0});
   2203      RefreshDriver()->AddPostRefreshObserver(
   2204          new CounterStyleCleaner(RefreshDriver(), mCounterStyleManager));
   2205    }
   2206    mCounterStylesDirty = false;
   2207  }
   2208 }
   2209 
   2210 void nsPresContext::MarkCounterStylesDirty() {
   2211  if (mCounterStyleManager->IsInitial()) {
   2212    // Still in its initial state, no need to touch anything.
   2213    return;
   2214  }
   2215 
   2216  mCounterStylesDirty = true;
   2217 }
   2218 
   2219 void nsPresContext::NotifyMissingFonts() {
   2220  if (mMissingFonts) {
   2221    mMissingFonts->Flush();
   2222  }
   2223 }
   2224 
   2225 void nsPresContext::EnsureSafeToHandOutCSSRules() {
   2226  if (!mPresShell->StyleSet()->EnsureUniqueInnerOnCSSSheets()) {
   2227    // Nothing to do.
   2228    return;
   2229  }
   2230 
   2231  RebuildAllStyleData(nsChangeHint(0), RestyleHint::RestyleSubtree());
   2232 }
   2233 
   2234 void nsPresContext::FireDOMPaintEvent(
   2235    nsTArray<nsRect>* aList, TransactionId aTransactionId,
   2236    mozilla::TimeStamp aTimeStamp /* = mozilla::TimeStamp() */) {
   2237  nsPIDOMWindowInner* ourWindow = mDocument->GetInnerWindow();
   2238  if (!ourWindow) {
   2239    return;
   2240  }
   2241 
   2242  nsCOMPtr<EventTarget> dispatchTarget = do_QueryInterface(ourWindow);
   2243  nsCOMPtr<EventTarget> eventTarget = dispatchTarget;
   2244  if (!IsChrome() && !StaticPrefs::dom_send_after_paint_to_content()) {
   2245    // Don't tell the window about this event, it should not know that
   2246    // something happened in a subdocument. Tell only the chrome event handler.
   2247    // (Events sent to the window get propagated to the chrome event handler
   2248    // automatically.)
   2249    dispatchTarget = ourWindow->GetParentTarget();
   2250    if (!dispatchTarget) {
   2251      return;
   2252    }
   2253  }
   2254 
   2255  if (aTimeStamp.IsNull()) {
   2256    aTimeStamp = mozilla::TimeStamp::Now();
   2257  }
   2258  DOMHighResTimeStamp timeStamp = 0;
   2259  if (ourWindow) {
   2260    mozilla::dom::Performance* perf = ourWindow->GetPerformance();
   2261    if (perf) {
   2262      timeStamp = perf->GetDOMTiming()->TimeStampToDOMHighRes(aTimeStamp);
   2263    }
   2264  }
   2265 
   2266  // Events sent to the window get propagated to the chrome event handler
   2267  // automatically.
   2268  //
   2269  // This will empty our list in case dispatching the event causes more damage
   2270  // (hopefully it won't, or we're likely to get an infinite loop! At least
   2271  // it won't be blocking app execution though).
   2272  RefPtr<NotifyPaintEvent> event =
   2273      NS_NewDOMNotifyPaintEvent(eventTarget, this, nullptr, eAfterPaint, aList,
   2274                                uint64_t(aTransactionId), timeStamp);
   2275 
   2276  // Even if we're not telling the window about the event (so eventTarget is
   2277  // the chrome event handler, not the window), the window is still
   2278  // logically the event target.
   2279  event->SetTarget(eventTarget);
   2280  event->SetTrusted(true);
   2281  EventDispatcher::DispatchDOMEvent(dispatchTarget, nullptr,
   2282                                    static_cast<Event*>(event), this, nullptr);
   2283 }
   2284 
   2285 nsPresContext::TransactionInvalidations* nsPresContext::GetInvalidations(
   2286    TransactionId aTransactionId) {
   2287  for (TransactionInvalidations& t : mTransactions) {
   2288    if (t.mTransactionId == aTransactionId) {
   2289      return &t;
   2290    }
   2291  }
   2292  return nullptr;
   2293 }
   2294 
   2295 void nsPresContext::NotifyInvalidation(TransactionId aTransactionId,
   2296                                       const nsRect& aRect) {
   2297  MOZ_ASSERT(GetContainerWeak(), "Invalidation in detached pres context");
   2298 
   2299  for (nsPresContext* pc = this; pc; pc = pc->GetParentPresContext()) {
   2300    TransactionInvalidations* transaction =
   2301        pc->GetInvalidations(aTransactionId);
   2302    if (transaction) {
   2303      break;
   2304    }
   2305    transaction = pc->mTransactions.AppendElement();
   2306    transaction->mTransactionId = aTransactionId;
   2307  }
   2308 
   2309  TransactionInvalidations* transaction = GetInvalidations(aTransactionId);
   2310  MOZ_ASSERT(transaction);
   2311  transaction->mInvalidations.AppendElement(aRect);
   2312 }
   2313 
   2314 class DelayedFireDOMPaintEvent : public Runnable {
   2315 public:
   2316  DelayedFireDOMPaintEvent(
   2317      nsPresContext* aPresContext, nsTArray<nsRect>&& aList,
   2318      TransactionId aTransactionId,
   2319      const mozilla::TimeStamp& aTimeStamp = mozilla::TimeStamp())
   2320      : mozilla::Runnable("DelayedFireDOMPaintEvent"),
   2321        mPresContext(aPresContext),
   2322        mTransactionId(aTransactionId),
   2323        mTimeStamp(aTimeStamp),
   2324        mList(std::move(aList)) {
   2325    MOZ_ASSERT(mPresContext->GetContainerWeak(),
   2326               "DOMPaintEvent requested for a detached pres context");
   2327  }
   2328  NS_IMETHOD Run() override {
   2329    // The pres context might have been detached during the delay -
   2330    // that's fine, just don't fire the event.
   2331    if (mPresContext->GetContainerWeak()) {
   2332      mPresContext->FireDOMPaintEvent(&mList, mTransactionId, mTimeStamp);
   2333    }
   2334    return NS_OK;
   2335  }
   2336 
   2337  RefPtr<nsPresContext> mPresContext;
   2338  TransactionId mTransactionId;
   2339  const mozilla::TimeStamp mTimeStamp;
   2340  nsTArray<nsRect> mList;
   2341 };
   2342 
   2343 void nsPresContext::NotifyRevokingDidPaint(TransactionId aTransactionId) {
   2344  if ((IsRoot() || !PresShell()->IsVisible()) && mTransactions.IsEmpty()) {
   2345    return;
   2346  }
   2347 
   2348  TransactionInvalidations* transaction = nullptr;
   2349  for (auto& t : mTransactions) {
   2350    if (t.mTransactionId == aTransactionId) {
   2351      transaction = &t;
   2352      break;
   2353    }
   2354  }
   2355  // If there are no transaction invalidations (which imply callers waiting
   2356  // on the event) for this revoked id, then we don't need to fire a
   2357  // MozAfterPaint.
   2358  if (!transaction) {
   2359    return;
   2360  }
   2361 
   2362  // If there are queued transactions with an earlier id, we can't send
   2363  // our event now since it will arrive out of order. Set the waiting for
   2364  // previous transaction flag to true, and we'll send the event when
   2365  // the others are completed.
   2366  // If this is the only transaction, then we can send it immediately.
   2367  if (mTransactions.Length() == 1) {
   2368    nsCOMPtr<nsIRunnable> ev = new DelayedFireDOMPaintEvent(
   2369        this, std::move(transaction->mInvalidations),
   2370        transaction->mTransactionId, mozilla::TimeStamp());
   2371    nsContentUtils::AddScriptRunner(ev);
   2372    mTransactions.RemoveElementAt(0);
   2373  } else {
   2374    transaction->mIsWaitingForPreviousTransaction = true;
   2375  }
   2376 
   2377  mDocument->EnumerateSubDocuments([&aTransactionId](dom::Document& aSubDoc) {
   2378    if (nsPresContext* pc = aSubDoc.GetPresContext()) {
   2379      pc->NotifyRevokingDidPaint(aTransactionId);
   2380    }
   2381    return CallState::Continue;
   2382  });
   2383 }
   2384 
   2385 void nsPresContext::NotifyDidPaintForSubtree(
   2386    TransactionId aTransactionId, const mozilla::TimeStamp& aTimeStamp) {
   2387  if (mFirstContentfulPaintTransactionId && !mHadContentfulPaintComposite) {
   2388    if (aTransactionId >= *mFirstContentfulPaintTransactionId) {
   2389      mHadContentfulPaintComposite = true;
   2390      RefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
   2391      if (timing && !IsPrintingOrPrintPreview()) {
   2392        timing->NotifyContentfulCompositeForRootContentDocument(aTimeStamp);
   2393      }
   2394    }
   2395  }
   2396 
   2397  if (IsRoot() && mTransactions.IsEmpty()) {
   2398    return;
   2399  }
   2400 
   2401  if (!PresShell()->IsVisible() && mTransactions.IsEmpty()) {
   2402    return;
   2403  }
   2404 
   2405  // Non-root prescontexts fire MozAfterPaint to all their descendants
   2406  // unconditionally, even if no invalidations have been collected. This is
   2407  // because we don't want to eat the cost of collecting invalidations for
   2408  // every subdocument (which would require putting every subdocument in its
   2409  // own layer).
   2410 
   2411  bool sent = false;
   2412  uint32_t i = 0;
   2413  while (i < mTransactions.Length()) {
   2414    if (mTransactions[i].mTransactionId <= aTransactionId) {
   2415      if (!mTransactions[i].mInvalidations.IsEmpty()) {
   2416        nsCOMPtr<nsIRunnable> ev = new DelayedFireDOMPaintEvent(
   2417            this, std::move(mTransactions[i].mInvalidations),
   2418            mTransactions[i].mTransactionId, aTimeStamp);
   2419        NS_DispatchToCurrentThreadQueue(ev.forget(),
   2420                                        EventQueuePriority::MediumHigh);
   2421        sent = true;
   2422      }
   2423      mTransactions.RemoveElementAt(i);
   2424    } else {
   2425      // If there are transaction which is waiting for this transaction,
   2426      // we should fire a MozAfterPaint immediately.
   2427      if (sent && mTransactions[i].mIsWaitingForPreviousTransaction) {
   2428        nsCOMPtr<nsIRunnable> ev = new DelayedFireDOMPaintEvent(
   2429            this, std::move(mTransactions[i].mInvalidations),
   2430            mTransactions[i].mTransactionId, aTimeStamp);
   2431        NS_DispatchToCurrentThreadQueue(ev.forget(),
   2432                                        EventQueuePriority::MediumHigh);
   2433        sent = true;
   2434        mTransactions.RemoveElementAt(i);
   2435        continue;
   2436      }
   2437      i++;
   2438    }
   2439  }
   2440 
   2441  if (!sent) {
   2442    nsTArray<nsRect> dummy;
   2443    nsCOMPtr<nsIRunnable> ev = new DelayedFireDOMPaintEvent(
   2444        this, std::move(dummy), aTransactionId, aTimeStamp);
   2445    NS_DispatchToCurrentThreadQueue(ev.forget(),
   2446                                    EventQueuePriority::MediumHigh);
   2447  }
   2448 
   2449  mDocument->EnumerateSubDocuments(
   2450      [&aTransactionId, &aTimeStamp](dom::Document& aSubDoc) {
   2451        if (nsPresContext* pc = aSubDoc.GetPresContext()) {
   2452          pc->NotifyDidPaintForSubtree(aTransactionId, aTimeStamp);
   2453        }
   2454        return CallState::Continue;
   2455      });
   2456 }
   2457 
   2458 already_AddRefed<nsITimer> nsPresContext::CreateTimer(
   2459    nsTimerCallbackFunc aCallback, const nsACString& aName, uint32_t aDelay) {
   2460  nsCOMPtr<nsITimer> timer;
   2461  NS_NewTimerWithFuncCallback(getter_AddRefs(timer), aCallback, this, aDelay,
   2462                              nsITimer::TYPE_ONE_SHOT, aName,
   2463                              GetMainThreadSerialEventTarget());
   2464  return timer.forget();
   2465 }
   2466 
   2467 static bool sGotInterruptEnv = false;
   2468 enum InterruptMode { ModeRandom, ModeCounter, ModeEvent };
   2469 // Controlled by the GECKO_REFLOW_INTERRUPT_MODE env var; allowed values are
   2470 // "random" (except on Windows) or "counter".  If neither is used, the mode is
   2471 // ModeEvent.
   2472 static InterruptMode sInterruptMode = ModeEvent;
   2473 #ifndef XP_WIN
   2474 // Used for the "random" mode.  Controlled by the GECKO_REFLOW_INTERRUPT_SEED
   2475 // env var.
   2476 static uint32_t sInterruptSeed = 1;
   2477 #endif
   2478 // Used for the "counter" mode.  This is the number of unskipped interrupt
   2479 // checks that have to happen before we interrupt.  Controlled by the
   2480 // GECKO_REFLOW_INTERRUPT_FREQUENCY env var.
   2481 static uint32_t sInterruptMaxCounter = 10;
   2482 // Used for the "counter" mode.  This counts up to sInterruptMaxCounter and is
   2483 // then reset to 0.
   2484 static uint32_t sInterruptCounter;
   2485 // Number of interrupt checks to skip before really trying to interrupt.
   2486 // Controlled by the GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP env var.
   2487 static uint32_t sInterruptChecksToSkip = 200;
   2488 // Number of milliseconds that a reflow should be allowed to run for before we
   2489 // actually allow interruption.  Controlled by the
   2490 // GECKO_REFLOW_MIN_NOINTERRUPT_DURATION env var.  Can't be initialized here,
   2491 // because TimeDuration/TimeStamp is not safe to use in static constructors..
   2492 static TimeDuration sInterruptTimeout;
   2493 
   2494 static void GetInterruptEnv() {
   2495  char* ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_MODE");
   2496  if (ev) {
   2497 #ifndef XP_WIN
   2498    if (nsCRT::strcasecmp(ev, "random") == 0) {
   2499      ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_SEED");
   2500      if (ev) {
   2501        sInterruptSeed = atoi(ev);
   2502      }
   2503      srandom(sInterruptSeed);
   2504      sInterruptMode = ModeRandom;
   2505    } else
   2506 #endif
   2507        if (PL_strcasecmp(ev, "counter") == 0) {
   2508      ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_FREQUENCY");
   2509      if (ev) {
   2510        sInterruptMaxCounter = atoi(ev);
   2511      }
   2512      sInterruptCounter = 0;
   2513      sInterruptMode = ModeCounter;
   2514    }
   2515  }
   2516  ev = PR_GetEnv("GECKO_REFLOW_INTERRUPT_CHECKS_TO_SKIP");
   2517  if (ev) {
   2518    sInterruptChecksToSkip = atoi(ev);
   2519  }
   2520 
   2521  ev = PR_GetEnv("GECKO_REFLOW_MIN_NOINTERRUPT_DURATION");
   2522  int duration_ms = ev ? atoi(ev) : 100;
   2523  sInterruptTimeout = TimeDuration::FromMilliseconds(duration_ms);
   2524 }
   2525 
   2526 bool nsPresContext::HavePendingInputEvent() {
   2527  switch (sInterruptMode) {
   2528 #ifndef XP_WIN
   2529    case ModeRandom:
   2530      return (random() & 1);
   2531 #endif
   2532    case ModeCounter:
   2533      if (sInterruptCounter < sInterruptMaxCounter) {
   2534        ++sInterruptCounter;
   2535        return false;
   2536      }
   2537      sInterruptCounter = 0;
   2538      return true;
   2539    default:
   2540    case ModeEvent: {
   2541      nsIFrame* f = PresShell()->GetRootFrame();
   2542      if (f) {
   2543        nsIWidget* w = f->GetNearestWidget();
   2544        if (w) {
   2545          return w->HasPendingInputEvent();
   2546        }
   2547      }
   2548      return false;
   2549    }
   2550  }
   2551 }
   2552 
   2553 void nsPresContext::ReflowStarted(bool aInterruptible) {
   2554 #ifdef NOISY_INTERRUPTIBLE_REFLOW
   2555  if (!aInterruptible) {
   2556    printf("STARTING NONINTERRUPTIBLE REFLOW\n");
   2557  }
   2558 #endif
   2559  // We don't support interrupting in paginated contexts, since page
   2560  // sequences only handle initial reflow
   2561  mInterruptsEnabled = aInterruptible && !IsPaginated() &&
   2562                       StaticPrefs::layout_interruptible_reflow_enabled();
   2563 
   2564  // Don't set mHasPendingInterrupt based on HavePendingInputEvent() here.  If
   2565  // we ever change that, then we need to update the code in
   2566  // PresShell::DoReflow to only add the just-reflown root to dirty roots if
   2567  // it's actually dirty.  Otherwise we can end up adding a root that has no
   2568  // interruptible descendants, just because we detected an interrupt at reflow
   2569  // start.
   2570  mHasPendingInterrupt = false;
   2571 
   2572  mInterruptChecksToSkip = sInterruptChecksToSkip;
   2573 
   2574  if (mInterruptsEnabled) {
   2575    mReflowStartTime = TimeStamp::Now();
   2576  }
   2577 }
   2578 
   2579 bool nsPresContext::CheckForInterrupt(nsIFrame* aFrame) {
   2580  if (mHasPendingInterrupt) {
   2581    mPresShell->FrameNeedsToContinueReflow(aFrame);
   2582    return true;
   2583  }
   2584 
   2585  if (!sGotInterruptEnv) {
   2586    sGotInterruptEnv = true;
   2587    GetInterruptEnv();
   2588  }
   2589 
   2590  if (!mInterruptsEnabled) {
   2591    return false;
   2592  }
   2593 
   2594  if (mInterruptChecksToSkip > 0) {
   2595    --mInterruptChecksToSkip;
   2596    return false;
   2597  }
   2598  mInterruptChecksToSkip = sInterruptChecksToSkip;
   2599 
   2600  // Don't interrupt if it's been less than sInterruptTimeout since we started
   2601  // the reflow.
   2602  mHasPendingInterrupt =
   2603      TimeStamp::Now() - mReflowStartTime > sInterruptTimeout &&
   2604      HavePendingInputEvent() && !IsChrome();
   2605 
   2606  if (mPendingInterruptFromTest) {
   2607    mPendingInterruptFromTest = false;
   2608    mHasPendingInterrupt = true;
   2609  }
   2610 
   2611  if (mHasPendingInterrupt) {
   2612 #ifdef NOISY_INTERRUPTIBLE_REFLOW
   2613    printf("*** DETECTED pending interrupt (time=%lld)\n", PR_Now());
   2614 #endif /* NOISY_INTERRUPTIBLE_REFLOW */
   2615    mPresShell->FrameNeedsToContinueReflow(aFrame);
   2616  }
   2617  return mHasPendingInterrupt;
   2618 }
   2619 
   2620 nsIFrame* nsPresContext::GetPrimaryFrameFor(nsIContent* aContent) {
   2621  MOZ_ASSERT(aContent, "Don't do that");
   2622  if (GetPresShell() &&
   2623      GetPresShell()->GetDocument() == aContent->GetComposedDoc()) {
   2624    return aContent->GetPrimaryFrame();
   2625  }
   2626  return nullptr;
   2627 }
   2628 
   2629 size_t nsPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
   2630  // Measurement may be added later if DMD finds it is worthwhile.
   2631  return 0;
   2632 }
   2633 
   2634 bool nsPresContext::IsRootContentDocumentInProcess() const {
   2635  if (mDocument->IsResourceDoc()) {
   2636    return false;
   2637  }
   2638  if (IsChrome()) {
   2639    return false;
   2640  }
   2641  auto* embedder = PresShell()->GetInProcessEmbedderFrame();
   2642  return !embedder || embedder->PresContext()->IsChrome();
   2643 }
   2644 
   2645 bool nsPresContext::IsRootContentDocumentCrossProcess() const {
   2646  if (mDocument->IsResourceDoc()) {
   2647    return false;
   2648  }
   2649 
   2650  if (BrowsingContext* browsingContext = mDocument->GetBrowsingContext()) {
   2651    if (browsingContext->GetEmbeddedInContentDocument()) {
   2652      return false;
   2653    }
   2654  }
   2655  return mDocument->IsTopLevelContentDocument();
   2656 }
   2657 
   2658 void nsPresContext::NotifyNonBlankPaint() {
   2659  MOZ_ASSERT(!mHadNonBlankPaint);
   2660  mHadNonBlankPaint = true;
   2661  if (IsRootContentDocumentCrossProcess()) {
   2662    RefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
   2663    if (timing && !IsPrintingOrPrintPreview()) {
   2664      timing->NotifyNonBlankPaintForRootContentDocument();
   2665    }
   2666 
   2667    mFirstNonBlankPaintTime = TimeStamp::Now();
   2668  }
   2669  if (IsChrome() && IsRoot()) {
   2670    if (nsCOMPtr<nsIWidget> rootWidget = GetRootWidget()) {
   2671      rootWidget->DidGetNonBlankPaint();
   2672    }
   2673  }
   2674 }
   2675 
   2676 bool nsPresContext::HasStoppedGeneratingLCP() const {
   2677  if (auto* perf = GetPerformanceMainThread()) {
   2678    return perf->HasDispatchedInputEvent() || perf->HasDispatchedScrollEvent();
   2679  }
   2680 
   2681  return true;
   2682 }
   2683 
   2684 void nsPresContext::NotifyContentfulPaint() {
   2685  if (mHadFirstContentfulPaint && HasStoppedGeneratingLCP()) {
   2686    MOZ_ASSERT(mHadNonTickContentfulPaint);
   2687    return;
   2688  }
   2689  nsRootPresContext* rootPresContext = GetRootPresContext();
   2690  if (!rootPresContext) {
   2691    return;
   2692  }
   2693 
   2694  if (!mHadNonTickContentfulPaint) {
   2695 #ifdef MOZ_WIDGET_ANDROID
   2696    (new AsyncEventDispatcher(mDocument, u"MozFirstContentfulPaint"_ns,
   2697                              CanBubble::eYes, ChromeOnlyDispatch::eYes))
   2698        ->PostDOMEvent();
   2699 #endif
   2700    mHadNonTickContentfulPaint = true;
   2701  }
   2702 
   2703  if (!rootPresContext->RefreshDriver()->IsInRefresh()) {
   2704    rootPresContext->RefreshDriver()->AddForceNotifyContentfulPaintPresContext(
   2705        this);
   2706    return;
   2707  }
   2708 
   2709  // From here on we know that we are inside a refresh tick.
   2710 
   2711  if (!mHadFirstContentfulPaint) {
   2712    mHadFirstContentfulPaint = true;
   2713    mFirstContentfulPaintTransactionId =
   2714        Some(rootPresContext->mRefreshDriver->LastTransactionId().Next());
   2715  }
   2716 
   2717  if (auto* perf = GetPerformanceMainThread()) {
   2718    mMarkPaintTimingStart = TimeStamp::Now();
   2719    MOZ_ASSERT(rootPresContext->RefreshDriver()->IsInRefresh(),
   2720               "We should only notify contentful paint during refresh "
   2721               "driver ticks");
   2722    if (!perf->HadFCPTimingEntry()) {
   2723      TimeStamp nowTime = mMarkPaintTimingStart;
   2724      MOZ_ASSERT(!nowTime.IsNull(),
   2725                 "Most recent refresh timestamp should exist since we are in "
   2726                 "a refresh driver tick");
   2727      auto paintTiming = MakeRefPtr<PerformancePaintTiming>(
   2728          perf, u"first-contentful-paint"_ns, nowTime);
   2729      perf->SetFCPTimingEntry(paintTiming);
   2730 
   2731      if (profiler_thread_is_being_profiled_for_markers()) {
   2732        RefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
   2733        if (timing) {
   2734          TimeStamp navigationStart = timing->GetNavigationStartTimeStamp();
   2735          TimeDuration elapsed = nowTime - navigationStart;
   2736          nsIURI* docURI = Document()->GetDocumentURI();
   2737          nsPrintfCString marker(
   2738              "Contentful paint after %dms for URL %s",
   2739              int(elapsed.ToMilliseconds()),
   2740              nsContentUtils::TruncatedURLForDisplay(docURI).get());
   2741          PROFILER_MARKER_TEXT(
   2742              "FirstContentfulPaint", DOM,
   2743              MarkerOptions(
   2744                  MarkerTiming::Interval(navigationStart, nowTime),
   2745                  MarkerInnerWindowId(mDocument->GetInnerWindow()->WindowID())),
   2746              marker);
   2747        }
   2748      }
   2749    }
   2750 
   2751    perf->ProcessElementTiming();
   2752  }
   2753 }
   2754 
   2755 void nsPresContext::NotifyPaintStatusReset() {
   2756  mHadNonBlankPaint = false;
   2757  mHadFirstContentfulPaint = false;
   2758 #if defined(MOZ_WIDGET_ANDROID)
   2759  (new AsyncEventDispatcher(mDocument, u"MozPaintStatusReset"_ns,
   2760                            CanBubble::eYes, ChromeOnlyDispatch::eYes))
   2761      ->PostDOMEvent();
   2762 #endif
   2763  mHadNonTickContentfulPaint = false;
   2764 }
   2765 
   2766 nscoord nsPresContext::GfxUnitsToAppUnits(gfxFloat aGfxUnits) const {
   2767  return mDeviceContext->GfxUnitsToAppUnits(aGfxUnits);
   2768 }
   2769 
   2770 gfxFloat nsPresContext::AppUnitsToGfxUnits(nscoord aAppUnits) const {
   2771  return mDeviceContext->AppUnitsToGfxUnits(aAppUnits);
   2772 }
   2773 
   2774 nscoord nsPresContext::PhysicalMillimetersToAppUnits(float aMM) const {
   2775  float inches = aMM / MM_PER_INCH_FLOAT;
   2776  return NSToCoordFloorClamped(
   2777      inches * float(DeviceContext()->AppUnitsPerPhysicalInch()));
   2778 }
   2779 
   2780 uint64_t nsPresContext::GetRestyleGeneration() const {
   2781  if (!mRestyleManager) {
   2782    return 0;
   2783  }
   2784  return mRestyleManager->GetRestyleGeneration();
   2785 }
   2786 
   2787 uint64_t nsPresContext::GetUndisplayedRestyleGeneration() const {
   2788  if (!mRestyleManager) {
   2789    return 0;
   2790  }
   2791  return mRestyleManager->GetUndisplayedRestyleGeneration();
   2792 }
   2793 
   2794 mozilla::intl::Bidi& nsPresContext::BidiEngine() {
   2795  MOZ_ASSERT(NS_IsMainThread());
   2796 
   2797  if (!mBidiEngine) {
   2798    mBidiEngine = MakeUnique<mozilla::intl::Bidi>();
   2799  }
   2800  return *mBidiEngine;
   2801 }
   2802 
   2803 void nsPresContext::FlushFontFeatureValues() {
   2804  if (!mPresShell) {
   2805    return;  // we've been torn down
   2806  }
   2807 
   2808  if (!mFontFeatureValuesDirty) {
   2809    return;
   2810  }
   2811 
   2812  ServoStyleSet* styleSet = mPresShell->StyleSet();
   2813  mFontFeatureValuesLookup = styleSet->BuildFontFeatureValueSet();
   2814  mFontFeatureValuesDirty = false;
   2815 }
   2816 
   2817 void nsPresContext::FlushFontPaletteValues() {
   2818  if (!mPresShell) {
   2819    return;  // we've been torn down
   2820  }
   2821 
   2822  if (!mFontPaletteValuesDirty) {
   2823    return;
   2824  }
   2825 
   2826  ServoStyleSet* styleSet = mPresShell->StyleSet();
   2827  mFontPaletteValueSet = styleSet->BuildFontPaletteValueSet();
   2828  mFontPaletteValuesDirty = false;
   2829 
   2830  if (mFontPaletteCache) {
   2831    mFontPaletteCache->SetPaletteValueSet(mFontPaletteValueSet);
   2832  }
   2833 
   2834  // Even if we're not reflowing anything, a change to the palette means we
   2835  // need to repaint in order to show the new colors.
   2836  InvalidatePaintedLayers();
   2837 }
   2838 
   2839 gfx::PaletteCache& nsPresContext::FontPaletteCache() {
   2840  if (!mFontPaletteCache) {
   2841    mFontPaletteCache = MakeUnique<gfx::PaletteCache>(mFontPaletteValueSet);
   2842  }
   2843  return *mFontPaletteCache.get();
   2844 }
   2845 
   2846 void nsPresContext::SetVisibleArea(const nsRect& aRect) {
   2847  if (!aRect.IsEqualEdges(mVisibleArea)) {
   2848    mVisibleArea = aRect;
   2849    mSizeForViewportUnits = mVisibleArea.Size();
   2850    AdjustSizeForViewportUnits();
   2851    // Visible area does not affect media queries when paginated.
   2852    if (!IsRootPaginatedDocument()) {
   2853      MediaFeatureValuesChanged(
   2854          {mozilla::MediaFeatureChangeReason::ViewportChange},
   2855          MediaFeatureChangePropagation::JustThisDocument);
   2856    }
   2857 
   2858    UpdateTopInnerSizeForRFP();
   2859  }
   2860 }
   2861 
   2862 void nsPresContext::SetInitialVisibleArea(const nsRect& aRect) {
   2863  MOZ_ASSERT(mPresShell);
   2864 
   2865  if (RefPtr<MobileViewportManager> mvm =
   2866          mPresShell->GetMobileViewportManager()) {
   2867    // On mobile environments the top level content document viewport size is
   2868    // depending on meta viewport tags in the document so we use it rather than
   2869    // using the given document viewer size directly.
   2870    SetVisibleArea(mvm->InitialVisibleArea());
   2871    return;
   2872  }
   2873  SetVisibleArea(aRect);
   2874 }
   2875 
   2876 void nsPresContext::SetDynamicToolbarMaxHeight(ScreenIntCoord aHeight) {
   2877  MOZ_ASSERT(IsRootContentDocumentCrossProcess());
   2878 
   2879  if (mDynamicToolbarMaxHeight == aHeight) {
   2880    return;
   2881  }
   2882  mDynamicToolbarMaxHeight = aHeight;
   2883  mDynamicToolbarHeight = aHeight;
   2884 
   2885  AdjustSizeForViewportUnits();
   2886 
   2887  if (RefPtr<mozilla::PresShell> presShell = mPresShell) {
   2888    // Changing the max height of the dynamic toolbar changes the ICB size, we
   2889    // need to kick a reflow with the current window dimensions since the max
   2890    // height change doesn't change the window dimensions but
   2891    // PresShell::ResizeReflow ends up subtracting the new dynamic toolbar
   2892    // height from the window dimensions and kick a reflow with the proper ICB
   2893    // size.
   2894    presShell->ForceResizeReflowWithCurrentDimensions();
   2895  }
   2896 }
   2897 
   2898 void nsPresContext::AdjustSizeForViewportUnits() {
   2899  if (!HasDynamicToolbar()) {
   2900    return;
   2901  }
   2902 
   2903  if (MOZ_UNLIKELY(mVisibleArea.height == NS_UNCONSTRAINEDSIZE)) {
   2904    // Ignore `NS_UNCONSTRAINEDSIZE` since it's a temporary state during a
   2905    // reflow. We will end up calling this function again with a proper size in
   2906    // the same reflow.
   2907    return;
   2908  }
   2909 
   2910  nscoord toolbarMaxHeight = GetDynamicToolbarMaxHeightInAppUnits();
   2911  if (MOZ_UNLIKELY(mVisibleArea.height + toolbarMaxHeight > nscoord_MAX)) {
   2912    MOZ_ASSERT_UNREACHABLE("The dynamic toolbar max height is probably wrong");
   2913    return;
   2914  }
   2915 
   2916  mSizeForViewportUnits.height = mVisibleArea.height + toolbarMaxHeight;
   2917 }
   2918 
   2919 void nsPresContext::UpdateDynamicToolbarOffset(ScreenIntCoord aOffset) {
   2920  MOZ_ASSERT(IsRootContentDocumentCrossProcess());
   2921  if (!mPresShell) {
   2922    return;
   2923  }
   2924 
   2925  if (!HasDynamicToolbar()) {
   2926    return;
   2927  }
   2928 
   2929  MOZ_ASSERT(-mDynamicToolbarMaxHeight <= aOffset && aOffset <= 0);
   2930  if (mDynamicToolbarHeight == mDynamicToolbarMaxHeight + aOffset) {
   2931    return;
   2932  }
   2933 
   2934  dom::InteractiveWidget interactiveWidget = mDocument->InteractiveWidget();
   2935  if (interactiveWidget == InteractiveWidget::OverlaysContent &&
   2936      GetKeyboardHeight() > 0) {
   2937    // On overlays-content mode, the toolbar offset change should NOT affect
   2938    // the visual viewport while the software keyboard is being shown since
   2939    // the toolbar will be positioned somewhere in the middle of the visual
   2940    // viewport.
   2941    return;
   2942  }
   2943 
   2944  // Forcibly flush position:fixed elements and position:sticky elements stuck
   2945  // to the root scroll container in the case where the dynamic toolbar is
   2946  // going to be completely hidden or starts to be visible so that %-based style
   2947  // values will be recomputed with the visual viewport size which is including
   2948  // the area covered by the dynamic toolbar, it also ensures that each
   2949  // position:fixed or position:sticky element is painted at the correct
   2950  // position on the main-thread.
   2951  if (mDynamicToolbarHeight == 0 || aOffset == -mDynamicToolbarMaxHeight) {
   2952    mPresShell->MarkFixedFramesForReflow();
   2953    mPresShell->MarkStickyFramesForReflow();
   2954    mPresShell->ScheduleResizeEventIfNeeded(
   2955        PresShell::ResizeEventKind::Regular);
   2956  }
   2957 
   2958  mDynamicToolbarHeight = mDynamicToolbarMaxHeight + aOffset;
   2959 
   2960  if (RefPtr<MobileViewportManager> mvm =
   2961          mPresShell->GetMobileViewportManager()) {
   2962    mvm->UpdateVisualViewportSizeByDynamicToolbar(-aOffset);
   2963  }
   2964 
   2965  mPresShell->StyleSet()->InvalidateForViewportUnits(
   2966      ServoStyleSet::OnlyDynamic::Yes);
   2967 }
   2968 
   2969 void nsPresContext::UpdateKeyboardHeight(ScreenIntCoord aHeight) {
   2970  MOZ_ASSERT(IsRootContentDocumentCrossProcess());
   2971  if (!mPresShell) {
   2972    return;
   2973  }
   2974 
   2975  if (RefPtr<MobileViewportManager> mvm =
   2976          mPresShell->GetMobileViewportManager()) {
   2977    mvm->UpdateKeyboardHeight(aHeight);
   2978  }
   2979 }
   2980 
   2981 ScreenIntCoord nsPresContext::GetKeyboardHeight() const {
   2982  MobileViewportManager* mvm = mPresShell->GetMobileViewportManager();
   2983  return mvm ? mvm->GetKeyboardHeight() : ScreenIntCoord(0);
   2984 }
   2985 
   2986 bool nsPresContext::IsKeyboardHiddenOrResizesContentMode() const {
   2987  return GetKeyboardHeight() == 0 ||
   2988         mDocument->InteractiveWidget() == InteractiveWidget::ResizesContent;
   2989 }
   2990 
   2991 DynamicToolbarState nsPresContext::GetDynamicToolbarState() const {
   2992  if (!HasDynamicToolbar()) {
   2993    return DynamicToolbarState::None;
   2994  }
   2995  if (mDynamicToolbarMaxHeight == mDynamicToolbarHeight) {
   2996    return DynamicToolbarState::Expanded;
   2997  }
   2998  if (mDynamicToolbarHeight == 0) {
   2999    return DynamicToolbarState::Collapsed;
   3000  }
   3001  return DynamicToolbarState::InTransition;
   3002 }
   3003 
   3004 static CSSToScreenScale GetMVMScale(PresShell* aPS) {
   3005  if (aPS) {
   3006    if (RefPtr mvm = aPS->GetMobileViewportManager()) {
   3007      return mvm->GetZoom();
   3008    }
   3009  }
   3010  return CSSToScreenScale(1.0f);
   3011 }
   3012 
   3013 nscoord nsPresContext::GetDynamicToolbarMaxHeightInAppUnits() const {
   3014  if (mDynamicToolbarMaxHeight == 0) {
   3015    return 0;
   3016  }
   3017  return CSSPixel::ToAppUnits(
   3018      ScreenCoord(GetDynamicToolbarMaxHeight()) /
   3019      // For viewport units the dynamic toolbar height needs to be the height
   3020      // as if this document is scaled by 1.0 whatever the current zoom scale
   3021      // is.
   3022      (CSSToDevPixelScale() * LayoutDeviceToScreenScale(1.0)));
   3023 }
   3024 
   3025 nscoord nsPresContext::GetBimodalDynamicToolbarHeightInAppUnits() const {
   3026  if (mDynamicToolbarMaxHeight == 0) {
   3027    return 0;
   3028  }
   3029  return GetDynamicToolbarState() == DynamicToolbarState::Collapsed
   3030             ? CSSPixel::ToAppUnits(ScreenCoord(GetDynamicToolbarMaxHeight()) /
   3031                                    GetMVMScale(mPresShell))
   3032             : 0;
   3033 }
   3034 
   3035 void nsPresContext::SetSafeAreaInsets(
   3036    const LayoutDeviceIntMargin& aSafeAreaInsets) {
   3037  if (mSafeAreaInsets == aSafeAreaInsets) {
   3038    return;
   3039  }
   3040  mSafeAreaInsets = aSafeAreaInsets;
   3041 
   3042  PostRebuildAllStyleDataEvent(nsChangeHint(0),
   3043                               RestyleHint::RecascadeSubtree());
   3044 }
   3045 
   3046 PerformanceMainThread* nsPresContext::GetPerformanceMainThread() const {
   3047  if (nsPIDOMWindowInner* innerWindow = mDocument->GetInnerWindow()) {
   3048    if (auto* perf = static_cast<PerformanceMainThread*>(
   3049            innerWindow->GetPerformance())) {
   3050      return perf;
   3051    }
   3052  }
   3053  return nullptr;
   3054 }
   3055 
   3056 void nsPresContext::DoUpdateHiddenByContentVisibilityForAnimations() {
   3057  MOZ_ASSERT(NeedsToUpdateHiddenByContentVisibilityForAnimations());
   3058  mNeedsToUpdateHiddenByContentVisibilityForAnimations = false;
   3059  mDocument->UpdateHiddenByContentVisibilityForAnimations();
   3060 }
   3061 
   3062 #ifdef DEBUG
   3063 
   3064 void nsPresContext::ValidatePresShellAndDocumentReleation() const {
   3065  NS_ASSERTION(!mPresShell || !mPresShell->GetDocument() ||
   3066                   mPresShell->GetDocument() == mDocument,
   3067               "nsPresContext doesn't have the same document as nsPresShell!");
   3068 }
   3069 
   3070 #endif  // #ifdef DEBUG
   3071 
   3072 // FontVisibilityProvider implementation
   3073 FontVisibility nsPresContext::GetFontVisibility() const {
   3074  return mFontVisibility;
   3075 }
   3076 
   3077 bool nsPresContext::ShouldResistFingerprinting(RFPTarget aTarget) const {
   3078  return Document()->ShouldResistFingerprinting(aTarget);
   3079 }
   3080 
   3081 void nsPresContext::ReportBlockedFontFamily(const nsCString& aMsg) const {
   3082  MOZ_LOG(gFingerprinterDetection, LogLevel::Info, ("%s", aMsg.get()));
   3083  nsContentUtils::ReportToConsoleNonLocalized(NS_ConvertUTF8toUTF16(aMsg),
   3084                                              nsIScriptError::warningFlag,
   3085                                              "Security"_ns, Document());
   3086 }
   3087 
   3088 bool nsPresContext::IsPrivateBrowsing() const {
   3089  return Document()->IsInPrivateBrowsing();
   3090 }
   3091 
   3092 nsICookieJarSettings* nsPresContext::GetCookieJarSettings() const {
   3093  return Document()->CookieJarSettings();
   3094 }
   3095 
   3096 Maybe<FontVisibility> nsPresContext::MaybeInheritFontVisibility() const {
   3097  return Nothing();
   3098 }
   3099 
   3100 nsRootPresContext::nsRootPresContext(dom::Document* aDocument,
   3101                                     nsPresContextType aType)
   3102    : nsPresContext(aDocument, aType) {}
   3103 
   3104 void nsRootPresContext::AddWillPaintObserver(nsIRunnable* aRunnable) {
   3105  if (!mWillPaintFallbackEvent.IsPending()) {
   3106    mWillPaintFallbackEvent = new RunWillPaintObservers(this);
   3107    Document()->Dispatch(do_AddRef(mWillPaintFallbackEvent));
   3108  }
   3109  mWillPaintObservers.AppendElement(aRunnable);
   3110 }
   3111 
   3112 /**
   3113 * Run all runnables that need to get called before the next paint.
   3114 */
   3115 void nsRootPresContext::FlushWillPaintObservers() {
   3116  mWillPaintFallbackEvent = nullptr;
   3117  nsTArray<nsCOMPtr<nsIRunnable>> observers = std::move(mWillPaintObservers);
   3118  for (uint32_t i = 0; i < observers.Length(); ++i) {
   3119    observers[i]->Run();
   3120  }
   3121 }
   3122 
   3123 size_t nsRootPresContext::SizeOfExcludingThis(
   3124    MallocSizeOf aMallocSizeOf) const {
   3125  return nsPresContext::SizeOfExcludingThis(aMallocSizeOf);
   3126 
   3127  // Measurement of the following members may be added later if DMD finds it is
   3128  // worthwhile:
   3129  // - mWillPaintObservers
   3130  // - mWillPaintFallbackEvent
   3131 }