Bug 1635702 [wpt PR 23413] - Move some internal scroll anchoring tests to wpt, a...
[gecko.git] / layout / style / GeckoBindings.cpp
blob81ded0ecbbdb70794f1f914887684f4ae41c041b
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 "GeckoProfiler.h"
14 #include "gfxFontFamilyList.h"
15 #include "gfxFontFeatures.h"
16 #include "gfxTextRun.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 "nsIContentInlines.h"
26 #include "mozilla/dom/DocumentInlines.h"
27 #include "nsILoadContext.h"
28 #include "nsIFrame.h"
29 #include "nsIMozBrowserFrame.h"
30 #include "nsINode.h"
31 #include "nsIURI.h"
32 #include "nsFontMetrics.h"
33 #include "nsHTMLStyleSheet.h"
34 #include "nsMappedAttributes.h"
35 #include "nsMediaFeatures.h"
36 #include "nsNameSpaceManager.h"
37 #include "nsNetUtil.h"
38 #include "nsProxyRelease.h"
39 #include "nsString.h"
40 #include "nsStyleStruct.h"
41 #include "nsStyleUtil.h"
42 #include "nsTArray.h"
43 #include "nsTransitionManager.h"
44 #include "nsWindowSizes.h"
46 #include "mozilla/css/ImageLoader.h"
47 #include "mozilla/DeclarationBlock.h"
48 #include "mozilla/EffectCompositor.h"
49 #include "mozilla/EffectSet.h"
50 #include "mozilla/EventStates.h"
51 #include "mozilla/FontPropertyTypes.h"
52 #include "mozilla/Keyframe.h"
53 #include "mozilla/Mutex.h"
54 #include "mozilla/Preferences.h"
55 #include "mozilla/ServoElementSnapshot.h"
56 #include "mozilla/ShadowParts.h"
57 #include "mozilla/StaticPresData.h"
58 #include "mozilla/StaticPrefs_browser.h"
59 #include "mozilla/StaticPrefs_layout.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/RWLock.h"
67 #include "mozilla/dom/Element.h"
68 #include "mozilla/dom/ElementInlines.h"
69 #include "mozilla/dom/HTMLTableCellElement.h"
70 #include "mozilla/dom/HTMLBodyElement.h"
71 #include "mozilla/dom/HTMLSlotElement.h"
72 #include "mozilla/dom/MediaList.h"
73 #include "mozilla/dom/SVGElement.h"
74 #include "mozilla/LookAndFeel.h"
75 #include "mozilla/URLExtraData.h"
76 #include "mozilla/dom/CSSMozDocumentRule.h"
78 #if defined(MOZ_MEMORY)
79 # include "mozmemory.h"
80 #endif
82 using namespace mozilla;
83 using namespace mozilla::css;
84 using namespace mozilla::dom;
86 // Definitions of the global traversal stats.
87 bool ServoTraversalStatistics::sActive = false;
88 ServoTraversalStatistics ServoTraversalStatistics::sSingleton;
90 static RWLock* sServoFFILock = nullptr;
92 static const nsFont* ThreadSafeGetDefaultFontHelper(
93 const Document& aDocument, nsAtom* aLanguage,
94 StyleGenericFontFamily aGenericId) {
95 bool needsCache = false;
96 const nsFont* retval;
98 auto GetDefaultFont = [&](bool* aNeedsToCache) {
99 auto* prefs = aDocument.GetFontPrefsForLang(aLanguage, aNeedsToCache);
100 return prefs ? prefs->GetDefaultFont(aGenericId) : nullptr;
104 AutoReadLock guard(*sServoFFILock);
105 retval = GetDefaultFont(&needsCache);
107 if (!needsCache) {
108 return retval;
111 AutoWriteLock guard(*sServoFFILock);
112 retval = GetDefaultFont(nullptr);
114 return retval;
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_GetPreviousSibling(const nsINode* aNode) {
133 return aNode->GetPreviousSibling();
136 const nsINode* Gecko_GetFlattenedTreeParentNode(const nsINode* aNode) {
137 return aNode->GetFlattenedTreeParentNodeForStyle();
140 const Element* Gecko_GetBeforeOrAfterPseudo(const Element* aElement,
141 bool aIsBefore) {
142 MOZ_ASSERT(aElement);
143 MOZ_ASSERT(aElement->HasProperties());
145 return aIsBefore ? nsLayoutUtils::GetBeforePseudo(aElement)
146 : nsLayoutUtils::GetAfterPseudo(aElement);
149 const Element* Gecko_GetMarkerPseudo(const Element* aElement) {
150 MOZ_ASSERT(aElement);
151 MOZ_ASSERT(aElement->HasProperties());
153 return nsLayoutUtils::GetMarkerPseudo(aElement);
156 nsTArray<nsIContent*>* Gecko_GetAnonymousContentForElement(
157 const Element* aElement) {
158 nsIAnonymousContentCreator* ac = do_QueryFrame(aElement->GetPrimaryFrame());
159 if (!ac) {
160 return nullptr;
163 auto* array = new nsTArray<nsIContent*>();
164 nsContentUtils::AppendNativeAnonymousChildren(aElement, *array, 0);
165 return array;
168 void Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* aAnonContent) {
169 MOZ_ASSERT(aAnonContent);
170 delete aAnonContent;
173 const nsTArray<RefPtr<nsINode>>* Gecko_GetAssignedNodes(
174 const Element* aElement) {
175 MOZ_ASSERT(HTMLSlotElement::FromNode(aElement));
176 return &static_cast<const HTMLSlotElement*>(aElement)->AssignedNodes();
179 void Gecko_ComputedStyle_Init(ComputedStyle* aStyle,
180 const ServoComputedData* aValues,
181 PseudoStyleType aPseudoType) {
182 new (KnownNotNull, aStyle)
183 ComputedStyle(aPseudoType, ServoComputedDataForgotten(aValues));
186 ServoComputedData::ServoComputedData(const ServoComputedDataForgotten aValue) {
187 PodAssign(this, aValue.mPtr);
190 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleStructsMallocEnclosingSizeOf)
192 void ServoComputedData::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const {
193 // Note: GetStyleFoo() returns a pointer to an nsStyleFoo that sits within a
194 // servo_arc::Arc, i.e. it is preceded by a word-sized refcount. So we need
195 // to measure it with a function that can handle an interior pointer. We use
196 // ServoStyleStructsEnclosingMallocSizeOf to clearly identify in DMD's
197 // output the memory measured here.
198 #define STYLE_STRUCT(name_) \
199 static_assert(alignof(nsStyle##name_) <= sizeof(size_t), \
200 "alignment will break AddSizeOfExcludingThis()"); \
201 const void* p##name_ = GetStyle##name_(); \
202 if (!aSizes.mState.HaveSeenPtr(p##name_)) { \
203 aSizes.mStyleSizes.NS_STYLE_SIZES_FIELD(name_) += \
204 ServoStyleStructsMallocEnclosingSizeOf(p##name_); \
206 #include "nsStyleStructList.h"
207 #undef STYLE_STRUCT
209 if (visited_style.mPtr && !aSizes.mState.HaveSeenPtr(visited_style.mPtr)) {
210 visited_style.mPtr->AddSizeOfIncludingThis(
211 aSizes, &aSizes.mLayoutComputedValuesVisited);
214 // Measurement of the following members may be added later if DMD finds it is
215 // worthwhile:
216 // - custom_properties
217 // - writing_mode
218 // - rules
219 // - font_computation_data
222 void Gecko_ComputedStyle_Destroy(ComputedStyle* aStyle) {
223 aStyle->~ComputedStyle();
226 void Gecko_ConstructStyleChildrenIterator(const Element* aElement,
227 StyleChildrenIterator* aIterator) {
228 MOZ_ASSERT(aElement);
229 MOZ_ASSERT(aIterator);
230 new (aIterator) StyleChildrenIterator(aElement);
233 void Gecko_DestroyStyleChildrenIterator(StyleChildrenIterator* aIterator) {
234 MOZ_ASSERT(aIterator);
236 aIterator->~StyleChildrenIterator();
239 const nsINode* Gecko_GetNextStyleChild(StyleChildrenIterator* aIterator) {
240 MOZ_ASSERT(aIterator);
241 return aIterator->GetNextChild();
244 bool Gecko_VisitedStylesEnabled(const Document* aDoc) {
245 MOZ_ASSERT(aDoc);
246 MOZ_ASSERT(NS_IsMainThread());
248 if (!StaticPrefs::layout_css_visited_links_enabled()) {
249 return false;
252 if (aDoc->IsBeingUsedAsImage()) {
253 return false;
256 nsILoadContext* loadContext = aDoc->GetLoadContext();
257 if (loadContext && loadContext->UsePrivateBrowsing()) {
258 return false;
261 return true;
264 EventStates::ServoType Gecko_ElementState(const Element* aElement) {
265 return aElement->StyleState().ServoValue();
268 bool Gecko_IsRootElement(const Element* aElement) {
269 return aElement->OwnerDoc()->GetRootElement() == aElement;
272 // Dirtiness tracking.
273 void Gecko_SetNodeFlags(const nsINode* aNode, uint32_t aFlags) {
274 const_cast<nsINode*>(aNode)->SetFlags(aFlags);
277 void Gecko_UnsetNodeFlags(const nsINode* aNode, uint32_t aFlags) {
278 const_cast<nsINode*>(aNode)->UnsetFlags(aFlags);
281 void Gecko_NoteDirtyElement(const Element* aElement) {
282 MOZ_ASSERT(NS_IsMainThread());
283 const_cast<Element*>(aElement)->NoteDirtyForServo();
286 void Gecko_NoteDirtySubtreeForInvalidation(const Element* aElement) {
287 MOZ_ASSERT(NS_IsMainThread());
288 const_cast<Element*>(aElement)->NoteDirtySubtreeForServo();
291 void Gecko_NoteAnimationOnlyDirtyElement(const Element* aElement) {
292 MOZ_ASSERT(NS_IsMainThread());
293 const_cast<Element*>(aElement)->NoteAnimationOnlyDirtyForServo();
296 bool Gecko_AnimationNameMayBeReferencedFromStyle(
297 const nsPresContext* aPresContext, nsAtom* aName) {
298 MOZ_ASSERT(aPresContext);
299 return aPresContext->AnimationManager()->AnimationMayBeReferenced(aName);
302 PseudoStyleType Gecko_GetImplementedPseudo(const Element* aElement) {
303 return aElement->GetPseudoElementType();
306 uint32_t Gecko_CalcStyleDifference(const ComputedStyle* aOldStyle,
307 const ComputedStyle* aNewStyle,
308 bool* aAnyStyleStructChanged,
309 bool* aOnlyResetStructsChanged) {
310 MOZ_ASSERT(aOldStyle);
311 MOZ_ASSERT(aNewStyle);
313 uint32_t equalStructs;
314 nsChangeHint result =
315 aOldStyle->CalcStyleDifference(*aNewStyle, &equalStructs);
317 *aAnyStyleStructChanged =
318 equalStructs != StyleStructConstants::kAllStructsMask;
320 const auto kInheritedStructsMask =
321 StyleStructConstants::kInheritedStructsMask;
322 *aOnlyResetStructsChanged =
323 (equalStructs & kInheritedStructsMask) == kInheritedStructsMask;
325 return result;
328 const ServoElementSnapshot* Gecko_GetElementSnapshot(
329 const ServoElementSnapshotTable* aTable, const Element* aElement) {
330 MOZ_ASSERT(aTable);
331 MOZ_ASSERT(aElement);
333 return aTable->Get(const_cast<Element*>(aElement));
336 bool Gecko_HaveSeenPtr(SeenPtrs* aTable, const void* aPtr) {
337 MOZ_ASSERT(NS_IsMainThread());
338 MOZ_ASSERT(aTable);
339 // Empty Rust allocations are indicated by small values up to the alignment
340 // of the relevant type. We shouldn't see anything like that here.
341 MOZ_ASSERT(uintptr_t(aPtr) > 16);
343 return aTable->HaveSeenPtr(aPtr);
346 const StyleStrong<RawServoDeclarationBlock>* Gecko_GetStyleAttrDeclarationBlock(
347 const Element* aElement) {
348 DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
349 if (!decl) {
350 return nullptr;
352 return decl->RefRawStrong();
355 void Gecko_UnsetDirtyStyleAttr(const Element* aElement) {
356 DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
357 if (!decl) {
358 return;
360 decl->UnsetDirty();
363 static const StyleStrong<RawServoDeclarationBlock>* AsRefRawStrong(
364 const RefPtr<RawServoDeclarationBlock>& aDecl) {
365 static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
366 sizeof(StyleStrong<RawServoDeclarationBlock>),
367 "RefPtr should just be a pointer");
368 return reinterpret_cast<const StyleStrong<RawServoDeclarationBlock>*>(&aDecl);
371 const StyleStrong<RawServoDeclarationBlock>*
372 Gecko_GetHTMLPresentationAttrDeclarationBlock(const Element* aElement) {
373 const nsMappedAttributes* attrs = aElement->GetMappedAttributes();
374 if (!attrs) {
375 auto* svg = SVGElement::FromNodeOrNull(aElement);
376 if (svg) {
377 if (auto decl = svg->GetContentDeclarationBlock()) {
378 return decl->RefRawStrong();
381 return nullptr;
384 return AsRefRawStrong(attrs->GetServoStyle());
387 const StyleStrong<RawServoDeclarationBlock>*
388 Gecko_GetExtraContentStyleDeclarations(const Element* aElement) {
389 if (!aElement->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th)) {
390 return nullptr;
392 const HTMLTableCellElement* cell =
393 static_cast<const HTMLTableCellElement*>(aElement);
394 if (nsMappedAttributes* attrs =
395 cell->GetMappedAttributesInheritedFromTable()) {
396 return AsRefRawStrong(attrs->GetServoStyle());
398 return nullptr;
401 const StyleStrong<RawServoDeclarationBlock>*
402 Gecko_GetUnvisitedLinkAttrDeclarationBlock(const Element* aElement) {
403 nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
404 if (!sheet) {
405 return nullptr;
408 return AsRefRawStrong(sheet->GetServoUnvisitedLinkDecl());
411 StyleSheet* Gecko_StyleSheet_Clone(const StyleSheet* aSheet,
412 const StyleSheet* aNewParentSheet) {
413 MOZ_ASSERT(aSheet);
414 MOZ_ASSERT(aSheet->GetParentSheet(), "Should only be used for @import");
415 MOZ_ASSERT(aNewParentSheet, "Wat");
417 RefPtr<StyleSheet> newSheet =
418 aSheet->Clone(nullptr, nullptr, nullptr, nullptr);
420 // NOTE(emilio): This code runs in the StylesheetInner constructor, which
421 // means that the inner pointer of `aNewParentSheet` still points to the old
422 // one.
424 // So we _don't_ update neither the parent pointer of the stylesheet, nor the
425 // child list (yet). This is fixed up in that same constructor.
426 return static_cast<StyleSheet*>(newSheet.forget().take());
429 void Gecko_StyleSheet_AddRef(const StyleSheet* aSheet) {
430 MOZ_ASSERT(NS_IsMainThread());
431 const_cast<StyleSheet*>(aSheet)->AddRef();
434 void Gecko_StyleSheet_Release(const StyleSheet* aSheet) {
435 MOZ_ASSERT(NS_IsMainThread());
436 const_cast<StyleSheet*>(aSheet)->Release();
439 const StyleStrong<RawServoDeclarationBlock>*
440 Gecko_GetVisitedLinkAttrDeclarationBlock(const Element* aElement) {
441 nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
442 if (!sheet) {
443 return nullptr;
446 return AsRefRawStrong(sheet->GetServoVisitedLinkDecl());
449 const StyleStrong<RawServoDeclarationBlock>*
450 Gecko_GetActiveLinkAttrDeclarationBlock(const Element* aElement) {
451 nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
452 if (!sheet) {
453 return nullptr;
456 return AsRefRawStrong(sheet->GetServoActiveLinkDecl());
459 static PseudoStyleType GetPseudoTypeFromElementForAnimation(
460 const Element*& aElementOrPseudo) {
461 if (aElementOrPseudo->IsGeneratedContentContainerForBefore()) {
462 aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
463 return PseudoStyleType::before;
466 if (aElementOrPseudo->IsGeneratedContentContainerForAfter()) {
467 aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
468 return PseudoStyleType::after;
471 if (aElementOrPseudo->IsGeneratedContentContainerForMarker()) {
472 aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
473 return PseudoStyleType::marker;
476 return PseudoStyleType::NotPseudo;
479 bool Gecko_GetAnimationRule(const Element* aElement,
480 EffectCompositor::CascadeLevel aCascadeLevel,
481 RawServoAnimationValueMap* aAnimationValues) {
482 MOZ_ASSERT(aElement);
484 Document* doc = aElement->GetComposedDoc();
485 if (!doc) {
486 return false;
488 nsPresContext* presContext = doc->GetPresContext();
489 if (!presContext) {
490 return false;
493 PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
495 return presContext->EffectCompositor()->GetServoAnimationRule(
496 aElement, pseudoType, aCascadeLevel, aAnimationValues);
499 bool Gecko_StyleAnimationsEquals(const nsStyleAutoArray<StyleAnimation>* aA,
500 const nsStyleAutoArray<StyleAnimation>* aB) {
501 return *aA == *aB;
504 void Gecko_CopyAnimationNames(nsStyleAutoArray<StyleAnimation>* aDest,
505 const nsStyleAutoArray<StyleAnimation>* aSrc) {
506 size_t srcLength = aSrc->Length();
507 aDest->EnsureLengthAtLeast(srcLength);
509 for (size_t index = 0; index < srcLength; index++) {
510 (*aDest)[index].SetName((*aSrc)[index].GetName());
514 void Gecko_SetAnimationName(StyleAnimation* aStyleAnimation, nsAtom* aAtom) {
515 MOZ_ASSERT(aStyleAnimation);
516 aStyleAnimation->SetName(already_AddRefed<nsAtom>(aAtom));
519 void Gecko_UpdateAnimations(const Element* aElement,
520 const ComputedStyle* aOldComputedData,
521 const ComputedStyle* aComputedData,
522 UpdateAnimationsTasks aTasks) {
523 MOZ_ASSERT(NS_IsMainThread());
524 MOZ_ASSERT(aElement);
526 if (!aElement->IsInComposedDoc()) {
527 return;
530 nsPresContext* presContext = nsContentUtils::GetContextForContent(aElement);
531 if (!presContext || !presContext->IsDynamic()) {
532 return;
535 nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
537 PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
539 if (aTasks & UpdateAnimationsTasks::CSSAnimations) {
540 presContext->AnimationManager()->UpdateAnimations(
541 const_cast<Element*>(aElement), pseudoType, aComputedData);
544 // aComputedData might be nullptr if the target element is now in a
545 // display:none subtree. We still call Gecko_UpdateAnimations in this case
546 // because we need to stop CSS animations in the display:none subtree.
547 // However, we don't need to update transitions since they are stopped by
548 // RestyleManager::AnimationsWithDestroyedFrame so we just return early
549 // here.
550 if (!aComputedData) {
551 return;
554 if (aTasks & UpdateAnimationsTasks::CSSTransitions) {
555 MOZ_ASSERT(aOldComputedData);
556 presContext->TransitionManager()->UpdateTransitions(
557 const_cast<Element*>(aElement), pseudoType, *aOldComputedData,
558 *aComputedData);
561 if (aTasks & UpdateAnimationsTasks::EffectProperties) {
562 presContext->EffectCompositor()->UpdateEffectProperties(
563 aComputedData, const_cast<Element*>(aElement), pseudoType);
566 if (aTasks & UpdateAnimationsTasks::CascadeResults) {
567 EffectSet* effectSet = EffectSet::GetEffectSet(aElement, pseudoType);
568 // CSS animations/transitions might have been destroyed as part of the above
569 // steps so before updating cascade results, we check if there are still any
570 // animations to update.
571 if (effectSet) {
572 // We call UpdateCascadeResults directly (intead of
573 // MaybeUpdateCascadeResults) since we know for sure that the cascade has
574 // changed, but we were unable to call MarkCascadeUpdated when we noticed
575 // it since we avoid mutating state as part of the Servo parallel
576 // traversal.
577 presContext->EffectCompositor()->UpdateCascadeResults(
578 *effectSet, const_cast<Element*>(aElement), pseudoType);
582 if (aTasks & UpdateAnimationsTasks::DisplayChangedFromNone) {
583 presContext->EffectCompositor()->RequestRestyle(
584 const_cast<Element*>(aElement), pseudoType,
585 EffectCompositor::RestyleType::Standard,
586 EffectCompositor::CascadeLevel::Animations);
590 size_t Gecko_GetAnimationEffectCount(const Element* aElementOrPseudo) {
591 PseudoStyleType pseudoType =
592 GetPseudoTypeFromElementForAnimation(aElementOrPseudo);
594 EffectSet* effectSet = EffectSet::GetEffectSet(aElementOrPseudo, pseudoType);
595 return effectSet ? effectSet->Count() : 0;
598 bool Gecko_ElementHasAnimations(const Element* aElement) {
599 PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
601 return !!EffectSet::GetEffectSet(aElement, pseudoType);
604 bool Gecko_ElementHasCSSAnimations(const Element* aElement) {
605 PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
606 nsAnimationManager::CSSAnimationCollection* collection =
607 nsAnimationManager::CSSAnimationCollection ::GetAnimationCollection(
608 aElement, pseudoType);
610 return collection && !collection->mAnimations.IsEmpty();
613 bool Gecko_ElementHasCSSTransitions(const Element* aElement) {
614 PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
615 nsTransitionManager::CSSTransitionCollection* collection =
616 nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
617 aElement, pseudoType);
619 return collection && !collection->mAnimations.IsEmpty();
622 size_t Gecko_ElementTransitions_Length(const Element* aElement) {
623 PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
624 nsTransitionManager::CSSTransitionCollection* collection =
625 nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
626 aElement, pseudoType);
628 return collection ? collection->mAnimations.Length() : 0;
631 static CSSTransition* GetCurrentTransitionAt(const Element* aElement,
632 size_t aIndex) {
633 PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
634 nsTransitionManager::CSSTransitionCollection* collection =
635 nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
636 aElement, pseudoType);
637 if (!collection) {
638 return nullptr;
640 nsTArray<RefPtr<CSSTransition>>& transitions = collection->mAnimations;
641 return aIndex < transitions.Length() ? transitions[aIndex].get() : nullptr;
644 nsCSSPropertyID Gecko_ElementTransitions_PropertyAt(const Element* aElement,
645 size_t aIndex) {
646 CSSTransition* transition = GetCurrentTransitionAt(aElement, aIndex);
647 return transition ? transition->TransitionProperty()
648 : nsCSSPropertyID::eCSSProperty_UNKNOWN;
651 const RawServoAnimationValue* Gecko_ElementTransitions_EndValueAt(
652 const Element* aElement, size_t aIndex) {
653 CSSTransition* transition = GetCurrentTransitionAt(aElement, aIndex);
654 return transition ? transition->ToValue().mServo.get() : nullptr;
657 double Gecko_GetProgressFromComputedTiming(const ComputedTiming* aTiming) {
658 return aTiming->mProgress.Value();
661 double Gecko_GetPositionInSegment(
662 const AnimationPropertySegment* aSegment, double aProgress,
663 ComputedTimingFunction::BeforeFlag aBeforeFlag) {
664 MOZ_ASSERT(aSegment->mFromKey < aSegment->mToKey,
665 "The segment from key should be less than to key");
667 double positionInSegment = (aProgress - aSegment->mFromKey) /
668 // To avoid floating precision inaccuracies, make
669 // sure we calculate both the numerator and
670 // denominator using double precision.
671 (double(aSegment->mToKey) - aSegment->mFromKey);
673 return ComputedTimingFunction::GetPortion(aSegment->mTimingFunction,
674 positionInSegment, aBeforeFlag);
677 const RawServoAnimationValue* Gecko_AnimationGetBaseStyle(
678 const RawServoAnimationValueTable* aBaseStyles, nsCSSPropertyID aProperty) {
679 auto base = reinterpret_cast<
680 const nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>*>(
681 aBaseStyles);
682 return base->GetWeak(aProperty);
685 void Gecko_FillAllImageLayers(nsStyleImageLayers* aLayers, uint32_t aMaxLen) {
686 aLayers->FillAllLayers(aMaxLen);
689 bool Gecko_IsDocumentBody(const Element* aElement) {
690 Document* doc = aElement->GetUncomposedDoc();
691 return doc && doc->GetBodyElement() == aElement;
694 nscolor Gecko_GetLookAndFeelSystemColor(int32_t aId, const Document* aDoc) {
695 bool useStandinsForNativeColors = !nsContentUtils::IsChromeDoc(aDoc);
696 nscolor result;
697 LookAndFeel::ColorID colorId = static_cast<LookAndFeel::ColorID>(aId);
698 AutoWriteLock guard(*sServoFFILock);
699 LookAndFeel::GetColor(colorId, useStandinsForNativeColors, &result);
700 return result;
703 bool Gecko_MatchLang(const Element* aElement, nsAtom* aOverrideLang,
704 bool aHasOverrideLang, const char16_t* aValue) {
705 MOZ_ASSERT(!(aOverrideLang && !aHasOverrideLang),
706 "aHasOverrideLang should only be set when aOverrideLang is null");
707 MOZ_ASSERT(aValue, "null lang parameter");
708 if (!aValue || !*aValue) {
709 return false;
712 // We have to determine the language of the current element. Since
713 // this is currently no property and since the language is inherited
714 // from the parent we have to be prepared to look at all parent
715 // nodes. The language itself is encoded in the LANG attribute.
716 if (auto* language = aHasOverrideLang ? aOverrideLang : aElement->GetLang()) {
717 return nsStyleUtil::DashMatchCompare(
718 nsDependentAtomString(language), nsDependentString(aValue),
719 nsASCIICaseInsensitiveStringComparator());
722 // Try to get the language from the HTTP header or if this
723 // is missing as well from the preferences.
724 // The content language can be a comma-separated list of
725 // language codes.
726 nsAutoString language;
727 aElement->OwnerDoc()->GetContentLanguage(language);
729 nsDependentString langString(aValue);
730 language.StripWhitespace();
731 for (auto const& lang : language.Split(char16_t(','))) {
732 if (nsStyleUtil::DashMatchCompare(
733 lang, langString, nsASCIICaseInsensitiveStringComparator())) {
734 return true;
737 return false;
740 nsAtom* Gecko_GetXMLLangValue(const Element* aElement) {
741 const nsAttrValue* attr =
742 aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
744 if (!attr) {
745 return nullptr;
748 MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
750 RefPtr<nsAtom> atom = attr->GetAtomValue();
751 return atom.forget().take();
754 Document::DocumentTheme Gecko_GetDocumentLWTheme(const Document* aDocument) {
755 return aDocument->ThreadSafeGetDocumentLWTheme();
758 const PreferenceSheet::Prefs* Gecko_GetPrefSheetPrefs(const Document* aDoc) {
759 return &PreferenceSheet::PrefsFor(*aDoc);
762 bool Gecko_IsTableBorderNonzero(const Element* aElement) {
763 if (!aElement->IsHTMLElement(nsGkAtoms::table)) {
764 return false;
766 const nsAttrValue* val = aElement->GetParsedAttr(nsGkAtoms::border);
767 return val &&
768 (val->Type() != nsAttrValue::eInteger || val->GetIntegerValue() != 0);
771 bool Gecko_IsBrowserFrame(const Element* aElement) {
772 nsIMozBrowserFrame* browserFrame =
773 const_cast<Element*>(aElement)->GetAsMozBrowserFrame();
774 return browserFrame && browserFrame->GetReallyIsBrowser();
777 template <typename Implementor>
778 static nsAtom* LangValue(Implementor* aElement) {
779 // TODO(emilio): Deduplicate a bit with nsIContent::GetLang().
780 const nsAttrValue* attr =
781 aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
782 if (!attr && aElement->SupportsLangAttr()) {
783 attr = aElement->GetParsedAttr(nsGkAtoms::lang);
786 if (!attr) {
787 return nullptr;
790 MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
791 RefPtr<nsAtom> atom = attr->GetAtomValue();
792 return atom.forget().take();
795 template <typename Implementor, typename MatchFn>
796 static bool DoMatch(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
797 MatchFn aMatch) {
798 if (MOZ_LIKELY(aNS)) {
799 int32_t ns = aNS == nsGkAtoms::_empty
800 ? kNameSpaceID_None
801 : nsContentUtils::NameSpaceManager()->GetNameSpaceID(
802 aNS, aElement->IsInChromeDocument());
804 MOZ_ASSERT(ns == nsContentUtils::NameSpaceManager()->GetNameSpaceID(
805 aNS, aElement->IsInChromeDocument()));
806 NS_ENSURE_TRUE(ns != kNameSpaceID_Unknown, false);
807 const nsAttrValue* value = aElement->GetParsedAttr(aName, ns);
808 return value && aMatch(value);
811 // No namespace means any namespace - we have to check them all. :-(
812 BorrowedAttrInfo attrInfo;
813 for (uint32_t i = 0; (attrInfo = aElement->GetAttrInfoAt(i)); ++i) {
814 if (attrInfo.mName->LocalName() != aName) {
815 continue;
817 if (aMatch(attrInfo.mValue)) {
818 return true;
821 return false;
824 template <typename Implementor>
825 static bool HasAttr(Implementor* aElement, nsAtom* aNS, nsAtom* aName) {
826 auto match = [](const nsAttrValue* aValue) { return true; };
827 return DoMatch(aElement, aNS, aName, match);
830 template <typename Implementor>
831 static bool AttrEquals(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
832 nsAtom* aStr, bool aIgnoreCase) {
833 auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
834 return aValue->Equals(aStr, aIgnoreCase ? eIgnoreCase : eCaseMatters);
836 return DoMatch(aElement, aNS, aName, match);
839 #define WITH_COMPARATOR(ignore_case_, c_, expr_) \
840 if (ignore_case_) { \
841 const nsCaseInsensitiveStringComparator c_; \
842 return expr_; \
843 } else { \
844 const nsDefaultStringComparator c_; \
845 return expr_; \
848 template <typename Implementor>
849 static bool AttrDashEquals(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
850 nsAtom* aStr, bool aIgnoreCase) {
851 auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
852 nsAutoString str;
853 aValue->ToString(str);
854 WITH_COMPARATOR(
855 aIgnoreCase, c,
856 nsStyleUtil::DashMatchCompare(str, nsDependentAtomString(aStr), c))
858 return DoMatch(aElement, aNS, aName, match);
861 template <typename Implementor>
862 static bool AttrIncludes(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
863 nsAtom* aStr, bool aIgnoreCase) {
864 auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
865 nsAutoString str;
866 aValue->ToString(str);
867 WITH_COMPARATOR(
868 aIgnoreCase, c,
869 nsStyleUtil::ValueIncludes(str, nsDependentAtomString(aStr), c))
871 return DoMatch(aElement, aNS, aName, match);
874 template <typename Implementor>
875 static bool AttrHasSubstring(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
876 nsAtom* aStr, bool aIgnoreCase) {
877 auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
878 nsAutoString str;
879 aValue->ToString(str);
880 WITH_COMPARATOR(aIgnoreCase, c,
881 FindInReadable(nsDependentAtomString(aStr), str, c))
883 return DoMatch(aElement, aNS, aName, match);
886 template <typename Implementor>
887 static bool AttrHasPrefix(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
888 nsAtom* aStr, bool aIgnoreCase) {
889 auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
890 nsAutoString str;
891 aValue->ToString(str);
892 WITH_COMPARATOR(aIgnoreCase, c,
893 StringBeginsWith(str, nsDependentAtomString(aStr), c))
895 return DoMatch(aElement, aNS, aName, match);
898 template <typename Implementor>
899 static bool AttrHasSuffix(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
900 nsAtom* aStr, bool aIgnoreCase) {
901 auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
902 nsAutoString str;
903 aValue->ToString(str);
904 WITH_COMPARATOR(aIgnoreCase, c,
905 StringEndsWith(str, nsDependentAtomString(aStr), c))
907 return DoMatch(aElement, aNS, aName, match);
910 #define SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_) \
911 nsAtom* prefix_##LangValue(implementor_ aElement) { \
912 return LangValue(aElement); \
914 bool prefix_##HasAttr(implementor_ aElement, nsAtom* aNS, nsAtom* aName) { \
915 return HasAttr(aElement, aNS, aName); \
917 bool prefix_##AttrEquals(implementor_ aElement, nsAtom* aNS, nsAtom* aName, \
918 nsAtom* aStr, bool aIgnoreCase) { \
919 return AttrEquals(aElement, aNS, aName, aStr, aIgnoreCase); \
921 bool prefix_##AttrDashEquals(implementor_ aElement, nsAtom* aNS, \
922 nsAtom* aName, nsAtom* aStr, \
923 bool aIgnoreCase) { \
924 return AttrDashEquals(aElement, aNS, aName, aStr, aIgnoreCase); \
926 bool prefix_##AttrIncludes(implementor_ aElement, nsAtom* aNS, \
927 nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) { \
928 return AttrIncludes(aElement, aNS, aName, aStr, aIgnoreCase); \
930 bool prefix_##AttrHasSubstring(implementor_ aElement, nsAtom* aNS, \
931 nsAtom* aName, nsAtom* aStr, \
932 bool aIgnoreCase) { \
933 return AttrHasSubstring(aElement, aNS, aName, aStr, aIgnoreCase); \
935 bool prefix_##AttrHasPrefix(implementor_ aElement, nsAtom* aNS, \
936 nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) { \
937 return AttrHasPrefix(aElement, aNS, aName, aStr, aIgnoreCase); \
939 bool prefix_##AttrHasSuffix(implementor_ aElement, nsAtom* aNS, \
940 nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) { \
941 return AttrHasSuffix(aElement, aNS, aName, aStr, aIgnoreCase); \
944 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, const Element*)
945 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot,
946 const ServoElementSnapshot*)
948 #undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
950 nsAtom* Gecko_Atomize(const char* aString, uint32_t aLength) {
951 return NS_Atomize(nsDependentCSubstring(aString, aLength)).take();
954 nsAtom* Gecko_Atomize16(const nsAString* aString) {
955 return NS_Atomize(*aString).take();
958 void Gecko_AddRefAtom(nsAtom* aAtom) { NS_ADDREF(aAtom); }
960 void Gecko_ReleaseAtom(nsAtom* aAtom) { NS_RELEASE(aAtom); }
962 void Gecko_nsTArray_FontFamilyName_AppendNamed(
963 nsTArray<FontFamilyName>* aNames, nsAtom* aName,
964 StyleFontFamilyNameSyntax aSyntax) {
965 aNames->AppendElement(FontFamilyName(aName, aSyntax));
968 void Gecko_nsTArray_FontFamilyName_AppendGeneric(
969 nsTArray<FontFamilyName>* aNames, StyleGenericFontFamily aType) {
970 aNames->AppendElement(FontFamilyName(aType));
973 SharedFontList* Gecko_SharedFontList_Create() {
974 RefPtr<SharedFontList> fontlist = new SharedFontList();
975 return fontlist.forget().take();
978 MOZ_DEFINE_MALLOC_SIZE_OF(GeckoSharedFontListMallocSizeOf)
980 size_t Gecko_SharedFontList_SizeOfIncludingThisIfUnshared(
981 SharedFontList* aFontlist) {
982 MOZ_ASSERT(NS_IsMainThread());
983 return aFontlist->SizeOfIncludingThisIfUnshared(
984 GeckoSharedFontListMallocSizeOf);
987 size_t Gecko_SharedFontList_SizeOfIncludingThis(SharedFontList* aFontlist) {
988 MOZ_ASSERT(NS_IsMainThread());
989 return aFontlist->SizeOfIncludingThis(GeckoSharedFontListMallocSizeOf);
992 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(SharedFontList, SharedFontList);
994 void Gecko_CopyFontFamilyFrom(nsFont* dst, const nsFont* src) {
995 dst->fontlist = src->fontlist;
998 void Gecko_nsFont_InitSystem(nsFont* aDest, int32_t aFontId,
999 const nsStyleFont* aFont,
1000 const Document* aDocument) {
1001 const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(
1002 *aDocument, aFont->mLanguage, StyleGenericFontFamily::None);
1004 // We have passed uninitialized memory to this function,
1005 // initialize it. We can't simply return an nsFont because then
1006 // we need to know its size beforehand. Servo cannot initialize nsFont
1007 // itself, so this will do.
1008 new (aDest) nsFont(*defaultVariableFont);
1010 LookAndFeel::FontID fontID = static_cast<LookAndFeel::FontID>(aFontId);
1012 AutoWriteLock guard(*sServoFFILock);
1013 nsLayoutUtils::ComputeSystemFont(aDest, fontID, defaultVariableFont);
1016 void Gecko_nsFont_Destroy(nsFont* aDest) { aDest->~nsFont(); }
1018 StyleGenericFontFamily Gecko_nsStyleFont_ComputeDefaultFontType(
1019 const Document* aDoc, StyleGenericFontFamily aGenericId,
1020 nsAtom* aLanguage) {
1021 const nsFont* defaultFont =
1022 ThreadSafeGetDefaultFontHelper(*aDoc, aLanguage, aGenericId);
1023 return defaultFont->fontlist.GetDefaultFontType();
1026 gfxFontFeatureValueSet* Gecko_ConstructFontFeatureValueSet() {
1027 return new gfxFontFeatureValueSet();
1030 nsTArray<uint32_t>* Gecko_AppendFeatureValueHashEntry(
1031 gfxFontFeatureValueSet* aFontFeatureValues, nsAtom* aFamily,
1032 uint32_t aAlternate, nsAtom* aName) {
1033 MOZ_ASSERT(NS_IsMainThread());
1034 return aFontFeatureValues->AppendFeatureValueHashEntry(nsAtomCString(aFamily),
1035 aName, aAlternate);
1038 float Gecko_FontStretch_ToFloat(FontStretch aStretch) {
1039 // Servo represents percentages with 1. being 100%.
1040 return aStretch.Percentage() / 100.0f;
1043 void Gecko_FontStretch_SetFloat(FontStretch* aStretch, float aFloat) {
1044 // Servo represents percentages with 1. being 100%.
1046 // Also, the font code assumes a given maximum that style doesn't really need
1047 // to know about. So clamp here at the boundary.
1048 *aStretch = FontStretch(std::min(aFloat * 100.0f, float(FontStretch::kMax)));
1051 void Gecko_FontSlantStyle_SetNormal(FontSlantStyle* aStyle) {
1052 *aStyle = FontSlantStyle::Normal();
1055 void Gecko_FontSlantStyle_SetItalic(FontSlantStyle* aStyle) {
1056 *aStyle = FontSlantStyle::Italic();
1059 void Gecko_FontSlantStyle_SetOblique(FontSlantStyle* aStyle,
1060 float aAngleInDegrees) {
1061 *aStyle = FontSlantStyle::Oblique(aAngleInDegrees);
1064 void Gecko_FontSlantStyle_Get(FontSlantStyle aStyle, bool* aNormal,
1065 bool* aItalic, float* aObliqueAngle) {
1066 *aNormal = aStyle.IsNormal();
1067 *aItalic = aStyle.IsItalic();
1068 if (aStyle.IsOblique()) {
1069 *aObliqueAngle = aStyle.ObliqueAngle();
1073 float Gecko_FontWeight_ToFloat(FontWeight aWeight) { return aWeight.ToFloat(); }
1075 void Gecko_FontWeight_SetFloat(FontWeight* aWeight, float aFloat) {
1076 *aWeight = FontWeight(aFloat);
1079 void Gecko_CounterStyle_ToPtr(const StyleCounterStyle* aStyle,
1080 CounterStylePtr* aPtr) {
1081 *aPtr = CounterStylePtr::FromStyle(*aStyle);
1084 void Gecko_SetCounterStyleToNone(CounterStylePtr* aPtr) {
1085 *aPtr = nsGkAtoms::none;
1088 void Gecko_SetCounterStyleToString(CounterStylePtr* aPtr,
1089 const nsACString* aSymbol) {
1090 *aPtr = new AnonymousCounterStyle(NS_ConvertUTF8toUTF16(*aSymbol));
1093 void Gecko_CopyCounterStyle(CounterStylePtr* aDst,
1094 const CounterStylePtr* aSrc) {
1095 *aDst = *aSrc;
1098 nsAtom* Gecko_CounterStyle_GetName(const CounterStylePtr* aPtr) {
1099 return aPtr->IsAtom() ? aPtr->AsAtom() : nullptr;
1102 const AnonymousCounterStyle* Gecko_CounterStyle_GetAnonymous(
1103 const CounterStylePtr* aPtr) {
1104 return aPtr->AsAnonymous();
1107 void Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity,
1108 size_t aElemSize) {
1109 auto base =
1110 reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator,
1111 nsTArray_RelocateUsingMemutils>*>(aArray);
1113 base->EnsureCapacity<nsTArrayInfallibleAllocator>(aCapacity, aElemSize);
1116 void Gecko_ClearPODTArray(void* aArray, size_t aElementSize,
1117 size_t aElementAlign) {
1118 auto base =
1119 reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator,
1120 nsTArray_RelocateUsingMemutils>*>(aArray);
1122 base->template ShiftData<nsTArrayInfallibleAllocator>(
1123 0, base->Length(), 0, aElementSize, aElementAlign);
1126 void Gecko_ResizeTArrayForStrings(nsTArray<nsString>* aArray,
1127 uint32_t aLength) {
1128 aArray->SetLength(aLength);
1131 void Gecko_ResizeAtomArray(nsTArray<RefPtr<nsAtom>>* aArray, uint32_t aLength) {
1132 aArray->SetLength(aLength);
1135 void Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen,
1136 nsStyleImageLayers::LayerType aLayerType) {
1137 size_t oldLength = aLayers->mLayers.Length();
1139 aLayers->mLayers.EnsureLengthAtLeast(aLen);
1141 for (size_t i = oldLength; i < aLen; ++i) {
1142 aLayers->mLayers[i].Initialize(aLayerType);
1146 template <typename StyleType>
1147 static void EnsureStyleAutoArrayLength(StyleType* aArray, size_t aLen) {
1148 size_t oldLength = aArray->Length();
1150 aArray->EnsureLengthAtLeast(aLen);
1152 for (size_t i = oldLength; i < aLen; ++i) {
1153 (*aArray)[i].SetInitialValues();
1157 void Gecko_EnsureStyleAnimationArrayLength(void* aArray, size_t aLen) {
1158 auto base = static_cast<nsStyleAutoArray<StyleAnimation>*>(aArray);
1159 EnsureStyleAutoArrayLength(base, aLen);
1162 void Gecko_EnsureStyleTransitionArrayLength(void* aArray, size_t aLen) {
1163 auto base = reinterpret_cast<nsStyleAutoArray<StyleTransition>*>(aArray);
1164 EnsureStyleAutoArrayLength(base, aLen);
1167 enum class KeyframeSearchDirection {
1168 Forwards,
1169 Backwards,
1172 enum class KeyframeInsertPosition {
1173 Prepend,
1174 LastForOffset,
1177 static Keyframe* GetOrCreateKeyframe(nsTArray<Keyframe>* aKeyframes,
1178 float aOffset,
1179 const nsTimingFunction* aTimingFunction,
1180 KeyframeSearchDirection aSearchDirection,
1181 KeyframeInsertPosition aInsertPosition) {
1182 MOZ_ASSERT(aKeyframes, "The keyframe array should be valid");
1183 MOZ_ASSERT(aTimingFunction, "The timing function should be valid");
1184 MOZ_ASSERT(aOffset >= 0. && aOffset <= 1.,
1185 "The offset should be in the range of [0.0, 1.0]");
1187 size_t keyframeIndex;
1188 switch (aSearchDirection) {
1189 case KeyframeSearchDirection::Forwards:
1190 if (nsAnimationManager::FindMatchingKeyframe(
1191 *aKeyframes, aOffset, *aTimingFunction, keyframeIndex)) {
1192 return &(*aKeyframes)[keyframeIndex];
1194 break;
1195 case KeyframeSearchDirection::Backwards:
1196 if (nsAnimationManager::FindMatchingKeyframe(Reversed(*aKeyframes),
1197 aOffset, *aTimingFunction,
1198 keyframeIndex)) {
1199 return &(*aKeyframes)[aKeyframes->Length() - 1 - keyframeIndex];
1201 keyframeIndex = aKeyframes->Length() - 1;
1202 break;
1205 Keyframe* keyframe = aKeyframes->InsertElementAt(
1206 aInsertPosition == KeyframeInsertPosition::Prepend ? 0 : keyframeIndex);
1207 keyframe->mOffset.emplace(aOffset);
1208 if (!aTimingFunction->IsLinear()) {
1209 keyframe->mTimingFunction.emplace();
1210 keyframe->mTimingFunction->Init(*aTimingFunction);
1213 return keyframe;
1216 Keyframe* Gecko_GetOrCreateKeyframeAtStart(
1217 nsTArray<Keyframe>* aKeyframes, float aOffset,
1218 const nsTimingFunction* aTimingFunction) {
1219 MOZ_ASSERT(aKeyframes->IsEmpty() ||
1220 aKeyframes->ElementAt(0).mOffset.value() >= aOffset,
1221 "The offset should be less than or equal to the first keyframe's "
1222 "offset if there are exisiting keyframes");
1224 return GetOrCreateKeyframe(aKeyframes, aOffset, aTimingFunction,
1225 KeyframeSearchDirection::Forwards,
1226 KeyframeInsertPosition::Prepend);
1229 Keyframe* Gecko_GetOrCreateInitialKeyframe(
1230 nsTArray<Keyframe>* aKeyframes, const nsTimingFunction* aTimingFunction) {
1231 return GetOrCreateKeyframe(aKeyframes, 0., aTimingFunction,
1232 KeyframeSearchDirection::Forwards,
1233 KeyframeInsertPosition::LastForOffset);
1236 Keyframe* Gecko_GetOrCreateFinalKeyframe(
1237 nsTArray<Keyframe>* aKeyframes, const nsTimingFunction* aTimingFunction) {
1238 return GetOrCreateKeyframe(aKeyframes, 1., aTimingFunction,
1239 KeyframeSearchDirection::Backwards,
1240 KeyframeInsertPosition::LastForOffset);
1243 PropertyValuePair* Gecko_AppendPropertyValuePair(
1244 nsTArray<PropertyValuePair>* aProperties, nsCSSPropertyID aProperty) {
1245 MOZ_ASSERT(aProperties);
1246 MOZ_ASSERT(aProperty == eCSSPropertyExtra_variable ||
1247 !nsCSSProps::PropHasFlags(aProperty, CSSPropFlags::IsLogical));
1248 return aProperties->AppendElement(PropertyValuePair{aProperty});
1251 void Gecko_GetComputedURLSpec(const StyleComputedUrl* aURL, nsCString* aOut) {
1252 MOZ_ASSERT(aURL);
1253 MOZ_ASSERT(aOut);
1254 if (aURL->IsLocalRef()) {
1255 aOut->Assign(aURL->SpecifiedSerialization());
1256 return;
1258 Gecko_GetComputedImageURLSpec(aURL, aOut);
1261 void Gecko_GetComputedImageURLSpec(const StyleComputedUrl* aURL,
1262 nsCString* aOut) {
1263 // Image URIs don't serialize local refs as local.
1264 if (nsIURI* uri = aURL->GetURI()) {
1265 nsresult rv = uri->GetSpec(*aOut);
1266 if (NS_SUCCEEDED(rv)) {
1267 return;
1271 aOut->AssignLiteral("about:invalid");
1274 void Gecko_nsIURI_Debug(nsIURI* aURI, nsCString* aOut) {
1275 // TODO(emilio): Do we have more useful stuff to put here, maybe?
1276 if (aURI) {
1277 *aOut = aURI->GetSpecOrDefault();
1281 // XXX Implemented by hand because even though it's thread-safe, only the
1282 // subclasses have the HasThreadSafeRefCnt bits.
1283 void Gecko_AddRefnsIURIArbitraryThread(nsIURI* aPtr) { NS_ADDREF(aPtr); }
1284 void Gecko_ReleasensIURIArbitraryThread(nsIURI* aPtr) { NS_RELEASE(aPtr); }
1286 void Gecko_nsIReferrerInfo_Debug(nsIReferrerInfo* aReferrerInfo,
1287 nsCString* aOut) {
1288 if (aReferrerInfo) {
1289 if (nsCOMPtr<nsIURI> referrer = aReferrerInfo->GetComputedReferrer()) {
1290 *aOut = referrer->GetSpecOrDefault();
1295 template <typename ElementLike>
1296 void DebugListAttributes(const ElementLike& aElement, nsCString& aOut) {
1297 const uint32_t kMaxAttributeLength = 40;
1299 uint32_t i = 0;
1300 while (BorrowedAttrInfo info = aElement.GetAttrInfoAt(i++)) {
1301 aOut.AppendLiteral(" ");
1302 if (nsAtom* prefix = info.mName->GetPrefix()) {
1303 aOut.Append(NS_ConvertUTF16toUTF8(nsDependentAtomString(prefix)));
1304 aOut.AppendLiteral(":");
1306 aOut.Append(
1307 NS_ConvertUTF16toUTF8(nsDependentAtomString(info.mName->LocalName())));
1308 if (!info.mValue) {
1309 continue;
1311 aOut.AppendLiteral("=\"");
1312 nsAutoString value;
1313 info.mValue->ToString(value);
1314 if (value.Length() > kMaxAttributeLength) {
1315 value.Truncate(kMaxAttributeLength - 3);
1316 value.AppendLiteral("...");
1318 aOut.Append(NS_ConvertUTF16toUTF8(value));
1319 aOut.AppendLiteral("\"");
1323 void Gecko_Element_DebugListAttributes(const Element* aElement,
1324 nsCString* aOut) {
1325 DebugListAttributes(*aElement, *aOut);
1328 void Gecko_Snapshot_DebugListAttributes(const ServoElementSnapshot* aSnapshot,
1329 nsCString* aOut) {
1330 DebugListAttributes(*aSnapshot, *aOut);
1333 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData);
1335 void Gecko_nsStyleFont_SetLang(nsStyleFont* aFont, nsAtom* aAtom) {
1336 aFont->mLanguage = dont_AddRef(aAtom);
1337 aFont->mExplicitLanguage = true;
1340 void Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont,
1341 const nsStyleFont* aSource) {
1342 aFont->mLanguage = aSource->mLanguage;
1345 void Gecko_nsStyleFont_PrioritizeUserFonts(
1346 nsStyleFont* aFont, StyleGenericFontFamily aDefaultGeneric) {
1347 MOZ_ASSERT(!StaticPrefs::browser_display_use_document_fonts());
1348 MOZ_ASSERT(aDefaultGeneric != StyleGenericFontFamily::None);
1349 if (!aFont->mFont.fontlist.PrioritizeFirstGeneric()) {
1350 aFont->mFont.fontlist.PrependGeneric(aDefaultGeneric);
1354 nscoord Gecko_nsStyleFont_ComputeMinSize(const nsStyleFont* aFont,
1355 const Document* aDocument) {
1356 // Don't change font-size:0, since that would un-hide hidden text,
1357 // or SVG text, or chrome docs, we assume those know what they do.
1358 if (aFont->mSize == 0 || !aFont->mAllowZoomAndMinSize ||
1359 nsContentUtils::IsChromeDoc(aDocument)) {
1360 return 0;
1363 nscoord minFontSize;
1364 bool needsCache = false;
1366 auto MinFontSize = [&](bool* aNeedsToCache) {
1367 auto* prefs =
1368 aDocument->GetFontPrefsForLang(aFont->mLanguage, aNeedsToCache);
1369 return prefs ? prefs->mMinimumFontSize : 0;
1373 AutoReadLock guard(*sServoFFILock);
1374 minFontSize = MinFontSize(&needsCache);
1377 if (needsCache) {
1378 AutoWriteLock guard(*sServoFFILock);
1379 minFontSize = MinFontSize(nullptr);
1382 if (minFontSize < 0) {
1383 return 0;
1386 return (minFontSize * aFont->mMinFontSizeRatio) / 100;
1389 void FontSizePrefs::CopyFrom(const LangGroupFontPrefs& prefs) {
1390 mDefaultVariableSize = prefs.mDefaultVariableFont.size;
1391 mDefaultSerifSize = prefs.mDefaultSerifFont.size;
1392 mDefaultSansSerifSize = prefs.mDefaultSansSerifFont.size;
1393 mDefaultMonospaceSize = prefs.mDefaultMonospaceFont.size;
1394 mDefaultCursiveSize = prefs.mDefaultCursiveFont.size;
1395 mDefaultFantasySize = prefs.mDefaultFantasyFont.size;
1398 FontSizePrefs Gecko_GetBaseSize(nsAtom* aLanguage) {
1399 LangGroupFontPrefs prefs;
1400 nsStaticAtom* langGroupAtom =
1401 StaticPresData::Get()->GetUncachedLangGroup(aLanguage);
1402 prefs.Initialize(langGroupAtom);
1403 FontSizePrefs sizes;
1404 sizes.CopyFrom(prefs);
1405 return sizes;
1408 static StaticRefPtr<UACacheReporter> gUACacheReporter;
1410 namespace mozilla {
1412 void InitializeServo() {
1413 URLExtraData::InitDummy();
1414 Servo_Initialize(URLExtraData::Dummy());
1416 gUACacheReporter = new UACacheReporter();
1417 RegisterWeakMemoryReporter(gUACacheReporter);
1419 sServoFFILock = new RWLock("Servo::FFILock");
1422 void ShutdownServo() {
1423 MOZ_ASSERT(sServoFFILock);
1425 UnregisterWeakMemoryReporter(gUACacheReporter);
1426 gUACacheReporter = nullptr;
1428 delete sServoFFILock;
1429 Servo_Shutdown();
1432 void AssertIsMainThreadOrServoFontMetricsLocked() {
1433 if (!NS_IsMainThread()) {
1434 MOZ_ASSERT(sServoFFILock &&
1435 sServoFFILock->LockedForWritingByCurrentThread());
1439 } // namespace mozilla
1441 GeckoFontMetrics Gecko_GetFontMetrics(const nsPresContext* aPresContext,
1442 bool aIsVertical,
1443 const nsStyleFont* aFont,
1444 nscoord aFontSize, bool aUseUserFontSet) {
1445 AutoWriteLock guard(*sServoFFILock);
1446 GeckoFontMetrics ret;
1448 // Getting font metrics can require some main thread only work to be
1449 // done, such as work that needs to touch non-threadsafe refcounted
1450 // objects (like the DOM FontFace/FontFaceSet objects), network loads, etc.
1452 // To handle this work, font code checks whether we are in a Servo traversal
1453 // and if so, appends PostTraversalTasks to the current ServoStyleSet
1454 // to be performed immediately after the traversal is finished. This
1455 // works well for starting downloadable font loads, since we don't have
1456 // those fonts available to get metrics for anyway. Platform fonts and
1457 // ArrayBuffer-backed FontFace objects are handled synchronously.
1459 nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
1460 presContext->SetUsesExChUnits(true);
1461 RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetMetricsFor(
1462 presContext, aIsVertical, aFont, aFontSize, aUseUserFontSet);
1464 ret.mXSize = fm->XHeight();
1465 gfxFloat zeroWidth = fm->GetThebesFontGroup()
1466 ->GetFirstValidFont()
1467 ->GetMetrics(fm->Orientation())
1468 .zeroWidth;
1469 ret.mChSize = zeroWidth >= 0.0
1470 ? NS_round(aPresContext->AppUnitsPerDevPixel() * zeroWidth)
1471 : -1.0;
1472 return ret;
1475 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(SheetLoadDataHolder, SheetLoadDataHolder);
1477 void Gecko_StyleSheet_FinishAsyncParse(
1478 SheetLoadDataHolder* aData,
1479 StyleStrong<RawServoStyleSheetContents> aSheetContents,
1480 StyleOwnedOrNull<StyleUseCounters> aUseCounters) {
1481 UniquePtr<StyleUseCounters> useCounters = aUseCounters.Consume();
1482 RefPtr<SheetLoadDataHolder> loadData = aData;
1483 RefPtr<RawServoStyleSheetContents> sheetContents = aSheetContents.Consume();
1484 NS_DispatchToMainThread(NS_NewRunnableFunction(
1485 __func__, [d = std::move(loadData), contents = std::move(sheetContents),
1486 counters = std::move(useCounters)]() mutable {
1487 MOZ_ASSERT(NS_IsMainThread());
1488 SheetLoadData* data = d->get();
1489 if (Document* doc = data->mLoader->GetDocument()) {
1490 if (const auto* docCounters = doc->GetStyleUseCounters()) {
1491 Servo_UseCounters_Merge(docCounters, counters.get());
1494 data->mSheet->FinishAsyncParse(contents.forget());
1495 }));
1498 static already_AddRefed<StyleSheet> LoadImportSheet(
1499 Loader* aLoader, StyleSheet* aParent, SheetLoadData* aParentLoadData,
1500 LoaderReusableStyleSheets* aReusableSheets, const StyleCssUrl& aURL,
1501 already_AddRefed<RawServoMediaList> aMediaList) {
1502 MOZ_ASSERT(NS_IsMainThread());
1503 MOZ_ASSERT(aLoader, "Should've catched this before");
1504 MOZ_ASSERT(aParent, "Only used for @import, so parent should exist!");
1506 RefPtr<MediaList> media = new MediaList(std::move(aMediaList));
1507 nsCOMPtr<nsIURI> uri = aURL.GetURI();
1508 nsresult rv = uri ? NS_OK : NS_ERROR_FAILURE;
1510 size_t previousSheetCount = aParent->ChildSheets().Length();
1511 if (NS_SUCCEEDED(rv)) {
1512 // TODO(emilio): We should probably make LoadChildSheet return the
1513 // stylesheet rather than the return code.
1514 rv = aLoader->LoadChildSheet(*aParent, aParentLoadData, uri, media,
1515 aReusableSheets);
1518 if (NS_FAILED(rv) || previousSheetCount == aParent->ChildSheets().Length()) {
1519 // Servo and Gecko have different ideas of what a valid URL is, so we might
1520 // get in here with a URL string that NS_NewURI can't handle. We may also
1521 // reach here via an import cycle. For the import cycle case, we need some
1522 // sheet object per spec, even if its empty. DevTools uses the URI to
1523 // realize it has hit an import cycle, so we mark it complete to make the
1524 // sheet readable from JS.
1525 RefPtr<StyleSheet> emptySheet =
1526 aParent->CreateEmptyChildSheet(media.forget());
1527 // Make a dummy URI if we don't have one because some methods assume
1528 // non-null URIs.
1529 if (!uri) {
1530 NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:invalid"));
1532 emptySheet->SetURIs(uri, uri, uri);
1533 emptySheet->SetPrincipal(aURL.ExtraData().Principal());
1534 nsCOMPtr<nsIReferrerInfo> referrerInfo =
1535 ReferrerInfo::CreateForExternalCSSResources(emptySheet);
1536 emptySheet->SetReferrerInfo(referrerInfo);
1537 emptySheet->SetComplete();
1538 aParent->AppendStyleSheet(*emptySheet);
1539 return emptySheet.forget();
1542 RefPtr<StyleSheet> sheet = aParent->ChildSheets().LastElement();
1543 return sheet.forget();
1546 StyleSheet* Gecko_LoadStyleSheet(Loader* aLoader, StyleSheet* aParent,
1547 SheetLoadData* aParentLoadData,
1548 LoaderReusableStyleSheets* aReusableSheets,
1549 const StyleCssUrl* aUrl,
1550 StyleStrong<RawServoMediaList> aMediaList) {
1551 MOZ_ASSERT(NS_IsMainThread());
1552 MOZ_ASSERT(aUrl);
1554 return LoadImportSheet(aLoader, aParent, aParentLoadData, aReusableSheets,
1555 *aUrl, aMediaList.Consume())
1556 .take();
1559 void Gecko_LoadStyleSheetAsync(SheetLoadDataHolder* aParentData,
1560 const StyleCssUrl* aUrl,
1561 StyleStrong<RawServoMediaList> aMediaList,
1562 StyleStrong<RawServoImportRule> aImportRule) {
1563 MOZ_ASSERT(aUrl);
1564 RefPtr<SheetLoadDataHolder> loadData = aParentData;
1565 RefPtr<RawServoMediaList> mediaList = aMediaList.Consume();
1566 RefPtr<RawServoImportRule> importRule = aImportRule.Consume();
1567 NS_DispatchToMainThread(NS_NewRunnableFunction(
1568 __func__,
1569 [data = std::move(loadData), url = StyleCssUrl(*aUrl),
1570 media = std::move(mediaList), import = std::move(importRule)]() mutable {
1571 MOZ_ASSERT(NS_IsMainThread());
1572 SheetLoadData* d = data->get();
1573 RefPtr<StyleSheet> sheet = LoadImportSheet(
1574 d->mLoader, d->mSheet, d, nullptr, url, media.forget());
1575 Servo_ImportRule_SetSheet(import, sheet);
1576 }));
1579 void Gecko_AddPropertyToSet(nsCSSPropertyIDSet* aPropertySet,
1580 nsCSSPropertyID aProperty) {
1581 aPropertySet->AddProperty(aProperty);
1584 #define STYLE_STRUCT(name) \
1586 void Gecko_Construct_Default_nsStyle##name(nsStyle##name* ptr, \
1587 const Document* doc) { \
1588 new (ptr) nsStyle##name(*doc); \
1591 void Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr, \
1592 const nsStyle##name* other) { \
1593 new (ptr) nsStyle##name(*other); \
1596 void Gecko_Destroy_nsStyle##name(nsStyle##name* ptr) { \
1597 ptr->~nsStyle##name(); \
1600 void Gecko_RegisterProfilerThread(const char* name) {
1601 PROFILER_REGISTER_THREAD(name);
1604 void Gecko_UnregisterProfilerThread() { PROFILER_UNREGISTER_THREAD(); }
1606 #ifdef MOZ_GECKO_PROFILER
1607 void Gecko_Construct_AutoProfilerLabel(AutoProfilerLabel* aAutoLabel,
1608 JS::ProfilingCategoryPair aCatPair) {
1609 new (aAutoLabel) AutoProfilerLabel(
1610 "", nullptr, aCatPair,
1611 uint32_t(
1612 js::ProfilingStackFrame::Flags::LABEL_DETERMINED_BY_CATEGORY_PAIR));
1615 void Gecko_Destroy_AutoProfilerLabel(AutoProfilerLabel* aAutoLabel) {
1616 aAutoLabel->~AutoProfilerLabel();
1618 #endif
1620 bool Gecko_DocumentRule_UseForPresentation(
1621 const Document* aDocument, const nsACString* aPattern,
1622 DocumentMatchingFunction aMatchingFunction) {
1623 MOZ_ASSERT(NS_IsMainThread());
1625 nsIURI* docURI = aDocument->GetDocumentURI();
1626 nsAutoCString docURISpec;
1627 if (docURI) {
1628 // If GetSpec fails (due to OOM) just skip these URI-specific CSS rules.
1629 nsresult rv = docURI->GetSpec(docURISpec);
1630 NS_ENSURE_SUCCESS(rv, false);
1633 return CSSMozDocumentRule::Match(aDocument, docURI, docURISpec, *aPattern,
1634 aMatchingFunction);
1637 void Gecko_SetJemallocThreadLocalArena(bool enabled) {
1638 #if defined(MOZ_MEMORY)
1639 jemalloc_thread_local_arena(enabled);
1640 #endif
1643 #include "nsStyleStructList.h"
1645 #undef STYLE_STRUCT
1647 bool Gecko_ErrorReportingEnabled(const StyleSheet* aSheet,
1648 const Loader* aLoader,
1649 uint64_t* aOutWindowId) {
1650 if (!ErrorReporter::ShouldReportErrors(aSheet, aLoader)) {
1651 return false;
1653 *aOutWindowId = ErrorReporter::FindInnerWindowId(aSheet, aLoader);
1654 return true;
1657 void Gecko_ReportUnexpectedCSSError(
1658 const uint64_t aWindowId, nsIURI* aURI, const char* message,
1659 const char* param, uint32_t paramLen, const char* prefix,
1660 const char* prefixParam, uint32_t prefixParamLen, const char* suffix,
1661 const char* source, uint32_t sourceLen, const char* selectors,
1662 uint32_t selectorsLen, uint32_t lineNumber, uint32_t colNumber) {
1663 MOZ_RELEASE_ASSERT(NS_IsMainThread());
1665 ErrorReporter reporter(aWindowId);
1667 if (prefix) {
1668 if (prefixParam) {
1669 nsDependentCSubstring paramValue(prefixParam, prefixParamLen);
1670 AutoTArray<nsString, 1> wideParam;
1671 CopyUTF8toUTF16(paramValue, *wideParam.AppendElement());
1672 reporter.ReportUnexpectedUnescaped(prefix, wideParam);
1673 } else {
1674 reporter.ReportUnexpected(prefix);
1678 if (param) {
1679 nsDependentCSubstring paramValue(param, paramLen);
1680 AutoTArray<nsString, 1> wideParam;
1681 CopyUTF8toUTF16(paramValue, *wideParam.AppendElement());
1682 reporter.ReportUnexpectedUnescaped(message, wideParam);
1683 } else {
1684 reporter.ReportUnexpected(message);
1687 if (suffix) {
1688 reporter.ReportUnexpected(suffix);
1690 nsDependentCSubstring sourceValue(source, sourceLen);
1691 nsDependentCSubstring selectorsValue(selectors, selectorsLen);
1692 reporter.OutputError(sourceValue, selectorsValue, lineNumber, colNumber,
1693 aURI);
1696 void Gecko_ContentList_AppendAll(nsSimpleContentList* aList,
1697 const Element** aElements, size_t aLength) {
1698 MOZ_ASSERT(NS_IsMainThread());
1699 MOZ_ASSERT(aElements);
1700 MOZ_ASSERT(aLength);
1701 MOZ_ASSERT(aList);
1703 aList->SetCapacity(aLength);
1705 for (size_t i = 0; i < aLength; ++i) {
1706 aList->AppendElement(const_cast<Element*>(aElements[i]));
1710 const nsTArray<Element*>* Gecko_Document_GetElementsWithId(const Document* aDoc,
1711 nsAtom* aId) {
1712 MOZ_ASSERT(aDoc);
1713 MOZ_ASSERT(aId);
1715 return aDoc->GetAllElementsForId(nsDependentAtomString(aId));
1718 const nsTArray<Element*>* Gecko_ShadowRoot_GetElementsWithId(
1719 const ShadowRoot* aShadowRoot, nsAtom* aId) {
1720 MOZ_ASSERT(aShadowRoot);
1721 MOZ_ASSERT(aId);
1723 return aShadowRoot->GetAllElementsForId(nsDependentAtomString(aId));
1726 bool Gecko_GetBoolPrefValue(const char* aPrefName) {
1727 MOZ_ASSERT(NS_IsMainThread());
1728 return Preferences::GetBool(aPrefName);
1731 bool Gecko_IsInServoTraversal() { return ServoStyleSet::IsInServoTraversal(); }
1733 bool Gecko_IsMainThread() { return NS_IsMainThread(); }
1735 const nsAttrValue* Gecko_GetSVGAnimatedClass(const Element* aElement) {
1736 MOZ_ASSERT(aElement->IsSVGElement());
1737 return static_cast<const SVGElement*>(aElement)->GetAnimatedClassName();
1740 bool Gecko_AssertClassAttrValueIsSane(const nsAttrValue* aValue) {
1741 MOZ_ASSERT(aValue->Type() == nsAttrValue::eAtom ||
1742 aValue->Type() == nsAttrValue::eString ||
1743 aValue->Type() == nsAttrValue::eAtomArray);
1744 MOZ_ASSERT_IF(
1745 aValue->Type() == nsAttrValue::eString,
1746 nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
1747 aValue->GetStringValue())
1748 .IsEmpty());
1749 return true;
1752 void Gecko_GetSafeAreaInsets(const nsPresContext* aPresContext, float* aTop,
1753 float* aRight, float* aBottom, float* aLeft) {
1754 MOZ_ASSERT(aPresContext);
1755 ScreenIntMargin safeAreaInsets = aPresContext->GetSafeAreaInsets();
1756 *aTop = aPresContext->DevPixelsToFloatCSSPixels(safeAreaInsets.top);
1757 *aRight = aPresContext->DevPixelsToFloatCSSPixels(safeAreaInsets.right);
1758 *aBottom = aPresContext->DevPixelsToFloatCSSPixels(safeAreaInsets.bottom);
1759 *aLeft = aPresContext->DevPixelsToFloatCSSPixels(safeAreaInsets.left);
1762 void Gecko_PrintfStderr(const nsCString* aStr) {
1763 printf_stderr("%s", aStr->get());
1766 nsAtom* Gecko_Element_ImportedPart(const nsAttrValue* aValue,
1767 nsAtom* aPartName) {
1768 if (aValue->Type() != nsAttrValue::eShadowParts) {
1769 return nullptr;
1771 return aValue->GetShadowPartsValue().GetReverse(aPartName);
1774 nsAtom** Gecko_Element_ExportedParts(const nsAttrValue* aValue,
1775 nsAtom* aPartName, size_t* aOutLength) {
1776 if (aValue->Type() != nsAttrValue::eShadowParts) {
1777 return nullptr;
1779 auto* parts = aValue->GetShadowPartsValue().Get(aPartName);
1780 if (!parts) {
1781 return nullptr;
1783 *aOutLength = parts->Length();
1784 static_assert(sizeof(RefPtr<nsAtom>) == sizeof(nsAtom*));
1785 static_assert(alignof(RefPtr<nsAtom>) == alignof(nsAtom*));
1786 return reinterpret_cast<nsAtom**>(parts->Elements());