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"
29 #include "nsIMozBrowserFrame.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"
40 #include "nsStyleStruct.h"
41 #include "nsStyleUtil.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"
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;
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
);
111 AutoWriteLock
guard(*sServoFFILock
);
112 retval
= GetDefaultFont(nullptr);
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
,
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());
163 auto* array
= new nsTArray
<nsIContent
*>();
164 nsContentUtils::AppendNativeAnonymousChildren(aElement
, *array
, 0);
168 void Gecko_DestroyAnonymousContentList(nsTArray
<nsIContent
*>* aAnonContent
) {
169 MOZ_ASSERT(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"
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
216 // - custom_properties
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
) {
246 MOZ_ASSERT(NS_IsMainThread());
248 if (!StaticPrefs::layout_css_visited_links_enabled()) {
252 if (aDoc
->IsBeingUsedAsImage()) {
256 nsILoadContext
* loadContext
= aDoc
->GetLoadContext();
257 if (loadContext
&& loadContext
->UsePrivateBrowsing()) {
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
;
328 const ServoElementSnapshot
* Gecko_GetElementSnapshot(
329 const ServoElementSnapshotTable
* aTable
, const Element
* aElement
) {
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());
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();
352 return decl
->RefRawStrong();
355 void Gecko_UnsetDirtyStyleAttr(const Element
* aElement
) {
356 DeclarationBlock
* decl
= aElement
->GetInlineStyleDeclaration();
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();
375 auto* svg
= SVGElement::FromNodeOrNull(aElement
);
377 if (auto decl
= svg
->GetContentDeclarationBlock()) {
378 return decl
->RefRawStrong();
384 return AsRefRawStrong(attrs
->GetServoStyle());
387 const StyleStrong
<RawServoDeclarationBlock
>*
388 Gecko_GetExtraContentStyleDeclarations(const Element
* aElement
) {
389 if (!aElement
->IsAnyOfHTMLElements(nsGkAtoms::td
, nsGkAtoms::th
)) {
392 const HTMLTableCellElement
* cell
=
393 static_cast<const HTMLTableCellElement
*>(aElement
);
394 if (nsMappedAttributes
* attrs
=
395 cell
->GetMappedAttributesInheritedFromTable()) {
396 return AsRefRawStrong(attrs
->GetServoStyle());
401 const StyleStrong
<RawServoDeclarationBlock
>*
402 Gecko_GetUnvisitedLinkAttrDeclarationBlock(const Element
* aElement
) {
403 nsHTMLStyleSheet
* sheet
= aElement
->OwnerDoc()->GetAttributeStyleSheet();
408 return AsRefRawStrong(sheet
->GetServoUnvisitedLinkDecl());
411 StyleSheet
* Gecko_StyleSheet_Clone(const StyleSheet
* aSheet
,
412 const StyleSheet
* aNewParentSheet
) {
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
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();
446 return AsRefRawStrong(sheet
->GetServoVisitedLinkDecl());
449 const StyleStrong
<RawServoDeclarationBlock
>*
450 Gecko_GetActiveLinkAttrDeclarationBlock(const Element
* aElement
) {
451 nsHTMLStyleSheet
* sheet
= aElement
->OwnerDoc()->GetAttributeStyleSheet();
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();
488 nsPresContext
* presContext
= doc
->GetPresContext();
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
) {
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()) {
530 nsPresContext
* presContext
= nsContentUtils::GetContextForContent(aElement
);
531 if (!presContext
|| !presContext
->IsDynamic()) {
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
550 if (!aComputedData
) {
554 if (aTasks
& UpdateAnimationsTasks::CSSTransitions
) {
555 MOZ_ASSERT(aOldComputedData
);
556 presContext
->TransitionManager()->UpdateTransitions(
557 const_cast<Element
*>(aElement
), pseudoType
, *aOldComputedData
,
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.
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
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
,
633 PseudoStyleType pseudoType
= GetPseudoTypeFromElementForAnimation(aElement
);
634 nsTransitionManager::CSSTransitionCollection
* collection
=
635 nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
636 aElement
, pseudoType
);
640 nsTArray
<RefPtr
<CSSTransition
>>& transitions
= collection
->mAnimations
;
641 return aIndex
< transitions
.Length() ? transitions
[aIndex
].get() : nullptr;
644 nsCSSPropertyID
Gecko_ElementTransitions_PropertyAt(const Element
* aElement
,
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
>*>(
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
);
697 LookAndFeel::ColorID colorId
= static_cast<LookAndFeel::ColorID
>(aId
);
698 AutoWriteLock
guard(*sServoFFILock
);
699 LookAndFeel::GetColor(colorId
, useStandinsForNativeColors
, &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
) {
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
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())) {
740 nsAtom
* Gecko_GetXMLLangValue(const Element
* aElement
) {
741 const nsAttrValue
* attr
=
742 aElement
->GetParsedAttr(nsGkAtoms::lang
, kNameSpaceID_XML
);
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
)) {
766 const nsAttrValue
* val
= aElement
->GetParsedAttr(nsGkAtoms::border
);
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
);
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
,
798 if (MOZ_LIKELY(aNS
)) {
799 int32_t ns
= aNS
== nsGkAtoms::_empty
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
) {
817 if (aMatch(attrInfo
.mValue
)) {
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_; \
844 const nsDefaultStringComparator c_; \
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
) {
853 aValue
->ToString(str
);
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
) {
866 aValue
->ToString(str
);
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
) {
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
) {
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
) {
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
),
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
) {
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
,
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
) {
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
,
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
{
1172 enum class KeyframeInsertPosition
{
1177 static Keyframe
* GetOrCreateKeyframe(nsTArray
<Keyframe
>* aKeyframes
,
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
];
1195 case KeyframeSearchDirection::Backwards
:
1196 if (nsAnimationManager::FindMatchingKeyframe(Reversed(*aKeyframes
),
1197 aOffset
, *aTimingFunction
,
1199 return &(*aKeyframes
)[aKeyframes
->Length() - 1 - keyframeIndex
];
1201 keyframeIndex
= aKeyframes
->Length() - 1;
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
);
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
) {
1254 if (aURL
->IsLocalRef()) {
1255 aOut
->Assign(aURL
->SpecifiedSerialization());
1258 Gecko_GetComputedImageURLSpec(aURL
, aOut
);
1261 void Gecko_GetComputedImageURLSpec(const StyleComputedUrl
* aURL
,
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
)) {
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?
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
,
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;
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(":");
1307 NS_ConvertUTF16toUTF8(nsDependentAtomString(info
.mName
->LocalName())));
1311 aOut
.AppendLiteral("=\"");
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
,
1325 DebugListAttributes(*aElement
, *aOut
);
1328 void Gecko_Snapshot_DebugListAttributes(const ServoElementSnapshot
* aSnapshot
,
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
)) {
1363 nscoord minFontSize
;
1364 bool needsCache
= false;
1366 auto MinFontSize
= [&](bool* aNeedsToCache
) {
1368 aDocument
->GetFontPrefsForLang(aFont
->mLanguage
, aNeedsToCache
);
1369 return prefs
? prefs
->mMinimumFontSize
: 0;
1373 AutoReadLock
guard(*sServoFFILock
);
1374 minFontSize
= MinFontSize(&needsCache
);
1378 AutoWriteLock
guard(*sServoFFILock
);
1379 minFontSize
= MinFontSize(nullptr);
1382 if (minFontSize
< 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
);
1408 static StaticRefPtr
<UACacheReporter
> gUACacheReporter
;
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
;
1432 void AssertIsMainThreadOrServoFontMetricsLocked() {
1433 if (!NS_IsMainThread()) {
1434 MOZ_ASSERT(sServoFFILock
&&
1435 sServoFFILock
->LockedForWritingByCurrentThread());
1439 } // namespace mozilla
1441 GeckoFontMetrics
Gecko_GetFontMetrics(const nsPresContext
* aPresContext
,
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())
1469 ret
.mChSize
= zeroWidth
>= 0.0
1470 ? NS_round(aPresContext
->AppUnitsPerDevPixel() * zeroWidth
)
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());
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
,
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
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());
1554 return LoadImportSheet(aLoader
, aParent
, aParentLoadData
, aReusableSheets
,
1555 *aUrl
, aMediaList
.Consume())
1559 void Gecko_LoadStyleSheetAsync(SheetLoadDataHolder
* aParentData
,
1560 const StyleCssUrl
* aUrl
,
1561 StyleStrong
<RawServoMediaList
> aMediaList
,
1562 StyleStrong
<RawServoImportRule
> aImportRule
) {
1564 RefPtr
<SheetLoadDataHolder
> loadData
= aParentData
;
1565 RefPtr
<RawServoMediaList
> mediaList
= aMediaList
.Consume();
1566 RefPtr
<RawServoImportRule
> importRule
= aImportRule
.Consume();
1567 NS_DispatchToMainThread(NS_NewRunnableFunction(
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
);
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
,
1612 js::ProfilingStackFrame::Flags::LABEL_DETERMINED_BY_CATEGORY_PAIR
));
1615 void Gecko_Destroy_AutoProfilerLabel(AutoProfilerLabel
* aAutoLabel
) {
1616 aAutoLabel
->~AutoProfilerLabel();
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
;
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
,
1637 void Gecko_SetJemallocThreadLocalArena(bool enabled
) {
1638 #if defined(MOZ_MEMORY)
1639 jemalloc_thread_local_arena(enabled
);
1643 #include "nsStyleStructList.h"
1647 bool Gecko_ErrorReportingEnabled(const StyleSheet
* aSheet
,
1648 const Loader
* aLoader
,
1649 uint64_t* aOutWindowId
) {
1650 if (!ErrorReporter::ShouldReportErrors(aSheet
, aLoader
)) {
1653 *aOutWindowId
= ErrorReporter::FindInnerWindowId(aSheet
, aLoader
);
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
);
1669 nsDependentCSubstring
paramValue(prefixParam
, prefixParamLen
);
1670 AutoTArray
<nsString
, 1> wideParam
;
1671 CopyUTF8toUTF16(paramValue
, *wideParam
.AppendElement());
1672 reporter
.ReportUnexpectedUnescaped(prefix
, wideParam
);
1674 reporter
.ReportUnexpected(prefix
);
1679 nsDependentCSubstring
paramValue(param
, paramLen
);
1680 AutoTArray
<nsString
, 1> wideParam
;
1681 CopyUTF8toUTF16(paramValue
, *wideParam
.AppendElement());
1682 reporter
.ReportUnexpectedUnescaped(message
, wideParam
);
1684 reporter
.ReportUnexpected(message
);
1688 reporter
.ReportUnexpected(suffix
);
1690 nsDependentCSubstring
sourceValue(source
, sourceLen
);
1691 nsDependentCSubstring
selectorsValue(selectors
, selectorsLen
);
1692 reporter
.OutputError(sourceValue
, selectorsValue
, lineNumber
, colNumber
,
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
);
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
,
1715 return aDoc
->GetAllElementsForId(nsDependentAtomString(aId
));
1718 const nsTArray
<Element
*>* Gecko_ShadowRoot_GetElementsWithId(
1719 const ShadowRoot
* aShadowRoot
, nsAtom
* aId
) {
1720 MOZ_ASSERT(aShadowRoot
);
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
);
1745 aValue
->Type() == nsAttrValue::eString
,
1746 nsContentUtils::TrimWhitespace
<nsContentUtils::IsHTMLWhitespace
>(
1747 aValue
->GetStringValue())
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
) {
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
) {
1779 auto* parts
= aValue
->GetShadowPartsValue().Get(aPartName
);
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());