tor-browser

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

ServoStyleConstsInlines.h (45098B)


      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 /* Some inline functions declared in cbindgen.toml */
      8 
      9 #ifndef mozilla_ServoStyleConstsInlines_h
     10 #define mozilla_ServoStyleConstsInlines_h
     11 
     12 #include <new>
     13 #include <type_traits>
     14 
     15 #include "MainThreadUtils.h"
     16 #include "mozilla/AspectRatio.h"
     17 #include "mozilla/EndianUtils.h"
     18 #include "mozilla/IntegerRange.h"
     19 #include "mozilla/SVGContentUtils.h"
     20 #include "mozilla/ServoStyleConsts.h"
     21 #include "mozilla/URLExtraData.h"
     22 #include "mozilla/dom/WorkerCommon.h"
     23 #include "nsGkAtoms.h"
     24 #include "nsNetUtil.h"
     25 
     26 // TODO(emilio): there are quite a few other implementations scattered around
     27 // that should move here.
     28 
     29 namespace mozilla {
     30 
     31 // We need to explicitly instantiate these so that the clang plugin can see that
     32 // they're trivially copyable...
     33 //
     34 // https://github.com/eqrion/cbindgen/issues/402 tracks doing something like
     35 // this automatically from cbindgen.
     36 template struct StyleStrong<ComputedStyle>;
     37 template struct StyleStrong<StyleLockedCssRules>;
     38 template struct StyleStrong<StyleAnimationValue>;
     39 template struct StyleStrong<StyleLockedDeclarationBlock>;
     40 template struct StyleStrong<StyleStylesheetContents>;
     41 template struct StyleStrong<StyleLockedKeyframe>;
     42 template struct StyleStrong<StyleLayerBlockRule>;
     43 template struct StyleStrong<StyleLayerStatementRule>;
     44 template struct StyleStrong<StyleLockedMediaList>;
     45 template struct StyleStrong<StyleLockedStyleRule>;
     46 template struct StyleStrong<StyleLockedImportRule>;
     47 template struct StyleStrong<StyleLockedKeyframesRule>;
     48 template struct StyleStrong<StyleMediaRule>;
     49 template struct StyleStrong<StyleCustomMediaRule>;
     50 template struct StyleStrong<StyleDocumentRule>;
     51 template struct StyleStrong<StyleNamespaceRule>;
     52 template struct StyleStrong<StyleMarginRule>;
     53 template struct StyleStrong<StyleLockedPageRule>;
     54 template struct StyleStrong<StylePropertyRule>;
     55 template struct StyleStrong<StyleSupportsRule>;
     56 template struct StyleStrong<StyleFontFeatureValuesRule>;
     57 template struct StyleStrong<StyleFontPaletteValuesRule>;
     58 template struct StyleStrong<StyleLockedFontFaceRule>;
     59 template struct StyleStrong<StyleLockedCounterStyleRule>;
     60 template struct StyleStrong<StyleContainerRule>;
     61 template struct StyleStrong<StyleScopeRule>;
     62 template struct StyleStrong<StyleStartingStyleRule>;
     63 template struct StyleStrong<StyleLockedPositionTryRule>;
     64 template struct StyleStrong<StyleLockedNestedDeclarationsRule>;
     65 
     66 template <typename T>
     67 inline void StyleOwnedSlice<T>::Clear() {
     68  if (!len) {
     69    return;
     70  }
     71  for (size_t i : IntegerRange(len)) {
     72    ptr[i].~T();
     73  }
     74  free(ptr);
     75  ptr = (T*)alignof(T);
     76  len = 0;
     77 }
     78 
     79 template <typename T>
     80 inline void StyleOwnedSlice<T>::CopyFrom(const StyleOwnedSlice& aOther) {
     81  Clear();
     82  len = aOther.len;
     83  if (!len) {
     84    ptr = (T*)alignof(T);
     85  } else {
     86    ptr = (T*)malloc(len * sizeof(T));
     87    size_t i = 0;
     88    for (const T& elem : aOther.AsSpan()) {
     89      new (ptr + i++) T(elem);
     90    }
     91  }
     92 }
     93 
     94 template <typename T>
     95 inline void StyleOwnedSlice<T>::SwapElements(StyleOwnedSlice& aOther) {
     96  std::swap(ptr, aOther.ptr);
     97  std::swap(len, aOther.len);
     98 }
     99 
    100 template <typename T>
    101 inline StyleOwnedSlice<T>::StyleOwnedSlice(const StyleOwnedSlice& aOther)
    102    : StyleOwnedSlice() {
    103  CopyFrom(aOther);
    104 }
    105 
    106 template <typename T>
    107 inline StyleOwnedSlice<T>::StyleOwnedSlice(StyleOwnedSlice&& aOther)
    108    : StyleOwnedSlice() {
    109  SwapElements(aOther);
    110 }
    111 
    112 template <typename T>
    113 inline StyleOwnedSlice<T>::StyleOwnedSlice(Vector<T>&& aVector)
    114    : StyleOwnedSlice() {
    115  if (!aVector.length()) {
    116    return;
    117  }
    118 
    119  // We could handle this if Vector provided the relevant APIs, see bug 1610702.
    120  MOZ_DIAGNOSTIC_ASSERT(aVector.length() == aVector.capacity(),
    121                        "Shouldn't over-allocate");
    122  len = aVector.length();
    123  ptr = aVector.extractRawBuffer();
    124  MOZ_ASSERT(ptr,
    125             "How did extractRawBuffer return null if we're not using inline "
    126             "capacity?");
    127 }
    128 
    129 template <typename T>
    130 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=(
    131    const StyleOwnedSlice& aOther) {
    132  CopyFrom(aOther);
    133  return *this;
    134 }
    135 
    136 template <typename T>
    137 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=(
    138    StyleOwnedSlice&& aOther) {
    139  Clear();
    140  SwapElements(aOther);
    141  return *this;
    142 }
    143 
    144 template <typename T>
    145 inline StyleOwnedSlice<T>::~StyleOwnedSlice() {
    146  Clear();
    147 }
    148 
    149 // This code is basically a C++ port of the Arc::clone() implementation in
    150 // servo/components/servo_arc/lib.rs.
    151 static constexpr const size_t kStaticRefcount =
    152    std::numeric_limits<size_t>::max();
    153 static constexpr const size_t kMaxRefcount =
    154    std::numeric_limits<intptr_t>::max();
    155 
    156 template <typename T>
    157 inline void StyleArcInner<T>::IncrementRef() {
    158  if (count.load(std::memory_order_relaxed) != kStaticRefcount) {
    159    auto old_size = count.fetch_add(1, std::memory_order_relaxed);
    160    if (MOZ_UNLIKELY(old_size > kMaxRefcount)) {
    161      ::abort();
    162    }
    163  }
    164 }
    165 
    166 // This is a C++ port-ish of Arc::drop().
    167 template <typename T>
    168 inline bool StyleArcInner<T>::DecrementRef() {
    169  if (count.load(std::memory_order_relaxed) == kStaticRefcount) {
    170    return false;
    171  }
    172  if (count.fetch_sub(1, std::memory_order_release) != 1) {
    173    return false;
    174  }
    175 #ifdef MOZ_TSAN
    176  // TSan doesn't understand std::atomic_thread_fence, so in order
    177  // to avoid a false positive for every time a refcounted object
    178  // is deleted, we replace the fence with an atomic operation.
    179  count.load(std::memory_order_acquire);
    180 #else
    181  std::atomic_thread_fence(std::memory_order_acquire);
    182 #endif
    183  MOZ_LOG_DTOR(this, "ServoArc", 8);
    184  return true;
    185 }
    186 
    187 template <typename H, typename T>
    188 inline bool StyleHeaderSlice<H, T>::operator==(
    189    const StyleHeaderSlice& aOther) const {
    190  return header == aOther.header && AsSpan() == aOther.AsSpan();
    191 }
    192 
    193 template <typename H, typename T>
    194 inline bool StyleHeaderSlice<H, T>::operator!=(
    195    const StyleHeaderSlice& aOther) const {
    196  return !(*this == aOther);
    197 }
    198 
    199 template <typename H, typename T>
    200 inline StyleHeaderSlice<H, T>::~StyleHeaderSlice() {
    201  for (T& elem : Span(data, len)) {
    202    elem.~T();
    203  }
    204 }
    205 
    206 template <typename H, typename T>
    207 inline Span<const T> StyleHeaderSlice<H, T>::AsSpan() const {
    208  // Explicitly specify template argument here to avoid instantiating Span<T>
    209  // first and then implicitly converting to Span<const T>
    210  return Span<const T>{data, len};
    211 }
    212 
    213 static constexpr const uint64_t kArcSliceCanary = 0xf3f3f3f3f3f3f3f3;
    214 
    215 #define ASSERT_CANARY \
    216  MOZ_DIAGNOSTIC_ASSERT(_0.p->data.header == kArcSliceCanary, "Uh?");
    217 
    218 template <typename T>
    219 inline StyleArcSlice<T>::StyleArcSlice()
    220    : _0(reinterpret_cast<decltype(_0.p)>(Servo_StyleArcSlice_EmptyPtr())) {
    221  ASSERT_CANARY
    222 }
    223 
    224 template <typename T>
    225 inline StyleArcSlice<T>::StyleArcSlice(
    226    const StyleForgottenArcSlicePtr<T>& aPtr) {
    227  // See the forget() implementation to see why reinterpret_cast() is ok.
    228  _0.p = reinterpret_cast<decltype(_0.p)>(aPtr._0);
    229  ASSERT_CANARY
    230 }
    231 
    232 template <typename T>
    233 inline size_t StyleArcSlice<T>::Length() const {
    234  ASSERT_CANARY
    235  return _0->Length();
    236 }
    237 
    238 template <typename T>
    239 inline bool StyleArcSlice<T>::IsEmpty() const {
    240  ASSERT_CANARY
    241  return _0->IsEmpty();
    242 }
    243 
    244 template <typename T>
    245 inline Span<const T> StyleArcSlice<T>::AsSpan() const {
    246  ASSERT_CANARY
    247  return _0->AsSpan();
    248 }
    249 
    250 #undef ASSERT_CANARY
    251 
    252 template <typename T>
    253 inline StyleArc<T>::StyleArc(const StyleArc& aOther) : p(aOther.p) {
    254  p->IncrementRef();
    255 }
    256 
    257 template <typename T>
    258 inline void StyleArc<T>::Release() {
    259  if (MOZ_LIKELY(!p->DecrementRef())) {
    260    return;
    261  }
    262  p->data.~T();
    263  free(p);
    264 }
    265 
    266 template <typename T>
    267 inline StyleArc<T>& StyleArc<T>::operator=(const StyleArc& aOther) {
    268  if (p != aOther.p) {
    269    Release();
    270    p = aOther.p;
    271    p->IncrementRef();
    272  }
    273  return *this;
    274 }
    275 
    276 template <typename T>
    277 inline StyleArc<T>& StyleArc<T>::operator=(StyleArc&& aOther) {
    278  std::swap(p, aOther.p);
    279  return *this;
    280 }
    281 
    282 template <typename T>
    283 inline StyleArc<T>::~StyleArc() {
    284  Release();
    285 }
    286 
    287 inline bool StyleAtom::IsStatic() const { return !!(_0 & 1); }
    288 
    289 inline nsAtom* StyleAtom::AsAtom() const {
    290  if (IsStatic()) {
    291    return const_cast<nsStaticAtom*>(&detail::gGkAtoms.mAtoms[_0 >> 1]);
    292  }
    293  return reinterpret_cast<nsAtom*>(_0);
    294 }
    295 
    296 inline void StyleAtom::AddRef() {
    297  if (!IsStatic()) {
    298    AsAtom()->AddRef();
    299  }
    300 }
    301 
    302 inline void StyleAtom::Release() {
    303  if (!IsStatic()) {
    304    AsAtom()->Release();
    305  }
    306 }
    307 
    308 inline StyleAtom::StyleAtom(already_AddRefed<nsAtom> aAtom) {
    309  nsAtom* atom = aAtom.take();
    310  if (atom->IsStatic()) {
    311    size_t index = atom->AsStatic() - &detail::gGkAtoms.mAtoms[0];
    312    _0 = (index << 1) | 1;
    313  } else {
    314    _0 = reinterpret_cast<uintptr_t>(atom);
    315  }
    316  MOZ_ASSERT(IsStatic() == atom->IsStatic());
    317  MOZ_ASSERT(AsAtom() == atom);
    318 }
    319 
    320 inline StyleAtom::StyleAtom(nsStaticAtom* aAtom)
    321    : StyleAtom(do_AddRef(static_cast<nsAtom*>(aAtom))) {}
    322 
    323 inline StyleAtom::StyleAtom(const StyleAtom& aOther) : _0(aOther._0) {
    324  AddRef();
    325 }
    326 
    327 inline StyleAtom& StyleAtom::operator=(const StyleAtom& aOther) {
    328  if (MOZ_LIKELY(this != &aOther)) {
    329    Release();
    330    _0 = aOther._0;
    331    AddRef();
    332  }
    333  return *this;
    334 }
    335 
    336 inline StyleAtom::~StyleAtom() { Release(); }
    337 
    338 inline nsAtom* StyleCustomIdent::AsAtom() const { return _0.AsAtom(); }
    339 
    340 inline nsDependentCSubstring StyleOwnedStr::AsString() const {
    341  Span<const uint8_t> s = _0.AsSpan();
    342  return nsDependentCSubstring(reinterpret_cast<const char*>(s.Elements()),
    343                               s.Length());
    344 }
    345 
    346 template <typename T>
    347 inline Span<const T> StyleGenericTransform<T>::Operations() const {
    348  return _0.AsSpan();
    349 }
    350 
    351 template <typename T>
    352 inline bool StyleGenericTransform<T>::IsNone() const {
    353  return Operations().IsEmpty();
    354 }
    355 
    356 inline StyleAngle StyleAngle::Zero() { return {0.0f}; }
    357 
    358 inline float StyleAngle::ToDegrees() const { return _0; }
    359 
    360 inline double StyleAngle::ToRadians() const {
    361  return double(ToDegrees()) * M_PI / 180.0;
    362 }
    363 
    364 inline bool StyleUrlExtraData::IsShared() const { return !!(_0 & 1); }
    365 
    366 inline StyleUrlExtraData::~StyleUrlExtraData() {
    367  if (!IsShared()) {
    368    reinterpret_cast<URLExtraData*>(_0)->Release();
    369  }
    370 }
    371 
    372 inline const URLExtraData& StyleUrlExtraData::get() const {
    373  if (IsShared()) {
    374    return *URLExtraData::sShared[_0 >> 1];
    375  }
    376  return *reinterpret_cast<const URLExtraData*>(_0);
    377 }
    378 
    379 inline nsDependentCSubstring StyleCssUrl::SpecifiedSerialization() const {
    380  return _0->serialization.AsString();
    381 }
    382 
    383 inline const URLExtraData& StyleCssUrl::ExtraData() const {
    384  return _0->extra_data.get();
    385 }
    386 
    387 inline const StyleLoadData& StyleCssUrl::LoadData() const {
    388  if (MOZ_LIKELY(_0->load_data.tag == StyleLoadDataSource::Tag::Owned)) {
    389    return _0->load_data.owned._0;
    390  }
    391  return *Servo_LoadData_GetLazy(&_0->load_data);
    392 }
    393 
    394 inline StyleLoadData& StyleCssUrl::MutLoadData() const {
    395  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread() ||
    396                        dom::IsCurrentThreadRunningWorker());
    397  return const_cast<StyleLoadData&>(LoadData());
    398 }
    399 
    400 inline nsIURI* StyleCssUrl::GetURI() const {
    401  auto& loadData = const_cast<StyleLoadData&>(LoadData());
    402  // Try to read the flags first. If it's set we can avoid entering the CAS
    403  // loop.
    404  auto flags = __atomic_load_n(&loadData.flags.bits, __ATOMIC_RELAXED);
    405  if (!(flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_URI.bits)) {
    406    nsDependentCSubstring serialization = SpecifiedSerialization();
    407    // https://drafts.csswg.org/css-values-4/#url-empty:
    408    //
    409    //     If the value of the url() is the empty string (like url("") or
    410    //     url()), the url must resolve to an invalid resource (similar to what
    411    //     the url about:invalid does).
    412    //
    413    nsIURI* resolved = nullptr;
    414    if (!serialization.IsEmpty()) {
    415      nsIURI* old_resolved = nullptr;
    416      // NOTE: This addrefs `resolved`, and `resolved` might still be null for
    417      // invalid URIs.
    418      NS_NewURI(&resolved, serialization, nullptr, ExtraData().BaseURI());
    419      if (!__atomic_compare_exchange_n(&loadData.resolved_uri, &old_resolved,
    420                                       resolved, /* weak = */ false,
    421                                       __ATOMIC_RELEASE, __ATOMIC_RELAXED)) {
    422        // In the unlikely case two threads raced to write the url, avoid
    423        // leaking resolved. The actual value is in `old_resolved`.
    424        NS_IF_RELEASE(resolved);
    425        resolved = old_resolved;
    426      }
    427    }
    428    // The flag is effectively just an optimization so we can use relaxed
    429    // ordering.
    430    __atomic_fetch_or(&loadData.flags.bits,
    431                      StyleLoadDataFlags::TRIED_TO_RESOLVE_URI.bits,
    432                      __ATOMIC_RELAXED);
    433    return resolved;
    434  }
    435  return __atomic_load_n(&loadData.resolved_uri, __ATOMIC_ACQUIRE);
    436 }
    437 
    438 inline nsDependentCSubstring StyleComputedUrl::SpecifiedSerialization() const {
    439  return _0.SpecifiedSerialization();
    440 }
    441 inline const URLExtraData& StyleComputedUrl::ExtraData() const {
    442  return _0.ExtraData();
    443 }
    444 inline const StyleLoadData& StyleComputedUrl::LoadData() const {
    445  return _0.LoadData();
    446 }
    447 inline StyleLoadData& StyleComputedUrl::MutLoadData() const {
    448  return _0.MutLoadData();
    449 }
    450 inline StyleCorsMode StyleComputedUrl::CorsMode() const {
    451  return _0._0->cors_mode;
    452 }
    453 inline nsIURI* StyleComputedUrl::GetURI() const { return _0.GetURI(); }
    454 
    455 inline bool StyleComputedUrl::IsLocalRef() const {
    456  return Servo_CssUrl_IsLocalRef(&_0);
    457 }
    458 
    459 inline bool StyleComputedUrl::HasRef() const {
    460  if (IsLocalRef()) {
    461    return true;
    462  }
    463  if (nsIURI* uri = GetURI()) {
    464    bool hasRef = false;
    465    return NS_SUCCEEDED(uri->GetHasRef(&hasRef)) && hasRef;
    466  }
    467  return false;
    468 }
    469 
    470 inline bool StyleComputedUrl::IsImageResolved() const {
    471  return bool(LoadData().flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE);
    472 }
    473 
    474 inline imgRequestProxy* StyleComputedUrl::GetImage() const {
    475  MOZ_ASSERT(IsImageResolved());
    476  return LoadData().resolved_image;
    477 }
    478 
    479 template <>
    480 inline bool StyleGradient::Repeating() const {
    481  if (IsLinear()) {
    482    return bool(AsLinear().flags & StyleGradientFlags::REPEATING);
    483  }
    484  if (IsRadial()) {
    485    return bool(AsRadial().flags & StyleGradientFlags::REPEATING);
    486  }
    487  return bool(AsConic().flags & StyleGradientFlags::REPEATING);
    488 }
    489 
    490 template <>
    491 bool StyleGradient::IsOpaque() const;
    492 
    493 template <>
    494 inline const StyleColorInterpolationMethod&
    495 StyleGradient::ColorInterpolationMethod() const {
    496  if (IsLinear()) {
    497    return AsLinear().color_interpolation_method;
    498  }
    499  if (IsRadial()) {
    500    return AsRadial().color_interpolation_method;
    501  }
    502  return AsConic().color_interpolation_method;
    503 }
    504 
    505 template <typename Integer>
    506 inline StyleGenericGridLine<Integer>::StyleGenericGridLine()
    507    : ident{StyleAtom(nsGkAtoms::_empty)}, line_num(0), is_span(false) {}
    508 
    509 template <>
    510 inline nsAtom* StyleGridLine::LineName() const {
    511  return ident.AsAtom();
    512 }
    513 
    514 template <>
    515 inline bool StyleGridLine::IsAuto() const {
    516  return LineName()->IsEmpty() && line_num == 0 && !is_span;
    517 }
    518 
    519 using LengthPercentage = StyleLengthPercentage;
    520 using LengthPercentageOrAuto = StyleLengthPercentageOrAuto;
    521 using NonNegativeLengthPercentage = StyleNonNegativeLengthPercentage;
    522 using NonNegativeLengthPercentageOrAuto =
    523    StyleNonNegativeLengthPercentageOrAuto;
    524 using NonNegativeLengthPercentageOrNormal =
    525    StyleNonNegativeLengthPercentageOrNormal;
    526 using Length = StyleLength;
    527 using LengthOrAuto = StyleLengthOrAuto;
    528 using NonNegativeLength = StyleNonNegativeLength;
    529 using NonNegativeLengthOrAuto = StyleNonNegativeLengthOrAuto;
    530 using BorderRadius = StyleBorderRadius;
    531 
    532 bool StyleCSSPixelLength::IsZero() const { return _0 == 0.0f; }
    533 
    534 void StyleCSSPixelLength::ScaleBy(float aScale) { _0 *= aScale; }
    535 
    536 StyleCSSPixelLength StyleCSSPixelLength::ScaledBy(float aScale) const {
    537  return FromPixels(ToCSSPixels() * aScale);
    538 }
    539 
    540 namespace detail {
    541 static inline nscoord DefaultPercentLengthToAppUnits(float aPixelLength) {
    542  return NSToCoordTruncClamped(aPixelLength);
    543 }
    544 
    545 static inline nscoord DefaultLengthToAppUnits(float aPixelLength) {
    546  // We want to round lengths rounding 0.5 away from zero, instead of the
    547  // default behavior of NSToCoordRound{,WithClamp} which do floor(x + 0.5).
    548  float length = aPixelLength * float(mozilla::AppUnitsPerCSSPixel());
    549  if (length >= float(nscoord_MAX)) {
    550    return nscoord_MAX;
    551  }
    552  if (length <= float(nscoord_MIN)) {
    553    return nscoord_MIN;
    554  }
    555  return NSToIntRound(length);
    556 }
    557 }  // namespace detail
    558 
    559 nscoord StyleCSSPixelLength::ToAppUnits() const {
    560  if (IsZero()) {
    561    // Avoid the expensive FP math below.
    562    return 0;
    563  }
    564  return detail::DefaultLengthToAppUnits(_0);
    565 }
    566 
    567 bool LengthPercentage::IsLength() const { return Tag() == TAG_LENGTH; }
    568 
    569 StyleLengthPercentageUnion::StyleLengthPercentageUnion() {
    570  length = {TAG_LENGTH, {0.0f}};
    571  MOZ_ASSERT(IsLength());
    572 }
    573 
    574 static_assert(sizeof(LengthPercentage) == sizeof(uint64_t), "");
    575 
    576 Length& LengthPercentage::AsLength() {
    577  MOZ_ASSERT(IsLength());
    578  return length.length;
    579 }
    580 
    581 const Length& LengthPercentage::AsLength() const {
    582  return const_cast<LengthPercentage*>(this)->AsLength();
    583 }
    584 
    585 bool LengthPercentage::IsPercentage() const { return Tag() == TAG_PERCENTAGE; }
    586 
    587 StylePercentage& LengthPercentage::AsPercentage() {
    588  MOZ_ASSERT(IsPercentage());
    589  return percentage.percentage;
    590 }
    591 
    592 const StylePercentage& LengthPercentage::AsPercentage() const {
    593  return const_cast<LengthPercentage*>(this)->AsPercentage();
    594 }
    595 
    596 bool LengthPercentage::IsCalc() const { return Tag() == TAG_CALC; }
    597 
    598 StyleCalcLengthPercentage& LengthPercentage::AsCalc() {
    599  MOZ_ASSERT(IsCalc());
    600  // NOTE: in 32-bits, the pointer is not swapped, and goes along with the tag.
    601 #ifdef SERVO_32_BITS
    602  return *reinterpret_cast<StyleCalcLengthPercentage*>(calc.ptr);
    603 #else
    604  return *reinterpret_cast<StyleCalcLengthPercentage*>(
    605      NativeEndian::swapFromLittleEndian(calc.ptr));
    606 #endif
    607 }
    608 
    609 const StyleCalcLengthPercentage& LengthPercentage::AsCalc() const {
    610  return const_cast<LengthPercentage*>(this)->AsCalc();
    611 }
    612 
    613 StyleLengthPercentageUnion::StyleLengthPercentageUnion(const Self& aOther) {
    614  if (aOther.IsLength()) {
    615    length = {TAG_LENGTH, aOther.AsLength()};
    616  } else if (aOther.IsPercentage()) {
    617    percentage = {TAG_PERCENTAGE, aOther.AsPercentage()};
    618  } else {
    619    MOZ_ASSERT(aOther.IsCalc());
    620    auto* ptr = new StyleCalcLengthPercentage(aOther.AsCalc());
    621    // NOTE: in 32-bits, the pointer is not swapped, and goes along with the
    622    // tag.
    623    calc = {
    624 #ifdef SERVO_32_BITS
    625        TAG_CALC,
    626        ptr,
    627 #else
    628        NativeEndian::swapToLittleEndian(reinterpret_cast<uintptr_t>(ptr)),
    629 #endif
    630    };
    631  }
    632  MOZ_ASSERT(Tag() == aOther.Tag());
    633 }
    634 
    635 StyleLengthPercentageUnion::~StyleLengthPercentageUnion() {
    636  if (IsCalc()) {
    637    delete &AsCalc();
    638  }
    639 }
    640 
    641 LengthPercentage& LengthPercentage::operator=(const LengthPercentage& aOther) {
    642  if (this != &aOther) {
    643    this->~LengthPercentage();
    644    new (this) LengthPercentage(aOther);
    645  }
    646  return *this;
    647 }
    648 
    649 bool LengthPercentage::operator==(const LengthPercentage& aOther) const {
    650  if (Tag() != aOther.Tag()) {
    651    return false;
    652  }
    653  if (IsLength()) {
    654    return AsLength() == aOther.AsLength();
    655  }
    656  if (IsPercentage()) {
    657    return AsPercentage() == aOther.AsPercentage();
    658  }
    659  return AsCalc() == aOther.AsCalc();
    660 }
    661 
    662 bool LengthPercentage::operator!=(const LengthPercentage& aOther) const {
    663  return !(*this == aOther);
    664 }
    665 
    666 LengthPercentage LengthPercentage::Zero() { return {}; }
    667 
    668 LengthPercentage LengthPercentage::FromPixels(CSSCoord aCoord) {
    669  LengthPercentage l;
    670  MOZ_ASSERT(l.IsLength());
    671  l.length.length = {aCoord};
    672  return l;
    673 }
    674 
    675 LengthPercentage LengthPercentage::FromAppUnits(nscoord aCoord) {
    676  return FromPixels(CSSPixel::FromAppUnits(aCoord));
    677 }
    678 
    679 LengthPercentage LengthPercentage::FromPercentage(float aPercentage) {
    680  LengthPercentage l;
    681  l.percentage = {TAG_PERCENTAGE, {aPercentage}};
    682  return l;
    683 }
    684 
    685 bool LengthPercentage::HasPercent() const { return IsPercentage() || IsCalc(); }
    686 
    687 bool LengthPercentage::ConvertsToLength() const { return IsLength(); }
    688 
    689 nscoord LengthPercentage::ToLength() const {
    690  MOZ_ASSERT(ConvertsToLength());
    691  return AsLength().ToAppUnits();
    692 }
    693 
    694 CSSCoord LengthPercentage::ToLengthInCSSPixels() const {
    695  MOZ_ASSERT(ConvertsToLength());
    696  return AsLength().ToCSSPixels();
    697 }
    698 
    699 bool LengthPercentage::ConvertsToPercentage() const { return IsPercentage(); }
    700 
    701 float LengthPercentage::ToPercentage() const {
    702  MOZ_ASSERT(ConvertsToPercentage());
    703  return AsPercentage()._0;
    704 }
    705 
    706 bool LengthPercentage::HasLengthAndPercentage() const {
    707  if (!IsCalc()) {
    708    return false;
    709  }
    710  MOZ_ASSERT(!ConvertsToLength() && !ConvertsToPercentage(),
    711             "Should've been simplified earlier");
    712  return true;
    713 }
    714 
    715 bool LengthPercentage::IsDefinitelyZero() const {
    716  if (IsLength()) {
    717    return AsLength().IsZero();
    718  }
    719  if (IsPercentage()) {
    720    return AsPercentage()._0 == 0.0f;
    721  }
    722  // calc() should've been simplified to a percentage.
    723  return false;
    724 }
    725 
    726 CSSCoord StyleCalcLengthPercentage::ResolveToCSSPixels(CSSCoord aBasis) const {
    727  return Servo_ResolveCalcLengthPercentage(this, aBasis);
    728 }
    729 
    730 template <typename Rounder>
    731 nscoord StyleCalcLengthPercentage::Resolve(nscoord aBasis,
    732                                           Rounder aRounder) const {
    733  static_assert(std::is_same_v<decltype(aRounder(1.0f)), nscoord>);
    734  CSSCoord result = ResolveToCSSPixels(CSSPixel::FromAppUnits(aBasis));
    735  return aRounder(result * AppUnitsPerCSSPixel());
    736 }
    737 
    738 template <>
    739 void StyleCalcNode::ScaleLengthsBy(float);
    740 
    741 CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const {
    742  if (IsLength()) {
    743    return AsLength().ToCSSPixels();
    744  }
    745  if (IsPercentage()) {
    746    return AsPercentage()._0 * aPercentageBasis;
    747  }
    748  return AsCalc().ResolveToCSSPixels(aPercentageBasis);
    749 }
    750 
    751 template <typename T>
    752 CSSCoord LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter) const {
    753  static_assert(std::is_same_v<decltype(aPercentageGetter()), CSSCoord>);
    754  if (ConvertsToLength()) {
    755    return ToLengthInCSSPixels();
    756  }
    757  return ResolveToCSSPixels(aPercentageGetter());
    758 }
    759 
    760 template <typename T, typename Rounder>
    761 nscoord LengthPercentage::Resolve(T aPercentageGetter, Rounder aRounder) const {
    762  static_assert(std::is_same_v<decltype(aPercentageGetter()), nscoord>);
    763  static_assert(std::is_same_v<decltype(aRounder(1.0f)), nscoord>);
    764  if (ConvertsToLength()) {
    765    return ToLength();
    766  }
    767  if (IsPercentage() && AsPercentage()._0 == 0.0f) {
    768    return 0;
    769  }
    770  nscoord basis = aPercentageGetter();
    771  if (IsPercentage()) {
    772    return aRounder(basis * AsPercentage()._0);
    773  }
    774  return AsCalc().Resolve(basis, aRounder);
    775 }
    776 
    777 nscoord LengthPercentage::Resolve(nscoord aPercentageBasis) const {
    778  return Resolve([=] { return aPercentageBasis; },
    779                 detail::DefaultPercentLengthToAppUnits);
    780 }
    781 
    782 template <typename T>
    783 nscoord LengthPercentage::Resolve(T aPercentageGetter) const {
    784  return Resolve(aPercentageGetter, detail::DefaultPercentLengthToAppUnits);
    785 }
    786 
    787 template <typename Rounder>
    788 nscoord LengthPercentage::Resolve(nscoord aPercentageBasis,
    789                                  Rounder aRounder) const {
    790  return Resolve([aPercentageBasis] { return aPercentageBasis; }, aRounder);
    791 }
    792 
    793 void LengthPercentage::ScaleLengthsBy(float aScale) {
    794  if (IsLength()) {
    795    AsLength().ScaleBy(aScale);
    796  }
    797  if (IsCalc()) {
    798    AsCalc().node.ScaleLengthsBy(aScale);
    799  }
    800 }
    801 
    802 #define IMPL_LENGTHPERCENTAGE_FORWARDS(ty_)                                 \
    803  template <>                                                               \
    804  inline bool ty_::HasPercent() const {                                     \
    805    return IsLengthPercentage() && AsLengthPercentage().HasPercent();       \
    806  }                                                                         \
    807  template <>                                                               \
    808  inline bool ty_::ConvertsToLength() const {                               \
    809    return IsLengthPercentage() && AsLengthPercentage().ConvertsToLength(); \
    810  }                                                                         \
    811  template <>                                                               \
    812  inline bool ty_::HasLengthAndPercentage() const {                         \
    813    return IsLengthPercentage() &&                                          \
    814           AsLengthPercentage().HasLengthAndPercentage();                   \
    815  }                                                                         \
    816  template <>                                                               \
    817  inline nscoord ty_::ToLength() const {                                    \
    818    MOZ_ASSERT(ConvertsToLength());                                         \
    819    return AsLengthPercentage().ToLength();                                 \
    820  }                                                                         \
    821  template <>                                                               \
    822  inline bool ty_::ConvertsToPercentage() const {                           \
    823    return IsLengthPercentage() &&                                          \
    824           AsLengthPercentage().ConvertsToPercentage();                     \
    825  }                                                                         \
    826  template <>                                                               \
    827  inline float ty_::ToPercentage() const {                                  \
    828    MOZ_ASSERT(ConvertsToPercentage());                                     \
    829    return AsLengthPercentage().ToPercentage();                             \
    830  }
    831 
    832 IMPL_LENGTHPERCENTAGE_FORWARDS(LengthPercentageOrAuto)
    833 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleSize)
    834 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleMaxSize)
    835 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleInset)
    836 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleMargin)
    837 
    838 template <>
    839 inline bool StyleInset::HasAnchorPositioningFunction() const {
    840  return IsAnchorFunction() || IsAnchorSizeFunction() ||
    841         IsAnchorContainingCalcFunction();
    842 }
    843 
    844 template <>
    845 inline bool StyleMargin::HasAnchorPositioningFunction() const {
    846  return IsAnchorSizeFunction() || IsAnchorContainingCalcFunction();
    847 }
    848 
    849 template <>
    850 inline bool StyleSize::HasAnchorPositioningFunction() const {
    851  return IsAnchorSizeFunction() || IsAnchorContainingCalcFunction();
    852 }
    853 
    854 template <>
    855 inline bool StyleMaxSize::HasAnchorPositioningFunction() const {
    856  return IsAnchorSizeFunction() || IsAnchorContainingCalcFunction();
    857 }
    858 
    859 #undef IMPL_LENGTHPERCENTAGE_FORWARDS
    860 
    861 template <>
    862 inline bool LengthOrAuto::IsLength() const {
    863  return IsLengthPercentage();
    864 }
    865 
    866 template <>
    867 inline const Length& LengthOrAuto::AsLength() const {
    868  return AsLengthPercentage();
    869 }
    870 
    871 template <>
    872 inline nscoord LengthOrAuto::ToLength() const {
    873  return AsLength().ToAppUnits();
    874 }
    875 
    876 template <>
    877 inline bool StyleFlexBasis::IsAuto() const {
    878  return IsSize() && AsSize().IsAuto();
    879 }
    880 
    881 #define IMPL_BEHAVES_LIKE_SIZE_METHODS(ty_, isInitialValMethod_)        \
    882  template <>                                                           \
    883  inline bool ty_::BehavesLikeStretchOnInlineAxis() const {             \
    884    return IsStretch() || IsMozAvailable() || IsWebkitFillAvailable();  \
    885  }                                                                     \
    886  template <>                                                           \
    887  inline bool ty_::BehavesLikeStretchOnBlockAxis() const {              \
    888    /* TODO(dholbert): Add "|| IsMozAvailable()" in bug 527285. */      \
    889    return IsStretch() || IsWebkitFillAvailable();                      \
    890  }                                                                     \
    891  template <>                                                           \
    892  inline bool ty_::BehavesLikeInitialValueOnBlockAxis() const {         \
    893    return isInitialValMethod_() ||                                     \
    894           (!BehavesLikeStretchOnBlockAxis() && !IsLengthPercentage()); \
    895  }
    896 
    897 IMPL_BEHAVES_LIKE_SIZE_METHODS(StyleSize, IsAuto)
    898 IMPL_BEHAVES_LIKE_SIZE_METHODS(StyleMaxSize, IsNone)
    899 
    900 #undef IMPL_BEHAVES_LIKE_SIZE_METHODS
    901 
    902 template <>
    903 inline bool StyleBackgroundSize::IsInitialValue() const {
    904  return IsExplicitSize() && explicit_size.width.IsAuto() &&
    905         explicit_size.height.IsAuto();
    906 }
    907 
    908 template <typename T>
    909 const T& StyleRect<T>::Get(mozilla::Side aSide) const {
    910  static_assert(sizeof(StyleRect<T>) == sizeof(T) * 4, "");
    911  static_assert(alignof(StyleRect<T>) == alignof(T), "");
    912  return reinterpret_cast<const T*>(this)[aSide];
    913 }
    914 
    915 template <typename T>
    916 T& StyleRect<T>::Get(mozilla::Side aSide) {
    917  return const_cast<T&>(static_cast<const StyleRect&>(*this).Get(aSide));
    918 }
    919 
    920 template <typename T>
    921 template <typename Predicate>
    922 bool StyleRect<T>::All(Predicate aPredicate) const {
    923  return aPredicate(_0) && aPredicate(_1) && aPredicate(_2) && aPredicate(_3);
    924 }
    925 
    926 template <typename T>
    927 template <typename Predicate>
    928 bool StyleRect<T>::Any(Predicate aPredicate) const {
    929  return aPredicate(_0) || aPredicate(_1) || aPredicate(_2) || aPredicate(_3);
    930 }
    931 
    932 template <>
    933 inline const LengthPercentage& BorderRadius::Get(HalfCorner aCorner) const {
    934  static_assert(sizeof(BorderRadius) == sizeof(LengthPercentage) * 8, "");
    935  static_assert(alignof(BorderRadius) == alignof(LengthPercentage), "");
    936  const auto* self = reinterpret_cast<const LengthPercentage*>(this);
    937  return self[aCorner];
    938 }
    939 
    940 template <>
    941 inline bool StyleTrackBreadth::HasPercent() const {
    942  return IsBreadth() && AsBreadth().HasPercent();
    943 }
    944 
    945 // Implemented in nsStyleStructs.cpp
    946 template <>
    947 bool StyleTransform::HasPercent() const;
    948 
    949 template <>
    950 inline bool StyleTransformOrigin::HasPercent() const {
    951  // NOTE(emilio): `depth` is just a `<length>` so doesn't have a percentage at
    952  // all.
    953  return horizontal.HasPercent() || vertical.HasPercent();
    954 }
    955 
    956 template <>
    957 inline Maybe<size_t> StyleGridTemplateComponent::RepeatAutoIndex() const {
    958  if (!IsTrackList()) {
    959    return Nothing();
    960  }
    961  const auto& list = *AsTrackList();
    962  return list.auto_repeat_index < list.values.Length()
    963             ? Some(list.auto_repeat_index)
    964             : Nothing();
    965 }
    966 
    967 template <>
    968 inline bool StyleGridTemplateComponent::HasRepeatAuto() const {
    969  return RepeatAutoIndex().isSome();
    970 }
    971 
    972 template <>
    973 inline Span<const StyleGenericTrackListValue<LengthPercentage, StyleInteger>>
    974 StyleGridTemplateComponent::TrackListValues() const {
    975  if (IsTrackList()) {
    976    return AsTrackList()->values.AsSpan();
    977  }
    978  return {};
    979 }
    980 
    981 template <>
    982 inline const StyleGenericTrackRepeat<LengthPercentage, StyleInteger>*
    983 StyleGridTemplateComponent::GetRepeatAutoValue() const {
    984  auto index = RepeatAutoIndex();
    985  if (!index) {
    986    return nullptr;
    987  }
    988  return &TrackListValues()[*index].AsTrackRepeat();
    989 }
    990 
    991 constexpr const auto kPaintOrderShift = StylePAINT_ORDER_SHIFT;
    992 constexpr const auto kPaintOrderMask = StylePAINT_ORDER_MASK;
    993 
    994 template <>
    995 inline nsRect StyleGenericClipRect<LengthOrAuto>::ToLayoutRect(
    996    nscoord aAutoSize) const {
    997  nscoord x = left.IsLength() ? left.ToLength() : 0;
    998  nscoord y = top.IsLength() ? top.ToLength() : 0;
    999  nscoord width = right.IsLength() ? right.ToLength() - x : aAutoSize;
   1000  nscoord height = bottom.IsLength() ? bottom.ToLength() - y : aAutoSize;
   1001  return nsRect(x, y, width, height);
   1002 }
   1003 
   1004 using RestyleHint = StyleRestyleHint;
   1005 
   1006 inline RestyleHint RestyleHint::RestyleSubtree() {
   1007  return RESTYLE_SELF | RESTYLE_DESCENDANTS;
   1008 }
   1009 
   1010 inline RestyleHint RestyleHint::RecascadeSubtree() {
   1011  return RECASCADE_SELF | RECASCADE_DESCENDANTS;
   1012 }
   1013 
   1014 inline RestyleHint RestyleHint::ForAnimations() {
   1015  return RESTYLE_CSS_TRANSITIONS | RESTYLE_CSS_ANIMATIONS | RESTYLE_SMIL;
   1016 }
   1017 
   1018 inline bool RestyleHint::DefinitelyRecascadesAllSubtree() const {
   1019  if (!(*this & (RECASCADE_DESCENDANTS | RESTYLE_DESCENDANTS))) {
   1020    return false;
   1021  }
   1022  return bool(*this & (RESTYLE_SELF | RECASCADE_SELF));
   1023 }
   1024 
   1025 template <>
   1026 ImageResolution StyleImage::GetResolution(const ComputedStyle*) const;
   1027 
   1028 template <>
   1029 inline const StyleImage& StyleImage::FinalImage() const {
   1030  if (!IsImageSet()) {
   1031    return *this;
   1032  }
   1033  const auto& set = *AsImageSet();
   1034  auto items = set.items.AsSpan();
   1035  if (MOZ_LIKELY(set.selected_index < items.Length())) {
   1036    return items[set.selected_index].image.FinalImage();
   1037  }
   1038  static auto sNone = StyleImage::None();
   1039  return sNone;
   1040 }
   1041 
   1042 template <>
   1043 inline bool StyleImage::IsImageRequestType() const {
   1044  const auto& finalImage = FinalImage();
   1045  return finalImage.IsUrl();
   1046 }
   1047 
   1048 template <>
   1049 inline const StyleComputedUrl* StyleImage::GetImageRequestURLValue() const {
   1050  const auto& finalImage = FinalImage();
   1051  if (finalImage.IsUrl()) {
   1052    return &finalImage.AsUrl();
   1053  }
   1054  return nullptr;
   1055 }
   1056 
   1057 template <>
   1058 inline imgRequestProxy* StyleImage::GetImageRequest() const {
   1059  const auto* url = GetImageRequestURLValue();
   1060  return url ? url->GetImage() : nullptr;
   1061 }
   1062 
   1063 template <>
   1064 inline bool StyleImage::IsResolved() const {
   1065  const auto* url = GetImageRequestURLValue();
   1066  return !url || url->IsImageResolved();
   1067 }
   1068 
   1069 template <>
   1070 bool StyleImage::IsOpaque() const;
   1071 template <>
   1072 bool StyleImage::IsSizeAvailable() const;
   1073 template <>
   1074 bool StyleImage::IsComplete() const;
   1075 template <>
   1076 void StyleImage::ResolveImage(dom::Document&, const StyleImage*);
   1077 
   1078 template <>
   1079 inline AspectRatio StyleRatio<StyleNonNegativeNumber>::ToLayoutRatio(
   1080    UseBoxSizing aUseBoxSizing) const {
   1081  // 0/1, 1/0, and 0/0 are all degenerate ratios (which behave as auto), and we
   1082  // always return 0.0f.
   1083  // https://drafts.csswg.org/css-values-4/#degenerate-ratio
   1084  return AspectRatio::FromSize(_0, _1, aUseBoxSizing);
   1085 }
   1086 
   1087 template <>
   1088 inline AspectRatio StyleAspectRatio::ToLayoutRatio() const {
   1089  return HasRatio() ? ratio.AsRatio().ToLayoutRatio(auto_ ? UseBoxSizing::No
   1090                                                          : UseBoxSizing::Yes)
   1091                    : AspectRatio();
   1092 }
   1093 
   1094 inline void StyleFontWeight::ToString(nsACString& aString) const {
   1095  Servo_FontWeight_ToCss(this, &aString);
   1096 }
   1097 
   1098 inline void StyleFontStretch::ToString(nsACString& aString) const {
   1099  Servo_FontStretch_ToCss(this, &aString);
   1100 }
   1101 
   1102 inline void StyleFontStyle::ToString(nsACString& aString) const {
   1103  Servo_FontStyle_ToCss(this, &aString);
   1104 }
   1105 
   1106 inline bool StyleFontWeight::IsBold() const { return *this >= BOLD_THRESHOLD; }
   1107 
   1108 inline bool StyleFontWeight::PreferBold() const {
   1109  return *this > PREFER_BOLD_THRESHOLD;
   1110 }
   1111 
   1112 inline bool StyleFontStyle::IsItalic() const { return *this == ITALIC; }
   1113 
   1114 inline float StyleFontStyle::ObliqueAngle() const {
   1115  MOZ_ASSERT(!IsItalic());
   1116  return ToFloat();
   1117 }
   1118 
   1119 inline float StyleFontStyle::SlantAngle() const {
   1120  return IsNormal() ? 0 : IsItalic() ? DEFAULT_OBLIQUE_DEGREES : ObliqueAngle();
   1121 }
   1122 
   1123 using FontStretch = StyleFontStretch;
   1124 using FontSlantStyle = StyleFontStyle;
   1125 using FontWeight = StyleFontWeight;
   1126 
   1127 template <>
   1128 inline double StyleComputedTimingFunction::At(double aPortion,
   1129                                              bool aBeforeFlag) const {
   1130  return Servo_EasingFunctionAt(
   1131      this, aPortion,
   1132      aBeforeFlag ? StyleEasingBeforeFlag::Set : StyleEasingBeforeFlag::Unset);
   1133 }
   1134 
   1135 template <>
   1136 inline void StyleComputedTimingFunction::AppendToString(
   1137    nsACString& aOut) const {
   1138  return Servo_SerializeEasing(this, &aOut);
   1139 }
   1140 
   1141 template <>
   1142 inline double StyleComputedTimingFunction::GetPortion(
   1143    const Maybe<StyleComputedTimingFunction>& aFn, double aPortion,
   1144    bool aBeforeFlag) {
   1145  return aFn ? aFn->At(aPortion, aBeforeFlag) : aPortion;
   1146 }
   1147 
   1148 /* static */
   1149 template <>
   1150 inline LengthPercentageOrAuto LengthPercentageOrAuto::Zero() {
   1151  return LengthPercentage(LengthPercentage::Zero());
   1152 }
   1153 
   1154 template <>
   1155 inline StyleViewTimelineInset::StyleGenericViewTimelineInset()
   1156    : start(LengthPercentageOrAuto::Auto()),
   1157      end(LengthPercentageOrAuto::Auto()) {}
   1158 
   1159 inline StyleDisplayOutside StyleDisplay::Outside() const {
   1160  return StyleDisplayOutside((_0 & OUTSIDE_MASK) >> OUTSIDE_SHIFT);
   1161 }
   1162 
   1163 inline StyleDisplayInside StyleDisplay::Inside() const {
   1164  return StyleDisplayInside(_0 & INSIDE_MASK);
   1165 }
   1166 
   1167 inline bool StyleDisplay::IsListItem() const { return _0 & LIST_ITEM_MASK; }
   1168 
   1169 inline bool StyleDisplay::IsInternalTable() const {
   1170  return Outside() == StyleDisplayOutside::InternalTable;
   1171 }
   1172 
   1173 inline bool StyleDisplay::IsInternalTableExceptCell() const {
   1174  return IsInternalTable() && *this != TableCell;
   1175 }
   1176 
   1177 inline bool StyleDisplay::IsInternalRuby() const {
   1178  return Outside() == StyleDisplayOutside::InternalRuby;
   1179 }
   1180 
   1181 inline bool StyleDisplay::IsRuby() const {
   1182  return Inside() == StyleDisplayInside::Ruby || IsInternalRuby();
   1183 }
   1184 
   1185 inline bool StyleDisplay::IsInlineFlow() const {
   1186  return Outside() == StyleDisplayOutside::Inline &&
   1187         Inside() == StyleDisplayInside::Flow;
   1188 }
   1189 
   1190 inline bool StyleDisplay::IsInlineInside() const {
   1191  return IsInlineFlow() || IsRuby();
   1192 }
   1193 
   1194 inline bool StyleDisplay::IsInlineOutside() const {
   1195  return Outside() == StyleDisplayOutside::Inline || IsInternalRuby();
   1196 }
   1197 
   1198 inline float StyleZoom::Zoom(float aValue) const {
   1199  if (*this == ONE) {
   1200    return aValue;
   1201  }
   1202  return ToFloat() * aValue;
   1203 }
   1204 
   1205 inline float StyleZoom::Unzoom(float aValue) const {
   1206  if (*this == ONE) {
   1207    return aValue;
   1208  }
   1209  return aValue / ToFloat();
   1210 }
   1211 
   1212 inline nscoord StyleZoom::ZoomCoord(nscoord aValue) const {
   1213  if (*this == ONE) {
   1214    return aValue;
   1215  }
   1216  return NSToCoordRoundWithClamp(Zoom(float(aValue)));
   1217 }
   1218 
   1219 inline nscoord StyleZoom::UnzoomCoord(nscoord aValue) const {
   1220  if (*this == ONE) {
   1221    return aValue;
   1222  }
   1223  return NSToCoordRoundWithClamp(Unzoom(float(aValue)));
   1224 }
   1225 
   1226 inline nsSize StyleZoom::Zoom(const nsSize& aValue) const {
   1227  if (*this == ONE) {
   1228    return aValue;
   1229  }
   1230  return nsSize(ZoomCoord(aValue.Width()), ZoomCoord(aValue.Height()));
   1231 }
   1232 
   1233 inline nsSize StyleZoom::Unzoom(const nsSize& aValue) const {
   1234  if (*this == ONE) {
   1235    return aValue;
   1236  }
   1237  return nsSize(UnzoomCoord(aValue.Width()), UnzoomCoord(aValue.Height()));
   1238 }
   1239 
   1240 inline nsPoint StyleZoom::Zoom(const nsPoint& aValue) const {
   1241  if (*this == ONE) {
   1242    return aValue;
   1243  }
   1244  return nsPoint(ZoomCoord(aValue.X()), ZoomCoord(aValue.Y()));
   1245 }
   1246 
   1247 inline nsPoint StyleZoom::Unzoom(const nsPoint& aValue) const {
   1248  if (*this == ONE) {
   1249    return aValue;
   1250  }
   1251  return nsPoint(UnzoomCoord(aValue.X()), UnzoomCoord(aValue.Y()));
   1252 }
   1253 
   1254 inline nsRect StyleZoom::Zoom(const nsRect& aValue) const {
   1255  if (*this == ONE) {
   1256    return aValue;
   1257  }
   1258  return nsRect(ZoomCoord(aValue.X()), ZoomCoord(aValue.Y()),
   1259                ZoomCoord(aValue.Width()), ZoomCoord(aValue.Height()));
   1260 }
   1261 
   1262 inline nsRect StyleZoom::Unzoom(const nsRect& aValue) const {
   1263  if (*this == ONE) {
   1264    return aValue;
   1265  }
   1266  return nsRect(UnzoomCoord(aValue.X()), UnzoomCoord(aValue.Y()),
   1267                UnzoomCoord(aValue.Width()), UnzoomCoord(aValue.Height()));
   1268 }
   1269 
   1270 template <>
   1271 inline gfx::Point StyleCoordinatePair<StyleCSSFloat>::ToGfxPoint(
   1272    const CSSSize* aBasis) const {
   1273  return gfx::Point(x, y);
   1274 }
   1275 
   1276 template <>
   1277 inline gfx::Point StyleCoordinatePair<LengthPercentage>::ToGfxPoint(
   1278    const CSSSize* aBasis) const {
   1279  MOZ_ASSERT(aBasis);
   1280  return gfx::Point(x.ResolveToCSSPixels(aBasis->Width()),
   1281                    y.ResolveToCSSPixels(aBasis->Height()));
   1282 }
   1283 
   1284 template <>
   1285 inline gfx::Point StyleShapePosition<StyleCSSFloat>::ToGfxPoint(
   1286    const CSSSize* aBasis) const {
   1287  return gfx::Point(horizontal, vertical);
   1288 }
   1289 
   1290 template <>
   1291 inline gfx::Point StyleShapePosition<LengthPercentage>::ToGfxPoint(
   1292    const CSSSize* aBasis) const {
   1293  MOZ_ASSERT(aBasis);
   1294  return gfx::Point(horizontal.ResolveToCSSPixels(aBasis->Width()),
   1295                    vertical.ResolveToCSSPixels(aBasis->Height()));
   1296 }
   1297 
   1298 template <>
   1299 inline gfx::Point
   1300 StyleCommandEndPoint<StyleShapePosition<StyleCSSFloat>,
   1301                     StyleCSSFloat>::ToGfxPoint(const CSSSize* aBasis) const {
   1302  if (IsToPosition()) {
   1303    auto& pos = AsToPosition();
   1304    return pos.ToGfxPoint();
   1305  } else {
   1306    auto& coord = AsByCoordinate();
   1307    return coord.ToGfxPoint();
   1308  }
   1309 }
   1310 
   1311 template <>
   1312 inline gfx::Point StyleCommandEndPoint<
   1313    StyleShapePosition<LengthPercentage>,
   1314    LengthPercentage>::ToGfxPoint(const CSSSize* aBasis) const {
   1315  MOZ_ASSERT(aBasis);
   1316  if (IsToPosition()) {
   1317    auto& pos = AsToPosition();
   1318    return pos.ToGfxPoint(aBasis);
   1319  } else {
   1320    auto& coord = AsByCoordinate();
   1321    return coord.ToGfxPoint(aBasis);
   1322  }
   1323 }
   1324 
   1325 template <>
   1326 inline gfx::Coord StyleAxisEndPoint<StyleCSSFloat>::ToGfxCoord(
   1327    const StyleCSSFloat* aBasis) const {
   1328  if (IsToPosition()) {
   1329    const auto pos = AsToPosition();
   1330    MOZ_ASSERT(pos.IsLengthPercent());
   1331    return gfx::Coord(pos.AsLengthPercent());
   1332  }
   1333  return gfx::Coord(AsByCoordinate());
   1334 }
   1335 
   1336 template <>
   1337 inline gfx::Coord StyleAxisEndPoint<LengthPercentage>::ToGfxCoord(
   1338    const StyleCSSFloat* aBasis) const {
   1339  MOZ_ASSERT(aBasis);
   1340  if (IsToPosition()) {
   1341    const auto pos = AsToPosition();
   1342    MOZ_ASSERT(pos.IsLengthPercent());
   1343    return gfx::Coord(pos.AsLengthPercent().ResolveToCSSPixels(*aBasis));
   1344  }
   1345  return gfx::Coord(AsByCoordinate().ResolveToCSSPixels(*aBasis));
   1346 }
   1347 
   1348 template <>
   1349 inline gfx::Point
   1350 StyleControlPoint<StyleShapePosition<StyleCSSFloat>, StyleCSSFloat>::ToGfxPoint(
   1351    const gfx::Point aStatePos, const gfx::Point aEndPoint,
   1352    const CSSSize* aBasis) const {
   1353  if (IsAbsolute()) {
   1354    auto& pos = AsAbsolute();
   1355    return pos.ToGfxPoint();
   1356  }
   1357 
   1358  // Else
   1359  auto& point = AsRelative();
   1360  auto cp = point.coord.ToGfxPoint();
   1361  if (point.reference == StyleControlReference::Start) {
   1362    return cp + aStatePos;
   1363  } else if (point.reference == StyleControlReference::End) {
   1364    return cp + aEndPoint;
   1365  } else {
   1366    return cp;
   1367  }
   1368 }
   1369 
   1370 template <>
   1371 inline gfx::Point
   1372 StyleControlPoint<StyleShapePosition<LengthPercentage>,
   1373                  LengthPercentage>::ToGfxPoint(const gfx::Point aStatePos,
   1374                                                const gfx::Point aEndPoint,
   1375                                                const CSSSize* aBasis) const {
   1376  MOZ_ASSERT(aBasis);
   1377  if (IsAbsolute()) {
   1378    auto& pos = AsAbsolute();
   1379    return pos.ToGfxPoint(aBasis);
   1380  }
   1381 
   1382  // Else
   1383  auto& point = AsRelative();
   1384  auto cp = point.coord.ToGfxPoint(aBasis);
   1385  if (point.reference == StyleControlReference::Start) {
   1386    return cp + aStatePos;
   1387  } else if (point.reference == StyleControlReference::End) {
   1388    return cp + aEndPoint;
   1389  } else {
   1390    return cp;
   1391  }
   1392 }
   1393 
   1394 template <>
   1395 inline gfx::Point StyleArcRadii<StyleCSSFloat>::ToGfxPoint(
   1396    const CSSSize* aBasis) const {
   1397  return ry.IsSome() ? gfx::Point(rx, ry.AsSome()) : gfx::Point(rx, rx);
   1398 }
   1399 
   1400 template <>
   1401 inline gfx::Point StyleArcRadii<LengthPercentage>::ToGfxPoint(
   1402    const CSSSize* aBasis) const {
   1403  MOZ_ASSERT(aBasis);
   1404  if (ry.IsSome()) {
   1405    return gfx::Point(rx.ResolveToCSSPixels(aBasis->Width()),
   1406                      ry.AsSome().ResolveToCSSPixels(aBasis->Height()));
   1407  }
   1408 
   1409  // Else percentages are resolved against the direction-agnostic size
   1410  // of the reference box for both radiuses.
   1411  // https://drafts.csswg.org/css-shapes-1/#typedef-shape-arc-command
   1412  const auto directionAgnostic = SVGContentUtils::ComputeNormalizedHypotenuse(
   1413      aBasis->Width(), aBasis->Height());
   1414  const auto radius = rx.ResolveToCSSPixels(directionAgnostic);
   1415  return gfx::Point(radius, radius);
   1416 }
   1417 
   1418 inline StylePhysicalSide ToStylePhysicalSide(mozilla::Side aSide) {
   1419  // TODO(dshin): Should look into merging these two types...
   1420  static_assert(static_cast<uint8_t>(mozilla::Side::eSideLeft) ==
   1421                    static_cast<uint8_t>(StylePhysicalSide::Left),
   1422                "Left side doesn't match");
   1423  static_assert(static_cast<uint8_t>(mozilla::Side::eSideRight) ==
   1424                    static_cast<uint8_t>(StylePhysicalSide::Right),
   1425                "Left side doesn't match");
   1426  static_assert(static_cast<uint8_t>(mozilla::Side::eSideTop) ==
   1427                    static_cast<uint8_t>(StylePhysicalSide::Top),
   1428                "Left side doesn't match");
   1429  static_assert(static_cast<uint8_t>(mozilla::Side::eSideBottom) ==
   1430                    static_cast<uint8_t>(StylePhysicalSide::Bottom),
   1431                "Left side doesn't match");
   1432  return static_cast<StylePhysicalSide>(static_cast<uint8_t>(aSide));
   1433 }
   1434 
   1435 inline StylePhysicalAxis ToStylePhysicalAxis(StylePhysicalSide aSide) {
   1436  return aSide == StylePhysicalSide::Top || aSide == StylePhysicalSide::Bottom
   1437             ? StylePhysicalAxis::Vertical
   1438             : StylePhysicalAxis::Horizontal;
   1439 }
   1440 
   1441 inline StylePhysicalAxis ToStylePhysicalAxis(mozilla::Side aSide) {
   1442  return ToStylePhysicalAxis(ToStylePhysicalSide(aSide));
   1443 }
   1444 
   1445 inline mozilla::Side ToSide(StylePhysicalSide aSide) {
   1446  return static_cast<mozilla::Side>(static_cast<uint8_t>(aSide));
   1447 }
   1448 
   1449 #define DEFINE_LENGTH_PERCENTAGE_CTOR(ty_)                               \
   1450  template <>                                                            \
   1451  inline Style##ty_::StyleGeneric##ty_(const StyleLengthPercentage& aLP) \
   1452      : tag{Tag::LengthPercentage} {                                     \
   1453    ::new (&length_percentage._0)(StyleLengthPercentage)(aLP);           \
   1454  }
   1455 
   1456 DEFINE_LENGTH_PERCENTAGE_CTOR(Inset)
   1457 DEFINE_LENGTH_PERCENTAGE_CTOR(Margin)
   1458 DEFINE_LENGTH_PERCENTAGE_CTOR(Size)
   1459 DEFINE_LENGTH_PERCENTAGE_CTOR(MaxSize)
   1460 
   1461 inline bool StylePositionArea::IsNone() const {
   1462  return first == StylePositionAreaKeyword::None;
   1463 }
   1464 
   1465 }  // namespace mozilla
   1466 
   1467 #endif