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/. */
7 /* FFI functions for Servo to call into Gecko */
9 #include "mozilla/GeckoBindings.h"
11 #include "ChildIterator.h"
12 #include "ErrorReporter.h"
13 #include "gfxFontFeatures.h"
14 #include "gfxMathTable.h"
15 #include "gfxTextRun.h"
16 #include "imgLoader.h"
17 #include "nsAnimationManager.h"
18 #include "nsAttrValueInlines.h"
19 #include "nsCSSFrameConstructor.h"
20 #include "nsCSSProps.h"
21 #include "nsCSSPseudoElements.h"
22 #include "nsContentUtils.h"
23 #include "nsDOMTokenList.h"
24 #include "nsDeviceContext.h"
25 #include "nsLayoutUtils.h"
26 #include "nsIContentInlines.h"
27 #include "mozilla/dom/DocumentInlines.h"
28 #include "nsILoadContext.h"
30 #include "nsIMozBrowserFrame.h"
33 #include "nsFontMetrics.h"
34 #include "nsNameSpaceManager.h"
35 #include "nsNetUtil.h"
36 #include "nsProxyRelease.h"
38 #include "nsStyleStruct.h"
39 #include "nsStyleUtil.h"
41 #include "nsTransitionManager.h"
42 #include "nsWindowSizes.h"
44 #include "mozilla/css/ImageLoader.h"
45 #include "mozilla/DeclarationBlock.h"
46 #include "mozilla/AttributeStyles.h"
47 #include "mozilla/EffectCompositor.h"
48 #include "mozilla/EffectSet.h"
49 #include "mozilla/FontPropertyTypes.h"
50 #include "mozilla/Hal.h"
51 #include "mozilla/Keyframe.h"
52 #include "mozilla/Mutex.h"
53 #include "mozilla/Preferences.h"
54 #include "mozilla/ServoElementSnapshot.h"
55 #include "mozilla/ShadowParts.h"
56 #include "mozilla/StaticPresData.h"
57 #include "mozilla/StaticPrefs_browser.h"
58 #include "mozilla/StaticPrefs_layout.h"
59 #include "mozilla/StaticPtr.h"
60 #include "mozilla/RestyleManager.h"
61 #include "mozilla/SizeOfState.h"
62 #include "mozilla/StyleAnimationValue.h"
63 #include "mozilla/ServoBindings.h"
64 #include "mozilla/ServoTraversalStatistics.h"
65 #include "mozilla/Telemetry.h"
66 #include "mozilla/TimelineManager.h"
67 #include "mozilla/RWLock.h"
68 #include "mozilla/dom/Element.h"
69 #include "mozilla/dom/ElementInlines.h"
70 #include "mozilla/dom/HTMLImageElement.h"
71 #include "mozilla/dom/HTMLTableCellElement.h"
72 #include "mozilla/dom/HTMLBodyElement.h"
73 #include "mozilla/dom/HTMLSelectElement.h"
74 #include "mozilla/dom/HTMLSlotElement.h"
75 #include "mozilla/dom/MediaList.h"
76 #include "mozilla/dom/ReferrerInfo.h"
77 #include "mozilla/dom/SVGElement.h"
78 #include "mozilla/dom/WorkerCommon.h"
79 #include "mozilla/LookAndFeel.h"
80 #include "mozilla/URLExtraData.h"
81 #include "mozilla/dom/CSSMozDocumentRule.h"
83 #if defined(MOZ_MEMORY)
84 # include "mozmemory.h"
87 using namespace mozilla
;
88 using namespace mozilla::css
;
89 using namespace mozilla::dom
;
91 // Definitions of the global traversal stats.
92 bool ServoTraversalStatistics::sActive
= false;
93 ServoTraversalStatistics
ServoTraversalStatistics::sSingleton
;
95 static StaticAutoPtr
<RWLock
> sServoFFILock
;
97 static const LangGroupFontPrefs
* ThreadSafeGetLangGroupFontPrefs(
98 const Document
& aDocument
, nsAtom
* aLanguage
) {
99 bool needsCache
= false;
101 AutoReadLock
guard(*sServoFFILock
);
102 if (auto* prefs
= aDocument
.GetFontPrefsForLang(aLanguage
, &needsCache
)) {
106 MOZ_ASSERT(needsCache
);
107 AutoWriteLock
guard(*sServoFFILock
);
108 return aDocument
.GetFontPrefsForLang(aLanguage
);
111 static const nsFont
& ThreadSafeGetDefaultVariableFont(const Document
& aDocument
,
113 return ThreadSafeGetLangGroupFontPrefs(aDocument
, aLanguage
)
114 ->mDefaultVariableFont
;
118 * Does this child count as significant for selector matching?
120 * See nsStyleUtil::IsSignificantChild for details.
122 bool Gecko_IsSignificantChild(const nsINode
* aNode
,
123 bool aWhitespaceIsSignificant
) {
124 return nsStyleUtil::ThreadSafeIsSignificantChild(aNode
->AsContent(),
125 aWhitespaceIsSignificant
);
128 const nsINode
* Gecko_GetLastChild(const nsINode
* aNode
) {
129 return aNode
->GetLastChild();
132 const nsINode
* Gecko_GetFlattenedTreeParentNode(const nsINode
* aNode
) {
133 return aNode
->GetFlattenedTreeParentNodeForStyle();
136 const Element
* Gecko_GetBeforeOrAfterPseudo(const Element
* aElement
,
138 MOZ_ASSERT(aElement
);
139 MOZ_ASSERT(aElement
->HasProperties());
141 return aIsBefore
? nsLayoutUtils::GetBeforePseudo(aElement
)
142 : nsLayoutUtils::GetAfterPseudo(aElement
);
145 const Element
* Gecko_GetMarkerPseudo(const Element
* aElement
) {
146 MOZ_ASSERT(aElement
);
147 MOZ_ASSERT(aElement
->HasProperties());
149 return nsLayoutUtils::GetMarkerPseudo(aElement
);
152 nsTArray
<nsIContent
*>* Gecko_GetAnonymousContentForElement(
153 const Element
* aElement
) {
154 nsIAnonymousContentCreator
* ac
= do_QueryFrame(aElement
->GetPrimaryFrame());
159 auto* array
= new nsTArray
<nsIContent
*>();
160 nsContentUtils::AppendNativeAnonymousChildren(aElement
, *array
, 0);
164 void Gecko_DestroyAnonymousContentList(nsTArray
<nsIContent
*>* aAnonContent
) {
165 MOZ_ASSERT(aAnonContent
);
169 const nsTArray
<RefPtr
<nsINode
>>* Gecko_GetAssignedNodes(
170 const Element
* aElement
) {
171 MOZ_ASSERT(HTMLSlotElement::FromNode(aElement
));
172 return &static_cast<const HTMLSlotElement
*>(aElement
)->AssignedNodes();
175 void Gecko_GetQueryContainerSize(const Element
* aElement
, nscoord
* aOutWidth
,
176 nscoord
* aOutHeight
) {
177 MOZ_ASSERT(aElement
);
178 const nsIFrame
* frame
= aElement
->GetPrimaryFrame();
182 const auto containAxes
= frame
->GetContainSizeAxes();
183 if (!containAxes
.IsAny()) {
186 nsSize size
= frame
->GetContentRectRelativeToSelf().Size();
187 bool isVertical
= frame
->GetWritingMode().IsVertical();
188 if (isVertical
? containAxes
.mBContained
: containAxes
.mIContained
) {
189 *aOutWidth
= size
.width
;
191 if (isVertical
? containAxes
.mIContained
: containAxes
.mBContained
) {
192 *aOutHeight
= size
.height
;
196 void Gecko_ComputedStyle_Init(ComputedStyle
* aStyle
,
197 const ServoComputedData
* aValues
,
198 PseudoStyleType aPseudoType
) {
199 new (KnownNotNull
, aStyle
)
200 ComputedStyle(aPseudoType
, ServoComputedDataForgotten(aValues
));
203 ServoComputedData::ServoComputedData(const ServoComputedDataForgotten aValue
) {
204 PodAssign(this, aValue
.mPtr
);
207 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleStructsMallocEnclosingSizeOf
)
209 void ServoComputedData::AddSizeOfExcludingThis(nsWindowSizes
& aSizes
) const {
210 // Note: GetStyleFoo() returns a pointer to an nsStyleFoo that sits within a
211 // servo_arc::Arc, i.e. it is preceded by a word-sized refcount. So we need
212 // to measure it with a function that can handle an interior pointer. We use
213 // ServoStyleStructsEnclosingMallocSizeOf to clearly identify in DMD's
214 // output the memory measured here.
215 #define STYLE_STRUCT(name_) \
216 static_assert(alignof(nsStyle##name_) <= sizeof(size_t), \
217 "alignment will break AddSizeOfExcludingThis()"); \
218 const void* p##name_ = Style##name_(); \
219 if (!aSizes.mState.HaveSeenPtr(p##name_)) { \
220 aSizes.mStyleSizes.NS_STYLE_SIZES_FIELD(name_) += \
221 ServoStyleStructsMallocEnclosingSizeOf(p##name_); \
223 #include "nsStyleStructList.h"
226 if (visited_style
&& !aSizes
.mState
.HaveSeenPtr(visited_style
)) {
227 visited_style
->AddSizeOfIncludingThis(aSizes
,
228 &aSizes
.mLayoutComputedValuesVisited
);
231 // Measurement of the following members may be added later if DMD finds it is
233 // - custom_properties
236 // - font_computation_data
239 void Gecko_ComputedStyle_Destroy(ComputedStyle
* aStyle
) {
240 aStyle
->~ComputedStyle();
243 void Gecko_ConstructStyleChildrenIterator(const Element
* aElement
,
244 StyleChildrenIterator
* aIterator
) {
245 MOZ_ASSERT(aElement
);
246 MOZ_ASSERT(aIterator
);
247 new (aIterator
) StyleChildrenIterator(aElement
);
250 void Gecko_DestroyStyleChildrenIterator(StyleChildrenIterator
* aIterator
) {
251 MOZ_ASSERT(aIterator
);
253 aIterator
->~StyleChildrenIterator();
256 const nsINode
* Gecko_GetNextStyleChild(StyleChildrenIterator
* aIterator
) {
257 MOZ_ASSERT(aIterator
);
258 return aIterator
->GetNextChild();
261 bool Gecko_VisitedStylesEnabled(const Document
* aDoc
) {
263 MOZ_ASSERT(NS_IsMainThread());
265 if (!StaticPrefs::layout_css_visited_links_enabled()) {
269 if (aDoc
->IsBeingUsedAsImage()) {
273 nsILoadContext
* loadContext
= aDoc
->GetLoadContext();
274 if (loadContext
&& loadContext
->UsePrivateBrowsing()) {
281 ElementState::InternalType
Gecko_ElementState(const Element
* aElement
) {
282 return aElement
->StyleState().GetInternalValue();
285 bool Gecko_IsRootElement(const Element
* aElement
) {
286 return aElement
->OwnerDoc()->GetRootElement() == aElement
;
289 void Gecko_NoteDirtyElement(const Element
* aElement
) {
290 MOZ_ASSERT(NS_IsMainThread());
291 const_cast<Element
*>(aElement
)->NoteDirtyForServo();
294 void Gecko_NoteDirtySubtreeForInvalidation(const Element
* aElement
) {
295 MOZ_ASSERT(NS_IsMainThread());
296 const_cast<Element
*>(aElement
)->NoteDirtySubtreeForServo();
299 void Gecko_NoteAnimationOnlyDirtyElement(const Element
* aElement
) {
300 MOZ_ASSERT(NS_IsMainThread());
301 const_cast<Element
*>(aElement
)->NoteAnimationOnlyDirtyForServo();
304 bool Gecko_AnimationNameMayBeReferencedFromStyle(
305 const nsPresContext
* aPresContext
, nsAtom
* aName
) {
306 MOZ_ASSERT(aPresContext
);
307 return aPresContext
->AnimationManager()->AnimationMayBeReferenced(aName
);
310 float Gecko_GetScrollbarInlineSize(const nsPresContext
* aPc
) {
312 AutoWriteLock
guard(*sServoFFILock
); // We read some look&feel values.
313 auto overlay
= aPc
->UseOverlayScrollbars() ? nsITheme::Overlay::Yes
314 : nsITheme::Overlay::No
;
315 LayoutDeviceIntCoord size
=
316 aPc
->Theme()->GetScrollbarSize(aPc
, StyleScrollbarWidth::Auto
, overlay
);
317 return aPc
->DevPixelsToFloatCSSPixels(size
);
320 PseudoStyleType
Gecko_GetImplementedPseudo(const Element
* aElement
) {
321 return aElement
->GetPseudoElementType();
324 uint32_t Gecko_CalcStyleDifference(const ComputedStyle
* aOldStyle
,
325 const ComputedStyle
* aNewStyle
,
326 bool* aAnyStyleStructChanged
,
327 bool* aOnlyResetStructsChanged
) {
328 MOZ_ASSERT(aOldStyle
);
329 MOZ_ASSERT(aNewStyle
);
331 uint32_t equalStructs
;
332 nsChangeHint result
=
333 aOldStyle
->CalcStyleDifference(*aNewStyle
, &equalStructs
);
335 *aAnyStyleStructChanged
=
336 equalStructs
!= StyleStructConstants::kAllStructsMask
;
338 const auto kInheritedStructsMask
=
339 StyleStructConstants::kInheritedStructsMask
;
340 *aOnlyResetStructsChanged
=
341 (equalStructs
& kInheritedStructsMask
) == kInheritedStructsMask
;
346 nscoord
Gecko_CalcLineHeight(const StyleLineHeight
* aLh
,
347 const nsPresContext
* aPc
, bool aVertical
,
348 const nsStyleFont
* aAgainstFont
,
349 const mozilla::dom::Element
* aElement
) {
350 // Normal line-height depends on font metrics.
351 AutoWriteLock
guard(*sServoFFILock
);
352 return ReflowInput::CalcLineHeight(*aLh
, *aAgainstFont
,
353 const_cast<nsPresContext
*>(aPc
), aVertical
,
354 aElement
, NS_UNCONSTRAINEDSIZE
, 1.0f
);
357 const ServoElementSnapshot
* Gecko_GetElementSnapshot(
358 const ServoElementSnapshotTable
* aTable
, const Element
* aElement
) {
360 MOZ_ASSERT(aElement
);
362 return aTable
->Get(const_cast<Element
*>(aElement
));
365 bool Gecko_HaveSeenPtr(SeenPtrs
* aTable
, const void* aPtr
) {
366 MOZ_ASSERT(NS_IsMainThread());
368 // Empty Rust allocations are indicated by small values up to the alignment
369 // of the relevant type. We shouldn't see anything like that here.
370 MOZ_ASSERT(uintptr_t(aPtr
) > 16);
372 return aTable
->HaveSeenPtr(aPtr
);
375 const StyleLockedDeclarationBlock
* Gecko_GetStyleAttrDeclarationBlock(
376 const Element
* aElement
) {
377 DeclarationBlock
* decl
= aElement
->GetInlineStyleDeclaration();
384 void Gecko_UnsetDirtyStyleAttr(const Element
* aElement
) {
385 DeclarationBlock
* decl
= aElement
->GetInlineStyleDeclaration();
392 const StyleLockedDeclarationBlock
*
393 Gecko_GetHTMLPresentationAttrDeclarationBlock(const Element
* aElement
) {
394 return aElement
->GetMappedAttributeStyle();
397 const StyleLockedDeclarationBlock
* Gecko_GetExtraContentStyleDeclarations(
398 const Element
* aElement
) {
399 if (const auto* cell
= HTMLTableCellElement::FromNode(aElement
)) {
400 return cell
->GetMappedAttributesInheritedFromTable();
402 if (const auto* img
= HTMLImageElement::FromNode(aElement
)) {
403 return img
->GetMappedAttributesFromSource();
408 const StyleLockedDeclarationBlock
* Gecko_GetUnvisitedLinkAttrDeclarationBlock(
409 const Element
* aElement
) {
410 AttributeStyles
* attrStyles
= aElement
->OwnerDoc()->GetAttributeStyles();
415 return attrStyles
->GetServoUnvisitedLinkDecl();
418 StyleSheet
* Gecko_StyleSheet_Clone(const StyleSheet
* aSheet
,
419 const StyleSheet
* aNewParentSheet
) {
421 MOZ_ASSERT(aSheet
->GetParentSheet(), "Should only be used for @import");
422 MOZ_ASSERT(aNewParentSheet
, "Wat");
424 RefPtr
<StyleSheet
> newSheet
= aSheet
->Clone(nullptr, nullptr);
426 // NOTE(emilio): This code runs in the StylesheetInner constructor, which
427 // means that the inner pointer of `aNewParentSheet` still points to the old
430 // So we _don't_ update neither the parent pointer of the stylesheet, nor the
431 // child list (yet). This is fixed up in that same constructor.
432 return static_cast<StyleSheet
*>(newSheet
.forget().take());
435 void Gecko_StyleSheet_AddRef(const StyleSheet
* aSheet
) {
436 MOZ_ASSERT(NS_IsMainThread());
437 const_cast<StyleSheet
*>(aSheet
)->AddRef();
440 void Gecko_StyleSheet_Release(const StyleSheet
* aSheet
) {
441 MOZ_ASSERT(NS_IsMainThread());
442 const_cast<StyleSheet
*>(aSheet
)->Release();
445 const StyleLockedDeclarationBlock
* Gecko_GetVisitedLinkAttrDeclarationBlock(
446 const Element
* aElement
) {
447 AttributeStyles
* attrStyles
= aElement
->OwnerDoc()->GetAttributeStyles();
451 return attrStyles
->GetServoVisitedLinkDecl();
454 const StyleLockedDeclarationBlock
* Gecko_GetActiveLinkAttrDeclarationBlock(
455 const Element
* aElement
) {
456 AttributeStyles
* attrStyles
= aElement
->OwnerDoc()->GetAttributeStyles();
460 return attrStyles
->GetServoActiveLinkDecl();
463 bool Gecko_GetAnimationRule(const Element
* aElement
,
464 EffectCompositor::CascadeLevel aCascadeLevel
,
465 StyleAnimationValueMap
* aAnimationValues
) {
466 MOZ_ASSERT(aElement
);
468 Document
* doc
= aElement
->GetComposedDoc();
472 nsPresContext
* presContext
= doc
->GetPresContext();
477 const auto [element
, pseudoType
] =
478 AnimationUtils::GetElementPseudoPair(aElement
);
479 return presContext
->EffectCompositor()->GetServoAnimationRule(
480 element
, pseudoType
, aCascadeLevel
, aAnimationValues
);
483 bool Gecko_StyleAnimationsEquals(const nsStyleAutoArray
<StyleAnimation
>* aA
,
484 const nsStyleAutoArray
<StyleAnimation
>* aB
) {
488 bool Gecko_StyleScrollTimelinesEquals(
489 const nsStyleAutoArray
<StyleScrollTimeline
>* aA
,
490 const nsStyleAutoArray
<StyleScrollTimeline
>* aB
) {
494 bool Gecko_StyleViewTimelinesEquals(
495 const nsStyleAutoArray
<StyleViewTimeline
>* aA
,
496 const nsStyleAutoArray
<StyleViewTimeline
>* aB
) {
500 void Gecko_CopyAnimationNames(nsStyleAutoArray
<StyleAnimation
>* aDest
,
501 const nsStyleAutoArray
<StyleAnimation
>* aSrc
) {
502 size_t srcLength
= aSrc
->Length();
503 aDest
->EnsureLengthAtLeast(srcLength
);
505 for (size_t index
= 0; index
< srcLength
; index
++) {
506 (*aDest
)[index
].SetName((*aSrc
)[index
].GetName());
510 void Gecko_SetAnimationName(StyleAnimation
* aStyleAnimation
, nsAtom
* aAtom
) {
511 MOZ_ASSERT(aStyleAnimation
);
512 aStyleAnimation
->SetName(already_AddRefed
<nsAtom
>(aAtom
));
515 void Gecko_UpdateAnimations(const Element
* aElement
,
516 const ComputedStyle
* aOldComputedData
,
517 const ComputedStyle
* aComputedData
,
518 UpdateAnimationsTasks aTasks
) {
519 MOZ_ASSERT(NS_IsMainThread());
520 MOZ_ASSERT(aElement
);
522 if (!aElement
->IsInComposedDoc()) {
526 nsPresContext
* presContext
= nsContentUtils::GetContextForContent(aElement
);
527 if (!presContext
|| !presContext
->IsDynamic()) {
531 nsAutoAnimationMutationBatch
mb(aElement
->OwnerDoc());
533 const auto [element
, pseudoType
] =
534 AnimationUtils::GetElementPseudoPair(aElement
);
536 // Handle scroll/view timelines first because CSS animations may refer to the
537 // timeline defined by itself.
538 if (aTasks
& UpdateAnimationsTasks::ScrollTimelines
) {
539 presContext
->TimelineManager()->UpdateTimelines(
540 const_cast<Element
*>(element
), pseudoType
, aComputedData
,
541 TimelineManager::ProgressTimelineType::Scroll
);
544 if (aTasks
& UpdateAnimationsTasks::ViewTimelines
) {
545 presContext
->TimelineManager()->UpdateTimelines(
546 const_cast<Element
*>(element
), pseudoType
, aComputedData
,
547 TimelineManager::ProgressTimelineType::View
);
550 if (aTasks
& UpdateAnimationsTasks::CSSAnimations
) {
551 presContext
->AnimationManager()->UpdateAnimations(
552 const_cast<Element
*>(element
), pseudoType
, aComputedData
);
555 // aComputedData might be nullptr if the target element is now in a
556 // display:none subtree. We still call Gecko_UpdateAnimations in this case
557 // because we need to stop CSS animations in the display:none subtree.
558 // However, we don't need to update transitions since they are stopped by
559 // RestyleManager::AnimationsWithDestroyedFrame so we just return early
561 if (!aComputedData
) {
565 if (aTasks
& UpdateAnimationsTasks::CSSTransitions
) {
566 MOZ_ASSERT(aOldComputedData
);
567 presContext
->TransitionManager()->UpdateTransitions(
568 const_cast<Element
*>(element
), pseudoType
, *aOldComputedData
,
572 if (aTasks
& UpdateAnimationsTasks::EffectProperties
) {
573 presContext
->EffectCompositor()->UpdateEffectProperties(
574 aComputedData
, const_cast<Element
*>(element
), pseudoType
);
577 if (aTasks
& UpdateAnimationsTasks::CascadeResults
) {
578 EffectSet
* effectSet
= EffectSet::Get(element
, pseudoType
);
579 // CSS animations/transitions might have been destroyed as part of the above
580 // steps so before updating cascade results, we check if there are still any
581 // animations to update.
583 // We call UpdateCascadeResults directly (intead of
584 // MaybeUpdateCascadeResults) since we know for sure that the cascade has
585 // changed, but we were unable to call MarkCascadeUpdated when we noticed
586 // it since we avoid mutating state as part of the Servo parallel
588 presContext
->EffectCompositor()->UpdateCascadeResults(
589 *effectSet
, const_cast<Element
*>(element
), pseudoType
);
593 if (aTasks
& UpdateAnimationsTasks::DisplayChangedFromNone
) {
594 presContext
->EffectCompositor()->RequestRestyle(
595 const_cast<Element
*>(element
), pseudoType
,
596 EffectCompositor::RestyleType::Standard
,
597 EffectCompositor::CascadeLevel::Animations
);
601 size_t Gecko_GetAnimationEffectCount(const Element
* aElementOrPseudo
) {
602 const auto [element
, pseudoType
] =
603 AnimationUtils::GetElementPseudoPair(aElementOrPseudo
);
605 EffectSet
* effectSet
= EffectSet::Get(element
, pseudoType
);
606 return effectSet
? effectSet
->Count() : 0;
609 bool Gecko_ElementHasAnimations(const Element
* aElement
) {
610 const auto [element
, pseudoType
] =
611 AnimationUtils::GetElementPseudoPair(aElement
);
612 return !!EffectSet::Get(element
, pseudoType
);
615 bool Gecko_ElementHasCSSAnimations(const Element
* aElement
) {
616 const auto [element
, pseudoType
] =
617 AnimationUtils::GetElementPseudoPair(aElement
);
619 nsAnimationManager::CSSAnimationCollection::Get(element
, pseudoType
);
620 return collection
&& !collection
->mAnimations
.IsEmpty();
623 bool Gecko_ElementHasCSSTransitions(const Element
* aElement
) {
624 const auto [element
, pseudoType
] =
625 AnimationUtils::GetElementPseudoPair(aElement
);
627 nsTransitionManager::CSSTransitionCollection::Get(element
, pseudoType
);
628 return collection
&& !collection
->mAnimations
.IsEmpty();
631 size_t Gecko_ElementTransitions_Length(const Element
* aElement
) {
632 const auto [element
, pseudoType
] =
633 AnimationUtils::GetElementPseudoPair(aElement
);
635 nsTransitionManager::CSSTransitionCollection::Get(element
, pseudoType
);
636 return collection
? collection
->mAnimations
.Length() : 0;
639 static CSSTransition
* GetCurrentTransitionAt(const Element
* aElement
,
641 const auto [element
, pseudoType
] =
642 AnimationUtils::GetElementPseudoPair(aElement
);
644 nsTransitionManager::CSSTransitionCollection ::Get(element
, pseudoType
);
648 return collection
->mAnimations
.SafeElementAt(aIndex
);
651 nsCSSPropertyID
Gecko_ElementTransitions_PropertyAt(const Element
* aElement
,
653 CSSTransition
* transition
= GetCurrentTransitionAt(aElement
, aIndex
);
654 return transition
? transition
->TransitionProperty()
655 : nsCSSPropertyID::eCSSProperty_UNKNOWN
;
658 const StyleAnimationValue
* Gecko_ElementTransitions_EndValueAt(
659 const Element
* aElement
, size_t aIndex
) {
660 CSSTransition
* transition
= GetCurrentTransitionAt(aElement
, aIndex
);
661 return transition
? transition
->ToValue().mServo
.get() : nullptr;
664 double Gecko_GetProgressFromComputedTiming(const ComputedTiming
* aTiming
) {
665 return aTiming
->mProgress
.Value();
668 double Gecko_GetPositionInSegment(const AnimationPropertySegment
* aSegment
,
669 double aProgress
, bool aBeforeFlag
) {
670 MOZ_ASSERT(aSegment
->mFromKey
< aSegment
->mToKey
,
671 "The segment from key should be less than to key");
673 double positionInSegment
= (aProgress
- aSegment
->mFromKey
) /
674 // To avoid floating precision inaccuracies, make
675 // sure we calculate both the numerator and
676 // denominator using double precision.
677 (double(aSegment
->mToKey
) - aSegment
->mFromKey
);
679 return StyleComputedTimingFunction::GetPortion(
680 aSegment
->mTimingFunction
, positionInSegment
, aBeforeFlag
);
683 const StyleAnimationValue
* Gecko_AnimationGetBaseStyle(
684 const RawServoAnimationValueTable
* aBaseStyles
, nsCSSPropertyID aProperty
) {
685 auto base
= reinterpret_cast<
686 const nsRefPtrHashtable
<nsUint32HashKey
, StyleAnimationValue
>*>(
688 return base
->GetWeak(aProperty
);
691 void Gecko_FillAllImageLayers(nsStyleImageLayers
* aLayers
, uint32_t aMaxLen
) {
692 aLayers
->FillAllLayers(aMaxLen
);
695 bool Gecko_IsDocumentBody(const Element
* aElement
) {
696 Document
* doc
= aElement
->GetUncomposedDoc();
697 return doc
&& doc
->GetBodyElement() == aElement
;
700 bool Gecko_IsDarkColorScheme(const Document
* aDoc
,
701 const StyleColorScheme
* aStyle
) {
702 return LookAndFeel::ColorSchemeForStyle(*aDoc
, aStyle
->bits
) ==
706 nscolor
Gecko_ComputeSystemColor(StyleSystemColor aColor
, const Document
* aDoc
,
707 const StyleColorScheme
* aStyle
) {
708 auto colorScheme
= LookAndFeel::ColorSchemeForStyle(*aDoc
, aStyle
->bits
);
710 const auto& colors
= PreferenceSheet::PrefsFor(*aDoc
).ColorsFor(colorScheme
);
712 case StyleSystemColor::Canvastext
:
713 return colors
.mDefault
;
714 case StyleSystemColor::Canvas
:
715 return colors
.mDefaultBackground
;
716 case StyleSystemColor::Linktext
:
718 case StyleSystemColor::Activetext
:
719 return colors
.mActiveLink
;
720 case StyleSystemColor::Visitedtext
:
721 return colors
.mVisitedLink
;
726 auto useStandins
= LookAndFeel::ShouldUseStandins(*aDoc
, aColor
);
728 AutoWriteLock
guard(*sServoFFILock
);
729 return LookAndFeel::Color(aColor
, colorScheme
, useStandins
);
732 int32_t Gecko_GetLookAndFeelInt(int32_t aId
) {
733 auto intId
= static_cast<LookAndFeel::IntID
>(aId
);
734 AutoWriteLock
guard(*sServoFFILock
);
735 return LookAndFeel::GetInt(intId
);
738 float Gecko_GetLookAndFeelFloat(int32_t aId
) {
739 auto id
= static_cast<LookAndFeel::FloatID
>(aId
);
740 AutoWriteLock
guard(*sServoFFILock
);
741 return LookAndFeel::GetFloat(id
);
744 bool Gecko_MatchLang(const Element
* aElement
, nsAtom
* aOverrideLang
,
745 bool aHasOverrideLang
, const char16_t
* aValue
) {
746 MOZ_ASSERT(!(aOverrideLang
&& !aHasOverrideLang
),
747 "aHasOverrideLang should only be set when aOverrideLang is null");
748 MOZ_ASSERT(aValue
, "null lang parameter");
749 if (!aValue
|| !*aValue
) {
753 // We have to determine the language of the current element. Since
754 // this is currently no property and since the language is inherited
755 // from the parent we have to be prepared to look at all parent
756 // nodes. The language itself is encoded in the LANG attribute.
757 if (auto* language
= aHasOverrideLang
? aOverrideLang
: aElement
->GetLang()) {
758 return nsStyleUtil::LangTagCompare(nsAtomCString(language
),
759 NS_ConvertUTF16toUTF8(aValue
));
762 // Try to get the language from the HTTP header or if this
763 // is missing as well from the preferences.
764 // The content language can be a comma-separated list of
766 nsAutoString language
;
767 aElement
->OwnerDoc()->GetContentLanguage(language
);
769 NS_ConvertUTF16toUTF8
langString(aValue
);
770 language
.StripWhitespace();
771 for (auto const& lang
: language
.Split(char16_t(','))) {
772 if (nsStyleUtil::LangTagCompare(NS_ConvertUTF16toUTF8(lang
), langString
)) {
779 nsAtom
* Gecko_GetXMLLangValue(const Element
* aElement
) {
780 const nsAttrValue
* attr
=
781 aElement
->GetParsedAttr(nsGkAtoms::lang
, kNameSpaceID_XML
);
787 MOZ_ASSERT(attr
->Type() == nsAttrValue::eAtom
);
789 RefPtr
<nsAtom
> atom
= attr
->GetAtomValue();
790 return atom
.forget().take();
793 const PreferenceSheet::Prefs
* Gecko_GetPrefSheetPrefs(const Document
* aDoc
) {
794 return &PreferenceSheet::PrefsFor(*aDoc
);
797 bool Gecko_IsTableBorderNonzero(const Element
* aElement
) {
798 if (!aElement
->IsHTMLElement(nsGkAtoms::table
)) {
801 const nsAttrValue
* val
= aElement
->GetParsedAttr(nsGkAtoms::border
);
803 (val
->Type() != nsAttrValue::eInteger
|| val
->GetIntegerValue() != 0);
806 bool Gecko_IsBrowserFrame(const Element
* aElement
) {
807 nsIMozBrowserFrame
* browserFrame
=
808 const_cast<Element
*>(aElement
)->GetAsMozBrowserFrame();
809 return browserFrame
&& browserFrame
->GetReallyIsBrowser();
812 bool Gecko_IsSelectListBox(const Element
* aElement
) {
813 const auto* select
= HTMLSelectElement::FromNode(aElement
);
814 return select
&& !select
->IsCombobox();
817 template <typename Implementor
>
818 static nsAtom
* LangValue(Implementor
* aElement
) {
819 // TODO(emilio): Deduplicate a bit with nsIContent::GetLang().
820 const nsAttrValue
* attr
=
821 aElement
->GetParsedAttr(nsGkAtoms::lang
, kNameSpaceID_XML
);
822 if (!attr
&& aElement
->SupportsLangAttr()) {
823 attr
= aElement
->GetParsedAttr(nsGkAtoms::lang
);
830 MOZ_ASSERT(attr
->Type() == nsAttrValue::eAtom
);
831 RefPtr
<nsAtom
> atom
= attr
->GetAtomValue();
832 return atom
.forget().take();
835 bool Gecko_AttrEquals(const nsAttrValue
* aValue
, const nsAtom
* aStr
,
837 return aValue
->Equals(aStr
, aIgnoreCase
? eIgnoreCase
: eCaseMatters
);
840 #define WITH_COMPARATOR(ignore_case_, c_, expr_) \
841 auto c_ = (ignore_case_) ? nsASCIICaseInsensitiveStringComparator \
842 : nsTDefaultStringComparator<char16_t>; \
845 bool Gecko_AttrDashEquals(const nsAttrValue
* aValue
, const nsAtom
* aStr
,
848 aValue
->ToString(str
);
851 nsStyleUtil::DashMatchCompare(str
, nsDependentAtomString(aStr
), c
))
854 bool Gecko_AttrIncludes(const nsAttrValue
* aValue
, const nsAtom
* aStr
,
856 if (aStr
== nsGkAtoms::_empty
) {
860 aValue
->ToString(str
);
863 nsStyleUtil::ValueIncludes(str
, nsDependentAtomString(aStr
), c
))
866 bool Gecko_AttrHasSubstring(const nsAttrValue
* aValue
, const nsAtom
* aStr
,
868 return aStr
!= nsGkAtoms::_empty
&&
869 aValue
->HasSubstring(nsDependentAtomString(aStr
),
870 aIgnoreCase
? eIgnoreCase
: eCaseMatters
);
873 bool Gecko_AttrHasPrefix(const nsAttrValue
* aValue
, const nsAtom
* aStr
,
875 return aStr
!= nsGkAtoms::_empty
&&
876 aValue
->HasPrefix(nsDependentAtomString(aStr
),
877 aIgnoreCase
? eIgnoreCase
: eCaseMatters
);
880 bool Gecko_AttrHasSuffix(const nsAttrValue
* aValue
, const nsAtom
* aStr
,
882 return aStr
!= nsGkAtoms::_empty
&&
883 aValue
->HasSuffix(nsDependentAtomString(aStr
),
884 aIgnoreCase
? eIgnoreCase
: eCaseMatters
);
887 #define SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_) \
888 nsAtom* prefix_##LangValue(implementor_ aElement) { \
889 return LangValue(aElement); \
892 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_
, const Element
*)
893 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot
,
894 const ServoElementSnapshot
*)
896 #undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
898 nsAtom
* Gecko_Atomize(const char* aString
, uint32_t aLength
) {
899 return NS_Atomize(nsDependentCSubstring(aString
, aLength
)).take();
902 nsAtom
* Gecko_Atomize16(const nsAString
* aString
) {
903 return NS_Atomize(*aString
).take();
906 void Gecko_AddRefAtom(nsAtom
* aAtom
) { NS_ADDREF(aAtom
); }
908 void Gecko_ReleaseAtom(nsAtom
* aAtom
) { NS_RELEASE(aAtom
); }
910 void Gecko_nsFont_InitSystem(nsFont
* aDest
, StyleSystemFont aFontId
,
911 const nsStyleFont
* aFont
,
912 const Document
* aDocument
) {
913 const nsFont
& defaultVariableFont
=
914 ThreadSafeGetDefaultVariableFont(*aDocument
, aFont
->mLanguage
);
916 // We have passed uninitialized memory to this function,
917 // initialize it. We can't simply return an nsFont because then
918 // we need to know its size beforehand. Servo cannot initialize nsFont
919 // itself, so this will do.
920 new (aDest
) nsFont(defaultVariableFont
);
922 AutoWriteLock
guard(*sServoFFILock
);
923 nsLayoutUtils::ComputeSystemFont(aDest
, aFontId
, defaultVariableFont
,
927 void Gecko_nsFont_Destroy(nsFont
* aDest
) { aDest
->~nsFont(); }
929 StyleGenericFontFamily
Gecko_nsStyleFont_ComputeFallbackFontTypeForLanguage(
930 const Document
* aDoc
, nsAtom
* aLanguage
) {
931 return ThreadSafeGetLangGroupFontPrefs(*aDoc
, aLanguage
)->GetDefaultGeneric();
934 Length
Gecko_GetBaseSize(const Document
* aDoc
, nsAtom
* aLang
,
935 StyleGenericFontFamily aGeneric
) {
936 return ThreadSafeGetLangGroupFontPrefs(*aDoc
, aLang
)
937 ->GetDefaultFont(aGeneric
)
941 gfxFontFeatureValueSet
* Gecko_ConstructFontFeatureValueSet() {
942 return new gfxFontFeatureValueSet();
945 nsTArray
<uint32_t>* Gecko_AppendFeatureValueHashEntry(
946 gfxFontFeatureValueSet
* aFontFeatureValues
, nsAtom
* aFamily
,
947 uint32_t aAlternate
, nsAtom
* aName
) {
948 MOZ_ASSERT(NS_IsMainThread());
949 return aFontFeatureValues
->AppendFeatureValueHashEntry(nsAtomCString(aFamily
),
953 gfx::FontPaletteValueSet
* Gecko_ConstructFontPaletteValueSet() {
954 return new gfx::FontPaletteValueSet();
957 gfx::FontPaletteValueSet::PaletteValues
* Gecko_AppendPaletteValueHashEntry(
958 gfx::FontPaletteValueSet
* aPaletteValueSet
, nsAtom
* aFamily
,
960 MOZ_ASSERT(NS_IsMainThread());
961 return aPaletteValueSet
->Insert(aName
, nsAtomCString(aFamily
));
964 void Gecko_SetFontPaletteBase(gfx::FontPaletteValueSet::PaletteValues
* aValues
,
965 int32_t aBasePaletteIndex
) {
966 aValues
->mBasePalette
= aBasePaletteIndex
;
969 void Gecko_SetFontPaletteOverride(
970 gfx::FontPaletteValueSet::PaletteValues
* aValues
, int32_t aIndex
,
971 StyleAbsoluteColor
* aColor
) {
975 aValues
->mOverrides
.AppendElement(gfx::FontPaletteValueSet::OverrideColor
{
976 uint32_t(aIndex
), gfx::sRGBColor::FromABGR(aColor
->ToColor())});
979 void Gecko_CounterStyle_ToPtr(const StyleCounterStyle
* aStyle
,
980 CounterStylePtr
* aPtr
) {
981 *aPtr
= CounterStylePtr::FromStyle(*aStyle
);
984 void Gecko_SetCounterStyleToNone(CounterStylePtr
* aPtr
) {
985 *aPtr
= nsGkAtoms::none
;
988 void Gecko_SetCounterStyleToString(CounterStylePtr
* aPtr
,
989 const nsACString
* aSymbol
) {
990 *aPtr
= new AnonymousCounterStyle(NS_ConvertUTF8toUTF16(*aSymbol
));
993 void Gecko_CopyCounterStyle(CounterStylePtr
* aDst
,
994 const CounterStylePtr
* aSrc
) {
998 nsAtom
* Gecko_CounterStyle_GetName(const CounterStylePtr
* aPtr
) {
999 return aPtr
->IsAtom() ? aPtr
->AsAtom() : nullptr;
1002 const AnonymousCounterStyle
* Gecko_CounterStyle_GetAnonymous(
1003 const CounterStylePtr
* aPtr
) {
1004 return aPtr
->AsAnonymous();
1007 void Gecko_EnsureTArrayCapacity(void* aArray
, size_t aCapacity
,
1010 reinterpret_cast<nsTArray_base
<nsTArrayInfallibleAllocator
,
1011 nsTArray_RelocateUsingMemutils
>*>(aArray
);
1013 base
->EnsureCapacity
<nsTArrayInfallibleAllocator
>(aCapacity
, aElemSize
);
1016 void Gecko_ClearPODTArray(void* aArray
, size_t aElementSize
,
1017 size_t aElementAlign
) {
1019 reinterpret_cast<nsTArray_base
<nsTArrayInfallibleAllocator
,
1020 nsTArray_RelocateUsingMemutils
>*>(aArray
);
1022 base
->template ShiftData
<nsTArrayInfallibleAllocator
>(
1023 0, base
->Length(), 0, aElementSize
, aElementAlign
);
1026 void Gecko_ResizeTArrayForStrings(nsTArray
<nsString
>* aArray
,
1028 aArray
->SetLength(aLength
);
1031 void Gecko_ResizeAtomArray(nsTArray
<RefPtr
<nsAtom
>>* aArray
, uint32_t aLength
) {
1032 aArray
->SetLength(aLength
);
1035 void Gecko_EnsureImageLayersLength(nsStyleImageLayers
* aLayers
, size_t aLen
,
1036 nsStyleImageLayers::LayerType aLayerType
) {
1037 size_t oldLength
= aLayers
->mLayers
.Length();
1039 aLayers
->mLayers
.EnsureLengthAtLeast(aLen
);
1041 for (size_t i
= oldLength
; i
< aLen
; ++i
) {
1042 aLayers
->mLayers
[i
].Initialize(aLayerType
);
1046 template <typename StyleType
>
1047 static void EnsureStyleAutoArrayLength(StyleType
* aArray
, size_t aLen
) {
1048 size_t oldLength
= aArray
->Length();
1050 aArray
->EnsureLengthAtLeast(aLen
);
1052 for (size_t i
= oldLength
; i
< aLen
; ++i
) {
1053 (*aArray
)[i
].SetInitialValues();
1057 void Gecko_EnsureStyleAnimationArrayLength(void* aArray
, size_t aLen
) {
1058 auto* base
= static_cast<nsStyleAutoArray
<StyleAnimation
>*>(aArray
);
1059 EnsureStyleAutoArrayLength(base
, aLen
);
1062 void Gecko_EnsureStyleTransitionArrayLength(void* aArray
, size_t aLen
) {
1063 auto* base
= reinterpret_cast<nsStyleAutoArray
<StyleTransition
>*>(aArray
);
1064 EnsureStyleAutoArrayLength(base
, aLen
);
1067 void Gecko_EnsureStyleScrollTimelineArrayLength(void* aArray
, size_t aLen
) {
1068 auto* base
= static_cast<nsStyleAutoArray
<StyleScrollTimeline
>*>(aArray
);
1069 EnsureStyleAutoArrayLength(base
, aLen
);
1072 void Gecko_EnsureStyleViewTimelineArrayLength(void* aArray
, size_t aLen
) {
1073 auto* base
= static_cast<nsStyleAutoArray
<StyleViewTimeline
>*>(aArray
);
1074 EnsureStyleAutoArrayLength(base
, aLen
);
1077 enum class KeyframeSearchDirection
{
1082 enum class KeyframeInsertPosition
{
1087 static Keyframe
* GetOrCreateKeyframe(
1088 nsTArray
<Keyframe
>* aKeyframes
, float aOffset
,
1089 const StyleComputedTimingFunction
* aTimingFunction
,
1090 const CompositeOperationOrAuto aComposition
,
1091 KeyframeSearchDirection aSearchDirection
,
1092 KeyframeInsertPosition aInsertPosition
) {
1093 MOZ_ASSERT(aKeyframes
, "The keyframe array should be valid");
1094 MOZ_ASSERT(aTimingFunction
, "The timing function should be valid");
1095 MOZ_ASSERT(aOffset
>= 0. && aOffset
<= 1.,
1096 "The offset should be in the range of [0.0, 1.0]");
1098 size_t keyframeIndex
;
1099 switch (aSearchDirection
) {
1100 case KeyframeSearchDirection::Forwards
:
1101 if (nsAnimationManager::FindMatchingKeyframe(
1102 *aKeyframes
, aOffset
, *aTimingFunction
, aComposition
,
1104 return &(*aKeyframes
)[keyframeIndex
];
1107 case KeyframeSearchDirection::Backwards
:
1108 if (nsAnimationManager::FindMatchingKeyframe(
1109 Reversed(*aKeyframes
), aOffset
, *aTimingFunction
, aComposition
,
1111 return &(*aKeyframes
)[aKeyframes
->Length() - 1 - keyframeIndex
];
1113 keyframeIndex
= aKeyframes
->Length() - 1;
1117 Keyframe
* keyframe
= aKeyframes
->InsertElementAt(
1118 aInsertPosition
== KeyframeInsertPosition::Prepend
? 0 : keyframeIndex
);
1119 keyframe
->mOffset
.emplace(aOffset
);
1120 if (!aTimingFunction
->IsLinearKeyword()) {
1121 keyframe
->mTimingFunction
.emplace(*aTimingFunction
);
1123 keyframe
->mComposite
= aComposition
;
1128 Keyframe
* Gecko_GetOrCreateKeyframeAtStart(
1129 nsTArray
<Keyframe
>* aKeyframes
, float aOffset
,
1130 const StyleComputedTimingFunction
* aTimingFunction
,
1131 const CompositeOperationOrAuto aComposition
) {
1132 MOZ_ASSERT(aKeyframes
->IsEmpty() ||
1133 aKeyframes
->ElementAt(0).mOffset
.value() >= aOffset
,
1134 "The offset should be less than or equal to the first keyframe's "
1135 "offset if there are exisiting keyframes");
1137 return GetOrCreateKeyframe(aKeyframes
, aOffset
, aTimingFunction
, aComposition
,
1138 KeyframeSearchDirection::Forwards
,
1139 KeyframeInsertPosition::Prepend
);
1142 Keyframe
* Gecko_GetOrCreateInitialKeyframe(
1143 nsTArray
<Keyframe
>* aKeyframes
,
1144 const StyleComputedTimingFunction
* aTimingFunction
,
1145 const CompositeOperationOrAuto aComposition
) {
1146 return GetOrCreateKeyframe(aKeyframes
, 0., aTimingFunction
, aComposition
,
1147 KeyframeSearchDirection::Forwards
,
1148 KeyframeInsertPosition::LastForOffset
);
1151 Keyframe
* Gecko_GetOrCreateFinalKeyframe(
1152 nsTArray
<Keyframe
>* aKeyframes
,
1153 const StyleComputedTimingFunction
* aTimingFunction
,
1154 const CompositeOperationOrAuto aComposition
) {
1155 return GetOrCreateKeyframe(aKeyframes
, 1., aTimingFunction
, aComposition
,
1156 KeyframeSearchDirection::Backwards
,
1157 KeyframeInsertPosition::LastForOffset
);
1160 PropertyValuePair
* Gecko_AppendPropertyValuePair(
1161 nsTArray
<PropertyValuePair
>* aProperties
, nsCSSPropertyID aProperty
) {
1162 MOZ_ASSERT(aProperties
);
1163 MOZ_ASSERT(aProperty
== eCSSPropertyExtra_variable
||
1164 !nsCSSProps::PropHasFlags(aProperty
, CSSPropFlags::IsLogical
));
1165 return aProperties
->AppendElement(PropertyValuePair
{aProperty
});
1168 void Gecko_GetComputedURLSpec(const StyleComputedUrl
* aURL
, nsCString
* aOut
) {
1171 if (aURL
->IsLocalRef()) {
1172 aOut
->Assign(aURL
->SpecifiedSerialization());
1175 Gecko_GetComputedImageURLSpec(aURL
, aOut
);
1178 void Gecko_GetComputedImageURLSpec(const StyleComputedUrl
* aURL
,
1180 if (aURL
->IsLocalRef() &&
1181 StaticPrefs::layout_css_computed_style_dont_resolve_image_local_refs()) {
1182 aOut
->Assign(aURL
->SpecifiedSerialization());
1186 if (nsIURI
* uri
= aURL
->GetURI()) {
1187 nsresult rv
= uri
->GetSpec(*aOut
);
1188 if (NS_SUCCEEDED(rv
)) {
1193 aOut
->AssignLiteral("about:invalid");
1196 bool Gecko_IsSupportedImageMimeType(const uint8_t* aMimeType
,
1197 const uint32_t aLen
) {
1198 nsDependentCSubstring
mime(reinterpret_cast<const char*>(aMimeType
), aLen
);
1199 return imgLoader::SupportImageWithMimeType(
1200 mime
, AcceptedMimeTypes::IMAGES_AND_DOCUMENTS
);
1203 void Gecko_nsIURI_Debug(nsIURI
* aURI
, nsCString
* aOut
) {
1204 // TODO(emilio): Do we have more useful stuff to put here, maybe?
1206 *aOut
= aURI
->GetSpecOrDefault();
1210 // XXX Implemented by hand because even though it's thread-safe, only the
1211 // subclasses have the HasThreadSafeRefCnt bits.
1212 void Gecko_AddRefnsIURIArbitraryThread(nsIURI
* aPtr
) { NS_ADDREF(aPtr
); }
1213 void Gecko_ReleasensIURIArbitraryThread(nsIURI
* aPtr
) { NS_RELEASE(aPtr
); }
1215 void Gecko_nsIReferrerInfo_Debug(nsIReferrerInfo
* aReferrerInfo
,
1217 if (aReferrerInfo
) {
1218 if (nsCOMPtr
<nsIURI
> referrer
= aReferrerInfo
->GetComputedReferrer()) {
1219 *aOut
= referrer
->GetSpecOrDefault();
1224 template <typename ElementLike
>
1225 void DebugListAttributes(const ElementLike
& aElement
, nsCString
& aOut
) {
1226 const uint32_t kMaxAttributeLength
= 40;
1229 while (BorrowedAttrInfo info
= aElement
.GetAttrInfoAt(i
++)) {
1230 aOut
.AppendLiteral(" ");
1231 if (nsAtom
* prefix
= info
.mName
->GetPrefix()) {
1232 aOut
.Append(NS_ConvertUTF16toUTF8(nsDependentAtomString(prefix
)));
1233 aOut
.AppendLiteral(":");
1236 NS_ConvertUTF16toUTF8(nsDependentAtomString(info
.mName
->LocalName())));
1240 aOut
.AppendLiteral("=\"");
1242 info
.mValue
->ToString(value
);
1243 if (value
.Length() > kMaxAttributeLength
) {
1244 value
.Truncate(kMaxAttributeLength
- 3);
1245 value
.AppendLiteral("...");
1247 aOut
.Append(NS_ConvertUTF16toUTF8(value
));
1248 aOut
.AppendLiteral("\"");
1252 void Gecko_Element_DebugListAttributes(const Element
* aElement
,
1254 DebugListAttributes(*aElement
, *aOut
);
1257 void Gecko_Snapshot_DebugListAttributes(const ServoElementSnapshot
* aSnapshot
,
1259 DebugListAttributes(*aSnapshot
, *aOut
);
1262 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData
, URLExtraData
);
1264 void Gecko_nsStyleFont_SetLang(nsStyleFont
* aFont
, nsAtom
* aAtom
) {
1265 aFont
->mLanguage
= dont_AddRef(aAtom
);
1266 aFont
->mExplicitLanguage
= true;
1269 void Gecko_nsStyleFont_CopyLangFrom(nsStyleFont
* aFont
,
1270 const nsStyleFont
* aSource
) {
1271 aFont
->mLanguage
= aSource
->mLanguage
;
1274 Length
Gecko_nsStyleFont_ComputeMinSize(const nsStyleFont
* aFont
,
1275 const Document
* aDocument
) {
1276 // Don't change font-size:0, since that would un-hide hidden text.
1277 if (aFont
->mSize
.IsZero()) {
1280 // Don't change it for docs where we don't enable the min-font-size.
1281 if (!aFont
->MinFontSizeEnabled()) {
1285 bool needsCache
= false;
1287 auto MinFontSize
= [&](bool* aNeedsToCache
) {
1289 aDocument
->GetFontPrefsForLang(aFont
->mLanguage
, aNeedsToCache
);
1290 return prefs
? prefs
->mMinimumFontSize
: Length
{0};
1294 AutoReadLock
guard(*sServoFFILock
);
1295 minFontSize
= MinFontSize(&needsCache
);
1299 AutoWriteLock
guard(*sServoFFILock
);
1300 minFontSize
= MinFontSize(nullptr);
1303 if (minFontSize
.ToCSSPixels() <= 0.0f
) {
1307 minFontSize
.ScaleBy(aFont
->mMinFontSizeRatio
);
1308 minFontSize
.ScaleBy(1.0f
/ 100.0f
);
1312 static StaticRefPtr
<UACacheReporter
> gUACacheReporter
;
1316 void InitializeServo() {
1317 URLExtraData::Init();
1318 Servo_Initialize(URLExtraData::Dummy(), URLExtraData::DummyChrome());
1320 gUACacheReporter
= new UACacheReporter();
1321 RegisterWeakMemoryReporter(gUACacheReporter
);
1323 sServoFFILock
= new RWLock("Servo::FFILock");
1326 void ShutdownServo() {
1327 MOZ_ASSERT(sServoFFILock
);
1329 UnregisterWeakMemoryReporter(gUACacheReporter
);
1330 gUACacheReporter
= nullptr;
1332 sServoFFILock
= nullptr;
1335 URLExtraData::Shutdown();
1338 void AssertIsMainThreadOrServoFontMetricsLocked() {
1339 if (!NS_IsMainThread()) {
1340 MOZ_ASSERT(sServoFFILock
&&
1341 sServoFFILock
->LockedForWritingByCurrentThread());
1345 } // namespace mozilla
1347 GeckoFontMetrics
Gecko_GetFontMetrics(const nsPresContext
* aPresContext
,
1349 const nsStyleFont
* aFont
,
1350 Length aFontSize
, bool aUseUserFontSet
,
1351 bool aRetrieveMathScales
) {
1352 AutoWriteLock
guard(*sServoFFILock
);
1354 // Getting font metrics can require some main thread only work to be
1355 // done, such as work that needs to touch non-threadsafe refcounted
1356 // objects (like the DOM FontFace/FontFaceSet objects), network loads, etc.
1358 // To handle this work, font code checks whether we are in a Servo traversal
1359 // and if so, appends PostTraversalTasks to the current ServoStyleSet
1360 // to be performed immediately after the traversal is finished. This
1361 // works well for starting downloadable font loads, since we don't have
1362 // those fonts available to get metrics for anyway. Platform fonts and
1363 // ArrayBuffer-backed FontFace objects are handled synchronously.
1365 nsPresContext
* presContext
= const_cast<nsPresContext
*>(aPresContext
);
1366 RefPtr
<nsFontMetrics
> fm
= nsLayoutUtils::GetMetricsFor(
1367 presContext
, aIsVertical
, aFont
, aFontSize
, aUseUserFontSet
);
1368 auto* fontGroup
= fm
->GetThebesFontGroup();
1369 auto metrics
= fontGroup
->GetMetricsForCSSUnits(fm
->Orientation());
1371 float scriptPercentScaleDown
= 0;
1372 float scriptScriptPercentScaleDown
= 0;
1373 if (aRetrieveMathScales
) {
1374 RefPtr
<gfxFont
> font
= fontGroup
->GetFirstValidFont();
1375 if (font
->TryGetMathTable()) {
1376 scriptPercentScaleDown
= static_cast<float>(
1377 font
->MathTable()->Constant(gfxMathTable::ScriptPercentScaleDown
));
1378 scriptScriptPercentScaleDown
=
1379 static_cast<float>(font
->MathTable()->Constant(
1380 gfxMathTable::ScriptScriptPercentScaleDown
));
1384 int32_t d2a
= aPresContext
->AppUnitsPerDevPixel();
1385 auto ToLength
= [](nscoord aLen
) {
1386 return Length::FromPixels(CSSPixel::FromAppUnits(aLen
));
1388 return {ToLength(NS_round(metrics
.xHeight
* d2a
)),
1389 ToLength(NS_round(metrics
.zeroWidth
* d2a
)),
1390 ToLength(NS_round(metrics
.capHeight
* d2a
)),
1391 ToLength(NS_round(metrics
.ideographicWidth
* d2a
)),
1392 ToLength(NS_round(metrics
.maxAscent
* d2a
)),
1393 ToLength(NS_round(fontGroup
->GetStyle()->size
* d2a
)),
1394 scriptPercentScaleDown
,
1395 scriptScriptPercentScaleDown
};
1398 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(SheetLoadDataHolder
, SheetLoadDataHolder
);
1400 void Gecko_StyleSheet_FinishAsyncParse(
1401 SheetLoadDataHolder
* aData
,
1402 StyleStrong
<StyleStylesheetContents
> aSheetContents
,
1403 StyleUseCounters
* aUseCounters
) {
1404 UniquePtr
<StyleUseCounters
> useCounters(aUseCounters
);
1405 RefPtr
<SheetLoadDataHolder
> loadData
= aData
;
1406 RefPtr
<StyleStylesheetContents
> sheetContents
= aSheetContents
.Consume();
1407 NS_DispatchToMainThreadQueue(
1408 NS_NewRunnableFunction(
1410 [d
= std::move(loadData
), contents
= std::move(sheetContents
),
1411 counters
= std::move(useCounters
)]() mutable {
1412 MOZ_ASSERT(NS_IsMainThread());
1413 SheetLoadData
* data
= d
->get();
1414 data
->mSheet
->FinishAsyncParse(contents
.forget(),
1415 std::move(counters
));
1417 EventQueuePriority::RenderBlocking
);
1420 static already_AddRefed
<StyleSheet
> LoadImportSheet(
1421 Loader
* aLoader
, StyleSheet
* aParent
, SheetLoadData
* aParentLoadData
,
1422 LoaderReusableStyleSheets
* aReusableSheets
, const StyleCssUrl
& aURL
,
1423 already_AddRefed
<StyleLockedMediaList
> aMediaList
) {
1424 MOZ_ASSERT(NS_IsMainThread());
1425 MOZ_ASSERT(aLoader
, "Should've catched this before");
1426 MOZ_ASSERT(aParent
, "Only used for @import, so parent should exist!");
1428 RefPtr
<MediaList
> media
= new MediaList(std::move(aMediaList
));
1429 nsCOMPtr
<nsIURI
> uri
= aURL
.GetURI();
1430 nsresult rv
= uri
? NS_OK
: NS_ERROR_FAILURE
;
1432 size_t previousSheetCount
= aParent
->ChildSheets().Length();
1433 if (NS_SUCCEEDED(rv
)) {
1434 // TODO(emilio): We should probably make LoadChildSheet return the
1435 // stylesheet rather than the return code.
1436 rv
= aLoader
->LoadChildSheet(*aParent
, aParentLoadData
, uri
, media
,
1440 if (NS_FAILED(rv
) || previousSheetCount
== aParent
->ChildSheets().Length()) {
1441 // Servo and Gecko have different ideas of what a valid URL is, so we might
1442 // get in here with a URL string that NS_NewURI can't handle. We may also
1443 // reach here via an import cycle. For the import cycle case, we need some
1444 // sheet object per spec, even if its empty. DevTools uses the URI to
1445 // realize it has hit an import cycle, so we mark it complete to make the
1446 // sheet readable from JS.
1447 RefPtr
<StyleSheet
> emptySheet
=
1448 aParent
->CreateEmptyChildSheet(media
.forget());
1449 // Make a dummy URI if we don't have one because some methods assume
1452 NS_NewURI(getter_AddRefs(uri
), "about:invalid"_ns
);
1454 emptySheet
->SetURIs(uri
, uri
, uri
);
1455 emptySheet
->SetPrincipal(aURL
.ExtraData().Principal());
1456 nsCOMPtr
<nsIReferrerInfo
> referrerInfo
=
1457 ReferrerInfo::CreateForExternalCSSResources(emptySheet
);
1458 emptySheet
->SetReferrerInfo(referrerInfo
);
1459 emptySheet
->SetComplete();
1460 aParent
->AppendStyleSheet(*emptySheet
);
1461 return emptySheet
.forget();
1464 RefPtr
<StyleSheet
> sheet
= aParent
->ChildSheets().LastElement();
1465 return sheet
.forget();
1468 StyleSheet
* Gecko_LoadStyleSheet(Loader
* aLoader
, StyleSheet
* aParent
,
1469 SheetLoadData
* aParentLoadData
,
1470 LoaderReusableStyleSheets
* aReusableSheets
,
1471 const StyleCssUrl
* aUrl
,
1472 StyleStrong
<StyleLockedMediaList
> aMediaList
) {
1473 MOZ_ASSERT(NS_IsMainThread());
1476 return LoadImportSheet(aLoader
, aParent
, aParentLoadData
, aReusableSheets
,
1477 *aUrl
, aMediaList
.Consume())
1481 void Gecko_LoadStyleSheetAsync(SheetLoadDataHolder
* aParentData
,
1482 const StyleCssUrl
* aUrl
,
1483 StyleStrong
<StyleLockedMediaList
> aMediaList
,
1484 StyleStrong
<StyleLockedImportRule
> aImportRule
) {
1486 RefPtr
<SheetLoadDataHolder
> loadData
= aParentData
;
1487 RefPtr
<StyleLockedMediaList
> mediaList
= aMediaList
.Consume();
1488 RefPtr
<StyleLockedImportRule
> importRule
= aImportRule
.Consume();
1489 NS_DispatchToMainThreadQueue(
1490 NS_NewRunnableFunction(
1492 [data
= std::move(loadData
), url
= StyleCssUrl(*aUrl
),
1493 media
= std::move(mediaList
),
1494 import
= std::move(importRule
)]() mutable {
1495 MOZ_ASSERT(NS_IsMainThread());
1496 SheetLoadData
* d
= data
->get();
1497 RefPtr
<StyleSheet
> sheet
= LoadImportSheet(
1498 d
->mLoader
, d
->mSheet
, d
, nullptr, url
, media
.forget());
1499 Servo_ImportRule_SetSheet(import
, sheet
);
1501 EventQueuePriority::RenderBlocking
);
1504 void Gecko_AddPropertyToSet(nsCSSPropertyIDSet
* aPropertySet
,
1505 nsCSSPropertyID aProperty
) {
1506 aPropertySet
->AddProperty(aProperty
);
1509 bool Gecko_DocumentRule_UseForPresentation(
1510 const Document
* aDocument
, const nsACString
* aPattern
,
1511 DocumentMatchingFunction aMatchingFunction
) {
1512 MOZ_ASSERT(NS_IsMainThread());
1514 nsIURI
* docURI
= aDocument
->GetDocumentURI();
1515 nsAutoCString docURISpec
;
1517 // If GetSpec fails (due to OOM) just skip these URI-specific CSS rules.
1518 nsresult rv
= docURI
->GetSpec(docURISpec
);
1519 NS_ENSURE_SUCCESS(rv
, false);
1522 return CSSMozDocumentRule::Match(aDocument
, docURI
, docURISpec
, *aPattern
,
1526 void Gecko_SetJemallocThreadLocalArena(bool enabled
) {
1527 #if defined(MOZ_MEMORY)
1528 jemalloc_thread_local_arena(enabled
);
1532 template <typename T
>
1533 void Construct(T
* aPtr
, const Document
* aDoc
) {
1534 if constexpr (std::is_constructible_v
<T
, const Document
&>) {
1536 new (KnownNotNull
, aPtr
) T(*aDoc
);
1539 new (KnownNotNull
, aPtr
) T();
1540 // These instance are intentionally global, and we don't want leakcheckers
1546 #define STYLE_STRUCT(name) \
1547 void Gecko_Construct_Default_nsStyle##name(nsStyle##name* ptr, \
1548 const Document* doc) { \
1549 Construct(ptr, doc); \
1551 void Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr, \
1552 const nsStyle##name* other) { \
1553 new (ptr) nsStyle##name(*other); \
1555 void Gecko_Destroy_nsStyle##name(nsStyle##name* ptr) { \
1556 ptr->~nsStyle##name(); \
1559 #include "nsStyleStructList.h"
1563 bool Gecko_ErrorReportingEnabled(const StyleSheet
* aSheet
,
1564 const Loader
* aLoader
,
1565 uint64_t* aOutWindowId
) {
1566 if (!ErrorReporter::ShouldReportErrors(aSheet
, aLoader
)) {
1569 *aOutWindowId
= ErrorReporter::FindInnerWindowId(aSheet
, aLoader
);
1573 void Gecko_ReportUnexpectedCSSError(
1574 const uint64_t aWindowId
, nsIURI
* aURI
, const char* message
,
1575 const char* param
, uint32_t paramLen
, const char* prefix
,
1576 const char* prefixParam
, uint32_t prefixParamLen
, const char* suffix
,
1577 const char* source
, uint32_t sourceLen
, const char* selectors
,
1578 uint32_t selectorsLen
, uint32_t lineNumber
, uint32_t colNumber
) {
1579 MOZ_RELEASE_ASSERT(NS_IsMainThread());
1581 ErrorReporter
reporter(aWindowId
);
1585 nsDependentCSubstring
paramValue(prefixParam
, prefixParamLen
);
1586 AutoTArray
<nsString
, 1> wideParam
;
1587 CopyUTF8toUTF16(paramValue
, *wideParam
.AppendElement());
1588 reporter
.ReportUnexpectedUnescaped(prefix
, wideParam
);
1590 reporter
.ReportUnexpected(prefix
);
1595 nsDependentCSubstring
paramValue(param
, paramLen
);
1596 AutoTArray
<nsString
, 1> wideParam
;
1597 CopyUTF8toUTF16(paramValue
, *wideParam
.AppendElement());
1598 reporter
.ReportUnexpectedUnescaped(message
, wideParam
);
1600 reporter
.ReportUnexpected(message
);
1604 reporter
.ReportUnexpected(suffix
);
1606 nsDependentCSubstring
sourceValue(source
, sourceLen
);
1607 nsDependentCSubstring
selectorsValue(selectors
, selectorsLen
);
1608 reporter
.OutputError(sourceValue
, selectorsValue
, lineNumber
+ 1, colNumber
,
1612 void Gecko_ContentList_AppendAll(nsSimpleContentList
* aList
,
1613 const Element
** aElements
, size_t aLength
) {
1614 MOZ_ASSERT(NS_IsMainThread());
1615 MOZ_ASSERT(aElements
);
1616 MOZ_ASSERT(aLength
);
1619 aList
->SetCapacity(aLength
);
1621 for (size_t i
= 0; i
< aLength
; ++i
) {
1622 aList
->AppendElement(const_cast<Element
*>(aElements
[i
]));
1626 const nsTArray
<Element
*>* Gecko_Document_GetElementsWithId(const Document
* aDoc
,
1630 return aDoc
->GetAllElementsForId(aId
);
1633 const nsTArray
<Element
*>* Gecko_ShadowRoot_GetElementsWithId(
1634 const ShadowRoot
* aShadowRoot
, nsAtom
* aId
) {
1635 MOZ_ASSERT(aShadowRoot
);
1637 return aShadowRoot
->GetAllElementsForId(aId
);
1640 bool Gecko_GetBoolPrefValue(const char* aPrefName
) {
1641 MOZ_ASSERT(NS_IsMainThread());
1642 return Preferences::GetBool(aPrefName
);
1645 bool Gecko_IsFontFormatSupported(StyleFontFaceSourceFormatKeyword aFormat
) {
1646 return gfxPlatform::GetPlatform()->IsFontFormatSupported(
1647 aFormat
, StyleFontFaceSourceTechFlags::Empty());
1650 bool Gecko_IsFontTechSupported(StyleFontFaceSourceTechFlags aFlag
) {
1651 return gfxPlatform::GetPlatform()->IsFontFormatSupported(
1652 StyleFontFaceSourceFormatKeyword::None
, aFlag
);
1655 bool Gecko_IsKnownIconFontFamily(const nsAtom
* aFamilyName
) {
1656 return gfxPlatform::GetPlatform()->IsKnownIconFontFamily(aFamilyName
);
1659 bool Gecko_IsInServoTraversal() { return ServoStyleSet::IsInServoTraversal(); }
1661 bool Gecko_IsMainThread() { return NS_IsMainThread(); }
1663 bool Gecko_IsDOMWorkerThread() { return !!GetCurrentThreadWorkerPrivate(); }
1665 int32_t Gecko_GetNumStyleThreads() {
1666 if (const auto& cpuInfo
= hal::GetHeterogeneousCpuInfo()) {
1667 size_t numBigCpus
= cpuInfo
->mBigCpus
.Count();
1668 // If CPUs are homogeneous we do not need to override stylo's
1669 // default number of threads.
1670 if (numBigCpus
!= cpuInfo
->mTotalNumCpus
) {
1671 // From testing on a variety of devices it appears using only
1672 // the number of big cores gives best performance when there are
1673 // 2 or more big cores. If there are fewer than 2 big cores then
1674 // additionally using the medium cores performs better.
1675 if (numBigCpus
>= 2) {
1676 return static_cast<int32_t>(numBigCpus
);
1678 return static_cast<int32_t>(numBigCpus
+ cpuInfo
->mMediumCpus
.Count());
1685 const nsAttrValue
* Gecko_GetSVGAnimatedClass(const Element
* aElement
) {
1686 MOZ_ASSERT(aElement
->IsSVGElement());
1687 return static_cast<const SVGElement
*>(aElement
)->GetAnimatedClassName();
1690 bool Gecko_AssertClassAttrValueIsSane(const nsAttrValue
* aValue
) {
1691 MOZ_ASSERT(aValue
->Type() == nsAttrValue::eAtom
||
1692 aValue
->Type() == nsAttrValue::eString
||
1693 aValue
->Type() == nsAttrValue::eAtomArray
);
1695 aValue
->Type() == nsAttrValue::eString
,
1696 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
1697 aValue
->GetStringValue())
1702 void Gecko_GetSafeAreaInsets(const nsPresContext
* aPresContext
, float* aTop
,
1703 float* aRight
, float* aBottom
, float* aLeft
) {
1704 MOZ_ASSERT(aPresContext
);
1705 ScreenIntMargin safeAreaInsets
= aPresContext
->GetSafeAreaInsets();
1706 *aTop
= aPresContext
->DevPixelsToFloatCSSPixels(safeAreaInsets
.top
);
1707 *aRight
= aPresContext
->DevPixelsToFloatCSSPixels(safeAreaInsets
.right
);
1708 *aBottom
= aPresContext
->DevPixelsToFloatCSSPixels(safeAreaInsets
.bottom
);
1709 *aLeft
= aPresContext
->DevPixelsToFloatCSSPixels(safeAreaInsets
.left
);
1712 void Gecko_PrintfStderr(const nsCString
* aStr
) {
1713 printf_stderr("%s", aStr
->get());
1716 nsAtom
* Gecko_Element_ImportedPart(const nsAttrValue
* aValue
,
1717 nsAtom
* aPartName
) {
1718 if (aValue
->Type() != nsAttrValue::eShadowParts
) {
1721 return aValue
->GetShadowPartsValue().GetReverse(aPartName
);
1724 nsAtom
** Gecko_Element_ExportedParts(const nsAttrValue
* aValue
,
1725 nsAtom
* aPartName
, size_t* aOutLength
) {
1726 if (aValue
->Type() != nsAttrValue::eShadowParts
) {
1729 auto* parts
= aValue
->GetShadowPartsValue().Get(aPartName
);
1733 *aOutLength
= parts
->Length();
1734 static_assert(sizeof(RefPtr
<nsAtom
>) == sizeof(nsAtom
*));
1735 static_assert(alignof(RefPtr
<nsAtom
>) == alignof(nsAtom
*));
1736 return reinterpret_cast<nsAtom
**>(parts
->Elements());
1739 bool StyleSingleFontFamily::IsNamedFamily(const nsAString
& aFamilyName
) const {
1740 if (!IsFamilyName()) {
1743 nsDependentAtomString
name(AsFamilyName().name
.AsAtom());
1744 return name
.Equals(aFamilyName
, nsCaseInsensitiveStringComparator
);
1747 StyleSingleFontFamily
StyleSingleFontFamily::Parse(
1748 const nsACString
& aFamilyOrGenericName
) {
1749 // should only be passed a single font - not entirely correct, a family
1750 // *could* have a comma in it but in practice never does so
1751 // for debug purposes this is fine
1752 NS_ASSERTION(aFamilyOrGenericName
.FindChar(',') == -1,
1753 "Convert method should only be passed a single family name");
1755 auto genericType
= Servo_GenericFontFamily_Parse(&aFamilyOrGenericName
);
1756 if (genericType
!= StyleGenericFontFamily::None
) {
1757 return Generic(genericType
);
1759 return FamilyName({StyleAtom(NS_Atomize(aFamilyOrGenericName
)),
1760 StyleFontFamilyNameSyntax::Identifiers
});
1763 void StyleSingleFontFamily::AppendToString(nsACString
& aName
,
1764 bool aQuote
) const {
1765 if (IsFamilyName()) {
1766 const auto& name
= AsFamilyName();
1768 aName
.Append(nsAutoAtomCString(name
.name
.AsAtom()));
1771 Servo_FamilyName_Serialize(&name
, &aName
);
1775 switch (AsGeneric()) {
1776 case StyleGenericFontFamily::None
:
1777 case StyleGenericFontFamily::MozEmoji
:
1778 MOZ_FALLTHROUGH_ASSERT("Should never appear in a font-family name!");
1779 case StyleGenericFontFamily::Serif
:
1780 return aName
.AppendLiteral("serif");
1781 case StyleGenericFontFamily::SansSerif
:
1782 return aName
.AppendLiteral("sans-serif");
1783 case StyleGenericFontFamily::Monospace
:
1784 return aName
.AppendLiteral("monospace");
1785 case StyleGenericFontFamily::Cursive
:
1786 return aName
.AppendLiteral("cursive");
1787 case StyleGenericFontFamily::Fantasy
:
1788 return aName
.AppendLiteral("fantasy");
1789 case StyleGenericFontFamily::SystemUi
:
1790 return aName
.AppendLiteral("system-ui");
1792 MOZ_ASSERT_UNREACHABLE("Unknown generic font-family!");
1793 return aName
.AppendLiteral("serif");
1796 StyleFontFamilyList
StyleFontFamilyList::WithNames(
1797 nsTArray
<StyleSingleFontFamily
>&& aNames
) {
1798 StyleFontFamilyList list
;
1799 Servo_FontFamilyList_WithNames(&aNames
, &list
);
1803 StyleFontFamilyList
StyleFontFamilyList::WithOneUnquotedFamily(
1804 const nsACString
& aName
) {
1805 AutoTArray
<StyleSingleFontFamily
, 1> names
;
1806 names
.AppendElement(StyleSingleFontFamily::FamilyName(
1807 {StyleAtom(NS_Atomize(aName
)), StyleFontFamilyNameSyntax::Identifiers
}));
1808 return WithNames(std::move(names
));