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