Bug 1839315: part 4) Link from `SheetLoadData::mWasAlternate` to spec. r=emilio DONTBUILD
[gecko.git] / layout / style / GeckoBindings.cpp
blobbddde4b189799283e23e2548eb523d95514405c7
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"
29 #include "nsIFrame.h"
30 #include "nsIMozBrowserFrame.h"
31 #include "nsINode.h"
32 #include "nsIURI.h"
33 #include "nsFontMetrics.h"
34 #include "nsNameSpaceManager.h"
35 #include "nsNetUtil.h"
36 #include "nsProxyRelease.h"
37 #include "nsString.h"
38 #include "nsStyleStruct.h"
39 #include "nsStyleUtil.h"
40 #include "nsTArray.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"
85 #endif
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)) {
103 return prefs;
106 MOZ_ASSERT(needsCache);
107 AutoWriteLock guard(*sServoFFILock);
108 return aDocument.GetFontPrefsForLang(aLanguage);
111 static const nsFont& ThreadSafeGetDefaultVariableFont(const Document& aDocument,
112 nsAtom* aLanguage) {
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,
137 bool aIsBefore) {
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());
155 if (!ac) {
156 return nullptr;
159 auto* array = new nsTArray<nsIContent*>();
160 nsContentUtils::AppendNativeAnonymousChildren(aElement, *array, 0);
161 return array;
164 void Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* aAnonContent) {
165 MOZ_ASSERT(aAnonContent);
166 delete 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();
179 if (!frame) {
180 return;
182 const auto containAxes = frame->GetContainSizeAxes();
183 if (!containAxes.IsAny()) {
184 return;
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"
224 #undef STYLE_STRUCT
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
232 // worthwhile:
233 // - custom_properties
234 // - writing_mode
235 // - rules
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) {
262 MOZ_ASSERT(aDoc);
263 MOZ_ASSERT(NS_IsMainThread());
265 if (!StaticPrefs::layout_css_visited_links_enabled()) {
266 return false;
269 if (aDoc->IsBeingUsedAsImage()) {
270 return false;
273 nsILoadContext* loadContext = aDoc->GetLoadContext();
274 if (loadContext && loadContext->UsePrivateBrowsing()) {
275 return false;
278 return true;
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) {
311 MOZ_ASSERT(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;
343 return result;
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) {
359 MOZ_ASSERT(aTable);
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());
367 MOZ_ASSERT(aTable);
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();
378 if (!decl) {
379 return nullptr;
381 return decl->Raw();
384 void Gecko_UnsetDirtyStyleAttr(const Element* aElement) {
385 DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
386 if (!decl) {
387 return;
389 decl->UnsetDirty();
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();
405 return nullptr;
408 const StyleLockedDeclarationBlock* Gecko_GetUnvisitedLinkAttrDeclarationBlock(
409 const Element* aElement) {
410 AttributeStyles* attrStyles = aElement->OwnerDoc()->GetAttributeStyles();
411 if (!attrStyles) {
412 return nullptr;
415 return attrStyles->GetServoUnvisitedLinkDecl();
418 StyleSheet* Gecko_StyleSheet_Clone(const StyleSheet* aSheet,
419 const StyleSheet* aNewParentSheet) {
420 MOZ_ASSERT(aSheet);
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
428 // one.
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();
448 if (!attrStyles) {
449 return nullptr;
451 return attrStyles->GetServoVisitedLinkDecl();
454 const StyleLockedDeclarationBlock* Gecko_GetActiveLinkAttrDeclarationBlock(
455 const Element* aElement) {
456 AttributeStyles* attrStyles = aElement->OwnerDoc()->GetAttributeStyles();
457 if (!attrStyles) {
458 return nullptr;
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();
469 if (!doc) {
470 return false;
472 nsPresContext* presContext = doc->GetPresContext();
473 if (!presContext) {
474 return false;
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) {
485 return *aA == *aB;
488 bool Gecko_StyleScrollTimelinesEquals(
489 const nsStyleAutoArray<StyleScrollTimeline>* aA,
490 const nsStyleAutoArray<StyleScrollTimeline>* aB) {
491 return *aA == *aB;
494 bool Gecko_StyleViewTimelinesEquals(
495 const nsStyleAutoArray<StyleViewTimeline>* aA,
496 const nsStyleAutoArray<StyleViewTimeline>* aB) {
497 return *aA == *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()) {
523 return;
526 nsPresContext* presContext = nsContentUtils::GetContextForContent(aElement);
527 if (!presContext || !presContext->IsDynamic()) {
528 return;
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
560 // here.
561 if (!aComputedData) {
562 return;
565 if (aTasks & UpdateAnimationsTasks::CSSTransitions) {
566 MOZ_ASSERT(aOldComputedData);
567 presContext->TransitionManager()->UpdateTransitions(
568 const_cast<Element*>(element), pseudoType, *aOldComputedData,
569 *aComputedData);
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.
582 if (effectSet) {
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
587 // traversal.
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);
618 auto* collection =
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);
626 auto* collection =
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);
634 auto* collection =
635 nsTransitionManager::CSSTransitionCollection::Get(element, pseudoType);
636 return collection ? collection->mAnimations.Length() : 0;
639 static CSSTransition* GetCurrentTransitionAt(const Element* aElement,
640 size_t aIndex) {
641 const auto [element, pseudoType] =
642 AnimationUtils::GetElementPseudoPair(aElement);
643 auto* collection =
644 nsTransitionManager::CSSTransitionCollection ::Get(element, pseudoType);
645 if (!collection) {
646 return nullptr;
648 return collection->mAnimations.SafeElementAt(aIndex);
651 nsCSSPropertyID Gecko_ElementTransitions_PropertyAt(const Element* aElement,
652 size_t aIndex) {
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>*>(
687 aBaseStyles);
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) ==
703 ColorScheme::Dark;
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);
711 switch (aColor) {
712 case StyleSystemColor::Canvastext:
713 return colors.mDefault;
714 case StyleSystemColor::Canvas:
715 return colors.mDefaultBackground;
716 case StyleSystemColor::Linktext:
717 return colors.mLink;
718 case StyleSystemColor::Activetext:
719 return colors.mActiveLink;
720 case StyleSystemColor::Visitedtext:
721 return colors.mVisitedLink;
722 default:
723 break;
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) {
750 return false;
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
765 // language codes.
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)) {
773 return true;
776 return false;
779 nsAtom* Gecko_GetXMLLangValue(const Element* aElement) {
780 const nsAttrValue* attr =
781 aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
783 if (!attr) {
784 return nullptr;
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)) {
799 return false;
801 const nsAttrValue* val = aElement->GetParsedAttr(nsGkAtoms::border);
802 return val &&
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);
826 if (!attr) {
827 return nullptr;
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,
836 bool aIgnoreCase) {
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>; \
843 return expr_;
845 bool Gecko_AttrDashEquals(const nsAttrValue* aValue, const nsAtom* aStr,
846 bool aIgnoreCase) {
847 nsAutoString str;
848 aValue->ToString(str);
849 WITH_COMPARATOR(
850 aIgnoreCase, c,
851 nsStyleUtil::DashMatchCompare(str, nsDependentAtomString(aStr), c))
854 bool Gecko_AttrIncludes(const nsAttrValue* aValue, const nsAtom* aStr,
855 bool aIgnoreCase) {
856 if (aStr == nsGkAtoms::_empty) {
857 return false;
859 nsAutoString str;
860 aValue->ToString(str);
861 WITH_COMPARATOR(
862 aIgnoreCase, c,
863 nsStyleUtil::ValueIncludes(str, nsDependentAtomString(aStr), c))
866 bool Gecko_AttrHasSubstring(const nsAttrValue* aValue, const nsAtom* aStr,
867 bool aIgnoreCase) {
868 return aStr != nsGkAtoms::_empty &&
869 aValue->HasSubstring(nsDependentAtomString(aStr),
870 aIgnoreCase ? eIgnoreCase : eCaseMatters);
873 bool Gecko_AttrHasPrefix(const nsAttrValue* aValue, const nsAtom* aStr,
874 bool aIgnoreCase) {
875 return aStr != nsGkAtoms::_empty &&
876 aValue->HasPrefix(nsDependentAtomString(aStr),
877 aIgnoreCase ? eIgnoreCase : eCaseMatters);
880 bool Gecko_AttrHasSuffix(const nsAttrValue* aValue, const nsAtom* aStr,
881 bool aIgnoreCase) {
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,
924 aDocument);
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)
938 ->size;
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),
950 aName, aAlternate);
953 gfx::FontPaletteValueSet* Gecko_ConstructFontPaletteValueSet() {
954 return new gfx::FontPaletteValueSet();
957 gfx::FontPaletteValueSet::PaletteValues* Gecko_AppendPaletteValueHashEntry(
958 gfx::FontPaletteValueSet* aPaletteValueSet, nsAtom* aFamily,
959 nsAtom* aName) {
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) {
972 if (aIndex < 0) {
973 return;
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) {
995 *aDst = *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,
1008 size_t aElemSize) {
1009 auto base =
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) {
1018 auto base =
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,
1027 uint32_t aLength) {
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 {
1078 Forwards,
1079 Backwards,
1082 enum class KeyframeInsertPosition {
1083 Prepend,
1084 LastForOffset,
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,
1103 keyframeIndex)) {
1104 return &(*aKeyframes)[keyframeIndex];
1106 break;
1107 case KeyframeSearchDirection::Backwards:
1108 if (nsAnimationManager::FindMatchingKeyframe(
1109 Reversed(*aKeyframes), aOffset, *aTimingFunction, aComposition,
1110 keyframeIndex)) {
1111 return &(*aKeyframes)[aKeyframes->Length() - 1 - keyframeIndex];
1113 keyframeIndex = aKeyframes->Length() - 1;
1114 break;
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;
1125 return keyframe;
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) {
1169 MOZ_ASSERT(aURL);
1170 MOZ_ASSERT(aOut);
1171 if (aURL->IsLocalRef()) {
1172 aOut->Assign(aURL->SpecifiedSerialization());
1173 return;
1175 Gecko_GetComputedImageURLSpec(aURL, aOut);
1178 void Gecko_GetComputedImageURLSpec(const StyleComputedUrl* aURL,
1179 nsCString* aOut) {
1180 if (aURL->IsLocalRef() &&
1181 StaticPrefs::layout_css_computed_style_dont_resolve_image_local_refs()) {
1182 aOut->Assign(aURL->SpecifiedSerialization());
1183 return;
1186 if (nsIURI* uri = aURL->GetURI()) {
1187 nsresult rv = uri->GetSpec(*aOut);
1188 if (NS_SUCCEEDED(rv)) {
1189 return;
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?
1205 if (aURI) {
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,
1216 nsCString* aOut) {
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;
1228 uint32_t i = 0;
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(":");
1235 aOut.Append(
1236 NS_ConvertUTF16toUTF8(nsDependentAtomString(info.mName->LocalName())));
1237 if (!info.mValue) {
1238 continue;
1240 aOut.AppendLiteral("=\"");
1241 nsAutoString value;
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,
1253 nsCString* aOut) {
1254 DebugListAttributes(*aElement, *aOut);
1257 void Gecko_Snapshot_DebugListAttributes(const ServoElementSnapshot* aSnapshot,
1258 nsCString* aOut) {
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()) {
1278 return {0};
1280 // Don't change it for docs where we don't enable the min-font-size.
1281 if (!aFont->MinFontSizeEnabled()) {
1282 return {0};
1284 Length minFontSize;
1285 bool needsCache = false;
1287 auto MinFontSize = [&](bool* aNeedsToCache) {
1288 const auto* prefs =
1289 aDocument->GetFontPrefsForLang(aFont->mLanguage, aNeedsToCache);
1290 return prefs ? prefs->mMinimumFontSize : Length{0};
1294 AutoReadLock guard(*sServoFFILock);
1295 minFontSize = MinFontSize(&needsCache);
1298 if (needsCache) {
1299 AutoWriteLock guard(*sServoFFILock);
1300 minFontSize = MinFontSize(nullptr);
1303 if (minFontSize.ToCSSPixels() <= 0.0f) {
1304 return {0};
1307 minFontSize.ScaleBy(aFont->mMinFontSizeRatio);
1308 minFontSize.ScaleBy(1.0f / 100.0f);
1309 return minFontSize;
1312 static StaticRefPtr<UACacheReporter> gUACacheReporter;
1314 namespace mozilla {
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;
1333 Servo_Shutdown();
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,
1348 bool aIsVertical,
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(
1409 __func__,
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,
1437 aReusableSheets);
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
1450 // non-null URIs.
1451 if (!uri) {
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());
1474 MOZ_ASSERT(aUrl);
1476 return LoadImportSheet(aLoader, aParent, aParentLoadData, aReusableSheets,
1477 *aUrl, aMediaList.Consume())
1478 .take();
1481 void Gecko_LoadStyleSheetAsync(SheetLoadDataHolder* aParentData,
1482 const StyleCssUrl* aUrl,
1483 StyleStrong<StyleLockedMediaList> aMediaList,
1484 StyleStrong<StyleLockedImportRule> aImportRule) {
1485 MOZ_ASSERT(aUrl);
1486 RefPtr<SheetLoadDataHolder> loadData = aParentData;
1487 RefPtr<StyleLockedMediaList> mediaList = aMediaList.Consume();
1488 RefPtr<StyleLockedImportRule> importRule = aImportRule.Consume();
1489 NS_DispatchToMainThreadQueue(
1490 NS_NewRunnableFunction(
1491 __func__,
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;
1516 if (docURI) {
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,
1523 aMatchingFunction);
1526 void Gecko_SetJemallocThreadLocalArena(bool enabled) {
1527 #if defined(MOZ_MEMORY)
1528 jemalloc_thread_local_arena(enabled);
1529 #endif
1532 template <typename T>
1533 void Construct(T* aPtr, const Document* aDoc) {
1534 if constexpr (std::is_constructible_v<T, const Document&>) {
1535 MOZ_ASSERT(aDoc);
1536 new (KnownNotNull, aPtr) T(*aDoc);
1537 } else {
1538 MOZ_ASSERT(!aDoc);
1539 new (KnownNotNull, aPtr) T();
1540 // These instance are intentionally global, and we don't want leakcheckers
1541 // to report them.
1542 aPtr->MarkLeaked();
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"
1561 #undef STYLE_STRUCT
1563 bool Gecko_ErrorReportingEnabled(const StyleSheet* aSheet,
1564 const Loader* aLoader,
1565 uint64_t* aOutWindowId) {
1566 if (!ErrorReporter::ShouldReportErrors(aSheet, aLoader)) {
1567 return false;
1569 *aOutWindowId = ErrorReporter::FindInnerWindowId(aSheet, aLoader);
1570 return true;
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);
1583 if (prefix) {
1584 if (prefixParam) {
1585 nsDependentCSubstring paramValue(prefixParam, prefixParamLen);
1586 AutoTArray<nsString, 1> wideParam;
1587 CopyUTF8toUTF16(paramValue, *wideParam.AppendElement());
1588 reporter.ReportUnexpectedUnescaped(prefix, wideParam);
1589 } else {
1590 reporter.ReportUnexpected(prefix);
1594 if (param) {
1595 nsDependentCSubstring paramValue(param, paramLen);
1596 AutoTArray<nsString, 1> wideParam;
1597 CopyUTF8toUTF16(paramValue, *wideParam.AppendElement());
1598 reporter.ReportUnexpectedUnescaped(message, wideParam);
1599 } else {
1600 reporter.ReportUnexpected(message);
1603 if (suffix) {
1604 reporter.ReportUnexpected(suffix);
1606 nsDependentCSubstring sourceValue(source, sourceLen);
1607 nsDependentCSubstring selectorsValue(selectors, selectorsLen);
1608 reporter.OutputError(sourceValue, selectorsValue, lineNumber + 1, colNumber,
1609 aURI);
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);
1617 MOZ_ASSERT(aList);
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,
1627 nsAtom* aId) {
1628 MOZ_ASSERT(aDoc);
1629 MOZ_ASSERT(aId);
1630 return aDoc->GetAllElementsForId(aId);
1633 const nsTArray<Element*>* Gecko_ShadowRoot_GetElementsWithId(
1634 const ShadowRoot* aShadowRoot, nsAtom* aId) {
1635 MOZ_ASSERT(aShadowRoot);
1636 MOZ_ASSERT(aId);
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());
1682 return -1;
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);
1694 MOZ_ASSERT_IF(
1695 aValue->Type() == nsAttrValue::eString,
1696 nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
1697 aValue->GetStringValue())
1698 .IsEmpty());
1699 return true;
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) {
1719 return nullptr;
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) {
1727 return nullptr;
1729 auto* parts = aValue->GetShadowPartsValue().Get(aPartName);
1730 if (!parts) {
1731 return nullptr;
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()) {
1741 return false;
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();
1767 if (!aQuote) {
1768 aName.Append(nsAutoAtomCString(name.name.AsAtom()));
1769 return;
1771 Servo_FamilyName_Serialize(&name, &aName);
1772 return;
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);
1800 return 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));