1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /* FFI functions for Servo to call into Gecko */
8 
9 #include "mozilla/GeckoBindings.h"
10 
11 #include "ChildIterator.h"
12 #include "ErrorReporter.h"
13 #include "gfxFontFeatures.h"
14 #include "gfxTextRun.h"
15 #include "imgLoader.h"
16 #include "nsAnimationManager.h"
17 #include "nsAttrValueInlines.h"
18 #include "nsCSSFrameConstructor.h"
19 #include "nsCSSProps.h"
20 #include "nsCSSPseudoElements.h"
21 #include "nsContentUtils.h"
22 #include "nsDOMTokenList.h"
23 #include "nsDeviceContext.h"
24 #include "nsLayoutUtils.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 "nsNameSpaceManager.h"
36 #include "nsNetUtil.h"
37 #include "nsProxyRelease.h"
38 #include "nsString.h"
39 #include "nsStyleStruct.h"
40 #include "nsStyleUtil.h"
41 #include "nsTArray.h"
42 #include "nsTransitionManager.h"
43 #include "nsWindowSizes.h"
44 
45 #include "mozilla/css/ImageLoader.h"
46 #include "mozilla/DeclarationBlock.h"
47 #include "mozilla/EffectCompositor.h"
48 #include "mozilla/EffectSet.h"
49 #include "mozilla/EventStates.h"
50 #include "mozilla/FontPropertyTypes.h"
51 #include "mozilla/Keyframe.h"
52 #include "mozilla/Mutex.h"
53 #include "mozilla/Preferences.h"
54 #include "mozilla/ServoElementSnapshot.h"
55 #include "mozilla/ShadowParts.h"
56 #include "mozilla/StaticPresData.h"
57 #include "mozilla/StaticPrefs_browser.h"
58 #include "mozilla/StaticPrefs_layout.h"
59 #include "mozilla/StaticPtr.h"
60 #include "mozilla/RestyleManager.h"
61 #include "mozilla/SizeOfState.h"
62 #include "mozilla/StyleAnimationValue.h"
63 #include "mozilla/ServoBindings.h"
64 #include "mozilla/ServoTraversalStatistics.h"
65 #include "mozilla/Telemetry.h"
66 #include "mozilla/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/HTMLSelectElement.h"
72 #include "mozilla/dom/HTMLSlotElement.h"
73 #include "mozilla/dom/MediaList.h"
74 #include "mozilla/dom/SVGElement.h"
75 #include "mozilla/LookAndFeel.h"
76 #include "mozilla/URLExtraData.h"
77 #include "mozilla/dom/CSSMozDocumentRule.h"
78 
79 #if defined(MOZ_MEMORY)
80 #  include "mozmemory.h"
81 #endif
82 
83 using namespace mozilla;
84 using namespace mozilla::css;
85 using namespace mozilla::dom;
86 
87 // Definitions of the global traversal stats.
88 bool ServoTraversalStatistics::sActive = false;
89 ServoTraversalStatistics ServoTraversalStatistics::sSingleton;
90 
91 static StaticAutoPtr<RWLock> sServoFFILock;
92 
ThreadSafeGetLangGroupFontPrefs(const Document & aDocument,nsAtom * aLanguage)93 static const LangGroupFontPrefs* ThreadSafeGetLangGroupFontPrefs(
94     const Document& aDocument, nsAtom* aLanguage) {
95   bool needsCache = false;
96   {
97     AutoReadLock guard(*sServoFFILock);
98     if (auto* prefs = aDocument.GetFontPrefsForLang(aLanguage, &needsCache)) {
99       return prefs;
100     }
101   }
102   MOZ_ASSERT(needsCache);
103   AutoWriteLock guard(*sServoFFILock);
104   return aDocument.GetFontPrefsForLang(aLanguage);
105 }
106 
ThreadSafeGetDefaultVariableFont(const Document & aDocument,nsAtom * aLanguage)107 static const nsFont& ThreadSafeGetDefaultVariableFont(const Document& aDocument,
108                                                       nsAtom* aLanguage) {
109   return ThreadSafeGetLangGroupFontPrefs(aDocument, aLanguage)
110       ->mDefaultVariableFont;
111 }
112 
113 /*
114  * Does this child count as significant for selector matching?
115  *
116  * See nsStyleUtil::IsSignificantChild for details.
117  */
Gecko_IsSignificantChild(const nsINode * aNode,bool aWhitespaceIsSignificant)118 bool Gecko_IsSignificantChild(const nsINode* aNode,
119                               bool aWhitespaceIsSignificant) {
120   return nsStyleUtil::ThreadSafeIsSignificantChild(aNode->AsContent(),
121                                                    aWhitespaceIsSignificant);
122 }
123 
Gecko_GetLastChild(const nsINode * aNode)124 const nsINode* Gecko_GetLastChild(const nsINode* aNode) {
125   return aNode->GetLastChild();
126 }
127 
Gecko_GetFlattenedTreeParentNode(const nsINode * aNode)128 const nsINode* Gecko_GetFlattenedTreeParentNode(const nsINode* aNode) {
129   return aNode->GetFlattenedTreeParentNodeForStyle();
130 }
131 
Gecko_GetBeforeOrAfterPseudo(const Element * aElement,bool aIsBefore)132 const Element* Gecko_GetBeforeOrAfterPseudo(const Element* aElement,
133                                             bool aIsBefore) {
134   MOZ_ASSERT(aElement);
135   MOZ_ASSERT(aElement->HasProperties());
136 
137   return aIsBefore ? nsLayoutUtils::GetBeforePseudo(aElement)
138                    : nsLayoutUtils::GetAfterPseudo(aElement);
139 }
140 
Gecko_GetMarkerPseudo(const Element * aElement)141 const Element* Gecko_GetMarkerPseudo(const Element* aElement) {
142   MOZ_ASSERT(aElement);
143   MOZ_ASSERT(aElement->HasProperties());
144 
145   return nsLayoutUtils::GetMarkerPseudo(aElement);
146 }
147 
Gecko_GetAnonymousContentForElement(const Element * aElement)148 nsTArray<nsIContent*>* Gecko_GetAnonymousContentForElement(
149     const Element* aElement) {
150   nsIAnonymousContentCreator* ac = do_QueryFrame(aElement->GetPrimaryFrame());
151   if (!ac) {
152     return nullptr;
153   }
154 
155   auto* array = new nsTArray<nsIContent*>();
156   nsContentUtils::AppendNativeAnonymousChildren(aElement, *array, 0);
157   return array;
158 }
159 
Gecko_DestroyAnonymousContentList(nsTArray<nsIContent * > * aAnonContent)160 void Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* aAnonContent) {
161   MOZ_ASSERT(aAnonContent);
162   delete aAnonContent;
163 }
164 
Gecko_GetAssignedNodes(const Element * aElement)165 const nsTArray<RefPtr<nsINode>>* Gecko_GetAssignedNodes(
166     const Element* aElement) {
167   MOZ_ASSERT(HTMLSlotElement::FromNode(aElement));
168   return &static_cast<const HTMLSlotElement*>(aElement)->AssignedNodes();
169 }
170 
Gecko_ComputedStyle_Init(ComputedStyle * aStyle,const ServoComputedData * aValues,PseudoStyleType aPseudoType)171 void Gecko_ComputedStyle_Init(ComputedStyle* aStyle,
172                               const ServoComputedData* aValues,
173                               PseudoStyleType aPseudoType) {
174   new (KnownNotNull, aStyle)
175       ComputedStyle(aPseudoType, ServoComputedDataForgotten(aValues));
176 }
177 
ServoComputedData(const ServoComputedDataForgotten aValue)178 ServoComputedData::ServoComputedData(const ServoComputedDataForgotten aValue) {
179   PodAssign(this, aValue.mPtr);
180 }
181 
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleStructsMallocEnclosingSizeOf)182 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleStructsMallocEnclosingSizeOf)
183 
184 void ServoComputedData::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const {
185   // Note: GetStyleFoo() returns a pointer to an nsStyleFoo that sits within a
186   // servo_arc::Arc, i.e. it is preceded by a word-sized refcount. So we need
187   // to measure it with a function that can handle an interior pointer. We use
188   // ServoStyleStructsEnclosingMallocSizeOf to clearly identify in DMD's
189   // output the memory measured here.
190 #define STYLE_STRUCT(name_)                                       \
191   static_assert(alignof(nsStyle##name_) <= sizeof(size_t),        \
192                 "alignment will break AddSizeOfExcludingThis()"); \
193   const void* p##name_ = GetStyle##name_();                       \
194   if (!aSizes.mState.HaveSeenPtr(p##name_)) {                     \
195     aSizes.mStyleSizes.NS_STYLE_SIZES_FIELD(name_) +=             \
196         ServoStyleStructsMallocEnclosingSizeOf(p##name_);         \
197   }
198 #include "nsStyleStructList.h"
199 #undef STYLE_STRUCT
200 
201   if (visited_style.mPtr && !aSizes.mState.HaveSeenPtr(visited_style.mPtr)) {
202     visited_style.mPtr->AddSizeOfIncludingThis(
203         aSizes, &aSizes.mLayoutComputedValuesVisited);
204   }
205 
206   // Measurement of the following members may be added later if DMD finds it is
207   // worthwhile:
208   // - custom_properties
209   // - writing_mode
210   // - rules
211   // - font_computation_data
212 }
213 
Gecko_ComputedStyle_Destroy(ComputedStyle * aStyle)214 void Gecko_ComputedStyle_Destroy(ComputedStyle* aStyle) {
215   aStyle->~ComputedStyle();
216 }
217 
Gecko_ConstructStyleChildrenIterator(const Element * aElement,StyleChildrenIterator * aIterator)218 void Gecko_ConstructStyleChildrenIterator(const Element* aElement,
219                                           StyleChildrenIterator* aIterator) {
220   MOZ_ASSERT(aElement);
221   MOZ_ASSERT(aIterator);
222   new (aIterator) StyleChildrenIterator(aElement);
223 }
224 
Gecko_DestroyStyleChildrenIterator(StyleChildrenIterator * aIterator)225 void Gecko_DestroyStyleChildrenIterator(StyleChildrenIterator* aIterator) {
226   MOZ_ASSERT(aIterator);
227 
228   aIterator->~StyleChildrenIterator();
229 }
230 
Gecko_GetNextStyleChild(StyleChildrenIterator * aIterator)231 const nsINode* Gecko_GetNextStyleChild(StyleChildrenIterator* aIterator) {
232   MOZ_ASSERT(aIterator);
233   return aIterator->GetNextChild();
234 }
235 
Gecko_VisitedStylesEnabled(const Document * aDoc)236 bool Gecko_VisitedStylesEnabled(const Document* aDoc) {
237   MOZ_ASSERT(aDoc);
238   MOZ_ASSERT(NS_IsMainThread());
239 
240   if (!StaticPrefs::layout_css_visited_links_enabled()) {
241     return false;
242   }
243 
244   if (aDoc->IsBeingUsedAsImage()) {
245     return false;
246   }
247 
248   nsILoadContext* loadContext = aDoc->GetLoadContext();
249   if (loadContext && loadContext->UsePrivateBrowsing()) {
250     return false;
251   }
252 
253   return true;
254 }
255 
Gecko_ElementState(const Element * aElement)256 EventStates::ServoType Gecko_ElementState(const Element* aElement) {
257   return aElement->StyleState().ServoValue();
258 }
259 
Gecko_IsRootElement(const Element * aElement)260 bool Gecko_IsRootElement(const Element* aElement) {
261   return aElement->OwnerDoc()->GetRootElement() == aElement;
262 }
263 
264 // Dirtiness tracking.
Gecko_SetNodeFlags(const nsINode * aNode,uint32_t aFlags)265 void Gecko_SetNodeFlags(const nsINode* aNode, uint32_t aFlags) {
266   const_cast<nsINode*>(aNode)->SetFlags(aFlags);
267 }
268 
Gecko_UnsetNodeFlags(const nsINode * aNode,uint32_t aFlags)269 void Gecko_UnsetNodeFlags(const nsINode* aNode, uint32_t aFlags) {
270   const_cast<nsINode*>(aNode)->UnsetFlags(aFlags);
271 }
272 
Gecko_NoteDirtyElement(const Element * aElement)273 void Gecko_NoteDirtyElement(const Element* aElement) {
274   MOZ_ASSERT(NS_IsMainThread());
275   const_cast<Element*>(aElement)->NoteDirtyForServo();
276 }
277 
Gecko_NoteDirtySubtreeForInvalidation(const Element * aElement)278 void Gecko_NoteDirtySubtreeForInvalidation(const Element* aElement) {
279   MOZ_ASSERT(NS_IsMainThread());
280   const_cast<Element*>(aElement)->NoteDirtySubtreeForServo();
281 }
282 
Gecko_NoteAnimationOnlyDirtyElement(const Element * aElement)283 void Gecko_NoteAnimationOnlyDirtyElement(const Element* aElement) {
284   MOZ_ASSERT(NS_IsMainThread());
285   const_cast<Element*>(aElement)->NoteAnimationOnlyDirtyForServo();
286 }
287 
Gecko_AnimationNameMayBeReferencedFromStyle(const nsPresContext * aPresContext,nsAtom * aName)288 bool Gecko_AnimationNameMayBeReferencedFromStyle(
289     const nsPresContext* aPresContext, nsAtom* aName) {
290   MOZ_ASSERT(aPresContext);
291   return aPresContext->AnimationManager()->AnimationMayBeReferenced(aName);
292 }
293 
Gecko_GetImplementedPseudo(const Element * aElement)294 PseudoStyleType Gecko_GetImplementedPseudo(const Element* aElement) {
295   return aElement->GetPseudoElementType();
296 }
297 
Gecko_CalcStyleDifference(const ComputedStyle * aOldStyle,const ComputedStyle * aNewStyle,bool * aAnyStyleStructChanged,bool * aOnlyResetStructsChanged)298 uint32_t Gecko_CalcStyleDifference(const ComputedStyle* aOldStyle,
299                                    const ComputedStyle* aNewStyle,
300                                    bool* aAnyStyleStructChanged,
301                                    bool* aOnlyResetStructsChanged) {
302   MOZ_ASSERT(aOldStyle);
303   MOZ_ASSERT(aNewStyle);
304 
305   uint32_t equalStructs;
306   nsChangeHint result =
307       aOldStyle->CalcStyleDifference(*aNewStyle, &equalStructs);
308 
309   *aAnyStyleStructChanged =
310       equalStructs != StyleStructConstants::kAllStructsMask;
311 
312   const auto kInheritedStructsMask =
313       StyleStructConstants::kInheritedStructsMask;
314   *aOnlyResetStructsChanged =
315       (equalStructs & kInheritedStructsMask) == kInheritedStructsMask;
316 
317   return result;
318 }
319 
Gecko_GetElementSnapshot(const ServoElementSnapshotTable * aTable,const Element * aElement)320 const ServoElementSnapshot* Gecko_GetElementSnapshot(
321     const ServoElementSnapshotTable* aTable, const Element* aElement) {
322   MOZ_ASSERT(aTable);
323   MOZ_ASSERT(aElement);
324 
325   return aTable->Get(const_cast<Element*>(aElement));
326 }
327 
Gecko_HaveSeenPtr(SeenPtrs * aTable,const void * aPtr)328 bool Gecko_HaveSeenPtr(SeenPtrs* aTable, const void* aPtr) {
329   MOZ_ASSERT(NS_IsMainThread());
330   MOZ_ASSERT(aTable);
331   // Empty Rust allocations are indicated by small values up to the alignment
332   // of the relevant type. We shouldn't see anything like that here.
333   MOZ_ASSERT(uintptr_t(aPtr) > 16);
334 
335   return aTable->HaveSeenPtr(aPtr);
336 }
337 
Gecko_GetStyleAttrDeclarationBlock(const Element * aElement)338 const StyleStrong<RawServoDeclarationBlock>* Gecko_GetStyleAttrDeclarationBlock(
339     const Element* aElement) {
340   DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
341   if (!decl) {
342     return nullptr;
343   }
344   return decl->RefRawStrong();
345 }
346 
Gecko_UnsetDirtyStyleAttr(const Element * aElement)347 void Gecko_UnsetDirtyStyleAttr(const Element* aElement) {
348   DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
349   if (!decl) {
350     return;
351   }
352   decl->UnsetDirty();
353 }
354 
AsRefRawStrong(const RefPtr<RawServoDeclarationBlock> & aDecl)355 static const StyleStrong<RawServoDeclarationBlock>* AsRefRawStrong(
356     const RefPtr<RawServoDeclarationBlock>& aDecl) {
357   static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
358                     sizeof(StyleStrong<RawServoDeclarationBlock>),
359                 "RefPtr should just be a pointer");
360   return reinterpret_cast<const StyleStrong<RawServoDeclarationBlock>*>(&aDecl);
361 }
362 
363 const StyleStrong<RawServoDeclarationBlock>*
Gecko_GetHTMLPresentationAttrDeclarationBlock(const Element * aElement)364 Gecko_GetHTMLPresentationAttrDeclarationBlock(const Element* aElement) {
365   const nsMappedAttributes* attrs = aElement->GetMappedAttributes();
366   if (!attrs) {
367     auto* svg = SVGElement::FromNodeOrNull(aElement);
368     if (svg) {
369       if (auto decl = svg->GetContentDeclarationBlock()) {
370         return decl->RefRawStrong();
371       }
372     }
373     return nullptr;
374   }
375 
376   return AsRefRawStrong(attrs->GetServoStyle());
377 }
378 
379 const StyleStrong<RawServoDeclarationBlock>*
Gecko_GetExtraContentStyleDeclarations(const Element * aElement)380 Gecko_GetExtraContentStyleDeclarations(const Element* aElement) {
381   if (!aElement->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th)) {
382     return nullptr;
383   }
384   const HTMLTableCellElement* cell =
385       static_cast<const HTMLTableCellElement*>(aElement);
386   if (nsMappedAttributes* attrs =
387           cell->GetMappedAttributesInheritedFromTable()) {
388     return AsRefRawStrong(attrs->GetServoStyle());
389   }
390   return nullptr;
391 }
392 
393 const StyleStrong<RawServoDeclarationBlock>*
Gecko_GetUnvisitedLinkAttrDeclarationBlock(const Element * aElement)394 Gecko_GetUnvisitedLinkAttrDeclarationBlock(const Element* aElement) {
395   nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
396   if (!sheet) {
397     return nullptr;
398   }
399 
400   return AsRefRawStrong(sheet->GetServoUnvisitedLinkDecl());
401 }
402 
Gecko_StyleSheet_Clone(const StyleSheet * aSheet,const StyleSheet * aNewParentSheet)403 StyleSheet* Gecko_StyleSheet_Clone(const StyleSheet* aSheet,
404                                    const StyleSheet* aNewParentSheet) {
405   MOZ_ASSERT(aSheet);
406   MOZ_ASSERT(aSheet->GetParentSheet(), "Should only be used for @import");
407   MOZ_ASSERT(aNewParentSheet, "Wat");
408 
409   RefPtr<StyleSheet> newSheet = aSheet->Clone(nullptr, nullptr);
410 
411   // NOTE(emilio): This code runs in the StylesheetInner constructor, which
412   // means that the inner pointer of `aNewParentSheet` still points to the old
413   // one.
414   //
415   // So we _don't_ update neither the parent pointer of the stylesheet, nor the
416   // child list (yet). This is fixed up in that same constructor.
417   return static_cast<StyleSheet*>(newSheet.forget().take());
418 }
419 
Gecko_StyleSheet_AddRef(const StyleSheet * aSheet)420 void Gecko_StyleSheet_AddRef(const StyleSheet* aSheet) {
421   MOZ_ASSERT(NS_IsMainThread());
422   const_cast<StyleSheet*>(aSheet)->AddRef();
423 }
424 
Gecko_StyleSheet_Release(const StyleSheet * aSheet)425 void Gecko_StyleSheet_Release(const StyleSheet* aSheet) {
426   MOZ_ASSERT(NS_IsMainThread());
427   const_cast<StyleSheet*>(aSheet)->Release();
428 }
429 
430 const StyleStrong<RawServoDeclarationBlock>*
Gecko_GetVisitedLinkAttrDeclarationBlock(const Element * aElement)431 Gecko_GetVisitedLinkAttrDeclarationBlock(const Element* aElement) {
432   nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
433   if (!sheet) {
434     return nullptr;
435   }
436 
437   return AsRefRawStrong(sheet->GetServoVisitedLinkDecl());
438 }
439 
440 const StyleStrong<RawServoDeclarationBlock>*
Gecko_GetActiveLinkAttrDeclarationBlock(const Element * aElement)441 Gecko_GetActiveLinkAttrDeclarationBlock(const Element* aElement) {
442   nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
443   if (!sheet) {
444     return nullptr;
445   }
446 
447   return AsRefRawStrong(sheet->GetServoActiveLinkDecl());
448 }
449 
GetPseudoTypeFromElementForAnimation(const Element * & aElementOrPseudo)450 static PseudoStyleType GetPseudoTypeFromElementForAnimation(
451     const Element*& aElementOrPseudo) {
452   if (aElementOrPseudo->IsGeneratedContentContainerForBefore()) {
453     aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
454     return PseudoStyleType::before;
455   }
456 
457   if (aElementOrPseudo->IsGeneratedContentContainerForAfter()) {
458     aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
459     return PseudoStyleType::after;
460   }
461 
462   if (aElementOrPseudo->IsGeneratedContentContainerForMarker()) {
463     aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
464     return PseudoStyleType::marker;
465   }
466 
467   return PseudoStyleType::NotPseudo;
468 }
469 
Gecko_GetAnimationRule(const Element * aElement,EffectCompositor::CascadeLevel aCascadeLevel,RawServoAnimationValueMap * aAnimationValues)470 bool Gecko_GetAnimationRule(const Element* aElement,
471                             EffectCompositor::CascadeLevel aCascadeLevel,
472                             RawServoAnimationValueMap* aAnimationValues) {
473   MOZ_ASSERT(aElement);
474 
475   Document* doc = aElement->GetComposedDoc();
476   if (!doc) {
477     return false;
478   }
479   nsPresContext* presContext = doc->GetPresContext();
480   if (!presContext) {
481     return false;
482   }
483 
484   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
485 
486   return presContext->EffectCompositor()->GetServoAnimationRule(
487       aElement, pseudoType, aCascadeLevel, aAnimationValues);
488 }
489 
Gecko_StyleAnimationsEquals(const nsStyleAutoArray<StyleAnimation> * aA,const nsStyleAutoArray<StyleAnimation> * aB)490 bool Gecko_StyleAnimationsEquals(const nsStyleAutoArray<StyleAnimation>* aA,
491                                  const nsStyleAutoArray<StyleAnimation>* aB) {
492   return *aA == *aB;
493 }
494 
Gecko_CopyAnimationNames(nsStyleAutoArray<StyleAnimation> * aDest,const nsStyleAutoArray<StyleAnimation> * aSrc)495 void Gecko_CopyAnimationNames(nsStyleAutoArray<StyleAnimation>* aDest,
496                               const nsStyleAutoArray<StyleAnimation>* aSrc) {
497   size_t srcLength = aSrc->Length();
498   aDest->EnsureLengthAtLeast(srcLength);
499 
500   for (size_t index = 0; index < srcLength; index++) {
501     (*aDest)[index].SetName((*aSrc)[index].GetName());
502   }
503 }
504 
Gecko_SetAnimationName(StyleAnimation * aStyleAnimation,nsAtom * aAtom)505 void Gecko_SetAnimationName(StyleAnimation* aStyleAnimation, nsAtom* aAtom) {
506   MOZ_ASSERT(aStyleAnimation);
507   aStyleAnimation->SetName(already_AddRefed<nsAtom>(aAtom));
508 }
509 
Gecko_UpdateAnimations(const Element * aElement,const ComputedStyle * aOldComputedData,const ComputedStyle * aComputedData,UpdateAnimationsTasks aTasks)510 void Gecko_UpdateAnimations(const Element* aElement,
511                             const ComputedStyle* aOldComputedData,
512                             const ComputedStyle* aComputedData,
513                             UpdateAnimationsTasks aTasks) {
514   MOZ_ASSERT(NS_IsMainThread());
515   MOZ_ASSERT(aElement);
516 
517   if (!aElement->IsInComposedDoc()) {
518     return;
519   }
520 
521   nsPresContext* presContext = nsContentUtils::GetContextForContent(aElement);
522   if (!presContext || !presContext->IsDynamic()) {
523     return;
524   }
525 
526   nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
527 
528   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
529 
530   if (aTasks & UpdateAnimationsTasks::CSSAnimations) {
531     presContext->AnimationManager()->UpdateAnimations(
532         const_cast<Element*>(aElement), pseudoType, aComputedData);
533   }
534 
535   // aComputedData might be nullptr if the target element is now in a
536   // display:none subtree. We still call Gecko_UpdateAnimations in this case
537   // because we need to stop CSS animations in the display:none subtree.
538   // However, we don't need to update transitions since they are stopped by
539   // RestyleManager::AnimationsWithDestroyedFrame so we just return early
540   // here.
541   if (!aComputedData) {
542     return;
543   }
544 
545   if (aTasks & UpdateAnimationsTasks::CSSTransitions) {
546     MOZ_ASSERT(aOldComputedData);
547     presContext->TransitionManager()->UpdateTransitions(
548         const_cast<Element*>(aElement), pseudoType, *aOldComputedData,
549         *aComputedData);
550   }
551 
552   if (aTasks & UpdateAnimationsTasks::EffectProperties) {
553     presContext->EffectCompositor()->UpdateEffectProperties(
554         aComputedData, const_cast<Element*>(aElement), pseudoType);
555   }
556 
557   if (aTasks & UpdateAnimationsTasks::CascadeResults) {
558     EffectSet* effectSet = EffectSet::GetEffectSet(aElement, pseudoType);
559     // CSS animations/transitions might have been destroyed as part of the above
560     // steps so before updating cascade results, we check if there are still any
561     // animations to update.
562     if (effectSet) {
563       // We call UpdateCascadeResults directly (intead of
564       // MaybeUpdateCascadeResults) since we know for sure that the cascade has
565       // changed, but we were unable to call MarkCascadeUpdated when we noticed
566       // it since we avoid mutating state as part of the Servo parallel
567       // traversal.
568       presContext->EffectCompositor()->UpdateCascadeResults(
569           *effectSet, const_cast<Element*>(aElement), pseudoType);
570     }
571   }
572 
573   if (aTasks & UpdateAnimationsTasks::DisplayChangedFromNone) {
574     presContext->EffectCompositor()->RequestRestyle(
575         const_cast<Element*>(aElement), pseudoType,
576         EffectCompositor::RestyleType::Standard,
577         EffectCompositor::CascadeLevel::Animations);
578   }
579 }
580 
Gecko_GetAnimationEffectCount(const Element * aElementOrPseudo)581 size_t Gecko_GetAnimationEffectCount(const Element* aElementOrPseudo) {
582   PseudoStyleType pseudoType =
583       GetPseudoTypeFromElementForAnimation(aElementOrPseudo);
584 
585   EffectSet* effectSet = EffectSet::GetEffectSet(aElementOrPseudo, pseudoType);
586   return effectSet ? effectSet->Count() : 0;
587 }
588 
Gecko_ElementHasAnimations(const Element * aElement)589 bool Gecko_ElementHasAnimations(const Element* aElement) {
590   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
591 
592   return !!EffectSet::GetEffectSet(aElement, pseudoType);
593 }
594 
Gecko_ElementHasCSSAnimations(const Element * aElement)595 bool Gecko_ElementHasCSSAnimations(const Element* aElement) {
596   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
597   nsAnimationManager::CSSAnimationCollection* collection =
598       nsAnimationManager::CSSAnimationCollection ::GetAnimationCollection(
599           aElement, pseudoType);
600 
601   return collection && !collection->mAnimations.IsEmpty();
602 }
603 
Gecko_ElementHasCSSTransitions(const Element * aElement)604 bool Gecko_ElementHasCSSTransitions(const Element* aElement) {
605   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
606   nsTransitionManager::CSSTransitionCollection* collection =
607       nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
608           aElement, pseudoType);
609 
610   return collection && !collection->mAnimations.IsEmpty();
611 }
612 
Gecko_ElementTransitions_Length(const Element * aElement)613 size_t Gecko_ElementTransitions_Length(const Element* aElement) {
614   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
615   nsTransitionManager::CSSTransitionCollection* collection =
616       nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
617           aElement, pseudoType);
618 
619   return collection ? collection->mAnimations.Length() : 0;
620 }
621 
GetCurrentTransitionAt(const Element * aElement,size_t aIndex)622 static CSSTransition* GetCurrentTransitionAt(const Element* aElement,
623                                              size_t aIndex) {
624   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
625   nsTransitionManager::CSSTransitionCollection* collection =
626       nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
627           aElement, pseudoType);
628   if (!collection) {
629     return nullptr;
630   }
631   nsTArray<RefPtr<CSSTransition>>& transitions = collection->mAnimations;
632   return aIndex < transitions.Length() ? transitions[aIndex].get() : nullptr;
633 }
634 
Gecko_ElementTransitions_PropertyAt(const Element * aElement,size_t aIndex)635 nsCSSPropertyID Gecko_ElementTransitions_PropertyAt(const Element* aElement,
636                                                     size_t aIndex) {
637   CSSTransition* transition = GetCurrentTransitionAt(aElement, aIndex);
638   return transition ? transition->TransitionProperty()
639                     : nsCSSPropertyID::eCSSProperty_UNKNOWN;
640 }
641 
Gecko_ElementTransitions_EndValueAt(const Element * aElement,size_t aIndex)642 const RawServoAnimationValue* Gecko_ElementTransitions_EndValueAt(
643     const Element* aElement, size_t aIndex) {
644   CSSTransition* transition = GetCurrentTransitionAt(aElement, aIndex);
645   return transition ? transition->ToValue().mServo.get() : nullptr;
646 }
647 
Gecko_GetProgressFromComputedTiming(const ComputedTiming * aTiming)648 double Gecko_GetProgressFromComputedTiming(const ComputedTiming* aTiming) {
649   return aTiming->mProgress.Value();
650 }
651 
Gecko_GetPositionInSegment(const AnimationPropertySegment * aSegment,double aProgress,ComputedTimingFunction::BeforeFlag aBeforeFlag)652 double Gecko_GetPositionInSegment(
653     const AnimationPropertySegment* aSegment, double aProgress,
654     ComputedTimingFunction::BeforeFlag aBeforeFlag) {
655   MOZ_ASSERT(aSegment->mFromKey < aSegment->mToKey,
656              "The segment from key should be less than to key");
657 
658   double positionInSegment = (aProgress - aSegment->mFromKey) /
659                              // To avoid floating precision inaccuracies, make
660                              // sure we calculate both the numerator and
661                              // denominator using double precision.
662                              (double(aSegment->mToKey) - aSegment->mFromKey);
663 
664   return ComputedTimingFunction::GetPortion(aSegment->mTimingFunction,
665                                             positionInSegment, aBeforeFlag);
666 }
667 
Gecko_AnimationGetBaseStyle(const RawServoAnimationValueTable * aBaseStyles,nsCSSPropertyID aProperty)668 const RawServoAnimationValue* Gecko_AnimationGetBaseStyle(
669     const RawServoAnimationValueTable* aBaseStyles, nsCSSPropertyID aProperty) {
670   auto base = reinterpret_cast<
671       const nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>*>(
672       aBaseStyles);
673   return base->GetWeak(aProperty);
674 }
675 
Gecko_FillAllImageLayers(nsStyleImageLayers * aLayers,uint32_t aMaxLen)676 void Gecko_FillAllImageLayers(nsStyleImageLayers* aLayers, uint32_t aMaxLen) {
677   aLayers->FillAllLayers(aMaxLen);
678 }
679 
Gecko_IsDocumentBody(const Element * aElement)680 bool Gecko_IsDocumentBody(const Element* aElement) {
681   Document* doc = aElement->GetUncomposedDoc();
682   return doc && doc->GetBodyElement() == aElement;
683 }
684 
Gecko_ComputeSystemColor(StyleSystemColor aColor,const Document * aDoc,const StyleColorScheme * aStyle)685 nscolor Gecko_ComputeSystemColor(StyleSystemColor aColor, const Document* aDoc,
686                                  const StyleColorScheme* aStyle) {
687   auto colorScheme = LookAndFeel::ColorSchemeForStyle(*aDoc, aStyle->bits);
688 
689   const auto& colors = PreferenceSheet::PrefsFor(*aDoc).ColorsFor(colorScheme);
690   switch (aColor) {
691     case StyleSystemColor::Canvastext:
692       return colors.mDefault;
693     case StyleSystemColor::Canvas:
694       return colors.mDefaultBackground;
695     case StyleSystemColor::Linktext:
696       return colors.mLink;
697     case StyleSystemColor::Activetext:
698       return colors.mActiveLink;
699     case StyleSystemColor::Visitedtext:
700       return colors.mVisitedLink;
701     default:
702       break;
703   }
704 
705   auto useStandins = LookAndFeel::ShouldUseStandins(*aDoc, aColor);
706 
707   AutoWriteLock guard(*sServoFFILock);
708   return LookAndFeel::Color(aColor, colorScheme, useStandins);
709 }
710 
Gecko_GetLookAndFeelInt(int32_t aId)711 int32_t Gecko_GetLookAndFeelInt(int32_t aId) {
712   auto intId = static_cast<LookAndFeel::IntID>(aId);
713   AutoWriteLock guard(*sServoFFILock);
714   return LookAndFeel::GetInt(intId);
715 }
716 
Gecko_GetLookAndFeelFloat(int32_t aId)717 float Gecko_GetLookAndFeelFloat(int32_t aId) {
718   auto id = static_cast<LookAndFeel::FloatID>(aId);
719   AutoWriteLock guard(*sServoFFILock);
720   return LookAndFeel::GetFloat(id);
721 }
722 
Gecko_MatchLang(const Element * aElement,nsAtom * aOverrideLang,bool aHasOverrideLang,const char16_t * aValue)723 bool Gecko_MatchLang(const Element* aElement, nsAtom* aOverrideLang,
724                      bool aHasOverrideLang, const char16_t* aValue) {
725   MOZ_ASSERT(!(aOverrideLang && !aHasOverrideLang),
726              "aHasOverrideLang should only be set when aOverrideLang is null");
727   MOZ_ASSERT(aValue, "null lang parameter");
728   if (!aValue || !*aValue) {
729     return false;
730   }
731 
732   // We have to determine the language of the current element.  Since
733   // this is currently no property and since the language is inherited
734   // from the parent we have to be prepared to look at all parent
735   // nodes.  The language itself is encoded in the LANG attribute.
736   if (auto* language = aHasOverrideLang ? aOverrideLang : aElement->GetLang()) {
737     return nsStyleUtil::DashMatchCompare(
738         nsDependentAtomString(language), nsDependentString(aValue),
739         nsASCIICaseInsensitiveStringComparator);
740   }
741 
742   // Try to get the language from the HTTP header or if this
743   // is missing as well from the preferences.
744   // The content language can be a comma-separated list of
745   // language codes.
746   nsAutoString language;
747   aElement->OwnerDoc()->GetContentLanguage(language);
748 
749   nsDependentString langString(aValue);
750   language.StripWhitespace();
751   for (auto const& lang : language.Split(char16_t(','))) {
752     if (nsStyleUtil::DashMatchCompare(lang, langString,
753                                       nsASCIICaseInsensitiveStringComparator)) {
754       return true;
755     }
756   }
757   return false;
758 }
759 
Gecko_GetXMLLangValue(const Element * aElement)760 nsAtom* Gecko_GetXMLLangValue(const Element* aElement) {
761   const nsAttrValue* attr =
762       aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
763 
764   if (!attr) {
765     return nullptr;
766   }
767 
768   MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
769 
770   RefPtr<nsAtom> atom = attr->GetAtomValue();
771   return atom.forget().take();
772 }
773 
Gecko_GetPrefSheetPrefs(const Document * aDoc)774 const PreferenceSheet::Prefs* Gecko_GetPrefSheetPrefs(const Document* aDoc) {
775   return &PreferenceSheet::PrefsFor(*aDoc);
776 }
777 
Gecko_IsTableBorderNonzero(const Element * aElement)778 bool Gecko_IsTableBorderNonzero(const Element* aElement) {
779   if (!aElement->IsHTMLElement(nsGkAtoms::table)) {
780     return false;
781   }
782   const nsAttrValue* val = aElement->GetParsedAttr(nsGkAtoms::border);
783   return val &&
784          (val->Type() != nsAttrValue::eInteger || val->GetIntegerValue() != 0);
785 }
786 
Gecko_IsBrowserFrame(const Element * aElement)787 bool Gecko_IsBrowserFrame(const Element* aElement) {
788   nsIMozBrowserFrame* browserFrame =
789       const_cast<Element*>(aElement)->GetAsMozBrowserFrame();
790   return browserFrame && browserFrame->GetReallyIsBrowser();
791 }
792 
Gecko_IsSelectListBox(const Element * aElement)793 bool Gecko_IsSelectListBox(const Element* aElement) {
794   const auto* select = HTMLSelectElement::FromNode(aElement);
795   return select && !select->IsCombobox();
796 }
797 
798 template <typename Implementor>
LangValue(Implementor * aElement)799 static nsAtom* LangValue(Implementor* aElement) {
800   // TODO(emilio): Deduplicate a bit with nsIContent::GetLang().
801   const nsAttrValue* attr =
802       aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
803   if (!attr && aElement->SupportsLangAttr()) {
804     attr = aElement->GetParsedAttr(nsGkAtoms::lang);
805   }
806 
807   if (!attr) {
808     return nullptr;
809   }
810 
811   MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
812   RefPtr<nsAtom> atom = attr->GetAtomValue();
813   return atom.forget().take();
814 }
815 
816 template <typename Implementor, typename MatchFn>
DoMatch(Implementor * aElement,nsAtom * aNS,nsAtom * aName,MatchFn aMatch)817 static bool DoMatch(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
818                     MatchFn aMatch) {
819   if (MOZ_LIKELY(aNS)) {
820     int32_t ns = aNS == nsGkAtoms::_empty
821                      ? kNameSpaceID_None
822                      : nsNameSpaceManager::GetInstance()->GetNameSpaceID(
823                            aNS, aElement->IsInChromeDocument());
824 
825     MOZ_ASSERT(ns == nsNameSpaceManager::GetInstance()->GetNameSpaceID(
826                          aNS, aElement->IsInChromeDocument()));
827     NS_ENSURE_TRUE(ns != kNameSpaceID_Unknown, false);
828     const nsAttrValue* value = aElement->GetParsedAttr(aName, ns);
829     return value && aMatch(value);
830   }
831 
832   // No namespace means any namespace - we have to check them all. :-(
833   BorrowedAttrInfo attrInfo;
834   for (uint32_t i = 0; (attrInfo = aElement->GetAttrInfoAt(i)); ++i) {
835     if (attrInfo.mName->LocalName() != aName) {
836       continue;
837     }
838     if (aMatch(attrInfo.mValue)) {
839       return true;
840     }
841   }
842   return false;
843 }
844 
845 template <typename Implementor>
HasAttr(Implementor * aElement,nsAtom * aNS,nsAtom * aName)846 static bool HasAttr(Implementor* aElement, nsAtom* aNS, nsAtom* aName) {
847   auto match = [](const nsAttrValue* aValue) { return true; };
848   return DoMatch(aElement, aNS, aName, match);
849 }
850 
851 template <typename Implementor>
AttrEquals(Implementor * aElement,nsAtom * aNS,nsAtom * aName,nsAtom * aStr,bool aIgnoreCase)852 static bool AttrEquals(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
853                        nsAtom* aStr, bool aIgnoreCase) {
854   auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
855     return aValue->Equals(aStr, aIgnoreCase ? eIgnoreCase : eCaseMatters);
856   };
857   return DoMatch(aElement, aNS, aName, match);
858 }
859 
860 #define WITH_COMPARATOR(ignore_case_, c_, expr_)                  \
861   auto c_ = ignore_case_ ? nsASCIICaseInsensitiveStringComparator \
862                          : nsTDefaultStringComparator<char16_t>;  \
863   return expr_;
864 
865 template <typename Implementor>
AttrDashEquals(Implementor * aElement,nsAtom * aNS,nsAtom * aName,nsAtom * aStr,bool aIgnoreCase)866 static bool AttrDashEquals(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
867                            nsAtom* aStr, bool aIgnoreCase) {
868   auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
869     nsAutoString str;
870     aValue->ToString(str);
871     WITH_COMPARATOR(
872         aIgnoreCase, c,
873         nsStyleUtil::DashMatchCompare(str, nsDependentAtomString(aStr), c))
874   };
875   return DoMatch(aElement, aNS, aName, match);
876 }
877 
878 template <typename Implementor>
AttrIncludes(Implementor * aElement,nsAtom * aNS,nsAtom * aName,nsAtom * aStr,bool aIgnoreCase)879 static bool AttrIncludes(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
880                          nsAtom* aStr, bool aIgnoreCase) {
881   auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
882     nsAutoString str;
883     aValue->ToString(str);
884     WITH_COMPARATOR(
885         aIgnoreCase, c,
886         nsStyleUtil::ValueIncludes(str, nsDependentAtomString(aStr), c))
887   };
888   return DoMatch(aElement, aNS, aName, match);
889 }
890 
891 template <typename Implementor>
AttrHasSubstring(Implementor * aElement,nsAtom * aNS,nsAtom * aName,nsAtom * aStr,bool aIgnoreCase)892 static bool AttrHasSubstring(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
893                              nsAtom* aStr, bool aIgnoreCase) {
894   auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
895     return aValue->HasSubstring(nsDependentAtomString(aStr),
896                                 aIgnoreCase ? eIgnoreCase : eCaseMatters);
897   };
898   return DoMatch(aElement, aNS, aName, match);
899 }
900 
901 template <typename Implementor>
AttrHasPrefix(Implementor * aElement,nsAtom * aNS,nsAtom * aName,nsAtom * aStr,bool aIgnoreCase)902 static bool AttrHasPrefix(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
903                           nsAtom* aStr, bool aIgnoreCase) {
904   auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
905     return aValue->HasPrefix(nsDependentAtomString(aStr),
906                              aIgnoreCase ? eIgnoreCase : eCaseMatters);
907   };
908   return DoMatch(aElement, aNS, aName, match);
909 }
910 
911 template <typename Implementor>
AttrHasSuffix(Implementor * aElement,nsAtom * aNS,nsAtom * aName,nsAtom * aStr,bool aIgnoreCase)912 static bool AttrHasSuffix(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
913                           nsAtom* aStr, bool aIgnoreCase) {
914   auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
915     return aValue->HasSuffix(nsDependentAtomString(aStr),
916                              aIgnoreCase ? eIgnoreCase : eCaseMatters);
917   };
918   return DoMatch(aElement, aNS, aName, match);
919 }
920 
921 #define SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_)      \
922   nsAtom* prefix_##LangValue(implementor_ aElement) {                          \
923     return LangValue(aElement);                                                \
924   }                                                                            \
925   bool prefix_##HasAttr(implementor_ aElement, nsAtom* aNS, nsAtom* aName) {   \
926     return HasAttr(aElement, aNS, aName);                                      \
927   }                                                                            \
928   bool prefix_##AttrEquals(implementor_ aElement, nsAtom* aNS, nsAtom* aName,  \
929                            nsAtom* aStr, bool aIgnoreCase) {                   \
930     return AttrEquals(aElement, aNS, aName, aStr, aIgnoreCase);                \
931   }                                                                            \
932   bool prefix_##AttrDashEquals(implementor_ aElement, nsAtom* aNS,             \
933                                nsAtom* aName, nsAtom* aStr,                    \
934                                bool aIgnoreCase) {                             \
935     return AttrDashEquals(aElement, aNS, aName, aStr, aIgnoreCase);            \
936   }                                                                            \
937   bool prefix_##AttrIncludes(implementor_ aElement, nsAtom* aNS,               \
938                              nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) {  \
939     return AttrIncludes(aElement, aNS, aName, aStr, aIgnoreCase);              \
940   }                                                                            \
941   bool prefix_##AttrHasSubstring(implementor_ aElement, nsAtom* aNS,           \
942                                  nsAtom* aName, nsAtom* aStr,                  \
943                                  bool aIgnoreCase) {                           \
944     return AttrHasSubstring(aElement, aNS, aName, aStr, aIgnoreCase);          \
945   }                                                                            \
946   bool prefix_##AttrHasPrefix(implementor_ aElement, nsAtom* aNS,              \
947                               nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) { \
948     return AttrHasPrefix(aElement, aNS, aName, aStr, aIgnoreCase);             \
949   }                                                                            \
950   bool prefix_##AttrHasSuffix(implementor_ aElement, nsAtom* aNS,              \
951                               nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) { \
952     return AttrHasSuffix(aElement, aNS, aName, aStr, aIgnoreCase);             \
953   }
954 
SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_,const Element *)955 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, const Element*)
956 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot,
957                                            const ServoElementSnapshot*)
958 
959 #undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
960 
961 nsAtom* Gecko_Atomize(const char* aString, uint32_t aLength) {
962   return NS_Atomize(nsDependentCSubstring(aString, aLength)).take();
963 }
964 
Gecko_Atomize16(const nsAString * aString)965 nsAtom* Gecko_Atomize16(const nsAString* aString) {
966   return NS_Atomize(*aString).take();
967 }
968 
Gecko_AddRefAtom(nsAtom * aAtom)969 void Gecko_AddRefAtom(nsAtom* aAtom) { NS_ADDREF(aAtom); }
970 
Gecko_ReleaseAtom(nsAtom * aAtom)971 void Gecko_ReleaseAtom(nsAtom* aAtom) { NS_RELEASE(aAtom); }
972 
Gecko_nsFont_InitSystem(nsFont * aDest,StyleSystemFont aFontId,const nsStyleFont * aFont,const Document * aDocument)973 void Gecko_nsFont_InitSystem(nsFont* aDest, StyleSystemFont aFontId,
974                              const nsStyleFont* aFont,
975                              const Document* aDocument) {
976   const nsFont& defaultVariableFont =
977       ThreadSafeGetDefaultVariableFont(*aDocument, aFont->mLanguage);
978 
979   // We have passed uninitialized memory to this function,
980   // initialize it. We can't simply return an nsFont because then
981   // we need to know its size beforehand. Servo cannot initialize nsFont
982   // itself, so this will do.
983   new (aDest) nsFont(defaultVariableFont);
984 
985   AutoWriteLock guard(*sServoFFILock);
986   nsLayoutUtils::ComputeSystemFont(aDest, aFontId, defaultVariableFont,
987                                    aDocument);
988 }
989 
Gecko_nsFont_Destroy(nsFont * aDest)990 void Gecko_nsFont_Destroy(nsFont* aDest) { aDest->~nsFont(); }
991 
Gecko_nsStyleFont_ComputeFallbackFontTypeForLanguage(const Document * aDoc,nsAtom * aLanguage)992 StyleGenericFontFamily Gecko_nsStyleFont_ComputeFallbackFontTypeForLanguage(
993     const Document* aDoc, nsAtom* aLanguage) {
994   return ThreadSafeGetLangGroupFontPrefs(*aDoc, aLanguage)->GetDefaultGeneric();
995 }
996 
Gecko_ConstructFontFeatureValueSet()997 gfxFontFeatureValueSet* Gecko_ConstructFontFeatureValueSet() {
998   return new gfxFontFeatureValueSet();
999 }
1000 
Gecko_AppendFeatureValueHashEntry(gfxFontFeatureValueSet * aFontFeatureValues,nsAtom * aFamily,uint32_t aAlternate,nsAtom * aName)1001 nsTArray<uint32_t>* Gecko_AppendFeatureValueHashEntry(
1002     gfxFontFeatureValueSet* aFontFeatureValues, nsAtom* aFamily,
1003     uint32_t aAlternate, nsAtom* aName) {
1004   MOZ_ASSERT(NS_IsMainThread());
1005   return aFontFeatureValues->AppendFeatureValueHashEntry(nsAtomCString(aFamily),
1006                                                          aName, aAlternate);
1007 }
1008 
Gecko_FontStretch_ToFloat(FontStretch aStretch)1009 float Gecko_FontStretch_ToFloat(FontStretch aStretch) {
1010   // Servo represents percentages with 1. being 100%.
1011   return aStretch.Percentage() / 100.0f;
1012 }
1013 
Gecko_FontStretch_SetFloat(FontStretch * aStretch,float aFloat)1014 void Gecko_FontStretch_SetFloat(FontStretch* aStretch, float aFloat) {
1015   // Servo represents percentages with 1. being 100%.
1016   //
1017   // Also, the font code assumes a given maximum that style doesn't really need
1018   // to know about. So clamp here at the boundary.
1019   *aStretch = FontStretch(std::min(aFloat * 100.0f, float(FontStretch::kMax)));
1020 }
1021 
Gecko_FontSlantStyle_SetNormal(FontSlantStyle * aStyle)1022 void Gecko_FontSlantStyle_SetNormal(FontSlantStyle* aStyle) {
1023   *aStyle = FontSlantStyle::Normal();
1024 }
1025 
Gecko_FontSlantStyle_SetItalic(FontSlantStyle * aStyle)1026 void Gecko_FontSlantStyle_SetItalic(FontSlantStyle* aStyle) {
1027   *aStyle = FontSlantStyle::Italic();
1028 }
1029 
Gecko_FontSlantStyle_SetOblique(FontSlantStyle * aStyle,float aAngleInDegrees)1030 void Gecko_FontSlantStyle_SetOblique(FontSlantStyle* aStyle,
1031                                      float aAngleInDegrees) {
1032   *aStyle = FontSlantStyle::Oblique(aAngleInDegrees);
1033 }
1034 
Gecko_FontSlantStyle_Get(FontSlantStyle aStyle,bool * aNormal,bool * aItalic,float * aObliqueAngle)1035 void Gecko_FontSlantStyle_Get(FontSlantStyle aStyle, bool* aNormal,
1036                               bool* aItalic, float* aObliqueAngle) {
1037   *aNormal = aStyle.IsNormal();
1038   *aItalic = aStyle.IsItalic();
1039   if (aStyle.IsOblique()) {
1040     *aObliqueAngle = aStyle.ObliqueAngle();
1041   }
1042 }
1043 
Gecko_FontWeight_ToFloat(FontWeight aWeight)1044 float Gecko_FontWeight_ToFloat(FontWeight aWeight) { return aWeight.ToFloat(); }
1045 
Gecko_FontWeight_SetFloat(FontWeight * aWeight,float aFloat)1046 void Gecko_FontWeight_SetFloat(FontWeight* aWeight, float aFloat) {
1047   *aWeight = FontWeight(aFloat);
1048 }
1049 
Gecko_CounterStyle_ToPtr(const StyleCounterStyle * aStyle,CounterStylePtr * aPtr)1050 void Gecko_CounterStyle_ToPtr(const StyleCounterStyle* aStyle,
1051                               CounterStylePtr* aPtr) {
1052   *aPtr = CounterStylePtr::FromStyle(*aStyle);
1053 }
1054 
Gecko_SetCounterStyleToNone(CounterStylePtr * aPtr)1055 void Gecko_SetCounterStyleToNone(CounterStylePtr* aPtr) {
1056   *aPtr = nsGkAtoms::none;
1057 }
1058 
Gecko_SetCounterStyleToString(CounterStylePtr * aPtr,const nsACString * aSymbol)1059 void Gecko_SetCounterStyleToString(CounterStylePtr* aPtr,
1060                                    const nsACString* aSymbol) {
1061   *aPtr = new AnonymousCounterStyle(NS_ConvertUTF8toUTF16(*aSymbol));
1062 }
1063 
Gecko_CopyCounterStyle(CounterStylePtr * aDst,const CounterStylePtr * aSrc)1064 void Gecko_CopyCounterStyle(CounterStylePtr* aDst,
1065                             const CounterStylePtr* aSrc) {
1066   *aDst = *aSrc;
1067 }
1068 
Gecko_CounterStyle_GetName(const CounterStylePtr * aPtr)1069 nsAtom* Gecko_CounterStyle_GetName(const CounterStylePtr* aPtr) {
1070   return aPtr->IsAtom() ? aPtr->AsAtom() : nullptr;
1071 }
1072 
Gecko_CounterStyle_GetAnonymous(const CounterStylePtr * aPtr)1073 const AnonymousCounterStyle* Gecko_CounterStyle_GetAnonymous(
1074     const CounterStylePtr* aPtr) {
1075   return aPtr->AsAnonymous();
1076 }
1077 
Gecko_EnsureTArrayCapacity(void * aArray,size_t aCapacity,size_t aElemSize)1078 void Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity,
1079                                 size_t aElemSize) {
1080   auto base =
1081       reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator,
1082                                      nsTArray_RelocateUsingMemutils>*>(aArray);
1083 
1084   base->EnsureCapacity<nsTArrayInfallibleAllocator>(aCapacity, aElemSize);
1085 }
1086 
Gecko_ClearPODTArray(void * aArray,size_t aElementSize,size_t aElementAlign)1087 void Gecko_ClearPODTArray(void* aArray, size_t aElementSize,
1088                           size_t aElementAlign) {
1089   auto base =
1090       reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator,
1091                                      nsTArray_RelocateUsingMemutils>*>(aArray);
1092 
1093   base->template ShiftData<nsTArrayInfallibleAllocator>(
1094       0, base->Length(), 0, aElementSize, aElementAlign);
1095 }
1096 
Gecko_ResizeTArrayForStrings(nsTArray<nsString> * aArray,uint32_t aLength)1097 void Gecko_ResizeTArrayForStrings(nsTArray<nsString>* aArray,
1098                                   uint32_t aLength) {
1099   aArray->SetLength(aLength);
1100 }
1101 
Gecko_ResizeAtomArray(nsTArray<RefPtr<nsAtom>> * aArray,uint32_t aLength)1102 void Gecko_ResizeAtomArray(nsTArray<RefPtr<nsAtom>>* aArray, uint32_t aLength) {
1103   aArray->SetLength(aLength);
1104 }
1105 
Gecko_EnsureImageLayersLength(nsStyleImageLayers * aLayers,size_t aLen,nsStyleImageLayers::LayerType aLayerType)1106 void Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen,
1107                                    nsStyleImageLayers::LayerType aLayerType) {
1108   size_t oldLength = aLayers->mLayers.Length();
1109 
1110   aLayers->mLayers.EnsureLengthAtLeast(aLen);
1111 
1112   for (size_t i = oldLength; i < aLen; ++i) {
1113     aLayers->mLayers[i].Initialize(aLayerType);
1114   }
1115 }
1116 
1117 template <typename StyleType>
EnsureStyleAutoArrayLength(StyleType * aArray,size_t aLen)1118 static void EnsureStyleAutoArrayLength(StyleType* aArray, size_t aLen) {
1119   size_t oldLength = aArray->Length();
1120 
1121   aArray->EnsureLengthAtLeast(aLen);
1122 
1123   for (size_t i = oldLength; i < aLen; ++i) {
1124     (*aArray)[i].SetInitialValues();
1125   }
1126 }
1127 
Gecko_EnsureStyleAnimationArrayLength(void * aArray,size_t aLen)1128 void Gecko_EnsureStyleAnimationArrayLength(void* aArray, size_t aLen) {
1129   auto base = static_cast<nsStyleAutoArray<StyleAnimation>*>(aArray);
1130   EnsureStyleAutoArrayLength(base, aLen);
1131 }
1132 
Gecko_EnsureStyleTransitionArrayLength(void * aArray,size_t aLen)1133 void Gecko_EnsureStyleTransitionArrayLength(void* aArray, size_t aLen) {
1134   auto base = reinterpret_cast<nsStyleAutoArray<StyleTransition>*>(aArray);
1135   EnsureStyleAutoArrayLength(base, aLen);
1136 }
1137 
1138 enum class KeyframeSearchDirection {
1139   Forwards,
1140   Backwards,
1141 };
1142 
1143 enum class KeyframeInsertPosition {
1144   Prepend,
1145   LastForOffset,
1146 };
1147 
GetOrCreateKeyframe(nsTArray<Keyframe> * aKeyframes,float aOffset,const nsTimingFunction * aTimingFunction,KeyframeSearchDirection aSearchDirection,KeyframeInsertPosition aInsertPosition)1148 static Keyframe* GetOrCreateKeyframe(nsTArray<Keyframe>* aKeyframes,
1149                                      float aOffset,
1150                                      const nsTimingFunction* aTimingFunction,
1151                                      KeyframeSearchDirection aSearchDirection,
1152                                      KeyframeInsertPosition aInsertPosition) {
1153   MOZ_ASSERT(aKeyframes, "The keyframe array should be valid");
1154   MOZ_ASSERT(aTimingFunction, "The timing function should be valid");
1155   MOZ_ASSERT(aOffset >= 0. && aOffset <= 1.,
1156              "The offset should be in the range of [0.0, 1.0]");
1157 
1158   size_t keyframeIndex;
1159   switch (aSearchDirection) {
1160     case KeyframeSearchDirection::Forwards:
1161       if (nsAnimationManager::FindMatchingKeyframe(
1162               *aKeyframes, aOffset, *aTimingFunction, keyframeIndex)) {
1163         return &(*aKeyframes)[keyframeIndex];
1164       }
1165       break;
1166     case KeyframeSearchDirection::Backwards:
1167       if (nsAnimationManager::FindMatchingKeyframe(Reversed(*aKeyframes),
1168                                                    aOffset, *aTimingFunction,
1169                                                    keyframeIndex)) {
1170         return &(*aKeyframes)[aKeyframes->Length() - 1 - keyframeIndex];
1171       }
1172       keyframeIndex = aKeyframes->Length() - 1;
1173       break;
1174   }
1175 
1176   Keyframe* keyframe = aKeyframes->InsertElementAt(
1177       aInsertPosition == KeyframeInsertPosition::Prepend ? 0 : keyframeIndex);
1178   keyframe->mOffset.emplace(aOffset);
1179   if (!aTimingFunction->IsLinear()) {
1180     keyframe->mTimingFunction.emplace();
1181     keyframe->mTimingFunction->Init(*aTimingFunction);
1182   }
1183 
1184   return keyframe;
1185 }
1186 
Gecko_GetOrCreateKeyframeAtStart(nsTArray<Keyframe> * aKeyframes,float aOffset,const nsTimingFunction * aTimingFunction)1187 Keyframe* Gecko_GetOrCreateKeyframeAtStart(
1188     nsTArray<Keyframe>* aKeyframes, float aOffset,
1189     const nsTimingFunction* aTimingFunction) {
1190   MOZ_ASSERT(aKeyframes->IsEmpty() ||
1191                  aKeyframes->ElementAt(0).mOffset.value() >= aOffset,
1192              "The offset should be less than or equal to the first keyframe's "
1193              "offset if there are exisiting keyframes");
1194 
1195   return GetOrCreateKeyframe(aKeyframes, aOffset, aTimingFunction,
1196                              KeyframeSearchDirection::Forwards,
1197                              KeyframeInsertPosition::Prepend);
1198 }
1199 
Gecko_GetOrCreateInitialKeyframe(nsTArray<Keyframe> * aKeyframes,const nsTimingFunction * aTimingFunction)1200 Keyframe* Gecko_GetOrCreateInitialKeyframe(
1201     nsTArray<Keyframe>* aKeyframes, const nsTimingFunction* aTimingFunction) {
1202   return GetOrCreateKeyframe(aKeyframes, 0., aTimingFunction,
1203                              KeyframeSearchDirection::Forwards,
1204                              KeyframeInsertPosition::LastForOffset);
1205 }
1206 
Gecko_GetOrCreateFinalKeyframe(nsTArray<Keyframe> * aKeyframes,const nsTimingFunction * aTimingFunction)1207 Keyframe* Gecko_GetOrCreateFinalKeyframe(
1208     nsTArray<Keyframe>* aKeyframes, const nsTimingFunction* aTimingFunction) {
1209   return GetOrCreateKeyframe(aKeyframes, 1., aTimingFunction,
1210                              KeyframeSearchDirection::Backwards,
1211                              KeyframeInsertPosition::LastForOffset);
1212 }
1213 
Gecko_AppendPropertyValuePair(nsTArray<PropertyValuePair> * aProperties,nsCSSPropertyID aProperty)1214 PropertyValuePair* Gecko_AppendPropertyValuePair(
1215     nsTArray<PropertyValuePair>* aProperties, nsCSSPropertyID aProperty) {
1216   MOZ_ASSERT(aProperties);
1217   MOZ_ASSERT(aProperty == eCSSPropertyExtra_variable ||
1218              !nsCSSProps::PropHasFlags(aProperty, CSSPropFlags::IsLogical));
1219   return aProperties->AppendElement(PropertyValuePair{aProperty});
1220 }
1221 
Gecko_GetComputedURLSpec(const StyleComputedUrl * aURL,nsCString * aOut)1222 void Gecko_GetComputedURLSpec(const StyleComputedUrl* aURL, nsCString* aOut) {
1223   MOZ_ASSERT(aURL);
1224   MOZ_ASSERT(aOut);
1225   if (aURL->IsLocalRef()) {
1226     aOut->Assign(aURL->SpecifiedSerialization());
1227     return;
1228   }
1229   Gecko_GetComputedImageURLSpec(aURL, aOut);
1230 }
1231 
Gecko_GetComputedImageURLSpec(const StyleComputedUrl * aURL,nsCString * aOut)1232 void Gecko_GetComputedImageURLSpec(const StyleComputedUrl* aURL,
1233                                    nsCString* aOut) {
1234   if (aURL->IsLocalRef() &&
1235       StaticPrefs::layout_css_computed_style_dont_resolve_image_local_refs()) {
1236     aOut->Assign(aURL->SpecifiedSerialization());
1237     return;
1238   }
1239 
1240   if (nsIURI* uri = aURL->GetURI()) {
1241     nsresult rv = uri->GetSpec(*aOut);
1242     if (NS_SUCCEEDED(rv)) {
1243       return;
1244     }
1245   }
1246 
1247   aOut->AssignLiteral("about:invalid");
1248 }
1249 
Gecko_IsSupportedImageMimeType(const uint8_t * aMimeType,const uint32_t aLen)1250 bool Gecko_IsSupportedImageMimeType(const uint8_t* aMimeType,
1251                                     const uint32_t aLen) {
1252   nsDependentCSubstring mime(reinterpret_cast<const char*>(aMimeType), aLen);
1253   return imgLoader::SupportImageWithMimeType(
1254       mime, AcceptedMimeTypes::IMAGES_AND_DOCUMENTS);
1255 }
1256 
Gecko_nsIURI_Debug(nsIURI * aURI,nsCString * aOut)1257 void Gecko_nsIURI_Debug(nsIURI* aURI, nsCString* aOut) {
1258   // TODO(emilio): Do we have more useful stuff to put here, maybe?
1259   if (aURI) {
1260     *aOut = aURI->GetSpecOrDefault();
1261   }
1262 }
1263 
1264 // XXX Implemented by hand because even though it's thread-safe, only the
1265 // subclasses have the HasThreadSafeRefCnt bits.
Gecko_AddRefnsIURIArbitraryThread(nsIURI * aPtr)1266 void Gecko_AddRefnsIURIArbitraryThread(nsIURI* aPtr) { NS_ADDREF(aPtr); }
Gecko_ReleasensIURIArbitraryThread(nsIURI * aPtr)1267 void Gecko_ReleasensIURIArbitraryThread(nsIURI* aPtr) { NS_RELEASE(aPtr); }
1268 
Gecko_nsIReferrerInfo_Debug(nsIReferrerInfo * aReferrerInfo,nsCString * aOut)1269 void Gecko_nsIReferrerInfo_Debug(nsIReferrerInfo* aReferrerInfo,
1270                                  nsCString* aOut) {
1271   if (aReferrerInfo) {
1272     if (nsCOMPtr<nsIURI> referrer = aReferrerInfo->GetComputedReferrer()) {
1273       *aOut = referrer->GetSpecOrDefault();
1274     }
1275   }
1276 }
1277 
1278 template <typename ElementLike>
DebugListAttributes(const ElementLike & aElement,nsCString & aOut)1279 void DebugListAttributes(const ElementLike& aElement, nsCString& aOut) {
1280   const uint32_t kMaxAttributeLength = 40;
1281 
1282   uint32_t i = 0;
1283   while (BorrowedAttrInfo info = aElement.GetAttrInfoAt(i++)) {
1284     aOut.AppendLiteral(" ");
1285     if (nsAtom* prefix = info.mName->GetPrefix()) {
1286       aOut.Append(NS_ConvertUTF16toUTF8(nsDependentAtomString(prefix)));
1287       aOut.AppendLiteral(":");
1288     }
1289     aOut.Append(
1290         NS_ConvertUTF16toUTF8(nsDependentAtomString(info.mName->LocalName())));
1291     if (!info.mValue) {
1292       continue;
1293     }
1294     aOut.AppendLiteral("=\"");
1295     nsAutoString value;
1296     info.mValue->ToString(value);
1297     if (value.Length() > kMaxAttributeLength) {
1298       value.Truncate(kMaxAttributeLength - 3);
1299       value.AppendLiteral("...");
1300     }
1301     aOut.Append(NS_ConvertUTF16toUTF8(value));
1302     aOut.AppendLiteral("\"");
1303   }
1304 }
1305 
Gecko_Element_DebugListAttributes(const Element * aElement,nsCString * aOut)1306 void Gecko_Element_DebugListAttributes(const Element* aElement,
1307                                        nsCString* aOut) {
1308   DebugListAttributes(*aElement, *aOut);
1309 }
1310 
Gecko_Snapshot_DebugListAttributes(const ServoElementSnapshot * aSnapshot,nsCString * aOut)1311 void Gecko_Snapshot_DebugListAttributes(const ServoElementSnapshot* aSnapshot,
1312                                         nsCString* aOut) {
1313   DebugListAttributes(*aSnapshot, *aOut);
1314 }
1315 
1316 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData);
1317 
Gecko_nsStyleFont_SetLang(nsStyleFont * aFont,nsAtom * aAtom)1318 void Gecko_nsStyleFont_SetLang(nsStyleFont* aFont, nsAtom* aAtom) {
1319   aFont->mLanguage = dont_AddRef(aAtom);
1320   aFont->mExplicitLanguage = true;
1321 }
1322 
Gecko_nsStyleFont_CopyLangFrom(nsStyleFont * aFont,const nsStyleFont * aSource)1323 void Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont,
1324                                     const nsStyleFont* aSource) {
1325   aFont->mLanguage = aSource->mLanguage;
1326 }
1327 
Gecko_nsStyleFont_ComputeMinSize(const nsStyleFont * aFont,const Document * aDocument)1328 Length Gecko_nsStyleFont_ComputeMinSize(const nsStyleFont* aFont,
1329                                         const Document* aDocument) {
1330   // Don't change font-size:0, since that would un-hide hidden text,
1331   // or SVG text, or chrome docs, we assume those know what they do.
1332   if (aFont->mSize.IsZero() || !aFont->mAllowZoomAndMinSize ||
1333       nsContentUtils::IsChromeDoc(aDocument)) {
1334     return {0};
1335   }
1336 
1337   Length minFontSize;
1338   bool needsCache = false;
1339 
1340   auto MinFontSize = [&](bool* aNeedsToCache) {
1341     auto* prefs =
1342         aDocument->GetFontPrefsForLang(aFont->mLanguage, aNeedsToCache);
1343     return prefs ? prefs->mMinimumFontSize : Length{0};
1344   };
1345 
1346   {
1347     AutoReadLock guard(*sServoFFILock);
1348     minFontSize = MinFontSize(&needsCache);
1349   }
1350 
1351   if (needsCache) {
1352     AutoWriteLock guard(*sServoFFILock);
1353     minFontSize = MinFontSize(nullptr);
1354   }
1355 
1356   if (minFontSize.ToCSSPixels() <= 0.0f) {
1357     return {0};
1358   }
1359 
1360   minFontSize.ScaleBy(aFont->mMinFontSizeRatio);
1361   minFontSize.ScaleBy(1.0f / 100.0f);
1362   return minFontSize;
1363 }
1364 
Gecko_GetBaseSize(nsAtom * aLanguage)1365 StyleDefaultFontSizes Gecko_GetBaseSize(nsAtom* aLanguage) {
1366   LangGroupFontPrefs prefs;
1367   nsStaticAtom* langGroupAtom =
1368       StaticPresData::Get()->GetUncachedLangGroup(aLanguage);
1369   prefs.Initialize(langGroupAtom);
1370   return {prefs.mDefaultVariableFont.size,  prefs.mDefaultSerifFont.size,
1371           prefs.mDefaultSansSerifFont.size, prefs.mDefaultMonospaceFont.size,
1372           prefs.mDefaultCursiveFont.size,   prefs.mDefaultFantasyFont.size,
1373           prefs.mDefaultSystemUiFont.size};
1374 }
1375 
1376 static StaticRefPtr<UACacheReporter> gUACacheReporter;
1377 
1378 namespace mozilla {
1379 
InitializeServo()1380 void InitializeServo() {
1381   URLExtraData::Init();
1382   Servo_Initialize(URLExtraData::Dummy(), URLExtraData::DummyChrome());
1383 
1384   gUACacheReporter = new UACacheReporter();
1385   RegisterWeakMemoryReporter(gUACacheReporter);
1386 
1387   sServoFFILock = new RWLock("Servo::FFILock");
1388 }
1389 
ShutdownServo()1390 void ShutdownServo() {
1391   MOZ_ASSERT(sServoFFILock);
1392 
1393   UnregisterWeakMemoryReporter(gUACacheReporter);
1394   gUACacheReporter = nullptr;
1395 
1396   sServoFFILock = nullptr;
1397   Servo_Shutdown();
1398 
1399   URLExtraData::Shutdown();
1400 }
1401 
AssertIsMainThreadOrServoFontMetricsLocked()1402 void AssertIsMainThreadOrServoFontMetricsLocked() {
1403   if (!NS_IsMainThread()) {
1404     MOZ_ASSERT(sServoFFILock &&
1405                sServoFFILock->LockedForWritingByCurrentThread());
1406   }
1407 }
1408 
1409 }  // namespace mozilla
1410 
Gecko_GetFontMetrics(const nsPresContext * aPresContext,bool aIsVertical,const nsStyleFont * aFont,Length aFontSize,bool aUseUserFontSet)1411 GeckoFontMetrics Gecko_GetFontMetrics(const nsPresContext* aPresContext,
1412                                       bool aIsVertical,
1413                                       const nsStyleFont* aFont,
1414                                       Length aFontSize, bool aUseUserFontSet) {
1415   AutoWriteLock guard(*sServoFFILock);
1416 
1417   // Getting font metrics can require some main thread only work to be
1418   // done, such as work that needs to touch non-threadsafe refcounted
1419   // objects (like the DOM FontFace/FontFaceSet objects), network loads, etc.
1420   //
1421   // To handle this work, font code checks whether we are in a Servo traversal
1422   // and if so, appends PostTraversalTasks to the current ServoStyleSet
1423   // to be performed immediately after the traversal is finished.  This
1424   // works well for starting downloadable font loads, since we don't have
1425   // those fonts available to get metrics for anyway.  Platform fonts and
1426   // ArrayBuffer-backed FontFace objects are handled synchronously.
1427 
1428   nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
1429   presContext->SetUsesFontMetricDependentFontUnits(true);
1430 
1431   RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetMetricsFor(
1432       presContext, aIsVertical, aFont, aFontSize, aUseUserFontSet);
1433   const auto& metrics =
1434       fm->GetThebesFontGroup()->GetFirstValidFont()->GetMetrics(
1435           fm->Orientation());
1436 
1437   int32_t d2a = aPresContext->AppUnitsPerDevPixel();
1438   auto ToLength = [](nscoord aLen) {
1439     return Length::FromPixels(CSSPixel::FromAppUnits(aLen));
1440   };
1441   return {ToLength(NS_round(metrics.xHeight * d2a)),
1442           ToLength(NS_round(metrics.zeroWidth * d2a)),
1443           ToLength(NS_round(metrics.capHeight * d2a)),
1444           ToLength(NS_round(metrics.ideographicWidth * d2a)),
1445           ToLength(NS_round(metrics.maxAscent * d2a))};
1446 }
1447 
1448 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(SheetLoadDataHolder, SheetLoadDataHolder);
1449 
Gecko_StyleSheet_FinishAsyncParse(SheetLoadDataHolder * aData,StyleStrong<RawServoStyleSheetContents> aSheetContents,StyleOwnedOrNull<StyleUseCounters> aUseCounters)1450 void Gecko_StyleSheet_FinishAsyncParse(
1451     SheetLoadDataHolder* aData,
1452     StyleStrong<RawServoStyleSheetContents> aSheetContents,
1453     StyleOwnedOrNull<StyleUseCounters> aUseCounters) {
1454   UniquePtr<StyleUseCounters> useCounters = aUseCounters.Consume();
1455   RefPtr<SheetLoadDataHolder> loadData = aData;
1456   RefPtr<RawServoStyleSheetContents> sheetContents = aSheetContents.Consume();
1457   NS_DispatchToMainThread(NS_NewRunnableFunction(
1458       __func__, [d = std::move(loadData), contents = std::move(sheetContents),
1459                  counters = std::move(useCounters)]() mutable {
1460         MOZ_ASSERT(NS_IsMainThread());
1461         SheetLoadData* data = d->get();
1462         data->mSheet->FinishAsyncParse(contents.forget(), std::move(counters));
1463       }));
1464 }
1465 
LoadImportSheet(Loader * aLoader,StyleSheet * aParent,SheetLoadData * aParentLoadData,LoaderReusableStyleSheets * aReusableSheets,const StyleCssUrl & aURL,already_AddRefed<RawServoMediaList> aMediaList)1466 static already_AddRefed<StyleSheet> LoadImportSheet(
1467     Loader* aLoader, StyleSheet* aParent, SheetLoadData* aParentLoadData,
1468     LoaderReusableStyleSheets* aReusableSheets, const StyleCssUrl& aURL,
1469     already_AddRefed<RawServoMediaList> aMediaList) {
1470   MOZ_ASSERT(NS_IsMainThread());
1471   MOZ_ASSERT(aLoader, "Should've catched this before");
1472   MOZ_ASSERT(aParent, "Only used for @import, so parent should exist!");
1473 
1474   RefPtr<MediaList> media = new MediaList(std::move(aMediaList));
1475   nsCOMPtr<nsIURI> uri = aURL.GetURI();
1476   nsresult rv = uri ? NS_OK : NS_ERROR_FAILURE;
1477 
1478   size_t previousSheetCount = aParent->ChildSheets().Length();
1479   if (NS_SUCCEEDED(rv)) {
1480     // TODO(emilio): We should probably make LoadChildSheet return the
1481     // stylesheet rather than the return code.
1482     rv = aLoader->LoadChildSheet(*aParent, aParentLoadData, uri, media,
1483                                  aReusableSheets);
1484   }
1485 
1486   if (NS_FAILED(rv) || previousSheetCount == aParent->ChildSheets().Length()) {
1487     // Servo and Gecko have different ideas of what a valid URL is, so we might
1488     // get in here with a URL string that NS_NewURI can't handle.  We may also
1489     // reach here via an import cycle.  For the import cycle case, we need some
1490     // sheet object per spec, even if its empty.  DevTools uses the URI to
1491     // realize it has hit an import cycle, so we mark it complete to make the
1492     // sheet readable from JS.
1493     RefPtr<StyleSheet> emptySheet =
1494         aParent->CreateEmptyChildSheet(media.forget());
1495     // Make a dummy URI if we don't have one because some methods assume
1496     // non-null URIs.
1497     if (!uri) {
1498       NS_NewURI(getter_AddRefs(uri), "about:invalid"_ns);
1499     }
1500     emptySheet->SetURIs(uri, uri, uri);
1501     emptySheet->SetPrincipal(aURL.ExtraData().Principal());
1502     nsCOMPtr<nsIReferrerInfo> referrerInfo =
1503         ReferrerInfo::CreateForExternalCSSResources(emptySheet);
1504     emptySheet->SetReferrerInfo(referrerInfo);
1505     emptySheet->SetComplete();
1506     aParent->AppendStyleSheet(*emptySheet);
1507     return emptySheet.forget();
1508   }
1509 
1510   RefPtr<StyleSheet> sheet = aParent->ChildSheets().LastElement();
1511   return sheet.forget();
1512 }
1513 
Gecko_LoadStyleSheet(Loader * aLoader,StyleSheet * aParent,SheetLoadData * aParentLoadData,LoaderReusableStyleSheets * aReusableSheets,const StyleCssUrl * aUrl,StyleStrong<RawServoMediaList> aMediaList)1514 StyleSheet* Gecko_LoadStyleSheet(Loader* aLoader, StyleSheet* aParent,
1515                                  SheetLoadData* aParentLoadData,
1516                                  LoaderReusableStyleSheets* aReusableSheets,
1517                                  const StyleCssUrl* aUrl,
1518                                  StyleStrong<RawServoMediaList> aMediaList) {
1519   MOZ_ASSERT(NS_IsMainThread());
1520   MOZ_ASSERT(aUrl);
1521 
1522   return LoadImportSheet(aLoader, aParent, aParentLoadData, aReusableSheets,
1523                          *aUrl, aMediaList.Consume())
1524       .take();
1525 }
1526 
Gecko_LoadStyleSheetAsync(SheetLoadDataHolder * aParentData,const StyleCssUrl * aUrl,StyleStrong<RawServoMediaList> aMediaList,StyleStrong<RawServoImportRule> aImportRule)1527 void Gecko_LoadStyleSheetAsync(SheetLoadDataHolder* aParentData,
1528                                const StyleCssUrl* aUrl,
1529                                StyleStrong<RawServoMediaList> aMediaList,
1530                                StyleStrong<RawServoImportRule> aImportRule) {
1531   MOZ_ASSERT(aUrl);
1532   RefPtr<SheetLoadDataHolder> loadData = aParentData;
1533   RefPtr<RawServoMediaList> mediaList = aMediaList.Consume();
1534   RefPtr<RawServoImportRule> importRule = aImportRule.Consume();
1535   NS_DispatchToMainThread(NS_NewRunnableFunction(
1536       __func__,
1537       [data = std::move(loadData), url = StyleCssUrl(*aUrl),
1538        media = std::move(mediaList), import = std::move(importRule)]() mutable {
1539         MOZ_ASSERT(NS_IsMainThread());
1540         SheetLoadData* d = data->get();
1541         RefPtr<StyleSheet> sheet = LoadImportSheet(
1542             d->mLoader, d->mSheet, d, nullptr, url, media.forget());
1543         Servo_ImportRule_SetSheet(import, sheet);
1544       }));
1545 }
1546 
Gecko_AddPropertyToSet(nsCSSPropertyIDSet * aPropertySet,nsCSSPropertyID aProperty)1547 void Gecko_AddPropertyToSet(nsCSSPropertyIDSet* aPropertySet,
1548                             nsCSSPropertyID aProperty) {
1549   aPropertySet->AddProperty(aProperty);
1550 }
1551 
1552 #define STYLE_STRUCT(name)                                             \
1553                                                                        \
1554   void Gecko_Construct_Default_nsStyle##name(nsStyle##name* ptr,       \
1555                                              const Document* doc) {    \
1556     new (ptr) nsStyle##name(*doc);                                     \
1557   }                                                                    \
1558                                                                        \
1559   void Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr,           \
1560                                          const nsStyle##name* other) { \
1561     new (ptr) nsStyle##name(*other);                                   \
1562   }                                                                    \
1563                                                                        \
1564   void Gecko_Destroy_nsStyle##name(nsStyle##name* ptr) {               \
1565     ptr->~nsStyle##name();                                             \
1566   }
1567 
Gecko_DocumentRule_UseForPresentation(const Document * aDocument,const nsACString * aPattern,DocumentMatchingFunction aMatchingFunction)1568 bool Gecko_DocumentRule_UseForPresentation(
1569     const Document* aDocument, const nsACString* aPattern,
1570     DocumentMatchingFunction aMatchingFunction) {
1571   MOZ_ASSERT(NS_IsMainThread());
1572 
1573   nsIURI* docURI = aDocument->GetDocumentURI();
1574   nsAutoCString docURISpec;
1575   if (docURI) {
1576     // If GetSpec fails (due to OOM) just skip these URI-specific CSS rules.
1577     nsresult rv = docURI->GetSpec(docURISpec);
1578     NS_ENSURE_SUCCESS(rv, false);
1579   }
1580 
1581   return CSSMozDocumentRule::Match(aDocument, docURI, docURISpec, *aPattern,
1582                                    aMatchingFunction);
1583 }
1584 
Gecko_SetJemallocThreadLocalArena(bool enabled)1585 void Gecko_SetJemallocThreadLocalArena(bool enabled) {
1586 #if defined(MOZ_MEMORY)
1587   jemalloc_thread_local_arena(enabled);
1588 #endif
1589 }
1590 
1591 #include "nsStyleStructList.h"
1592 
1593 #undef STYLE_STRUCT
1594 
Gecko_ErrorReportingEnabled(const StyleSheet * aSheet,const Loader * aLoader,uint64_t * aOutWindowId)1595 bool Gecko_ErrorReportingEnabled(const StyleSheet* aSheet,
1596                                  const Loader* aLoader,
1597                                  uint64_t* aOutWindowId) {
1598   if (!ErrorReporter::ShouldReportErrors(aSheet, aLoader)) {
1599     return false;
1600   }
1601   *aOutWindowId = ErrorReporter::FindInnerWindowId(aSheet, aLoader);
1602   return true;
1603 }
1604 
Gecko_ReportUnexpectedCSSError(const uint64_t aWindowId,nsIURI * aURI,const char * message,const char * param,uint32_t paramLen,const char * prefix,const char * prefixParam,uint32_t prefixParamLen,const char * suffix,const char * source,uint32_t sourceLen,const char * selectors,uint32_t selectorsLen,uint32_t lineNumber,uint32_t colNumber)1605 void Gecko_ReportUnexpectedCSSError(
1606     const uint64_t aWindowId, nsIURI* aURI, const char* message,
1607     const char* param, uint32_t paramLen, const char* prefix,
1608     const char* prefixParam, uint32_t prefixParamLen, const char* suffix,
1609     const char* source, uint32_t sourceLen, const char* selectors,
1610     uint32_t selectorsLen, uint32_t lineNumber, uint32_t colNumber) {
1611   MOZ_RELEASE_ASSERT(NS_IsMainThread());
1612 
1613   ErrorReporter reporter(aWindowId);
1614 
1615   if (prefix) {
1616     if (prefixParam) {
1617       nsDependentCSubstring paramValue(prefixParam, prefixParamLen);
1618       AutoTArray<nsString, 1> wideParam;
1619       CopyUTF8toUTF16(paramValue, *wideParam.AppendElement());
1620       reporter.ReportUnexpectedUnescaped(prefix, wideParam);
1621     } else {
1622       reporter.ReportUnexpected(prefix);
1623     }
1624   }
1625 
1626   if (param) {
1627     nsDependentCSubstring paramValue(param, paramLen);
1628     AutoTArray<nsString, 1> wideParam;
1629     CopyUTF8toUTF16(paramValue, *wideParam.AppendElement());
1630     reporter.ReportUnexpectedUnescaped(message, wideParam);
1631   } else {
1632     reporter.ReportUnexpected(message);
1633   }
1634 
1635   if (suffix) {
1636     reporter.ReportUnexpected(suffix);
1637   }
1638   nsDependentCSubstring sourceValue(source, sourceLen);
1639   nsDependentCSubstring selectorsValue(selectors, selectorsLen);
1640   reporter.OutputError(sourceValue, selectorsValue, lineNumber, colNumber,
1641                        aURI);
1642 }
1643 
Gecko_ContentList_AppendAll(nsSimpleContentList * aList,const Element ** aElements,size_t aLength)1644 void Gecko_ContentList_AppendAll(nsSimpleContentList* aList,
1645                                  const Element** aElements, size_t aLength) {
1646   MOZ_ASSERT(NS_IsMainThread());
1647   MOZ_ASSERT(aElements);
1648   MOZ_ASSERT(aLength);
1649   MOZ_ASSERT(aList);
1650 
1651   aList->SetCapacity(aLength);
1652 
1653   for (size_t i = 0; i < aLength; ++i) {
1654     aList->AppendElement(const_cast<Element*>(aElements[i]));
1655   }
1656 }
1657 
Gecko_Document_GetElementsWithId(const Document * aDoc,nsAtom * aId)1658 const nsTArray<Element*>* Gecko_Document_GetElementsWithId(const Document* aDoc,
1659                                                            nsAtom* aId) {
1660   MOZ_ASSERT(aDoc);
1661   MOZ_ASSERT(aId);
1662 
1663   return aDoc->GetAllElementsForId(nsDependentAtomString(aId));
1664 }
1665 
Gecko_ShadowRoot_GetElementsWithId(const ShadowRoot * aShadowRoot,nsAtom * aId)1666 const nsTArray<Element*>* Gecko_ShadowRoot_GetElementsWithId(
1667     const ShadowRoot* aShadowRoot, nsAtom* aId) {
1668   MOZ_ASSERT(aShadowRoot);
1669   MOZ_ASSERT(aId);
1670 
1671   return aShadowRoot->GetAllElementsForId(nsDependentAtomString(aId));
1672 }
1673 
Gecko_GetBoolPrefValue(const char * aPrefName)1674 bool Gecko_GetBoolPrefValue(const char* aPrefName) {
1675   MOZ_ASSERT(NS_IsMainThread());
1676   return Preferences::GetBool(aPrefName);
1677 }
1678 
Gecko_IsInServoTraversal()1679 bool Gecko_IsInServoTraversal() { return ServoStyleSet::IsInServoTraversal(); }
1680 
Gecko_IsMainThread()1681 bool Gecko_IsMainThread() { return NS_IsMainThread(); }
1682 
Gecko_GetSVGAnimatedClass(const Element * aElement)1683 const nsAttrValue* Gecko_GetSVGAnimatedClass(const Element* aElement) {
1684   MOZ_ASSERT(aElement->IsSVGElement());
1685   return static_cast<const SVGElement*>(aElement)->GetAnimatedClassName();
1686 }
1687 
Gecko_AssertClassAttrValueIsSane(const nsAttrValue * aValue)1688 bool Gecko_AssertClassAttrValueIsSane(const nsAttrValue* aValue) {
1689   MOZ_ASSERT(aValue->Type() == nsAttrValue::eAtom ||
1690              aValue->Type() == nsAttrValue::eString ||
1691              aValue->Type() == nsAttrValue::eAtomArray);
1692   MOZ_ASSERT_IF(
1693       aValue->Type() == nsAttrValue::eString,
1694       nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
1695           aValue->GetStringValue())
1696           .IsEmpty());
1697   return true;
1698 }
1699 
Gecko_GetSafeAreaInsets(const nsPresContext * aPresContext,float * aTop,float * aRight,float * aBottom,float * aLeft)1700 void Gecko_GetSafeAreaInsets(const nsPresContext* aPresContext, float* aTop,
1701                              float* aRight, float* aBottom, float* aLeft) {
1702   MOZ_ASSERT(aPresContext);
1703   ScreenIntMargin safeAreaInsets = aPresContext->GetSafeAreaInsets();
1704   *aTop = aPresContext->DevPixelsToFloatCSSPixels(safeAreaInsets.top);
1705   *aRight = aPresContext->DevPixelsToFloatCSSPixels(safeAreaInsets.right);
1706   *aBottom = aPresContext->DevPixelsToFloatCSSPixels(safeAreaInsets.bottom);
1707   *aLeft = aPresContext->DevPixelsToFloatCSSPixels(safeAreaInsets.left);
1708 }
1709 
Gecko_PrintfStderr(const nsCString * aStr)1710 void Gecko_PrintfStderr(const nsCString* aStr) {
1711   printf_stderr("%s", aStr->get());
1712 }
1713 
Gecko_Element_ImportedPart(const nsAttrValue * aValue,nsAtom * aPartName)1714 nsAtom* Gecko_Element_ImportedPart(const nsAttrValue* aValue,
1715                                    nsAtom* aPartName) {
1716   if (aValue->Type() != nsAttrValue::eShadowParts) {
1717     return nullptr;
1718   }
1719   return aValue->GetShadowPartsValue().GetReverse(aPartName);
1720 }
1721 
Gecko_Element_ExportedParts(const nsAttrValue * aValue,nsAtom * aPartName,size_t * aOutLength)1722 nsAtom** Gecko_Element_ExportedParts(const nsAttrValue* aValue,
1723                                      nsAtom* aPartName, size_t* aOutLength) {
1724   if (aValue->Type() != nsAttrValue::eShadowParts) {
1725     return nullptr;
1726   }
1727   auto* parts = aValue->GetShadowPartsValue().Get(aPartName);
1728   if (!parts) {
1729     return nullptr;
1730   }
1731   *aOutLength = parts->Length();
1732   static_assert(sizeof(RefPtr<nsAtom>) == sizeof(nsAtom*));
1733   static_assert(alignof(RefPtr<nsAtom>) == alignof(nsAtom*));
1734   return reinterpret_cast<nsAtom**>(parts->Elements());
1735 }
1736 
IsNamedFamily(const nsAString & aFamilyName) const1737 bool StyleSingleFontFamily::IsNamedFamily(const nsAString& aFamilyName) const {
1738   if (!IsFamilyName()) {
1739     return false;
1740   }
1741   nsDependentAtomString name(AsFamilyName().name.AsAtom());
1742   return name.Equals(aFamilyName, nsCaseInsensitiveStringComparator);
1743 }
1744 
Parse(const nsACString & aFamilyOrGenericName)1745 StyleSingleFontFamily StyleSingleFontFamily::Parse(
1746     const nsACString& aFamilyOrGenericName) {
1747   // should only be passed a single font - not entirely correct, a family
1748   // *could* have a comma in it but in practice never does so
1749   // for debug purposes this is fine
1750   NS_ASSERTION(aFamilyOrGenericName.FindChar(',') == -1,
1751                "Convert method should only be passed a single family name");
1752 
1753   auto genericType = Servo_GenericFontFamily_Parse(&aFamilyOrGenericName);
1754   if (genericType != StyleGenericFontFamily::None) {
1755     return Generic(genericType);
1756   }
1757   return FamilyName({StyleAtom(NS_Atomize(aFamilyOrGenericName)),
1758                      StyleFontFamilyNameSyntax::Identifiers});
1759 }
1760 
AppendToString(nsACString & aName,bool aQuote) const1761 void StyleSingleFontFamily::AppendToString(nsACString& aName,
1762                                            bool aQuote) const {
1763   if (IsFamilyName()) {
1764     const auto& name = AsFamilyName();
1765     bool quote = aQuote && name.syntax == StyleFontFamilyNameSyntax::Quoted;
1766     if (quote) {
1767       aName.Append('"');
1768     }
1769     aName.Append(nsAtomCString(name.name.AsAtom()));
1770     if (quote) {
1771       aName.Append('"');
1772     }
1773     return;
1774   }
1775 
1776   switch (AsGeneric()) {
1777     case StyleGenericFontFamily::None:
1778     case StyleGenericFontFamily::MozEmoji:
1779       MOZ_FALLTHROUGH_ASSERT("Should never appear in a font-family name!");
1780     case StyleGenericFontFamily::Serif:
1781       return aName.AppendLiteral("serif");
1782     case StyleGenericFontFamily::SansSerif:
1783       return aName.AppendLiteral("sans-serif");
1784     case StyleGenericFontFamily::Monospace:
1785       return aName.AppendLiteral("monospace");
1786     case StyleGenericFontFamily::Cursive:
1787       return aName.AppendLiteral("cursive");
1788     case StyleGenericFontFamily::Fantasy:
1789       return aName.AppendLiteral("fantasy");
1790     case StyleGenericFontFamily::SystemUi:
1791       return aName.AppendLiteral("system-ui");
1792   }
1793   MOZ_ASSERT_UNREACHABLE("Unknown generic font-family!");
1794   return aName.AppendLiteral("serif");
1795 }
1796 
WithNames(nsTArray<StyleSingleFontFamily> && aNames)1797 StyleFontFamilyList StyleFontFamilyList::WithNames(
1798     nsTArray<StyleSingleFontFamily>&& aNames) {
1799   StyleFontFamilyList list;
1800   Servo_FontFamilyList_WithNames(&aNames, &list);
1801   return list;
1802 }
1803 
WithOneUnquotedFamily(const nsACString & aName)1804 StyleFontFamilyList StyleFontFamilyList::WithOneUnquotedFamily(
1805     const nsACString& aName) {
1806   AutoTArray<StyleSingleFontFamily, 1> names;
1807   names.AppendElement(StyleSingleFontFamily::FamilyName(
1808       {StyleAtom(NS_Atomize(aName)), StyleFontFamilyNameSyntax::Identifiers}));
1809   return WithNames(std::move(names));
1810 }
1811