tor-browser

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

GeckoBindings.cpp (75266B)


      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 /* FFI functions for Servo to call into Gecko */
      8 
      9 #include "mozilla/GeckoBindings.h"
     10 
     11 #include "AnchorPositioningUtils.h"
     12 #include "ChildIterator.h"
     13 #include "ErrorReporter.h"
     14 #include "gfxFontFeatures.h"
     15 #include "gfxMathTable.h"
     16 #include "gfxTextRun.h"
     17 #include "imgLoader.h"
     18 #include "mozilla/AttributeStyles.h"
     19 #include "mozilla/ClearOnShutdown.h"
     20 #include "mozilla/DeclarationBlock.h"
     21 #include "mozilla/EffectCompositor.h"
     22 #include "mozilla/EffectSet.h"
     23 #include "mozilla/FontPropertyTypes.h"
     24 #include "mozilla/Hal.h"
     25 #include "mozilla/Keyframe.h"
     26 #include "mozilla/LookAndFeel.h"
     27 #include "mozilla/Mutex.h"
     28 #include "mozilla/Preferences.h"
     29 #include "mozilla/RWLock.h"
     30 #include "mozilla/RestyleManager.h"
     31 #include "mozilla/ServoBindings.h"
     32 #include "mozilla/ServoElementSnapshot.h"
     33 #include "mozilla/ServoTraversalStatistics.h"
     34 #include "mozilla/ShadowParts.h"
     35 #include "mozilla/SizeOfState.h"
     36 #include "mozilla/StaticPrefs_browser.h"
     37 #include "mozilla/StaticPrefs_layout.h"
     38 #include "mozilla/StaticPresData.h"
     39 #include "mozilla/StaticPtr.h"
     40 #include "mozilla/StyleAnimationValue.h"
     41 #include "mozilla/TimelineManager.h"
     42 #include "mozilla/URLExtraData.h"
     43 #include "mozilla/css/ImageLoader.h"
     44 #include "mozilla/dom/CSSMozDocumentRule.h"
     45 #include "mozilla/dom/DocumentInlines.h"
     46 #include "mozilla/dom/Element.h"
     47 #include "mozilla/dom/ElementInlines.h"
     48 #include "mozilla/dom/HTMLBodyElement.h"
     49 #include "mozilla/dom/HTMLImageElement.h"
     50 #include "mozilla/dom/HTMLSelectElement.h"
     51 #include "mozilla/dom/HTMLSlotElement.h"
     52 #include "mozilla/dom/HTMLTableCellElement.h"
     53 #include "mozilla/dom/MediaList.h"
     54 #include "mozilla/dom/ReferrerInfo.h"
     55 #include "mozilla/dom/SVGElement.h"
     56 #include "mozilla/dom/ViewTransition.h"
     57 #include "mozilla/dom/WorkerCommon.h"
     58 #include "nsAnimationManager.h"
     59 #include "nsAttrValueInlines.h"
     60 #include "nsCSSFrameConstructor.h"
     61 #include "nsCSSProps.h"
     62 #include "nsCSSPseudoElements.h"
     63 #include "nsContentUtils.h"
     64 #include "nsDOMTokenList.h"
     65 #include "nsDeviceContext.h"
     66 #include "nsFontMetrics.h"
     67 #include "nsIContentInlines.h"
     68 #include "nsIFrame.h"
     69 #include "nsIFrameInlines.h"
     70 #include "nsILoadContext.h"
     71 #include "nsINode.h"
     72 #include "nsIURI.h"
     73 #include "nsLayoutUtils.h"
     74 #include "nsNameSpaceManager.h"
     75 #include "nsNetUtil.h"
     76 #include "nsProxyRelease.h"
     77 #include "nsString.h"
     78 #include "nsStyleStruct.h"
     79 #include "nsStyleUtil.h"
     80 #include "nsTArray.h"
     81 #include "nsTransitionManager.h"
     82 #include "nsWindowSizes.h"
     83 
     84 #if defined(MOZ_MEMORY)
     85 #  include "mozmemory.h"
     86 #endif
     87 
     88 using namespace mozilla;
     89 using namespace mozilla::css;
     90 using namespace mozilla::dom;
     91 
     92 // Definitions of the global traversal stats.
     93 bool ServoTraversalStatistics::sActive = false;
     94 ServoTraversalStatistics ServoTraversalStatistics::sSingleton;
     95 
     96 static StaticAutoPtr<RWLock> sServoFFILock;
     97 
     98 static const LangGroupFontPrefs* ThreadSafeGetLangGroupFontPrefs(
     99    const Document& aDocument, nsAtom* aLanguage) {
    100  bool needsCache = false;
    101  {
    102    AutoReadLock guard(*sServoFFILock);
    103    if (auto* prefs = aDocument.GetFontPrefsForLang(aLanguage, &needsCache)) {
    104      return prefs;
    105    }
    106  }
    107  MOZ_ASSERT(needsCache);
    108  AutoWriteLock guard(*sServoFFILock);
    109  return aDocument.GetFontPrefsForLang(aLanguage);
    110 }
    111 
    112 static const nsFont& ThreadSafeGetDefaultVariableFont(const Document& aDocument,
    113                                                      nsAtom* aLanguage) {
    114  return ThreadSafeGetLangGroupFontPrefs(aDocument, aLanguage)
    115      ->mDefaultVariableFont;
    116 }
    117 
    118 /*
    119 * Does this child count as significant for selector matching?
    120 *
    121 * See nsStyleUtil::IsSignificantChild for details.
    122 */
    123 bool Gecko_IsSignificantChild(const nsINode* aNode,
    124                              bool aWhitespaceIsSignificant) {
    125  return nsStyleUtil::ThreadSafeIsSignificantChild(aNode->AsContent(),
    126                                                   aWhitespaceIsSignificant);
    127 }
    128 
    129 const nsINode* Gecko_GetLastChild(const nsINode* aNode) {
    130  return aNode->GetLastChild();
    131 }
    132 
    133 const nsINode* Gecko_GetFlattenedTreeParentNode(const nsINode* aNode) {
    134  return aNode->GetFlattenedTreeParentNodeForStyle();
    135 }
    136 
    137 void Gecko_GetAnonymousContentForElement(const Element* aElement,
    138                                         nsTArray<nsIContent*>* aArray) {
    139  MOZ_ASSERT(aElement->MayHaveAnonymousChildren());
    140  if (aElement->HasProperties()) {
    141    if (auto* backdrop = nsLayoutUtils::GetBackdropPseudo(aElement)) {
    142      aArray->AppendElement(backdrop);
    143    }
    144    if (auto* marker = nsLayoutUtils::GetMarkerPseudo(aElement)) {
    145      aArray->AppendElement(marker);
    146    }
    147    if (auto* before = nsLayoutUtils::GetBeforePseudo(aElement)) {
    148      aArray->AppendElement(before);
    149    }
    150    if (auto* after = nsLayoutUtils::GetAfterPseudo(aElement)) {
    151      aArray->AppendElement(after);
    152    }
    153  }
    154  nsContentUtils::AppendNativeAnonymousChildren(
    155      aElement, *aArray, nsIContent::eSkipDocumentLevelNativeAnonymousContent);
    156 }
    157 
    158 void Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* aAnonContent) {
    159  MOZ_ASSERT(aAnonContent);
    160  delete aAnonContent;
    161 }
    162 
    163 RustSpan<const nsINode* const> Gecko_GetAssignedNodes(const Element* aElement) {
    164  MOZ_ASSERT(HTMLSlotElement::FromNode(aElement));
    165  Span<const RefPtr<nsINode>> span =
    166      static_cast<const HTMLSlotElement*>(aElement)->AssignedNodes();
    167  return {reinterpret_cast<const nsINode* const*>(span.Elements()),
    168          span.Length()};
    169 }
    170 
    171 void Gecko_GetQueryContainerSize(const Element* aElement, nscoord* aOutWidth,
    172                                 nscoord* aOutHeight) {
    173  MOZ_ASSERT(aElement);
    174  const nsIFrame* frame = aElement->GetPrimaryFrame();
    175  if (!frame) {
    176    return;
    177  }
    178  const auto containAxes = frame->GetContainSizeAxes();
    179  if (!containAxes.IsAny()) {
    180    return;
    181  }
    182  nsSize size = frame->GetContentRectRelativeToSelf().Size();
    183  bool isVertical = frame->GetWritingMode().IsVertical();
    184  if (isVertical ? containAxes.mBContained : containAxes.mIContained) {
    185    *aOutWidth = size.width;
    186  }
    187  if (isVertical ? containAxes.mIContained : containAxes.mBContained) {
    188    *aOutHeight = size.height;
    189  }
    190 }
    191 
    192 void Gecko_ComputedStyle_Init(ComputedStyle* aStyle,
    193                              const ServoComputedData* aValues,
    194                              PseudoStyleType aPseudoType) {
    195  new (KnownNotNull, aStyle)
    196      ComputedStyle(aPseudoType, ServoComputedDataForgotten(aValues));
    197 }
    198 
    199 ServoComputedData::ServoComputedData(const ServoComputedDataForgotten aValue) {
    200  memcpy((void*)this, aValue.mPtr, sizeof(*this));
    201 }
    202 
    203 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleStructsMallocEnclosingSizeOf)
    204 
    205 void ServoComputedData::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const {
    206  // Note: GetStyleFoo() returns a pointer to an nsStyleFoo that sits within a
    207  // servo_arc::Arc, i.e. it is preceded by a word-sized refcount. So we need
    208  // to measure it with a function that can handle an interior pointer. We use
    209  // ServoStyleStructsEnclosingMallocSizeOf to clearly identify in DMD's
    210  // output the memory measured here.
    211 #define MEASURE_STRUCT(name_)                                     \
    212  static_assert(alignof(nsStyle##name_) <= sizeof(size_t),        \
    213                "alignment will break AddSizeOfExcludingThis()"); \
    214  const void* p##name_ = Style##name_();                          \
    215  if (!aSizes.mState.HaveSeenPtr(p##name_)) {                     \
    216    aSizes.mStyleSizes.NS_STYLE_SIZES_FIELD(name_) +=             \
    217        ServoStyleStructsMallocEnclosingSizeOf(p##name_);         \
    218  }
    219  FOR_EACH_STYLE_STRUCT(MEASURE_STRUCT, MEASURE_STRUCT)
    220 #undef MEASURE_STRUCT
    221 
    222  if (visited_style && !aSizes.mState.HaveSeenPtr(visited_style)) {
    223    visited_style->AddSizeOfIncludingThis(aSizes,
    224                                          &aSizes.mLayoutComputedValuesVisited);
    225  }
    226 
    227  // Measurement of the following members may be added later if DMD finds it is
    228  // worthwhile:
    229  // - custom_properties
    230  // - writing_mode
    231  // - rules
    232  // - font_computation_data
    233 }
    234 
    235 void Gecko_ComputedStyle_Destroy(ComputedStyle* aStyle) {
    236  aStyle->~ComputedStyle();
    237 }
    238 
    239 void Gecko_ConstructStyleChildrenIterator(const Element* aElement,
    240                                          StyleChildrenIterator* aIterator) {
    241  MOZ_ASSERT(aElement);
    242  MOZ_ASSERT(aIterator);
    243  new (aIterator) StyleChildrenIterator(aElement);
    244 }
    245 
    246 void Gecko_DestroyStyleChildrenIterator(StyleChildrenIterator* aIterator) {
    247  MOZ_ASSERT(aIterator);
    248 
    249  aIterator->~StyleChildrenIterator();
    250 }
    251 
    252 const nsINode* Gecko_GetNextStyleChild(StyleChildrenIterator* aIterator) {
    253  MOZ_ASSERT(aIterator);
    254  return aIterator->GetNextChild();
    255 }
    256 
    257 bool Gecko_VisitedStylesEnabled(const Document* aDoc) {
    258  MOZ_ASSERT(aDoc);
    259  MOZ_ASSERT(NS_IsMainThread());
    260 
    261  if (!StaticPrefs::layout_css_visited_links_enabled()) {
    262    return false;
    263  }
    264 
    265  if (aDoc->IsBeingUsedAsImage()) {
    266    return false;
    267  }
    268 
    269  nsILoadContext* loadContext = aDoc->GetLoadContext();
    270  if (loadContext && loadContext->UsePrivateBrowsing()) {
    271    return false;
    272  }
    273 
    274  return true;
    275 }
    276 
    277 ElementState::InternalType Gecko_ElementState(const Element* aElement) {
    278  return aElement->StyleState().GetInternalValue();
    279 }
    280 
    281 bool Gecko_IsRootElement(const Element* aElement) {
    282  return aElement->OwnerDoc()->GetRootElement() == aElement;
    283 }
    284 
    285 void Gecko_NoteDirtyElement(const Element* aElement) {
    286  MOZ_ASSERT(NS_IsMainThread());
    287  const_cast<Element*>(aElement)->NoteDirtyForServo();
    288 }
    289 
    290 void Gecko_NoteDirtySubtreeForInvalidation(const Element* aElement) {
    291  MOZ_ASSERT(NS_IsMainThread());
    292  const_cast<Element*>(aElement)->NoteDirtySubtreeForServo();
    293 }
    294 
    295 void Gecko_NoteAnimationOnlyDirtyElement(const Element* aElement) {
    296  MOZ_ASSERT(NS_IsMainThread());
    297  const_cast<Element*>(aElement)->NoteAnimationOnlyDirtyForServo();
    298 }
    299 
    300 bool Gecko_AnimationNameMayBeReferencedFromStyle(
    301    const nsPresContext* aPresContext, nsAtom* aName) {
    302  MOZ_ASSERT(aPresContext);
    303  return aPresContext->AnimationManager()->AnimationMayBeReferenced(aName);
    304 }
    305 
    306 void Gecko_InvalidatePositionTry(const Element* aElement) {
    307  auto* f = aElement->GetPrimaryFrame();
    308  if (!f || !f->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
    309    return;
    310  }
    311  f->RemoveProperty(nsIFrame::LastSuccessfulPositionFallback());
    312  f->PresShell()->MarkPositionedFrameForReflow(f);
    313 }
    314 
    315 float Gecko_GetScrollbarInlineSize(const nsPresContext* aPc) {
    316  MOZ_ASSERT(aPc);
    317  auto overlay = aPc->UseOverlayScrollbars() ? nsITheme::Overlay::Yes
    318                                             : nsITheme::Overlay::No;
    319  LayoutDeviceIntCoord size =
    320      aPc->Theme()->GetScrollbarSize(aPc, StyleScrollbarWidth::Auto, overlay);
    321  return aPc->DevPixelsToFloatCSSPixels(size);
    322 }
    323 
    324 PseudoStyleType Gecko_GetImplementedPseudoType(const Element* aElement) {
    325  return aElement->GetPseudoElementType();
    326 }
    327 
    328 nsAtom* Gecko_GetImplementedPseudoIdentifier(const Element* aElement) {
    329  if (!PseudoStyle::IsNamedViewTransitionPseudoElement(
    330          aElement->GetPseudoElementType())) {
    331    return nullptr;
    332  }
    333 
    334  if (!aElement->HasName()) {
    335    return nullptr;
    336  }
    337 
    338  return aElement->GetParsedAttr(nsGkAtoms::name)->GetAtomValue();
    339 }
    340 
    341 uint32_t Gecko_CalcStyleDifference(const ComputedStyle* aOldStyle,
    342                                   const ComputedStyle* aNewStyle,
    343                                   bool* aAnyStyleStructChanged,
    344                                   bool* aOnlyResetStructsChanged) {
    345  MOZ_ASSERT(aOldStyle);
    346  MOZ_ASSERT(aNewStyle);
    347 
    348  uint32_t equalStructs;
    349  nsChangeHint result =
    350      aOldStyle->CalcStyleDifference(*aNewStyle, &equalStructs);
    351 
    352  *aAnyStyleStructChanged =
    353      equalStructs != StyleStructConstants::kAllStructsMask;
    354 
    355  const auto kInheritedStructsMask =
    356      StyleStructConstants::kInheritedStructsMask;
    357  *aOnlyResetStructsChanged =
    358      (equalStructs & kInheritedStructsMask) == kInheritedStructsMask;
    359 
    360  return result;
    361 }
    362 
    363 nscoord Gecko_CalcLineHeight(const StyleLineHeight* aLh,
    364                             const nsPresContext* aPc, bool aVertical,
    365                             const nsStyleFont* aAgainstFont,
    366                             const mozilla::dom::Element* aElement) {
    367  // Normal line-height depends on font metrics.
    368  AutoWriteLock guard(*sServoFFILock);
    369  return ReflowInput::CalcLineHeight(*aLh, *aAgainstFont,
    370                                     const_cast<nsPresContext*>(aPc), aVertical,
    371                                     aElement, NS_UNCONSTRAINEDSIZE, 1.0f);
    372 }
    373 
    374 const ServoElementSnapshot* Gecko_GetElementSnapshot(
    375    const ServoElementSnapshotTable* aTable, const Element* aElement) {
    376  MOZ_ASSERT(aTable);
    377  MOZ_ASSERT(aElement);
    378 
    379  return aTable->Get(const_cast<Element*>(aElement));
    380 }
    381 
    382 bool Gecko_HaveSeenPtr(SeenPtrs* aTable, const void* aPtr) {
    383  MOZ_ASSERT(NS_IsMainThread());
    384  MOZ_ASSERT(aTable);
    385  // Empty Rust allocations are indicated by small values up to the alignment
    386  // of the relevant type. We shouldn't see anything like that here.
    387  MOZ_ASSERT(uintptr_t(aPtr) > 16);
    388 
    389  return aTable->HaveSeenPtr(aPtr);
    390 }
    391 
    392 const StyleLockedDeclarationBlock* Gecko_GetStyleAttrDeclarationBlock(
    393    const Element* aElement) {
    394  DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
    395  if (!decl) {
    396    return nullptr;
    397  }
    398  return decl->Raw();
    399 }
    400 
    401 void Gecko_UnsetDirtyStyleAttr(const Element* aElement) {
    402  DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
    403  if (!decl) {
    404    return;
    405  }
    406  decl->UnsetDirty();
    407 }
    408 
    409 const StyleLockedDeclarationBlock*
    410 Gecko_GetHTMLPresentationAttrDeclarationBlock(const Element* aElement) {
    411  return aElement->GetMappedAttributeStyle();
    412 }
    413 
    414 const StyleLockedDeclarationBlock* Gecko_GetViewTransitionDynamicRule(
    415    const Element* aElement) {
    416  const auto* vt = aElement->OwnerDoc()->GetActiveViewTransition();
    417  if (!vt) {
    418    return nullptr;
    419  }
    420  return vt->GetDynamicRuleFor(*aElement);
    421 }
    422 
    423 const StyleLockedDeclarationBlock* Gecko_GetExtraContentStyleDeclarations(
    424    const Element* aElement) {
    425  if (const auto* cell = HTMLTableCellElement::FromNode(aElement)) {
    426    return cell->GetMappedAttributesInheritedFromTable();
    427  }
    428  if (const auto* img = HTMLImageElement::FromNode(aElement)) {
    429    return img->GetMappedAttributesFromSource();
    430  }
    431  return nullptr;
    432 }
    433 
    434 const StyleLockedDeclarationBlock* Gecko_GetUnvisitedLinkAttrDeclarationBlock(
    435    const Element* aElement) {
    436  AttributeStyles* attrStyles = aElement->OwnerDoc()->GetAttributeStyles();
    437  if (!attrStyles) {
    438    return nullptr;
    439  }
    440 
    441  return attrStyles->GetServoUnvisitedLinkDecl();
    442 }
    443 
    444 StyleSheet* Gecko_StyleSheet_Clone(const StyleSheet* aSheet) {
    445  MOZ_ASSERT(aSheet);
    446  MOZ_ASSERT(aSheet->GetParentSheet(), "Should only be used for @import");
    447  // NOTE(emilio): We don't pass either the parent pointer of the stylesheet,
    448  // nor fix up the child list (yet). This is fixed up in the StylesheetInner
    449  // constructor.
    450  RefPtr<StyleSheet> newSheet = aSheet->Clone(nullptr, nullptr);
    451  return static_cast<StyleSheet*>(newSheet.forget().take());
    452 }
    453 
    454 void Gecko_StyleSheet_AddRef(const StyleSheet* aSheet) {
    455  MOZ_ASSERT(NS_IsMainThread());
    456  const_cast<StyleSheet*>(aSheet)->AddRef();
    457 }
    458 
    459 void Gecko_StyleSheet_Release(const StyleSheet* aSheet) {
    460  MOZ_ASSERT(NS_IsMainThread());
    461  const_cast<StyleSheet*>(aSheet)->Release();
    462 }
    463 
    464 GeckoImplicitScopeRoot Gecko_StyleSheet_ImplicitScopeRoot(
    465    const mozilla::StyleSheet* aSheet) {
    466  if (aSheet->IsConstructed()) {
    467    return GeckoImplicitScopeRoot{
    468        .mHost = nullptr, .mRoot = nullptr, .mConstructed = true};
    469  }
    470  // https://drafts.csswg.org/css-cascade-6/#scope-limits
    471  // "If no <scope-start> is specified, the scoping root is the parent element
    472  // of the owner node of the stylesheet where the @scope rule is defined."
    473  const auto* node = aSheet->GetOwnerNodeOfOutermostSheet();
    474  if (!node) {
    475    return GeckoImplicitScopeRoot{
    476        .mHost = nullptr, .mRoot = nullptr, .mConstructed = false};
    477  }
    478  const auto* host = node->GetContainingShadowHost();
    479 
    480  if (auto* aElement = node->GetParentElement()) {
    481    return GeckoImplicitScopeRoot{
    482        .mHost = host, .mRoot = aElement, .mConstructed = false};
    483  }
    484  // "[...] If no such element exists, then the scoping root is the root of the
    485  // containing node tree." This really should only happen for stylesheets
    486  // defined at the edge of the shadow root.
    487  return GeckoImplicitScopeRoot{
    488      .mHost = host, .mRoot = host, .mConstructed = false};
    489 }
    490 
    491 const StyleLockedDeclarationBlock* Gecko_GetVisitedLinkAttrDeclarationBlock(
    492    const Element* aElement) {
    493  AttributeStyles* attrStyles = aElement->OwnerDoc()->GetAttributeStyles();
    494  if (!attrStyles) {
    495    return nullptr;
    496  }
    497  return attrStyles->GetServoVisitedLinkDecl();
    498 }
    499 
    500 const StyleLockedDeclarationBlock* Gecko_GetActiveLinkAttrDeclarationBlock(
    501    const Element* aElement) {
    502  AttributeStyles* attrStyles = aElement->OwnerDoc()->GetAttributeStyles();
    503  if (!attrStyles) {
    504    return nullptr;
    505  }
    506  return attrStyles->GetServoActiveLinkDecl();
    507 }
    508 
    509 bool Gecko_GetAnimationRule(const Element* aElement,
    510                            EffectCompositor::CascadeLevel aCascadeLevel,
    511                            StyleAnimationValueMap* aAnimationValues) {
    512  MOZ_ASSERT(aElement);
    513 
    514  Document* doc = aElement->GetComposedDoc();
    515  if (!doc) {
    516    return false;
    517  }
    518  nsPresContext* presContext = doc->GetPresContext();
    519  if (!presContext) {
    520    return false;
    521  }
    522 
    523  const auto [element, pseudoRequest] =
    524      AnimationUtils::GetElementPseudoPair(aElement);
    525  return presContext->EffectCompositor()->GetServoAnimationRule(
    526      element, pseudoRequest, aCascadeLevel, aAnimationValues);
    527 }
    528 
    529 bool Gecko_StyleAnimationsEquals(const nsStyleAutoArray<StyleAnimation>* aA,
    530                                 const nsStyleAutoArray<StyleAnimation>* aB) {
    531  return *aA == *aB;
    532 }
    533 
    534 bool Gecko_StyleScrollTimelinesEquals(
    535    const nsStyleAutoArray<StyleScrollTimeline>* aA,
    536    const nsStyleAutoArray<StyleScrollTimeline>* aB) {
    537  return *aA == *aB;
    538 }
    539 
    540 bool Gecko_StyleViewTimelinesEquals(
    541    const nsStyleAutoArray<StyleViewTimeline>* aA,
    542    const nsStyleAutoArray<StyleViewTimeline>* aB) {
    543  return *aA == *aB;
    544 }
    545 
    546 void Gecko_UpdateAnimations(const Element* aElement,
    547                            const ComputedStyle* aOldComputedData,
    548                            const ComputedStyle* aComputedData,
    549                            UpdateAnimationsTasks aTasks) {
    550  MOZ_ASSERT(NS_IsMainThread());
    551  MOZ_ASSERT(aElement);
    552 
    553  if (!aElement->IsInComposedDoc()) {
    554    return;
    555  }
    556 
    557  nsPresContext* presContext = nsContentUtils::GetContextForContent(aElement);
    558  if (!presContext || !presContext->IsDynamic()) {
    559    return;
    560  }
    561 
    562  nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
    563 
    564  const auto [element, pseudoRequest] =
    565      AnimationUtils::GetElementPseudoPair(aElement);
    566 
    567  // Handle scroll/view timelines first because CSS animations may refer to the
    568  // timeline defined by itself.
    569  if (aTasks & UpdateAnimationsTasks::ScrollTimelines) {
    570    presContext->TimelineManager()->UpdateTimelines(
    571        const_cast<Element*>(element), pseudoRequest, aComputedData,
    572        TimelineManager::ProgressTimelineType::Scroll);
    573  }
    574 
    575  if (aTasks & UpdateAnimationsTasks::ViewTimelines) {
    576    presContext->TimelineManager()->UpdateTimelines(
    577        const_cast<Element*>(element), pseudoRequest, aComputedData,
    578        TimelineManager::ProgressTimelineType::View);
    579  }
    580 
    581  if (aTasks & UpdateAnimationsTasks::CSSAnimations) {
    582    presContext->AnimationManager()->UpdateAnimations(
    583        const_cast<Element*>(element), pseudoRequest, aComputedData);
    584  }
    585 
    586  // aComputedData might be nullptr if the target element is now in a
    587  // display:none subtree. We still call Gecko_UpdateAnimations in this case
    588  // because we need to stop CSS animations in the display:none subtree.
    589  // However, we don't need to update transitions since they are stopped by
    590  // RestyleManager::AnimationsWithDestroyedFrame so we just return early
    591  // here.
    592  if (!aComputedData) {
    593    return;
    594  }
    595 
    596  if (aTasks & UpdateAnimationsTasks::CSSTransitions) {
    597    MOZ_ASSERT(aOldComputedData);
    598    presContext->TransitionManager()->UpdateTransitions(
    599        const_cast<Element*>(element), pseudoRequest, *aOldComputedData,
    600        *aComputedData);
    601  }
    602 
    603  if (aTasks & UpdateAnimationsTasks::EffectProperties) {
    604    presContext->EffectCompositor()->UpdateEffectProperties(
    605        aComputedData, const_cast<Element*>(element), pseudoRequest);
    606  }
    607 
    608  if (aTasks & UpdateAnimationsTasks::CascadeResults) {
    609    EffectSet* effectSet = EffectSet::Get(element, pseudoRequest);
    610    // CSS animations/transitions might have been destroyed as part of the above
    611    // steps so before updating cascade results, we check if there are still any
    612    // animations to update.
    613    if (effectSet) {
    614      // We call UpdateCascadeResults directly (intead of
    615      // MaybeUpdateCascadeResults) since we know for sure that the cascade has
    616      // changed, but we were unable to call MarkCascadeUpdated when we noticed
    617      // it since we avoid mutating state as part of the Servo parallel
    618      // traversal.
    619      presContext->EffectCompositor()->UpdateCascadeResults(
    620          *effectSet, const_cast<Element*>(element), pseudoRequest);
    621    }
    622  }
    623 
    624  if (aTasks & UpdateAnimationsTasks::DisplayChangedFromNone) {
    625    presContext->EffectCompositor()->RequestRestyle(
    626        const_cast<Element*>(element), pseudoRequest,
    627        EffectCompositor::RestyleType::Standard,
    628        EffectCompositor::CascadeLevel::Animations);
    629  }
    630 }
    631 
    632 size_t Gecko_GetAnimationEffectCount(const Element* aElementOrPseudo) {
    633  const auto [element, pseudo] =
    634      AnimationUtils::GetElementPseudoPair(aElementOrPseudo);
    635 
    636  EffectSet* effectSet = EffectSet::Get(element, pseudo);
    637  return effectSet ? effectSet->Count() : 0;
    638 }
    639 
    640 bool Gecko_ElementHasAnimations(const Element* aElement) {
    641  const auto [element, pseudo] = AnimationUtils::GetElementPseudoPair(aElement);
    642  return !!EffectSet::Get(element, pseudo);
    643 }
    644 
    645 bool Gecko_ElementHasCSSAnimations(const Element* aElement) {
    646  const auto [element, pseudo] = AnimationUtils::GetElementPseudoPair(aElement);
    647  auto* collection =
    648      nsAnimationManager::CSSAnimationCollection::Get(element, pseudo);
    649  return collection && !collection->mAnimations.IsEmpty();
    650 }
    651 
    652 bool Gecko_ElementHasCSSTransitions(const Element* aElement) {
    653  const auto [element, pseudo] = AnimationUtils::GetElementPseudoPair(aElement);
    654  auto* collection =
    655      nsTransitionManager::CSSTransitionCollection::Get(element, pseudo);
    656  return collection && !collection->mAnimations.IsEmpty();
    657 }
    658 
    659 size_t Gecko_ElementTransitions_Length(const Element* aElement) {
    660  const auto [element, pseudo] = AnimationUtils::GetElementPseudoPair(aElement);
    661  auto* collection =
    662      nsTransitionManager::CSSTransitionCollection::Get(element, pseudo);
    663  return collection ? collection->mAnimations.Length() : 0;
    664 }
    665 
    666 static CSSTransition* GetCurrentTransitionAt(const Element* aElement,
    667                                             size_t aIndex) {
    668  const auto [element, pseudo] = AnimationUtils::GetElementPseudoPair(aElement);
    669  auto* collection =
    670      nsTransitionManager::CSSTransitionCollection ::Get(element, pseudo);
    671  if (!collection) {
    672    return nullptr;
    673  }
    674  return collection->mAnimations.SafeElementAt(aIndex);
    675 }
    676 
    677 NonCustomCSSPropertyId Gecko_ElementTransitions_PropertyAt(
    678    const Element* aElement, size_t aIndex) {
    679  CSSTransition* transition = GetCurrentTransitionAt(aElement, aIndex);
    680  return transition ? transition->TransitionProperty().mId
    681                    : NonCustomCSSPropertyId::eCSSProperty_UNKNOWN;
    682 }
    683 
    684 const StyleAnimationValue* Gecko_ElementTransitions_EndValueAt(
    685    const Element* aElement, size_t aIndex) {
    686  CSSTransition* transition = GetCurrentTransitionAt(aElement, aIndex);
    687  return transition ? transition->ToValue().mServo.get() : nullptr;
    688 }
    689 
    690 double Gecko_GetProgressFromComputedTiming(const ComputedTiming* aTiming) {
    691  return aTiming->mProgress.Value();
    692 }
    693 
    694 double Gecko_GetPositionInSegment(const AnimationPropertySegment* aSegment,
    695                                  double aProgress, bool aBeforeFlag) {
    696  MOZ_ASSERT(aSegment->mFromKey < aSegment->mToKey,
    697             "The segment from key should be less than to key");
    698 
    699  double positionInSegment = (aProgress - aSegment->mFromKey) /
    700                             // To avoid floating precision inaccuracies, make
    701                             // sure we calculate both the numerator and
    702                             // denominator using double precision.
    703                             (double(aSegment->mToKey) - aSegment->mFromKey);
    704 
    705  return StyleComputedTimingFunction::GetPortion(
    706      aSegment->mTimingFunction, positionInSegment, aBeforeFlag);
    707 }
    708 
    709 const StyleAnimationValue* Gecko_AnimationGetBaseStyle(
    710    const RawServoAnimationValueTable* aBaseStyles,
    711    const mozilla::CSSPropertyId* aProperty) {
    712  const auto* base = reinterpret_cast<const nsRefPtrHashtable<
    713      nsGenericHashKey<CSSPropertyId>, StyleAnimationValue>*>(aBaseStyles);
    714  return base->GetWeak(*aProperty);
    715 }
    716 
    717 void Gecko_FillAllImageLayers(nsStyleImageLayers* aLayers, uint32_t aMaxLen) {
    718  aLayers->FillAllLayers(aMaxLen);
    719 }
    720 
    721 bool Gecko_IsDocumentBody(const Element* aElement) {
    722  Document* doc = aElement->GetUncomposedDoc();
    723  return doc && doc->GetBodyElement() == aElement;
    724 }
    725 
    726 bool Gecko_IsDarkColorScheme(const Document* aDoc,
    727                             const StyleColorSchemeFlags* aStyle) {
    728  return LookAndFeel::ColorSchemeForStyle(*aDoc, *aStyle) == ColorScheme::Dark;
    729 }
    730 
    731 nscolor Gecko_ComputeSystemColor(StyleSystemColor aColor, const Document* aDoc,
    732                                 const StyleColorSchemeFlags* aStyle) {
    733  auto colorScheme = LookAndFeel::ColorSchemeForStyle(*aDoc, *aStyle);
    734  const auto& prefs = PreferenceSheet::PrefsFor(*aDoc);
    735  if (prefs.mMustUseLightSystemColors) {
    736    colorScheme = ColorScheme::Light;
    737  }
    738  const auto& colors = prefs.ColorsFor(colorScheme);
    739  switch (aColor) {
    740    case StyleSystemColor::Canvastext:
    741      return colors.mDefault;
    742    case StyleSystemColor::Canvas:
    743      return colors.mDefaultBackground;
    744    case StyleSystemColor::Linktext:
    745      return colors.mLink;
    746    case StyleSystemColor::Activetext:
    747      return colors.mActiveLink;
    748    case StyleSystemColor::Visitedtext:
    749      return colors.mVisitedLink;
    750    default:
    751      break;
    752  }
    753 
    754  auto useStandins = LookAndFeel::ShouldUseStandins(*aDoc, aColor);
    755  return LookAndFeel::Color(aColor, colorScheme, useStandins);
    756 }
    757 
    758 int32_t Gecko_GetLookAndFeelInt(int32_t aId) {
    759  auto intId = static_cast<LookAndFeel::IntID>(aId);
    760  return LookAndFeel::GetInt(intId);
    761 }
    762 
    763 float Gecko_GetLookAndFeelFloat(int32_t aId) {
    764  auto id = static_cast<LookAndFeel::FloatID>(aId);
    765  return LookAndFeel::GetFloat(id);
    766 }
    767 
    768 bool Gecko_MatchLang(const Element* aElement, nsAtom* aOverrideLang,
    769                     bool aHasOverrideLang, const char16_t* aValue) {
    770  MOZ_ASSERT(!(aOverrideLang && !aHasOverrideLang),
    771             "aHasOverrideLang should only be set when aOverrideLang is null");
    772  MOZ_ASSERT(aValue, "null lang parameter");
    773  if (!aValue || !*aValue) {
    774    return false;
    775  }
    776 
    777  // We have to determine the language of the current element.  Since
    778  // this is currently no property and since the language is inherited
    779  // from the parent we have to be prepared to look at all parent
    780  // nodes.  The language itself is encoded in the LANG attribute.
    781  if (auto* language = aHasOverrideLang ? aOverrideLang : aElement->GetLang()) {
    782    return nsStyleUtil::LangTagCompare(nsAtomCString(language),
    783                                       NS_ConvertUTF16toUTF8(aValue));
    784  }
    785 
    786  // Try to get the language from the HTTP header or if this
    787  // is missing as well from the preferences.
    788  // The content language can be a comma-separated list of
    789  // language codes.
    790  // FIXME: We're not really consistent in our treatment of comma-separated
    791  // content-language values.
    792  if (nsAtom* language = aElement->OwnerDoc()->GetContentLanguage()) {
    793    const NS_ConvertUTF16toUTF8 langString(aValue);
    794    nsAtomCString docLang(language);
    795    docLang.StripWhitespace();
    796    for (auto const& lang : docLang.Split(',')) {
    797      if (nsStyleUtil::LangTagCompare(lang, langString)) {
    798        return true;
    799      }
    800    }
    801  }
    802  return false;
    803 }
    804 
    805 bool Gecko_MatchViewTransitionClass(
    806    const mozilla::dom::Element* aElement,
    807    const nsTArray<StyleAtom>* aPtNameAndClassSelector) {
    808  MOZ_ASSERT(aElement && aPtNameAndClassSelector);
    809 
    810  const Document* doc = aElement->OwnerDoc();
    811  MOZ_ASSERT(doc);
    812  const ViewTransition* vt = doc->GetActiveViewTransition();
    813  MOZ_ASSERT(
    814      vt, "We should have an active view transition for this pseudo-element");
    815 
    816  nsAtom* name = Gecko_GetImplementedPseudoIdentifier(aElement);
    817  MOZ_ASSERT(name);
    818  return vt->MatchClassList(name, *aPtNameAndClassSelector);
    819 }
    820 
    821 static bool IsValidViewTransitionType(nsAtom* aName) {
    822  nsDependentAtomString str(aName);
    823  return !StringBeginsWith(str, u"-ua-"_ns,
    824                           nsASCIICaseInsensitiveStringComparator) &&
    825         !str.LowerCaseEqualsASCII("none");
    826 }
    827 
    828 bool Gecko_HasActiveViewTransitionTypes(
    829    const mozilla::dom::Document* aDoc,
    830    const nsTArray<StyleCustomIdent>* aNames) {
    831  MOZ_ASSERT(aDoc);
    832  MOZ_ASSERT(aNames);
    833  const ViewTransition* vt = aDoc->GetActiveViewTransition();
    834  if (!vt) {
    835    return false;
    836  }
    837  const auto& typeList = vt->GetTypeList();
    838  if (typeList.IsEmpty()) {
    839    return false;
    840  }
    841  for (const auto& name : *aNames) {
    842    if (typeList.Contains(name.AsAtom())) {
    843      // NOTE(emilio): This IsValidViewTransitionType() check is not in the spec
    844      // and is rather weird, but matches other browsers for now, see:
    845      // https://github.com/w3c/csswg-drafts/issues/13141
    846      if (IsValidViewTransitionType(name.AsAtom())) {
    847        return true;
    848      }
    849    }
    850  }
    851  return false;
    852 }
    853 
    854 nsAtom* Gecko_GetXMLLangValue(const Element* aElement) {
    855  const nsAttrValue* attr =
    856      aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
    857 
    858  if (!attr) {
    859    return nullptr;
    860  }
    861 
    862  MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
    863 
    864  RefPtr<nsAtom> atom = attr->GetAtomValue();
    865  return atom.forget().take();
    866 }
    867 
    868 const PreferenceSheet::Prefs* Gecko_GetPrefSheetPrefs(const Document* aDoc) {
    869  return &PreferenceSheet::PrefsFor(*aDoc);
    870 }
    871 
    872 bool Gecko_IsTableBorderNonzero(const Element* aElement) {
    873  if (!aElement->IsHTMLElement(nsGkAtoms::table)) {
    874    return false;
    875  }
    876  const nsAttrValue* val = aElement->GetParsedAttr(nsGkAtoms::border);
    877  return val &&
    878         (val->Type() != nsAttrValue::eInteger || val->GetIntegerValue() != 0);
    879 }
    880 
    881 bool Gecko_IsSelectListBox(const Element* aElement) {
    882  const auto* select = HTMLSelectElement::FromNode(aElement);
    883  return select && !select->IsCombobox();
    884 }
    885 
    886 bool Gecko_LookupAttrValue(const Element* aElement, const nsAtom& aName,
    887                           nsAString& aResult) {
    888  return aElement->GetAttr(&aName, aResult);
    889 }
    890 
    891 template <typename Implementor>
    892 static nsAtom* LangValue(Implementor* aElement) {
    893  // TODO(emilio): Deduplicate a bit with nsIContent::GetLang().
    894  const nsAttrValue* attr =
    895      aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
    896  if (!attr && aElement->SupportsLangAttr()) {
    897    attr = aElement->GetParsedAttr(nsGkAtoms::lang);
    898  }
    899 
    900  if (!attr) {
    901    return nullptr;
    902  }
    903 
    904  MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
    905  RefPtr<nsAtom> atom = attr->GetAtomValue();
    906  return atom.forget().take();
    907 }
    908 
    909 bool Gecko_AttrEquals(const nsAttrValue* aValue, const nsAtom* aStr,
    910                      bool aIgnoreCase) {
    911  return aValue->Equals(aStr, aIgnoreCase ? eIgnoreCase : eCaseMatters);
    912 }
    913 
    914 #define WITH_COMPARATOR(ignore_case_, c_, expr_)                    \
    915  auto c_ = (ignore_case_) ? nsASCIICaseInsensitiveStringComparator \
    916                           : nsTDefaultStringComparator<char16_t>;  \
    917  return expr_;
    918 
    919 bool Gecko_AttrDashEquals(const nsAttrValue* aValue, const nsAtom* aStr,
    920                          bool aIgnoreCase) {
    921  nsAutoString str;
    922  aValue->ToString(str);
    923  WITH_COMPARATOR(
    924      aIgnoreCase, c,
    925      nsStyleUtil::DashMatchCompare(str, nsDependentAtomString(aStr), c))
    926 }
    927 
    928 bool Gecko_AttrIncludes(const nsAttrValue* aValue, const nsAtom* aStr,
    929                        bool aIgnoreCase) {
    930  if (aStr == nsGkAtoms::_empty) {
    931    return false;
    932  }
    933  nsAutoString str;
    934  aValue->ToString(str);
    935  WITH_COMPARATOR(
    936      aIgnoreCase, c,
    937      nsStyleUtil::ValueIncludes(str, nsDependentAtomString(aStr), c))
    938 }
    939 
    940 bool Gecko_AttrHasSubstring(const nsAttrValue* aValue, const nsAtom* aStr,
    941                            bool aIgnoreCase) {
    942  return aStr != nsGkAtoms::_empty &&
    943         aValue->HasSubstring(nsDependentAtomString(aStr),
    944                              aIgnoreCase ? eIgnoreCase : eCaseMatters);
    945 }
    946 
    947 bool Gecko_AttrHasPrefix(const nsAttrValue* aValue, const nsAtom* aStr,
    948                         bool aIgnoreCase) {
    949  return aStr != nsGkAtoms::_empty &&
    950         aValue->HasPrefix(nsDependentAtomString(aStr),
    951                           aIgnoreCase ? eIgnoreCase : eCaseMatters);
    952 }
    953 
    954 bool Gecko_AttrHasSuffix(const nsAttrValue* aValue, const nsAtom* aStr,
    955                         bool aIgnoreCase) {
    956  return aStr != nsGkAtoms::_empty &&
    957         aValue->HasSuffix(nsDependentAtomString(aStr),
    958                           aIgnoreCase ? eIgnoreCase : eCaseMatters);
    959 }
    960 
    961 #define SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_) \
    962  nsAtom* prefix_##LangValue(implementor_ aElement) {                     \
    963    return LangValue(aElement);                                           \
    964  }
    965 
    966 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, const Element*)
    967 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot,
    968                                           const ServoElementSnapshot*)
    969 
    970 #undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
    971 
    972 nsAtom* Gecko_Atomize(const char* aString, uint32_t aLength) {
    973  return NS_Atomize(nsDependentCSubstring(aString, aLength)).take();
    974 }
    975 
    976 nsAtom* Gecko_Atomize16(const nsAString* aString) {
    977  return NS_Atomize(*aString).take();
    978 }
    979 
    980 void Gecko_AddRefAtom(nsAtom* aAtom) { NS_ADDREF(aAtom); }
    981 
    982 void Gecko_ReleaseAtom(nsAtom* aAtom) { NS_RELEASE(aAtom); }
    983 
    984 void Gecko_nsFont_InitSystem(nsFont* aDest, StyleSystemFont aFontId,
    985                             const nsStyleFont* aFont,
    986                             const Document* aDocument) {
    987  const nsFont& defaultVariableFont =
    988      ThreadSafeGetDefaultVariableFont(*aDocument, aFont->mLanguage);
    989 
    990  // We have passed uninitialized memory to this function,
    991  // initialize it. We can't simply return an nsFont because then
    992  // we need to know its size beforehand. Servo cannot initialize nsFont
    993  // itself, so this will do.
    994  new (aDest) nsFont(defaultVariableFont);
    995 
    996  nsLayoutUtils::ComputeSystemFont(aDest, aFontId, defaultVariableFont,
    997                                   aDocument);
    998 }
    999 
   1000 void Gecko_nsFont_Destroy(nsFont* aDest) { aDest->~nsFont(); }
   1001 
   1002 StyleGenericFontFamily Gecko_nsStyleFont_ComputeFallbackFontTypeForLanguage(
   1003    const Document* aDoc, nsAtom* aLanguage) {
   1004  return ThreadSafeGetLangGroupFontPrefs(*aDoc, aLanguage)->GetDefaultGeneric();
   1005 }
   1006 
   1007 Length Gecko_GetBaseSize(const Document* aDoc, nsAtom* aLang,
   1008                         StyleGenericFontFamily aGeneric) {
   1009  return ThreadSafeGetLangGroupFontPrefs(*aDoc, aLang)
   1010      ->GetDefaultFont(aGeneric)
   1011      ->size;
   1012 }
   1013 
   1014 gfxFontFeatureValueSet* Gecko_ConstructFontFeatureValueSet() {
   1015  return new gfxFontFeatureValueSet();
   1016 }
   1017 
   1018 nsTArray<uint32_t>* Gecko_AppendFeatureValueHashEntry(
   1019    gfxFontFeatureValueSet* aFontFeatureValues, nsAtom* aFamily,
   1020    uint32_t aAlternate, nsAtom* aName) {
   1021  MOZ_ASSERT(NS_IsMainThread());
   1022  return aFontFeatureValues->AppendFeatureValueHashEntry(nsAtomCString(aFamily),
   1023                                                         aName, aAlternate);
   1024 }
   1025 
   1026 gfx::FontPaletteValueSet* Gecko_ConstructFontPaletteValueSet() {
   1027  return new gfx::FontPaletteValueSet();
   1028 }
   1029 
   1030 gfx::FontPaletteValueSet::PaletteValues* Gecko_AppendPaletteValueHashEntry(
   1031    gfx::FontPaletteValueSet* aPaletteValueSet, nsAtom* aFamily,
   1032    nsAtom* aName) {
   1033  MOZ_ASSERT(NS_IsMainThread());
   1034  return aPaletteValueSet->Insert(aName, nsAtomCString(aFamily));
   1035 }
   1036 
   1037 void Gecko_SetFontPaletteBase(gfx::FontPaletteValueSet::PaletteValues* aValues,
   1038                              int32_t aBasePaletteIndex) {
   1039  aValues->mBasePalette = aBasePaletteIndex;
   1040 }
   1041 
   1042 void Gecko_SetFontPaletteOverride(
   1043    gfx::FontPaletteValueSet::PaletteValues* aValues, int32_t aIndex,
   1044    StyleAbsoluteColor* aColor) {
   1045  if (aIndex < 0) {
   1046    return;
   1047  }
   1048  aValues->mOverrides.AppendElement(gfx::FontPaletteValueSet::OverrideColor{
   1049      uint32_t(aIndex), gfx::sRGBColor::FromABGR(aColor->ToColor())});
   1050 }
   1051 
   1052 void Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen,
   1053                                   nsStyleImageLayers::LayerType aLayerType) {
   1054  size_t oldLength = aLayers->mLayers.Length();
   1055 
   1056  aLayers->mLayers.EnsureLengthAtLeast(aLen);
   1057 
   1058  for (size_t i = oldLength; i < aLen; ++i) {
   1059    aLayers->mLayers[i].Initialize(aLayerType);
   1060  }
   1061 }
   1062 
   1063 template <typename StyleType>
   1064 static void EnsureStyleAutoArrayLength(StyleType* aArray, size_t aLen) {
   1065  aArray->EnsureLengthAtLeast(aLen);
   1066 }
   1067 
   1068 void Gecko_EnsureStyleAnimationArrayLength(void* aArray, size_t aLen) {
   1069  auto* base = static_cast<nsStyleAutoArray<StyleAnimation>*>(aArray);
   1070  EnsureStyleAutoArrayLength(base, aLen);
   1071 }
   1072 
   1073 void Gecko_EnsureStyleTransitionArrayLength(void* aArray, size_t aLen) {
   1074  auto* base = reinterpret_cast<nsStyleAutoArray<StyleTransition>*>(aArray);
   1075  EnsureStyleAutoArrayLength(base, aLen);
   1076 }
   1077 
   1078 void Gecko_EnsureStyleScrollTimelineArrayLength(void* aArray, size_t aLen) {
   1079  auto* base = static_cast<nsStyleAutoArray<StyleScrollTimeline>*>(aArray);
   1080  EnsureStyleAutoArrayLength(base, aLen);
   1081 }
   1082 
   1083 void Gecko_EnsureStyleViewTimelineArrayLength(void* aArray, size_t aLen) {
   1084  auto* base = static_cast<nsStyleAutoArray<StyleViewTimeline>*>(aArray);
   1085  EnsureStyleAutoArrayLength(base, aLen);
   1086 }
   1087 
   1088 enum class KeyframeSearchDirection {
   1089  Forwards,
   1090  Backwards,
   1091 };
   1092 
   1093 enum class KeyframeInsertPosition {
   1094  Prepend,
   1095  LastForOffset,
   1096 };
   1097 
   1098 static Keyframe* GetOrCreateKeyframe(
   1099    nsTArray<Keyframe>* aKeyframes, float aOffset,
   1100    const StyleComputedTimingFunction* aTimingFunction,
   1101    const CompositeOperationOrAuto aComposition,
   1102    KeyframeSearchDirection aSearchDirection,
   1103    KeyframeInsertPosition aInsertPosition) {
   1104  MOZ_ASSERT(aKeyframes, "The keyframe array should be valid");
   1105  MOZ_ASSERT(aTimingFunction, "The timing function should be valid");
   1106  MOZ_ASSERT(aOffset >= 0. && aOffset <= 1.,
   1107             "The offset should be in the range of [0.0, 1.0]");
   1108 
   1109  size_t keyframeIndex;
   1110  switch (aSearchDirection) {
   1111    case KeyframeSearchDirection::Forwards:
   1112      if (nsAnimationManager::FindMatchingKeyframe(
   1113              *aKeyframes, aOffset, *aTimingFunction, aComposition,
   1114              keyframeIndex)) {
   1115        return &(*aKeyframes)[keyframeIndex];
   1116      }
   1117      break;
   1118    case KeyframeSearchDirection::Backwards:
   1119      if (nsAnimationManager::FindMatchingKeyframe(
   1120              Reversed(*aKeyframes), aOffset, *aTimingFunction, aComposition,
   1121              keyframeIndex)) {
   1122        return &(*aKeyframes)[aKeyframes->Length() - 1 - keyframeIndex];
   1123      }
   1124      keyframeIndex = aKeyframes->Length() - 1;
   1125      break;
   1126  }
   1127 
   1128  Keyframe* keyframe = aKeyframes->InsertElementAt(
   1129      aInsertPosition == KeyframeInsertPosition::Prepend ? 0 : keyframeIndex);
   1130  keyframe->mOffset.emplace(aOffset);
   1131  if (!aTimingFunction->IsLinearKeyword()) {
   1132    keyframe->mTimingFunction.emplace(*aTimingFunction);
   1133  }
   1134  keyframe->mComposite = aComposition;
   1135 
   1136  return keyframe;
   1137 }
   1138 
   1139 Keyframe* Gecko_GetOrCreateKeyframeAtStart(
   1140    nsTArray<Keyframe>* aKeyframes, float aOffset,
   1141    const StyleComputedTimingFunction* aTimingFunction,
   1142    const CompositeOperationOrAuto aComposition) {
   1143  MOZ_ASSERT(aKeyframes->IsEmpty() ||
   1144                 aKeyframes->ElementAt(0).mOffset.value() >= aOffset,
   1145             "The offset should be less than or equal to the first keyframe's "
   1146             "offset if there are exisiting keyframes");
   1147 
   1148  return GetOrCreateKeyframe(aKeyframes, aOffset, aTimingFunction, aComposition,
   1149                             KeyframeSearchDirection::Forwards,
   1150                             KeyframeInsertPosition::Prepend);
   1151 }
   1152 
   1153 Keyframe* Gecko_GetOrCreateInitialKeyframe(
   1154    nsTArray<Keyframe>* aKeyframes,
   1155    const StyleComputedTimingFunction* aTimingFunction,
   1156    const CompositeOperationOrAuto aComposition) {
   1157  return GetOrCreateKeyframe(aKeyframes, 0., aTimingFunction, aComposition,
   1158                             KeyframeSearchDirection::Forwards,
   1159                             KeyframeInsertPosition::LastForOffset);
   1160 }
   1161 
   1162 Keyframe* Gecko_GetOrCreateFinalKeyframe(
   1163    nsTArray<Keyframe>* aKeyframes,
   1164    const StyleComputedTimingFunction* aTimingFunction,
   1165    const CompositeOperationOrAuto aComposition) {
   1166  return GetOrCreateKeyframe(aKeyframes, 1., aTimingFunction, aComposition,
   1167                             KeyframeSearchDirection::Backwards,
   1168                             KeyframeInsertPosition::LastForOffset);
   1169 }
   1170 
   1171 void Gecko_GetComputedURLSpec(const StyleComputedUrl* aURL, nsCString* aOut) {
   1172  MOZ_ASSERT(aURL);
   1173  MOZ_ASSERT(aOut);
   1174  if (aURL->IsLocalRef()) {
   1175    aOut->Assign(aURL->SpecifiedSerialization());
   1176    return;
   1177  }
   1178 
   1179  if (nsIURI* uri = aURL->GetURI()) {
   1180    nsresult rv = uri->GetSpec(*aOut);
   1181    if (NS_SUCCEEDED(rv)) {
   1182      return;
   1183    }
   1184  }
   1185 
   1186  // Empty URL computes to empty, per spec:
   1187  if (aURL->SpecifiedSerialization().IsEmpty()) {
   1188    aOut->Truncate();
   1189  } else {
   1190    aOut->AssignLiteral("about:invalid");
   1191  }
   1192 }
   1193 
   1194 bool Gecko_IsSupportedImageMimeType(const uint8_t* aMimeType,
   1195                                    const uint32_t aLen) {
   1196  nsDependentCSubstring mime(reinterpret_cast<const char*>(aMimeType), aLen);
   1197  return imgLoader::SupportImageWithMimeType(
   1198      mime, AcceptedMimeTypes::IMAGES_AND_DOCUMENTS);
   1199 }
   1200 
   1201 void Gecko_nsIURI_Debug(nsIURI* aURI, nsCString* aOut) {
   1202  // TODO(emilio): Do we have more useful stuff to put here, maybe?
   1203  if (aURI) {
   1204    *aOut = aURI->GetSpecOrDefault();
   1205  }
   1206 }
   1207 
   1208 // XXX Implemented by hand because even though it's thread-safe, only the
   1209 // subclasses have the HasThreadSafeRefCnt bits.
   1210 void Gecko_AddRefnsIURIArbitraryThread(nsIURI* aPtr) { NS_ADDREF(aPtr); }
   1211 void Gecko_ReleasensIURIArbitraryThread(nsIURI* aPtr) { NS_RELEASE(aPtr); }
   1212 
   1213 void Gecko_nsIReferrerInfo_Debug(nsIReferrerInfo* aReferrerInfo,
   1214                                 nsCString* aOut) {
   1215  if (aReferrerInfo) {
   1216    if (nsCOMPtr<nsIURI> referrer = aReferrerInfo->GetComputedReferrer()) {
   1217      *aOut = referrer->GetSpecOrDefault();
   1218    }
   1219  }
   1220 }
   1221 
   1222 template <typename ElementLike>
   1223 void DebugListAttributes(const ElementLike& aElement, nsCString& aOut) {
   1224  const uint32_t kMaxAttributeLength = 40;
   1225 
   1226  uint32_t i = 0;
   1227  while (BorrowedAttrInfo info = aElement.GetAttrInfoAt(i++)) {
   1228    aOut.AppendLiteral(" ");
   1229    if (nsAtom* prefix = info.mName->GetPrefix()) {
   1230      aOut.Append(NS_ConvertUTF16toUTF8(nsDependentAtomString(prefix)));
   1231      aOut.AppendLiteral(":");
   1232    }
   1233    aOut.Append(
   1234        NS_ConvertUTF16toUTF8(nsDependentAtomString(info.mName->LocalName())));
   1235    if (!info.mValue) {
   1236      continue;
   1237    }
   1238    aOut.AppendLiteral("=\"");
   1239    nsAutoString value;
   1240    info.mValue->ToString(value);
   1241    if (value.Length() > kMaxAttributeLength) {
   1242      value.Truncate(kMaxAttributeLength - 3);
   1243      value.AppendLiteral("...");
   1244    }
   1245    aOut.Append(NS_ConvertUTF16toUTF8(value));
   1246    aOut.AppendLiteral("\"");
   1247  }
   1248 }
   1249 
   1250 void Gecko_Element_DebugListAttributes(const Element* aElement,
   1251                                       nsCString* aOut) {
   1252  DebugListAttributes(*aElement, *aOut);
   1253 }
   1254 
   1255 void Gecko_Snapshot_DebugListAttributes(const ServoElementSnapshot* aSnapshot,
   1256                                        nsCString* aOut) {
   1257  DebugListAttributes(*aSnapshot, *aOut);
   1258 }
   1259 
   1260 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData);
   1261 
   1262 void Gecko_nsStyleFont_SetLang(nsStyleFont* aFont, nsAtom* aAtom) {
   1263  aFont->mLanguage = dont_AddRef(aAtom);
   1264  aFont->mExplicitLanguage = true;
   1265 }
   1266 
   1267 void Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont,
   1268                                    const nsStyleFont* aSource) {
   1269  aFont->mLanguage = aSource->mLanguage;
   1270 }
   1271 
   1272 Length Gecko_nsStyleFont_ComputeMinSize(const nsStyleFont* aFont,
   1273                                        const Document* aDocument) {
   1274  // Don't change font-size:0, since that would un-hide hidden text.
   1275  if (aFont->mSize.IsZero()) {
   1276    return {0};
   1277  }
   1278  // Don't change it for docs where we don't enable the min-font-size.
   1279  if (!aFont->MinFontSizeEnabled()) {
   1280    return {0};
   1281  }
   1282  Length minFontSize;
   1283  bool needsCache = false;
   1284 
   1285  auto MinFontSize = [&](bool* aNeedsToCache) {
   1286    const auto* prefs =
   1287        aDocument->GetFontPrefsForLang(aFont->mLanguage, aNeedsToCache);
   1288    return prefs ? prefs->mMinimumFontSize : Length{0};
   1289  };
   1290 
   1291  {
   1292    AutoReadLock guard(*sServoFFILock);
   1293    minFontSize = MinFontSize(&needsCache);
   1294  }
   1295 
   1296  if (needsCache) {
   1297    AutoWriteLock guard(*sServoFFILock);
   1298    minFontSize = MinFontSize(nullptr);
   1299  }
   1300 
   1301  if (minFontSize.ToCSSPixels() <= 0.0f) {
   1302    return {0};
   1303  }
   1304 
   1305  minFontSize.ScaleBy(aFont->mMinFontSizeRatio._0);
   1306  return minFontSize;
   1307 }
   1308 
   1309 static StaticRefPtr<UACacheReporter> gUACacheReporter;
   1310 
   1311 namespace mozilla {
   1312 
   1313 void InitializeServo() {
   1314  URLExtraData::Init();
   1315  Servo_Initialize(URLExtraData::Dummy(), URLExtraData::DummyChrome());
   1316 
   1317  gUACacheReporter = new UACacheReporter();
   1318  RegisterWeakMemoryReporter(gUACacheReporter);
   1319 
   1320  sServoFFILock = new RWLock("Servo::FFILock");
   1321 }
   1322 
   1323 void ShutdownServo() {
   1324  MOZ_ASSERT(sServoFFILock);
   1325 
   1326  UnregisterWeakMemoryReporter(gUACacheReporter);
   1327  gUACacheReporter = nullptr;
   1328 
   1329  sServoFFILock = nullptr;
   1330  Servo_Shutdown();
   1331 
   1332  URLExtraData::Shutdown();
   1333 }
   1334 
   1335 void AssertIsMainThreadOrServoFontMetricsLocked() {
   1336  if (!NS_IsMainThread()) {
   1337    MOZ_ASSERT(sServoFFILock &&
   1338               sServoFFILock->LockedForWritingByCurrentThread());
   1339  }
   1340 }
   1341 
   1342 }  // namespace mozilla
   1343 
   1344 GeckoFontMetrics Gecko_GetFontMetrics(const nsPresContext* aPresContext,
   1345                                      bool aIsVertical,
   1346                                      const nsStyleFont* aFont,
   1347                                      Length aFontSize,
   1348                                      StyleQueryFontMetricsFlags flags) {
   1349  AutoWriteLock guard(*sServoFFILock);
   1350 
   1351  // Getting font metrics can require some main thread only work to be
   1352  // done, such as work that needs to touch non-threadsafe refcounted
   1353  // objects (like the DOM FontFace/FontFaceSet objects), network loads, etc.
   1354  //
   1355  // To handle this work, font code checks whether we are in a Servo traversal
   1356  // and if so, appends PostTraversalTasks to the current ServoStyleSet
   1357  // to be performed immediately after the traversal is finished.  This
   1358  // works well for starting downloadable font loads, since we don't have
   1359  // those fonts available to get metrics for anyway.  Platform fonts and
   1360  // ArrayBuffer-backed FontFace objects are handled synchronously.
   1361 
   1362  nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
   1363  RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetMetricsFor(
   1364      presContext, aIsVertical, aFont, aFontSize,
   1365      bool(flags & StyleQueryFontMetricsFlags::USE_USER_FONT_SET));
   1366  auto* fontGroup = fm->GetThebesFontGroup();
   1367  auto metrics = fontGroup->GetMetricsForCSSUnits(fm->Orientation(), flags);
   1368 
   1369  float scriptPercentScaleDown = 0;
   1370  float scriptScriptPercentScaleDown = 0;
   1371  if (flags & StyleQueryFontMetricsFlags::NEEDS_MATH_SCALES) {
   1372    RefPtr<gfxFont> font = fontGroup->GetFirstValidFont();
   1373    if (font->TryGetMathTable()) {
   1374      scriptPercentScaleDown = static_cast<float>(
   1375          font->MathTable()->Constant(gfxMathTable::ScriptPercentScaleDown));
   1376      scriptScriptPercentScaleDown =
   1377          static_cast<float>(font->MathTable()->Constant(
   1378              gfxMathTable::ScriptScriptPercentScaleDown));
   1379    }
   1380  }
   1381 
   1382  int32_t d2a = aPresContext->AppUnitsPerDevPixel();
   1383  auto ToLength = [](nscoord aLen) {
   1384    return Length::FromPixels(CSSPixel::FromAppUnits(aLen));
   1385  };
   1386  return {ToLength(NS_round(metrics.xHeight * d2a)),
   1387          ToLength(NS_round(metrics.zeroWidth * d2a)),
   1388          ToLength(NS_round(metrics.capHeight * d2a)),
   1389          ToLength(NS_round(metrics.ideographicWidth * d2a)),
   1390          ToLength(NS_round(metrics.maxAscent * d2a)),
   1391          ToLength(NS_round(fontGroup->GetStyle()->size * d2a)),
   1392          scriptPercentScaleDown,
   1393          scriptScriptPercentScaleDown};
   1394 }
   1395 
   1396 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(SheetLoadDataHolder, SheetLoadDataHolder);
   1397 
   1398 void Gecko_StyleSheet_FinishAsyncParse(
   1399    SheetLoadDataHolder* aData,
   1400    StyleStrong<StyleStylesheetContents> aSheetContents) {
   1401  RefPtr<SheetLoadDataHolder> loadData = aData;
   1402  RefPtr<StyleStylesheetContents> sheetContents = aSheetContents.Consume();
   1403  NS_DispatchToMainThreadQueue(
   1404      NS_NewRunnableFunction(__func__,
   1405                             [d = std::move(loadData),
   1406                              contents = std::move(sheetContents)]() mutable {
   1407                               MOZ_ASSERT(NS_IsMainThread());
   1408                               SheetLoadData* data = d->get();
   1409                               data->mSheet->FinishAsyncParse(
   1410                                   contents.forget());
   1411                             }),
   1412      EventQueuePriority::RenderBlocking);
   1413 }
   1414 
   1415 static already_AddRefed<StyleSheet> LoadImportSheet(
   1416    Loader* aLoader, StyleSheet* aParent, SheetLoadData* aParentLoadData,
   1417    LoaderReusableStyleSheets* aReusableSheets, const StyleCssUrl& aURL,
   1418    already_AddRefed<StyleLockedMediaList> aMediaList) {
   1419  MOZ_ASSERT(NS_IsMainThread());
   1420  MOZ_ASSERT(aLoader, "Should've catched this before");
   1421  MOZ_ASSERT(aParent, "Only used for @import, so parent should exist!");
   1422 
   1423  auto media = MakeRefPtr<MediaList>(std::move(aMediaList));
   1424  nsCOMPtr<nsIURI> uri = aURL.GetURI();
   1425  nsresult rv = uri ? NS_OK : NS_ERROR_FAILURE;
   1426 
   1427  size_t previousSheetCount = aParent->ChildSheets().Length();
   1428  if (NS_SUCCEEDED(rv)) {
   1429    // TODO(emilio): We should probably make LoadChildSheet return the
   1430    // stylesheet rather than the return code.
   1431    rv = aLoader->LoadChildSheet(*aParent, aParentLoadData, uri, media,
   1432                                 aReusableSheets);
   1433  }
   1434 
   1435  if (NS_FAILED(rv) || previousSheetCount == aParent->ChildSheets().Length()) {
   1436    // Servo and Gecko have different ideas of what a valid URL is, so we might
   1437    // get in here with a URL string that NS_NewURI can't handle.  We may also
   1438    // reach here via an import cycle.  For the import cycle case, we need some
   1439    // sheet object per spec, even if its empty.  DevTools uses the URI to
   1440    // realize it has hit an import cycle, so we mark it complete to make the
   1441    // sheet readable from JS.
   1442    RefPtr<StyleSheet> emptySheet =
   1443        aParent->CreateEmptyChildSheet(media.forget());
   1444    // Make a dummy URI if we don't have one because some methods assume
   1445    // non-null URIs.
   1446    if (!uri) {
   1447      NS_NewURI(getter_AddRefs(uri), "about:invalid"_ns);
   1448    }
   1449    nsCOMPtr<nsIReferrerInfo> referrerInfo =
   1450        ReferrerInfo::CreateForExternalCSSResources(emptySheet, uri);
   1451    emptySheet->SetURIs(uri, uri, referrerInfo, aURL.ExtraData().Principal());
   1452    emptySheet->SetComplete();
   1453    aParent->AppendStyleSheet(*emptySheet);
   1454    return emptySheet.forget();
   1455  }
   1456 
   1457  RefPtr<StyleSheet> sheet = aParent->ChildSheets().LastElement();
   1458  return sheet.forget();
   1459 }
   1460 
   1461 StyleSheet* Gecko_LoadStyleSheet(Loader* aLoader, StyleSheet* aParent,
   1462                                 SheetLoadData* aParentLoadData,
   1463                                 LoaderReusableStyleSheets* aReusableSheets,
   1464                                 const StyleCssUrl* aUrl,
   1465                                 StyleStrong<StyleLockedMediaList> aMediaList) {
   1466  MOZ_ASSERT(NS_IsMainThread());
   1467  MOZ_ASSERT(aUrl);
   1468 
   1469  return LoadImportSheet(aLoader, aParent, aParentLoadData, aReusableSheets,
   1470                         *aUrl, aMediaList.Consume())
   1471      .take();
   1472 }
   1473 
   1474 void Gecko_LoadStyleSheetAsync(SheetLoadDataHolder* aParentData,
   1475                               const StyleCssUrl* aUrl,
   1476                               StyleStrong<StyleLockedMediaList> aMediaList,
   1477                               StyleStrong<StyleLockedImportRule> aImportRule) {
   1478  MOZ_ASSERT(aUrl);
   1479  RefPtr<SheetLoadDataHolder> loadData = aParentData;
   1480  RefPtr<StyleLockedMediaList> mediaList = aMediaList.Consume();
   1481  RefPtr<StyleLockedImportRule> importRule = aImportRule.Consume();
   1482  NS_DispatchToMainThreadQueue(
   1483      NS_NewRunnableFunction(
   1484          __func__,
   1485          [data = std::move(loadData), url = StyleCssUrl(*aUrl),
   1486           media = std::move(mediaList),
   1487           import = std::move(importRule)]() mutable {
   1488            MOZ_ASSERT(NS_IsMainThread());
   1489            SheetLoadData* d = data->get();
   1490            RefPtr<StyleSheet> sheet = LoadImportSheet(
   1491                d->mLoader, d->mSheet, d, nullptr, url, media.forget());
   1492            Servo_ImportRule_SetSheet(import, sheet);
   1493          }),
   1494      EventQueuePriority::RenderBlocking);
   1495 }
   1496 
   1497 void Gecko_AddPropertyToSet(nsCSSPropertyIDSet* aPropertySet,
   1498                            NonCustomCSSPropertyId aProperty) {
   1499  aPropertySet->AddProperty(aProperty);
   1500 }
   1501 
   1502 bool Gecko_DocumentRule_UseForPresentation(
   1503    const Document* aDocument, const nsACString* aPattern,
   1504    DocumentMatchingFunction aMatchingFunction) {
   1505  MOZ_ASSERT(NS_IsMainThread());
   1506 
   1507  nsIURI* docURI = aDocument->GetDocumentURI();
   1508  nsAutoCString docURISpec;
   1509  if (docURI) {
   1510    // If GetSpec fails (due to OOM) just skip these URI-specific CSS rules.
   1511    nsresult rv = docURI->GetSpec(docURISpec);
   1512    NS_ENSURE_SUCCESS(rv, false);
   1513  }
   1514 
   1515  return CSSMozDocumentRule::Match(aDocument, docURI, docURISpec, *aPattern,
   1516                                   aMatchingFunction);
   1517 }
   1518 
   1519 void Gecko_SetJemallocThreadLocalArena(bool enabled) {
   1520 #if defined(MOZ_MEMORY)
   1521  jemalloc_thread_local_arena(enabled);
   1522 #endif
   1523 }
   1524 
   1525 template <typename T>
   1526 void Construct(T* aPtr, const Document* aDoc) {
   1527  if constexpr (std::is_constructible_v<T, const Document&>) {
   1528    MOZ_ASSERT(aDoc);
   1529    new (KnownNotNull, aPtr) T(*aDoc);
   1530  } else {
   1531    MOZ_ASSERT(!aDoc);
   1532    new (KnownNotNull, aPtr) T();
   1533    // These instance are intentionally global, and we don't want leakcheckers
   1534    // to report them.
   1535    aPtr->MarkLeaked();
   1536  }
   1537 }
   1538 
   1539 #define GENERATE_GECKO_FUNCTIONS(name)                                 \
   1540  void Gecko_Construct_Default_nsStyle##name(nsStyle##name* ptr,       \
   1541                                             const Document* doc) {    \
   1542    Construct(ptr, doc);                                               \
   1543  }                                                                    \
   1544  void Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr,           \
   1545                                         const nsStyle##name* other) { \
   1546    new (ptr) nsStyle##name(*other);                                   \
   1547  }                                                                    \
   1548  void Gecko_Destroy_nsStyle##name(nsStyle##name* ptr) {               \
   1549    ptr->~nsStyle##name();                                             \
   1550  }
   1551 
   1552 FOR_EACH_STYLE_STRUCT(GENERATE_GECKO_FUNCTIONS, GENERATE_GECKO_FUNCTIONS)
   1553 
   1554 #undef GENERATE_GECKO_FUNCTIONS
   1555 
   1556 bool Gecko_ErrorReportingEnabled(const StyleSheet* aSheet,
   1557                                 const Loader* aLoader,
   1558                                 uint64_t* aOutWindowId) {
   1559  if (!ErrorReporter::ShouldReportErrors(aSheet, aLoader)) {
   1560    return false;
   1561  }
   1562  *aOutWindowId = ErrorReporter::FindInnerWindowId(aSheet, aLoader);
   1563  return true;
   1564 }
   1565 
   1566 void Gecko_ReportUnexpectedCSSError(const uint64_t aWindowId, nsIURI* aURI,
   1567                                    const char* message, const char* param,
   1568                                    uint32_t paramLen, const char* prefix,
   1569                                    const char* prefixParam,
   1570                                    uint32_t prefixParamLen, const char* suffix,
   1571                                    const char* selectors,
   1572                                    uint32_t selectorsLen, uint32_t lineNumber,
   1573                                    uint32_t colNumber) {
   1574  MOZ_RELEASE_ASSERT(NS_IsMainThread());
   1575 
   1576  ErrorReporter reporter(aWindowId);
   1577 
   1578  if (prefix) {
   1579    if (prefixParam) {
   1580      nsDependentCSubstring paramValue(prefixParam, prefixParamLen);
   1581      AutoTArray<nsString, 1> wideParam;
   1582      CopyUTF8toUTF16(paramValue, *wideParam.AppendElement());
   1583      reporter.ReportUnexpectedUnescaped(prefix, wideParam);
   1584    } else {
   1585      reporter.ReportUnexpected(prefix);
   1586    }
   1587  }
   1588 
   1589  if (param) {
   1590    nsDependentCSubstring paramValue(param, paramLen);
   1591    AutoTArray<nsString, 1> wideParam;
   1592    CopyUTF8toUTF16(paramValue, *wideParam.AppendElement());
   1593    reporter.ReportUnexpectedUnescaped(message, wideParam);
   1594  } else {
   1595    reporter.ReportUnexpected(message);
   1596  }
   1597 
   1598  if (suffix) {
   1599    reporter.ReportUnexpected(suffix);
   1600  }
   1601  nsDependentCSubstring selectorsValue(selectors, selectorsLen);
   1602  reporter.OutputError(selectorsValue, lineNumber + 1, colNumber, aURI);
   1603 }
   1604 
   1605 void Gecko_ContentList_AppendAll(nsSimpleContentList* aList,
   1606                                 const Element** aElements, size_t aLength) {
   1607  MOZ_ASSERT(NS_IsMainThread());
   1608  MOZ_ASSERT(aElements);
   1609  MOZ_ASSERT(aLength);
   1610  MOZ_ASSERT(aList);
   1611 
   1612  aList->SetCapacity(aLength);
   1613 
   1614  for (size_t i = 0; i < aLength; ++i) {
   1615    aList->AppendElement(const_cast<Element*>(aElements[i]));
   1616  }
   1617 }
   1618 
   1619 RustSpan<const Element* const> Gecko_Document_GetElementsWithId(
   1620    const Document* aDoc, nsAtom* aId) {
   1621  MOZ_ASSERT(aDoc);
   1622  MOZ_ASSERT(aId);
   1623  auto span = aDoc->GetAllElementsForId(aId);
   1624  return {span.Elements(), span.Length()};
   1625 }
   1626 
   1627 RustSpan<const Element* const> Gecko_ShadowRoot_GetElementsWithId(
   1628    const ShadowRoot* aShadowRoot, nsAtom* aId) {
   1629  MOZ_ASSERT(aShadowRoot);
   1630  MOZ_ASSERT(aId);
   1631  auto span = aShadowRoot->GetAllElementsForId(aId);
   1632  return {span.Elements(), span.Length()};
   1633 }
   1634 
   1635 static StyleComputedMozPrefFeatureValue GetPrefValue(const nsCString& aPref) {
   1636  using Value = StyleComputedMozPrefFeatureValue;
   1637  switch (Preferences::GetType(aPref.get())) {
   1638    case nsIPrefBranch::PREF_STRING: {
   1639      nsAutoString value;
   1640      Preferences::GetString(aPref.get(), value);
   1641      return Value::String(StyleAtomString{NS_Atomize(value)});
   1642    }
   1643    case nsIPrefBranch::PREF_INT:
   1644      return Value::Integer(Preferences::GetInt(aPref.get(), 0));
   1645    case nsIPrefBranch::PREF_BOOL: {
   1646      auto value = Preferences::GetBool(aPref.get(), false)
   1647                       ? StyleBoolValue::True
   1648                       : StyleBoolValue::False;
   1649      return Value::Boolean(value);
   1650    }
   1651    case nsIPrefBranch::PREF_INVALID:
   1652    default:
   1653      break;
   1654  }
   1655 
   1656  return StyleComputedMozPrefFeatureValue::None();
   1657 }
   1658 
   1659 bool Gecko_EvalMozPrefFeature(nsAtom* aPref,
   1660                              const StyleComputedMozPrefFeatureValue* aValue) {
   1661  MOZ_ASSERT(NS_IsMainThread());
   1662  MOZ_ASSERT(aValue);
   1663  using Value = StyleComputedMozPrefFeatureValue;
   1664  using PrefMap = nsTHashMap<RefPtr<nsAtom>, Value>;
   1665  // This map leaks until shutdown, but that's fine, all the values are
   1666  // controlled by us so it's not expected to be big.
   1667  static StaticAutoPtr<PrefMap> sRegisteredPrefs;
   1668  if (!sRegisteredPrefs) {
   1669    if (PastShutdownPhase(ShutdownPhase::XPCOMShutdownFinal)) {
   1670      // Styling doesn't really matter much at this point, don't bother.
   1671      return false;
   1672    }
   1673    sRegisteredPrefs = new PrefMap();
   1674    ClearOnShutdown(&sRegisteredPrefs);
   1675  }
   1676 
   1677  const auto& value = sRegisteredPrefs->LookupOrInsertWith(aPref, [&] {
   1678    nsAutoAtomCString prefName(aPref);
   1679    Preferences::RegisterCallback(
   1680        [](const char* aPrefName, void*) {
   1681          nsDependentCString name(aPrefName);
   1682          if (sRegisteredPrefs) {
   1683            RefPtr<nsAtom> nameAtom = NS_Atomize(name);
   1684            sRegisteredPrefs->InsertOrUpdate(nameAtom, GetPrefValue(name));
   1685          }
   1686          LookAndFeel::NotifyChangedAllWindows(
   1687              widget::ThemeChangeKind::MediaQueriesOnly);
   1688        },
   1689        prefName);
   1690    return GetPrefValue(prefName);
   1691  });
   1692  if (aValue->IsNone()) {
   1693    // For a non-specified query, we return true if the pref is not false, zero,
   1694    // empty or invalid
   1695    switch (value.tag) {
   1696      case Value::Tag::None:
   1697        return false;
   1698      case Value::Tag::Boolean:
   1699        return value.AsBoolean() == StyleBoolValue::True;
   1700      case Value::Tag::Integer:
   1701        return value.AsInteger() != 0;
   1702      case Value::Tag::String:
   1703        return !value.AsString().AsAtom()->IsEmpty();
   1704    }
   1705    return false;
   1706  }
   1707  return value == *aValue;
   1708 }
   1709 
   1710 bool Gecko_IsFontFormatSupported(StyleFontFaceSourceFormatKeyword aFormat) {
   1711  return gfxPlatform::GetPlatform()->IsFontFormatSupported(
   1712      aFormat, StyleFontFaceSourceTechFlags::Empty());
   1713 }
   1714 
   1715 bool Gecko_IsFontTechSupported(StyleFontFaceSourceTechFlags aFlag) {
   1716  return gfxPlatform::GetPlatform()->IsFontFormatSupported(
   1717      StyleFontFaceSourceFormatKeyword::None, aFlag);
   1718 }
   1719 
   1720 bool Gecko_IsKnownIconFontFamily(const nsAtom* aFamilyName) {
   1721  return gfxPlatform::GetPlatform()->IsKnownIconFontFamily(aFamilyName);
   1722 }
   1723 
   1724 bool Gecko_IsInServoTraversal() { return ServoStyleSet::IsInServoTraversal(); }
   1725 
   1726 bool Gecko_IsMainThread() { return NS_IsMainThread(); }
   1727 
   1728 bool Gecko_IsDOMWorkerThread() { return !!GetCurrentThreadWorkerPrivate(); }
   1729 
   1730 int32_t Gecko_GetNumStyleThreads() {
   1731  if (const auto& cpuInfo = hal::GetHeterogeneousCpuInfo()) {
   1732    size_t numBigCpus = cpuInfo->mBigCpus.Count();
   1733    // If CPUs are homogeneous we do not need to override stylo's
   1734    // default number of threads.
   1735    if (numBigCpus != cpuInfo->mTotalNumCpus) {
   1736      // From testing on a variety of devices it appears using only
   1737      // the number of big cores gives best performance when there are
   1738      // 2 or more big cores. If there are fewer than 2 big cores then
   1739      // additionally using the medium cores performs better.
   1740      if (numBigCpus >= 2) {
   1741        return static_cast<int32_t>(numBigCpus);
   1742      }
   1743      return static_cast<int32_t>(numBigCpus + cpuInfo->mMediumCpus.Count());
   1744    }
   1745  }
   1746 
   1747  return -1;
   1748 }
   1749 
   1750 const nsAttrValue* Gecko_GetSVGAnimatedClass(const Element* aElement) {
   1751  MOZ_ASSERT(aElement->IsSVGElement());
   1752  return static_cast<const SVGElement*>(aElement)->GetAnimatedClassName();
   1753 }
   1754 
   1755 bool Gecko_AssertClassAttrValueIsSane(const nsAttrValue* aValue) {
   1756  MOZ_ASSERT(aValue->Type() == nsAttrValue::eAtom ||
   1757             aValue->Type() == nsAttrValue::eString ||
   1758             aValue->Type() == nsAttrValue::eAtomArray);
   1759  MOZ_ASSERT_IF(
   1760      aValue->Type() == nsAttrValue::eString,
   1761      nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
   1762          aValue->GetStringValue())
   1763          .IsEmpty());
   1764  return true;
   1765 }
   1766 
   1767 void Gecko_GetSafeAreaInsets(const nsPresContext* aPresContext, float* aTop,
   1768                             float* aRight, float* aBottom, float* aLeft) {
   1769  MOZ_ASSERT(aPresContext);
   1770  const CSSMargin insets =
   1771      LayoutDeviceMargin(aPresContext->GetSafeAreaInsets()) /
   1772      aPresContext->CSSToDevPixelScale();
   1773  *aTop = insets.top;
   1774  *aRight = insets.right;
   1775  *aBottom = insets.bottom;
   1776  *aLeft = insets.left;
   1777 }
   1778 
   1779 void Gecko_PrintfStderr(const nsCString* aStr) {
   1780  printf_stderr("%s", aStr->get());
   1781 }
   1782 
   1783 nsAtom* Gecko_Element_ImportedPart(const nsAttrValue* aValue,
   1784                                   nsAtom* aPartName) {
   1785  if (aValue->Type() != nsAttrValue::eShadowParts) {
   1786    return nullptr;
   1787  }
   1788  return aValue->GetShadowPartsValue().GetReverse(aPartName);
   1789 }
   1790 
   1791 nsAtom** Gecko_Element_ExportedParts(const nsAttrValue* aValue,
   1792                                     nsAtom* aPartName, size_t* aOutLength) {
   1793  if (aValue->Type() != nsAttrValue::eShadowParts) {
   1794    return nullptr;
   1795  }
   1796  auto* parts = aValue->GetShadowPartsValue().Get(aPartName);
   1797  if (!parts) {
   1798    return nullptr;
   1799  }
   1800  *aOutLength = parts->Length();
   1801  static_assert(sizeof(RefPtr<nsAtom>) == sizeof(nsAtom*));
   1802  static_assert(alignof(RefPtr<nsAtom>) == alignof(nsAtom*));
   1803  return reinterpret_cast<nsAtom**>(parts->Elements());
   1804 }
   1805 
   1806 uint64_t Gecko_Element_GetSubtreeBloomFilter(const Element* aElement) {
   1807  return aElement->GetSubtreeBloomFilter();
   1808 }
   1809 
   1810 bool StyleSingleFontFamily::IsNamedFamily(const nsAString& aFamilyName) const {
   1811  if (!IsFamilyName()) {
   1812    return false;
   1813  }
   1814  nsDependentAtomString name(AsFamilyName().name.AsAtom());
   1815  return name.Equals(aFamilyName, nsCaseInsensitiveStringComparator);
   1816 }
   1817 
   1818 StyleSingleFontFamily StyleSingleFontFamily::Parse(
   1819    const nsACString& aFamilyOrGenericName) {
   1820  // should only be passed a single font - not entirely correct, a family
   1821  // *could* have a comma in it but in practice never does so
   1822  // for debug purposes this is fine
   1823  NS_ASSERTION(aFamilyOrGenericName.FindChar(',') == -1,
   1824               "Convert method should only be passed a single family name");
   1825 
   1826  auto genericType = Servo_GenericFontFamily_Parse(&aFamilyOrGenericName);
   1827  if (genericType != StyleGenericFontFamily::None) {
   1828    return Generic(genericType);
   1829  }
   1830  return FamilyName({StyleAtom(NS_Atomize(aFamilyOrGenericName)),
   1831                     StyleFontFamilyNameSyntax::Identifiers});
   1832 }
   1833 
   1834 void StyleSingleFontFamily::AppendToString(nsACString& aName,
   1835                                           bool aQuote) const {
   1836  if (IsFamilyName()) {
   1837    const auto& name = AsFamilyName();
   1838    if (!aQuote) {
   1839      aName.Append(nsAutoAtomCString(name.name.AsAtom()));
   1840      return;
   1841    }
   1842    Servo_FamilyName_Serialize(&name, &aName);
   1843    return;
   1844  }
   1845 
   1846  switch (AsGeneric()) {
   1847    case StyleGenericFontFamily::None:
   1848    case StyleGenericFontFamily::MozEmoji:
   1849      MOZ_FALLTHROUGH_ASSERT("Should never appear in a font-family name!");
   1850    case StyleGenericFontFamily::Serif:
   1851      return aName.AppendLiteral("serif");
   1852    case StyleGenericFontFamily::SansSerif:
   1853      return aName.AppendLiteral("sans-serif");
   1854    case StyleGenericFontFamily::Monospace:
   1855      return aName.AppendLiteral("monospace");
   1856    case StyleGenericFontFamily::Cursive:
   1857      return aName.AppendLiteral("cursive");
   1858    case StyleGenericFontFamily::Fantasy:
   1859      return aName.AppendLiteral("fantasy");
   1860    case StyleGenericFontFamily::Math:
   1861      return aName.AppendLiteral("math");
   1862    case StyleGenericFontFamily::SystemUi:
   1863      return aName.AppendLiteral("system-ui");
   1864  }
   1865  MOZ_ASSERT_UNREACHABLE("Unknown generic font-family!");
   1866  return aName.AppendLiteral("serif");
   1867 }
   1868 
   1869 StyleFontFamilyList StyleFontFamilyList::WithNames(
   1870    nsTArray<StyleSingleFontFamily>&& aNames) {
   1871  StyleFontFamilyList list;
   1872  Servo_FontFamilyList_WithNames(&aNames, &list);
   1873  return list;
   1874 }
   1875 
   1876 StyleFontFamilyList StyleFontFamilyList::WithOneUnquotedFamily(
   1877    const nsACString& aName) {
   1878  AutoTArray<StyleSingleFontFamily, 1> names;
   1879  names.AppendElement(StyleSingleFontFamily::FamilyName(
   1880      {StyleAtom(NS_Atomize(aName)), StyleFontFamilyNameSyntax::Identifiers}));
   1881  return WithNames(std::move(names));
   1882 }
   1883 
   1884 static bool AnchorSideUsesCBWM(
   1885    const StyleAnchorSideKeyword& aAnchorSideKeyword) {
   1886  switch (aAnchorSideKeyword) {
   1887    case StyleAnchorSideKeyword::SelfStart:
   1888    case StyleAnchorSideKeyword::SelfEnd:
   1889      return false;
   1890    case StyleAnchorSideKeyword::Inside:
   1891    case StyleAnchorSideKeyword::Outside:
   1892    case StyleAnchorSideKeyword::Start:
   1893    case StyleAnchorSideKeyword::End:
   1894    case StyleAnchorSideKeyword::Center:
   1895      return true;
   1896    // Return value shouldn't matter for these physical keywords.
   1897    case StyleAnchorSideKeyword::Left:
   1898    case StyleAnchorSideKeyword::Right:
   1899    case StyleAnchorSideKeyword::Top:
   1900    case StyleAnchorSideKeyword::Bottom:
   1901      return true;
   1902  }
   1903  return false;
   1904 }
   1905 
   1906 bool Gecko_GetAnchorPosOffset(const AnchorPosOffsetResolutionParams* aParams,
   1907                              const nsAtom* aAnchorName,
   1908                              StylePhysicalSide aPropSide,
   1909                              StyleAnchorSideKeyword aAnchorSideKeyword,
   1910                              float aPercentage, Length* aOut) {
   1911  if (!aParams || !aParams->mBaseParams.mFrame) {
   1912    return false;
   1913  }
   1914  const auto* positioned = aParams->mBaseParams.mFrame;
   1915  const auto* containingBlock = positioned->GetParent();
   1916  auto* cache = aParams->mBaseParams.mCache;
   1917  const auto info = AnchorPositioningUtils::ResolveAnchorPosRect(
   1918      positioned, containingBlock, aAnchorName, !aParams->mCBSize, cache);
   1919  if (!info) {
   1920    return false;
   1921  }
   1922  if (cache) {
   1923    // Cache is set during reflow, which is really the only time we want to
   1924    // actively modify scroll compensation state & side.
   1925    if (info->mCompensatesForScroll) {
   1926      const auto axis = [aPropSide]() {
   1927        switch (aPropSide) {
   1928          case StylePhysicalSide::Left:
   1929          case StylePhysicalSide::Right:
   1930            return PhysicalAxis::Horizontal;
   1931          case StylePhysicalSide::Top:
   1932          case StylePhysicalSide::Bottom:
   1933            break;
   1934          default:
   1935            MOZ_ASSERT_UNREACHABLE("Unhandled side?");
   1936        }
   1937        return PhysicalAxis::Vertical;
   1938      }();
   1939      cache->mReferenceData->AdjustCompensatingForScroll(axis);
   1940      // Non scroll-compensated anchor will not have any impact on the
   1941      // containing block due to scrolling. See documentation for
   1942      // `mScrollCompensatedSides`.
   1943      cache->mReferenceData->mScrollCompensatedSides |=
   1944          SideToSideBit(ToSide(aPropSide));
   1945    }
   1946  }
   1947  // Compute the offset here in C++, where translating between physical/logical
   1948  // coordinates is easier.
   1949 
   1950  const auto usesCBWM = AnchorSideUsesCBWM(aAnchorSideKeyword);
   1951  const auto cbwm = containingBlock->GetWritingMode();
   1952  const auto wm =
   1953      usesCBWM ? aParams->mBaseParams.mFrame->GetWritingMode() : cbwm;
   1954  const auto [rect, logicalCBSize] = [&] {
   1955    // We need `AnchorPosReferenceData` to compute the anchor offset against
   1956    // the adjusted CB, so make the best attempt to retrieve it.
   1957    // TODO(dshin, bug 2005207): We really need to unify containing block
   1958    // lookups and clean up cache lookups here.
   1959    const auto* referenceData =
   1960        cache ? cache->mReferenceData
   1961              : positioned->GetProperty(nsIFrame::AnchorPosReferences());
   1962    if (!referenceData) {
   1963      return std::make_pair(
   1964          info->mRect, aParams->mCBSize ? aParams->mCBSize->ConvertTo(wm, cbwm)
   1965                                        : containingBlock->PaddingSize(wm));
   1966    }
   1967    // Offset happens from padding rect.
   1968    const auto offset = referenceData->mAdjustedContainingBlock.TopLeft() -
   1969                        referenceData->mOriginalContainingBlockRect.TopLeft();
   1970    return std::make_pair(
   1971        info->mRect - offset,
   1972        aParams->mCBSize
   1973            ? aParams->mCBSize->ConvertTo(wm, cbwm)
   1974            : LogicalSize{cbwm, referenceData->mAdjustedContainingBlock.Size()}
   1975                  .ConvertTo(wm, cbwm));
   1976  }();
   1977  const LogicalRect logicalAnchorRect{wm, rect,
   1978                                      logicalCBSize.GetPhysicalSize(wm)};
   1979  const auto logicalPropSide = wm.LogicalSideForPhysicalSide(ToSide(aPropSide));
   1980  const auto propAxis = GetAxis(logicalPropSide);
   1981  const auto propEdge = GetEdge(logicalPropSide);
   1982 
   1983  const auto anchorEdge = [&]() {
   1984    switch (aAnchorSideKeyword) {
   1985      case StyleAnchorSideKeyword::Left:
   1986        return GetEdge(wm.LogicalSideForPhysicalSide(eSideLeft));
   1987      case StyleAnchorSideKeyword::Right:
   1988        return GetEdge(wm.LogicalSideForPhysicalSide(eSideRight));
   1989      case StyleAnchorSideKeyword::Top:
   1990        return GetEdge(wm.LogicalSideForPhysicalSide(eSideTop));
   1991      case StyleAnchorSideKeyword::Bottom:
   1992        return GetEdge(wm.LogicalSideForPhysicalSide(eSideBottom));
   1993      case StyleAnchorSideKeyword::Inside:
   1994        return propEdge;
   1995      case StyleAnchorSideKeyword::Outside:
   1996        return GetOppositeEdge(propEdge);
   1997      case StyleAnchorSideKeyword::Start:
   1998      case StyleAnchorSideKeyword::SelfStart:
   1999      case StyleAnchorSideKeyword::Center:
   2000        return LogicalEdge::Start;
   2001      case StyleAnchorSideKeyword::End:
   2002      case StyleAnchorSideKeyword::SelfEnd:
   2003        return LogicalEdge::End;
   2004    }
   2005    return LogicalEdge::Start;
   2006  }();
   2007 
   2008  nscoord result = [&]() {
   2009    // Offset to the desired anchor edge, from the containing block's start
   2010    // edge.
   2011    const auto anchorOffsetFromStartEdge =
   2012        anchorEdge == LogicalEdge::Start ? logicalAnchorRect.Start(propAxis, wm)
   2013                                         : logicalAnchorRect.End(propAxis, wm);
   2014    if (propEdge == LogicalEdge::Start) {
   2015      return anchorOffsetFromStartEdge;
   2016    }
   2017    // Need the offset from the end edge of the containing block.
   2018    const auto anchorOffsetFromEndEdge =
   2019        logicalCBSize.Size(propAxis, wm) - anchorOffsetFromStartEdge;
   2020    return anchorOffsetFromEndEdge;
   2021  }();
   2022 
   2023  // Apply the percentage value, with the percentage basis as the anchor
   2024  // element's size in the relevant axis.
   2025  if (aPercentage != 0.f) {
   2026    const nscoord anchorSize = LogicalSize{wm, rect.Size()}.Size(propAxis, wm);
   2027    result += (propEdge == LogicalEdge::End ? -1 : 1) *
   2028              ((aPercentage != 1.f)
   2029                   ? NSToCoordRoundWithClamp(aPercentage *
   2030                                             static_cast<float>(anchorSize))
   2031                   : anchorSize);
   2032  }
   2033  *aOut = Length::FromPixels(CSSPixel::FromAppUnits(result));
   2034  return true;
   2035 }
   2036 
   2037 bool Gecko_GetAnchorPosSize(const AnchorPosResolutionParams* aParams,
   2038                            const nsAtom* aAnchorName,
   2039                            StylePhysicalAxis aPropAxis,
   2040                            StyleAnchorSizeKeyword aAnchorSizeKeyword,
   2041                            Length* aOut) {
   2042  if (!aParams || !aParams->mFrame) {
   2043    return false;
   2044  }
   2045  const auto* positioned = aParams->mFrame;
   2046  const auto size = AnchorPositioningUtils::ResolveAnchorPosSize(
   2047      positioned, aAnchorName, aParams->mCache);
   2048  if (!size) {
   2049    return false;
   2050  }
   2051  const auto* containingBlock = positioned->GetParent();
   2052  const auto l = [&]() {
   2053    switch (aAnchorSizeKeyword) {
   2054      case StyleAnchorSizeKeyword::None:
   2055        switch (aPropAxis) {
   2056          case StylePhysicalAxis::Horizontal:
   2057            return size->Width();
   2058          case StylePhysicalAxis::Vertical:
   2059            return size->Height();
   2060        }
   2061        MOZ_ASSERT_UNREACHABLE("Unexpected physical axis.");
   2062        return size->Width();
   2063      case StyleAnchorSizeKeyword::Width:
   2064        return size->Width();
   2065      case StyleAnchorSizeKeyword::Height:
   2066        return size->Height();
   2067      case StyleAnchorSizeKeyword::Inline: {
   2068        const auto wm = containingBlock->GetWritingMode();
   2069        return LogicalSize{wm, *size}.ISize(wm);
   2070      }
   2071      case StyleAnchorSizeKeyword::Block: {
   2072        const auto wm = containingBlock->GetWritingMode();
   2073        return LogicalSize{wm, *size}.BSize(wm);
   2074      }
   2075      case StyleAnchorSizeKeyword::SelfInline: {
   2076        const auto wm = positioned->GetWritingMode();
   2077        return LogicalSize{wm, *size}.ISize(wm);
   2078      }
   2079      case StyleAnchorSizeKeyword::SelfBlock: {
   2080        const auto wm = positioned->GetWritingMode();
   2081        return LogicalSize{wm, *size}.BSize(wm);
   2082      }
   2083    }
   2084    MOZ_ASSERT_UNREACHABLE("Unhandled anchor size keyword.");
   2085    return size->Width();
   2086  }();
   2087  *aOut = Length::FromPixels(CSSPixel::FromAppUnits(l));
   2088  return true;
   2089 }