tor-browser

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

nsStyleStruct.cpp (146413B)


      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 /*
      8 * structs that contain the data provided by ComputedStyle, the
      9 * internal API for computed style data for an element
     10 */
     11 
     12 #include "nsStyleStruct.h"
     13 
     14 #include <algorithm>
     15 
     16 #include "AnchorPositioningUtils.h"
     17 #include "CounterStyleManager.h"
     18 #include "ImageLoader.h"
     19 #include "imgIContainer.h"
     20 #include "imgIRequest.h"
     21 #include "mozilla/CORSMode.h"
     22 #include "mozilla/ClearOnShutdown.h"
     23 #include "mozilla/GeckoBindings.h"
     24 #include "mozilla/Likely.h"
     25 #include "mozilla/PreferenceSheet.h"
     26 #include "mozilla/SchedulerGroup.h"
     27 #include "mozilla/StaticPrefs_layout.h"
     28 #include "mozilla/StaticPresData.h"
     29 #include "mozilla/dom/AnimationEffectBinding.h"    // for PlaybackDirection
     30 #include "mozilla/dom/BaseKeyframeTypesBinding.h"  // for CompositeOperation
     31 #include "mozilla/dom/DocGroup.h"
     32 #include "mozilla/dom/Document.h"
     33 #include "mozilla/dom/DocumentInlines.h"
     34 #include "nsBidiUtils.h"
     35 #include "nsCOMPtr.h"
     36 #include "nsCRTGlue.h"
     37 #include "nsCSSProps.h"
     38 #include "nsContainerFrame.h"
     39 #include "nsDeviceContext.h"
     40 #include "nsIURI.h"
     41 #include "nsIURIMutator.h"
     42 #include "nsIWidget.h"
     43 #include "nsLayoutUtils.h"
     44 #include "nsPresContext.h"
     45 #include "nsString.h"
     46 #include "nsStyleConsts.h"
     47 #include "nsStyleStructInlines.h"
     48 #include "nsStyleStructList.h"
     49 #include "nsStyleUtil.h"
     50 
     51 using namespace mozilla;
     52 using namespace mozilla::dom;
     53 
     54 MOZ_RUNINIT static const nscoord kMediumBorderWidth =
     55    nsPresContext::CSSPixelsToAppUnits(3);
     56 
     57 // We set the size limit of style structs to 504 bytes so that when they
     58 // are allocated by Servo side with Arc, the total size doesn't exceed
     59 // 512 bytes, which minimizes allocator slop.
     60 static constexpr size_t kStyleStructSizeLimit = 504;
     61 
     62 template <typename Struct, size_t Actual, size_t Limit>
     63 struct AssertSizeIsLessThan {
     64  static_assert(Actual == sizeof(Struct), "Bogus invocation");
     65  static_assert(Actual <= Limit,
     66                "Style struct became larger than the size limit");
     67  static constexpr bool instantiate = true;
     68 };
     69 
     70 #define ASSERT_SIZE(name_)                                                   \
     71  static_assert(AssertSizeIsLessThan<nsStyle##name_, sizeof(nsStyle##name_), \
     72                                     kStyleStructSizeLimit>::instantiate,    \
     73                "");
     74 FOR_EACH_STYLE_STRUCT(ASSERT_SIZE, ASSERT_SIZE)
     75 #undef ASSERT_SIZE
     76 
     77 bool StyleCssUrlData::operator==(const StyleCssUrlData& aOther) const {
     78  // This very intentionally avoids comparing LoadData and such.
     79  const auto& extra = extra_data.get();
     80  const auto& otherExtra = aOther.extra_data.get();
     81  if (extra.BaseURI() != otherExtra.BaseURI() ||
     82      extra.Principal() != otherExtra.Principal() ||
     83      cors_mode != aOther.cors_mode) {
     84    // NOTE(emilio): This does pointer comparison, but it's what URLValue used
     85    // to do. That's ok though since this is only used for style struct diffing.
     86    return false;
     87  }
     88  return serialization == aOther.serialization;
     89 }
     90 
     91 StyleLoadData::~StyleLoadData() { Gecko_LoadData_Drop(this); }
     92 
     93 void StyleComputedUrl::ResolveImage(Document& aDocument,
     94                                    const StyleComputedUrl* aOldImage) {
     95  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
     96 
     97  StyleLoadData& data = MutLoadData();
     98 
     99  MOZ_ASSERT(!(data.flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE));
    100 
    101  data.flags |= StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE;
    102 
    103  // TODO(emilio, bug 1440442): This is a hackaround to avoid flickering due the
    104  // lack of non-http image caching in imagelib (bug 1406134), which causes
    105  // stuff like bug 1439285. Cleanest fix if that doesn't get fixed is bug
    106  // 1440305, but that seems too risky, and a lot of work to do before 60.
    107  //
    108  // Once that's fixed, the "old style" argument to TriggerImageLoads can go
    109  // away, and same for mSharedCount in the image loader and so on.
    110  const bool reuseProxy = nsContentUtils::IsChromeDoc(&aDocument) &&
    111                          aOldImage && aOldImage->IsImageResolved() &&
    112                          *this == *aOldImage;
    113 
    114  RefPtr<imgRequestProxy> request;
    115  if (reuseProxy) {
    116    request = aOldImage->LoadData().resolved_image;
    117    if (request) {
    118      css::ImageLoader::NoteSharedLoad(request);
    119    }
    120  } else {
    121    request = css::ImageLoader::LoadImage(*this, aDocument);
    122  }
    123 
    124  if (!request) {
    125    return;
    126  }
    127 
    128  data.resolved_image = request.forget().take();
    129 
    130  // Boost priority now that we know the image is present in the ComputedStyle
    131  // of some frame.
    132  data.resolved_image->BoostPriority(imgIRequest::CATEGORY_FRAME_STYLE);
    133 }
    134 
    135 /**
    136 * Runnable to release the image request's mRequestProxy on the main thread, and
    137 * to perform any necessary unlocking and untracking of the image.
    138 */
    139 class StyleImageRequestCleanupTask final : public mozilla::Runnable {
    140 public:
    141  explicit StyleImageRequestCleanupTask(StyleLoadData& aData)
    142      : mozilla::Runnable("StyleImageRequestCleanupTask"),
    143        mRequestProxy(dont_AddRef(aData.resolved_image)) {
    144    MOZ_ASSERT(mRequestProxy);
    145    aData.resolved_image = nullptr;
    146  }
    147 
    148  NS_IMETHOD Run() final {
    149    MOZ_ASSERT(NS_IsMainThread());
    150    css::ImageLoader::UnloadImage(mRequestProxy);
    151    return NS_OK;
    152  }
    153 
    154 protected:
    155  virtual ~StyleImageRequestCleanupTask() {
    156    MOZ_ASSERT(!mRequestProxy || NS_IsMainThread(),
    157               "mRequestProxy destructor need to run on the main thread!");
    158  }
    159 
    160 private:
    161  // Since we always dispatch this runnable to the main thread, these will be
    162  // released on the main thread when the runnable itself is released.
    163  RefPtr<imgRequestProxy> mRequestProxy;
    164 };
    165 
    166 // This is defined here for parallelism with LoadURI.
    167 void Gecko_LoadData_Drop(StyleLoadData* aData) {
    168  if (aData->resolved_image) {
    169    // We want to dispatch this async to prevent reentrancy issues, as
    170    // imgRequestProxy going away can destroy documents, etc, see bug 1677555.
    171    auto task = MakeRefPtr<StyleImageRequestCleanupTask>(*aData);
    172    SchedulerGroup::Dispatch(task.forget());
    173  }
    174 
    175  // URIs are safe to refcount from any thread.
    176  NS_IF_RELEASE(aData->resolved_uri);
    177 }
    178 
    179 // --------------------
    180 // nsStyleFont
    181 //
    182 nsStyleFont::nsStyleFont(const nsStyleFont& aSrc)
    183    : mFont(aSrc.mFont),
    184      mSize(aSrc.mSize),
    185      mFontSizeFactor(aSrc.mFontSizeFactor),
    186      mFontSizeOffset(aSrc.mFontSizeOffset),
    187      mFontSizeKeyword(aSrc.mFontSizeKeyword),
    188      mFontPalette(aSrc.mFontPalette),
    189      mMathDepth(aSrc.mMathDepth),
    190      mLineHeight(aSrc.mLineHeight),
    191      mMinFontSizeRatio(aSrc.mMinFontSizeRatio),
    192      mMathVariant(aSrc.mMathVariant),
    193      mMathStyle(aSrc.mMathStyle),
    194      mMathShift(aSrc.mMathShift),
    195      mExplicitLanguage(aSrc.mExplicitLanguage),
    196      mXTextScale(aSrc.mXTextScale),
    197      mScriptUnconstrainedSize(aSrc.mScriptUnconstrainedSize),
    198      mScriptMinSize(aSrc.mScriptMinSize),
    199      mLanguage(aSrc.mLanguage) {
    200  MOZ_COUNT_CTOR(nsStyleFont);
    201 }
    202 
    203 static StyleXTextScale InitialTextScale(const Document& aDoc) {
    204  if (nsContentUtils::IsChromeDoc(&aDoc) ||
    205      nsContentUtils::IsPDFJS(aDoc.NodePrincipal())) {
    206    return StyleXTextScale::ZoomOnly;
    207  }
    208  return StyleXTextScale::All;
    209 }
    210 
    211 nsStyleFont::nsStyleFont(const Document& aDocument)
    212    : mFont(*aDocument.GetFontPrefsForLang(nullptr)->GetDefaultFont(
    213          StyleGenericFontFamily::None)),
    214      mSize(ZoomText(aDocument, mFont.size)),
    215      mFontSizeFactor(1.0),
    216      mFontSizeOffset{0},
    217      mFontSizeKeyword(StyleFontSizeKeyword::Medium),
    218      mFontPalette(StyleFontPalette::Normal()),
    219      mMathDepth(0),
    220      mLineHeight(StyleLineHeight::Normal()),
    221      mMathVariant(StyleMathVariant::None),
    222      mMathStyle(StyleMathStyle::Normal),
    223      mMathShift(StyleMathShift::Normal),
    224      mXTextScale(InitialTextScale(aDocument)),
    225      mScriptUnconstrainedSize(mSize),
    226      mScriptMinSize(Length::FromPixels(
    227          CSSPixel::FromPoints(kMathMLDefaultScriptMinSizePt))),
    228      mLanguage(aDocument.GetLanguageForStyle()) {
    229  MOZ_COUNT_CTOR(nsStyleFont);
    230  MOZ_ASSERT(NS_IsMainThread());
    231  mFont.family.is_initial = true;
    232  mFont.size = mSize;
    233  if (MinFontSizeEnabled()) {
    234    const Length minimumFontSize =
    235        aDocument.GetFontPrefsForLang(mLanguage)->mMinimumFontSize;
    236    mFont.size = Length::FromPixels(
    237        std::max(mSize.ToCSSPixels(), minimumFontSize.ToCSSPixels()));
    238  }
    239 }
    240 
    241 nsChangeHint nsStyleFont::CalcDifference(const nsStyleFont& aNewData) const {
    242  MOZ_ASSERT(mXTextScale == aNewData.mXTextScale,
    243             "expected -x-text-scale to be the same on both nsStyleFonts");
    244  if (mSize != aNewData.mSize || mLanguage != aNewData.mLanguage ||
    245      mExplicitLanguage != aNewData.mExplicitLanguage ||
    246      mMathVariant != aNewData.mMathVariant ||
    247      mMathStyle != aNewData.mMathStyle || mMathShift != aNewData.mMathShift ||
    248      mMinFontSizeRatio != aNewData.mMinFontSizeRatio ||
    249      mLineHeight != aNewData.mLineHeight) {
    250    return NS_STYLE_HINT_REFLOW;
    251  }
    252 
    253  switch (mFont.CalcDifference(aNewData.mFont)) {
    254    case nsFont::MaxDifference::eLayoutAffecting:
    255      return NS_STYLE_HINT_REFLOW;
    256 
    257    case nsFont::MaxDifference::eVisual:
    258      return NS_STYLE_HINT_VISUAL;
    259 
    260    case nsFont::MaxDifference::eNone:
    261      break;
    262  }
    263 
    264  if (mFontPalette != aNewData.mFontPalette) {
    265    return NS_STYLE_HINT_VISUAL;
    266  }
    267 
    268  // XXX Should any of these cause a non-nsChangeHint_NeutralChange change?
    269  if (mMathDepth != aNewData.mMathDepth ||
    270      mScriptUnconstrainedSize != aNewData.mScriptUnconstrainedSize ||
    271      mScriptMinSize != aNewData.mScriptMinSize) {
    272    return nsChangeHint_NeutralChange;
    273  }
    274 
    275  return nsChangeHint(0);
    276 }
    277 
    278 Length nsStyleFont::ZoomText(const Document& aDocument, Length aSize) {
    279  if (auto* pc = aDocument.GetPresContext()) {
    280    aSize.ScaleBy(pc->TextZoom());
    281  }
    282  return aSize;
    283 }
    284 
    285 template <typename T>
    286 static StyleRect<T> StyleRectWithAllSides(const T& aSide) {
    287  return {aSide, aSide, aSide, aSide};
    288 }
    289 
    290 bool AnchorPosResolutionParams::AutoResolutionOverrideParams::OverriddenToZero(
    291    StylePhysicalAxis aAxis) const {
    292  if (mPositionAreaInUse) {
    293    // If `position-area` is used "Any auto inset properties resolve to 0":
    294    // https://drafts.csswg.org/css-anchor-position-1/#valdef-position-area-position-area
    295    return true;
    296  }
    297 
    298  // If `anchor-center` is used with a valid anchor, "auto inset
    299  // properties resolve to 0" on that axis:
    300  // https://drafts.csswg.org/css-anchor-position-1/#anchor-center
    301  if (aAxis == StylePhysicalAxis::Vertical) {
    302    return mVAnchorCenter;
    303  }
    304  MOZ_ASSERT(aAxis == StylePhysicalAxis::Horizontal);
    305  return mHAnchorCenter;
    306 }
    307 
    308 static AnchorPosResolutionParams::AutoResolutionOverrideParams
    309 GetAutoResolutionOverrideParams(const nsIFrame* aFrame,
    310                                bool aDefaultAnchorValid) {
    311  if (!aFrame) {
    312    return {};
    313  }
    314  nsIFrame* parent = aFrame->GetParent();
    315  if (!parent || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) ||
    316      !aDefaultAnchorValid) {
    317    return {};
    318  }
    319 
    320  const auto* stylePos = aFrame->StylePosition();
    321  const auto cbwm = parent->GetWritingMode();
    322 
    323  auto checkAxis = [&](LogicalAxis aAxis) {
    324    StyleAlignFlags alignment =
    325        stylePos->UsedSelfAlignment(aAxis, parent->Style());
    326    return (alignment & ~StyleAlignFlags::FLAG_BITS) ==
    327           StyleAlignFlags::ANCHOR_CENTER;
    328  };
    329 
    330  const auto horizontalLogicalAxis =
    331      cbwm.IsVertical() ? LogicalAxis::Block : LogicalAxis::Inline;
    332  AnchorPosResolutionParams::AutoResolutionOverrideParams result;
    333  result.mHAnchorCenter = checkAxis(horizontalLogicalAxis);
    334  result.mVAnchorCenter = checkAxis(GetOrthogonalAxis(horizontalLogicalAxis));
    335  result.mPositionAreaInUse = !stylePos->mPositionArea.IsNone();
    336  return result;
    337 }
    338 
    339 AnchorPosResolutionParams::AutoResolutionOverrideParams::
    340    AutoResolutionOverrideParams(
    341        const nsIFrame* aFrame, const mozilla::AnchorPosResolutionCache* aCache)
    342    : AutoResolutionOverrideParams{GetAutoResolutionOverrideParams(
    343          aFrame, aCache && aCache->mDefaultAnchorCache.mAnchor)} {}
    344 
    345 AnchorPosResolutionParams::AutoResolutionOverrideParams::
    346    AutoResolutionOverrideParams(const nsIFrame* aFrame)
    347    : AutoResolutionOverrideParams{
    348          GetAutoResolutionOverrideParams(aFrame, [&]() {
    349            if (!aFrame) {
    350              return false;
    351            }
    352            const auto* references =
    353                aFrame->GetProperty(nsIFrame::AnchorPosReferences());
    354            if (!references || !references->mDefaultAnchorName) {
    355              // It is presumed that this is called on a reflowed frame.
    356              return false;
    357            }
    358            return references->Lookup(references->mDefaultAnchorName)->isSome();
    359          }())} {}
    360 
    361 AnchorResolvedMargin AnchorResolvedMarginHelper::ResolveAnchor(
    362    const StyleMargin& aValue, StylePhysicalAxis aAxis,
    363    const AnchorPosResolutionParams& aParams) {
    364  MOZ_ASSERT(aValue.HasAnchorPositioningFunction(),
    365             "Calling anchor resolution without using it?");
    366  if (aValue.IsAnchorSizeFunction()) {
    367    auto resolved = StyleAnchorPositioningFunctionResolution::Invalid();
    368    Servo_ResolveAnchorSizeFunctionForMargin(&*aValue.AsAnchorSizeFunction(),
    369                                             &aParams, aAxis, &resolved);
    370    if (resolved.IsInvalid()) {
    371      return Zero();
    372    }
    373    if (resolved.IsResolvedReference()) {
    374      return MakeUniqueOfUniqueOrNonOwning<const StyleMargin>(
    375          *resolved.AsResolvedReference());
    376    }
    377    return MakeUniqueOfUniqueOrNonOwning<const StyleMargin>(
    378        resolved.AsResolved());
    379  }
    380 
    381  const auto& lp = aValue.AsAnchorContainingCalcFunction();
    382  const auto& c = lp.AsCalc();
    383  auto result = StyleCalcAnchorPositioningFunctionResolution::Invalid();
    384  AnchorPosOffsetResolutionParams params =
    385      AnchorPosOffsetResolutionParams::UseCBFrameSize(aParams);
    386  const auto allowed =
    387      StyleAllowAnchorPosResolutionInCalcPercentage::AnchorSizeOnly(aAxis);
    388  Servo_ResolveAnchorFunctionsInCalcPercentage(&c, &allowed, &params, &result);
    389  if (result.IsInvalid()) {
    390    return Zero();
    391  }
    392  return MakeUniqueOfUniqueOrNonOwning<const StyleMargin>(result.AsValid());
    393 }
    394 
    395 nsStyleMargin::nsStyleMargin()
    396    : mMargin(StyleRectWithAllSides(
    397          StyleMargin::LengthPercentage(LengthPercentage::Zero()))),
    398      mScrollMargin(StyleRectWithAllSides(StyleLength{0.})),
    399      mOverflowClipMargin(
    400          {StyleLength::Zero(), StyleOverflowClipMarginBox::PaddingBox}) {
    401  MOZ_COUNT_CTOR(nsStyleMargin);
    402 }
    403 
    404 nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc)
    405    : mMargin(aSrc.mMargin),
    406      mScrollMargin(aSrc.mScrollMargin),
    407      mOverflowClipMargin(aSrc.mOverflowClipMargin) {
    408  MOZ_COUNT_CTOR(nsStyleMargin);
    409 }
    410 
    411 nsChangeHint nsStyleMargin::CalcDifference(
    412    const nsStyleMargin& aNewData) const {
    413  nsChangeHint hint = nsChangeHint(0);
    414 
    415  if (!MarginEquals(aNewData)) {
    416    // Margin differences can't affect descendant intrinsic sizes and
    417    // don't need to force children to reflow.
    418    hint |= nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition |
    419            nsChangeHint_ClearAncestorIntrinsics;
    420  }
    421 
    422  if (mScrollMargin != aNewData.mScrollMargin) {
    423    // FIXME: Bug 1530253 Support re-snapping when scroll-margin changes.
    424    hint |= nsChangeHint_NeutralChange;
    425  }
    426 
    427  if (mOverflowClipMargin != aNewData.mOverflowClipMargin) {
    428    hint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
    429  }
    430 
    431  return hint;
    432 }
    433 
    434 nsStylePadding::nsStylePadding()
    435    : mPadding(StyleRectWithAllSides(LengthPercentage::Zero())),
    436      mScrollPadding(StyleRectWithAllSides(LengthPercentageOrAuto::Auto())) {
    437  MOZ_COUNT_CTOR(nsStylePadding);
    438 }
    439 
    440 nsStylePadding::nsStylePadding(const nsStylePadding& aSrc)
    441    : mPadding(aSrc.mPadding), mScrollPadding(aSrc.mScrollPadding) {
    442  MOZ_COUNT_CTOR(nsStylePadding);
    443 }
    444 
    445 nsChangeHint nsStylePadding::CalcDifference(
    446    const nsStylePadding& aNewData) const {
    447  nsChangeHint hint = nsChangeHint(0);
    448 
    449  if (mPadding != aNewData.mPadding) {
    450    // Padding differences can't affect descendant intrinsic sizes, but do need
    451    // to force children to reflow so that we can reposition them, since their
    452    // offsets are from our frame bounds but our content rect's position within
    453    // those bounds is moving.
    454    // FIXME: It would be good to return a weaker hint here that doesn't
    455    // force reflow of all descendants, but the hint would need to force
    456    // reflow of the frame's children (see how
    457    // ReflowInput::InitResizeFlags initializes the inline-resize flag).
    458    hint |= NS_STYLE_HINT_REFLOW & ~nsChangeHint_ClearDescendantIntrinsics;
    459  }
    460 
    461  if (mScrollPadding != aNewData.mScrollPadding) {
    462    // FIXME: Bug 1530253 Support re-snapping when scroll-padding changes.
    463    hint |= nsChangeHint_NeutralChange;
    464  }
    465 
    466  return hint;
    467 }
    468 
    469 static inline BorderRadius ZeroBorderRadius() {
    470  auto zero = LengthPercentage::Zero();
    471  return {{{zero, zero}}, {{zero, zero}}, {{zero, zero}}, {{zero, zero}}};
    472 }
    473 
    474 nsStyleBorder::nsStyleBorder()
    475    : mBorderRadius(ZeroBorderRadius()),
    476      mBorderImageSource(StyleImage::None()),
    477      mBorderImageWidth(
    478          StyleRectWithAllSides(StyleBorderImageSideWidth::Number(1.))),
    479      mBorderImageOutset(
    480          StyleRectWithAllSides(StyleNonNegativeLengthOrNumber::Number(0.))),
    481      mBorderImageSlice(
    482          {StyleRectWithAllSides(StyleNumberOrPercentage::Percentage({1.})),
    483           false}),
    484      mBorderImageRepeat{StyleBorderImageRepeatKeyword::Stretch,
    485                         StyleBorderImageRepeatKeyword::Stretch},
    486      mFloatEdge(StyleFloatEdge::ContentBox),
    487      mBoxDecorationBreak(StyleBoxDecorationBreak::Slice),
    488      mBorderStyle(StyleRectWithAllSides(StyleBorderStyle::None)),
    489      mBorder(StyleRectWithAllSides(kMediumBorderWidth)),
    490      mBorderTopColor(StyleColor::CurrentColor()),
    491      mBorderRightColor(StyleColor::CurrentColor()),
    492      mBorderBottomColor(StyleColor::CurrentColor()),
    493      mBorderLeftColor(StyleColor::CurrentColor()) {
    494  MOZ_COUNT_CTOR(nsStyleBorder);
    495 }
    496 
    497 nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
    498    : mBorderRadius(aSrc.mBorderRadius),
    499      mBorderImageSource(aSrc.mBorderImageSource),
    500      mBorderImageWidth(aSrc.mBorderImageWidth),
    501      mBorderImageOutset(aSrc.mBorderImageOutset),
    502      mBorderImageSlice(aSrc.mBorderImageSlice),
    503      mBorderImageRepeat(aSrc.mBorderImageRepeat),
    504      mFloatEdge(aSrc.mFloatEdge),
    505      mBoxDecorationBreak(aSrc.mBoxDecorationBreak),
    506      mBorderStyle(aSrc.mBorderStyle),
    507      mBorder(aSrc.mBorder),
    508      mBorderTopColor(aSrc.mBorderTopColor),
    509      mBorderRightColor(aSrc.mBorderRightColor),
    510      mBorderBottomColor(aSrc.mBorderBottomColor),
    511      mBorderLeftColor(aSrc.mBorderLeftColor) {
    512  MOZ_COUNT_CTOR(nsStyleBorder);
    513 }
    514 
    515 void nsStyleBorder::TriggerImageLoads(Document& aDocument,
    516                                      const nsStyleBorder* aOldStyle) {
    517  MOZ_ASSERT(NS_IsMainThread());
    518 
    519  mBorderImageSource.ResolveImage(
    520      aDocument, aOldStyle ? &aOldStyle->mBorderImageSource : nullptr);
    521 }
    522 
    523 nsMargin nsStyleBorder::GetImageOutset() const {
    524  // We don't check whether there is a border-image (which is OK since
    525  // the initial values yields 0 outset) so that we don't have to
    526  // reflow to update overflow areas when an image loads.
    527  nsMargin outset;
    528  auto computedBorder = GetComputedBorder();
    529  for (const auto s : mozilla::AllPhysicalSides()) {
    530    const auto& coord = mBorderImageOutset.Get(s);
    531    nscoord value;
    532    if (coord.IsLength()) {
    533      value = coord.AsLength().ToAppUnits();
    534    } else {
    535      MOZ_ASSERT(coord.IsNumber());
    536      value = coord.AsNumber() * computedBorder.Side(s);
    537    }
    538    outset.Side(s) = value;
    539  }
    540  return outset;
    541 }
    542 
    543 nsChangeHint nsStyleBorder::CalcDifference(
    544    const nsStyleBorder& aNewData) const {
    545  // FIXME: XXXbz: As in nsStylePadding::CalcDifference, many of these
    546  // differences should not need to clear descendant intrinsics.
    547  // FIXME: It would be good to return a weaker hint for the
    548  // GetComputedBorder() differences (and perhaps others) that doesn't
    549  // force reflow of all descendants, but the hint would need to force
    550  // reflow of the frame's children (see how
    551  // ReflowInput::InitResizeFlags initializes the inline-resize flag).
    552  if (GetComputedBorder() != aNewData.GetComputedBorder() ||
    553      mFloatEdge != aNewData.mFloatEdge ||
    554      mBorderImageOutset != aNewData.mBorderImageOutset ||
    555      mBoxDecorationBreak != aNewData.mBoxDecorationBreak) {
    556    return NS_STYLE_HINT_REFLOW;
    557  }
    558 
    559  for (const auto ix : mozilla::AllPhysicalSides()) {
    560    if (mBorderStyle.Get(ix) != aNewData.mBorderStyle.Get(ix) ||
    561        BorderColorFor(ix) != aNewData.BorderColorFor(ix)) {
    562      return nsChangeHint_RepaintFrame;
    563    }
    564  }
    565 
    566  // Note that border radius also controls the outline radius if the
    567  // layout.css.outline-follows-border-radius.enabled pref is set. Any
    568  // optimizations here should apply to both.
    569  if (mBorderRadius != aNewData.mBorderRadius) {
    570    return nsChangeHint_RepaintFrame;
    571  }
    572 
    573  // Loading status of the border image can be accessed in main thread only
    574  // while CalcDifference might be executed on a background thread. As a
    575  // result, we have to check mBorderImage* fields even before border image was
    576  // actually loaded.
    577  if (!mBorderImageSource.IsNone() || !aNewData.mBorderImageSource.IsNone()) {
    578    if (mBorderImageSource != aNewData.mBorderImageSource ||
    579        mBorderImageRepeat != aNewData.mBorderImageRepeat ||
    580        mBorderImageSlice != aNewData.mBorderImageSlice ||
    581        mBorderImageWidth != aNewData.mBorderImageWidth) {
    582      return nsChangeHint_RepaintFrame;
    583    }
    584  }
    585 
    586  // mBorder is the specified border value.  Changes to this don't
    587  // need any change processing, since we operate on the computed
    588  // border values instead.
    589  // mBorderImage* fields are checked only when border-image is not 'none'.
    590  if (mBorder != aNewData.mBorder ||
    591      mBorderImageSource != aNewData.mBorderImageSource ||
    592      mBorderImageRepeat != aNewData.mBorderImageRepeat ||
    593      mBorderImageSlice != aNewData.mBorderImageSlice ||
    594      mBorderImageWidth != aNewData.mBorderImageWidth) {
    595    return nsChangeHint_NeutralChange;
    596  }
    597 
    598  return nsChangeHint(0);
    599 }
    600 
    601 nsStyleOutline::nsStyleOutline()
    602    : mOutlineWidth(kMediumBorderWidth),
    603      mOutlineOffset(0),
    604      mOutlineColor(StyleColor::CurrentColor()),
    605      mOutlineStyle(StyleOutlineStyle::BorderStyle(StyleBorderStyle::None)) {
    606  MOZ_COUNT_CTOR(nsStyleOutline);
    607 }
    608 
    609 nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc)
    610    : mOutlineWidth(aSrc.mOutlineWidth),
    611      mOutlineOffset(aSrc.mOutlineOffset),
    612      mOutlineColor(aSrc.mOutlineColor),
    613      mOutlineStyle(aSrc.mOutlineStyle) {
    614  MOZ_COUNT_CTOR(nsStyleOutline);
    615 }
    616 
    617 nsChangeHint nsStyleOutline::CalcDifference(
    618    const nsStyleOutline& aNewData) const {
    619  const bool shouldPaintOutline = ShouldPaintOutline();
    620  // We need the explicit 'outline-style: auto' check because
    621  // 'outline-style: auto' effectively also changes 'outline-width'.
    622  if (shouldPaintOutline != aNewData.ShouldPaintOutline() ||
    623      mOutlineWidth != aNewData.mOutlineWidth ||
    624      mOutlineStyle.IsAuto() != aNewData.mOutlineStyle.IsAuto() ||
    625      (shouldPaintOutline && mOutlineOffset != aNewData.mOutlineOffset)) {
    626    return nsChangeHint_UpdateOverflow | nsChangeHint_SchedulePaint |
    627           nsChangeHint_RepaintFrame;
    628  }
    629 
    630  if (mOutlineStyle != aNewData.mOutlineStyle ||
    631      mOutlineColor != aNewData.mOutlineColor) {
    632    return shouldPaintOutline ? nsChangeHint_RepaintFrame
    633                              : nsChangeHint_NeutralChange;
    634  }
    635 
    636  if (mOutlineWidth != aNewData.mOutlineWidth ||
    637      mOutlineOffset != aNewData.mOutlineOffset) {
    638    return nsChangeHint_NeutralChange;
    639  }
    640 
    641  return nsChangeHint(0);
    642 }
    643 
    644 nsSize nsStyleOutline::EffectiveOffsetFor(const nsRect& aRect) const {
    645  const nscoord offset = mOutlineOffset;
    646  if (offset >= 0) {
    647    // Fast path for non-negative offset values
    648    return nsSize(offset, offset);
    649  }
    650 
    651  return nsSize(std::max(offset, -(aRect.Width() / 2)),
    652                std::max(offset, -(aRect.Height() / 2)));
    653 }
    654 
    655 // --------------------
    656 // nsStyleList
    657 //
    658 nsStyleList::nsStyleList()
    659    : mListStylePosition(StyleListStylePosition::Outside),
    660      mListStyleType(StyleCounterStyle::Name({StyleAtom(nsGkAtoms::disc)})),
    661      mQuotes(StyleQuotes::Auto()),
    662      mListStyleImage(StyleImage::None()) {
    663  MOZ_COUNT_CTOR(nsStyleList);
    664  MOZ_ASSERT(NS_IsMainThread());
    665 }
    666 
    667 nsStyleList::nsStyleList(const nsStyleList& aSource)
    668    : mListStylePosition(aSource.mListStylePosition),
    669      mListStyleType(aSource.mListStyleType),
    670      mQuotes(aSource.mQuotes),
    671      mListStyleImage(aSource.mListStyleImage) {
    672  MOZ_COUNT_CTOR(nsStyleList);
    673 }
    674 
    675 void nsStyleList::TriggerImageLoads(Document& aDocument,
    676                                    const nsStyleList* aOldStyle) {
    677  MOZ_ASSERT(NS_IsMainThread());
    678  mListStyleImage.ResolveImage(
    679      aDocument, aOldStyle ? &aOldStyle->mListStyleImage : nullptr);
    680 }
    681 
    682 nsChangeHint nsStyleList::CalcDifference(const nsStyleList& aNewData,
    683                                         const ComputedStyle& aOldStyle) const {
    684  // If the quotes implementation is ever going to change we might not need
    685  // a framechange here and a reflow should be sufficient.  See bug 35768.
    686  if (mQuotes != aNewData.mQuotes) {
    687    return nsChangeHint_ReconstructFrame;
    688  }
    689  nsChangeHint hint = nsChangeHint(0);
    690  // Only elements whose display value is list-item can be affected by
    691  // list-style-{position,type,image}. This also relies on that when the display
    692  // value changes from something else to list-item, that change itself would
    693  // cause ReconstructFrame.
    694  if (mListStylePosition != aNewData.mListStylePosition ||
    695      mListStyleType != aNewData.mListStyleType ||
    696      mListStyleImage != aNewData.mListStyleImage) {
    697    if (aOldStyle.StyleDisplay()->IsListItem()) {
    698      return nsChangeHint_ReconstructFrame;
    699    }
    700    // list-style-image may affect nsImageFrame for XUL elements, but that is
    701    // dealt with explicitly in nsImageFrame::DidSetComputedStyle.
    702    hint = nsChangeHint_NeutralChange;
    703  }
    704  return hint;
    705 }
    706 
    707 // --------------------
    708 // nsStyleXUL
    709 //
    710 nsStyleXUL::nsStyleXUL()
    711    : mBoxFlex(0.0f),
    712      mBoxOrdinal(1),
    713      mBoxAlign(StyleBoxAlign::Stretch),
    714      mBoxDirection(StyleBoxDirection::Normal),
    715      mBoxOrient(StyleBoxOrient::Horizontal),
    716      mBoxPack(StyleBoxPack::Start) {
    717  MOZ_COUNT_CTOR(nsStyleXUL);
    718 }
    719 
    720 nsStyleXUL::nsStyleXUL(const nsStyleXUL& aSource)
    721    : mBoxFlex(aSource.mBoxFlex),
    722      mBoxOrdinal(aSource.mBoxOrdinal),
    723      mBoxAlign(aSource.mBoxAlign),
    724      mBoxDirection(aSource.mBoxDirection),
    725      mBoxOrient(aSource.mBoxOrient),
    726      mBoxPack(aSource.mBoxPack) {
    727  MOZ_COUNT_CTOR(nsStyleXUL);
    728 }
    729 
    730 nsChangeHint nsStyleXUL::CalcDifference(const nsStyleXUL& aNewData) const {
    731  if (mBoxAlign == aNewData.mBoxAlign &&
    732      mBoxDirection == aNewData.mBoxDirection &&
    733      mBoxFlex == aNewData.mBoxFlex && mBoxOrient == aNewData.mBoxOrient &&
    734      mBoxPack == aNewData.mBoxPack && mBoxOrdinal == aNewData.mBoxOrdinal) {
    735    return nsChangeHint(0);
    736  }
    737  if (mBoxOrdinal != aNewData.mBoxOrdinal) {
    738    return nsChangeHint_ReconstructFrame;
    739  }
    740  return NS_STYLE_HINT_REFLOW;
    741 }
    742 
    743 // --------------------
    744 // nsStyleColumn
    745 //
    746 
    747 nsStyleColumn::nsStyleColumn()
    748    : mColumnWidth(LengthOrAuto::Auto()),
    749      mColumnRuleColor(StyleColor::CurrentColor()),
    750      mColumnRuleStyle(StyleBorderStyle::None),
    751      mColumnRuleWidth(kMediumBorderWidth) {
    752  MOZ_COUNT_CTOR(nsStyleColumn);
    753 }
    754 
    755 nsStyleColumn::nsStyleColumn(const nsStyleColumn& aSource)
    756    : mColumnCount(aSource.mColumnCount),
    757      mColumnWidth(aSource.mColumnWidth),
    758      mColumnRuleColor(aSource.mColumnRuleColor),
    759      mColumnRuleStyle(aSource.mColumnRuleStyle),
    760      mColumnFill(aSource.mColumnFill),
    761      mColumnSpan(aSource.mColumnSpan),
    762      mColumnRuleWidth(aSource.mColumnRuleWidth) {
    763  MOZ_COUNT_CTOR(nsStyleColumn);
    764 }
    765 
    766 nsChangeHint nsStyleColumn::CalcDifference(
    767    const nsStyleColumn& aNewData) const {
    768  if (mColumnWidth.IsAuto() != aNewData.mColumnWidth.IsAuto() ||
    769      mColumnCount != aNewData.mColumnCount ||
    770      mColumnSpan != aNewData.mColumnSpan) {
    771    // We force column count changes to do a reframe, because it's tricky to
    772    // handle some edge cases where the column count gets smaller and content
    773    // overflows.
    774    // XXX not ideal
    775    return nsChangeHint_ReconstructFrame;
    776  }
    777 
    778  if (mColumnWidth != aNewData.mColumnWidth ||
    779      mColumnFill != aNewData.mColumnFill) {
    780    return NS_STYLE_HINT_REFLOW;
    781  }
    782 
    783  if (mColumnRuleWidth != aNewData.mColumnRuleWidth ||
    784      mColumnRuleStyle != aNewData.mColumnRuleStyle ||
    785      mColumnRuleColor != aNewData.mColumnRuleColor) {
    786    return NS_STYLE_HINT_VISUAL;
    787  }
    788 
    789  return nsChangeHint(0);
    790 }
    791 
    792 using SVGPaintFallback = StyleGenericSVGPaintFallback<StyleColor>;
    793 
    794 // --------------------
    795 // nsStyleSVG
    796 //
    797 nsStyleSVG::nsStyleSVG()
    798    : mFill{StyleSVGPaintKind::Color(StyleColor::Black()),
    799            SVGPaintFallback::Unset()},
    800      mStroke{StyleSVGPaintKind::None(), SVGPaintFallback::Unset()},
    801      mMarkerEnd(StyleUrlOrNone::None()),
    802      mMarkerMid(StyleUrlOrNone::None()),
    803      mMarkerStart(StyleUrlOrNone::None()),
    804      mMozContextProperties{{}, {0}},
    805      mStrokeDasharray(StyleSVGStrokeDashArray::Values({})),
    806      mStrokeDashoffset(
    807          StyleSVGLength::LengthPercentage(LengthPercentage::Zero())),
    808      mStrokeWidth(
    809          StyleSVGWidth::LengthPercentage(LengthPercentage::FromPixels(1.0f))),
    810      mFillOpacity(StyleSVGOpacity::Opacity(1.0f)),
    811      mStrokeMiterlimit(4.0f),
    812      mStrokeOpacity(StyleSVGOpacity::Opacity(1.0f)),
    813      mClipRule(StyleFillRule::Nonzero),
    814      mColorInterpolation(StyleColorInterpolation::Srgb),
    815      mColorInterpolationFilters(StyleColorInterpolation::Linearrgb),
    816      mFillRule(StyleFillRule::Nonzero),
    817      mPaintOrder(0),
    818      mShapeRendering(StyleShapeRendering::Auto),
    819      mStrokeLinecap(StyleStrokeLinecap::Butt),
    820      mStrokeLinejoin(StyleStrokeLinejoin::Miter),
    821      mDominantBaseline(StyleDominantBaseline::Auto),
    822      mTextAnchor(StyleTextAnchor::Start) {
    823  MOZ_COUNT_CTOR(nsStyleSVG);
    824 }
    825 
    826 nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
    827    : mFill(aSource.mFill),
    828      mStroke(aSource.mStroke),
    829      mMarkerEnd(aSource.mMarkerEnd),
    830      mMarkerMid(aSource.mMarkerMid),
    831      mMarkerStart(aSource.mMarkerStart),
    832      mMozContextProperties(aSource.mMozContextProperties),
    833      mStrokeDasharray(aSource.mStrokeDasharray),
    834      mStrokeDashoffset(aSource.mStrokeDashoffset),
    835      mStrokeWidth(aSource.mStrokeWidth),
    836      mFillOpacity(aSource.mFillOpacity),
    837      mStrokeMiterlimit(aSource.mStrokeMiterlimit),
    838      mStrokeOpacity(aSource.mStrokeOpacity),
    839      mClipRule(aSource.mClipRule),
    840      mColorInterpolation(aSource.mColorInterpolation),
    841      mColorInterpolationFilters(aSource.mColorInterpolationFilters),
    842      mFillRule(aSource.mFillRule),
    843      mPaintOrder(aSource.mPaintOrder),
    844      mShapeRendering(aSource.mShapeRendering),
    845      mStrokeLinecap(aSource.mStrokeLinecap),
    846      mStrokeLinejoin(aSource.mStrokeLinejoin),
    847      mDominantBaseline(aSource.mDominantBaseline),
    848      mTextAnchor(aSource.mTextAnchor) {
    849  MOZ_COUNT_CTOR(nsStyleSVG);
    850 }
    851 
    852 static bool PaintURIChanged(const StyleSVGPaint& aPaint1,
    853                            const StyleSVGPaint& aPaint2) {
    854  if (aPaint1.kind.IsPaintServer() != aPaint2.kind.IsPaintServer()) {
    855    return true;
    856  }
    857  return aPaint1.kind.IsPaintServer() &&
    858         aPaint1.kind.AsPaintServer() != aPaint2.kind.AsPaintServer();
    859 }
    860 
    861 nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aNewData) const {
    862  nsChangeHint hint = nsChangeHint(0);
    863 
    864  if (mMarkerEnd != aNewData.mMarkerEnd || mMarkerMid != aNewData.mMarkerMid ||
    865      mMarkerStart != aNewData.mMarkerStart) {
    866    // Markers currently contribute to SVGGeometryFrame::mRect,
    867    // so we need a reflow as well as a repaint. No intrinsic sizes need
    868    // to change, so nsChangeHint_NeedReflow is sufficient.
    869    return nsChangeHint_UpdateEffects | nsChangeHint_NeedReflow |
    870           nsChangeHint_RepaintFrame;
    871  }
    872 
    873  if (mFill != aNewData.mFill || mStroke != aNewData.mStroke ||
    874      mFillOpacity != aNewData.mFillOpacity ||
    875      mStrokeOpacity != aNewData.mStrokeOpacity) {
    876    hint |= nsChangeHint_RepaintFrame;
    877    if (HasStroke() != aNewData.HasStroke() ||
    878        (!HasStroke() && HasFill() != aNewData.HasFill())) {
    879      // Frame bounds and overflow rects depend on whether we "have" fill or
    880      // stroke. Whether we have stroke or not just changed, or else we have no
    881      // stroke (in which case whether we have fill or not is significant to
    882      // frame bounds) and whether we have fill or not just changed. In either
    883      // case we need to reflow so the frame rect is updated.
    884      // XXXperf this is a waste on non SVGGeometryFrames.
    885      hint |= nsChangeHint_NeedReflow;
    886    }
    887    if (PaintURIChanged(mFill, aNewData.mFill) ||
    888        PaintURIChanged(mStroke, aNewData.mStroke)) {
    889      hint |= nsChangeHint_UpdateEffects;
    890    }
    891  }
    892 
    893  // Stroke currently contributes to SVGGeometryFrame::mRect, so
    894  // we need a reflow here. No intrinsic sizes need to change, so
    895  // nsChangeHint_NeedReflow is sufficient.
    896  // Note that stroke-dashoffset does not affect SVGGeometryFrame::mRect.
    897  // text-anchor and dominant-baseline changes also require a reflow since
    898  // they change frames' rects.
    899  if (mStrokeWidth != aNewData.mStrokeWidth ||
    900      mStrokeMiterlimit != aNewData.mStrokeMiterlimit ||
    901      mStrokeLinecap != aNewData.mStrokeLinecap ||
    902      mStrokeLinejoin != aNewData.mStrokeLinejoin ||
    903      mDominantBaseline != aNewData.mDominantBaseline ||
    904      mTextAnchor != aNewData.mTextAnchor) {
    905    return hint | nsChangeHint_NeedReflow | nsChangeHint_RepaintFrame;
    906  }
    907 
    908  if (hint & nsChangeHint_RepaintFrame) {
    909    return hint;  // we don't add anything else below
    910  }
    911 
    912  if (mStrokeDashoffset != aNewData.mStrokeDashoffset ||
    913      mClipRule != aNewData.mClipRule ||
    914      mColorInterpolation != aNewData.mColorInterpolation ||
    915      mColorInterpolationFilters != aNewData.mColorInterpolationFilters ||
    916      mFillRule != aNewData.mFillRule || mPaintOrder != aNewData.mPaintOrder ||
    917      mShapeRendering != aNewData.mShapeRendering ||
    918      mStrokeDasharray != aNewData.mStrokeDasharray ||
    919      mMozContextProperties.bits != aNewData.mMozContextProperties.bits) {
    920    return hint | nsChangeHint_RepaintFrame;
    921  }
    922 
    923  if (!hint) {
    924    if (mMozContextProperties.idents != aNewData.mMozContextProperties.idents) {
    925      hint = nsChangeHint_NeutralChange;
    926    }
    927  }
    928 
    929  return hint;
    930 }
    931 
    932 // --------------------
    933 // nsStyleSVGReset
    934 //
    935 nsStyleSVGReset::nsStyleSVGReset()
    936    : mX(LengthPercentage::Zero()),
    937      mY(LengthPercentage::Zero()),
    938      mCx(LengthPercentage::Zero()),
    939      mCy(LengthPercentage::Zero()),
    940      mRx(NonNegativeLengthPercentageOrAuto::Auto()),
    941      mRy(NonNegativeLengthPercentageOrAuto::Auto()),
    942      mR(NonNegativeLengthPercentage::Zero()),
    943      mMask(nsStyleImageLayers::LayerType::Mask),
    944      mClipPath(StyleClipPath::None()),
    945      mStopColor(StyleColor::Black()),
    946      mFloodColor(StyleColor::Black()),
    947      mLightingColor(StyleColor::White()),
    948      mStopOpacity(1.0f),
    949      mFloodOpacity(1.0f),
    950      mVectorEffect(StyleVectorEffect::NONE),
    951      mMaskType(StyleMaskType::Luminance),
    952      mD(StyleDProperty::None()) {
    953  MOZ_COUNT_CTOR(nsStyleSVGReset);
    954 }
    955 
    956 nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource)
    957    : mX(aSource.mX),
    958      mY(aSource.mY),
    959      mCx(aSource.mCx),
    960      mCy(aSource.mCy),
    961      mRx(aSource.mRx),
    962      mRy(aSource.mRy),
    963      mR(aSource.mR),
    964      mMask(aSource.mMask),
    965      mClipPath(aSource.mClipPath),
    966      mStopColor(aSource.mStopColor),
    967      mFloodColor(aSource.mFloodColor),
    968      mLightingColor(aSource.mLightingColor),
    969      mStopOpacity(aSource.mStopOpacity),
    970      mFloodOpacity(aSource.mFloodOpacity),
    971      mVectorEffect(aSource.mVectorEffect),
    972      mMaskType(aSource.mMaskType),
    973      mD(aSource.mD) {
    974  MOZ_COUNT_CTOR(nsStyleSVGReset);
    975 }
    976 
    977 void nsStyleSVGReset::TriggerImageLoads(Document& aDocument,
    978                                        const nsStyleSVGReset* aOldStyle) {
    979  MOZ_ASSERT(NS_IsMainThread());
    980  // NOTE(emilio): we intentionally don't call TriggerImageLoads for clip-path.
    981 
    982  NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mMask) {
    983    auto& image = mMask.mLayers[i].mImage;
    984    if (!image.IsImageRequestType()) {
    985      continue;
    986    }
    987    const auto* url = image.GetImageRequestURLValue();
    988    // If the url is a local ref, it must be a <mask-resource>, so we don't
    989    // need to resolve the style image.
    990    if (url->IsLocalRef()) {
    991      continue;
    992    }
    993 #if 0
    994    // XXX The old style system also checks whether this is a reference to
    995    // the current document with reference, but it doesn't seem to be a
    996    // behavior mentioned anywhere, so we comment out the code for now.
    997    nsIURI* docURI = aPresContext->Document()->GetDocumentURI();
    998    if (url->EqualsExceptRef(docURI)) {
    999      continue;
   1000    }
   1001 #endif
   1002    // Otherwise, we may need the image even if it has a reference, in case
   1003    // the referenced element isn't a valid SVG <mask> element.
   1004    const auto* oldImage = (aOldStyle && aOldStyle->mMask.mLayers.Length() > i)
   1005                               ? &aOldStyle->mMask.mLayers[i].mImage
   1006                               : nullptr;
   1007 
   1008    image.ResolveImage(aDocument, oldImage);
   1009  }
   1010 }
   1011 
   1012 nsChangeHint nsStyleSVGReset::CalcDifference(
   1013    const nsStyleSVGReset& aNewData) const {
   1014  nsChangeHint hint = nsChangeHint(0);
   1015 
   1016  if (mX != aNewData.mX || mY != aNewData.mY || mCx != aNewData.mCx ||
   1017      mCy != aNewData.mCy || mR != aNewData.mR || mRx != aNewData.mRx ||
   1018      mRy != aNewData.mRy || mD != aNewData.mD) {
   1019    hint |= nsChangeHint_InvalidateRenderingObservers | nsChangeHint_NeedReflow;
   1020  }
   1021 
   1022  if (mClipPath != aNewData.mClipPath) {
   1023    hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
   1024  }
   1025 
   1026  if (mVectorEffect != aNewData.mVectorEffect) {
   1027    // Stroke currently affects SVGGeometryFrame::mRect, and
   1028    // vector-effect affect stroke. As a result we need to reflow if
   1029    // vector-effect changes in order to have SVGGeometryFrame::
   1030    // ReflowSVG called to update its mRect. No intrinsic sizes need
   1031    // to change so nsChangeHint_NeedReflow is sufficient.
   1032    hint |= nsChangeHint_NeedReflow | nsChangeHint_RepaintFrame;
   1033  } else if (mStopColor != aNewData.mStopColor ||
   1034             mFloodColor != aNewData.mFloodColor ||
   1035             mLightingColor != aNewData.mLightingColor ||
   1036             mStopOpacity != aNewData.mStopOpacity ||
   1037             mFloodOpacity != aNewData.mFloodOpacity ||
   1038             mMaskType != aNewData.mMaskType || mD != aNewData.mD) {
   1039    hint |= nsChangeHint_RepaintFrame;
   1040  }
   1041 
   1042  hint |=
   1043      mMask.CalcDifference(aNewData.mMask, nsStyleImageLayers::LayerType::Mask);
   1044 
   1045  return hint;
   1046 }
   1047 
   1048 bool nsStyleSVGReset::HasMask() const {
   1049  for (uint32_t i = 0; i < mMask.mImageCount; i++) {
   1050    if (!mMask.mLayers[i].mImage.IsNone()) {
   1051      return true;
   1052    }
   1053  }
   1054 
   1055  return false;
   1056 }
   1057 
   1058 // --------------------
   1059 // nsStylePage
   1060 //
   1061 
   1062 nsStylePage::nsStylePage(const nsStylePage& aSrc)
   1063    : mSize(aSrc.mSize),
   1064      mPage(aSrc.mPage),
   1065      mPageOrientation(aSrc.mPageOrientation) {
   1066  MOZ_COUNT_CTOR(nsStylePage);
   1067 }
   1068 
   1069 nsChangeHint nsStylePage::CalcDifference(const nsStylePage& aNewData) const {
   1070  // Page rule styling only matters when printing or using print preview.
   1071  if (aNewData.mSize != mSize || aNewData.mPage != mPage ||
   1072      aNewData.mPageOrientation != mPageOrientation) {
   1073    return nsChangeHint_NeutralChange;
   1074  }
   1075  return nsChangeHint_Empty;
   1076 }
   1077 
   1078 // --------------------
   1079 // nsStylePosition
   1080 //
   1081 nsStylePosition::nsStylePosition()
   1082    : mObjectPosition(Position::FromPercentage(0.5f)),
   1083      mOffset(StyleRectWithAllSides(StyleInset::Auto())),
   1084      mWidth(StyleSize::Auto()),
   1085      mMinWidth(StyleSize::Auto()),
   1086      mMaxWidth(StyleMaxSize::None()),
   1087      mHeight(StyleSize::Auto()),
   1088      mMinHeight(StyleSize::Auto()),
   1089      mMaxHeight(StyleMaxSize::None()),
   1090      mPositionAnchor(StylePositionAnchor::None()),
   1091      mPositionVisibility(StylePositionVisibility::ANCHORS_VISIBLE),
   1092      mPositionTryFallbacks(StylePositionTryFallbacks()),
   1093      mPositionTryOrder(StylePositionTryOrder::Normal),
   1094      mFlexBasis(StyleFlexBasis::Size(StyleSize::Auto())),
   1095      mAspectRatio(StyleAspectRatio::Auto()),
   1096      mGridAutoFlow(StyleGridAutoFlow::ROW),
   1097      mMasonryAutoFlow(
   1098          {StyleMasonryPlacement::Pack, StyleMasonryItemOrder::DefiniteFirst}),
   1099      mAlignContent({StyleAlignFlags::NORMAL}),
   1100      mAlignItems({StyleAlignFlags::NORMAL}),
   1101      mAlignSelf({StyleAlignFlags::AUTO}),
   1102      mJustifyContent({StyleAlignFlags::NORMAL}),
   1103      mJustifyItems({{StyleAlignFlags::LEGACY}, {StyleAlignFlags::NORMAL}}),
   1104      mJustifySelf({StyleAlignFlags::AUTO}),
   1105      mFlexDirection(StyleFlexDirection::Row),
   1106      mFlexWrap(StyleFlexWrap::Nowrap),
   1107      mObjectFit(StyleObjectFit::Fill),
   1108      mBoxSizing(StyleBoxSizing::Content),
   1109      mOrder(0),
   1110      mFlexGrow(0.0f),
   1111      mFlexShrink(1.0f),
   1112      mZIndex(StyleZIndex::Auto()),
   1113      mGridTemplateColumns(StyleGridTemplateComponent::None()),
   1114      mGridTemplateRows(StyleGridTemplateComponent::None()),
   1115      mGridTemplateAreas(StyleGridTemplateAreas::None()),
   1116      mColumnGap(NonNegativeLengthPercentageOrNormal::Normal()),
   1117      mRowGap(NonNegativeLengthPercentageOrNormal::Normal()),
   1118      mContainIntrinsicWidth(StyleContainIntrinsicSize::None()),
   1119      mContainIntrinsicHeight(StyleContainIntrinsicSize::None()) {
   1120  MOZ_COUNT_CTOR(nsStylePosition);
   1121 
   1122  // The initial value of grid-auto-columns and grid-auto-rows is 'auto',
   1123  // which computes to 'minmax(auto, auto)'.
   1124 
   1125  // Other members get their default constructors
   1126  // which initialize them to representations of their respective initial value.
   1127  // mGridTemplate{Rows,Columns}: false and empty arrays for 'none'
   1128  // mGrid{Column,Row}{Start,End}: false/0/empty values for 'auto'
   1129 }
   1130 
   1131 nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
   1132    : mObjectPosition(aSource.mObjectPosition),
   1133      mOffset(aSource.mOffset),
   1134      mWidth(aSource.mWidth),
   1135      mMinWidth(aSource.mMinWidth),
   1136      mMaxWidth(aSource.mMaxWidth),
   1137      mHeight(aSource.mHeight),
   1138      mMinHeight(aSource.mMinHeight),
   1139      mMaxHeight(aSource.mMaxHeight),
   1140      mPositionAnchor(aSource.mPositionAnchor),
   1141      mPositionArea(aSource.mPositionArea),
   1142      mPositionVisibility(aSource.mPositionVisibility),
   1143      mPositionTryFallbacks(aSource.mPositionTryFallbacks),
   1144      mPositionTryOrder(aSource.mPositionTryOrder),
   1145      mFlexBasis(aSource.mFlexBasis),
   1146      mGridAutoColumns(aSource.mGridAutoColumns),
   1147      mGridAutoRows(aSource.mGridAutoRows),
   1148      mAspectRatio(aSource.mAspectRatio),
   1149      mGridAutoFlow(aSource.mGridAutoFlow),
   1150      mMasonryAutoFlow(aSource.mMasonryAutoFlow),
   1151      mAlignContent(aSource.mAlignContent),
   1152      mAlignItems(aSource.mAlignItems),
   1153      mAlignSelf(aSource.mAlignSelf),
   1154      mJustifyContent(aSource.mJustifyContent),
   1155      mJustifyItems(aSource.mJustifyItems),
   1156      mJustifySelf(aSource.mJustifySelf),
   1157      mFlexDirection(aSource.mFlexDirection),
   1158      mFlexWrap(aSource.mFlexWrap),
   1159      mObjectFit(aSource.mObjectFit),
   1160      mBoxSizing(aSource.mBoxSizing),
   1161      mOrder(aSource.mOrder),
   1162      mFlexGrow(aSource.mFlexGrow),
   1163      mFlexShrink(aSource.mFlexShrink),
   1164      mZIndex(aSource.mZIndex),
   1165      mGridTemplateColumns(aSource.mGridTemplateColumns),
   1166      mGridTemplateRows(aSource.mGridTemplateRows),
   1167      mGridTemplateAreas(aSource.mGridTemplateAreas),
   1168      mGridColumnStart(aSource.mGridColumnStart),
   1169      mGridColumnEnd(aSource.mGridColumnEnd),
   1170      mGridRowStart(aSource.mGridRowStart),
   1171      mGridRowEnd(aSource.mGridRowEnd),
   1172      mColumnGap(aSource.mColumnGap),
   1173      mRowGap(aSource.mRowGap),
   1174      mContainIntrinsicWidth(aSource.mContainIntrinsicWidth),
   1175      mContainIntrinsicHeight(aSource.mContainIntrinsicHeight) {
   1176  MOZ_COUNT_CTOR(nsStylePosition);
   1177 }
   1178 
   1179 static bool IsEqualInsetType(const StyleRect<StyleInset>& aSides1,
   1180                             const StyleRect<StyleInset>& aSides2) {
   1181  for (const auto side : mozilla::AllPhysicalSides()) {
   1182    if (aSides1.Get(side).tag != aSides2.Get(side).tag) {
   1183      return false;
   1184    }
   1185  }
   1186  return true;
   1187 }
   1188 
   1189 nsChangeHint nsStylePosition::CalcDifference(
   1190    const nsStylePosition& aNewData, const ComputedStyle& aOldStyle) const {
   1191  if (mGridTemplateColumns.IsMasonry() !=
   1192          aNewData.mGridTemplateColumns.IsMasonry() ||
   1193      mGridTemplateRows.IsMasonry() != aNewData.mGridTemplateRows.IsMasonry()) {
   1194    // XXXmats this could be optimized to AllReflowHints with a bit of work,
   1195    // but I'll assume this is a very rare use case in practice. (bug 1623886)
   1196    return nsChangeHint_ReconstructFrame;
   1197  }
   1198 
   1199  nsChangeHint hint = nsChangeHint(0);
   1200 
   1201  // Changes to "z-index" require a repaint.
   1202  if (mZIndex != aNewData.mZIndex) {
   1203    hint |= nsChangeHint_RepaintFrame;
   1204  }
   1205 
   1206  // Changes to "object-fit" & "object-position" require a repaint.  They
   1207  // may also require a reflow, if we have a nsSubDocumentFrame, so that we
   1208  // can adjust the size & position of the subdocument.
   1209  if (mObjectFit != aNewData.mObjectFit ||
   1210      mObjectPosition != aNewData.mObjectPosition) {
   1211    hint |= nsChangeHint_RepaintFrame | nsChangeHint_NeedReflow;
   1212  }
   1213 
   1214  if (mContainIntrinsicWidth != aNewData.mContainIntrinsicWidth ||
   1215      mContainIntrinsicHeight != aNewData.mContainIntrinsicHeight) {
   1216    hint |= NS_STYLE_HINT_REFLOW;
   1217  }
   1218 
   1219  if (mOrder != aNewData.mOrder) {
   1220    // "order" impacts both layout order and stacking order, so we need both a
   1221    // reflow and a repaint when it changes.  (Technically, we only need a
   1222    // reflow if we're in a multi-line flexbox (which we can't be sure about,
   1223    // since that's determined by styling on our parent) -- there, "order" can
   1224    // affect which flex line we end up on, & hence can affect our sizing by
   1225    // changing the group of flex items we're competing with for space.)
   1226    return hint | nsChangeHint_RepaintFrame | nsChangeHint_AllReflowHints;
   1227  }
   1228 
   1229  if (mBoxSizing != aNewData.mBoxSizing) {
   1230    // Can affect both widths and heights; just a bad scene.
   1231    return hint | nsChangeHint_AllReflowHints;
   1232  }
   1233 
   1234  if (mAlignItems != aNewData.mAlignItems ||
   1235      mAlignSelf != aNewData.mAlignSelf) {
   1236    return hint | nsChangeHint_AllReflowHints;
   1237  }
   1238 
   1239  // Properties that apply to flex items:
   1240  // XXXdholbert These should probably be more targeted (bug 819536)
   1241  if (mFlexBasis != aNewData.mFlexBasis || mFlexGrow != aNewData.mFlexGrow ||
   1242      mFlexShrink != aNewData.mFlexShrink) {
   1243    return hint | nsChangeHint_AllReflowHints;
   1244  }
   1245 
   1246  // Properties that apply to flex containers:
   1247  // - flex-direction can swap a flex container between vertical & horizontal.
   1248  // - flex-wrap changes whether a flex container's children are wrapped, which
   1249  //   impacts their sizing/positioning and hence impacts the container's size.
   1250  if (mFlexDirection != aNewData.mFlexDirection ||
   1251      mFlexWrap != aNewData.mFlexWrap) {
   1252    return hint | nsChangeHint_AllReflowHints;
   1253  }
   1254 
   1255  // Properties that apply to grid containers:
   1256  // FIXME: only for grid containers
   1257  // (ie. 'display: grid' or 'display: inline-grid')
   1258  if (mGridTemplateColumns != aNewData.mGridTemplateColumns ||
   1259      mGridTemplateRows != aNewData.mGridTemplateRows ||
   1260      mGridTemplateAreas != aNewData.mGridTemplateAreas ||
   1261      mGridAutoColumns != aNewData.mGridAutoColumns ||
   1262      mGridAutoRows != aNewData.mGridAutoRows ||
   1263      mGridAutoFlow != aNewData.mGridAutoFlow ||
   1264      mMasonryAutoFlow != aNewData.mMasonryAutoFlow) {
   1265    return hint | nsChangeHint_AllReflowHints;
   1266  }
   1267 
   1268  // Properties that apply to grid items:
   1269  // FIXME: only for grid items
   1270  // (ie. parent frame is 'display: grid' or 'display: inline-grid')
   1271  if (mGridColumnStart != aNewData.mGridColumnStart ||
   1272      mGridColumnEnd != aNewData.mGridColumnEnd ||
   1273      mGridRowStart != aNewData.mGridRowStart ||
   1274      mGridRowEnd != aNewData.mGridRowEnd ||
   1275      mColumnGap != aNewData.mColumnGap || mRowGap != aNewData.mRowGap) {
   1276    return hint | nsChangeHint_AllReflowHints;
   1277  }
   1278 
   1279  // Changing 'justify-content/items/self' might affect the positioning,
   1280  // but it won't affect any sizing.
   1281  if (mJustifyContent != aNewData.mJustifyContent ||
   1282      mJustifyItems.computed != aNewData.mJustifyItems.computed ||
   1283      mJustifySelf != aNewData.mJustifySelf) {
   1284    hint |= nsChangeHint_NeedReflow;
   1285  }
   1286 
   1287  // No need to do anything if specified justify-items changes, as long as the
   1288  // computed one (tested above) is unchanged.
   1289  if (mJustifyItems.specified != aNewData.mJustifyItems.specified) {
   1290    hint |= nsChangeHint_NeutralChange;
   1291  }
   1292 
   1293  // 'align-content' doesn't apply to a single-line flexbox but we don't know
   1294  // if we're a flex container at this point so we can't optimize for that.
   1295  if (mAlignContent != aNewData.mAlignContent) {
   1296    hint |= nsChangeHint_NeedReflow;
   1297  }
   1298 
   1299  bool widthChanged = mWidth != aNewData.mWidth ||
   1300                      mMinWidth != aNewData.mMinWidth ||
   1301                      mMaxWidth != aNewData.mMaxWidth;
   1302  bool heightChanged = mHeight != aNewData.mHeight ||
   1303                       mMinHeight != aNewData.mMinHeight ||
   1304                       mMaxHeight != aNewData.mMaxHeight;
   1305 
   1306  if (widthChanged || heightChanged) {
   1307    // It doesn't matter whether we're looking at the old or new visibility
   1308    // struct, since a change between vertical and horizontal writing-mode will
   1309    // cause a reframe.
   1310    const bool isVertical = aOldStyle.StyleVisibility()->mWritingMode !=
   1311                            StyleWritingModeProperty::HorizontalTb;
   1312    if (isVertical ? widthChanged : heightChanged) {
   1313      hint |= nsChangeHint_ReflowHintsForBSizeChange;
   1314    }
   1315    if (isVertical ? heightChanged : widthChanged) {
   1316      hint |= nsChangeHint_ReflowHintsForISizeChange;
   1317    }
   1318  }
   1319 
   1320  // Note(dshin): Following hints based on changes in `position-*`
   1321  // is conditional on being absolutely positioned, but we don't have
   1322  // enough information here.
   1323  if (mPositionVisibility != aNewData.mPositionVisibility) {
   1324    // position-visibility doesn't affect layout boxes.
   1325    hint |= nsChangeHint_RepaintFrame;
   1326  }
   1327 
   1328  if (mPositionAnchor != aNewData.mPositionAnchor ||
   1329      mPositionTryFallbacks != aNewData.mPositionTryFallbacks ||
   1330      mPositionTryOrder != aNewData.mPositionTryOrder ||
   1331      mPositionArea != aNewData.mPositionArea) {
   1332    // We need to reflow in order to update the `AnchorPosReferences`
   1333    // property at minimum.
   1334    hint |= nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition;
   1335  }
   1336 
   1337  if (mAspectRatio != aNewData.mAspectRatio) {
   1338    hint |= nsChangeHint_ReflowHintsForISizeChange |
   1339            nsChangeHint_ReflowHintsForBSizeChange;
   1340  }
   1341 
   1342  // If any of the offsets have changed, then return the respective hints
   1343  // so that we would hopefully be able to avoid reflowing.
   1344  // Note that it is possible that we'll need to reflow when processing
   1345  // restyles, but we don't have enough information to make a good decision
   1346  // right now.
   1347  // Don't try to handle changes between types efficiently; at least for
   1348  // changing into/out of `auto`, we will hardly ever be able to avoid a reflow.
   1349  if (mOffset != aNewData.mOffset) {
   1350    if (IsEqualInsetType(mOffset, aNewData.mOffset) &&
   1351        aNewData.mOffset.All([](const StyleInset& aInset) {
   1352          // Anchor positioning invalidation depends on `AnchorPosReferences`
   1353          // being updated, which happens during reflow.
   1354          return !aInset.HasAnchorPositioningFunction();
   1355        })) {
   1356      hint |=
   1357          nsChangeHint_RecomputePosition | nsChangeHint_UpdateParentOverflow;
   1358    } else {
   1359      hint |=
   1360          nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition;
   1361    }
   1362  }
   1363  return hint;
   1364 }
   1365 
   1366 const StyleContainIntrinsicSize& nsStylePosition::ContainIntrinsicBSize(
   1367    const WritingMode& aWM) const {
   1368  return aWM.IsVertical() ? mContainIntrinsicWidth : mContainIntrinsicHeight;
   1369 }
   1370 
   1371 const StyleContainIntrinsicSize& nsStylePosition::ContainIntrinsicISize(
   1372    const WritingMode& aWM) const {
   1373  return aWM.IsVertical() ? mContainIntrinsicHeight : mContainIntrinsicWidth;
   1374 }
   1375 
   1376 StyleSelfAlignment nsStylePosition::UsedAlignSelf(
   1377    const ComputedStyle* aParent) const {
   1378  if (mAlignSelf._0 != StyleAlignFlags::AUTO) {
   1379    return mAlignSelf;
   1380  }
   1381  if (MOZ_LIKELY(aParent)) {
   1382    auto parentAlignItems = aParent->StylePosition()->mAlignItems;
   1383    MOZ_ASSERT(!(parentAlignItems._0 & StyleAlignFlags::LEGACY),
   1384               "align-items can't have 'legacy'");
   1385    return {parentAlignItems._0};
   1386  }
   1387  return {StyleAlignFlags::NORMAL};
   1388 }
   1389 
   1390 StyleSelfAlignment nsStylePosition::UsedJustifySelf(
   1391    const ComputedStyle* aParent) const {
   1392  if (mJustifySelf._0 != StyleAlignFlags::AUTO) {
   1393    return mJustifySelf;
   1394  }
   1395  if (MOZ_LIKELY(aParent)) {
   1396    const auto& inheritedJustifyItems =
   1397        aParent->StylePosition()->mJustifyItems.computed._0;
   1398    return {inheritedJustifyItems._0 & ~StyleAlignFlags::LEGACY};
   1399  }
   1400  return {StyleAlignFlags::NORMAL};
   1401 }
   1402 
   1403 AnchorResolvedInset AnchorResolvedInsetHelper::ResolveAnchor(
   1404    const mozilla::StyleInset& aValue, mozilla::StylePhysicalSide aSide,
   1405    const AnchorPosOffsetResolutionParams& aParams) {
   1406  MOZ_ASSERT(aValue.HasAnchorPositioningFunction(),
   1407             "Calling anchor resolution without using it?");
   1408  switch (aValue.tag) {
   1409    case StyleInset::Tag::AnchorContainingCalcFunction: {
   1410      const auto& lp = aValue.AsAnchorContainingCalcFunction();
   1411      const auto& c = lp.AsCalc();
   1412      auto result = StyleCalcAnchorPositioningFunctionResolution::Invalid();
   1413      const auto allowed =
   1414          StyleAllowAnchorPosResolutionInCalcPercentage::Both(aSide);
   1415      Servo_ResolveAnchorFunctionsInCalcPercentage(&c, &allowed, &aParams,
   1416                                                   &result);
   1417      if (result.IsInvalid()) {
   1418        return Auto();
   1419      }
   1420      return MakeUniqueOfUniqueOrNonOwning<const StyleInset>(result.AsValid());
   1421    }
   1422    case StyleInset::Tag::AnchorFunction: {
   1423      auto resolved = StyleAnchorPositioningFunctionResolution::Invalid();
   1424      Servo_ResolveAnchorFunction(&*aValue.AsAnchorFunction(), &aParams, aSide,
   1425                                  &resolved);
   1426      if (resolved.IsInvalid()) {
   1427        return Auto();
   1428      }
   1429      if (resolved.IsResolvedReference()) {
   1430        return MakeUniqueOfUniqueOrNonOwning<const StyleInset>(
   1431            *resolved.AsResolvedReference());
   1432      }
   1433      return AnchorResolvedInset{
   1434          MakeUniqueOfUniqueOrNonOwning<const StyleInset>(
   1435              resolved.AsResolved())};
   1436    }
   1437    case StyleInset::Tag::AnchorSizeFunction: {
   1438      auto resolved = StyleAnchorPositioningFunctionResolution::Invalid();
   1439      Servo_ResolveAnchorSizeFunctionForInset(
   1440          &*aValue.AsAnchorSizeFunction(), &aParams, ToStylePhysicalAxis(aSide),
   1441          &resolved);
   1442      if (resolved.IsInvalid()) {
   1443        return Auto();
   1444      }
   1445      if (resolved.IsResolvedReference()) {
   1446        return MakeUniqueOfUniqueOrNonOwning<const StyleInset>(
   1447            *resolved.AsResolvedReference());
   1448      }
   1449      return MakeUniqueOfUniqueOrNonOwning<const StyleInset>(
   1450          resolved.AsResolved());
   1451    }
   1452    default:
   1453      MOZ_ASSERT_UNREACHABLE("Unhandled inset type");
   1454      return Auto();
   1455  }
   1456 }
   1457 
   1458 AnchorResolvedSize AnchorResolvedSizeHelper::ResolveAnchor(
   1459    const mozilla::StyleSize& aValue, StylePhysicalAxis aAxis,
   1460    const AnchorPosResolutionParams& aParams) {
   1461  MOZ_ASSERT(aValue.HasAnchorPositioningFunction(),
   1462             "Calling anchor resolution without using it?");
   1463  if (aValue.IsAnchorSizeFunction()) {
   1464    auto resolved = StyleAnchorPositioningFunctionResolution::Invalid();
   1465    Servo_ResolveAnchorSizeFunctionForSize(&*aValue.AsAnchorSizeFunction(),
   1466                                           &aParams, aAxis, &resolved);
   1467    if (resolved.IsInvalid()) {
   1468      return Auto();
   1469    }
   1470    if (resolved.IsResolvedReference()) {
   1471      return MakeUniqueOfUniqueOrNonOwning<const StyleSize>(
   1472          *resolved.AsResolvedReference());
   1473    }
   1474    return MakeUniqueOfUniqueOrNonOwning<const StyleSize>(
   1475        resolved.AsResolved());
   1476  }
   1477 
   1478  const auto& lp = aValue.AsAnchorContainingCalcFunction();
   1479  // Follows the same reasoning as anchor resolved insets.
   1480  const auto& c = lp.AsCalc();
   1481  auto result = StyleCalcAnchorPositioningFunctionResolution::Invalid();
   1482  AnchorPosOffsetResolutionParams params =
   1483      AnchorPosOffsetResolutionParams::UseCBFrameSize(aParams);
   1484  const auto allowed =
   1485      StyleAllowAnchorPosResolutionInCalcPercentage::AnchorSizeOnly(aAxis);
   1486  Servo_ResolveAnchorFunctionsInCalcPercentage(&c, &allowed, &params, &result);
   1487  if (result.IsInvalid()) {
   1488    return Auto();
   1489  }
   1490  return MakeUniqueOfUniqueOrNonOwning<const StyleSize>(result.AsValid());
   1491 }
   1492 
   1493 AnchorResolvedMaxSize AnchorResolvedMaxSizeHelper::ResolveAnchor(
   1494    const mozilla::StyleMaxSize& aValue, StylePhysicalAxis aAxis,
   1495    const AnchorPosResolutionParams& aParams) {
   1496  MOZ_ASSERT(aValue.HasAnchorPositioningFunction(),
   1497             "Calling anchor resolution without using it?");
   1498  if (aValue.IsAnchorSizeFunction()) {
   1499    auto resolved = StyleAnchorPositioningFunctionResolution::Invalid();
   1500    Servo_ResolveAnchorSizeFunctionForMaxSize(&*aValue.AsAnchorSizeFunction(),
   1501                                              &aParams, aAxis, &resolved);
   1502    if (resolved.IsInvalid()) {
   1503      return None();
   1504    }
   1505    if (resolved.IsResolvedReference()) {
   1506      return MakeUniqueOfUniqueOrNonOwning<const StyleMaxSize>(
   1507          *resolved.AsResolvedReference());
   1508    }
   1509    return MakeUniqueOfUniqueOrNonOwning<const StyleMaxSize>(
   1510        resolved.AsResolved());
   1511  }
   1512 
   1513  const auto& lp = aValue.AsAnchorContainingCalcFunction();
   1514  // Follows the same reasoning as anchor resolved insets.
   1515  const auto& c = lp.AsCalc();
   1516  auto result = StyleCalcAnchorPositioningFunctionResolution::Invalid();
   1517  AnchorPosOffsetResolutionParams params =
   1518      AnchorPosOffsetResolutionParams::UseCBFrameSize(aParams);
   1519  const auto allowed =
   1520      StyleAllowAnchorPosResolutionInCalcPercentage::AnchorSizeOnly(aAxis);
   1521  Servo_ResolveAnchorFunctionsInCalcPercentage(&c, &allowed, &params, &result);
   1522  if (result.IsInvalid()) {
   1523    return None();
   1524  }
   1525  return MakeUniqueOfUniqueOrNonOwning<const StyleMaxSize>(result.AsValid());
   1526 }
   1527 
   1528 // --------------------
   1529 // nsStyleTable
   1530 //
   1531 
   1532 nsStyleTable::nsStyleTable()
   1533    : mLayoutStrategy(StyleTableLayout::Auto), mXSpan(1) {
   1534  MOZ_COUNT_CTOR(nsStyleTable);
   1535 }
   1536 
   1537 nsStyleTable::nsStyleTable(const nsStyleTable& aSource)
   1538    : mLayoutStrategy(aSource.mLayoutStrategy), mXSpan(aSource.mXSpan) {
   1539  MOZ_COUNT_CTOR(nsStyleTable);
   1540 }
   1541 
   1542 nsChangeHint nsStyleTable::CalcDifference(const nsStyleTable& aNewData) const {
   1543  if (mXSpan != aNewData.mXSpan ||
   1544      mLayoutStrategy != aNewData.mLayoutStrategy) {
   1545    return nsChangeHint_ReconstructFrame;
   1546  }
   1547  return nsChangeHint(0);
   1548 }
   1549 
   1550 // -----------------------
   1551 // nsStyleTableBorder
   1552 
   1553 nsStyleTableBorder::nsStyleTableBorder()
   1554    : mBorderSpacing{Length::Zero(), Length::Zero()},
   1555      mBorderCollapse(StyleBorderCollapse::Separate),
   1556      mCaptionSide(StyleCaptionSide::Top),
   1557      mEmptyCells(StyleEmptyCells::Show) {
   1558  MOZ_COUNT_CTOR(nsStyleTableBorder);
   1559 }
   1560 
   1561 nsStyleTableBorder::nsStyleTableBorder(const nsStyleTableBorder& aSource)
   1562    : mBorderSpacing(aSource.mBorderSpacing),
   1563      mBorderCollapse(aSource.mBorderCollapse),
   1564      mCaptionSide(aSource.mCaptionSide),
   1565      mEmptyCells(aSource.mEmptyCells) {
   1566  MOZ_COUNT_CTOR(nsStyleTableBorder);
   1567 }
   1568 
   1569 nsChangeHint nsStyleTableBorder::CalcDifference(
   1570    const nsStyleTableBorder& aNewData) const {
   1571  // Border-collapse changes need a reframe, because we use a different frame
   1572  // class for table cells in the collapsed border model.  This is used to
   1573  // conserve memory when using the separated border model (collapsed borders
   1574  // require extra state to be stored).
   1575  if (mBorderCollapse != aNewData.mBorderCollapse) {
   1576    return nsChangeHint_ReconstructFrame;
   1577  }
   1578  if (mCaptionSide != aNewData.mCaptionSide ||
   1579      mBorderSpacing != aNewData.mBorderSpacing) {
   1580    return NS_STYLE_HINT_REFLOW;
   1581  }
   1582  if (mEmptyCells != aNewData.mEmptyCells) {
   1583    return NS_STYLE_HINT_VISUAL;
   1584  }
   1585  return nsChangeHint(0);
   1586 }
   1587 
   1588 template <typename T>
   1589 static bool GradientItemsAreOpaque(
   1590    Span<const StyleGenericGradientItem<StyleColor, T>> aItems) {
   1591  for (auto& stop : aItems) {
   1592    if (stop.IsInterpolationHint()) {
   1593      continue;
   1594    }
   1595 
   1596    auto& color = stop.IsSimpleColorStop() ? stop.AsSimpleColorStop()
   1597                                           : stop.AsComplexColorStop().color;
   1598    if (color.MaybeTransparent()) {
   1599      // We don't know the foreground color here, so if it's being used
   1600      // we must assume it might be transparent.
   1601      return false;
   1602    }
   1603  }
   1604 
   1605  return true;
   1606 }
   1607 
   1608 template <>
   1609 bool StyleGradient::IsOpaque() const {
   1610  switch (tag) {
   1611    case Tag::Linear:
   1612      return GradientItemsAreOpaque(AsLinear().items.AsSpan());
   1613    case Tag::Radial:
   1614      return GradientItemsAreOpaque(AsRadial().items.AsSpan());
   1615    case Tag::Conic:
   1616      return GradientItemsAreOpaque(AsConic().items.AsSpan());
   1617  }
   1618  MOZ_ASSERT_UNREACHABLE("Unexpected gradient type");
   1619  return false;
   1620 }
   1621 
   1622 template <>
   1623 bool StyleImage::IsOpaque() const {
   1624  switch (tag) {
   1625    case Tag::ImageSet:
   1626      return FinalImage().IsOpaque();
   1627    case Tag::Gradient:
   1628      return AsGradient()->IsOpaque();
   1629    case Tag::Url: {
   1630      if (!IsComplete()) {
   1631        return false;
   1632      }
   1633      MOZ_ASSERT(GetImageRequest(), "should've returned earlier above");
   1634      nsCOMPtr<imgIContainer> imageContainer;
   1635      GetImageRequest()->GetImage(getter_AddRefs(imageContainer));
   1636      MOZ_ASSERT(imageContainer, "IsComplete() said image container is ready");
   1637      return imageContainer->WillDrawOpaqueNow();
   1638    }
   1639    case Tag::CrossFade:
   1640      for (const auto& el : AsCrossFade()->elements.AsSpan()) {
   1641        if (el.image.IsColor()) {
   1642          if (el.image.AsColor().MaybeTransparent()) {
   1643            return false;
   1644          }
   1645          continue;
   1646        }
   1647        MOZ_ASSERT(el.image.IsImage());
   1648        if (!el.image.AsImage().IsOpaque()) {
   1649          return false;
   1650        }
   1651      }
   1652      return true;
   1653    case Tag::LightDark:
   1654      MOZ_FALLTHROUGH_ASSERT("Should be computed already");
   1655    case Tag::Element:
   1656    case Tag::MozSymbolicIcon:
   1657    case Tag::None:
   1658      break;
   1659  }
   1660  return false;
   1661 }
   1662 
   1663 template <>
   1664 bool StyleImage::IsComplete() const {
   1665  switch (tag) {
   1666    case Tag::None:
   1667      return false;
   1668    case Tag::Gradient:
   1669    case Tag::Element:
   1670    case Tag::MozSymbolicIcon:
   1671      return true;
   1672    case Tag::Url: {
   1673      if (!IsResolved()) {
   1674        return false;
   1675      }
   1676      imgRequestProxy* req = GetImageRequest();
   1677      if (!req) {
   1678        return false;
   1679      }
   1680      uint32_t status = imgIRequest::STATUS_ERROR;
   1681      return NS_SUCCEEDED(req->GetImageStatus(&status)) &&
   1682             (status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
   1683             (status & imgIRequest::STATUS_FRAME_COMPLETE);
   1684    }
   1685    case Tag::ImageSet:
   1686      return FinalImage().IsComplete();
   1687    // Bug 546052 cross-fade not yet implemented.
   1688    case Tag::CrossFade:
   1689      return true;
   1690    case Tag::LightDark:
   1691      MOZ_ASSERT_UNREACHABLE("light-dark() should be computed already");
   1692      break;
   1693  }
   1694  MOZ_ASSERT_UNREACHABLE("unexpected image type");
   1695  return false;
   1696 }
   1697 
   1698 template <>
   1699 bool StyleImage::IsSizeAvailable() const {
   1700  switch (tag) {
   1701    case Tag::None:
   1702      return false;
   1703    case Tag::Gradient:
   1704    case Tag::Element:
   1705    case Tag::MozSymbolicIcon:
   1706      return true;
   1707    case Tag::Url: {
   1708      imgRequestProxy* req = GetImageRequest();
   1709      if (!req) {
   1710        return false;
   1711      }
   1712      uint32_t status = imgIRequest::STATUS_ERROR;
   1713      return NS_SUCCEEDED(req->GetImageStatus(&status)) &&
   1714             !(status & imgIRequest::STATUS_ERROR) &&
   1715             (status & imgIRequest::STATUS_SIZE_AVAILABLE);
   1716    }
   1717    case Tag::ImageSet:
   1718      return FinalImage().IsSizeAvailable();
   1719    case Tag::CrossFade:
   1720      // TODO: Bug 546052 cross-fade not yet implemented.
   1721      return true;
   1722    case Tag::LightDark:
   1723      MOZ_ASSERT_UNREACHABLE("light-dark() should be computed already");
   1724      break;
   1725  }
   1726  MOZ_ASSERT_UNREACHABLE("unexpected image type");
   1727  return false;
   1728 }
   1729 
   1730 template <>
   1731 void StyleImage::ResolveImage(Document& aDoc, const StyleImage* aOld) {
   1732  if (IsResolved()) {
   1733    return;
   1734  }
   1735  const auto* old = aOld ? aOld->GetImageRequestURLValue() : nullptr;
   1736  const auto* url = GetImageRequestURLValue();
   1737  // We could avoid this const_cast generating more code but it's not really
   1738  // worth it.
   1739  const_cast<StyleComputedUrl*>(url)->ResolveImage(aDoc, old);
   1740 }
   1741 
   1742 template <>
   1743 ImageResolution StyleImage::GetResolution(
   1744    const ComputedStyle* aStyleForZoom) const {
   1745  ImageResolution resolution;
   1746  if (imgRequestProxy* request = GetImageRequest()) {
   1747    RefPtr<imgIContainer> image;
   1748    request->GetImage(getter_AddRefs(image));
   1749    if (image) {
   1750      resolution = image->GetResolution();
   1751    }
   1752  }
   1753  if (IsImageSet()) {
   1754    const auto& set = *AsImageSet();
   1755    auto items = set.items.AsSpan();
   1756    if (MOZ_LIKELY(set.selected_index < items.Length())) {
   1757      float r = items[set.selected_index].resolution._0;
   1758      resolution.ScaleBy(r);
   1759    }
   1760  }
   1761  if (aStyleForZoom && aStyleForZoom->EffectiveZoom() != StyleZoom::ONE) {
   1762    resolution.ScaleBy(1.0f / aStyleForZoom->EffectiveZoom().ToFloat());
   1763  }
   1764  return resolution;
   1765 }
   1766 
   1767 // --------------------
   1768 // nsStyleImageLayers
   1769 //
   1770 
   1771 const NonCustomCSSPropertyId nsStyleImageLayers::kBackgroundLayerTable[] = {
   1772    eCSSProperty_background,             // shorthand
   1773    eCSSProperty_background_color,       // color
   1774    eCSSProperty_background_image,       // image
   1775    eCSSProperty_background_repeat,      // repeat
   1776    eCSSProperty_background_position_x,  // positionX
   1777    eCSSProperty_background_position_y,  // positionY
   1778    eCSSProperty_background_clip,        // clip
   1779    eCSSProperty_background_origin,      // origin
   1780    eCSSProperty_background_size,        // size
   1781    eCSSProperty_background_attachment,  // attachment
   1782    eCSSProperty_UNKNOWN,                // maskMode
   1783    eCSSProperty_UNKNOWN                 // composite
   1784 };
   1785 
   1786 const NonCustomCSSPropertyId nsStyleImageLayers::kMaskLayerTable[] = {
   1787    eCSSProperty_mask,             // shorthand
   1788    eCSSProperty_UNKNOWN,          // color
   1789    eCSSProperty_mask_image,       // image
   1790    eCSSProperty_mask_repeat,      // repeat
   1791    eCSSProperty_mask_position_x,  // positionX
   1792    eCSSProperty_mask_position_y,  // positionY
   1793    eCSSProperty_mask_clip,        // clip
   1794    eCSSProperty_mask_origin,      // origin
   1795    eCSSProperty_mask_size,        // size
   1796    eCSSProperty_UNKNOWN,          // attachment
   1797    eCSSProperty_mask_mode,        // maskMode
   1798    eCSSProperty_mask_composite    // composite
   1799 };
   1800 
   1801 nsStyleImageLayers::nsStyleImageLayers(nsStyleImageLayers::LayerType aType)
   1802    : mAttachmentCount(1),
   1803      mClipCount(1),
   1804      mOriginCount(1),
   1805      mRepeatCount(1),
   1806      mPositionXCount(1),
   1807      mPositionYCount(1),
   1808      mImageCount(1),
   1809      mSizeCount(1),
   1810      mMaskModeCount(1),
   1811      mBlendModeCount(1),
   1812      mCompositeCount(1),
   1813      mLayers(nsStyleAutoArray<Layer>::WITH_SINGLE_INITIAL_ELEMENT) {
   1814  // Ensure first layer is initialized as specified layer type
   1815  mLayers[0].Initialize(aType);
   1816 }
   1817 
   1818 nsStyleImageLayers::nsStyleImageLayers(const nsStyleImageLayers& aSource)
   1819    : mAttachmentCount(aSource.mAttachmentCount),
   1820      mClipCount(aSource.mClipCount),
   1821      mOriginCount(aSource.mOriginCount),
   1822      mRepeatCount(aSource.mRepeatCount),
   1823      mPositionXCount(aSource.mPositionXCount),
   1824      mPositionYCount(aSource.mPositionYCount),
   1825      mImageCount(aSource.mImageCount),
   1826      mSizeCount(aSource.mSizeCount),
   1827      mMaskModeCount(aSource.mMaskModeCount),
   1828      mBlendModeCount(aSource.mBlendModeCount),
   1829      mCompositeCount(aSource.mCompositeCount),
   1830      mLayers(aSource.mLayers.Clone()) {}
   1831 
   1832 static bool AnyLayerIsElementImage(const nsStyleImageLayers& aLayers) {
   1833  NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, aLayers) {
   1834    if (aLayers.mLayers[i].mImage.FinalImage().IsElement()) {
   1835      return true;
   1836    }
   1837  }
   1838  return false;
   1839 }
   1840 
   1841 nsChangeHint nsStyleImageLayers::CalcDifference(
   1842    const nsStyleImageLayers& aNewLayers, LayerType aType) const {
   1843  nsChangeHint hint = nsChangeHint(0);
   1844 
   1845  // If the number of visible images changes, then it's easy-peasy.
   1846  if (mImageCount != aNewLayers.mImageCount) {
   1847    hint |= nsChangeHint_RepaintFrame;
   1848    if (aType == nsStyleImageLayers::LayerType::Mask ||
   1849        AnyLayerIsElementImage(*this) || AnyLayerIsElementImage(aNewLayers)) {
   1850      hint |= nsChangeHint_UpdateEffects;
   1851    }
   1852    return hint;
   1853  }
   1854 
   1855  const nsStyleImageLayers& moreLayers =
   1856      mLayers.Length() > aNewLayers.mLayers.Length() ? *this : aNewLayers;
   1857  const nsStyleImageLayers& lessLayers =
   1858      mLayers.Length() > aNewLayers.mLayers.Length() ? aNewLayers : *this;
   1859 
   1860  for (size_t i = 0; i < moreLayers.mLayers.Length(); ++i) {
   1861    const Layer& moreLayersLayer = moreLayers.mLayers[i];
   1862    if (i < moreLayers.mImageCount) {
   1863      // This is a visible image we're diffing, we may need to repaint.
   1864      const Layer& lessLayersLayer = lessLayers.mLayers[i];
   1865      nsChangeHint layerDifference =
   1866          moreLayersLayer.CalcDifference(lessLayersLayer);
   1867      if (layerDifference &&
   1868          (moreLayersLayer.mImage.FinalImage().IsElement() ||
   1869           lessLayersLayer.mImage.FinalImage().IsElement())) {
   1870        layerDifference |=
   1871            nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
   1872      }
   1873      hint |= layerDifference;
   1874      continue;
   1875    }
   1876    if (hint) {
   1877      // If they're different by now, we're done.
   1878      return hint;
   1879    }
   1880    if (i >= lessLayers.mLayers.Length()) {
   1881      // The layer count differs, we know some property has changed, but if we
   1882      // got here we know it won't affect rendering.
   1883      return nsChangeHint_NeutralChange;
   1884    }
   1885 
   1886    const Layer& lessLayersLayer = lessLayers.mLayers[i];
   1887    MOZ_ASSERT(moreLayersLayer.mImage.IsNone());
   1888    MOZ_ASSERT(lessLayersLayer.mImage.IsNone());
   1889    if (moreLayersLayer.CalcDifference(lessLayersLayer)) {
   1890      // We don't care about the difference returned, we know it's not visible,
   1891      // but if something changed, then we need to return the neutral change.
   1892      return nsChangeHint_NeutralChange;
   1893    }
   1894  }
   1895 
   1896  if (hint) {
   1897    // If they're different by now, we're done.
   1898    return hint;
   1899  }
   1900 
   1901  // We could have same layers and values, but different count still.
   1902  if (mAttachmentCount != aNewLayers.mAttachmentCount ||
   1903      mBlendModeCount != aNewLayers.mBlendModeCount ||
   1904      mClipCount != aNewLayers.mClipCount ||
   1905      mCompositeCount != aNewLayers.mCompositeCount ||
   1906      mMaskModeCount != aNewLayers.mMaskModeCount ||
   1907      mOriginCount != aNewLayers.mOriginCount ||
   1908      mRepeatCount != aNewLayers.mRepeatCount ||
   1909      mPositionXCount != aNewLayers.mPositionXCount ||
   1910      mPositionYCount != aNewLayers.mPositionYCount ||
   1911      mSizeCount != aNewLayers.mSizeCount) {
   1912    hint |= nsChangeHint_NeutralChange;
   1913  }
   1914 
   1915  return hint;
   1916 }
   1917 
   1918 nsStyleImageLayers& nsStyleImageLayers::operator=(
   1919    const nsStyleImageLayers& aOther) {
   1920  mAttachmentCount = aOther.mAttachmentCount;
   1921  mClipCount = aOther.mClipCount;
   1922  mOriginCount = aOther.mOriginCount;
   1923  mRepeatCount = aOther.mRepeatCount;
   1924  mPositionXCount = aOther.mPositionXCount;
   1925  mPositionYCount = aOther.mPositionYCount;
   1926  mImageCount = aOther.mImageCount;
   1927  mSizeCount = aOther.mSizeCount;
   1928  mMaskModeCount = aOther.mMaskModeCount;
   1929  mBlendModeCount = aOther.mBlendModeCount;
   1930  mCompositeCount = aOther.mCompositeCount;
   1931  mLayers = aOther.mLayers.Clone();
   1932 
   1933  return *this;
   1934 }
   1935 
   1936 bool nsStyleImageLayers::operator==(const nsStyleImageLayers& aOther) const {
   1937  if (mAttachmentCount != aOther.mAttachmentCount ||
   1938      mClipCount != aOther.mClipCount || mOriginCount != aOther.mOriginCount ||
   1939      mRepeatCount != aOther.mRepeatCount ||
   1940      mPositionXCount != aOther.mPositionXCount ||
   1941      mPositionYCount != aOther.mPositionYCount ||
   1942      mImageCount != aOther.mImageCount || mSizeCount != aOther.mSizeCount ||
   1943      mMaskModeCount != aOther.mMaskModeCount ||
   1944      mBlendModeCount != aOther.mBlendModeCount) {
   1945    return false;
   1946  }
   1947 
   1948  if (mLayers.Length() != aOther.mLayers.Length()) {
   1949    return false;
   1950  }
   1951 
   1952  for (uint32_t i = 0; i < mLayers.Length(); i++) {
   1953    if (mLayers[i].mPosition != aOther.mLayers[i].mPosition ||
   1954        mLayers[i].mImage != aOther.mLayers[i].mImage ||
   1955        mLayers[i].mSize != aOther.mLayers[i].mSize ||
   1956        mLayers[i].mClip != aOther.mLayers[i].mClip ||
   1957        mLayers[i].mOrigin != aOther.mLayers[i].mOrigin ||
   1958        mLayers[i].mAttachment != aOther.mLayers[i].mAttachment ||
   1959        mLayers[i].mBlendMode != aOther.mLayers[i].mBlendMode ||
   1960        mLayers[i].mComposite != aOther.mLayers[i].mComposite ||
   1961        mLayers[i].mMaskMode != aOther.mLayers[i].mMaskMode ||
   1962        mLayers[i].mRepeat != aOther.mLayers[i].mRepeat) {
   1963      return false;
   1964    }
   1965  }
   1966 
   1967  return true;
   1968 }
   1969 
   1970 static bool SizeDependsOnPositioningAreaSize(const StyleBackgroundSize& aSize,
   1971                                             const StyleImage& aImage) {
   1972  MOZ_ASSERT(!aImage.IsNone(), "caller should have handled this");
   1973  MOZ_ASSERT(!aImage.IsImageSet(), "caller should have handled this");
   1974 
   1975  // Contain and cover straightforwardly depend on frame size.
   1976  if (aSize.IsCover() || aSize.IsContain()) {
   1977    return true;
   1978  }
   1979 
   1980  MOZ_ASSERT(aSize.IsExplicitSize());
   1981  const auto& size = aSize.AsExplicitSize();
   1982 
   1983  // If either dimension contains a non-zero percentage, rendering for that
   1984  // dimension straightforwardly depends on frame size.
   1985  if (size.width.HasPercent() || size.height.HasPercent()) {
   1986    return true;
   1987  }
   1988 
   1989  // If both dimensions are fixed lengths, there's no dependency.
   1990  if (!size.width.IsAuto() && !size.height.IsAuto()) {
   1991    return false;
   1992  }
   1993 
   1994  // Gradient rendering depends on frame size when auto is involved because
   1995  // gradients have no intrinsic ratio or dimensions, and therefore the relevant
   1996  // dimension is "treat[ed] as 100%".
   1997  if (aImage.IsGradient()) {
   1998    return true;
   1999  }
   2000 
   2001  // XXX Element rendering for auto or fixed length doesn't depend on frame size
   2002  //     according to the spec.  However, we don't implement the spec yet, so
   2003  //     for now we bail and say element() plus auto affects ultimate size.
   2004  if (aImage.IsElement()) {
   2005    return true;
   2006  }
   2007 
   2008  MOZ_ASSERT(aImage.IsImageRequestType(), "Missed some image");
   2009  if (auto* request = aImage.GetImageRequest()) {
   2010    nsCOMPtr<imgIContainer> imgContainer;
   2011    request->GetImage(getter_AddRefs(imgContainer));
   2012    if (imgContainer) {
   2013      CSSIntSize imageSize;
   2014      AspectRatio imageRatio;
   2015      bool hasWidth, hasHeight;
   2016      // We could bother getting the right resolution here but it doesn't matter
   2017      // since we ignore `imageSize`.
   2018      nsLayoutUtils::ComputeSizeForDrawing(imgContainer, ImageResolution(),
   2019                                           imageSize, imageRatio, hasWidth,
   2020                                           hasHeight);
   2021 
   2022      // If the image has a fixed width and height, rendering never depends on
   2023      // the frame size.
   2024      if (hasWidth && hasHeight) {
   2025        return false;
   2026      }
   2027 
   2028      // If the image has an intrinsic ratio, rendering will depend on frame
   2029      // size when background-size is all auto.
   2030      if (imageRatio) {
   2031        return size.width.IsAuto() == size.height.IsAuto();
   2032      }
   2033 
   2034      // Otherwise, rendering depends on frame size when the image dimensions
   2035      // and background-size don't complement each other.
   2036      return !(hasWidth && size.width.IsLengthPercentage()) &&
   2037             !(hasHeight && size.height.IsLengthPercentage());
   2038    }
   2039  }
   2040 
   2041  // Passed the gauntlet: no dependency.
   2042  return false;
   2043 }
   2044 
   2045 nsStyleImageLayers::Layer::Layer()
   2046    : mImage(StyleImage::None()),
   2047      mSize(StyleBackgroundSize::ExplicitSize(LengthPercentageOrAuto::Auto(),
   2048                                              LengthPercentageOrAuto::Auto())),
   2049 
   2050      mClip(StyleGeometryBox::BorderBox),
   2051      mAttachment(StyleImageLayerAttachment::Scroll),
   2052      mBlendMode(StyleBlend::Normal),
   2053      mComposite(StyleMaskComposite::Add),
   2054      mMaskMode(StyleMaskMode::MatchSource) {}
   2055 
   2056 nsStyleImageLayers::Layer::~Layer() = default;
   2057 
   2058 void nsStyleImageLayers::Layer::Initialize(
   2059    nsStyleImageLayers::LayerType aType) {
   2060  mPosition = Position::FromPercentage(0.);
   2061 
   2062  if (aType == LayerType::Background) {
   2063    mOrigin = StyleGeometryBox::PaddingBox;
   2064  } else {
   2065    MOZ_ASSERT(aType == LayerType::Mask, "unsupported layer type.");
   2066    mOrigin = StyleGeometryBox::BorderBox;
   2067  }
   2068 }
   2069 
   2070 bool nsStyleImageLayers::Layer::
   2071    RenderingMightDependOnPositioningAreaSizeChange() const {
   2072  // Do we even have an image?
   2073  if (mImage.IsNone()) {
   2074    return false;
   2075  }
   2076 
   2077  return mPosition.DependsOnPositioningAreaSize() ||
   2078         SizeDependsOnPositioningAreaSize(mSize, mImage.FinalImage()) ||
   2079         mRepeat.DependsOnPositioningAreaSize();
   2080 }
   2081 
   2082 bool nsStyleImageLayers::Layer::operator==(const Layer& aOther) const {
   2083  return mAttachment == aOther.mAttachment && mClip == aOther.mClip &&
   2084         mOrigin == aOther.mOrigin && mRepeat == aOther.mRepeat &&
   2085         mBlendMode == aOther.mBlendMode && mPosition == aOther.mPosition &&
   2086         mSize == aOther.mSize && mImage == aOther.mImage &&
   2087         mMaskMode == aOther.mMaskMode && mComposite == aOther.mComposite;
   2088 }
   2089 
   2090 template <class ComputedValueItem>
   2091 static void FillImageLayerList(
   2092    nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
   2093    ComputedValueItem nsStyleImageLayers::Layer::* aResultLocation,
   2094    uint32_t aItemCount, uint32_t aFillCount) {
   2095  MOZ_ASSERT(aFillCount <= aLayers.Length(), "unexpected array length");
   2096  for (uint32_t sourceLayer = 0, destLayer = aItemCount; destLayer < aFillCount;
   2097       ++sourceLayer, ++destLayer) {
   2098    aLayers[destLayer].*aResultLocation = aLayers[sourceLayer].*aResultLocation;
   2099  }
   2100 }
   2101 
   2102 // The same as FillImageLayerList, but for values stored in
   2103 // layer.mPosition.*aResultLocation instead of layer.*aResultLocation.
   2104 static void FillImageLayerPositionCoordList(
   2105    nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
   2106    LengthPercentage Position::* aResultLocation, uint32_t aItemCount,
   2107    uint32_t aFillCount) {
   2108  MOZ_ASSERT(aFillCount <= aLayers.Length(), "unexpected array length");
   2109  for (uint32_t sourceLayer = 0, destLayer = aItemCount; destLayer < aFillCount;
   2110       ++sourceLayer, ++destLayer) {
   2111    aLayers[destLayer].mPosition.*aResultLocation =
   2112        aLayers[sourceLayer].mPosition.*aResultLocation;
   2113  }
   2114 }
   2115 
   2116 void nsStyleImageLayers::FillAllLayers(uint32_t aMaxItemCount) {
   2117  // Delete any extra items.  We need to keep layers in which any
   2118  // property was specified.
   2119  mLayers.TruncateLengthNonZero(aMaxItemCount);
   2120 
   2121  uint32_t fillCount = mImageCount;
   2122  FillImageLayerList(mLayers, &Layer::mImage, mImageCount, fillCount);
   2123  FillImageLayerList(mLayers, &Layer::mRepeat, mRepeatCount, fillCount);
   2124  FillImageLayerList(mLayers, &Layer::mAttachment, mAttachmentCount, fillCount);
   2125  FillImageLayerList(mLayers, &Layer::mClip, mClipCount, fillCount);
   2126  FillImageLayerList(mLayers, &Layer::mBlendMode, mBlendModeCount, fillCount);
   2127  FillImageLayerList(mLayers, &Layer::mOrigin, mOriginCount, fillCount);
   2128  FillImageLayerPositionCoordList(mLayers, &Position::horizontal,
   2129                                  mPositionXCount, fillCount);
   2130  FillImageLayerPositionCoordList(mLayers, &Position::vertical, mPositionYCount,
   2131                                  fillCount);
   2132  FillImageLayerList(mLayers, &Layer::mSize, mSizeCount, fillCount);
   2133  FillImageLayerList(mLayers, &Layer::mMaskMode, mMaskModeCount, fillCount);
   2134  FillImageLayerList(mLayers, &Layer::mComposite, mCompositeCount, fillCount);
   2135 }
   2136 
   2137 static bool UrlValuesEqual(const StyleImage& aImage,
   2138                           const StyleImage& aOtherImage) {
   2139  const auto* url = aImage.GetImageRequestURLValue();
   2140  const auto* other = aOtherImage.GetImageRequestURLValue();
   2141  return url == other || (url && other && *url == *other);
   2142 }
   2143 
   2144 nsChangeHint nsStyleImageLayers::Layer::CalcDifference(
   2145    const nsStyleImageLayers::Layer& aNewLayer) const {
   2146  nsChangeHint hint = nsChangeHint(0);
   2147  if (!UrlValuesEqual(mImage, aNewLayer.mImage)) {
   2148    hint |= nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects;
   2149  } else if (mAttachment != aNewLayer.mAttachment || mClip != aNewLayer.mClip ||
   2150             mOrigin != aNewLayer.mOrigin || mRepeat != aNewLayer.mRepeat ||
   2151             mBlendMode != aNewLayer.mBlendMode || mSize != aNewLayer.mSize ||
   2152             mImage != aNewLayer.mImage || mMaskMode != aNewLayer.mMaskMode ||
   2153             mComposite != aNewLayer.mComposite) {
   2154    hint |= nsChangeHint_RepaintFrame;
   2155  }
   2156 
   2157  if (mPosition != aNewLayer.mPosition) {
   2158    hint |= nsChangeHint_UpdateBackgroundPosition;
   2159  }
   2160 
   2161  return hint;
   2162 }
   2163 
   2164 // --------------------
   2165 // nsStyleBackground
   2166 //
   2167 
   2168 nsStyleBackground::nsStyleBackground()
   2169    : mImage(nsStyleImageLayers::LayerType::Background),
   2170      mBackgroundColor(StyleColor::Transparent()) {
   2171  MOZ_COUNT_CTOR(nsStyleBackground);
   2172 }
   2173 
   2174 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
   2175    : mImage(aSource.mImage), mBackgroundColor(aSource.mBackgroundColor) {
   2176  MOZ_COUNT_CTOR(nsStyleBackground);
   2177 }
   2178 
   2179 void nsStyleBackground::TriggerImageLoads(Document& aDocument,
   2180                                          const nsStyleBackground* aOldStyle) {
   2181  MOZ_ASSERT(NS_IsMainThread());
   2182  mImage.ResolveImages(aDocument, aOldStyle ? &aOldStyle->mImage : nullptr);
   2183 }
   2184 
   2185 nsChangeHint nsStyleBackground::CalcDifference(
   2186    const nsStyleBackground& aNewData) const {
   2187  nsChangeHint hint = nsChangeHint(0);
   2188  if (mBackgroundColor != aNewData.mBackgroundColor) {
   2189    hint |= nsChangeHint_RepaintFrame;
   2190  }
   2191 
   2192  hint |= mImage.CalcDifference(aNewData.mImage,
   2193                                nsStyleImageLayers::LayerType::Background);
   2194 
   2195  return hint;
   2196 }
   2197 
   2198 bool nsStyleBackground::HasFixedBackground(nsIFrame* aFrame) const {
   2199  NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mImage) {
   2200    const nsStyleImageLayers::Layer& layer = mImage.mLayers[i];
   2201    if (layer.mAttachment == StyleImageLayerAttachment::Fixed &&
   2202        !layer.mImage.IsNone() && !nsLayoutUtils::IsTransformed(aFrame)) {
   2203      return true;
   2204    }
   2205  }
   2206  return false;
   2207 }
   2208 
   2209 nscolor nsStyleBackground::BackgroundColor(const nsIFrame* aFrame) const {
   2210  return mBackgroundColor.CalcColor(aFrame);
   2211 }
   2212 
   2213 nscolor nsStyleBackground::BackgroundColor(const ComputedStyle* aStyle) const {
   2214  return mBackgroundColor.CalcColor(*aStyle);
   2215 }
   2216 
   2217 bool nsStyleBackground::IsTransparent(const nsIFrame* aFrame) const {
   2218  return IsTransparent(aFrame->Style());
   2219 }
   2220 
   2221 bool nsStyleBackground::IsTransparent(const ComputedStyle* aStyle) const {
   2222  return BottomLayer().mImage.IsNone() && mImage.mImageCount == 1 &&
   2223         NS_GET_A(BackgroundColor(aStyle)) == 0;
   2224 }
   2225 
   2226 StyleTransition::StyleTransition(const StyleTransition& aCopy) = default;
   2227 
   2228 bool StyleTransition::operator==(const StyleTransition& aOther) const {
   2229  return mTimingFunction == aOther.mTimingFunction &&
   2230         mDuration == aOther.mDuration && mDelay == aOther.mDelay &&
   2231         mProperty == aOther.mProperty && mBehavior == aOther.mBehavior;
   2232 }
   2233 
   2234 StyleAnimation::StyleAnimation(const StyleAnimation& aCopy) = default;
   2235 
   2236 bool StyleAnimation::operator==(const StyleAnimation& aOther) const {
   2237  return mTimingFunction == aOther.mTimingFunction &&
   2238         mDuration == aOther.mDuration && mDelay == aOther.mDelay &&
   2239         mName == aOther.mName && mDirection == aOther.mDirection &&
   2240         mFillMode == aOther.mFillMode && mPlayState == aOther.mPlayState &&
   2241         mIterationCount == aOther.mIterationCount &&
   2242         mComposition == aOther.mComposition && mTimeline == aOther.mTimeline;
   2243 }
   2244 
   2245 // --------------------
   2246 // nsStyleDisplay
   2247 //
   2248 nsStyleDisplay::nsStyleDisplay()
   2249    : mDisplay(StyleDisplay::Inline),
   2250      mOriginalDisplay(StyleDisplay::Inline),
   2251      mContentVisibility(StyleContentVisibility::Visible),
   2252      mContainerType(StyleContainerType::NORMAL),
   2253      mAppearance(StyleAppearance::None),
   2254      mContain(StyleContain::NONE),
   2255      mEffectiveContainment(StyleContain::NONE),
   2256      mDefaultAppearance(StyleAppearance::None),
   2257      mPosition(StylePositionProperty::Static),
   2258      mFloat(StyleFloat::None),
   2259      mClear(StyleClear::None),
   2260      mBreakInside(StyleBreakWithin::Auto),
   2261      mBreakBefore(StyleBreakBetween::Auto),
   2262      mBreakAfter(StyleBreakBetween::Auto),
   2263      mOverflowX(StyleOverflow::Visible),
   2264      mOverflowY(StyleOverflow::Visible),
   2265      mScrollbarGutter(StyleScrollbarGutter::AUTO),
   2266      mResize(StyleResize::None),
   2267      mOrient(StyleOrient::Inline),
   2268      mIsolation(StyleIsolation::Auto),
   2269      mTopLayer(StyleTopLayer::None),
   2270      mTouchAction(StyleTouchAction::AUTO),
   2271      mScrollBehavior(StyleScrollBehavior::Auto),
   2272      mOverscrollBehaviorX(StyleOverscrollBehavior::Auto),
   2273      mOverscrollBehaviorY(StyleOverscrollBehavior::Auto),
   2274      mOverflowAnchor(StyleOverflowAnchor::Auto),
   2275      mScrollSnapAlign{StyleScrollSnapAlignKeyword::None,
   2276                       StyleScrollSnapAlignKeyword::None},
   2277      mScrollSnapStop{StyleScrollSnapStop::Normal},
   2278      mScrollSnapType{StyleScrollSnapAxis::Both,
   2279                      StyleScrollSnapStrictness::None},
   2280      mBackfaceVisibility(StyleBackfaceVisibility::Visible),
   2281      mTransformStyle(StyleTransformStyle::Flat),
   2282      mTransformBox(StyleTransformBox::ViewBox),
   2283      mRotate(StyleRotate::None()),
   2284      mTranslate(StyleTranslate::None()),
   2285      mScale(StyleScale::None()),
   2286      mWillChange{{}, {0}},
   2287      mOffsetPath(StyleOffsetPath::None()),
   2288      mOffsetDistance(LengthPercentage::Zero()),
   2289      mOffsetRotate{true, StyleAngle{0.0}},
   2290      mOffsetAnchor(StylePositionOrAuto::Auto()),
   2291      mOffsetPosition(StyleOffsetPosition::Normal()),
   2292      mTransformOrigin{LengthPercentage::FromPercentage(0.5),
   2293                       LengthPercentage::FromPercentage(0.5),
   2294                       {0.}},
   2295      mChildPerspective(StylePerspective::None()),
   2296      mPerspectiveOrigin(Position::FromPercentage(0.5f)),
   2297      mVerticalAlign(
   2298          StyleVerticalAlign::Keyword(StyleVerticalAlignKeyword::Baseline)),
   2299      mBaselineSource(StyleBaselineSource::Auto),
   2300      mWebkitLineClamp(0),
   2301      mShapeMargin(LengthPercentage::Zero()),
   2302      mShapeOutside(StyleShapeOutside::None()),
   2303      mAnchorScope(StyleAnchorScope::None()) {
   2304  MOZ_COUNT_CTOR(nsStyleDisplay);
   2305 }
   2306 
   2307 nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
   2308    : mDisplay(aSource.mDisplay),
   2309      mOriginalDisplay(aSource.mOriginalDisplay),
   2310      mContentVisibility(aSource.mContentVisibility),
   2311      mContainerType(aSource.mContainerType),
   2312      mAppearance(aSource.mAppearance),
   2313      mContain(aSource.mContain),
   2314      mEffectiveContainment(aSource.mEffectiveContainment),
   2315      mDefaultAppearance(aSource.mDefaultAppearance),
   2316      mPosition(aSource.mPosition),
   2317      mFloat(aSource.mFloat),
   2318      mClear(aSource.mClear),
   2319      mBreakInside(aSource.mBreakInside),
   2320      mBreakBefore(aSource.mBreakBefore),
   2321      mBreakAfter(aSource.mBreakAfter),
   2322      mOverflowX(aSource.mOverflowX),
   2323      mOverflowY(aSource.mOverflowY),
   2324      mScrollbarGutter(aSource.mScrollbarGutter),
   2325      mResize(aSource.mResize),
   2326      mOrient(aSource.mOrient),
   2327      mIsolation(aSource.mIsolation),
   2328      mTopLayer(aSource.mTopLayer),
   2329      mTouchAction(aSource.mTouchAction),
   2330      mScrollBehavior(aSource.mScrollBehavior),
   2331      mOverscrollBehaviorX(aSource.mOverscrollBehaviorX),
   2332      mOverscrollBehaviorY(aSource.mOverscrollBehaviorY),
   2333      mOverflowAnchor(aSource.mOverflowAnchor),
   2334      mScrollSnapAlign(aSource.mScrollSnapAlign),
   2335      mScrollSnapStop(aSource.mScrollSnapStop),
   2336      mScrollSnapType(aSource.mScrollSnapType),
   2337      mBackfaceVisibility(aSource.mBackfaceVisibility),
   2338      mTransformStyle(aSource.mTransformStyle),
   2339      mTransformBox(aSource.mTransformBox),
   2340      mTransform(aSource.mTransform),
   2341      mRotate(aSource.mRotate),
   2342      mTranslate(aSource.mTranslate),
   2343      mScale(aSource.mScale),
   2344      mContainerName(aSource.mContainerName),
   2345      mWillChange(aSource.mWillChange),
   2346      mOffsetPath(aSource.mOffsetPath),
   2347      mOffsetDistance(aSource.mOffsetDistance),
   2348      mOffsetRotate(aSource.mOffsetRotate),
   2349      mOffsetAnchor(aSource.mOffsetAnchor),
   2350      mOffsetPosition(aSource.mOffsetPosition),
   2351      mTransformOrigin(aSource.mTransformOrigin),
   2352      mChildPerspective(aSource.mChildPerspective),
   2353      mPerspectiveOrigin(aSource.mPerspectiveOrigin),
   2354      mVerticalAlign(aSource.mVerticalAlign),
   2355      mBaselineSource(aSource.mBaselineSource),
   2356      mWebkitLineClamp(aSource.mWebkitLineClamp),
   2357      mShapeImageThreshold(aSource.mShapeImageThreshold),
   2358      mShapeMargin(aSource.mShapeMargin),
   2359      mShapeOutside(aSource.mShapeOutside),
   2360      mAnchorName(aSource.mAnchorName),
   2361      mAnchorScope(aSource.mAnchorScope) {
   2362  MOZ_COUNT_CTOR(nsStyleDisplay);
   2363 }
   2364 
   2365 void nsStyleDisplay::TriggerImageLoads(Document& aDocument,
   2366                                       const nsStyleDisplay* aOldStyle) {
   2367  MOZ_ASSERT(NS_IsMainThread());
   2368 
   2369  if (mShapeOutside.IsImage()) {
   2370    const auto* old = aOldStyle && aOldStyle->mShapeOutside.IsImage()
   2371                          ? &aOldStyle->mShapeOutside.AsImage()
   2372                          : nullptr;
   2373    // Const-cast is ugly but legit, we could avoid it by generating mut-casts
   2374    // with cbindgen.
   2375    const_cast<StyleImage&>(mShapeOutside.AsImage())
   2376        .ResolveImage(aDocument, old);
   2377  }
   2378 }
   2379 
   2380 template <typename TransformLike>
   2381 static inline nsChangeHint CompareTransformValues(
   2382    const TransformLike& aOldTransform, const TransformLike& aNewTransform) {
   2383  nsChangeHint result = nsChangeHint(0);
   2384 
   2385  // Note: If we add a new change hint for transform changes here, we have to
   2386  // modify KeyframeEffect::CalculateCumulativeChangeHint too!
   2387  if (aOldTransform != aNewTransform) {
   2388    result |= nsChangeHint_UpdateTransformLayer;
   2389    if (!aOldTransform.IsNone() && !aNewTransform.IsNone()) {
   2390      result |= nsChangeHint_UpdatePostTransformOverflow;
   2391    } else {
   2392      result |= nsChangeHint_UpdateOverflow;
   2393    }
   2394  }
   2395 
   2396  return result;
   2397 }
   2398 
   2399 static inline nsChangeHint CompareMotionValues(
   2400    const nsStyleDisplay& aDisplay, const nsStyleDisplay& aNewDisplay) {
   2401  if (aDisplay.mOffsetPath == aNewDisplay.mOffsetPath) {
   2402    if (aDisplay.mOffsetDistance == aNewDisplay.mOffsetDistance &&
   2403        aDisplay.mOffsetRotate == aNewDisplay.mOffsetRotate &&
   2404        aDisplay.mOffsetAnchor == aNewDisplay.mOffsetAnchor &&
   2405        aDisplay.mOffsetPosition == aNewDisplay.mOffsetPosition) {
   2406      return nsChangeHint(0);
   2407    }
   2408 
   2409    // No motion path transform is applied.
   2410    if (aDisplay.mOffsetPath.IsNone()) {
   2411      return nsChangeHint_NeutralChange;
   2412    }
   2413  }
   2414 
   2415  // TODO: Bug 1482737: This probably doesn't need to UpdateOverflow
   2416  // (or UpdateTransformLayer) if there's already a transform.
   2417  // Set the same hints as what we use for transform because motion path is
   2418  // a kind of transform and will be combined with other transforms.
   2419  nsChangeHint result = nsChangeHint_UpdateTransformLayer;
   2420  if (!aDisplay.mOffsetPath.IsNone() && !aNewDisplay.mOffsetPath.IsNone()) {
   2421    result |= nsChangeHint_UpdatePostTransformOverflow;
   2422  } else {
   2423    result |= nsChangeHint_UpdateOverflow;
   2424  }
   2425  return result;
   2426 }
   2427 
   2428 static bool ScrollbarGenerationChanged(const nsStyleDisplay& aOld,
   2429                                       const nsStyleDisplay& aNew) {
   2430  auto changed = [](StyleOverflow aOld, StyleOverflow aNew) {
   2431    return aOld != aNew &&
   2432           (aOld == StyleOverflow::Hidden || aNew == StyleOverflow::Hidden);
   2433  };
   2434  return changed(aOld.mOverflowX, aNew.mOverflowX) ||
   2435         changed(aOld.mOverflowY, aNew.mOverflowY);
   2436 }
   2437 
   2438 static bool AppearanceValueAffectsFrames(StyleAppearance aAppearance,
   2439                                         StyleAppearance aDefaultAppearance) {
   2440  switch (aAppearance) {
   2441    case StyleAppearance::None:
   2442      // Checkbox / radio with appearance none doesn't construct an
   2443      // nsCheckboxRadioFrame.
   2444      return aDefaultAppearance == StyleAppearance::Checkbox ||
   2445             aDefaultAppearance == StyleAppearance::Radio;
   2446    case StyleAppearance::Textfield:
   2447      // This is for <input type=number/search> where we allow authors to
   2448      // specify a |-moz-appearance:textfield| to get a control without buttons.
   2449      // We need to reframe since this affects the spinbox creation in
   2450      // nsNumberControlFrame::CreateAnonymousContent.
   2451      return aDefaultAppearance == StyleAppearance::NumberInput ||
   2452             aDefaultAppearance == StyleAppearance::PasswordInput;
   2453    case StyleAppearance::Menulist:
   2454      // This affects the menulist button creation.
   2455      return aDefaultAppearance == StyleAppearance::Menulist;
   2456    default:
   2457      return false;
   2458  }
   2459 }
   2460 
   2461 nsChangeHint nsStyleDisplay::CalcDifference(
   2462    const nsStyleDisplay& aNewData, const ComputedStyle& aOldStyle) const {
   2463  if (mDisplay != aNewData.mDisplay ||
   2464      (mFloat == StyleFloat::None) != (aNewData.mFloat == StyleFloat::None) ||
   2465      mTopLayer != aNewData.mTopLayer || mResize != aNewData.mResize) {
   2466    return nsChangeHint_ReconstructFrame;
   2467  }
   2468 
   2469  auto oldAppearance = EffectiveAppearance();
   2470  auto newAppearance = aNewData.EffectiveAppearance();
   2471  if (oldAppearance != newAppearance) {
   2472    // Changes to the mDefaultAppearance values handled in
   2473    // AppearanceValueAffectsFrames reconstruct their frames via other means.
   2474    // E.g. switching the <input> type attribute reframes via
   2475    // GetAttributeChangeHint. Thus, it doesn't matter whether we pick
   2476    // mDefaultAppearance or aNewData.mDefaultAppearance for the check below.
   2477    if (AppearanceValueAffectsFrames(oldAppearance, mDefaultAppearance) ||
   2478        AppearanceValueAffectsFrames(newAppearance, mDefaultAppearance)) {
   2479      return nsChangeHint_ReconstructFrame;
   2480    }
   2481  }
   2482 
   2483  auto hint = nsChangeHint(0);
   2484  const auto containmentDiff =
   2485      mEffectiveContainment ^ aNewData.mEffectiveContainment;
   2486  if (containmentDiff) {
   2487    if (containmentDiff & StyleContain::STYLE) {
   2488      // Style containment affects counters so we need to re-frame.
   2489      return nsChangeHint_ReconstructFrame;
   2490    }
   2491    if (containmentDiff & (StyleContain::PAINT | StyleContain::LAYOUT)) {
   2492      // Paint and layout containment boxes are absolutely/fixed positioning
   2493      // containers.
   2494      hint |= nsChangeHint_UpdateContainingBlock;
   2495    }
   2496    // The other container types only need a reflow.
   2497    hint |= nsChangeHint_AllReflowHints | nsChangeHint_RepaintFrame;
   2498  }
   2499  if (mPosition != aNewData.mPosition) {
   2500    if (IsAbsolutelyPositionedStyle() ||
   2501        aNewData.IsAbsolutelyPositionedStyle()) {
   2502      // This changes our parent relationship on the frame tree and / or needs
   2503      // to create a placeholder, so gotta reframe. There are some cases (when
   2504      // switching from fixed to absolute or viceversa, if our containing block
   2505      // happens to remain the same, i.e., if it has a transform or such) where
   2506      // this wouldn't really be needed (though we'd still need to move the
   2507      // frame from one child list to another). In any case we don't have a hand
   2508      // to that information from here, and it doesn't seem like a case worth
   2509      // optimizing for.
   2510      return nsChangeHint_ReconstructFrame;
   2511    }
   2512    // We start or stop being a containing block for abspos descendants. This
   2513    // also causes painting to change, as we'd become a pseudo-stacking context.
   2514    if (IsRelativelyOrStickyPositionedStyle() !=
   2515        aNewData.IsRelativelyOrStickyPositionedStyle()) {
   2516      hint |= nsChangeHint_UpdateContainingBlock | nsChangeHint_RepaintFrame;
   2517    }
   2518    if (IsPositionForcingStackingContext() !=
   2519        aNewData.IsPositionForcingStackingContext()) {
   2520      hint |= nsChangeHint_RepaintFrame;
   2521    }
   2522    // On top of that: if the above ends up not reframing, we need a reflow to
   2523    // compute our relative, static or sticky position.
   2524    hint |= nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition;
   2525  }
   2526 
   2527  if (mScrollSnapAlign != aNewData.mScrollSnapAlign ||
   2528      mScrollSnapType != aNewData.mScrollSnapType ||
   2529      mScrollSnapStop != aNewData.mScrollSnapStop) {
   2530    hint |= nsChangeHint_RepaintFrame;
   2531  }
   2532  if (mScrollBehavior != aNewData.mScrollBehavior) {
   2533    hint |= nsChangeHint_NeutralChange;
   2534  }
   2535 
   2536  if (mOverflowX != aNewData.mOverflowX || mOverflowY != aNewData.mOverflowY) {
   2537    const bool isScrollable = IsScrollableOverflow();
   2538    if (isScrollable != aNewData.IsScrollableOverflow()) {
   2539      // We may need to construct or destroy a scroll frame as a result of this
   2540      // change. If we don't, we still need to update our overflow in some cases
   2541      // (like svg:foreignObject), which ignore the scrollable-ness of our
   2542      // overflow.
   2543      hint |= nsChangeHint_ScrollbarChange | nsChangeHint_UpdateOverflow |
   2544              nsChangeHint_RepaintFrame;
   2545    } else if (isScrollable) {
   2546      if (ScrollbarGenerationChanged(*this, aNewData)) {
   2547        // We might need to reframe in the case of hidden -> non-hidden case
   2548        // though, since ScrollContainerFrame::CreateAnonymousContent avoids
   2549        // creating scrollbars altogether for overflow: hidden. That seems it
   2550        // could create some interesting perf cliffs...
   2551        hint |= nsChangeHint_ScrollbarChange;
   2552      } else {
   2553        // Otherwise, for changes where both overflow values are scrollable,
   2554        // means that scrollbars may appear or disappear. We need to reflow,
   2555        // since reflow is what determines which scrollbars if any are visible.
   2556        hint |= nsChangeHint_ReflowHintsForScrollbarChange;
   2557      }
   2558    } else {
   2559      // Otherwise this is a change between 'visible' and 'clip'.
   2560      // Here only whether we have a 'clip' changes, so just repaint and
   2561      // update our overflow areas in that case.
   2562      hint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
   2563    }
   2564  }
   2565 
   2566  if (mScrollbarGutter != aNewData.mScrollbarGutter) {
   2567    if (IsScrollableOverflow() || aOldStyle.IsRootElementStyle()) {
   2568      // Changing scrollbar-gutter affects available inline-size of a inner
   2569      // scrolled frame, so we need a reflow for scrollbar change. Note that the
   2570      // root is always scrollable in HTML, even if its style doesn't say so.
   2571      hint |= nsChangeHint_ReflowHintsForScrollbarChange;
   2572    } else {
   2573      // scrollbar-gutter only applies to scroll containers.
   2574      hint |= nsChangeHint_NeutralChange;
   2575    }
   2576  }
   2577 
   2578  if (mFloat != aNewData.mFloat) {
   2579    // Changing which side we're floating on (float:none was handled above).
   2580    hint |= nsChangeHint_ReflowHintsForFloatAreaChange;
   2581  }
   2582 
   2583  if (mShapeOutside != aNewData.mShapeOutside ||
   2584      mShapeMargin != aNewData.mShapeMargin ||
   2585      mShapeImageThreshold != aNewData.mShapeImageThreshold) {
   2586    if (aNewData.mFloat != StyleFloat::None) {
   2587      // If we are floating, and our shape-outside, shape-margin, or
   2588      // shape-image-threshold are changed, our descendants are not impacted,
   2589      // but our ancestor and siblings are.
   2590      hint |= nsChangeHint_ReflowHintsForFloatAreaChange;
   2591    } else {
   2592      // shape-outside or shape-margin or shape-image-threshold changed,
   2593      // but we don't need to reflow because we're not floating.
   2594      hint |= nsChangeHint_NeutralChange;
   2595    }
   2596  }
   2597 
   2598  if (mWebkitLineClamp != aNewData.mWebkitLineClamp ||
   2599      mVerticalAlign != aNewData.mVerticalAlign ||
   2600      mBaselineSource != aNewData.mBaselineSource) {
   2601    // XXX Can this just be AllReflowHints + RepaintFrame, and be included in
   2602    // the block below?
   2603    hint |= NS_STYLE_HINT_REFLOW;
   2604  }
   2605 
   2606  // XXX the following is conservative, for now: changing float breaking
   2607  // shouldn't necessarily require a repaint, reflow should suffice.
   2608  //
   2609  // FIXME(emilio): We definitely change the frame tree in nsCSSFrameConstructor
   2610  // based on break-before / break-after... Shouldn't that reframe?
   2611  if (mClear != aNewData.mClear || mBreakInside != aNewData.mBreakInside ||
   2612      mBreakBefore != aNewData.mBreakBefore ||
   2613      mBreakAfter != aNewData.mBreakAfter ||
   2614      mAppearance != aNewData.mAppearance ||
   2615      mDefaultAppearance != aNewData.mDefaultAppearance ||
   2616      mOrient != aNewData.mOrient) {
   2617    hint |= nsChangeHint_AllReflowHints | nsChangeHint_RepaintFrame;
   2618  }
   2619 
   2620  if (mIsolation != aNewData.mIsolation) {
   2621    hint |= nsChangeHint_RepaintFrame;
   2622  }
   2623 
   2624  /* If we've added or removed the transform property, we need to reconstruct
   2625   * the frame to add or remove the view object, and also to handle abs-pos and
   2626   * fixed-pos containers.
   2627   */
   2628  if (HasTransformStyle() != aNewData.HasTransformStyle()) {
   2629    hint |= nsChangeHint_ComprehensiveAddOrRemoveTransform;
   2630  } else {
   2631    /* Otherwise, if we've kept the property lying around and we already had a
   2632     * transform, we need to see whether or not we've changed the transform.
   2633     * If so, we need to recompute its overflow rect (which probably changed
   2634     * if the transform changed) and to redraw within the bounds of that new
   2635     * overflow rect.
   2636     *
   2637     * If the property isn't present in either style struct, we still do the
   2638     * comparisons but turn all the resulting change hints into
   2639     * nsChangeHint_NeutralChange.
   2640     */
   2641    nsChangeHint transformHint = CalcTransformPropertyDifference(aNewData);
   2642 
   2643    if (transformHint) {
   2644      if (HasTransformStyle()) {
   2645        hint |= transformHint;
   2646      } else {
   2647        hint |= nsChangeHint_NeutralChange;
   2648      }
   2649    }
   2650  }
   2651 
   2652  if (HasPerspectiveStyle() != aNewData.HasPerspectiveStyle()) {
   2653    // A change from/to being a containing block for position:fixed.
   2654    hint |= nsChangeHint_UpdateContainingBlock | nsChangeHint_UpdateOverflow |
   2655            nsChangeHint_RepaintFrame;
   2656  } else if (mChildPerspective != aNewData.mChildPerspective) {
   2657    hint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
   2658  }
   2659 
   2660  // Note that the HasTransformStyle() != aNewData.HasTransformStyle()
   2661  // test above handles relevant changes in the StyleWillChangeBit_TRANSFORM
   2662  // bit, which in turn handles frame reconstruction for changes in the
   2663  // containing block of fixed-positioned elements.
   2664  auto willChangeBitsChanged = mWillChange.bits ^ aNewData.mWillChange.bits;
   2665 
   2666  if (willChangeBitsChanged &
   2667      (StyleWillChangeBits::STACKING_CONTEXT_UNCONDITIONAL |
   2668       StyleWillChangeBits::SCROLL | StyleWillChangeBits::OPACITY |
   2669       StyleWillChangeBits::PERSPECTIVE | StyleWillChangeBits::TRANSFORM |
   2670       StyleWillChangeBits::Z_INDEX)) {
   2671    hint |= nsChangeHint_RepaintFrame;
   2672  }
   2673 
   2674  if (willChangeBitsChanged &
   2675      (StyleWillChangeBits::FIXPOS_CB_NON_SVG | StyleWillChangeBits::TRANSFORM |
   2676       StyleWillChangeBits::PERSPECTIVE | StyleWillChangeBits::POSITION |
   2677       StyleWillChangeBits::CONTAIN)) {
   2678    hint |= nsChangeHint_UpdateContainingBlock;
   2679  }
   2680 
   2681  // If touch-action is changed, we need to regenerate the event regions on
   2682  // the layers and send it over to the compositor for APZ to handle.
   2683  if (mTouchAction != aNewData.mTouchAction) {
   2684    hint |= nsChangeHint_RepaintFrame;
   2685  }
   2686 
   2687  // If overscroll-behavior has changed, the changes are picked up
   2688  // during a repaint.
   2689  if (mOverscrollBehaviorX != aNewData.mOverscrollBehaviorX ||
   2690      mOverscrollBehaviorY != aNewData.mOverscrollBehaviorY) {
   2691    hint |= nsChangeHint_SchedulePaint;
   2692  }
   2693 
   2694  if (mOriginalDisplay != aNewData.mOriginalDisplay) {
   2695    // Our hypothetical box position may have changed.
   2696    //
   2697    // Note that it doesn't matter if we look at the old or the new struct,
   2698    // since a change on whether we need a hypothetical position would trigger
   2699    // reflow anyway.
   2700    if (IsAbsolutelyPositionedStyle() &&
   2701        aOldStyle.StylePosition()->NeedsHypotheticalPositionIfAbsPos()) {
   2702      hint |=
   2703          nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition;
   2704    } else {
   2705      hint |= nsChangeHint_NeutralChange;
   2706    }
   2707  }
   2708 
   2709  // Note:  Our current behavior for handling changes to the
   2710  // transition-duration, transition-delay, and transition-timing-function
   2711  // properties is to do nothing.  In other words, the transition
   2712  // property that matters is what it is when the transition begins, and
   2713  // we don't stop a transition later because the transition property
   2714  // changed.
   2715  // We do handle changes to transition-property, but we don't need to
   2716  // bother with anything here, since the transition manager is notified
   2717  // of any ComputedStyle change anyway.
   2718 
   2719  // Note: Likewise, for animation-*, the animation manager gets
   2720  // notified about every new ComputedStyle constructed, and it uses
   2721  // that opportunity to handle dynamic changes appropriately.
   2722 
   2723  // But we still need to return nsChangeHint_NeutralChange for these
   2724  // properties, since some data did change in the style struct.
   2725 
   2726  // TODO(emilio): Figure out change hints for container-name, maybe it needs to
   2727  // be handled by the style system as a special-case (since it changes
   2728  // container-query selection on descendants).
   2729  // container-type / contain / content-visibility are handled by the
   2730  // mEffectiveContainment check.
   2731  if (!hint && (mWillChange != aNewData.mWillChange ||
   2732                mOverflowAnchor != aNewData.mOverflowAnchor ||
   2733                mContentVisibility != aNewData.mContentVisibility ||
   2734                mContainerType != aNewData.mContainerType ||
   2735                mContain != aNewData.mContain ||
   2736                mContainerName != aNewData.mContainerName ||
   2737                mAnchorName != aNewData.mAnchorName ||
   2738                mAnchorScope != aNewData.mAnchorScope)) {
   2739    hint |= nsChangeHint_NeutralChange;
   2740  }
   2741 
   2742  return hint;
   2743 }
   2744 
   2745 nsChangeHint nsStyleDisplay::CalcTransformPropertyDifference(
   2746    const nsStyleDisplay& aNewData) const {
   2747  nsChangeHint transformHint = nsChangeHint(0);
   2748 
   2749  transformHint |= CompareTransformValues(mTransform, aNewData.mTransform);
   2750  transformHint |= CompareTransformValues(mRotate, aNewData.mRotate);
   2751  transformHint |= CompareTransformValues(mTranslate, aNewData.mTranslate);
   2752  transformHint |= CompareTransformValues(mScale, aNewData.mScale);
   2753  transformHint |= CompareMotionValues(*this, aNewData);
   2754 
   2755  if (mTransformOrigin != aNewData.mTransformOrigin) {
   2756    transformHint |= nsChangeHint_UpdateTransformLayer |
   2757                     nsChangeHint_UpdatePostTransformOverflow;
   2758  }
   2759 
   2760  if (mPerspectiveOrigin != aNewData.mPerspectiveOrigin ||
   2761      mTransformStyle != aNewData.mTransformStyle ||
   2762      mTransformBox != aNewData.mTransformBox) {
   2763    transformHint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
   2764  }
   2765 
   2766  if (mBackfaceVisibility != aNewData.mBackfaceVisibility) {
   2767    transformHint |= nsChangeHint_RepaintFrame;
   2768  }
   2769 
   2770  return transformHint;
   2771 }
   2772 
   2773 // --------------------
   2774 // nsStyleVisibility
   2775 //
   2776 
   2777 nsStyleVisibility::nsStyleVisibility(const Document& aDocument)
   2778    : mDirection(aDocument.GetBidiOptions() == IBMBIDI_TEXTDIRECTION_RTL
   2779                     ? StyleDirection::Rtl
   2780                     : StyleDirection::Ltr),
   2781      mVisible(StyleVisibility::Visible),
   2782      mImageRendering(StyleImageRendering::Auto),
   2783      mWritingMode(StyleWritingModeProperty::HorizontalTb),
   2784      mTextOrientation(StyleTextOrientation::Mixed),
   2785      mMozBoxCollapse(StyleMozBoxCollapse::Flex),
   2786      mPrintColorAdjust(StylePrintColorAdjust::Economy),
   2787      mImageOrientation(StyleImageOrientation::FromImage) {
   2788  MOZ_COUNT_CTOR(nsStyleVisibility);
   2789 }
   2790 
   2791 nsStyleVisibility::nsStyleVisibility(const nsStyleVisibility& aSource)
   2792    : mDirection(aSource.mDirection),
   2793      mVisible(aSource.mVisible),
   2794      mImageRendering(aSource.mImageRendering),
   2795      mWritingMode(aSource.mWritingMode),
   2796      mTextOrientation(aSource.mTextOrientation),
   2797      mMozBoxCollapse(aSource.mMozBoxCollapse),
   2798      mPrintColorAdjust(aSource.mPrintColorAdjust),
   2799      mImageOrientation(aSource.mImageOrientation) {
   2800  MOZ_COUNT_CTOR(nsStyleVisibility);
   2801 }
   2802 
   2803 nsChangeHint nsStyleVisibility::CalcDifference(
   2804    const nsStyleVisibility& aNewData) const {
   2805  nsChangeHint hint = nsChangeHint(0);
   2806 
   2807  if (mDirection != aNewData.mDirection ||
   2808      mWritingMode != aNewData.mWritingMode) {
   2809    // It's important that a change in mWritingMode results in frame
   2810    // reconstruction, because it may affect intrinsic size (see
   2811    // nsSubDocumentFrame::GetIntrinsicISize/BSize).
   2812    // Also, the used writing-mode value is now a field on nsIFrame and some
   2813    // classes (e.g. table rows/cells) copy their value from an ancestor.
   2814    return nsChangeHint_ReconstructFrame;
   2815  }
   2816  if (mImageOrientation != aNewData.mImageOrientation) {
   2817    hint |= nsChangeHint_AllReflowHints | nsChangeHint_RepaintFrame;
   2818  }
   2819  if (mVisible != aNewData.mVisible) {
   2820    if (mVisible == StyleVisibility::Visible ||
   2821        aNewData.mVisible == StyleVisibility::Visible) {
   2822      hint |= nsChangeHint_VisibilityChange;
   2823    }
   2824    if (mVisible == StyleVisibility::Collapse ||
   2825        aNewData.mVisible == StyleVisibility::Collapse) {
   2826      hint |= NS_STYLE_HINT_REFLOW;
   2827    } else {
   2828      hint |= NS_STYLE_HINT_VISUAL;
   2829    }
   2830  }
   2831  if (mTextOrientation != aNewData.mTextOrientation ||
   2832      mMozBoxCollapse != aNewData.mMozBoxCollapse) {
   2833    hint |= NS_STYLE_HINT_REFLOW;
   2834  }
   2835  if (mImageRendering != aNewData.mImageRendering) {
   2836    hint |= nsChangeHint_RepaintFrame;
   2837  }
   2838  if (mPrintColorAdjust != aNewData.mPrintColorAdjust) {
   2839    // color-adjust only affects media where dynamic changes can't happen.
   2840    hint |= nsChangeHint_NeutralChange;
   2841  }
   2842  return hint;
   2843 }
   2844 
   2845 StyleImageOrientation nsStyleVisibility::UsedImageOrientation(
   2846    imgIRequest* aRequest, StyleImageOrientation aOrientation) {
   2847  if (aOrientation == StyleImageOrientation::FromImage || !aRequest) {
   2848    return aOrientation;
   2849  }
   2850 
   2851  nsCOMPtr<nsIPrincipal> triggeringPrincipal =
   2852      aRequest->GetTriggeringPrincipal();
   2853 
   2854  // If the request was for a blob, the request may not have a triggering
   2855  // principal and we should use the input orientation.
   2856  if (!triggeringPrincipal) {
   2857    return aOrientation;
   2858  }
   2859 
   2860  nsCOMPtr<nsIURI> uri = aRequest->GetURI();
   2861  // If the image request is a data uri, then treat the request as a
   2862  // same origin request.
   2863  bool isSameOrigin =
   2864      uri->SchemeIs("data") || triggeringPrincipal->IsSameOrigin(uri);
   2865 
   2866  // If the image request is a cross-origin request that does not use CORS,
   2867  // do not enforce the image orientation found in the style. Use the image
   2868  // orientation found in the exif data.
   2869  if (!isSameOrigin && !nsLayoutUtils::ImageRequestUsesCORS(aRequest)) {
   2870    return StyleImageOrientation::FromImage;
   2871  }
   2872 
   2873  return aOrientation;
   2874 }
   2875 
   2876 //-----------------------
   2877 // nsStyleContent
   2878 //
   2879 
   2880 nsStyleContent::nsStyleContent() : mContent(StyleContent::Normal()) {
   2881  MOZ_COUNT_CTOR(nsStyleContent);
   2882 }
   2883 
   2884 nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
   2885    : mContent(aSource.mContent),
   2886      mCounterIncrement(aSource.mCounterIncrement),
   2887      mCounterReset(aSource.mCounterReset),
   2888      mCounterSet(aSource.mCounterSet) {
   2889  MOZ_COUNT_CTOR(nsStyleContent);
   2890 }
   2891 
   2892 nsChangeHint nsStyleContent::CalcDifference(
   2893    const nsStyleContent& aNewData) const {
   2894  // Unfortunately we need to reframe even if the content lengths are the same;
   2895  // a simple reflow will not pick up different text or different image URLs,
   2896  // since we set all that up in the CSSFrameConstructor
   2897  if (mContent != aNewData.mContent ||
   2898      mCounterIncrement != aNewData.mCounterIncrement ||
   2899      mCounterReset != aNewData.mCounterReset ||
   2900      mCounterSet != aNewData.mCounterSet) {
   2901    return nsChangeHint_ReconstructFrame;
   2902  }
   2903 
   2904  return nsChangeHint(0);
   2905 }
   2906 
   2907 void nsStyleContent::TriggerImageLoads(Document& aDoc,
   2908                                       const nsStyleContent* aOld) {
   2909  if (!mContent.IsItems()) {
   2910    return;
   2911  }
   2912 
   2913  Span<const StyleContentItem> oldItems;
   2914  if (aOld) {
   2915    oldItems = aOld->NonAltContentItems();
   2916  }
   2917 
   2918  auto items = NonAltContentItems();
   2919  for (size_t i = 0; i < items.Length(); ++i) {
   2920    const auto& item = items[i];
   2921    if (!item.IsImage()) {
   2922      continue;
   2923    }
   2924    const auto& image = item.AsImage();
   2925    const auto* oldImage = i < oldItems.Length() && oldItems[i].IsImage()
   2926                               ? &oldItems[i].AsImage()
   2927                               : nullptr;
   2928    const_cast<StyleImage&>(image).ResolveImage(aDoc, oldImage);
   2929  }
   2930 }
   2931 
   2932 // --------------------
   2933 // nsStyleTextReset
   2934 //
   2935 
   2936 nsStyleTextReset::nsStyleTextReset()
   2937    : mTextDecorationLine(StyleTextDecorationLine::NONE),
   2938      mTextDecorationStyle(StyleTextDecorationStyle::Solid),
   2939      mUnicodeBidi(StyleUnicodeBidi::Normal),
   2940      mInitialLetter{0, 0},
   2941      mTextDecorationColor(StyleColor::CurrentColor()),
   2942      mTextDecorationThickness(StyleTextDecorationLength::Auto()),
   2943      mTextDecorationInset(StyleTextDecorationInset::Length(
   2944          StyleLength::Zero(), StyleLength::Zero())) {
   2945  MOZ_COUNT_CTOR(nsStyleTextReset);
   2946 }
   2947 
   2948 nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
   2949    : mTextOverflow(aSource.mTextOverflow),
   2950      mTextDecorationLine(aSource.mTextDecorationLine),
   2951      mTextDecorationStyle(aSource.mTextDecorationStyle),
   2952      mUnicodeBidi(aSource.mUnicodeBidi),
   2953      mInitialLetter(aSource.mInitialLetter),
   2954      mTextDecorationColor(aSource.mTextDecorationColor),
   2955      mTextDecorationThickness(aSource.mTextDecorationThickness),
   2956      mTextDecorationInset(aSource.mTextDecorationInset) {
   2957  MOZ_COUNT_CTOR(nsStyleTextReset);
   2958 }
   2959 
   2960 nsChangeHint nsStyleTextReset::CalcDifference(
   2961    const nsStyleTextReset& aNewData) const {
   2962  if (mUnicodeBidi != aNewData.mUnicodeBidi ||
   2963      mInitialLetter != aNewData.mInitialLetter) {
   2964    return NS_STYLE_HINT_REFLOW;
   2965  }
   2966 
   2967  if (mTextDecorationLine != aNewData.mTextDecorationLine ||
   2968      mTextDecorationStyle != aNewData.mTextDecorationStyle ||
   2969      mTextDecorationThickness != aNewData.mTextDecorationThickness ||
   2970      mTextDecorationInset != aNewData.mTextDecorationInset) {
   2971    // Changes to our text-decoration line can impact our overflow area &
   2972    // also our descendants' overflow areas (particularly for text-frame
   2973    // descendants).  So, we update those areas & trigger a repaint.
   2974    return nsChangeHint_RepaintFrame | nsChangeHint_UpdateSubtreeOverflow |
   2975           nsChangeHint_SchedulePaint;
   2976  }
   2977 
   2978  // Repaint for decoration color changes or text-overflow.
   2979  if (mTextDecorationColor != aNewData.mTextDecorationColor ||
   2980      mTextOverflow != aNewData.mTextOverflow) {
   2981    return nsChangeHint_RepaintFrame;
   2982  }
   2983 
   2984  return nsChangeHint(0);
   2985 }
   2986 
   2987 // --------------------
   2988 // nsStyleText
   2989 //
   2990 
   2991 static StyleAbsoluteColor DefaultColor(const Document& aDocument) {
   2992  return StyleAbsoluteColor::FromColor(
   2993      PreferenceSheet::PrefsFor(aDocument)
   2994          .ColorsFor(aDocument.DefaultColorScheme())
   2995          .mDefault);
   2996 }
   2997 
   2998 nsStyleText::nsStyleText(const Document& aDocument)
   2999    : mColor(DefaultColor(aDocument)),
   3000      mForcedColorAdjust(StyleForcedColorAdjust::Auto),
   3001      mTextTransform(StyleTextTransform::NONE),
   3002      mTextAlign(StyleTextAlign::Start),
   3003      mTextAlignLast(StyleTextAlignLast::Auto),
   3004      mTextJustify(StyleTextJustify::Auto),
   3005      mHyphens(StyleHyphens::Manual),
   3006      mRubyAlign(StyleRubyAlign::SpaceAround),
   3007      mRubyPosition(StyleRubyPosition::AlternateOver),
   3008      mTextSizeAdjust(StyleTextSizeAdjust::Auto),
   3009      mTextCombineUpright(StyleTextCombineUpright::None),
   3010      mMozControlCharacterVisibility(
   3011          StaticPrefs::layout_css_control_characters_visible()
   3012              ? StyleMozControlCharacterVisibility::Visible
   3013              : StyleMozControlCharacterVisibility::Hidden),
   3014      mTextEmphasisPosition(StyleTextEmphasisPosition::AUTO),
   3015      mTextRendering(StyleTextRendering::Auto),
   3016      mTextEmphasisColor(StyleColor::CurrentColor()),
   3017      mWebkitTextFillColor(StyleColor::CurrentColor()),
   3018      mWebkitTextStrokeColor(StyleColor::CurrentColor()),
   3019      mTabSize(StyleNonNegativeLengthOrNumber::Number(8.f)),
   3020      mWordSpacing(LengthPercentage::Zero()),
   3021      mLetterSpacing(LengthPercentage::Zero()),
   3022      mTextUnderlineOffset(LengthPercentageOrAuto::Auto()),
   3023      mTextDecorationSkipInk(StyleTextDecorationSkipInk::Auto),
   3024      mTextUnderlinePosition(StyleTextUnderlinePosition::AUTO),
   3025      mWebkitTextStrokeWidth(0),
   3026      mTextEmphasisStyle(StyleTextEmphasisStyle::None()) {
   3027  MOZ_COUNT_CTOR(nsStyleText);
   3028 }
   3029 
   3030 nsStyleText::nsStyleText(const nsStyleText& aSource)
   3031    : mColor(aSource.mColor),
   3032      mForcedColorAdjust(aSource.mForcedColorAdjust),
   3033      mTextTransform(aSource.mTextTransform),
   3034      mTextAlign(aSource.mTextAlign),
   3035      mTextAlignLast(aSource.mTextAlignLast),
   3036      mTextJustify(aSource.mTextJustify),
   3037      mWhiteSpaceCollapse(aSource.mWhiteSpaceCollapse),
   3038      mTextWrapMode(aSource.mTextWrapMode),
   3039      mLineBreak(aSource.mLineBreak),
   3040      mWordBreak(aSource.mWordBreak),
   3041      mOverflowWrap(aSource.mOverflowWrap),
   3042      mTextAutospace(aSource.mTextAutospace),
   3043      mHyphens(aSource.mHyphens),
   3044      mRubyAlign(aSource.mRubyAlign),
   3045      mRubyPosition(aSource.mRubyPosition),
   3046      mTextSizeAdjust(aSource.mTextSizeAdjust),
   3047      mTextCombineUpright(aSource.mTextCombineUpright),
   3048      mMozControlCharacterVisibility(aSource.mMozControlCharacterVisibility),
   3049      mTextEmphasisPosition(aSource.mTextEmphasisPosition),
   3050      mTextRendering(aSource.mTextRendering),
   3051      mTextEmphasisColor(aSource.mTextEmphasisColor),
   3052      mWebkitTextFillColor(aSource.mWebkitTextFillColor),
   3053      mWebkitTextStrokeColor(aSource.mWebkitTextStrokeColor),
   3054      mTabSize(aSource.mTabSize),
   3055      mWordSpacing(aSource.mWordSpacing),
   3056      mLetterSpacing(aSource.mLetterSpacing),
   3057      mTextIndent(aSource.mTextIndent),
   3058      mTextUnderlineOffset(aSource.mTextUnderlineOffset),
   3059      mTextDecorationSkipInk(aSource.mTextDecorationSkipInk),
   3060      mTextUnderlinePosition(aSource.mTextUnderlinePosition),
   3061      mWebkitTextStrokeWidth(aSource.mWebkitTextStrokeWidth),
   3062      mTextShadow(aSource.mTextShadow),
   3063      mTextEmphasisStyle(aSource.mTextEmphasisStyle),
   3064      mHyphenateCharacter(aSource.mHyphenateCharacter),
   3065      mHyphenateLimitChars(aSource.mHyphenateLimitChars),
   3066      mWebkitTextSecurity(aSource.mWebkitTextSecurity),
   3067      mTextWrapStyle(aSource.mTextWrapStyle) {
   3068  MOZ_COUNT_CTOR(nsStyleText);
   3069 }
   3070 
   3071 nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aNewData) const {
   3072  if (WhiteSpaceOrNewlineIsSignificant() !=
   3073      aNewData.WhiteSpaceOrNewlineIsSignificant()) {
   3074    // This may require construction of suppressed text frames
   3075    return nsChangeHint_ReconstructFrame;
   3076  }
   3077 
   3078  if (mTextCombineUpright != aNewData.mTextCombineUpright ||
   3079      mMozControlCharacterVisibility !=
   3080          aNewData.mMozControlCharacterVisibility) {
   3081    return nsChangeHint_ReconstructFrame;
   3082  }
   3083 
   3084  if ((mTextAlign != aNewData.mTextAlign) ||
   3085      (mTextAlignLast != aNewData.mTextAlignLast) ||
   3086      (mTextTransform != aNewData.mTextTransform) ||
   3087      (mWhiteSpaceCollapse != aNewData.mWhiteSpaceCollapse) ||
   3088      (mTextWrapMode != aNewData.mTextWrapMode) ||
   3089      (mLineBreak != aNewData.mLineBreak) ||
   3090      (mWordBreak != aNewData.mWordBreak) ||
   3091      (mOverflowWrap != aNewData.mOverflowWrap) ||
   3092      (mHyphens != aNewData.mHyphens) || (mRubyAlign != aNewData.mRubyAlign) ||
   3093      (mRubyPosition != aNewData.mRubyPosition) ||
   3094      (mTextSizeAdjust != aNewData.mTextSizeAdjust) ||
   3095      (mLetterSpacing != aNewData.mLetterSpacing) ||
   3096      (mTextIndent != aNewData.mTextIndent) ||
   3097      (mTextJustify != aNewData.mTextJustify) ||
   3098      (mWordSpacing != aNewData.mWordSpacing) ||
   3099      (mTabSize != aNewData.mTabSize) ||
   3100      (mHyphenateCharacter != aNewData.mHyphenateCharacter) ||
   3101      (mHyphenateLimitChars != aNewData.mHyphenateLimitChars) ||
   3102      (mWebkitTextSecurity != aNewData.mWebkitTextSecurity) ||
   3103      (mTextWrapStyle != aNewData.mTextWrapStyle) ||
   3104      (mTextAutospace != aNewData.mTextAutospace)) {
   3105    return NS_STYLE_HINT_REFLOW;
   3106  }
   3107 
   3108  if (HasEffectiveTextEmphasis() != aNewData.HasEffectiveTextEmphasis() ||
   3109      (HasEffectiveTextEmphasis() &&
   3110       mTextEmphasisPosition != aNewData.mTextEmphasisPosition)) {
   3111    // Text emphasis position change could affect line height calculation.
   3112    return nsChangeHint_AllReflowHints | nsChangeHint_RepaintFrame;
   3113  }
   3114 
   3115  nsChangeHint hint = nsChangeHint(0);
   3116 
   3117  // text-rendering changes require a reflow since they change SVG
   3118  // frames' rects.
   3119  if (mTextRendering != aNewData.mTextRendering) {
   3120    hint |= nsChangeHint_NeedReflow | nsChangeHint_RepaintFrame;
   3121  }
   3122 
   3123  if (mTextShadow != aNewData.mTextShadow ||
   3124      mTextEmphasisStyle != aNewData.mTextEmphasisStyle ||
   3125      mWebkitTextStrokeWidth != aNewData.mWebkitTextStrokeWidth ||
   3126      mTextUnderlineOffset != aNewData.mTextUnderlineOffset ||
   3127      mTextDecorationSkipInk != aNewData.mTextDecorationSkipInk ||
   3128      mTextUnderlinePosition != aNewData.mTextUnderlinePosition) {
   3129    hint |= nsChangeHint_UpdateSubtreeOverflow | nsChangeHint_SchedulePaint |
   3130            nsChangeHint_RepaintFrame;
   3131 
   3132    // We don't add any other hints below.
   3133    return hint;
   3134  }
   3135 
   3136  if (mColor != aNewData.mColor) {
   3137    hint |= nsChangeHint_RepaintFrame;
   3138  }
   3139 
   3140  if (mTextEmphasisColor != aNewData.mTextEmphasisColor ||
   3141      mWebkitTextFillColor != aNewData.mWebkitTextFillColor ||
   3142      mWebkitTextStrokeColor != aNewData.mWebkitTextStrokeColor) {
   3143    hint |= nsChangeHint_SchedulePaint | nsChangeHint_RepaintFrame;
   3144  }
   3145 
   3146  if (hint) {
   3147    return hint;
   3148  }
   3149 
   3150  if (mTextEmphasisPosition != aNewData.mTextEmphasisPosition ||
   3151      mForcedColorAdjust != aNewData.mForcedColorAdjust) {
   3152    return nsChangeHint_NeutralChange;
   3153  }
   3154 
   3155  return nsChangeHint(0);
   3156 }
   3157 
   3158 LogicalSide nsStyleText::TextEmphasisSide(WritingMode aWM,
   3159                                          const nsAtom* aLanguage) const {
   3160  mozilla::Side side;
   3161  if (mTextEmphasisPosition & StyleTextEmphasisPosition::AUTO) {
   3162    // 'auto' resolves to 'under right' for Chinese, 'over right' otherwise.
   3163    if (aWM.IsVertical()) {
   3164      side = eSideRight;
   3165    } else {
   3166      if (nsStyleUtil::MatchesLanguagePrefix(aLanguage, u"zh")) {
   3167        side = eSideBottom;
   3168      } else {
   3169        side = eSideTop;
   3170      }
   3171    }
   3172  } else {
   3173    if (aWM.IsVertical()) {
   3174      side = mTextEmphasisPosition & StyleTextEmphasisPosition::LEFT
   3175                 ? eSideLeft
   3176                 : eSideRight;
   3177    } else {
   3178      side = mTextEmphasisPosition & StyleTextEmphasisPosition::OVER
   3179                 ? eSideTop
   3180                 : eSideBottom;
   3181    }
   3182  }
   3183 
   3184  LogicalSide result = aWM.LogicalSideForPhysicalSide(side);
   3185  MOZ_ASSERT(IsBlock(result));
   3186  return result;
   3187 }
   3188 
   3189 //-----------------------
   3190 // nsStyleUI
   3191 //
   3192 
   3193 nsStyleUI::nsStyleUI()
   3194    : mInert(StyleInert::None),
   3195      mMozTheme(StyleMozTheme::Auto),
   3196      mUserFocus(StyleUserFocus::Normal),
   3197      mPointerEvents(StylePointerEvents::Auto),
   3198      mCursor{{}, StyleCursorKind::Auto},
   3199      mAccentColor(StyleColorOrAuto::Auto()),
   3200      mCaretColor(StyleColorOrAuto::Auto()),
   3201      mScrollbarColor(StyleScrollbarColor::Auto()),
   3202      mColorScheme(StyleColorScheme{{}, {}}) {
   3203  MOZ_COUNT_CTOR(nsStyleUI);
   3204 }
   3205 
   3206 nsStyleUI::nsStyleUI(const nsStyleUI& aSource)
   3207    : mInert(aSource.mInert),
   3208      mMozTheme(aSource.mMozTheme),
   3209      mUserFocus(aSource.mUserFocus),
   3210      mPointerEvents(aSource.mPointerEvents),
   3211      mCursor(aSource.mCursor),
   3212      mAccentColor(aSource.mAccentColor),
   3213      mCaretColor(aSource.mCaretColor),
   3214      mScrollbarColor(aSource.mScrollbarColor),
   3215      mColorScheme(aSource.mColorScheme) {
   3216  MOZ_COUNT_CTOR(nsStyleUI);
   3217 }
   3218 
   3219 void nsStyleUI::TriggerImageLoads(Document& aDocument,
   3220                                  const nsStyleUI* aOldStyle) {
   3221  MOZ_ASSERT(NS_IsMainThread());
   3222 
   3223  auto cursorImages = mCursor.images.AsSpan();
   3224  auto oldCursorImages = aOldStyle ? aOldStyle->mCursor.images.AsSpan()
   3225                                   : Span<const StyleCursorImage>();
   3226  for (size_t i = 0; i < cursorImages.Length(); ++i) {
   3227    const auto& cursor = cursorImages[i];
   3228    const auto* oldCursorImage =
   3229        oldCursorImages.Length() > i ? &oldCursorImages[i].image : nullptr;
   3230    const_cast<StyleCursorImage&>(cursor).image.ResolveImage(aDocument,
   3231                                                             oldCursorImage);
   3232  }
   3233 }
   3234 
   3235 nsChangeHint nsStyleUI::CalcDifference(const nsStyleUI& aNewData) const {
   3236  // SVGGeometryFrame's mRect depends on stroke _and_ on the value of
   3237  // pointer-events. See SVGGeometryFrame::ReflowSVG's use of GetHitTestFlags.
   3238  // (Only a reflow, no visual change.)
   3239  //
   3240  // pointer-events changes can change event regions overrides on layers and
   3241  // so needs a repaint.
   3242  const auto kPointerEventsHint =
   3243      nsChangeHint_NeedReflow | nsChangeHint_SchedulePaint;
   3244 
   3245  nsChangeHint hint = nsChangeHint(0);
   3246  if (mCursor != aNewData.mCursor) {
   3247    hint |= nsChangeHint_UpdateCursor;
   3248  }
   3249 
   3250  if (mPointerEvents != aNewData.mPointerEvents) {
   3251    hint |= kPointerEventsHint;
   3252  }
   3253 
   3254  if (mInert != aNewData.mInert) {
   3255    // inert affects pointer-events, user-select, user-focus.
   3256    // Do the union of all them (minus
   3257    // nsChangeHint_NeutralChange which isn't needed if there's any other hint).
   3258    hint |= NS_STYLE_HINT_VISUAL | kPointerEventsHint;
   3259  }
   3260 
   3261  if (mUserFocus != aNewData.mUserFocus) {
   3262    hint |= nsChangeHint_NeutralChange;
   3263  }
   3264 
   3265  if (mCaretColor != aNewData.mCaretColor ||
   3266      mAccentColor != aNewData.mAccentColor ||
   3267      mScrollbarColor != aNewData.mScrollbarColor ||
   3268      mMozTheme != aNewData.mMozTheme ||
   3269      mColorScheme != aNewData.mColorScheme) {
   3270    hint |= nsChangeHint_RepaintFrame;
   3271  }
   3272 
   3273  return hint;
   3274 }
   3275 
   3276 //-----------------------
   3277 // nsStyleUIReset
   3278 //
   3279 
   3280 nsStyleUIReset::nsStyleUIReset()
   3281    : mUserSelect(StyleUserSelect::Auto),
   3282      mScrollbarWidth(StyleScrollbarWidth::Auto),
   3283      mMozForceBrokenImageIcon(false),
   3284      mMozSubtreeHiddenOnlyVisually(false),
   3285      mIMEMode(StyleImeMode::Auto),
   3286      mWindowDragging(StyleWindowDragging::Default),
   3287      mWindowShadow(StyleWindowShadow::Auto),
   3288      mWindowOpacity(1.0),
   3289      mMozWindowInputRegionMargin(StyleLength::Zero()),
   3290      mTransitions(
   3291          nsStyleAutoArray<StyleTransition>::WITH_SINGLE_INITIAL_ELEMENT),
   3292      mTransitionTimingFunctionCount(1),
   3293      mTransitionDurationCount(1),
   3294      mTransitionDelayCount(1),
   3295      mTransitionPropertyCount(1),
   3296      mTransitionBehaviorCount(1),
   3297      mAnimations(
   3298          nsStyleAutoArray<StyleAnimation>::WITH_SINGLE_INITIAL_ELEMENT),
   3299      mAnimationTimingFunctionCount(1),
   3300      mAnimationDurationCount(1),
   3301      mAnimationDelayCount(1),
   3302      mAnimationNameCount(1),
   3303      mAnimationDirectionCount(1),
   3304      mAnimationFillModeCount(1),
   3305      mAnimationPlayStateCount(1),
   3306      mAnimationIterationCountCount(1),
   3307      mAnimationCompositionCount(1),
   3308      mAnimationTimelineCount(1),
   3309      mScrollTimelines(
   3310          nsStyleAutoArray<StyleScrollTimeline>::WITH_SINGLE_INITIAL_ELEMENT),
   3311      mScrollTimelineNameCount(1),
   3312      mScrollTimelineAxisCount(1),
   3313      mViewTimelines(
   3314          nsStyleAutoArray<StyleViewTimeline>::WITH_SINGLE_INITIAL_ELEMENT),
   3315      mViewTimelineNameCount(1),
   3316      mViewTimelineAxisCount(1),
   3317      mViewTimelineInsetCount(1),
   3318      mFieldSizing(StyleFieldSizing::Fixed),
   3319      mViewTransitionName(StyleViewTransitionName::None()) {
   3320  MOZ_COUNT_CTOR(nsStyleUIReset);
   3321 }
   3322 
   3323 nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource)
   3324    : mUserSelect(aSource.mUserSelect),
   3325      mScrollbarWidth(aSource.mScrollbarWidth),
   3326      mMozForceBrokenImageIcon(aSource.mMozForceBrokenImageIcon),
   3327      mMozSubtreeHiddenOnlyVisually(aSource.mMozSubtreeHiddenOnlyVisually),
   3328      mIMEMode(aSource.mIMEMode),
   3329      mWindowDragging(aSource.mWindowDragging),
   3330      mWindowShadow(aSource.mWindowShadow),
   3331      mWindowOpacity(aSource.mWindowOpacity),
   3332      mMozWindowInputRegionMargin(aSource.mMozWindowInputRegionMargin),
   3333      mMozWindowTransform(aSource.mMozWindowTransform),
   3334      mTransitions(aSource.mTransitions.Clone()),
   3335      mTransitionTimingFunctionCount(aSource.mTransitionTimingFunctionCount),
   3336      mTransitionDurationCount(aSource.mTransitionDurationCount),
   3337      mTransitionDelayCount(aSource.mTransitionDelayCount),
   3338      mTransitionPropertyCount(aSource.mTransitionPropertyCount),
   3339      mTransitionBehaviorCount(aSource.mTransitionBehaviorCount),
   3340      mAnimations(aSource.mAnimations.Clone()),
   3341      mAnimationTimingFunctionCount(aSource.mAnimationTimingFunctionCount),
   3342      mAnimationDurationCount(aSource.mAnimationDurationCount),
   3343      mAnimationDelayCount(aSource.mAnimationDelayCount),
   3344      mAnimationNameCount(aSource.mAnimationNameCount),
   3345      mAnimationDirectionCount(aSource.mAnimationDirectionCount),
   3346      mAnimationFillModeCount(aSource.mAnimationFillModeCount),
   3347      mAnimationPlayStateCount(aSource.mAnimationPlayStateCount),
   3348      mAnimationIterationCountCount(aSource.mAnimationIterationCountCount),
   3349      mAnimationCompositionCount(aSource.mAnimationCompositionCount),
   3350      mAnimationTimelineCount(aSource.mAnimationTimelineCount),
   3351      mScrollTimelines(aSource.mScrollTimelines.Clone()),
   3352      mScrollTimelineNameCount(aSource.mScrollTimelineNameCount),
   3353      mScrollTimelineAxisCount(aSource.mScrollTimelineAxisCount),
   3354      mViewTimelines(aSource.mViewTimelines.Clone()),
   3355      mViewTimelineNameCount(aSource.mViewTimelineNameCount),
   3356      mViewTimelineAxisCount(aSource.mViewTimelineAxisCount),
   3357      mViewTimelineInsetCount(aSource.mViewTimelineInsetCount),
   3358      mFieldSizing(aSource.mFieldSizing),
   3359      mViewTransitionName(aSource.mViewTransitionName),
   3360      mViewTransitionClass(aSource.mViewTransitionClass) {
   3361  MOZ_COUNT_CTOR(nsStyleUIReset);
   3362 }
   3363 
   3364 nsChangeHint nsStyleUIReset::CalcDifference(
   3365    const nsStyleUIReset& aNewData) const {
   3366  nsChangeHint hint = nsChangeHint(0);
   3367 
   3368  if (mMozForceBrokenImageIcon != aNewData.mMozForceBrokenImageIcon) {
   3369    hint |= nsChangeHint_ReconstructFrame;
   3370  }
   3371  if (mMozSubtreeHiddenOnlyVisually != aNewData.mMozSubtreeHiddenOnlyVisually) {
   3372    hint |= nsChangeHint_RepaintFrame;
   3373  }
   3374  if (mFieldSizing != aNewData.mFieldSizing) {
   3375    hint |= nsChangeHint_NeutralChange;
   3376  }
   3377  if (mScrollbarWidth != aNewData.mScrollbarWidth) {
   3378    // For scrollbar-width change, we need some special handling similar
   3379    // to overflow properties. Specifically, we may need to reconstruct
   3380    // the scrollbar or force reflow of the viewport scrollbar.
   3381    hint |= nsChangeHint_ScrollbarChange;
   3382  }
   3383  if (mWindowShadow != aNewData.mWindowShadow) {
   3384    // We really need just an nsChangeHint_SyncFrameView, except
   3385    // on an ancestor of the frame, so we get that by doing a
   3386    // reflow.
   3387    hint |= NS_STYLE_HINT_REFLOW;
   3388  }
   3389  if (mUserSelect != aNewData.mUserSelect) {
   3390    hint |= NS_STYLE_HINT_VISUAL;
   3391  }
   3392 
   3393  if (mWindowDragging != aNewData.mWindowDragging) {
   3394    hint |= nsChangeHint_SchedulePaint;
   3395  }
   3396 
   3397  if (mViewTransitionName != aNewData.mViewTransitionName) {
   3398    if (HasViewTransitionName() != aNewData.HasViewTransitionName()) {
   3399      hint |= nsChangeHint_RepaintFrame;
   3400    } else {
   3401      hint |= nsChangeHint_NeutralChange;
   3402    }
   3403  }
   3404 
   3405  if (mViewTransitionClass != aNewData.mViewTransitionClass) {
   3406    hint |= nsChangeHint_NeutralChange;
   3407  }
   3408 
   3409  if (!hint &&
   3410      (mTransitions != aNewData.mTransitions ||
   3411       mTransitionTimingFunctionCount !=
   3412           aNewData.mTransitionTimingFunctionCount ||
   3413       mTransitionDurationCount != aNewData.mTransitionDurationCount ||
   3414       mTransitionDelayCount != aNewData.mTransitionDelayCount ||
   3415       mTransitionPropertyCount != aNewData.mTransitionPropertyCount ||
   3416       mTransitionBehaviorCount != aNewData.mTransitionBehaviorCount ||
   3417       mAnimations != aNewData.mAnimations ||
   3418       mAnimationTimingFunctionCount !=
   3419           aNewData.mAnimationTimingFunctionCount ||
   3420       mAnimationDurationCount != aNewData.mAnimationDurationCount ||
   3421       mAnimationDelayCount != aNewData.mAnimationDelayCount ||
   3422       mAnimationNameCount != aNewData.mAnimationNameCount ||
   3423       mAnimationDirectionCount != aNewData.mAnimationDirectionCount ||
   3424       mAnimationFillModeCount != aNewData.mAnimationFillModeCount ||
   3425       mAnimationPlayStateCount != aNewData.mAnimationPlayStateCount ||
   3426       mAnimationIterationCountCount !=
   3427           aNewData.mAnimationIterationCountCount ||
   3428       mAnimationCompositionCount != aNewData.mAnimationCompositionCount ||
   3429       mAnimationTimelineCount != aNewData.mAnimationTimelineCount ||
   3430       mIMEMode != aNewData.mIMEMode ||
   3431       mWindowOpacity != aNewData.mWindowOpacity ||
   3432       mMozWindowInputRegionMargin != aNewData.mMozWindowInputRegionMargin ||
   3433       mMozWindowTransform != aNewData.mMozWindowTransform ||
   3434       mScrollTimelines != aNewData.mScrollTimelines ||
   3435       mScrollTimelineNameCount != aNewData.mScrollTimelineNameCount ||
   3436       mScrollTimelineAxisCount != aNewData.mScrollTimelineAxisCount ||
   3437       mViewTimelines != aNewData.mViewTimelines ||
   3438       mViewTimelineNameCount != aNewData.mViewTimelineNameCount ||
   3439       mViewTimelineAxisCount != aNewData.mViewTimelineAxisCount ||
   3440       mViewTimelineInsetCount != aNewData.mViewTimelineInsetCount)) {
   3441    hint |= nsChangeHint_NeutralChange;
   3442  }
   3443 
   3444  return hint;
   3445 }
   3446 
   3447 StyleScrollbarWidth nsStyleUIReset::ScrollbarWidth() const {
   3448  if (MOZ_UNLIKELY(StaticPrefs::layout_css_scrollbar_width_thin_disabled())) {
   3449    if (mScrollbarWidth == StyleScrollbarWidth::Thin) {
   3450      return StyleScrollbarWidth::Auto;
   3451    }
   3452  }
   3453  return mScrollbarWidth;
   3454 }
   3455 
   3456 //-----------------------
   3457 // nsStyleEffects
   3458 //
   3459 
   3460 nsStyleEffects::nsStyleEffects()
   3461    : mClip(StyleClipRectOrAuto::Auto()),
   3462      mOpacity(1.0f),
   3463      mMixBlendMode(StyleBlend::Normal) {
   3464  MOZ_COUNT_CTOR(nsStyleEffects);
   3465 }
   3466 
   3467 nsStyleEffects::nsStyleEffects(const nsStyleEffects& aSource)
   3468    : mFilters(aSource.mFilters),
   3469      mBoxShadow(aSource.mBoxShadow),
   3470      mBackdropFilters(aSource.mBackdropFilters),
   3471      mClip(aSource.mClip),
   3472      mOpacity(aSource.mOpacity),
   3473      mMixBlendMode(aSource.mMixBlendMode) {
   3474  MOZ_COUNT_CTOR(nsStyleEffects);
   3475 }
   3476 
   3477 static bool AnyAutonessChanged(const StyleClipRectOrAuto& aOld,
   3478                               const StyleClipRectOrAuto& aNew) {
   3479  if (aOld.IsAuto() != aNew.IsAuto()) {
   3480    return true;
   3481  }
   3482  if (aOld.IsAuto()) {
   3483    return false;
   3484  }
   3485  const auto& oldRect = aOld.AsRect();
   3486  const auto& newRect = aNew.AsRect();
   3487  return oldRect.top.IsAuto() != newRect.top.IsAuto() ||
   3488         oldRect.right.IsAuto() != newRect.right.IsAuto() ||
   3489         oldRect.bottom.IsAuto() != newRect.bottom.IsAuto() ||
   3490         oldRect.left.IsAuto() != newRect.left.IsAuto();
   3491 }
   3492 
   3493 nsChangeHint nsStyleEffects::CalcDifference(
   3494    const nsStyleEffects& aNewData) const {
   3495  nsChangeHint hint = nsChangeHint(0);
   3496 
   3497  if (mBoxShadow != aNewData.mBoxShadow) {
   3498    // Update overflow regions & trigger DLBI to be sure it's noticed.
   3499    // Also request a repaint, since it's possible that only the color
   3500    // of the shadow is changing (and UpdateOverflow/SchedulePaint won't
   3501    // repaint for that, since they won't know what needs invalidating.)
   3502    hint |= nsChangeHint_UpdateOverflow | nsChangeHint_SchedulePaint |
   3503            nsChangeHint_RepaintFrame;
   3504  }
   3505 
   3506  if (AnyAutonessChanged(mClip, aNewData.mClip)) {
   3507    hint |= nsChangeHint_AllReflowHints | nsChangeHint_RepaintFrame;
   3508  } else if (mClip != aNewData.mClip) {
   3509    // If the clip has changed, we just need to update overflow areas. DLBI
   3510    // will handle the invalidation.
   3511    hint |= nsChangeHint_UpdateOverflow | nsChangeHint_SchedulePaint;
   3512  }
   3513 
   3514  if (mOpacity != aNewData.mOpacity) {
   3515    hint |= nsChangeHint_UpdateOpacityLayer;
   3516 
   3517    // If we're going from the optimized >=0.99 opacity value to 1.0 or back,
   3518    // then repaint the frame because DLBI will not catch the invalidation.
   3519    // Otherwise, just update the opacity layer.
   3520    if ((mOpacity >= 0.99f && mOpacity < 1.0f && aNewData.mOpacity == 1.0f) ||
   3521        (aNewData.mOpacity >= 0.99f && aNewData.mOpacity < 1.0f &&
   3522         mOpacity == 1.0f)) {
   3523      hint |= nsChangeHint_RepaintFrame;
   3524    } else {
   3525      if ((mOpacity == 1.0f) != (aNewData.mOpacity == 1.0f)) {
   3526        hint |= nsChangeHint_UpdateUsesOpacity;
   3527      }
   3528    }
   3529  }
   3530 
   3531  if (HasFilters() != aNewData.HasFilters()) {
   3532    // A change from/to being a containing block for position:fixed.
   3533    hint |= nsChangeHint_UpdateContainingBlock;
   3534  }
   3535 
   3536  if (mFilters != aNewData.mFilters) {
   3537    hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame |
   3538            nsChangeHint_UpdateOverflow;
   3539  }
   3540 
   3541  if (mMixBlendMode != aNewData.mMixBlendMode) {
   3542    hint |= nsChangeHint_RepaintFrame;
   3543  }
   3544 
   3545  if (HasBackdropFilters() != aNewData.HasBackdropFilters()) {
   3546    // A change from/to being a containing block for position:fixed.
   3547    hint |= nsChangeHint_UpdateContainingBlock;
   3548  }
   3549 
   3550  if (mBackdropFilters != aNewData.mBackdropFilters) {
   3551    hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
   3552  }
   3553 
   3554  return hint;
   3555 }
   3556 
   3557 static bool TransformOperationHasPercent(const StyleTransformOperation& aOp) {
   3558  switch (aOp.tag) {
   3559    case StyleTransformOperation::Tag::TranslateX:
   3560      return aOp.AsTranslateX().HasPercent();
   3561    case StyleTransformOperation::Tag::TranslateY:
   3562      return aOp.AsTranslateY().HasPercent();
   3563    case StyleTransformOperation::Tag::TranslateZ:
   3564      return false;
   3565    case StyleTransformOperation::Tag::Translate3D: {
   3566      const auto& translate = aOp.AsTranslate3D();
   3567      // NOTE(emilio): z translation is a `<length>`, so can't have percentages.
   3568      return translate._0.HasPercent() || translate._1.HasPercent();
   3569    }
   3570    case StyleTransformOperation::Tag::Translate: {
   3571      const auto& translate = aOp.AsTranslate();
   3572      return translate._0.HasPercent() || translate._1.HasPercent();
   3573    }
   3574    case StyleTransformOperation::Tag::AccumulateMatrix: {
   3575      const auto& accum = aOp.AsAccumulateMatrix();
   3576      return accum.from_list.HasPercent() || accum.to_list.HasPercent();
   3577    }
   3578    case StyleTransformOperation::Tag::InterpolateMatrix: {
   3579      const auto& interpolate = aOp.AsInterpolateMatrix();
   3580      return interpolate.from_list.HasPercent() ||
   3581             interpolate.to_list.HasPercent();
   3582    }
   3583    case StyleTransformOperation::Tag::Perspective:
   3584    case StyleTransformOperation::Tag::RotateX:
   3585    case StyleTransformOperation::Tag::RotateY:
   3586    case StyleTransformOperation::Tag::RotateZ:
   3587    case StyleTransformOperation::Tag::Rotate:
   3588    case StyleTransformOperation::Tag::Rotate3D:
   3589    case StyleTransformOperation::Tag::SkewX:
   3590    case StyleTransformOperation::Tag::SkewY:
   3591    case StyleTransformOperation::Tag::Skew:
   3592    case StyleTransformOperation::Tag::ScaleX:
   3593    case StyleTransformOperation::Tag::ScaleY:
   3594    case StyleTransformOperation::Tag::ScaleZ:
   3595    case StyleTransformOperation::Tag::Scale:
   3596    case StyleTransformOperation::Tag::Scale3D:
   3597    case StyleTransformOperation::Tag::Matrix:
   3598    case StyleTransformOperation::Tag::Matrix3D:
   3599      return false;
   3600    default:
   3601      MOZ_ASSERT_UNREACHABLE("Unknown transform operation");
   3602      return false;
   3603  }
   3604 }
   3605 
   3606 template <>
   3607 bool StyleTransform::HasPercent() const {
   3608  for (const auto& op : Operations()) {
   3609    if (TransformOperationHasPercent(op)) {
   3610      return true;
   3611    }
   3612  }
   3613  return false;
   3614 }
   3615 
   3616 template <>
   3617 void StyleCalcNode::ScaleLengthsBy(float aScale) {
   3618  auto ScaleNode = [aScale](const StyleCalcNode& aNode) {
   3619    // This const_cast could be removed by generating more mut-casts, if
   3620    // needed.
   3621    const_cast<StyleCalcNode&>(aNode).ScaleLengthsBy(aScale);
   3622  };
   3623 
   3624  switch (tag) {
   3625    case Tag::Leaf: {
   3626      const auto& leaf = AsLeaf();
   3627      if (leaf.IsLength()) {
   3628        // This const_cast could be removed by generating more mut-casts, if
   3629        // needed.
   3630        const_cast<Length&>(leaf.AsLength()).ScaleBy(aScale);
   3631      }
   3632      break;
   3633    }
   3634    case Tag::Clamp: {
   3635      const auto& clamp = AsClamp();
   3636      ScaleNode(*clamp.min);
   3637      ScaleNode(*clamp.center);
   3638      ScaleNode(*clamp.max);
   3639      break;
   3640    }
   3641    case Tag::Round: {
   3642      const auto& round = AsRound();
   3643      ScaleNode(*round.value);
   3644      ScaleNode(*round.step);
   3645      break;
   3646    }
   3647    case Tag::ModRem: {
   3648      const auto& modRem = AsModRem();
   3649      ScaleNode(*modRem.dividend);
   3650      ScaleNode(*modRem.divisor);
   3651      break;
   3652    }
   3653    case Tag::MinMax: {
   3654      for (const auto& child : AsMinMax()._0.AsSpan()) {
   3655        ScaleNode(child);
   3656      }
   3657      break;
   3658    }
   3659    case Tag::Sum: {
   3660      for (const auto& child : AsSum().AsSpan()) {
   3661        ScaleNode(child);
   3662      }
   3663      break;
   3664    }
   3665    case Tag::Product: {
   3666      for (const auto& child : AsProduct().AsSpan()) {
   3667        ScaleNode(child);
   3668      }
   3669      break;
   3670    }
   3671    case Tag::Negate: {
   3672      const auto& negate = AsNegate();
   3673      ScaleNode(*negate);
   3674      break;
   3675    }
   3676    case Tag::Invert: {
   3677      const auto& invert = AsInvert();
   3678      ScaleNode(*invert);
   3679      break;
   3680    }
   3681    case Tag::Hypot: {
   3682      for (const auto& child : AsHypot().AsSpan()) {
   3683        ScaleNode(child);
   3684      }
   3685      break;
   3686    }
   3687    case Tag::Abs: {
   3688      const auto& abs = AsAbs();
   3689      ScaleNode(*abs);
   3690      break;
   3691    }
   3692    case Tag::Sign: {
   3693      const auto& sign = AsSign();
   3694      ScaleNode(*sign);
   3695      break;
   3696    }
   3697    case Tag::Anchor: {
   3698      MOZ_ASSERT_UNREACHABLE("Unresolved anchor() function");
   3699      break;
   3700    }
   3701    case Tag::AnchorSize: {
   3702      MOZ_ASSERT_UNREACHABLE("Unresolved anchor-size() function");
   3703      break;
   3704    }
   3705  }
   3706 }
   3707 
   3708 bool nsStyleDisplay::PrecludesSizeContainmentOrContentVisibilityWithFrame(
   3709    const nsIFrame& aFrame) const {
   3710  // The spec says that in the case of SVG, the contain property only applies
   3711  // to <svg> elements that have an associated CSS layout box.
   3712  // https://drafts.csswg.org/css-contain/#contain-property
   3713  // Internal SVG elements do not use the standard CSS box model, and wouldn't
   3714  // be affected by size containment. By disabling it we prevent them from
   3715  // becoming query containers for size features.
   3716  if (aFrame.HasAnyStateBits(NS_FRAME_SVG_LAYOUT)) {
   3717    return true;
   3718  }
   3719 
   3720  // Note: The spec for size containment says it should have no effect
   3721  // - on non-atomic, inline-level boxes.
   3722  // - on internal ruby boxes.
   3723  // - if inner display type is table.
   3724  // - on internal table boxes.
   3725  // https://drafts.csswg.org/css-contain/#containment-size
   3726  bool isNonReplacedInline = aFrame.IsLineParticipant() && !aFrame.IsReplaced();
   3727  return isNonReplacedInline || IsInternalRubyDisplayType() ||
   3728         DisplayInside() == mozilla::StyleDisplayInside::Table ||
   3729         IsInnerTableStyle();
   3730 }
   3731 
   3732 ContainSizeAxes nsStyleDisplay::GetContainSizeAxes(
   3733    const nsIFrame& aFrame) const {
   3734  // Short circuit for no containment whatsoever
   3735  if (MOZ_LIKELY(!mEffectiveContainment)) {
   3736    return ContainSizeAxes(false, false);
   3737  }
   3738 
   3739  if (PrecludesSizeContainmentOrContentVisibilityWithFrame(aFrame)) {
   3740    return ContainSizeAxes(false, false);
   3741  }
   3742 
   3743  // https://drafts.csswg.org/css-contain-2/#content-visibility
   3744  // If this content skips its content via content-visibility, it always has
   3745  // size containment.
   3746  if (MOZ_LIKELY(!(mEffectiveContainment & StyleContain::SIZE)) &&
   3747      MOZ_UNLIKELY(aFrame.HidesContent())) {
   3748    return ContainSizeAxes(true, true);
   3749  }
   3750 
   3751  return ContainSizeAxes(
   3752      static_cast<bool>(mEffectiveContainment & StyleContain::INLINE_SIZE),
   3753      static_cast<bool>(mEffectiveContainment & StyleContain::BLOCK_SIZE));
   3754 }
   3755 
   3756 StyleContentVisibility nsStyleDisplay::ContentVisibility(
   3757    const nsIFrame& aFrame) const {
   3758  if (MOZ_LIKELY(mContentVisibility == StyleContentVisibility::Visible)) {
   3759    return StyleContentVisibility::Visible;
   3760  }
   3761  // content-visibility applies to elements for which size containment applies.
   3762  // https://drafts.csswg.org/css-contain/#content-visibility
   3763  if (PrecludesSizeContainmentOrContentVisibilityWithFrame(aFrame)) {
   3764    return StyleContentVisibility::Visible;
   3765  }
   3766  // If we're in print/print-preview, or being used as an image, we should
   3767  // always treat `auto` as `visible`.
   3768  if (mContentVisibility == StyleContentVisibility::Auto &&
   3769      (aFrame.PresContext()->IsPrintingOrPrintPreview() ||
   3770       aFrame.PresContext()->Document()->IsBeingUsedAsImage())) {
   3771    return StyleContentVisibility::Visible;
   3772  }
   3773  return mContentVisibility;
   3774 }
   3775 
   3776 static nscoord Resolve(const StyleContainIntrinsicSize& aSize,
   3777                       nscoord aNoneValue, const nsIFrame& aFrame,
   3778                       LogicalAxis aAxis) {
   3779  if (aSize.IsNone()) {
   3780    return aNoneValue;
   3781  }
   3782  if (aSize.IsLength()) {
   3783    return aSize.AsLength().ToAppUnits();
   3784  }
   3785  MOZ_ASSERT(aSize.HasAuto());
   3786  if (const auto* element = Element::FromNodeOrNull(aFrame.GetContent())) {
   3787    Maybe<float> lastSize = aAxis == LogicalAxis::Block
   3788                                ? element->GetLastRememberedBSize()
   3789                                : element->GetLastRememberedISize();
   3790    if (lastSize && aFrame.HidesContent()) {
   3791      return CSSPixel::ToAppUnits(*lastSize);
   3792    }
   3793  }
   3794  if (aSize.IsAutoNone()) {
   3795    return aNoneValue;
   3796  }
   3797  return aSize.AsAutoLength().ToAppUnits();
   3798 }
   3799 
   3800 Maybe<nscoord> ContainSizeAxes::ContainIntrinsicBSize(
   3801    const nsIFrame& aFrame, nscoord aNoneValue) const {
   3802  if (!mBContained) {
   3803    return Nothing();
   3804  }
   3805  const StyleContainIntrinsicSize& bSize =
   3806      aFrame.StylePosition()->ContainIntrinsicBSize(aFrame.GetWritingMode());
   3807  return Some(Resolve(bSize, aNoneValue, aFrame, LogicalAxis::Block));
   3808 }
   3809 
   3810 Maybe<nscoord> ContainSizeAxes::ContainIntrinsicISize(
   3811    const nsIFrame& aFrame, nscoord aNoneValue) const {
   3812  if (!mIContained) {
   3813    return Nothing();
   3814  }
   3815  const StyleContainIntrinsicSize& iSize =
   3816      aFrame.StylePosition()->ContainIntrinsicISize(aFrame.GetWritingMode());
   3817  return Some(Resolve(iSize, aNoneValue, aFrame, LogicalAxis::Inline));
   3818 }
   3819 
   3820 nsSize ContainSizeAxes::ContainSize(const nsSize& aUncontainedSize,
   3821                                    const nsIFrame& aFrame) const {
   3822  if (!IsAny()) {
   3823    return aUncontainedSize;
   3824  }
   3825  if (aFrame.GetWritingMode().IsVertical()) {
   3826    return nsSize(
   3827        ContainIntrinsicBSize(aFrame).valueOr(aUncontainedSize.Width()),
   3828        ContainIntrinsicISize(aFrame).valueOr(aUncontainedSize.Height()));
   3829  }
   3830  return nsSize(
   3831      ContainIntrinsicISize(aFrame).valueOr(aUncontainedSize.Width()),
   3832      ContainIntrinsicBSize(aFrame).valueOr(aUncontainedSize.Height()));
   3833 }
   3834 
   3835 IntrinsicSize ContainSizeAxes::ContainIntrinsicSize(
   3836    const IntrinsicSize& aUncontainedSize, const nsIFrame& aFrame) const {
   3837  if (!IsAny()) {
   3838    return aUncontainedSize;
   3839  }
   3840  IntrinsicSize result(aUncontainedSize);
   3841  const auto wm = aFrame.GetWritingMode();
   3842  if (Maybe<nscoord> containBSize = ContainIntrinsicBSize(aFrame)) {
   3843    result.BSize(wm) = containBSize;
   3844  }
   3845  if (Maybe<nscoord> containISize = ContainIntrinsicISize(aFrame)) {
   3846    result.ISize(wm) = containISize;
   3847  }
   3848  return result;
   3849 }