1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4 
5 use super::error_reporter::ErrorReporter;
6 use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader};
7 use bincode::{deserialize, serialize};
8 use cssparser::ToCss as ParserToCss;
9 use cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation, UnicodeRange};
10 use malloc_size_of::MallocSizeOfOps;
11 use nsstring::{nsCString, nsString};
12 use selectors::matching::{matches_selector, MatchingContext, MatchingMode, VisitedHandlingMode};
13 use selectors::{NthIndexCache, SelectorList};
14 use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
15 use smallvec::SmallVec;
16 use std::cell::RefCell;
17 use std::collections::BTreeSet;
18 use std::fmt::Write;
19 use std::iter;
20 use std::os::raw::c_void;
21 use std::ptr;
22 use style::applicable_declarations::ApplicableDeclarationBlock;
23 use style::author_styles::AuthorStyles;
24 use style::context::ThreadLocalStyleContext;
25 use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
26 use style::counter_style;
27 use style::data::{self, ElementStyles};
28 use style::dom::{ShowSubtreeData, TDocument, TElement, TNode};
29 use style::driver;
30 use style::element_state::{DocumentState, ElementState};
31 use style::error_reporting::{ContextualParseError, ParseErrorReporter};
32 use style::font_face::{self, ComputedFontStyleDescriptor, FontFaceSourceListComponent, Source};
33 use style::font_metrics::{get_metrics_provider_for_product, FontMetricsProvider};
34 use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl};
35 use style::gecko::restyle_damage::GeckoRestyleDamage;
36 use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement};
37 use style::gecko::traversal::RecalcStyleOnly;
38 use style::gecko::url;
39 use style::gecko::wrapper::{GeckoElement, GeckoNode};
40 use style::gecko_bindings::bindings;
41 use style::gecko_bindings::bindings::nsACString;
42 use style::gecko_bindings::bindings::nsAString;
43 use style::gecko_bindings::bindings::Gecko_AddPropertyToSet;
44 use style::gecko_bindings::bindings::Gecko_AppendPropertyValuePair;
45 use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet;
46 use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
47 use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
48 use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
49 use style::gecko_bindings::bindings::Gecko_HaveSeenPtr;
50 use style::gecko_bindings::structs;
51 use style::gecko_bindings::structs::gfxFontFeatureValueSet;
52 use style::gecko_bindings::structs::ipc::ByteBuf;
53 use style::gecko_bindings::structs::nsAtom;
54 use style::gecko_bindings::structs::nsCSSCounterDesc;
55 use style::gecko_bindings::structs::nsCSSFontDesc;
56 use style::gecko_bindings::structs::nsCSSPropertyID;
57 use style::gecko_bindings::structs::nsChangeHint;
58 use style::gecko_bindings::structs::nsCompatibility;
59 use style::gecko_bindings::structs::nsStyleTransformMatrix::MatrixTransformOperator;
60 use style::gecko_bindings::structs::nsTArray;
61 use style::gecko_bindings::structs::nsTimingFunction;
62 use style::gecko_bindings::structs::nsresult;
63 use style::gecko_bindings::structs::AtomArray;
64 use style::gecko_bindings::structs::CallerType;
65 use style::gecko_bindings::structs::CompositeOperation;
66 use style::gecko_bindings::structs::DeclarationBlockMutationClosure;
67 use style::gecko_bindings::structs::IterationCompositeOperation;
68 use style::gecko_bindings::structs::Loader;
69 use style::gecko_bindings::structs::LoaderReusableStyleSheets;
70 use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf;
71 use style::gecko_bindings::structs::OriginFlags;
72 use style::gecko_bindings::structs::PropertyValuePair;
73 use style::gecko_bindings::structs::PseudoStyleType;
74 use style::gecko_bindings::structs::RawServoSelectorList;
75 use style::gecko_bindings::structs::RawServoSourceSizeList;
76 use style::gecko_bindings::structs::RawServoStyleRule;
77 use style::gecko_bindings::structs::SeenPtrs;
78 use style::gecko_bindings::structs::ServoElementSnapshotTable;
79 use style::gecko_bindings::structs::ServoStyleSetSizes;
80 use style::gecko_bindings::structs::ServoTraversalFlags;
81 use style::gecko_bindings::structs::SheetLoadData;
82 use style::gecko_bindings::structs::SheetLoadDataHolder;
83 use style::gecko_bindings::structs::SheetParsingMode;
84 use style::gecko_bindings::structs::StyleRuleInclusion;
85 use style::gecko_bindings::structs::StyleSheet as DomStyleSheet;
86 use style::gecko_bindings::structs::URLExtraData;
87 use style::gecko_bindings::structs::{nsINode as RawGeckoNode, Element as RawGeckoElement};
88 use style::gecko_bindings::structs::{
89     RawServoAnimationValue, RawServoAuthorStyles, RawServoCounterStyleRule,
90     RawServoDeclarationBlock, RawServoFontFaceRule, RawServoFontFeatureValuesRule,
91     RawServoImportRule, RawServoKeyframe, RawServoKeyframesRule, RawServoMediaList,
92     RawServoMediaRule, RawServoMozDocumentRule, RawServoNamespaceRule, RawServoPageRule,
93     RawServoSharedMemoryBuilder, RawServoStyleSet, RawServoStyleSheetContents,
94     RawServoSupportsRule, ServoCssRules,
95 };
96 use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasFFI};
97 use style::gecko_bindings::sugar::ownership::{
98     HasBoxFFI, HasSimpleFFI, Owned, OwnedOrNull, Strong,
99 };
100 use style::gecko_bindings::sugar::refptr::RefPtr;
101 use style::global_style_data::{GlobalStyleData, GLOBAL_STYLE_DATA, StyleThreadPool, STYLE_THREAD_POOL};
102 use style::invalidation::element::restyle_hints::RestyleHint;
103 use style::media_queries::MediaList;
104 use style::parser::{self, Parse, ParserContext};
105 use style::profiler_label;
106 use style::properties::animated_properties::{AnimationValue, AnimationValueMap};
107 use style::properties::{parse_one_declaration_into, parse_style_attribute};
108 use style::properties::{ComputedValues, CountedUnknownProperty, Importance, NonCustomPropertyId};
109 use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId};
110 use style::properties::{PropertyDeclarationId, ShorthandId};
111 use style::properties::{SourcePropertyDeclaration, StyleBuilder, UnparsedValue};
112 use style::rule_cache::RuleCacheConditions;
113 use style::rule_tree::{CascadeLevel, StrongRuleNode};
114 use style::selector_parser::PseudoElementCascadeType;
115 use style::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard};
116 use style::string_cache::{Atom, WeakAtom};
117 use style::style_adjuster::StyleAdjuster;
118 use style::stylesheets::import_rule::ImportSheet;
119 use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
120 use style::stylesheets::supports_rule::parse_condition_or_declaration;
121 use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
122 use style::stylesheets::{CounterStyleRule, CssRule, CssRuleType, CssRules, CssRulesHelpers};
123 use style::stylesheets::{DocumentRule, FontFaceRule, FontFeatureValuesRule, ImportRule};
124 use style::stylesheets::{KeyframesRule, MediaRule, NamespaceRule, Origin, OriginSet, PageRule};
125 use style::stylesheets::{StyleRule, StylesheetContents, SupportsRule, UrlExtraData};
126 use style::stylesheets::{SanitizationData, SanitizationKind, AllowImportRules};
127 use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
128 use style::thread_state;
129 use style::timer::Timer;
130 use style::traversal::resolve_style;
131 use style::traversal::DomTraversal;
132 use style::traversal_flags::{self, TraversalFlags};
133 use style::use_counters::UseCounters;
134 use style::values::animated::{Animate, Procedure, ToAnimatedZero};
135 use style::values::computed::{self, Context, ToComputedValue};
136 use style::values::distance::ComputeSquaredDistance;
137 use style::values::specified;
138 use style::values::specified::gecko::IntersectionObserverRootMargin;
139 use style::values::specified::source_size_list::SourceSizeList;
140 use style::values::{CustomIdent, KeyframesName};
141 use style_traits::{CssWriter, ParsingMode, StyleParseErrorKind, ToCss};
142 use to_shmem::SharedMemoryBuilder;
143 
144 trait ClosureHelper {
invoke(&self)145     fn invoke(&self);
146 }
147 
148 impl ClosureHelper for DeclarationBlockMutationClosure {
149     #[inline]
invoke(&self)150     fn invoke(&self) {
151         if let Some(function) = self.function.as_ref() {
152             unsafe { function(self.data) };
153         }
154     }
155 }
156 
157 /*
158  * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
159  * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
160  * those signatures as well, giving us a second declaration of all the Servo_* functions in this
161  * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
162  * depend on but good enough for our purposes.
163  */
164 
165 // A dummy url data for where we don't pass url data in.
166 // We need to get rid of this sooner than later.
167 static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut _;
168 
169 #[no_mangle]
Servo_Initialize(dummy_url_data: *mut URLExtraData)170 pub unsafe extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) {
171     use style::gecko_bindings::sugar::origin_flags;
172 
173     // Pretend that we're a Servo Layout thread, to make some assertions happy.
174     thread_state::initialize(thread_state::ThreadState::LAYOUT);
175 
176     // Perform some debug-only runtime assertions.
177     origin_flags::assert_flags_match();
178     parser::assert_parsing_mode_match();
179     traversal_flags::assert_traversal_flags_match();
180     specified::font::assert_variant_east_asian_matches();
181     specified::font::assert_variant_ligatures_matches();
182 
183     DUMMY_URL_DATA = dummy_url_data;
184 }
185 
186 #[no_mangle]
Servo_Shutdown()187 pub unsafe extern "C" fn Servo_Shutdown() {
188     DUMMY_URL_DATA = ptr::null_mut();
189     Stylist::shutdown();
190     url::shutdown();
191 }
192 
193 #[inline(always)]
dummy_url_data() -> &'static UrlExtraData194 unsafe fn dummy_url_data() -> &'static UrlExtraData {
195     UrlExtraData::from_ptr_ref(&DUMMY_URL_DATA)
196 }
197 
198 #[allow(dead_code)]
is_main_thread() -> bool199 fn is_main_thread() -> bool {
200     unsafe { bindings::Gecko_IsMainThread() }
201 }
202 
203 #[allow(dead_code)]
is_in_servo_traversal() -> bool204 fn is_in_servo_traversal() -> bool {
205     unsafe { bindings::Gecko_IsInServoTraversal() }
206 }
207 
create_shared_context<'a>( global_style_data: &GlobalStyleData, guard: &'a SharedRwLockReadGuard, per_doc_data: &'a PerDocumentStyleDataImpl, traversal_flags: TraversalFlags, snapshot_map: &'a ServoElementSnapshotTable, ) -> SharedStyleContext<'a>208 fn create_shared_context<'a>(
209     global_style_data: &GlobalStyleData,
210     guard: &'a SharedRwLockReadGuard,
211     per_doc_data: &'a PerDocumentStyleDataImpl,
212     traversal_flags: TraversalFlags,
213     snapshot_map: &'a ServoElementSnapshotTable,
214 ) -> SharedStyleContext<'a> {
215     SharedStyleContext {
216         stylist: &per_doc_data.stylist,
217         visited_styles_enabled: per_doc_data.visited_styles_enabled(),
218         options: global_style_data.options.clone(),
219         guards: StylesheetGuards::same(guard),
220         timer: Timer::new(),
221         traversal_flags,
222         snapshot_map,
223     }
224 }
225 
traverse_subtree( element: GeckoElement, global_style_data: &GlobalStyleData, per_doc_data: &PerDocumentStyleDataImpl, guard: &SharedRwLockReadGuard, traversal_flags: TraversalFlags, snapshots: &ServoElementSnapshotTable, )226 fn traverse_subtree(
227     element: GeckoElement,
228     global_style_data: &GlobalStyleData,
229     per_doc_data: &PerDocumentStyleDataImpl,
230     guard: &SharedRwLockReadGuard,
231     traversal_flags: TraversalFlags,
232     snapshots: &ServoElementSnapshotTable,
233 ) {
234     let shared_style_context = create_shared_context(
235         &global_style_data,
236         &guard,
237         &per_doc_data,
238         traversal_flags,
239         snapshots,
240     );
241 
242     let token = RecalcStyleOnly::pre_traverse(element, &shared_style_context);
243 
244     if !token.should_traverse() {
245         return;
246     }
247 
248     debug!("Traversing subtree from {:?}", element);
249 
250     let thread_pool_holder = &*STYLE_THREAD_POOL;
251     let pool;
252     let thread_pool = if traversal_flags.contains(TraversalFlags::ParallelTraversal) {
253         pool = thread_pool_holder.pool();
254         pool.as_ref()
255     } else {
256         None
257     };
258 
259     let traversal = RecalcStyleOnly::new(shared_style_context);
260     driver::traverse_dom(&traversal, token, thread_pool);
261 }
262 
263 /// Traverses the subtree rooted at `root` for restyling.
264 ///
265 /// Returns whether the root was restyled. Whether anything else was restyled or
266 /// not can be inferred from the dirty bits in the rest of the tree.
267 #[no_mangle]
Servo_TraverseSubtree( root: &RawGeckoElement, raw_data: &RawServoStyleSet, snapshots: *const ServoElementSnapshotTable, raw_flags: ServoTraversalFlags, ) -> bool268 pub extern "C" fn Servo_TraverseSubtree(
269     root: &RawGeckoElement,
270     raw_data: &RawServoStyleSet,
271     snapshots: *const ServoElementSnapshotTable,
272     raw_flags: ServoTraversalFlags,
273 ) -> bool {
274     let traversal_flags = TraversalFlags::from_bits_truncate(raw_flags);
275     debug_assert!(!snapshots.is_null());
276 
277     let element = GeckoElement(root);
278 
279     debug!("Servo_TraverseSubtree (flags={:?})", traversal_flags);
280     debug!("{:?}", ShowSubtreeData(element.as_node()));
281 
282     if cfg!(debug_assertions) {
283         if let Some(parent) = element.traversal_parent() {
284             let data = parent
285                 .borrow_data()
286                 .expect("Styling element with unstyled parent");
287             assert!(
288                 !data.styles.is_display_none(),
289                 "Styling element with display: none parent"
290             );
291         }
292     }
293 
294     let needs_animation_only_restyle =
295         element.has_animation_only_dirty_descendants() || element.has_animation_restyle_hints();
296 
297     let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
298     debug_assert!(!per_doc_data.stylist.stylesheets_have_changed());
299 
300     let global_style_data = &*GLOBAL_STYLE_DATA;
301     let guard = global_style_data.shared_lock.read();
302 
303     let was_initial_style = !element.has_data();
304 
305     if needs_animation_only_restyle {
306         debug!(
307             "Servo_TraverseSubtree doing animation-only restyle (aodd={})",
308             element.has_animation_only_dirty_descendants()
309         );
310         traverse_subtree(
311             element,
312             &global_style_data,
313             &per_doc_data,
314             &guard,
315             traversal_flags | TraversalFlags::AnimationOnly,
316             unsafe { &*snapshots },
317         );
318     }
319 
320     traverse_subtree(
321         element,
322         &global_style_data,
323         &per_doc_data,
324         &guard,
325         traversal_flags,
326         unsafe { &*snapshots },
327     );
328 
329     debug!(
330         "Servo_TraverseSubtree complete (dd={}, aodd={}, lfcd={}, lfc={}, data={:?})",
331         element.has_dirty_descendants(),
332         element.has_animation_only_dirty_descendants(),
333         element.descendants_need_frames(),
334         element.needs_frame(),
335         element.borrow_data().unwrap()
336     );
337 
338     if was_initial_style {
339         debug_assert!(!element.borrow_data().unwrap().contains_restyle_data());
340         false
341     } else {
342         let element_was_restyled = element.borrow_data().unwrap().contains_restyle_data();
343         element_was_restyled
344     }
345 }
346 
347 /// Checks whether the rule tree has crossed its threshold for unused nodes, and
348 /// if so, frees them.
349 #[no_mangle]
Servo_MaybeGCRuleTree(raw_data: &RawServoStyleSet)350 pub extern "C" fn Servo_MaybeGCRuleTree(raw_data: &RawServoStyleSet) {
351     let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
352     per_doc_data.stylist.rule_tree().maybe_gc();
353 }
354 
355 #[no_mangle]
Servo_AnimationValues_Interpolate( from: &RawServoAnimationValue, to: &RawServoAnimationValue, progress: f64, ) -> Strong<RawServoAnimationValue>356 pub extern "C" fn Servo_AnimationValues_Interpolate(
357     from: &RawServoAnimationValue,
358     to: &RawServoAnimationValue,
359     progress: f64,
360 ) -> Strong<RawServoAnimationValue> {
361     let from_value = AnimationValue::as_arc(&from);
362     let to_value = AnimationValue::as_arc(&to);
363     if let Ok(value) = from_value.animate(to_value, Procedure::Interpolate { progress }) {
364         Arc::new(value).into_strong()
365     } else {
366         Strong::null()
367     }
368 }
369 
370 #[no_mangle]
Servo_AnimationValues_IsInterpolable( from: &RawServoAnimationValue, to: &RawServoAnimationValue, ) -> bool371 pub extern "C" fn Servo_AnimationValues_IsInterpolable(
372     from: &RawServoAnimationValue,
373     to: &RawServoAnimationValue,
374 ) -> bool {
375     let from_value = AnimationValue::as_arc(&from);
376     let to_value = AnimationValue::as_arc(&to);
377     from_value
378         .animate(to_value, Procedure::Interpolate { progress: 0.5 })
379         .is_ok()
380 }
381 
382 #[no_mangle]
Servo_AnimationValues_Add( a: &RawServoAnimationValue, b: &RawServoAnimationValue, ) -> Strong<RawServoAnimationValue>383 pub extern "C" fn Servo_AnimationValues_Add(
384     a: &RawServoAnimationValue,
385     b: &RawServoAnimationValue,
386 ) -> Strong<RawServoAnimationValue> {
387     let a_value = AnimationValue::as_arc(&a);
388     let b_value = AnimationValue::as_arc(&b);
389     if let Ok(value) = a_value.animate(b_value, Procedure::Add) {
390         Arc::new(value).into_strong()
391     } else {
392         Strong::null()
393     }
394 }
395 
396 #[no_mangle]
Servo_AnimationValues_Accumulate( a: &RawServoAnimationValue, b: &RawServoAnimationValue, count: u64, ) -> Strong<RawServoAnimationValue>397 pub extern "C" fn Servo_AnimationValues_Accumulate(
398     a: &RawServoAnimationValue,
399     b: &RawServoAnimationValue,
400     count: u64,
401 ) -> Strong<RawServoAnimationValue> {
402     let a_value = AnimationValue::as_arc(&a);
403     let b_value = AnimationValue::as_arc(&b);
404     if let Ok(value) = a_value.animate(b_value, Procedure::Accumulate { count }) {
405         Arc::new(value).into_strong()
406     } else {
407         Strong::null()
408     }
409 }
410 
411 #[no_mangle]
Servo_AnimationValues_GetZeroValue( value_to_match: &RawServoAnimationValue, ) -> Strong<RawServoAnimationValue>412 pub extern "C" fn Servo_AnimationValues_GetZeroValue(
413     value_to_match: &RawServoAnimationValue,
414 ) -> Strong<RawServoAnimationValue> {
415     let value_to_match = AnimationValue::as_arc(&value_to_match);
416     if let Ok(zero_value) = value_to_match.to_animated_zero() {
417         Arc::new(zero_value).into_strong()
418     } else {
419         Strong::null()
420     }
421 }
422 
423 #[no_mangle]
Servo_AnimationValues_ComputeDistance( from: &RawServoAnimationValue, to: &RawServoAnimationValue, ) -> f64424 pub extern "C" fn Servo_AnimationValues_ComputeDistance(
425     from: &RawServoAnimationValue,
426     to: &RawServoAnimationValue,
427 ) -> f64 {
428     let from_value = AnimationValue::as_arc(&from);
429     let to_value = AnimationValue::as_arc(&to);
430     // If compute_squared_distance() failed, this function will return negative value
431     // in order to check whether we support the specified paced animation values.
432     from_value
433         .compute_squared_distance(to_value)
434         .map(|d| d.sqrt())
435         .unwrap_or(-1.0)
436 }
437 
438 /// Compute one of the endpoints for the interpolation interval, compositing it with the
439 /// underlying value if needed.
440 /// An None returned value means, "Just use endpoint_value as-is."
441 /// It is the responsibility of the caller to ensure that |underlying_value| is provided
442 /// when it will be used.
composite_endpoint( endpoint_value: Option<&RawOffsetArc<AnimationValue>>, composite: CompositeOperation, underlying_value: Option<&AnimationValue>, ) -> Option<AnimationValue>443 fn composite_endpoint(
444     endpoint_value: Option<&RawOffsetArc<AnimationValue>>,
445     composite: CompositeOperation,
446     underlying_value: Option<&AnimationValue>,
447 ) -> Option<AnimationValue> {
448     match endpoint_value {
449         Some(endpoint_value) => match composite {
450             CompositeOperation::Add => underlying_value
451                 .expect("We should have an underlying_value")
452                 .animate(endpoint_value, Procedure::Add)
453                 .ok(),
454             CompositeOperation::Accumulate => underlying_value
455                 .expect("We should have an underlying value")
456                 .animate(endpoint_value, Procedure::Accumulate { count: 1 })
457                 .ok(),
458             _ => None,
459         },
460         None => underlying_value.map(|v| v.clone()),
461     }
462 }
463 
464 /// Accumulate one of the endpoints of the animation interval.
465 /// A returned value of None means, "Just use endpoint_value as-is."
accumulate_endpoint( endpoint_value: Option<&RawOffsetArc<AnimationValue>>, composited_value: Option<AnimationValue>, last_value: &AnimationValue, current_iteration: u64, ) -> Option<AnimationValue>466 fn accumulate_endpoint(
467     endpoint_value: Option<&RawOffsetArc<AnimationValue>>,
468     composited_value: Option<AnimationValue>,
469     last_value: &AnimationValue,
470     current_iteration: u64,
471 ) -> Option<AnimationValue> {
472     debug_assert!(
473         endpoint_value.is_some() || composited_value.is_some(),
474         "Should have a suitable value to use"
475     );
476 
477     let count = current_iteration;
478     match composited_value {
479         Some(endpoint) => last_value
480             .animate(&endpoint, Procedure::Accumulate { count })
481             .ok()
482             .or(Some(endpoint)),
483         None => last_value
484             .animate(endpoint_value.unwrap(), Procedure::Accumulate { count })
485             .ok(),
486     }
487 }
488 
489 /// Compose the animation segment. We composite it with the underlying_value and last_value if
490 /// needed.
491 /// The caller is responsible for providing an underlying value and last value
492 /// in all situations where there are needed.
compose_animation_segment( segment: &structs::AnimationPropertySegment, underlying_value: Option<&AnimationValue>, last_value: Option<&AnimationValue>, iteration_composite: IterationCompositeOperation, current_iteration: u64, total_progress: f64, segment_progress: f64, ) -> AnimationValue493 fn compose_animation_segment(
494     segment: &structs::AnimationPropertySegment,
495     underlying_value: Option<&AnimationValue>,
496     last_value: Option<&AnimationValue>,
497     iteration_composite: IterationCompositeOperation,
498     current_iteration: u64,
499     total_progress: f64,
500     segment_progress: f64,
501 ) -> AnimationValue {
502     // Extract keyframe values.
503     let raw_from_value;
504     let keyframe_from_value = if !segment.mFromValue.mServo.mRawPtr.is_null() {
505         raw_from_value = unsafe { &*segment.mFromValue.mServo.mRawPtr };
506         Some(AnimationValue::as_arc(&raw_from_value))
507     } else {
508         None
509     };
510 
511     let raw_to_value;
512     let keyframe_to_value = if !segment.mToValue.mServo.mRawPtr.is_null() {
513         raw_to_value = unsafe { &*segment.mToValue.mServo.mRawPtr };
514         Some(AnimationValue::as_arc(&raw_to_value))
515     } else {
516         None
517     };
518 
519     let mut composited_from_value = composite_endpoint(
520         keyframe_from_value,
521         segment.mFromComposite,
522         underlying_value,
523     );
524     let mut composited_to_value =
525         composite_endpoint(keyframe_to_value, segment.mToComposite, underlying_value);
526 
527     debug_assert!(
528         keyframe_from_value.is_some() || composited_from_value.is_some(),
529         "Should have a suitable from value to use"
530     );
531     debug_assert!(
532         keyframe_to_value.is_some() || composited_to_value.is_some(),
533         "Should have a suitable to value to use"
534     );
535 
536     // Apply iteration composite behavior.
537     if iteration_composite == IterationCompositeOperation::Accumulate && current_iteration > 0 {
538         let last_value = last_value
539             .unwrap_or_else(|| underlying_value.expect("Should have a valid underlying value"));
540 
541         composited_from_value = accumulate_endpoint(
542             keyframe_from_value,
543             composited_from_value,
544             last_value,
545             current_iteration,
546         );
547         composited_to_value = accumulate_endpoint(
548             keyframe_to_value,
549             composited_to_value,
550             last_value,
551             current_iteration,
552         );
553     }
554 
555     // Use the composited value if there is one, otherwise, use the original keyframe value.
556     let from = composited_from_value
557         .as_ref()
558         .unwrap_or_else(|| keyframe_from_value.unwrap());
559     let to = composited_to_value
560         .as_ref()
561         .unwrap_or_else(|| keyframe_to_value.unwrap());
562 
563     if segment.mToKey == segment.mFromKey {
564         return if total_progress < 0. {
565             from.clone()
566         } else {
567             to.clone()
568         };
569     }
570 
571     match from.animate(
572         to,
573         Procedure::Interpolate {
574             progress: segment_progress,
575         },
576     ) {
577         Ok(value) => value,
578         _ => {
579             if segment_progress < 0.5 {
580                 from.clone()
581             } else {
582                 to.clone()
583             }
584         },
585     }
586 }
587 
588 #[no_mangle]
Servo_ComposeAnimationSegment( segment: &structs::AnimationPropertySegment, underlying_value: Option<&RawServoAnimationValue>, last_value: Option<&RawServoAnimationValue>, iteration_composite: IterationCompositeOperation, progress: f64, current_iteration: u64, ) -> Strong<RawServoAnimationValue>589 pub extern "C" fn Servo_ComposeAnimationSegment(
590     segment: &structs::AnimationPropertySegment,
591     underlying_value: Option<&RawServoAnimationValue>,
592     last_value: Option<&RawServoAnimationValue>,
593     iteration_composite: IterationCompositeOperation,
594     progress: f64,
595     current_iteration: u64,
596 ) -> Strong<RawServoAnimationValue> {
597     let underlying_value = AnimationValue::arc_from_borrowed(&underlying_value).map(|v| &**v);
598     let last_value = AnimationValue::arc_from_borrowed(&last_value).map(|v| &**v);
599     let result = compose_animation_segment(
600         segment,
601         underlying_value,
602         last_value,
603         iteration_composite,
604         current_iteration,
605         progress,
606         progress,
607     );
608     Arc::new(result).into_strong()
609 }
610 
611 #[no_mangle]
Servo_AnimationCompose( raw_value_map: &mut structs::RawServoAnimationValueMap, base_values: &structs::RawServoAnimationValueTable, css_property: nsCSSPropertyID, segment: &structs::AnimationPropertySegment, last_segment: &structs::AnimationPropertySegment, computed_timing: &structs::ComputedTiming, iteration_composite: IterationCompositeOperation, )612 pub extern "C" fn Servo_AnimationCompose(
613     raw_value_map: &mut structs::RawServoAnimationValueMap,
614     base_values: &structs::RawServoAnimationValueTable,
615     css_property: nsCSSPropertyID,
616     segment: &structs::AnimationPropertySegment,
617     last_segment: &structs::AnimationPropertySegment,
618     computed_timing: &structs::ComputedTiming,
619     iteration_composite: IterationCompositeOperation,
620 ) {
621     use style::gecko_bindings::bindings::Gecko_AnimationGetBaseStyle;
622     use style::gecko_bindings::bindings::Gecko_GetPositionInSegment;
623     use style::gecko_bindings::bindings::Gecko_GetProgressFromComputedTiming;
624 
625     let property = match LonghandId::from_nscsspropertyid(css_property) {
626         Ok(longhand) if longhand.is_animatable() => longhand,
627         _ => return,
628     };
629     let value_map = AnimationValueMap::from_ffi_mut(raw_value_map);
630 
631     // We will need an underlying value if either of the endpoints is null...
632     let need_underlying_value = segment.mFromValue.mServo.mRawPtr.is_null() ||
633                                 segment.mToValue.mServo.mRawPtr.is_null() ||
634                                 // ... or if they have a non-replace composite mode ...
635                                 segment.mFromComposite != CompositeOperation::Replace ||
636                                 segment.mToComposite != CompositeOperation::Replace ||
637                                 // ... or if we accumulate onto the last value and it is null.
638                                 (iteration_composite == IterationCompositeOperation::Accumulate &&
639                                  computed_timing.mCurrentIteration > 0 &&
640                                  last_segment.mToValue.mServo.mRawPtr.is_null());
641 
642     // If either of the segment endpoints are null, get the underlying value to
643     // use from the current value in the values map (set by a lower-priority
644     // effect), or, if there is no current value, look up the cached base value
645     // for this property.
646     let underlying_value = if need_underlying_value {
647         let previous_composed_value = value_map.get(&property).cloned();
648         previous_composed_value.or_else(|| {
649             let raw_base_style =
650                 unsafe { Gecko_AnimationGetBaseStyle(base_values, css_property).as_ref() };
651             AnimationValue::arc_from_borrowed(&raw_base_style)
652                 .map(|v| &**v)
653                 .cloned()
654         })
655     } else {
656         None
657     };
658 
659     if need_underlying_value && underlying_value.is_none() {
660         warn!("Underlying value should be valid when we expect to use it");
661         return;
662     }
663 
664     let raw_last_value;
665     let last_value = if !last_segment.mToValue.mServo.mRawPtr.is_null() {
666         raw_last_value = unsafe { &*last_segment.mToValue.mServo.mRawPtr };
667         Some(&**AnimationValue::as_arc(&raw_last_value))
668     } else {
669         None
670     };
671 
672     let progress = unsafe { Gecko_GetProgressFromComputedTiming(computed_timing) };
673     let position = if segment.mToKey == segment.mFromKey {
674         // Note: compose_animation_segment doesn't use this value
675         // if segment.mFromKey == segment.mToKey, so assigning |progress| directly is fine.
676         progress
677     } else {
678         unsafe { Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag) }
679     };
680 
681     let result = compose_animation_segment(
682         segment,
683         underlying_value.as_ref(),
684         last_value,
685         iteration_composite,
686         computed_timing.mCurrentIteration,
687         progress,
688         position,
689     );
690     value_map.insert(property, result);
691 }
692 
693 macro_rules! get_property_id_from_nscsspropertyid {
694     ($property_id: ident, $ret: expr) => {{
695         match PropertyId::from_nscsspropertyid($property_id) {
696             Ok(property_id) => property_id,
697             Err(()) => {
698                 return $ret;
699             },
700         }
701     }};
702 }
703 
704 #[no_mangle]
Servo_AnimationValue_Serialize( value: &RawServoAnimationValue, property: nsCSSPropertyID, raw_data: &RawServoStyleSet, buffer: &mut nsAString, )705 pub extern "C" fn Servo_AnimationValue_Serialize(
706     value: &RawServoAnimationValue,
707     property: nsCSSPropertyID,
708     raw_data: &RawServoStyleSet,
709     buffer: &mut nsAString,
710 ) {
711     let uncomputed_value = AnimationValue::as_arc(&value).uncompute();
712     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
713     let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
714         .single_value_to_css(
715             &get_property_id_from_nscsspropertyid!(property, ()),
716             buffer,
717             None,
718             None, /* No extra custom properties */
719             &data.stylist.device(),
720         );
721     debug_assert!(rv.is_ok());
722 }
723 
724 /// Debug: MOZ_DBG for AnimationValue.
725 #[no_mangle]
Servo_AnimationValue_Dump( value: &RawServoAnimationValue, result: &mut nsAString, )726 pub extern "C" fn Servo_AnimationValue_Dump(
727     value: &RawServoAnimationValue,
728     result: &mut nsAString,
729 ) {
730     let value = AnimationValue::as_arc(&value);
731     write!(result, "{:?}", value).unwrap();
732 }
733 
734 #[no_mangle]
Servo_AnimationValue_GetColor( value: &RawServoAnimationValue, foreground_color: structs::nscolor, ) -> structs::nscolor735 pub extern "C" fn Servo_AnimationValue_GetColor(
736     value: &RawServoAnimationValue,
737     foreground_color: structs::nscolor,
738 ) -> structs::nscolor {
739     use style::gecko::values::convert_nscolor_to_rgba;
740     use style::gecko::values::convert_rgba_to_nscolor;
741     use style::values::animated::ToAnimatedValue;
742     use style::values::computed::color::Color as ComputedColor;
743 
744     let value = AnimationValue::as_arc(&value);
745     match **value {
746         AnimationValue::BackgroundColor(color) => {
747             let computed: ComputedColor = ToAnimatedValue::from_animated_value(color);
748             let foreground_color = convert_nscolor_to_rgba(foreground_color);
749             convert_rgba_to_nscolor(&computed.to_rgba(foreground_color))
750         },
751         _ => panic!("Other color properties are not supported yet"),
752     }
753 }
754 
755 #[no_mangle]
Servo_AnimationValue_IsCurrentColor( value: &RawServoAnimationValue, ) -> bool756 pub extern "C" fn Servo_AnimationValue_IsCurrentColor(
757     value: &RawServoAnimationValue,
758 ) -> bool {
759     let value = AnimationValue::as_arc(&value);
760     match **value {
761         AnimationValue::BackgroundColor(color) => {
762             color.is_currentcolor()
763         },
764         _ => {
765             debug_assert!(false, "Other color properties are not supported yet");
766             false
767         },
768     }
769 }
770 
771 #[no_mangle]
Servo_AnimationValue_GetOpacity(value: &RawServoAnimationValue) -> f32772 pub extern "C" fn Servo_AnimationValue_GetOpacity(value: &RawServoAnimationValue) -> f32 {
773     let value = AnimationValue::as_arc(&value);
774     if let AnimationValue::Opacity(opacity) = **value {
775         opacity
776     } else {
777         panic!("The AnimationValue should be Opacity");
778     }
779 }
780 
781 #[no_mangle]
Servo_AnimationValue_Opacity(opacity: f32) -> Strong<RawServoAnimationValue>782 pub extern "C" fn Servo_AnimationValue_Opacity(opacity: f32) -> Strong<RawServoAnimationValue> {
783     Arc::new(AnimationValue::Opacity(opacity)).into_strong()
784 }
785 
786 #[no_mangle]
Servo_AnimationValue_Color( color_property: nsCSSPropertyID, color: structs::nscolor, ) -> Strong<RawServoAnimationValue>787 pub extern "C" fn Servo_AnimationValue_Color(
788     color_property: nsCSSPropertyID,
789     color: structs::nscolor,
790 ) -> Strong<RawServoAnimationValue> {
791     use style::gecko::values::convert_nscolor_to_rgba;
792     use style::values::animated::color::RGBA as AnimatedRGBA;
793 
794     let property = LonghandId::from_nscsspropertyid(color_property)
795         .expect("We don't have shorthand property animation value");
796 
797     let rgba = convert_nscolor_to_rgba(color);
798 
799     let animatedRGBA = AnimatedRGBA::new(
800         rgba.red_f32(),
801         rgba.green_f32(),
802         rgba.blue_f32(),
803         rgba.alpha_f32(),
804     );
805     match property {
806         LonghandId::BackgroundColor => {
807             Arc::new(AnimationValue::BackgroundColor(animatedRGBA.into())).into_strong()
808         },
809         _ => panic!("Should be background-color property"),
810     }
811 }
812 
813 #[no_mangle]
Servo_AnimationValue_GetScale( value: &RawServoAnimationValue, ) -> *const computed::Scale814 pub unsafe extern "C" fn Servo_AnimationValue_GetScale(
815     value: &RawServoAnimationValue,
816 ) -> *const computed::Scale {
817     let value = AnimationValue::as_arc(&value);
818     match **value {
819         AnimationValue::Scale(ref value) => value,
820         _ => unreachable!("Expected scale"),
821     }
822 }
823 
824 #[no_mangle]
Servo_AnimationValue_GetTranslate( value: &RawServoAnimationValue, ) -> *const computed::Translate825 pub unsafe extern "C" fn Servo_AnimationValue_GetTranslate(
826     value: &RawServoAnimationValue,
827 ) -> *const computed::Translate {
828     let value = AnimationValue::as_arc(&value);
829     match **value {
830         AnimationValue::Translate(ref value) => value,
831         _ => unreachable!("Expected translate"),
832     }
833 }
834 
835 #[no_mangle]
Servo_AnimationValue_GetRotate( value: &RawServoAnimationValue, ) -> *const computed::Rotate836 pub unsafe extern "C" fn Servo_AnimationValue_GetRotate(
837     value: &RawServoAnimationValue,
838 ) -> *const computed::Rotate {
839     let value = AnimationValue::as_arc(&value);
840     match **value {
841         AnimationValue::Rotate(ref value) => value,
842         _ => unreachable!("Expected rotate"),
843     }
844 }
845 
846 #[no_mangle]
Servo_AnimationValue_GetTransform( value: &RawServoAnimationValue, ) -> *const computed::Transform847 pub unsafe extern "C" fn Servo_AnimationValue_GetTransform(
848     value: &RawServoAnimationValue,
849 ) -> *const computed::Transform {
850     let value = AnimationValue::as_arc(&value);
851     match **value {
852         AnimationValue::Transform(ref value) => value,
853         _ => unreachable!("Unsupported transform animation value"),
854     }
855 }
856 
857 #[no_mangle]
Servo_AnimationValue_GetOffsetPath( value: &RawServoAnimationValue, ) -> *const computed::motion::OffsetPath858 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPath(
859     value: &RawServoAnimationValue,
860 ) -> *const computed::motion::OffsetPath {
861     let value = AnimationValue::as_arc(&value);
862     match **value {
863         AnimationValue::OffsetPath(ref value) => value,
864         _ => unreachable!("Expected offset-path"),
865     }
866 }
867 
868 #[no_mangle]
Servo_AnimationValue_GetOffsetDistance( value: &RawServoAnimationValue, ) -> *const computed::LengthPercentage869 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetDistance(
870     value: &RawServoAnimationValue,
871 ) -> *const computed::LengthPercentage {
872     let value = AnimationValue::as_arc(&value);
873     match **value {
874         AnimationValue::OffsetDistance(ref value) => value,
875         _ => unreachable!("Expected offset-distance"),
876     }
877 }
878 
879 #[no_mangle]
Servo_AnimationValue_GetOffsetRotate( value: &RawServoAnimationValue, ) -> *const computed::motion::OffsetRotate880 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetRotate(
881     value: &RawServoAnimationValue,
882 ) -> *const computed::motion::OffsetRotate {
883     let value = AnimationValue::as_arc(&value);
884     match **value {
885         AnimationValue::OffsetRotate(ref value) => value,
886         _ => unreachable!("Expected offset-rotate"),
887     }
888 }
889 
890 #[no_mangle]
Servo_AnimationValue_GetOffsetAnchor( value: &RawServoAnimationValue, ) -> *const computed::position::PositionOrAuto891 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetAnchor(
892     value: &RawServoAnimationValue,
893 ) -> *const computed::position::PositionOrAuto {
894     let value = AnimationValue::as_arc(&value);
895     match **value {
896         AnimationValue::OffsetAnchor(ref value) => value,
897         _ => unreachable!("Expected offset-anchor"),
898     }
899 }
900 
901 #[no_mangle]
Servo_AnimationValue_Rotate( r: &computed::Rotate, ) -> Strong<RawServoAnimationValue>902 pub unsafe extern "C" fn Servo_AnimationValue_Rotate(
903     r: &computed::Rotate,
904 ) -> Strong<RawServoAnimationValue> {
905     Arc::new(AnimationValue::Rotate(r.clone())).into_strong()
906 }
907 
908 #[no_mangle]
Servo_AnimationValue_Translate( t: &computed::Translate, ) -> Strong<RawServoAnimationValue>909 pub unsafe extern "C" fn Servo_AnimationValue_Translate(
910     t: &computed::Translate,
911 ) -> Strong<RawServoAnimationValue> {
912     Arc::new(AnimationValue::Translate(t.clone())).into_strong()
913 }
914 
915 #[no_mangle]
Servo_AnimationValue_Scale( s: &computed::Scale, ) -> Strong<RawServoAnimationValue>916 pub unsafe extern "C" fn Servo_AnimationValue_Scale(
917     s: &computed::Scale,
918 ) -> Strong<RawServoAnimationValue> {
919     Arc::new(AnimationValue::Scale(s.clone())).into_strong()
920 }
921 
922 #[no_mangle]
Servo_AnimationValue_Transform( transform: &computed::Transform, ) -> Strong<RawServoAnimationValue>923 pub unsafe extern "C" fn Servo_AnimationValue_Transform(
924     transform: &computed::Transform,
925 ) -> Strong<RawServoAnimationValue> {
926     Arc::new(AnimationValue::Transform(transform.clone())).into_strong()
927 }
928 
929 #[no_mangle]
Servo_AnimationValue_OffsetPath( p: &computed::motion::OffsetPath, ) -> Strong<RawServoAnimationValue>930 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPath(
931     p: &computed::motion::OffsetPath,
932 ) -> Strong<RawServoAnimationValue> {
933     Arc::new(AnimationValue::OffsetPath(p.clone())).into_strong()
934 }
935 
936 #[no_mangle]
Servo_AnimationValue_OffsetDistance( d: &computed::length::LengthPercentage, ) -> Strong<RawServoAnimationValue>937 pub unsafe extern "C" fn Servo_AnimationValue_OffsetDistance(
938     d: &computed::length::LengthPercentage,
939 ) -> Strong<RawServoAnimationValue> {
940     Arc::new(AnimationValue::OffsetDistance(d.clone())).into_strong()
941 }
942 
943 #[no_mangle]
Servo_AnimationValue_OffsetRotate( r: &computed::motion::OffsetRotate, ) -> Strong<RawServoAnimationValue>944 pub unsafe extern "C" fn Servo_AnimationValue_OffsetRotate(
945     r: &computed::motion::OffsetRotate,
946 ) -> Strong<RawServoAnimationValue> {
947     Arc::new(AnimationValue::OffsetRotate(*r)).into_strong()
948 }
949 
950 #[no_mangle]
Servo_AnimationValue_OffsetAnchor( p: &computed::position::PositionOrAuto, ) -> Strong<RawServoAnimationValue>951 pub unsafe extern "C" fn Servo_AnimationValue_OffsetAnchor(
952     p: &computed::position::PositionOrAuto,
953 ) -> Strong<RawServoAnimationValue> {
954     Arc::new(AnimationValue::OffsetAnchor(p.clone())).into_strong()
955 }
956 
957 #[no_mangle]
Servo_AnimationValue_DeepEqual( this: &RawServoAnimationValue, other: &RawServoAnimationValue, ) -> bool958 pub extern "C" fn Servo_AnimationValue_DeepEqual(
959     this: &RawServoAnimationValue,
960     other: &RawServoAnimationValue,
961 ) -> bool {
962     let this_value = AnimationValue::as_arc(&this);
963     let other_value = AnimationValue::as_arc(&other);
964     this_value == other_value
965 }
966 
967 #[no_mangle]
Servo_AnimationValue_Uncompute( value: &RawServoAnimationValue, ) -> Strong<RawServoDeclarationBlock>968 pub extern "C" fn Servo_AnimationValue_Uncompute(
969     value: &RawServoAnimationValue,
970 ) -> Strong<RawServoDeclarationBlock> {
971     let value = AnimationValue::as_arc(&value);
972     let global_style_data = &*GLOBAL_STYLE_DATA;
973     Arc::new(
974         global_style_data
975             .shared_lock
976             .wrap(PropertyDeclarationBlock::with_one(
977                 value.uncompute(),
978                 Importance::Normal,
979             )),
980     )
981     .into_strong()
982 }
983 
984 #[inline]
create_byte_buf_from_vec(mut v: Vec<u8>) -> ByteBuf985 fn create_byte_buf_from_vec(mut v: Vec<u8>) -> ByteBuf {
986     let w = ByteBuf {
987         mData: v.as_mut_ptr(),
988         mLen: v.len(),
989         mCapacity: v.capacity(),
990     };
991     std::mem::forget(v);
992     w
993 }
994 
995 #[inline]
view_byte_buf(b: &ByteBuf) -> &[u8]996 fn view_byte_buf(b: &ByteBuf) -> &[u8] {
997     if b.mData.is_null() {
998         debug_assert_eq!(b.mCapacity, 0);
999         return &[];
1000     }
1001     unsafe { std::slice::from_raw_parts(b.mData, b.mLen) }
1002 }
1003 
1004 macro_rules! impl_basic_serde_funcs {
1005     ($ser_name:ident, $de_name:ident, $computed_type:ty) => {
1006         #[no_mangle]
1007         pub extern "C" fn $ser_name(v: &$computed_type, output: &mut ByteBuf) -> bool {
1008             let buf = match serialize(v) {
1009                 Ok(buf) => buf,
1010                 Err(..) => return false,
1011             };
1012 
1013             *output = create_byte_buf_from_vec(buf);
1014             true
1015         }
1016 
1017         #[no_mangle]
1018         pub extern "C" fn $de_name(input: &ByteBuf, v: &mut $computed_type) -> bool {
1019             let buf = match deserialize(view_byte_buf(input)) {
1020                 Ok(buf) => buf,
1021                 Err(..) => return false,
1022             };
1023 
1024             *v = buf;
1025             true
1026         }
1027     };
1028 }
1029 
1030 impl_basic_serde_funcs!(
1031     Servo_LengthPercentage_Serialize,
1032     Servo_LengthPercentage_Deserialize,
1033     computed::LengthPercentage
1034 );
1035 
1036 impl_basic_serde_funcs!(
1037     Servo_StyleRotate_Serialize,
1038     Servo_StyleRotate_Deserialize,
1039     computed::transform::Rotate
1040 );
1041 
1042 impl_basic_serde_funcs!(
1043     Servo_StyleScale_Serialize,
1044     Servo_StyleScale_Deserialize,
1045     computed::transform::Scale
1046 );
1047 
1048 impl_basic_serde_funcs!(
1049     Servo_StyleTranslate_Serialize,
1050     Servo_StyleTranslate_Deserialize,
1051     computed::transform::Translate
1052 );
1053 
1054 impl_basic_serde_funcs!(
1055     Servo_StyleTransform_Serialize,
1056     Servo_StyleTransform_Deserialize,
1057     computed::transform::Transform
1058 );
1059 
1060 impl_basic_serde_funcs!(
1061     Servo_StyleOffsetPath_Serialize,
1062     Servo_StyleOffsetPath_Deserialize,
1063     computed::motion::OffsetPath
1064 );
1065 
1066 impl_basic_serde_funcs!(
1067     Servo_StyleOffsetRotate_Serialize,
1068     Servo_StyleOffsetRotate_Deserialize,
1069     computed::motion::OffsetRotate
1070 );
1071 
1072 impl_basic_serde_funcs!(
1073     Servo_StylePositionOrAuto_Serialize,
1074     Servo_StylePositionOrAuto_Deserialize,
1075     computed::position::PositionOrAuto
1076 );
1077 
1078 #[no_mangle]
Servo_SVGPathData_Normalize( input: &specified::SVGPathData, output: &mut specified::SVGPathData, )1079 pub extern "C" fn Servo_SVGPathData_Normalize(
1080     input: &specified::SVGPathData,
1081     output: &mut specified::SVGPathData,
1082 ) {
1083     *output = input.normalize();
1084 }
1085 
1086 // Return the ComputedValues by a base ComputedValues and the rules.
resolve_rules_for_element_with_context<'a>( element: GeckoElement<'a>, mut context: StyleContext<GeckoElement<'a>>, rules: StrongRuleNode, ) -> Arc<ComputedValues>1087 fn resolve_rules_for_element_with_context<'a>(
1088     element: GeckoElement<'a>,
1089     mut context: StyleContext<GeckoElement<'a>>,
1090     rules: StrongRuleNode,
1091 ) -> Arc<ComputedValues> {
1092     use style::style_resolver::{PseudoElementResolution, StyleResolverForElement};
1093 
1094     // This currently ignores visited styles, which seems acceptable, as
1095     // existing browsers don't appear to animate visited styles.
1096     let inputs = CascadeInputs {
1097         rules: Some(rules),
1098         visited_rules: None,
1099     };
1100 
1101     // Actually `PseudoElementResolution` doesn't matter.
1102     let mut resolver = StyleResolverForElement::new(
1103         element,
1104         &mut context,
1105         RuleInclusion::All,
1106         PseudoElementResolution::IfApplicable,
1107     );
1108     resolver
1109         .cascade_style_and_visited_with_default_parents(inputs)
1110         .0
1111 }
1112 
1113 #[no_mangle]
Servo_AnimationValueMap_Create() -> Owned<structs::RawServoAnimationValueMap>1114 pub extern "C" fn Servo_AnimationValueMap_Create() -> Owned<structs::RawServoAnimationValueMap> {
1115     Box::<AnimationValueMap>::default().into_ffi()
1116 }
1117 
1118 #[no_mangle]
Servo_AnimationValueMap_Drop( value_map: *mut structs::RawServoAnimationValueMap, )1119 pub unsafe extern "C" fn Servo_AnimationValueMap_Drop(
1120     value_map: *mut structs::RawServoAnimationValueMap,
1121 ) {
1122     AnimationValueMap::drop_ffi(value_map)
1123 }
1124 
1125 #[no_mangle]
Servo_AnimationValueMap_GetValue( raw_value_map: &mut structs::RawServoAnimationValueMap, property_id: nsCSSPropertyID, ) -> Strong<RawServoAnimationValue>1126 pub extern "C" fn Servo_AnimationValueMap_GetValue(
1127     raw_value_map: &mut structs::RawServoAnimationValueMap,
1128     property_id: nsCSSPropertyID,
1129 ) -> Strong<RawServoAnimationValue> {
1130     let property = match LonghandId::from_nscsspropertyid(property_id) {
1131         Ok(longhand) => longhand,
1132         Err(()) => return Strong::null(),
1133     };
1134     let value_map = AnimationValueMap::from_ffi_mut(raw_value_map);
1135 
1136     value_map.get(&property).map_or(Strong::null(), |value| {
1137         Arc::new(value.clone()).into_strong()
1138     })
1139 }
1140 
1141 #[no_mangle]
Servo_StyleSet_GetBaseComputedValuesForElement( raw_style_set: &RawServoStyleSet, element: &RawGeckoElement, computed_values: &ComputedValues, snapshots: *const ServoElementSnapshotTable, ) -> Strong<ComputedValues>1142 pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(
1143     raw_style_set: &RawServoStyleSet,
1144     element: &RawGeckoElement,
1145     computed_values: &ComputedValues,
1146     snapshots: *const ServoElementSnapshotTable,
1147 ) -> Strong<ComputedValues> {
1148     debug_assert!(!snapshots.is_null());
1149     let computed_values = unsafe { ArcBorrow::from_ref(computed_values) };
1150 
1151     let rules = match computed_values.rules {
1152         None => return computed_values.clone_arc().into(),
1153         Some(ref rules) => rules,
1154     };
1155 
1156     let doc_data = PerDocumentStyleData::from_ffi(raw_style_set).borrow();
1157     let without_animations_rules = doc_data.stylist.rule_tree().remove_animation_rules(rules);
1158     if without_animations_rules == *rules {
1159         return computed_values.clone_arc().into();
1160     }
1161 
1162     let element = GeckoElement(element);
1163 
1164     let global_style_data = &*GLOBAL_STYLE_DATA;
1165     let guard = global_style_data.shared_lock.read();
1166     let shared = create_shared_context(
1167         &global_style_data,
1168         &guard,
1169         &doc_data,
1170         TraversalFlags::empty(),
1171         unsafe { &*snapshots },
1172     );
1173     let mut tlc = ThreadLocalStyleContext::new(&shared);
1174     let context = StyleContext {
1175         shared: &shared,
1176         thread_local: &mut tlc,
1177     };
1178 
1179     resolve_rules_for_element_with_context(element, context, without_animations_rules).into()
1180 }
1181 
1182 #[no_mangle]
Servo_StyleSet_GetComputedValuesByAddingAnimation( raw_style_set: &RawServoStyleSet, element: &RawGeckoElement, computed_values: &ComputedValues, snapshots: *const ServoElementSnapshotTable, animation_value: &RawServoAnimationValue, ) -> Strong<ComputedValues>1183 pub extern "C" fn Servo_StyleSet_GetComputedValuesByAddingAnimation(
1184     raw_style_set: &RawServoStyleSet,
1185     element: &RawGeckoElement,
1186     computed_values: &ComputedValues,
1187     snapshots: *const ServoElementSnapshotTable,
1188     animation_value: &RawServoAnimationValue,
1189 ) -> Strong<ComputedValues> {
1190     debug_assert!(!snapshots.is_null());
1191     let rules = match computed_values.rules {
1192         None => return Strong::null(),
1193         Some(ref rules) => rules,
1194     };
1195 
1196     let global_style_data = &*GLOBAL_STYLE_DATA;
1197     let guard = global_style_data.shared_lock.read();
1198     let uncomputed_value = AnimationValue::as_arc(&animation_value).uncompute();
1199     let doc_data = PerDocumentStyleData::from_ffi(raw_style_set).borrow();
1200 
1201     let with_animations_rules = {
1202         let guards = StylesheetGuards::same(&guard);
1203         let declarations = Arc::new(global_style_data.shared_lock.wrap(
1204             PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal),
1205         ));
1206         doc_data
1207             .stylist
1208             .rule_tree()
1209             .add_animation_rules_at_transition_level(rules, declarations, &guards)
1210     };
1211 
1212     let element = GeckoElement(element);
1213     if element.borrow_data().is_none() {
1214         return Strong::null();
1215     }
1216 
1217     let shared = create_shared_context(
1218         &global_style_data,
1219         &guard,
1220         &doc_data,
1221         TraversalFlags::empty(),
1222         unsafe { &*snapshots },
1223     );
1224     let mut tlc: ThreadLocalStyleContext<GeckoElement> = ThreadLocalStyleContext::new(&shared);
1225     let context = StyleContext {
1226         shared: &shared,
1227         thread_local: &mut tlc,
1228     };
1229 
1230     resolve_rules_for_element_with_context(element, context, with_animations_rules).into()
1231 }
1232 
1233 #[no_mangle]
Servo_ComputedValues_ExtractAnimationValue( computed_values: &ComputedValues, property_id: nsCSSPropertyID, ) -> Strong<RawServoAnimationValue>1234 pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue(
1235     computed_values: &ComputedValues,
1236     property_id: nsCSSPropertyID,
1237 ) -> Strong<RawServoAnimationValue> {
1238     let property = match LonghandId::from_nscsspropertyid(property_id) {
1239         Ok(longhand) => longhand,
1240         Err(()) => return Strong::null(),
1241     };
1242     match AnimationValue::from_computed_values(property, &computed_values) {
1243         Some(v) => Arc::new(v).into_strong(),
1244         None => Strong::null(),
1245     }
1246 }
1247 
1248 #[no_mangle]
Servo_ResolveLogicalProperty( property_id: nsCSSPropertyID, style: &ComputedValues, ) -> nsCSSPropertyID1249 pub extern "C" fn Servo_ResolveLogicalProperty(
1250     property_id: nsCSSPropertyID,
1251     style: &ComputedValues,
1252 ) -> nsCSSPropertyID {
1253     let longhand = LonghandId::from_nscsspropertyid(property_id)
1254         .expect("We shouldn't need to care about shorthands");
1255 
1256     longhand
1257         .to_physical(style.writing_mode)
1258         .to_nscsspropertyid()
1259 }
1260 
1261 #[no_mangle]
Servo_Property_LookupEnabledForAllContent( prop: &nsACString, ) -> nsCSSPropertyID1262 pub unsafe extern "C" fn Servo_Property_LookupEnabledForAllContent(
1263     prop: &nsACString,
1264 ) -> nsCSSPropertyID {
1265     match PropertyId::parse_enabled_for_all_content(prop.as_str_unchecked()) {
1266         Ok(p) => p.to_nscsspropertyid_resolving_aliases(),
1267         Err(..) => nsCSSPropertyID::eCSSProperty_UNKNOWN,
1268     }
1269 }
1270 
1271 #[no_mangle]
Servo_Property_GetName( prop: nsCSSPropertyID, out_length: *mut u32, ) -> *const u81272 pub unsafe extern "C" fn Servo_Property_GetName(
1273     prop: nsCSSPropertyID,
1274     out_length: *mut u32,
1275 ) -> *const u8 {
1276     let (ptr, len) = match NonCustomPropertyId::from_nscsspropertyid(prop) {
1277         Ok(p) => {
1278             let name = p.name();
1279             (name.as_bytes().as_ptr(), name.len())
1280         },
1281         Err(..) => (ptr::null(), 0),
1282     };
1283 
1284     *out_length = len as u32;
1285     ptr
1286 }
1287 
1288 macro_rules! parse_enabled_property_name {
1289     ($prop_name:ident, $found:ident, $default:expr) => {{
1290         let prop_name = $prop_name.as_str_unchecked();
1291         match PropertyId::parse_enabled_for_all_content(prop_name) {
1292             Ok(p) => {
1293                 *$found = true;
1294                 p
1295             },
1296             Err(..) => {
1297                 *$found = false;
1298                 return $default;
1299             },
1300         }
1301     }};
1302 }
1303 
1304 #[no_mangle]
Servo_Property_IsShorthand( prop_name: &nsACString, found: *mut bool, ) -> bool1305 pub unsafe extern "C" fn Servo_Property_IsShorthand(
1306     prop_name: &nsACString,
1307     found: *mut bool,
1308 ) -> bool {
1309     let prop_id = parse_enabled_property_name!(prop_name, found, false);
1310     prop_id.is_shorthand()
1311 }
1312 
1313 #[no_mangle]
Servo_Property_IsInherited(prop_name: &nsACString) -> bool1314 pub unsafe extern "C" fn Servo_Property_IsInherited(prop_name: &nsACString) -> bool {
1315     let prop_name = prop_name.as_str_unchecked();
1316     let prop_id = match PropertyId::parse_enabled_for_all_content(prop_name) {
1317         Ok(id) => id,
1318         Err(_) => return false,
1319     };
1320     let longhand_id = match prop_id {
1321         PropertyId::Custom(_) => return true,
1322         PropertyId::Longhand(id) | PropertyId::LonghandAlias(id, _) => id,
1323         PropertyId::Shorthand(id) | PropertyId::ShorthandAlias(id, _) => {
1324             id.longhands().next().unwrap()
1325         },
1326     };
1327     longhand_id.inherited()
1328 }
1329 
1330 #[no_mangle]
Servo_Property_SupportsType( prop_name: &nsACString, ty: u8, found: *mut bool, ) -> bool1331 pub unsafe extern "C" fn Servo_Property_SupportsType(
1332     prop_name: &nsACString,
1333     ty: u8,
1334     found: *mut bool,
1335 ) -> bool {
1336     let prop_id = parse_enabled_property_name!(prop_name, found, false);
1337     prop_id.supports_type(ty)
1338 }
1339 
1340 // TODO(emilio): We could use ThinVec instead of nsTArray.
1341 #[no_mangle]
Servo_Property_GetCSSValuesForProperty( prop_name: &nsACString, found: *mut bool, result: &mut nsTArray<nsString>, )1342 pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty(
1343     prop_name: &nsACString,
1344     found: *mut bool,
1345     result: &mut nsTArray<nsString>,
1346 ) {
1347     let prop_id = parse_enabled_property_name!(prop_name, found, ());
1348     // Use B-tree set for unique and sorted result.
1349     let mut values = BTreeSet::<&'static str>::new();
1350     prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter()));
1351 
1352     let mut extras = vec![];
1353     if values.contains("transparent") {
1354         // This is a special value devtools use to avoid inserting the
1355         // long list of color keywords. We need to prepend it to values.
1356         extras.push("COLOR");
1357     }
1358 
1359     let len = extras.len() + values.len();
1360     bindings::Gecko_ResizeTArrayForStrings(result, len as u32);
1361 
1362     for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) {
1363         dest.write_str(src).unwrap();
1364     }
1365 }
1366 
1367 #[no_mangle]
Servo_Property_IsAnimatable(prop: nsCSSPropertyID) -> bool1368 pub extern "C" fn Servo_Property_IsAnimatable(prop: nsCSSPropertyID) -> bool {
1369     NonCustomPropertyId::from_nscsspropertyid(prop)
1370         .ok()
1371         .map_or(false, |p| p.is_animatable())
1372 }
1373 
1374 #[no_mangle]
Servo_Property_IsTransitionable(prop: nsCSSPropertyID) -> bool1375 pub extern "C" fn Servo_Property_IsTransitionable(prop: nsCSSPropertyID) -> bool {
1376     NonCustomPropertyId::from_nscsspropertyid(prop)
1377         .ok()
1378         .map_or(false, |p| p.is_transitionable())
1379 }
1380 
1381 #[no_mangle]
Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID) -> bool1382 pub extern "C" fn Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID) -> bool {
1383     match LonghandId::from_nscsspropertyid(property) {
1384         Ok(longhand) => longhand.is_discrete_animatable(),
1385         Err(()) => return false,
1386     }
1387 }
1388 
1389 #[no_mangle]
Servo_Element_ClearData(element: &RawGeckoElement)1390 pub extern "C" fn Servo_Element_ClearData(element: &RawGeckoElement) {
1391     unsafe { GeckoElement(element).clear_data() };
1392 }
1393 
1394 #[no_mangle]
Servo_Element_SizeOfExcludingThisAndCVs( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, seen_ptrs: *mut SeenPtrs, element: &RawGeckoElement, ) -> usize1395 pub extern "C" fn Servo_Element_SizeOfExcludingThisAndCVs(
1396     malloc_size_of: GeckoMallocSizeOf,
1397     malloc_enclosing_size_of: GeckoMallocSizeOf,
1398     seen_ptrs: *mut SeenPtrs,
1399     element: &RawGeckoElement,
1400 ) -> usize {
1401     let element = GeckoElement(element);
1402     let borrow = element.borrow_data();
1403     if let Some(data) = borrow {
1404         let have_seen_ptr = move |ptr| unsafe { Gecko_HaveSeenPtr(seen_ptrs, ptr) };
1405         let mut ops = MallocSizeOfOps::new(
1406             malloc_size_of.unwrap(),
1407             Some(malloc_enclosing_size_of.unwrap()),
1408             Some(Box::new(have_seen_ptr)),
1409         );
1410         (*data).size_of_excluding_cvs(&mut ops)
1411     } else {
1412         0
1413     }
1414 }
1415 
1416 #[no_mangle]
Servo_Element_GetMaybeOutOfDateStyle( element: &RawGeckoElement, ) -> *const ComputedValues1417 pub extern "C" fn Servo_Element_GetMaybeOutOfDateStyle(
1418     element: &RawGeckoElement,
1419 ) -> *const ComputedValues {
1420     let element = GeckoElement(element);
1421     let data = match element.borrow_data() {
1422         Some(d) => d,
1423         None => return ptr::null(),
1424     };
1425     &**data.styles.primary() as *const _
1426 }
1427 
1428 #[no_mangle]
Servo_Element_GetMaybeOutOfDatePseudoStyle( element: &RawGeckoElement, index: usize, ) -> *const ComputedValues1429 pub extern "C" fn Servo_Element_GetMaybeOutOfDatePseudoStyle(
1430     element: &RawGeckoElement,
1431     index: usize,
1432 ) -> *const ComputedValues {
1433     let element = GeckoElement(element);
1434     let data = match element.borrow_data() {
1435         Some(d) => d,
1436         None => return ptr::null(),
1437     };
1438     match data.styles.pseudos.as_array()[index].as_ref() {
1439         Some(style) => &**style as *const _,
1440         None => ptr::null(),
1441     }
1442 }
1443 
1444 #[no_mangle]
Servo_Element_IsDisplayNone(element: &RawGeckoElement) -> bool1445 pub extern "C" fn Servo_Element_IsDisplayNone(element: &RawGeckoElement) -> bool {
1446     let element = GeckoElement(element);
1447     let data = element
1448         .get_data()
1449         .expect("Invoking Servo_Element_IsDisplayNone on unstyled element");
1450 
1451     // This function is hot, so we bypass the AtomicRefCell.
1452     //
1453     // It would be nice to also assert that we're not in the servo traversal,
1454     // but this function is called at various intermediate checkpoints when
1455     // managing the traversal on the Gecko side.
1456     debug_assert!(is_main_thread());
1457     unsafe { &*data.as_ptr() }.styles.is_display_none()
1458 }
1459 
1460 #[no_mangle]
Servo_Element_IsDisplayContents(element: &RawGeckoElement) -> bool1461 pub extern "C" fn Servo_Element_IsDisplayContents(element: &RawGeckoElement) -> bool {
1462     let element = GeckoElement(element);
1463     let data = element
1464         .get_data()
1465         .expect("Invoking Servo_Element_IsDisplayContents on unstyled element");
1466 
1467     debug_assert!(is_main_thread());
1468     unsafe { &*data.as_ptr() }
1469         .styles
1470         .primary()
1471         .get_box()
1472         .clone_display()
1473         .is_contents()
1474 }
1475 
1476 #[no_mangle]
Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGeckoElement) -> bool1477 pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGeckoElement) -> bool {
1478     let element = GeckoElement(element);
1479     let data = element
1480         .borrow_data()
1481         .expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element");
1482     data.flags
1483         .contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
1484 }
1485 
mode_to_origin(mode: SheetParsingMode) -> Origin1486 fn mode_to_origin(mode: SheetParsingMode) -> Origin {
1487     match mode {
1488         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
1489         SheetParsingMode::eUserSheetFeatures => Origin::User,
1490         SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
1491     }
1492 }
1493 
1494 #[no_mangle]
Servo_StyleSheet_Empty( mode: SheetParsingMode, ) -> Strong<RawServoStyleSheetContents>1495 pub extern "C" fn Servo_StyleSheet_Empty(
1496     mode: SheetParsingMode,
1497 ) -> Strong<RawServoStyleSheetContents> {
1498     let global_style_data = &*GLOBAL_STYLE_DATA;
1499     let origin = mode_to_origin(mode);
1500     let shared_lock = &global_style_data.shared_lock;
1501     Arc::new(StylesheetContents::from_str(
1502         "",
1503         unsafe { dummy_url_data() }.clone(),
1504         origin,
1505         shared_lock,
1506         /* loader = */ None,
1507         None,
1508         QuirksMode::NoQuirks,
1509         0,
1510         /* use_counters = */ None,
1511         AllowImportRules::Yes,
1512         /* sanitization_data = */ None,
1513     ))
1514     .into_strong()
1515 }
1516 
1517 /// Note: The load_data corresponds to this sheet, and is passed as the parent
1518 /// load data for child sheet loads. It may be null for certain cases where we
1519 /// know we won't have child loads.
1520 #[no_mangle]
Servo_StyleSheet_FromUTF8Bytes( loader: *mut Loader, stylesheet: *mut DomStyleSheet, load_data: *mut SheetLoadData, bytes: &nsACString, mode: SheetParsingMode, extra_data: *mut URLExtraData, line_number_offset: u32, quirks_mode: nsCompatibility, reusable_sheets: *mut LoaderReusableStyleSheets, use_counters: Option<&UseCounters>, allow_import_rules: AllowImportRules, sanitization_kind: SanitizationKind, sanitized_output: Option<&mut nsAString>, ) -> Strong<RawServoStyleSheetContents>1521 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8Bytes(
1522     loader: *mut Loader,
1523     stylesheet: *mut DomStyleSheet,
1524     load_data: *mut SheetLoadData,
1525     bytes: &nsACString,
1526     mode: SheetParsingMode,
1527     extra_data: *mut URLExtraData,
1528     line_number_offset: u32,
1529     quirks_mode: nsCompatibility,
1530     reusable_sheets: *mut LoaderReusableStyleSheets,
1531     use_counters: Option<&UseCounters>,
1532     allow_import_rules: AllowImportRules,
1533     sanitization_kind: SanitizationKind,
1534     sanitized_output: Option<&mut nsAString>,
1535 ) -> Strong<RawServoStyleSheetContents> {
1536     let global_style_data = &*GLOBAL_STYLE_DATA;
1537     let input = bytes.as_str_unchecked();
1538 
1539     let reporter = ErrorReporter::new(stylesheet, loader, extra_data);
1540     let url_data = UrlExtraData::from_ptr_ref(&extra_data);
1541     let loader = if loader.is_null() {
1542         None
1543     } else {
1544         debug_assert!(
1545             sanitized_output.is_none(),
1546             "Shouldn't trigger @import loads for sanitization",
1547         );
1548         Some(StylesheetLoader::new(
1549             loader,
1550             stylesheet,
1551             load_data,
1552             reusable_sheets,
1553         ))
1554     };
1555 
1556     // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
1557     let loader: Option<&dyn StyleStylesheetLoader> = match loader {
1558         None => None,
1559         Some(ref s) => Some(s),
1560     };
1561 
1562     let mut sanitization_data = SanitizationData::new(sanitization_kind);
1563 
1564     let contents = Arc::new(StylesheetContents::from_str(
1565         input,
1566         url_data.clone(),
1567         mode_to_origin(mode),
1568         &global_style_data.shared_lock,
1569         loader,
1570         reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
1571         quirks_mode.into(),
1572         line_number_offset,
1573         use_counters,
1574         allow_import_rules,
1575         sanitization_data.as_mut(),
1576     ));
1577 
1578     if let Some(data) = sanitization_data {
1579         sanitized_output.unwrap().assign_utf8(data.take().as_bytes());
1580     }
1581 
1582     contents.into_strong()
1583 }
1584 
1585 #[no_mangle]
Servo_StyleSheet_FromUTF8BytesAsync( load_data: *mut SheetLoadDataHolder, extra_data: *mut URLExtraData, bytes: &nsACString, mode: SheetParsingMode, line_number_offset: u32, quirks_mode: nsCompatibility, should_record_use_counters: bool, allow_import_rules: AllowImportRules, )1586 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
1587     load_data: *mut SheetLoadDataHolder,
1588     extra_data: *mut URLExtraData,
1589     bytes: &nsACString,
1590     mode: SheetParsingMode,
1591     line_number_offset: u32,
1592     quirks_mode: nsCompatibility,
1593     should_record_use_counters: bool,
1594     allow_import_rules: AllowImportRules,
1595 ) {
1596     let load_data = RefPtr::new(load_data);
1597     let extra_data = UrlExtraData::new(extra_data);
1598 
1599     let mut sheet_bytes = nsCString::new();
1600     sheet_bytes.assign(bytes);
1601 
1602     let async_parser = AsyncStylesheetParser::new(
1603         load_data,
1604         extra_data,
1605         sheet_bytes,
1606         mode_to_origin(mode),
1607         quirks_mode.into(),
1608         line_number_offset,
1609         should_record_use_counters,
1610         allow_import_rules,
1611     );
1612 
1613     if let Some(thread_pool) = STYLE_THREAD_POOL.pool().as_ref() {
1614         thread_pool.spawn(|| {
1615             profiler_label!(Parse);
1616             async_parser.parse();
1617         });
1618     } else {
1619         async_parser.parse();
1620     }
1621 }
1622 
1623 #[no_mangle]
Servo_ShutdownThreadPool()1624 pub unsafe extern "C" fn Servo_ShutdownThreadPool() {
1625     debug_assert!(is_main_thread() && !is_in_servo_traversal());
1626     StyleThreadPool::shutdown();
1627 }
1628 
1629 #[no_mangle]
Servo_StyleSheet_FromSharedData( extra_data: *mut URLExtraData, shared_rules: &ServoCssRules, ) -> Strong<RawServoStyleSheetContents>1630 pub unsafe extern "C" fn Servo_StyleSheet_FromSharedData(
1631     extra_data: *mut URLExtraData,
1632     shared_rules: &ServoCssRules,
1633 ) -> Strong<RawServoStyleSheetContents> {
1634     let shared_rules = Locked::<CssRules>::as_arc(&shared_rules);
1635     Arc::new(StylesheetContents::from_shared_data(
1636         shared_rules.clone_arc(),
1637         Origin::UserAgent,
1638         UrlExtraData::new(extra_data),
1639         QuirksMode::NoQuirks,
1640     ))
1641     .into_strong()
1642 }
1643 
1644 #[no_mangle]
Servo_StyleSet_AppendStyleSheet( raw_data: &RawServoStyleSet, sheet: *const DomStyleSheet, )1645 pub extern "C" fn Servo_StyleSet_AppendStyleSheet(
1646     raw_data: &RawServoStyleSet,
1647     sheet: *const DomStyleSheet,
1648 ) {
1649     let global_style_data = &*GLOBAL_STYLE_DATA;
1650     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1651     let data = &mut *data;
1652     let guard = global_style_data.shared_lock.read();
1653     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1654     data.stylist.append_stylesheet(sheet, &guard);
1655 }
1656 
1657 #[no_mangle]
Servo_AuthorStyles_Create() -> Owned<RawServoAuthorStyles>1658 pub extern "C" fn Servo_AuthorStyles_Create() -> Owned<RawServoAuthorStyles> {
1659     Box::new(AuthorStyles::<GeckoStyleSheet>::new()).into_ffi()
1660 }
1661 
1662 #[no_mangle]
Servo_AuthorStyles_Drop(styles: *mut RawServoAuthorStyles)1663 pub unsafe extern "C" fn Servo_AuthorStyles_Drop(styles: *mut RawServoAuthorStyles) {
1664     AuthorStyles::drop_ffi(styles)
1665 }
1666 
1667 #[no_mangle]
Servo_AuthorStyles_AppendStyleSheet( styles: &mut RawServoAuthorStyles, sheet: *const DomStyleSheet, )1668 pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet(
1669     styles: &mut RawServoAuthorStyles,
1670     sheet: *const DomStyleSheet,
1671 ) {
1672     let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
1673 
1674     let global_style_data = &*GLOBAL_STYLE_DATA;
1675     let guard = global_style_data.shared_lock.read();
1676     let sheet = GeckoStyleSheet::new(sheet);
1677     styles.stylesheets.append_stylesheet(None, sheet, &guard);
1678 }
1679 
1680 #[no_mangle]
Servo_AuthorStyles_InsertStyleSheetBefore( styles: &mut RawServoAuthorStyles, sheet: *const DomStyleSheet, before_sheet: *const DomStyleSheet, )1681 pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore(
1682     styles: &mut RawServoAuthorStyles,
1683     sheet: *const DomStyleSheet,
1684     before_sheet: *const DomStyleSheet,
1685 ) {
1686     let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
1687 
1688     let global_style_data = &*GLOBAL_STYLE_DATA;
1689     let guard = global_style_data.shared_lock.read();
1690     styles.stylesheets.insert_stylesheet_before(
1691         None,
1692         GeckoStyleSheet::new(sheet),
1693         GeckoStyleSheet::new(before_sheet),
1694         &guard,
1695     );
1696 }
1697 
1698 #[no_mangle]
Servo_AuthorStyles_RemoveStyleSheet( styles: &mut RawServoAuthorStyles, sheet: *const DomStyleSheet, )1699 pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet(
1700     styles: &mut RawServoAuthorStyles,
1701     sheet: *const DomStyleSheet,
1702 ) {
1703     let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
1704 
1705     let global_style_data = &*GLOBAL_STYLE_DATA;
1706     let guard = global_style_data.shared_lock.read();
1707     styles
1708         .stylesheets
1709         .remove_stylesheet(None, GeckoStyleSheet::new(sheet), &guard);
1710 }
1711 
1712 #[no_mangle]
Servo_AuthorStyles_ForceDirty(styles: &mut RawServoAuthorStyles)1713 pub unsafe extern "C" fn Servo_AuthorStyles_ForceDirty(styles: &mut RawServoAuthorStyles) {
1714     let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
1715     styles.stylesheets.force_dirty();
1716 }
1717 
1718 #[no_mangle]
Servo_AuthorStyles_IsDirty(styles: &RawServoAuthorStyles) -> bool1719 pub unsafe extern "C" fn Servo_AuthorStyles_IsDirty(styles: &RawServoAuthorStyles) -> bool {
1720     let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(styles);
1721     styles.stylesheets.dirty()
1722 }
1723 
1724 #[no_mangle]
Servo_AuthorStyles_Flush( styles: &mut RawServoAuthorStyles, document_set: &RawServoStyleSet, )1725 pub unsafe extern "C" fn Servo_AuthorStyles_Flush(
1726     styles: &mut RawServoAuthorStyles,
1727     document_set: &RawServoStyleSet,
1728 ) {
1729     let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
1730     // Try to avoid the atomic borrow below if possible.
1731     if !styles.stylesheets.dirty() {
1732         return;
1733     }
1734 
1735     let global_style_data = &*GLOBAL_STYLE_DATA;
1736     let guard = global_style_data.shared_lock.read();
1737 
1738     let document_data = PerDocumentStyleData::from_ffi(document_set).borrow();
1739 
1740     let stylist = &document_data.stylist;
1741 
1742     // TODO(emilio): This is going to need an element or something to do proper
1743     // invalidation in Shadow roots.
1744     styles.flush::<GeckoElement>(stylist.device(), stylist.quirks_mode(), &guard);
1745 }
1746 
1747 #[no_mangle]
Servo_DeclarationBlock_SizeOfIncludingThis( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, declarations: &RawServoDeclarationBlock, ) -> usize1748 pub unsafe extern "C" fn Servo_DeclarationBlock_SizeOfIncludingThis(
1749     malloc_size_of: GeckoMallocSizeOf,
1750     malloc_enclosing_size_of: GeckoMallocSizeOf,
1751     declarations: &RawServoDeclarationBlock,
1752 ) -> usize {
1753     use malloc_size_of::MallocSizeOf;
1754     use malloc_size_of::MallocUnconditionalShallowSizeOf;
1755 
1756     let global_style_data = &*GLOBAL_STYLE_DATA;
1757     let guard = global_style_data.shared_lock.read();
1758 
1759     let mut ops = MallocSizeOfOps::new(
1760         malloc_size_of.unwrap(),
1761         Some(malloc_enclosing_size_of.unwrap()),
1762         None,
1763     );
1764 
1765     Locked::<PropertyDeclarationBlock>::as_arc(&declarations).with_arc(|declarations| {
1766         let mut n = 0;
1767         n += declarations.unconditional_shallow_size_of(&mut ops);
1768         n += declarations.read_with(&guard).size_of(&mut ops);
1769         n
1770     })
1771 }
1772 
1773 #[no_mangle]
Servo_AuthorStyles_SizeOfIncludingThis( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, styles: &RawServoAuthorStyles, ) -> usize1774 pub unsafe extern "C" fn Servo_AuthorStyles_SizeOfIncludingThis(
1775     malloc_size_of: GeckoMallocSizeOf,
1776     malloc_enclosing_size_of: GeckoMallocSizeOf,
1777     styles: &RawServoAuthorStyles,
1778 ) -> usize {
1779     // We cannot `use` MallocSizeOf at the top level, otherwise the compiler
1780     // would complain in `Servo_StyleSheet_SizeOfIncludingThis` for `size_of`
1781     // there.
1782     use malloc_size_of::MallocSizeOf;
1783     let malloc_size_of = malloc_size_of.unwrap();
1784     let malloc_size_of_this =
1785         malloc_size_of(styles as *const RawServoAuthorStyles as *const c_void);
1786 
1787     let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(styles);
1788     let mut ops = MallocSizeOfOps::new(
1789         malloc_size_of,
1790         Some(malloc_enclosing_size_of.unwrap()),
1791         None,
1792     );
1793     malloc_size_of_this + styles.size_of(&mut ops)
1794 }
1795 
1796 #[no_mangle]
Servo_StyleSet_MediumFeaturesChanged( document_set: &RawServoStyleSet, non_document_styles: &mut nsTArray<&mut RawServoAuthorStyles>, may_affect_default_style: bool, ) -> structs::MediumFeaturesChangedResult1797 pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged(
1798     document_set: &RawServoStyleSet,
1799     non_document_styles: &mut nsTArray<&mut RawServoAuthorStyles>,
1800     may_affect_default_style: bool,
1801 ) -> structs::MediumFeaturesChangedResult {
1802     let global_style_data = &*GLOBAL_STYLE_DATA;
1803     let guard = global_style_data.shared_lock.read();
1804 
1805     // NOTE(emilio): We don't actually need to flush the stylist here and ensure
1806     // it's up to date.
1807     //
1808     // In case it isn't we would trigger a rebuild + restyle as needed too.
1809     //
1810     // We need to ensure the default computed values are up to date though,
1811     // because those can influence the result of media query evaluation.
1812     let mut document_data = PerDocumentStyleData::from_ffi(document_set).borrow_mut();
1813 
1814     if may_affect_default_style {
1815         document_data.stylist.device_mut().reset_computed_values();
1816     }
1817     let guards = StylesheetGuards::same(&guard);
1818 
1819     let origins_in_which_rules_changed = document_data
1820         .stylist
1821         .media_features_change_changed_style(&guards, document_data.stylist.device());
1822 
1823     let affects_document_rules = !origins_in_which_rules_changed.is_empty();
1824     if affects_document_rules {
1825         document_data
1826             .stylist
1827             .force_stylesheet_origins_dirty(origins_in_which_rules_changed);
1828     }
1829 
1830     let mut affects_non_document_rules = false;
1831     for author_styles in &mut **non_document_styles {
1832         let author_styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(&mut *author_styles);
1833         let affected_style = author_styles.stylesheets.iter().any(|sheet| {
1834             !author_styles.data.media_feature_affected_matches(
1835                 sheet,
1836                 &guards.author,
1837                 document_data.stylist.device(),
1838                 document_data.stylist.quirks_mode(),
1839             )
1840         });
1841         if affected_style {
1842             affects_non_document_rules = true;
1843             author_styles.stylesheets.force_dirty();
1844         }
1845     }
1846 
1847     let uses_viewport_units = document_data.stylist.device().used_viewport_size();
1848 
1849     structs::MediumFeaturesChangedResult {
1850         mAffectsDocumentRules: affects_document_rules,
1851         mAffectsNonDocumentRules: affects_non_document_rules,
1852         mUsesViewportUnits: uses_viewport_units,
1853     }
1854 }
1855 
1856 #[no_mangle]
Servo_StyleSet_InsertStyleSheetBefore( raw_data: &RawServoStyleSet, sheet: *const DomStyleSheet, before_sheet: *const DomStyleSheet, )1857 pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(
1858     raw_data: &RawServoStyleSet,
1859     sheet: *const DomStyleSheet,
1860     before_sheet: *const DomStyleSheet,
1861 ) {
1862     let global_style_data = &*GLOBAL_STYLE_DATA;
1863     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1864     let data = &mut *data;
1865     let guard = global_style_data.shared_lock.read();
1866     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1867     data.stylist.insert_stylesheet_before(
1868         sheet,
1869         unsafe { GeckoStyleSheet::new(before_sheet) },
1870         &guard,
1871     );
1872 }
1873 
1874 #[no_mangle]
Servo_StyleSet_RemoveStyleSheet( raw_data: &RawServoStyleSet, sheet: *const DomStyleSheet, )1875 pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(
1876     raw_data: &RawServoStyleSet,
1877     sheet: *const DomStyleSheet,
1878 ) {
1879     let global_style_data = &*GLOBAL_STYLE_DATA;
1880     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1881     let data = &mut *data;
1882     let guard = global_style_data.shared_lock.read();
1883     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1884     data.stylist.remove_stylesheet(sheet, &guard);
1885 }
1886 
1887 #[no_mangle]
Servo_StyleSet_GetSheetAt( raw_data: &RawServoStyleSet, origin: Origin, index: usize, ) -> *const DomStyleSheet1888 pub unsafe extern "C" fn Servo_StyleSet_GetSheetAt(
1889     raw_data: &RawServoStyleSet,
1890     origin: Origin,
1891     index: usize,
1892 ) -> *const DomStyleSheet {
1893     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
1894     data.stylist
1895         .sheet_at(origin, index)
1896         .map_or(ptr::null(), |s| s.raw())
1897 }
1898 
1899 #[no_mangle]
Servo_StyleSet_GetSheetCount( raw_data: &RawServoStyleSet, origin: Origin, ) -> usize1900 pub unsafe extern "C" fn Servo_StyleSet_GetSheetCount(
1901     raw_data: &RawServoStyleSet,
1902     origin: Origin,
1903 ) -> usize {
1904     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
1905     data.stylist.sheet_count(origin)
1906 }
1907 
1908 #[no_mangle]
Servo_StyleSet_FlushStyleSheets( raw_data: &RawServoStyleSet, doc_element: Option<&RawGeckoElement>, snapshots: *const ServoElementSnapshotTable, )1909 pub unsafe extern "C" fn Servo_StyleSet_FlushStyleSheets(
1910     raw_data: &RawServoStyleSet,
1911     doc_element: Option<&RawGeckoElement>,
1912     snapshots: *const ServoElementSnapshotTable,
1913 ) {
1914     let global_style_data = &*GLOBAL_STYLE_DATA;
1915     let guard = global_style_data.shared_lock.read();
1916     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1917     let doc_element = doc_element.map(GeckoElement);
1918 
1919     let have_invalidations = data.flush_stylesheets(&guard, doc_element, snapshots.as_ref());
1920 
1921     if have_invalidations && doc_element.is_some() {
1922         // The invalidation machinery propagates the bits up, but we still need
1923         // to tell the Gecko restyle root machinery about it.
1924         bindings::Gecko_NoteDirtySubtreeForInvalidation(doc_element.unwrap().0);
1925     }
1926 }
1927 
1928 #[no_mangle]
Servo_StyleSet_NoteStyleSheetsChanged( raw_data: &RawServoStyleSet, changed_origins: OriginFlags, )1929 pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(
1930     raw_data: &RawServoStyleSet,
1931     changed_origins: OriginFlags,
1932 ) {
1933     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1934     data.stylist
1935         .force_stylesheet_origins_dirty(OriginSet::from(changed_origins));
1936 }
1937 
1938 #[no_mangle]
Servo_StyleSet_SetAuthorStyleDisabled( raw_data: &RawServoStyleSet, author_style_disabled: bool, )1939 pub extern "C" fn Servo_StyleSet_SetAuthorStyleDisabled(
1940     raw_data: &RawServoStyleSet,
1941     author_style_disabled: bool,
1942 ) {
1943     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1944     let enabled = if author_style_disabled {
1945         AuthorStylesEnabled::No
1946     } else {
1947         AuthorStylesEnabled::Yes
1948     };
1949     data.stylist.set_author_styles_enabled(enabled);
1950 }
1951 
1952 #[no_mangle]
Servo_StyleSheet_HasRules(raw_contents: &RawServoStyleSheetContents) -> bool1953 pub extern "C" fn Servo_StyleSheet_HasRules(raw_contents: &RawServoStyleSheetContents) -> bool {
1954     let global_style_data = &*GLOBAL_STYLE_DATA;
1955     let guard = global_style_data.shared_lock.read();
1956     !StylesheetContents::as_arc(&raw_contents)
1957         .rules
1958         .read_with(&guard)
1959         .0
1960         .is_empty()
1961 }
1962 
1963 #[no_mangle]
Servo_StyleSheet_GetRules( sheet: &RawServoStyleSheetContents, ) -> Strong<ServoCssRules>1964 pub extern "C" fn Servo_StyleSheet_GetRules(
1965     sheet: &RawServoStyleSheetContents,
1966 ) -> Strong<ServoCssRules> {
1967     StylesheetContents::as_arc(&sheet)
1968         .rules
1969         .clone()
1970         .into_strong()
1971 }
1972 
1973 #[no_mangle]
Servo_StyleSheet_Clone( raw_sheet: &RawServoStyleSheetContents, reference_sheet: *const DomStyleSheet, ) -> Strong<RawServoStyleSheetContents>1974 pub extern "C" fn Servo_StyleSheet_Clone(
1975     raw_sheet: &RawServoStyleSheetContents,
1976     reference_sheet: *const DomStyleSheet,
1977 ) -> Strong<RawServoStyleSheetContents> {
1978     use style::shared_lock::{DeepCloneParams, DeepCloneWithLock};
1979     let global_style_data = &*GLOBAL_STYLE_DATA;
1980     let guard = global_style_data.shared_lock.read();
1981     let contents = StylesheetContents::as_arc(&raw_sheet);
1982     let params = DeepCloneParams { reference_sheet };
1983 
1984     Arc::new(contents.deep_clone_with_lock(&global_style_data.shared_lock, &guard, &params))
1985         .into_strong()
1986 }
1987 
1988 #[no_mangle]
Servo_StyleSheet_SizeOfIncludingThis( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, sheet: &RawServoStyleSheetContents, ) -> usize1989 pub extern "C" fn Servo_StyleSheet_SizeOfIncludingThis(
1990     malloc_size_of: GeckoMallocSizeOf,
1991     malloc_enclosing_size_of: GeckoMallocSizeOf,
1992     sheet: &RawServoStyleSheetContents,
1993 ) -> usize {
1994     let global_style_data = &*GLOBAL_STYLE_DATA;
1995     let guard = global_style_data.shared_lock.read();
1996     let mut ops = MallocSizeOfOps::new(
1997         malloc_size_of.unwrap(),
1998         Some(malloc_enclosing_size_of.unwrap()),
1999         None,
2000     );
2001     // TODO(emilio): We're not measuring the size of the Arc<StyleSheetContents>
2002     // allocation itself here.
2003     StylesheetContents::as_arc(&sheet).size_of(&guard, &mut ops)
2004 }
2005 
2006 #[no_mangle]
Servo_StyleSheet_GetOrigin(sheet: &RawServoStyleSheetContents) -> Origin2007 pub extern "C" fn Servo_StyleSheet_GetOrigin(sheet: &RawServoStyleSheetContents) -> Origin {
2008     StylesheetContents::as_arc(&sheet).origin
2009 }
2010 
2011 #[no_mangle]
Servo_StyleSheet_GetSourceMapURL( sheet: &RawServoStyleSheetContents, result: &mut nsAString, )2012 pub extern "C" fn Servo_StyleSheet_GetSourceMapURL(
2013     sheet: &RawServoStyleSheetContents,
2014     result: &mut nsAString,
2015 ) {
2016     let contents = StylesheetContents::as_arc(&sheet);
2017     let url_opt = contents.source_map_url.read();
2018     if let Some(ref url) = *url_opt {
2019         write!(result, "{}", url).unwrap();
2020     }
2021 }
2022 
2023 #[no_mangle]
Servo_StyleSheet_GetSourceURL( sheet: &RawServoStyleSheetContents, result: &mut nsAString, )2024 pub extern "C" fn Servo_StyleSheet_GetSourceURL(
2025     sheet: &RawServoStyleSheetContents,
2026     result: &mut nsAString,
2027 ) {
2028     let contents = StylesheetContents::as_arc(&sheet);
2029     let url_opt = contents.source_url.read();
2030     if let Some(ref url) = *url_opt {
2031         write!(result, "{}", url).unwrap();
2032     }
2033 }
2034 
read_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R where Locked<T>: HasArcFFI, F: FnOnce(&T) -> R,2035 fn read_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
2036 where
2037     Locked<T>: HasArcFFI,
2038     F: FnOnce(&T) -> R,
2039 {
2040     let global_style_data = &*GLOBAL_STYLE_DATA;
2041     let guard = global_style_data.shared_lock.read();
2042     func(Locked::<T>::as_arc(&raw).read_with(&guard))
2043 }
2044 
2045 #[cfg(debug_assertions)]
read_locked_arc_unchecked<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R where Locked<T>: HasArcFFI, F: FnOnce(&T) -> R,2046 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
2047 where
2048     Locked<T>: HasArcFFI,
2049     F: FnOnce(&T) -> R,
2050 {
2051     debug_assert!(is_main_thread() && !is_in_servo_traversal());
2052     read_locked_arc(raw, func)
2053 }
2054 
2055 #[cfg(not(debug_assertions))]
read_locked_arc_unchecked<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R where Locked<T>: HasArcFFI, F: FnOnce(&T) -> R,2056 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
2057 where
2058     Locked<T>: HasArcFFI,
2059     F: FnOnce(&T) -> R,
2060 {
2061     func(Locked::<T>::as_arc(&raw).read_unchecked())
2062 }
2063 
write_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R where Locked<T>: HasArcFFI, F: FnOnce(&mut T) -> R,2064 fn write_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
2065 where
2066     Locked<T>: HasArcFFI,
2067     F: FnOnce(&mut T) -> R,
2068 {
2069     let global_style_data = &*GLOBAL_STYLE_DATA;
2070     let mut guard = global_style_data.shared_lock.write();
2071     func(Locked::<T>::as_arc(&raw).write_with(&mut guard))
2072 }
2073 
2074 #[no_mangle]
Servo_CssRules_ListTypes(rules: &ServoCssRules, result: &mut nsTArray<usize>)2075 pub extern "C" fn Servo_CssRules_ListTypes(rules: &ServoCssRules, result: &mut nsTArray<usize>) {
2076     read_locked_arc(rules, |rules: &CssRules| {
2077         result.assign_from_iter_pod(rules.0.iter().map(|rule| rule.rule_type() as usize));
2078     })
2079 }
2080 
2081 #[no_mangle]
Servo_CssRules_InsertRule( rules: &ServoCssRules, contents: &RawServoStyleSheetContents, rule: &nsACString, index: u32, nested: bool, loader: *mut Loader, allow_import_rules: AllowImportRules, gecko_stylesheet: *mut DomStyleSheet, rule_type: *mut u16, ) -> nsresult2082 pub extern "C" fn Servo_CssRules_InsertRule(
2083     rules: &ServoCssRules,
2084     contents: &RawServoStyleSheetContents,
2085     rule: &nsACString,
2086     index: u32,
2087     nested: bool,
2088     loader: *mut Loader,
2089     allow_import_rules: AllowImportRules,
2090     gecko_stylesheet: *mut DomStyleSheet,
2091     rule_type: *mut u16,
2092 ) -> nsresult {
2093     let loader = if loader.is_null() {
2094         None
2095     } else {
2096         Some(StylesheetLoader::new(
2097             loader,
2098             gecko_stylesheet,
2099             ptr::null_mut(),
2100             ptr::null_mut(),
2101         ))
2102     };
2103     let loader = loader
2104         .as_ref()
2105         .map(|loader| loader as &dyn StyleStylesheetLoader);
2106     let rule = unsafe { rule.as_str_unchecked() };
2107 
2108     let global_style_data = &*GLOBAL_STYLE_DATA;
2109     let contents = StylesheetContents::as_arc(&contents);
2110     let result = Locked::<CssRules>::as_arc(&rules).insert_rule(
2111         &global_style_data.shared_lock,
2112         rule,
2113         contents,
2114         index as usize,
2115         nested,
2116         loader,
2117         allow_import_rules,
2118     );
2119 
2120     match result {
2121         Ok(new_rule) => {
2122             *unsafe { rule_type.as_mut().unwrap() } = new_rule.rule_type() as u16;
2123             nsresult::NS_OK
2124         },
2125         Err(err) => err.into(),
2126     }
2127 }
2128 
2129 #[no_mangle]
Servo_CssRules_DeleteRule(rules: &ServoCssRules, index: u32) -> nsresult2130 pub extern "C" fn Servo_CssRules_DeleteRule(rules: &ServoCssRules, index: u32) -> nsresult {
2131     write_locked_arc(rules, |rules: &mut CssRules| {
2132         match rules.remove_rule(index as usize) {
2133             Ok(_) => nsresult::NS_OK,
2134             Err(err) => err.into(),
2135         }
2136     })
2137 }
2138 
2139 macro_rules! impl_basic_rule_funcs_without_getter {
2140     { ($rule_type:ty, $raw_type:ty),
2141         debug: $debug:ident,
2142         to_css: $to_css:ident,
2143     } => {
2144         #[cfg(debug_assertions)]
2145         #[no_mangle]
2146         pub extern "C" fn $debug(rule: &$raw_type, result: *mut nsACString) {
2147             read_locked_arc(rule, |rule: &$rule_type| {
2148                 write!(unsafe { result.as_mut().unwrap() }, "{:?}", *rule).unwrap();
2149             })
2150         }
2151 
2152         #[cfg(not(debug_assertions))]
2153         #[no_mangle]
2154         pub extern "C" fn $debug(_: &$raw_type, _: *mut nsACString) {
2155             unreachable!()
2156         }
2157 
2158         #[no_mangle]
2159         pub extern "C" fn $to_css(rule: &$raw_type, result: &mut nsAString) {
2160             let global_style_data = &*GLOBAL_STYLE_DATA;
2161             let guard = global_style_data.shared_lock.read();
2162             let rule = Locked::<$rule_type>::as_arc(&rule);
2163             rule.read_with(&guard).to_css(&guard, result).unwrap();
2164         }
2165     }
2166 }
2167 
2168 macro_rules! impl_basic_rule_funcs {
2169     { ($name:ident, $rule_type:ty, $raw_type:ty),
2170         getter: $getter:ident,
2171         debug: $debug:ident,
2172         to_css: $to_css:ident,
2173     } => {
2174         #[no_mangle]
2175         pub extern "C" fn $getter(
2176             rules: &ServoCssRules,
2177             index: u32,
2178             line: *mut u32,
2179             column: *mut u32,
2180         ) -> Strong<$raw_type> {
2181             let global_style_data = &*GLOBAL_STYLE_DATA;
2182             let guard = global_style_data.shared_lock.read();
2183             let rules = Locked::<CssRules>::as_arc(&rules).read_with(&guard);
2184             let index = index as usize;
2185 
2186             if index >= rules.0.len() {
2187                 return Strong::null();
2188             }
2189 
2190             match rules.0[index] {
2191                 CssRule::$name(ref rule) => {
2192                     let location = rule.read_with(&guard).source_location;
2193                     *unsafe { line.as_mut().unwrap() } = location.line as u32;
2194                     *unsafe { column.as_mut().unwrap() } = location.column as u32;
2195                     rule.clone().into_strong()
2196                 },
2197                 _ => {
2198                     Strong::null()
2199                 }
2200             }
2201         }
2202 
2203         impl_basic_rule_funcs_without_getter! { ($rule_type, $raw_type),
2204             debug: $debug,
2205             to_css: $to_css,
2206         }
2207     }
2208 }
2209 
2210 macro_rules! impl_group_rule_funcs {
2211     { ($name:ident, $rule_type:ty, $raw_type:ty),
2212       get_rules: $get_rules:ident,
2213       $($basic:tt)+
2214     } => {
2215         impl_basic_rule_funcs! { ($name, $rule_type, $raw_type), $($basic)+ }
2216 
2217         #[no_mangle]
2218         pub extern "C" fn $get_rules(rule: &$raw_type) -> Strong<ServoCssRules> {
2219             read_locked_arc(rule, |rule: &$rule_type| {
2220                 rule.rules.clone().into_strong()
2221             })
2222         }
2223     }
2224 }
2225 
2226 impl_basic_rule_funcs! { (Style, StyleRule, RawServoStyleRule),
2227     getter: Servo_CssRules_GetStyleRuleAt,
2228     debug: Servo_StyleRule_Debug,
2229     to_css: Servo_StyleRule_GetCssText,
2230 }
2231 
2232 impl_basic_rule_funcs! { (Import, ImportRule, RawServoImportRule),
2233     getter: Servo_CssRules_GetImportRuleAt,
2234     debug: Servo_ImportRule_Debug,
2235     to_css: Servo_ImportRule_GetCssText,
2236 }
2237 
2238 impl_basic_rule_funcs_without_getter! { (Keyframe, RawServoKeyframe),
2239     debug: Servo_Keyframe_Debug,
2240     to_css: Servo_Keyframe_GetCssText,
2241 }
2242 
2243 impl_basic_rule_funcs! { (Keyframes, KeyframesRule, RawServoKeyframesRule),
2244     getter: Servo_CssRules_GetKeyframesRuleAt,
2245     debug: Servo_KeyframesRule_Debug,
2246     to_css: Servo_KeyframesRule_GetCssText,
2247 }
2248 
2249 impl_group_rule_funcs! { (Media, MediaRule, RawServoMediaRule),
2250     get_rules: Servo_MediaRule_GetRules,
2251     getter: Servo_CssRules_GetMediaRuleAt,
2252     debug: Servo_MediaRule_Debug,
2253     to_css: Servo_MediaRule_GetCssText,
2254 }
2255 
2256 impl_basic_rule_funcs! { (Namespace, NamespaceRule, RawServoNamespaceRule),
2257     getter: Servo_CssRules_GetNamespaceRuleAt,
2258     debug: Servo_NamespaceRule_Debug,
2259     to_css: Servo_NamespaceRule_GetCssText,
2260 }
2261 
2262 impl_basic_rule_funcs! { (Page, PageRule, RawServoPageRule),
2263     getter: Servo_CssRules_GetPageRuleAt,
2264     debug: Servo_PageRule_Debug,
2265     to_css: Servo_PageRule_GetCssText,
2266 }
2267 
2268 impl_group_rule_funcs! { (Supports, SupportsRule, RawServoSupportsRule),
2269     get_rules: Servo_SupportsRule_GetRules,
2270     getter: Servo_CssRules_GetSupportsRuleAt,
2271     debug: Servo_SupportsRule_Debug,
2272     to_css: Servo_SupportsRule_GetCssText,
2273 }
2274 
2275 impl_group_rule_funcs! { (Document, DocumentRule, RawServoMozDocumentRule),
2276     get_rules: Servo_MozDocumentRule_GetRules,
2277     getter: Servo_CssRules_GetMozDocumentRuleAt,
2278     debug: Servo_MozDocumentRule_Debug,
2279     to_css: Servo_MozDocumentRule_GetCssText,
2280 }
2281 
2282 impl_basic_rule_funcs! { (FontFeatureValues, FontFeatureValuesRule, RawServoFontFeatureValuesRule),
2283     getter: Servo_CssRules_GetFontFeatureValuesRuleAt,
2284     debug: Servo_FontFeatureValuesRule_Debug,
2285     to_css: Servo_FontFeatureValuesRule_GetCssText,
2286 }
2287 
2288 impl_basic_rule_funcs! { (FontFace, FontFaceRule, RawServoFontFaceRule),
2289     getter: Servo_CssRules_GetFontFaceRuleAt,
2290     debug: Servo_FontFaceRule_Debug,
2291     to_css: Servo_FontFaceRule_GetCssText,
2292 }
2293 
2294 impl_basic_rule_funcs! { (CounterStyle, CounterStyleRule, RawServoCounterStyleRule),
2295     getter: Servo_CssRules_GetCounterStyleRuleAt,
2296     debug: Servo_CounterStyleRule_Debug,
2297     to_css: Servo_CounterStyleRule_GetCssText,
2298 }
2299 
2300 #[no_mangle]
Servo_StyleRule_GetStyle( rule: &RawServoStyleRule, ) -> Strong<RawServoDeclarationBlock>2301 pub extern "C" fn Servo_StyleRule_GetStyle(
2302     rule: &RawServoStyleRule,
2303 ) -> Strong<RawServoDeclarationBlock> {
2304     read_locked_arc(rule, |rule: &StyleRule| rule.block.clone().into_strong())
2305 }
2306 
2307 #[no_mangle]
Servo_StyleRule_SetStyle( rule: &RawServoStyleRule, declarations: &RawServoDeclarationBlock, )2308 pub extern "C" fn Servo_StyleRule_SetStyle(
2309     rule: &RawServoStyleRule,
2310     declarations: &RawServoDeclarationBlock,
2311 ) {
2312     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
2313     write_locked_arc(rule, |rule: &mut StyleRule| {
2314         rule.block = declarations.clone_arc();
2315     })
2316 }
2317 
2318 #[no_mangle]
Servo_StyleRule_GetSelectorText( rule: &RawServoStyleRule, result: &mut nsAString, )2319 pub extern "C" fn Servo_StyleRule_GetSelectorText(
2320     rule: &RawServoStyleRule,
2321     result: &mut nsAString,
2322 ) {
2323     read_locked_arc(rule, |rule: &StyleRule| {
2324         rule.selectors.to_css(result).unwrap();
2325     })
2326 }
2327 
2328 #[no_mangle]
Servo_StyleRule_GetSelectorTextAtIndex( rule: &RawServoStyleRule, index: u32, result: &mut nsAString, )2329 pub extern "C" fn Servo_StyleRule_GetSelectorTextAtIndex(
2330     rule: &RawServoStyleRule,
2331     index: u32,
2332     result: &mut nsAString,
2333 ) {
2334     read_locked_arc(rule, |rule: &StyleRule| {
2335         let index = index as usize;
2336         if index >= rule.selectors.0.len() {
2337             return;
2338         }
2339         rule.selectors.0[index].to_css(result).unwrap();
2340     })
2341 }
2342 
2343 #[no_mangle]
Servo_StyleRule_GetSelectorCount(rule: &RawServoStyleRule, count: *mut u32)2344 pub extern "C" fn Servo_StyleRule_GetSelectorCount(rule: &RawServoStyleRule, count: *mut u32) {
2345     read_locked_arc(rule, |rule: &StyleRule| {
2346         *unsafe { count.as_mut().unwrap() } = rule.selectors.0.len() as u32;
2347     })
2348 }
2349 
2350 #[no_mangle]
Servo_StyleRule_GetSpecificityAtIndex( rule: &RawServoStyleRule, index: u32, specificity: *mut u64, )2351 pub extern "C" fn Servo_StyleRule_GetSpecificityAtIndex(
2352     rule: &RawServoStyleRule,
2353     index: u32,
2354     specificity: *mut u64,
2355 ) {
2356     read_locked_arc(rule, |rule: &StyleRule| {
2357         let specificity = unsafe { specificity.as_mut().unwrap() };
2358         let index = index as usize;
2359         if index >= rule.selectors.0.len() {
2360             *specificity = 0;
2361             return;
2362         }
2363         *specificity = rule.selectors.0[index].specificity() as u64;
2364     })
2365 }
2366 
2367 #[no_mangle]
Servo_StyleRule_SelectorMatchesElement( rule: &RawServoStyleRule, element: &RawGeckoElement, index: u32, pseudo_type: PseudoStyleType, relevant_link_visited: bool, ) -> bool2368 pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(
2369     rule: &RawServoStyleRule,
2370     element: &RawGeckoElement,
2371     index: u32,
2372     pseudo_type: PseudoStyleType,
2373     relevant_link_visited: bool,
2374 ) -> bool {
2375     read_locked_arc(rule, |rule: &StyleRule| {
2376         let index = index as usize;
2377         if index >= rule.selectors.0.len() {
2378             return false;
2379         }
2380 
2381         let selector = &rule.selectors.0[index];
2382         let mut matching_mode = MatchingMode::Normal;
2383 
2384         match PseudoElement::from_pseudo_type(pseudo_type) {
2385             Some(pseudo) => {
2386                 // We need to make sure that the requested pseudo element type
2387                 // matches the selector pseudo element type before proceeding.
2388                 match selector.pseudo_element() {
2389                     Some(selector_pseudo) if *selector_pseudo == pseudo => {
2390                         matching_mode = MatchingMode::ForStatelessPseudoElement
2391                     },
2392                     _ => return false,
2393                 };
2394             },
2395             None => {
2396                 // Do not attempt to match if a pseudo element is requested and
2397                 // this is not a pseudo element selector, or vice versa.
2398                 if selector.has_pseudo_element() {
2399                     return false;
2400                 }
2401             },
2402         };
2403 
2404         let element = GeckoElement(element);
2405         let quirks_mode = element.as_node().owner_doc().quirks_mode();
2406         let visited_mode =
2407             if relevant_link_visited {
2408                 VisitedHandlingMode::RelevantLinkVisited
2409             } else {
2410                 VisitedHandlingMode::AllLinksUnvisited
2411             };
2412         let mut ctx =
2413             MatchingContext::new_for_visited(matching_mode, None, None, visited_mode, quirks_mode);
2414         matches_selector(selector, 0, None, &element, &mut ctx, &mut |_, _| {})
2415     })
2416 }
2417 
2418 #[no_mangle]
Servo_StyleRule_SetSelectorText( sheet: &RawServoStyleSheetContents, rule: &RawServoStyleRule, text: &nsAString, ) -> bool2419 pub extern "C" fn Servo_StyleRule_SetSelectorText(
2420     sheet: &RawServoStyleSheetContents,
2421     rule: &RawServoStyleRule,
2422     text: &nsAString,
2423 ) -> bool {
2424     let value_str = text.to_string();
2425 
2426     write_locked_arc(rule, |rule: &mut StyleRule| {
2427         use style::selector_parser::SelectorParser;
2428 
2429         let contents = StylesheetContents::as_arc(&sheet);
2430         let namespaces = contents.namespaces.read();
2431         let url_data = contents.url_data.read();
2432         let parser = SelectorParser {
2433             stylesheet_origin: contents.origin,
2434             namespaces: &namespaces,
2435             url_data: Some(&url_data),
2436         };
2437 
2438         let mut parser_input = ParserInput::new(&value_str);
2439         match SelectorList::parse(&parser, &mut Parser::new(&mut parser_input)) {
2440             Ok(selectors) => {
2441                 rule.selectors = selectors;
2442                 true
2443             },
2444             Err(_) => false,
2445         }
2446     })
2447 }
2448 
2449 #[no_mangle]
Servo_SelectorList_Closest( element: &RawGeckoElement, selectors: &RawServoSelectorList, ) -> *const RawGeckoElement2450 pub unsafe extern "C" fn Servo_SelectorList_Closest(
2451     element: &RawGeckoElement,
2452     selectors: &RawServoSelectorList,
2453 ) -> *const RawGeckoElement {
2454     use std::borrow::Borrow;
2455     use style::dom_apis;
2456 
2457     let element = GeckoElement(element);
2458     let quirks_mode = element.as_node().owner_doc().quirks_mode();
2459     let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
2460 
2461     dom_apis::element_closest(element, &selectors, quirks_mode).map_or(ptr::null(), |e| e.0)
2462 }
2463 
2464 #[no_mangle]
Servo_SelectorList_Matches( element: &RawGeckoElement, selectors: &RawServoSelectorList, ) -> bool2465 pub unsafe extern "C" fn Servo_SelectorList_Matches(
2466     element: &RawGeckoElement,
2467     selectors: &RawServoSelectorList,
2468 ) -> bool {
2469     use std::borrow::Borrow;
2470     use style::dom_apis;
2471 
2472     let element = GeckoElement(element);
2473     let quirks_mode = element.as_node().owner_doc().quirks_mode();
2474     let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
2475     dom_apis::element_matches(&element, &selectors, quirks_mode)
2476 }
2477 
2478 #[no_mangle]
Servo_SelectorList_QueryFirst( node: &RawGeckoNode, selectors: &RawServoSelectorList, may_use_invalidation: bool, ) -> *const RawGeckoElement2479 pub unsafe extern "C" fn Servo_SelectorList_QueryFirst(
2480     node: &RawGeckoNode,
2481     selectors: &RawServoSelectorList,
2482     may_use_invalidation: bool,
2483 ) -> *const RawGeckoElement {
2484     use std::borrow::Borrow;
2485     use style::dom_apis::{self, MayUseInvalidation, QueryFirst};
2486 
2487     let node = GeckoNode(node);
2488     let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
2489     let mut result = None;
2490 
2491     let may_use_invalidation = if may_use_invalidation {
2492         MayUseInvalidation::Yes
2493     } else {
2494         MayUseInvalidation::No
2495     };
2496 
2497     dom_apis::query_selector::<GeckoElement, QueryFirst>(
2498         node,
2499         &selectors,
2500         &mut result,
2501         may_use_invalidation,
2502     );
2503 
2504     result.map_or(ptr::null(), |e| e.0)
2505 }
2506 
2507 #[no_mangle]
Servo_SelectorList_QueryAll( node: &RawGeckoNode, selectors: &RawServoSelectorList, content_list: *mut structs::nsSimpleContentList, may_use_invalidation: bool, )2508 pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
2509     node: &RawGeckoNode,
2510     selectors: &RawServoSelectorList,
2511     content_list: *mut structs::nsSimpleContentList,
2512     may_use_invalidation: bool,
2513 ) {
2514     use std::borrow::Borrow;
2515     use style::dom_apis::{self, MayUseInvalidation, QueryAll};
2516 
2517     let node = GeckoNode(node);
2518     let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
2519     let mut result = SmallVec::new();
2520 
2521     let may_use_invalidation = if may_use_invalidation {
2522         MayUseInvalidation::Yes
2523     } else {
2524         MayUseInvalidation::No
2525     };
2526 
2527     dom_apis::query_selector::<GeckoElement, QueryAll>(
2528         node,
2529         &selectors,
2530         &mut result,
2531         may_use_invalidation,
2532     );
2533 
2534     if !result.is_empty() {
2535         // NOTE(emilio): This relies on a slice of GeckoElement having the same
2536         // memory representation than a slice of element pointers.
2537         bindings::Gecko_ContentList_AppendAll(
2538             content_list,
2539             result.as_ptr() as *mut *const _,
2540             result.len(),
2541         )
2542     }
2543 }
2544 
2545 #[no_mangle]
Servo_ImportRule_GetHref(rule: &RawServoImportRule, result: &mut nsAString)2546 pub extern "C" fn Servo_ImportRule_GetHref(rule: &RawServoImportRule, result: &mut nsAString) {
2547     read_locked_arc(rule, |rule: &ImportRule| {
2548         write!(result, "{}", rule.url.as_str()).unwrap();
2549     })
2550 }
2551 
2552 #[no_mangle]
Servo_ImportRule_GetSheet(rule: &RawServoImportRule) -> *const DomStyleSheet2553 pub extern "C" fn Servo_ImportRule_GetSheet(rule: &RawServoImportRule) -> *const DomStyleSheet {
2554     read_locked_arc(rule, |rule: &ImportRule| {
2555         rule.stylesheet.as_sheet().unwrap().raw() as *const DomStyleSheet
2556     })
2557 }
2558 
2559 #[no_mangle]
Servo_ImportRule_SetSheet(rule: &RawServoImportRule, sheet: *mut DomStyleSheet)2560 pub extern "C" fn Servo_ImportRule_SetSheet(rule: &RawServoImportRule, sheet: *mut DomStyleSheet) {
2561     write_locked_arc(rule, |rule: &mut ImportRule| {
2562         let sheet = unsafe { GeckoStyleSheet::new(sheet) };
2563         rule.stylesheet = ImportSheet::new(sheet);
2564     })
2565 }
2566 
2567 #[no_mangle]
Servo_Keyframe_GetKeyText(keyframe: &RawServoKeyframe, result: &mut nsAString)2568 pub extern "C" fn Servo_Keyframe_GetKeyText(keyframe: &RawServoKeyframe, result: &mut nsAString) {
2569     read_locked_arc(keyframe, |keyframe: &Keyframe| {
2570         keyframe.selector.to_css(&mut CssWriter::new(result)).unwrap()
2571     })
2572 }
2573 
2574 #[no_mangle]
Servo_Keyframe_SetKeyText( keyframe: &RawServoKeyframe, text: &nsACString, ) -> bool2575 pub extern "C" fn Servo_Keyframe_SetKeyText(
2576     keyframe: &RawServoKeyframe,
2577     text: &nsACString,
2578 ) -> bool {
2579     let text = unsafe { text.as_str_unchecked() };
2580     let mut input = ParserInput::new(&text);
2581     if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
2582         write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2583             keyframe.selector = selector;
2584         });
2585         true
2586     } else {
2587         false
2588     }
2589 }
2590 
2591 #[no_mangle]
Servo_Keyframe_GetStyle( keyframe: &RawServoKeyframe, ) -> Strong<RawServoDeclarationBlock>2592 pub extern "C" fn Servo_Keyframe_GetStyle(
2593     keyframe: &RawServoKeyframe,
2594 ) -> Strong<RawServoDeclarationBlock> {
2595     read_locked_arc(keyframe, |keyframe: &Keyframe| {
2596         keyframe.block.clone().into_strong()
2597     })
2598 }
2599 
2600 #[no_mangle]
Servo_Keyframe_SetStyle( keyframe: &RawServoKeyframe, declarations: &RawServoDeclarationBlock, )2601 pub extern "C" fn Servo_Keyframe_SetStyle(
2602     keyframe: &RawServoKeyframe,
2603     declarations: &RawServoDeclarationBlock,
2604 ) {
2605     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
2606     write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2607         keyframe.block = declarations.clone_arc();
2608     })
2609 }
2610 
2611 #[no_mangle]
Servo_KeyframesRule_GetName(rule: &RawServoKeyframesRule) -> *mut nsAtom2612 pub extern "C" fn Servo_KeyframesRule_GetName(rule: &RawServoKeyframesRule) -> *mut nsAtom {
2613     read_locked_arc(rule, |rule: &KeyframesRule| rule.name.as_atom().as_ptr())
2614 }
2615 
2616 #[no_mangle]
Servo_KeyframesRule_SetName( rule: &RawServoKeyframesRule, name: *mut nsAtom, )2617 pub unsafe extern "C" fn Servo_KeyframesRule_SetName(
2618     rule: &RawServoKeyframesRule,
2619     name: *mut nsAtom,
2620 ) {
2621     write_locked_arc(rule, |rule: &mut KeyframesRule| {
2622         rule.name = KeyframesName::Ident(CustomIdent(Atom::from_addrefed(name)));
2623     })
2624 }
2625 
2626 #[no_mangle]
Servo_KeyframesRule_GetCount(rule: &RawServoKeyframesRule) -> u322627 pub extern "C" fn Servo_KeyframesRule_GetCount(rule: &RawServoKeyframesRule) -> u32 {
2628     read_locked_arc(rule, |rule: &KeyframesRule| rule.keyframes.len() as u32)
2629 }
2630 
2631 #[no_mangle]
Servo_KeyframesRule_GetKeyframeAt( rule: &RawServoKeyframesRule, index: u32, line: *mut u32, column: *mut u32, ) -> Strong<RawServoKeyframe>2632 pub extern "C" fn Servo_KeyframesRule_GetKeyframeAt(
2633     rule: &RawServoKeyframesRule,
2634     index: u32,
2635     line: *mut u32,
2636     column: *mut u32,
2637 ) -> Strong<RawServoKeyframe> {
2638     let global_style_data = &*GLOBAL_STYLE_DATA;
2639     let guard = global_style_data.shared_lock.read();
2640     let key = Locked::<KeyframesRule>::as_arc(&rule)
2641         .read_with(&guard)
2642         .keyframes[index as usize]
2643         .clone();
2644     let location = key.read_with(&guard).source_location;
2645     *unsafe { line.as_mut().unwrap() } = location.line as u32;
2646     *unsafe { column.as_mut().unwrap() } = location.column as u32;
2647     key.into_strong()
2648 }
2649 
2650 #[no_mangle]
Servo_KeyframesRule_FindRule( rule: &RawServoKeyframesRule, key: &nsACString, ) -> u322651 pub extern "C" fn Servo_KeyframesRule_FindRule(
2652     rule: &RawServoKeyframesRule,
2653     key: &nsACString,
2654 ) -> u32 {
2655     let key = unsafe { key.as_str_unchecked() };
2656     let global_style_data = &*GLOBAL_STYLE_DATA;
2657     let guard = global_style_data.shared_lock.read();
2658     Locked::<KeyframesRule>::as_arc(&rule)
2659         .read_with(&guard)
2660         .find_rule(&guard, key)
2661         .map(|index| index as u32)
2662         .unwrap_or(u32::max_value())
2663 }
2664 
2665 #[no_mangle]
Servo_KeyframesRule_AppendRule( rule: &RawServoKeyframesRule, contents: &RawServoStyleSheetContents, css: &nsACString, ) -> bool2666 pub extern "C" fn Servo_KeyframesRule_AppendRule(
2667     rule: &RawServoKeyframesRule,
2668     contents: &RawServoStyleSheetContents,
2669     css: &nsACString,
2670 ) -> bool {
2671     let css = unsafe { css.as_str_unchecked() };
2672     let contents = StylesheetContents::as_arc(&contents);
2673     let global_style_data = &*GLOBAL_STYLE_DATA;
2674 
2675     match Keyframe::parse(css, &contents, &global_style_data.shared_lock) {
2676         Ok(keyframe) => {
2677             write_locked_arc(rule, |rule: &mut KeyframesRule| {
2678                 rule.keyframes.push(keyframe);
2679             });
2680             true
2681         },
2682         Err(..) => false,
2683     }
2684 }
2685 
2686 #[no_mangle]
Servo_KeyframesRule_DeleteRule(rule: &RawServoKeyframesRule, index: u32)2687 pub extern "C" fn Servo_KeyframesRule_DeleteRule(rule: &RawServoKeyframesRule, index: u32) {
2688     write_locked_arc(rule, |rule: &mut KeyframesRule| {
2689         rule.keyframes.remove(index as usize);
2690     })
2691 }
2692 
2693 #[no_mangle]
Servo_MediaRule_GetMedia(rule: &RawServoMediaRule) -> Strong<RawServoMediaList>2694 pub extern "C" fn Servo_MediaRule_GetMedia(rule: &RawServoMediaRule) -> Strong<RawServoMediaList> {
2695     read_locked_arc(rule, |rule: &MediaRule| {
2696         rule.media_queries.clone().into_strong()
2697     })
2698 }
2699 
2700 #[no_mangle]
Servo_NamespaceRule_GetPrefix(rule: &RawServoNamespaceRule) -> *mut nsAtom2701 pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: &RawServoNamespaceRule) -> *mut nsAtom {
2702     read_locked_arc(rule, |rule: &NamespaceRule| {
2703         rule.prefix.as_ref().unwrap_or(&atom!("")).as_ptr()
2704     })
2705 }
2706 
2707 #[no_mangle]
Servo_NamespaceRule_GetURI(rule: &RawServoNamespaceRule) -> *mut nsAtom2708 pub extern "C" fn Servo_NamespaceRule_GetURI(rule: &RawServoNamespaceRule) -> *mut nsAtom {
2709     read_locked_arc(rule, |rule: &NamespaceRule| rule.url.0.as_ptr())
2710 }
2711 
2712 #[no_mangle]
Servo_PageRule_GetStyle( rule: &RawServoPageRule, ) -> Strong<RawServoDeclarationBlock>2713 pub extern "C" fn Servo_PageRule_GetStyle(
2714     rule: &RawServoPageRule,
2715 ) -> Strong<RawServoDeclarationBlock> {
2716     read_locked_arc(rule, |rule: &PageRule| rule.block.clone().into_strong())
2717 }
2718 
2719 #[no_mangle]
Servo_PageRule_SetStyle( rule: &RawServoPageRule, declarations: &RawServoDeclarationBlock, )2720 pub extern "C" fn Servo_PageRule_SetStyle(
2721     rule: &RawServoPageRule,
2722     declarations: &RawServoDeclarationBlock,
2723 ) {
2724     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
2725     write_locked_arc(rule, |rule: &mut PageRule| {
2726         rule.block = declarations.clone_arc();
2727     })
2728 }
2729 
2730 #[no_mangle]
Servo_SupportsRule_GetConditionText( rule: &RawServoSupportsRule, result: &mut nsAString, )2731 pub extern "C" fn Servo_SupportsRule_GetConditionText(
2732     rule: &RawServoSupportsRule,
2733     result: &mut nsAString,
2734 ) {
2735     read_locked_arc(rule, |rule: &SupportsRule| {
2736         rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
2737     })
2738 }
2739 
2740 #[no_mangle]
Servo_MozDocumentRule_GetConditionText( rule: &RawServoMozDocumentRule, result: &mut nsAString, )2741 pub extern "C" fn Servo_MozDocumentRule_GetConditionText(
2742     rule: &RawServoMozDocumentRule,
2743     result: &mut nsAString,
2744 ) {
2745     read_locked_arc(rule, |rule: &DocumentRule| {
2746         rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
2747     })
2748 }
2749 
2750 #[no_mangle]
Servo_FontFeatureValuesRule_GetFontFamily( rule: &RawServoFontFeatureValuesRule, result: &mut nsAString, )2751 pub extern "C" fn Servo_FontFeatureValuesRule_GetFontFamily(
2752     rule: &RawServoFontFeatureValuesRule,
2753     result: &mut nsAString,
2754 ) {
2755     read_locked_arc(rule, |rule: &FontFeatureValuesRule| {
2756         rule.font_family_to_css(&mut CssWriter::new(result)).unwrap()
2757     })
2758 }
2759 
2760 #[no_mangle]
Servo_FontFeatureValuesRule_GetValueText( rule: &RawServoFontFeatureValuesRule, result: &mut nsAString, )2761 pub extern "C" fn Servo_FontFeatureValuesRule_GetValueText(
2762     rule: &RawServoFontFeatureValuesRule,
2763     result: &mut nsAString,
2764 ) {
2765     read_locked_arc(rule, |rule: &FontFeatureValuesRule| {
2766         rule.value_to_css(&mut CssWriter::new(result)).unwrap();
2767     })
2768 }
2769 
2770 #[no_mangle]
Servo_FontFaceRule_CreateEmpty() -> Strong<RawServoFontFaceRule>2771 pub extern "C" fn Servo_FontFaceRule_CreateEmpty() -> Strong<RawServoFontFaceRule> {
2772     let global_style_data = &*GLOBAL_STYLE_DATA;
2773     // XXX This is not great. We should split FontFace descriptor data
2774     // from the rule, so that we don't need to create the rule like this
2775     // and the descriptor data itself can be hold in UniquePtr from the
2776     // Gecko side. See bug 1450904.
2777     Arc::new(
2778         global_style_data
2779             .shared_lock
2780             .wrap(FontFaceRule::empty(SourceLocation { line: 0, column: 0 })),
2781     )
2782     .into_strong()
2783 }
2784 
2785 #[no_mangle]
Servo_FontFaceRule_Clone( rule: &RawServoFontFaceRule, ) -> Strong<RawServoFontFaceRule>2786 pub unsafe extern "C" fn Servo_FontFaceRule_Clone(
2787     rule: &RawServoFontFaceRule,
2788 ) -> Strong<RawServoFontFaceRule> {
2789     let clone = read_locked_arc(rule, |rule: &FontFaceRule| rule.clone());
2790     let global_style_data = &*GLOBAL_STYLE_DATA;
2791     Arc::new(global_style_data.shared_lock.wrap(clone)).into_strong()
2792 }
2793 
2794 #[no_mangle]
Servo_FontFaceRule_GetSourceLocation( rule: &RawServoFontFaceRule, line: *mut u32, column: *mut u32, )2795 pub unsafe extern "C" fn Servo_FontFaceRule_GetSourceLocation(
2796     rule: &RawServoFontFaceRule,
2797     line: *mut u32,
2798     column: *mut u32,
2799 ) {
2800     read_locked_arc(rule, |rule: &FontFaceRule| {
2801         let location = rule.source_location;
2802         *line.as_mut().unwrap() = location.line as u32;
2803         *column.as_mut().unwrap() = location.column as u32;
2804     });
2805 }
2806 
2807 macro_rules! apply_font_desc_list {
2808     ($apply_macro:ident) => {
2809         $apply_macro! {
2810             valid: [
2811                 eCSSFontDesc_Family => family,
2812                 eCSSFontDesc_Style => style,
2813                 eCSSFontDesc_Weight => weight,
2814                 eCSSFontDesc_Stretch => stretch,
2815                 eCSSFontDesc_Src => sources,
2816                 eCSSFontDesc_UnicodeRange => unicode_range,
2817                 eCSSFontDesc_FontFeatureSettings => feature_settings,
2818                 eCSSFontDesc_FontVariationSettings => variation_settings,
2819                 eCSSFontDesc_FontLanguageOverride => language_override,
2820                 eCSSFontDesc_Display => display,
2821             ]
2822             invalid: [
2823                 eCSSFontDesc_UNKNOWN,
2824                 eCSSFontDesc_COUNT,
2825             ]
2826         }
2827     };
2828 }
2829 
2830 #[no_mangle]
Servo_FontFaceRule_Length(rule: &RawServoFontFaceRule) -> u322831 pub unsafe extern "C" fn Servo_FontFaceRule_Length(rule: &RawServoFontFaceRule) -> u32 {
2832     read_locked_arc(rule, |rule: &FontFaceRule| {
2833         let mut result = 0;
2834         macro_rules! count_values {
2835             (
2836                 valid: [$($v_enum_name:ident => $field:ident,)*]
2837                 invalid: [$($i_enum_name:ident,)*]
2838             ) => {
2839                 $(if rule.$field.is_some() {
2840                     result += 1;
2841                 })*
2842             }
2843         }
2844         apply_font_desc_list!(count_values);
2845         result
2846     })
2847 }
2848 
2849 #[no_mangle]
Servo_FontFaceRule_IndexGetter( rule: &RawServoFontFaceRule, index: u32, ) -> nsCSSFontDesc2850 pub unsafe extern "C" fn Servo_FontFaceRule_IndexGetter(
2851     rule: &RawServoFontFaceRule,
2852     index: u32,
2853 ) -> nsCSSFontDesc {
2854     read_locked_arc(rule, |rule: &FontFaceRule| {
2855         let mut count = 0;
2856         macro_rules! lookup_index {
2857             (
2858                 valid: [$($v_enum_name:ident => $field:ident,)*]
2859                 invalid: [$($i_enum_name:ident,)*]
2860             ) => {
2861                 $(if rule.$field.is_some() {
2862                     count += 1;
2863                     if count - 1 == index {
2864                         return nsCSSFontDesc::$v_enum_name;
2865                     }
2866                 })*
2867             }
2868         }
2869         apply_font_desc_list!(lookup_index);
2870         return nsCSSFontDesc::eCSSFontDesc_UNKNOWN;
2871     })
2872 }
2873 
2874 #[no_mangle]
Servo_FontFaceRule_GetDeclCssText( rule: &RawServoFontFaceRule, result: &mut nsAString, )2875 pub unsafe extern "C" fn Servo_FontFaceRule_GetDeclCssText(
2876     rule: &RawServoFontFaceRule,
2877     result: &mut nsAString,
2878 ) {
2879     read_locked_arc(rule, |rule: &FontFaceRule| {
2880         rule.decl_to_css(result).unwrap();
2881     })
2882 }
2883 
2884 macro_rules! simple_font_descriptor_getter_impl {
2885     ($rule:ident, $out:ident, $field:ident, $compute:ident) => {
2886         read_locked_arc($rule, |rule: &FontFaceRule| {
2887             match rule.$field {
2888                 None => return false,
2889                 Some(ref f) => *$out = f.$compute(),
2890             }
2891             true
2892         })
2893     };
2894 }
2895 
2896 #[no_mangle]
Servo_FontFaceRule_GetFontWeight( rule: &RawServoFontFaceRule, out: &mut font_face::ComputedFontWeightRange, ) -> bool2897 pub unsafe extern "C" fn Servo_FontFaceRule_GetFontWeight(
2898     rule: &RawServoFontFaceRule,
2899     out: &mut font_face::ComputedFontWeightRange,
2900 ) -> bool {
2901     simple_font_descriptor_getter_impl!(rule, out, weight, compute)
2902 }
2903 
2904 #[no_mangle]
Servo_FontFaceRule_GetFontStretch( rule: &RawServoFontFaceRule, out: &mut font_face::ComputedFontStretchRange, ) -> bool2905 pub unsafe extern "C" fn Servo_FontFaceRule_GetFontStretch(
2906     rule: &RawServoFontFaceRule,
2907     out: &mut font_face::ComputedFontStretchRange,
2908 ) -> bool {
2909     simple_font_descriptor_getter_impl!(rule, out, stretch, compute)
2910 }
2911 
2912 #[no_mangle]
Servo_FontFaceRule_GetFontStyle( rule: &RawServoFontFaceRule, out: &mut font_face::ComputedFontStyleDescriptor, ) -> bool2913 pub unsafe extern "C" fn Servo_FontFaceRule_GetFontStyle(
2914     rule: &RawServoFontFaceRule,
2915     out: &mut font_face::ComputedFontStyleDescriptor,
2916 ) -> bool {
2917     simple_font_descriptor_getter_impl!(rule, out, style, compute)
2918 }
2919 
2920 #[no_mangle]
Servo_FontFaceRule_GetFontDisplay( rule: &RawServoFontFaceRule, out: &mut font_face::FontDisplay, ) -> bool2921 pub unsafe extern "C" fn Servo_FontFaceRule_GetFontDisplay(
2922     rule: &RawServoFontFaceRule,
2923     out: &mut font_face::FontDisplay,
2924 ) -> bool {
2925     simple_font_descriptor_getter_impl!(rule, out, display, clone)
2926 }
2927 
2928 #[no_mangle]
Servo_FontFaceRule_GetFontLanguageOverride( rule: &RawServoFontFaceRule, out: &mut computed::FontLanguageOverride, ) -> bool2929 pub unsafe extern "C" fn Servo_FontFaceRule_GetFontLanguageOverride(
2930     rule: &RawServoFontFaceRule,
2931     out: &mut computed::FontLanguageOverride,
2932 ) -> bool {
2933     simple_font_descriptor_getter_impl!(rule, out, language_override, compute_non_system)
2934 }
2935 
2936 #[no_mangle]
Servo_FontFaceRule_GetFamilyName( rule: &RawServoFontFaceRule, ) -> *mut nsAtom2937 pub unsafe extern "C" fn Servo_FontFaceRule_GetFamilyName(
2938     rule: &RawServoFontFaceRule,
2939 ) -> *mut nsAtom {
2940     read_locked_arc(rule, |rule: &FontFaceRule| {
2941         // TODO(emilio): font-family is a mandatory descriptor, can't we unwrap
2942         // here, and remove the null-checks in Gecko?
2943         rule.family
2944             .as_ref()
2945             .map_or(ptr::null_mut(), |f| f.name.as_ptr())
2946     })
2947 }
2948 
2949 #[no_mangle]
Servo_FontFaceRule_GetUnicodeRanges( rule: &RawServoFontFaceRule, out_len: *mut usize, ) -> *const UnicodeRange2950 pub unsafe extern "C" fn Servo_FontFaceRule_GetUnicodeRanges(
2951     rule: &RawServoFontFaceRule,
2952     out_len: *mut usize,
2953 ) -> *const UnicodeRange {
2954     *out_len = 0;
2955     read_locked_arc(rule, |rule: &FontFaceRule| {
2956         let ranges = match rule.unicode_range {
2957             Some(ref ranges) => ranges,
2958             None => return ptr::null(),
2959         };
2960         *out_len = ranges.len();
2961         ranges.as_ptr() as *const _
2962     })
2963 }
2964 
2965 #[no_mangle]
Servo_FontFaceRule_GetSources( rule: &RawServoFontFaceRule, out: *mut nsTArray<FontFaceSourceListComponent>, )2966 pub unsafe extern "C" fn Servo_FontFaceRule_GetSources(
2967     rule: &RawServoFontFaceRule,
2968     out: *mut nsTArray<FontFaceSourceListComponent>,
2969 ) {
2970     let out = &mut *out;
2971     read_locked_arc(rule, |rule: &FontFaceRule| {
2972         let sources = match rule.sources {
2973             Some(ref s) => s,
2974             None => return,
2975         };
2976         let len = sources.iter().fold(0, |acc, src| {
2977             acc + match *src {
2978                 // Each format hint takes one position in the array of mSrc.
2979                 Source::Url(ref url) => url.format_hints.len() + 1,
2980                 Source::Local(_) => 1,
2981             }
2982         });
2983 
2984         out.set_len(len as u32);
2985 
2986         let mut iter = out.iter_mut();
2987 
2988         {
2989             let mut set_next = |component: FontFaceSourceListComponent| {
2990                 *iter.next().expect("miscalculated length") = component;
2991             };
2992 
2993             for source in sources.iter() {
2994                 match *source {
2995                     Source::Url(ref url) => {
2996                         set_next(FontFaceSourceListComponent::Url(&url.url));
2997                         for hint in url.format_hints.iter() {
2998                             set_next(FontFaceSourceListComponent::FormatHint {
2999                                 length: hint.len(),
3000                                 utf8_bytes: hint.as_ptr(),
3001                             });
3002                         }
3003                     },
3004                     Source::Local(ref name) => {
3005                         set_next(FontFaceSourceListComponent::Local(name.name.as_ptr()));
3006                     },
3007                 }
3008             }
3009         }
3010 
3011         assert!(iter.next().is_none(), "miscalculated");
3012     })
3013 }
3014 
3015 #[no_mangle]
Servo_FontFaceRule_GetVariationSettings( rule: &RawServoFontFaceRule, variations: *mut nsTArray<structs::gfxFontVariation>, )3016 pub unsafe extern "C" fn Servo_FontFaceRule_GetVariationSettings(
3017     rule: &RawServoFontFaceRule,
3018     variations: *mut nsTArray<structs::gfxFontVariation>,
3019 ) {
3020     read_locked_arc(rule, |rule: &FontFaceRule| {
3021         let source_variations = match rule.variation_settings {
3022             Some(ref v) => v,
3023             None => return,
3024         };
3025 
3026         (*variations).set_len(source_variations.0.len() as u32);
3027         for (target, source) in (*variations).iter_mut().zip(source_variations.0.iter()) {
3028             *target = structs::gfxFontVariation {
3029                 mTag: source.tag.0,
3030                 mValue: source.value.get(),
3031             };
3032         }
3033     });
3034 }
3035 
3036 #[no_mangle]
Servo_FontFaceRule_GetFeatureSettings( rule: &RawServoFontFaceRule, features: *mut nsTArray<structs::gfxFontFeature>, )3037 pub unsafe extern "C" fn Servo_FontFaceRule_GetFeatureSettings(
3038     rule: &RawServoFontFaceRule,
3039     features: *mut nsTArray<structs::gfxFontFeature>,
3040 ) {
3041     read_locked_arc(rule, |rule: &FontFaceRule| {
3042         let source_features = match rule.feature_settings {
3043             Some(ref v) => v,
3044             None => return,
3045         };
3046 
3047         (*features).set_len(source_features.0.len() as u32);
3048         for (target, source) in (*features).iter_mut().zip(source_features.0.iter()) {
3049             *target = structs::gfxFontFeature {
3050                 mTag: source.tag.0,
3051                 mValue: source.value.value() as u32,
3052             };
3053         }
3054     });
3055 }
3056 
3057 #[no_mangle]
Servo_FontFaceRule_GetDescriptorCssText( rule: &RawServoFontFaceRule, desc: nsCSSFontDesc, result: &mut nsAString, )3058 pub unsafe extern "C" fn Servo_FontFaceRule_GetDescriptorCssText(
3059     rule: &RawServoFontFaceRule,
3060     desc: nsCSSFontDesc,
3061     result: &mut nsAString,
3062 ) {
3063     read_locked_arc(rule, |rule: &FontFaceRule| {
3064         let mut writer = CssWriter::new(result);
3065         macro_rules! to_css_text {
3066             (
3067                 valid: [$($v_enum_name:ident => $field:ident,)*]
3068                 invalid: [$($i_enum_name:ident,)*]
3069             ) => {
3070                 match desc {
3071                     $(
3072                         nsCSSFontDesc::$v_enum_name => {
3073                             if let Some(ref value) = rule.$field {
3074                                 value.to_css(&mut writer).unwrap();
3075                             }
3076                         }
3077                     )*
3078                     $(
3079                         nsCSSFontDesc::$i_enum_name => {
3080                             debug_assert!(false, "not a valid font descriptor");
3081                         }
3082                     )*
3083                 }
3084             }
3085         }
3086         apply_font_desc_list!(to_css_text)
3087     })
3088 }
3089 
3090 #[no_mangle]
Servo_FontFaceRule_SetDescriptor( rule: &RawServoFontFaceRule, desc: nsCSSFontDesc, value: &nsACString, data: *mut URLExtraData, out_changed: *mut bool, ) -> bool3091 pub unsafe extern "C" fn Servo_FontFaceRule_SetDescriptor(
3092     rule: &RawServoFontFaceRule,
3093     desc: nsCSSFontDesc,
3094     value: &nsACString,
3095     data: *mut URLExtraData,
3096     out_changed: *mut bool,
3097 ) -> bool {
3098     let value = value.as_str_unchecked();
3099     let mut input = ParserInput::new(&value);
3100     let mut parser = Parser::new(&mut input);
3101     let url_data = UrlExtraData::from_ptr_ref(&data);
3102     let context = ParserContext::new(
3103         Origin::Author,
3104         url_data,
3105         Some(CssRuleType::FontFace),
3106         ParsingMode::DEFAULT,
3107         QuirksMode::NoQuirks,
3108         None,
3109         None,
3110     );
3111 
3112     write_locked_arc(rule, |rule: &mut FontFaceRule| {
3113         macro_rules! to_css_text {
3114             (
3115                 valid: [$($v_enum_name:ident => $field:ident,)*]
3116                 invalid: [$($i_enum_name:ident,)*]
3117             ) => {
3118                 match desc {
3119                     $(
3120                         nsCSSFontDesc::$v_enum_name => {
3121                             if let Ok(value) = parser.parse_entirely(|i| Parse::parse(&context, i)) {
3122                                 let result = Some(value);
3123                                 *out_changed = result != rule.$field;
3124                                 rule.$field = result;
3125                                 true
3126                             } else {
3127                                 false
3128                             }
3129                         }
3130                     )*
3131                     $(
3132                         nsCSSFontDesc::$i_enum_name => {
3133                             debug_assert!(false, "not a valid font descriptor");
3134                             false
3135                         }
3136                     )*
3137                 }
3138             }
3139         }
3140         apply_font_desc_list!(to_css_text)
3141     })
3142 }
3143 
3144 #[no_mangle]
Servo_FontFaceRule_ResetDescriptor( rule: &RawServoFontFaceRule, desc: nsCSSFontDesc, )3145 pub unsafe extern "C" fn Servo_FontFaceRule_ResetDescriptor(
3146     rule: &RawServoFontFaceRule,
3147     desc: nsCSSFontDesc,
3148 ) {
3149     write_locked_arc(rule, |rule: &mut FontFaceRule| {
3150         macro_rules! reset_desc {
3151             (
3152                 valid: [$($v_enum_name:ident => $field:ident,)*]
3153                 invalid: [$($i_enum_name:ident,)*]
3154             ) => {
3155                 match desc {
3156                     $(nsCSSFontDesc::$v_enum_name => rule.$field = None,)*
3157                     $(nsCSSFontDesc::$i_enum_name => debug_assert!(false, "not a valid font descriptor"),)*
3158                 }
3159             }
3160         }
3161         apply_font_desc_list!(reset_desc)
3162     })
3163 }
3164 
3165 #[no_mangle]
Servo_CounterStyleRule_GetName( rule: &RawServoCounterStyleRule, ) -> *mut nsAtom3166 pub unsafe extern "C" fn Servo_CounterStyleRule_GetName(
3167     rule: &RawServoCounterStyleRule,
3168 ) -> *mut nsAtom {
3169     read_locked_arc(rule, |rule: &CounterStyleRule| rule.name().0.as_ptr())
3170 }
3171 
3172 #[no_mangle]
Servo_CounterStyleRule_SetName( rule: &RawServoCounterStyleRule, value: &nsACString, ) -> bool3173 pub unsafe extern "C" fn Servo_CounterStyleRule_SetName(
3174     rule: &RawServoCounterStyleRule,
3175     value: &nsACString,
3176 ) -> bool {
3177     let value = value.as_str_unchecked();
3178     let mut input = ParserInput::new(&value);
3179     let mut parser = Parser::new(&mut input);
3180     match parser.parse_entirely(counter_style::parse_counter_style_name_definition) {
3181         Ok(name) => {
3182             write_locked_arc(rule, |rule: &mut CounterStyleRule| rule.set_name(name));
3183             true
3184         },
3185         Err(_) => false,
3186     }
3187 }
3188 
3189 #[no_mangle]
Servo_CounterStyleRule_GetGeneration( rule: &RawServoCounterStyleRule, ) -> u323190 pub unsafe extern "C" fn Servo_CounterStyleRule_GetGeneration(
3191     rule: &RawServoCounterStyleRule,
3192 ) -> u32 {
3193     read_locked_arc(rule, |rule: &CounterStyleRule| rule.generation())
3194 }
3195 
symbol_to_string(s: &counter_style::Symbol) -> nsString3196 fn symbol_to_string(s: &counter_style::Symbol) -> nsString {
3197     match *s {
3198         counter_style::Symbol::String(ref s) => nsString::from(&**s),
3199         counter_style::Symbol::Ident(ref i) => nsString::from(i.0.as_slice()),
3200     }
3201 }
3202 
3203 // TODO(emilio): Cbindgen could be used to simplify a bunch of code here.
3204 #[no_mangle]
Servo_CounterStyleRule_GetPad( rule: &RawServoCounterStyleRule, width: &mut i32, symbol: &mut nsString, ) -> bool3205 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPad(
3206     rule: &RawServoCounterStyleRule,
3207     width: &mut i32,
3208     symbol: &mut nsString,
3209 ) -> bool {
3210     read_locked_arc(rule, |rule: &CounterStyleRule| {
3211         let pad = match rule.pad() {
3212             Some(pad) => pad,
3213             None => return false,
3214         };
3215         *width = pad.0.value();
3216         *symbol = symbol_to_string(&pad.1);
3217         true
3218     })
3219 }
3220 
get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool3221 fn get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool {
3222     let s = match s {
3223         Some(s) => s,
3224         None => return false,
3225     };
3226     *out = symbol_to_string(s);
3227     true
3228 }
3229 
3230 #[no_mangle]
Servo_CounterStyleRule_GetPrefix( rule: &RawServoCounterStyleRule, out: &mut nsString, ) -> bool3231 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPrefix(
3232     rule: &RawServoCounterStyleRule,
3233     out: &mut nsString,
3234 ) -> bool {
3235     read_locked_arc(rule, |rule: &CounterStyleRule| {
3236         get_symbol(rule.prefix(), out)
3237     })
3238 }
3239 
3240 #[no_mangle]
Servo_CounterStyleRule_GetSuffix( rule: &RawServoCounterStyleRule, out: &mut nsString, ) -> bool3241 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSuffix(
3242     rule: &RawServoCounterStyleRule,
3243     out: &mut nsString,
3244 ) -> bool {
3245     read_locked_arc(rule, |rule: &CounterStyleRule| {
3246         get_symbol(rule.suffix(), out)
3247     })
3248 }
3249 
3250 #[no_mangle]
Servo_CounterStyleRule_GetNegative( rule: &RawServoCounterStyleRule, prefix: &mut nsString, suffix: &mut nsString, ) -> bool3251 pub unsafe extern "C" fn Servo_CounterStyleRule_GetNegative(
3252     rule: &RawServoCounterStyleRule,
3253     prefix: &mut nsString,
3254     suffix: &mut nsString,
3255 ) -> bool {
3256     read_locked_arc(rule, |rule: &CounterStyleRule| {
3257         let negative = match rule.negative() {
3258             Some(n) => n,
3259             None => return false,
3260         };
3261         *prefix = symbol_to_string(&negative.0);
3262         *suffix = match negative.1 {
3263             Some(ref s) => symbol_to_string(s),
3264             None => nsString::new(),
3265         };
3266         true
3267     })
3268 }
3269 
3270 #[repr(u8)]
3271 pub enum IsOrdinalInRange {
3272     Auto,
3273     InRange,
3274     NotInRange,
3275     NoOrdinalSpecified,
3276 }
3277 
3278 #[no_mangle]
Servo_CounterStyleRule_IsInRange( rule: &RawServoCounterStyleRule, ordinal: i32, ) -> IsOrdinalInRange3279 pub unsafe extern "C" fn Servo_CounterStyleRule_IsInRange(
3280     rule: &RawServoCounterStyleRule,
3281     ordinal: i32,
3282 ) -> IsOrdinalInRange {
3283     use style::counter_style::CounterBound;
3284     read_locked_arc(rule, |rule: &CounterStyleRule| {
3285         let range = match rule.range() {
3286             Some(r) => r,
3287             None => return IsOrdinalInRange::NoOrdinalSpecified,
3288         };
3289 
3290         if range.0.is_empty() {
3291             return IsOrdinalInRange::Auto;
3292         }
3293 
3294         let in_range = range.0.iter().any(|r| {
3295             if let CounterBound::Integer(start) = r.start {
3296                 if start.value() > ordinal {
3297                     return false;
3298                 }
3299             }
3300 
3301             if let CounterBound::Integer(end) = r.end {
3302                 if end.value() < ordinal {
3303                     return false;
3304                 }
3305             }
3306 
3307             true
3308         });
3309 
3310         if in_range {
3311             IsOrdinalInRange::InRange
3312         } else {
3313             IsOrdinalInRange::NotInRange
3314         }
3315     })
3316 }
3317 
3318 #[no_mangle]
Servo_CounterStyleRule_GetSymbols( rule: &RawServoCounterStyleRule, symbols: &mut style::OwnedSlice<nsString>, )3319 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols(
3320     rule: &RawServoCounterStyleRule,
3321     symbols: &mut style::OwnedSlice<nsString>,
3322 ) {
3323     read_locked_arc(rule, |rule: &CounterStyleRule| {
3324         *symbols = match rule.symbols() {
3325             Some(s) => s.0.iter().map(symbol_to_string).collect(),
3326             None => style::OwnedSlice::default(),
3327         };
3328     })
3329 }
3330 
3331 #[repr(C)]
3332 pub struct AdditiveSymbol {
3333     pub weight: i32,
3334     pub symbol: nsString,
3335 }
3336 
3337 #[no_mangle]
Servo_CounterStyleRule_GetAdditiveSymbols( rule: &RawServoCounterStyleRule, symbols: &mut style::OwnedSlice<AdditiveSymbol>, )3338 pub unsafe extern "C" fn Servo_CounterStyleRule_GetAdditiveSymbols(
3339     rule: &RawServoCounterStyleRule,
3340     symbols: &mut style::OwnedSlice<AdditiveSymbol>,
3341 ) {
3342     read_locked_arc(rule, |rule: &CounterStyleRule| {
3343         *symbols = match rule.additive_symbols() {
3344             Some(s) => {
3345                 s.0.iter()
3346                     .map(|s| AdditiveSymbol {
3347                         weight: s.weight.value(),
3348                         symbol: symbol_to_string(&s.symbol),
3349                     })
3350                     .collect()
3351             },
3352             None => style::OwnedSlice::default(),
3353         };
3354     })
3355 }
3356 
3357 #[repr(C, u8)]
3358 pub enum CounterSpeakAs {
3359     None,
3360     Auto,
3361     Bullets,
3362     Numbers,
3363     Words,
3364     Ident(*mut nsAtom),
3365 }
3366 
3367 #[no_mangle]
Servo_CounterStyleRule_GetSpeakAs( rule: &RawServoCounterStyleRule, out: &mut CounterSpeakAs, )3368 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSpeakAs(
3369     rule: &RawServoCounterStyleRule,
3370     out: &mut CounterSpeakAs,
3371 ) {
3372     use style::counter_style::SpeakAs;
3373     *out = read_locked_arc(rule, |rule: &CounterStyleRule| {
3374         let speak_as = match rule.speak_as() {
3375             Some(s) => s,
3376             None => return CounterSpeakAs::None,
3377         };
3378         match *speak_as {
3379             SpeakAs::Auto => CounterSpeakAs::Auto,
3380             SpeakAs::Bullets => CounterSpeakAs::Bullets,
3381             SpeakAs::Numbers => CounterSpeakAs::Numbers,
3382             SpeakAs::Words => CounterSpeakAs::Words,
3383             SpeakAs::Other(ref other) => CounterSpeakAs::Ident(other.0.as_ptr()),
3384         }
3385     });
3386 }
3387 
3388 #[repr(u8)]
3389 pub enum CounterSystem {
3390   Cyclic = 0,
3391   Numeric,
3392   Alphabetic,
3393   Symbolic,
3394   Additive,
3395   Fixed,
3396   Extends
3397 }
3398 
3399 #[no_mangle]
Servo_CounterStyleRule_GetSystem( rule: &RawServoCounterStyleRule ) -> CounterSystem3400 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSystem(
3401     rule: &RawServoCounterStyleRule
3402 ) -> CounterSystem {
3403     use style::counter_style::System;
3404     read_locked_arc(rule, |rule: &CounterStyleRule| {
3405         match *rule.resolved_system() {
3406             System::Cyclic => CounterSystem::Cyclic,
3407             System::Numeric => CounterSystem::Numeric,
3408             System::Alphabetic => CounterSystem::Alphabetic,
3409             System::Symbolic => CounterSystem::Symbolic,
3410             System::Additive => CounterSystem::Additive,
3411             System::Fixed { .. } => CounterSystem::Fixed,
3412             System::Extends(_) => CounterSystem::Extends,
3413         }
3414     })
3415 }
3416 
3417 #[no_mangle]
Servo_CounterStyleRule_GetExtended( rule: &RawServoCounterStyleRule, ) -> *mut nsAtom3418 pub unsafe extern "C" fn Servo_CounterStyleRule_GetExtended(
3419     rule: &RawServoCounterStyleRule,
3420 ) -> *mut nsAtom {
3421     read_locked_arc(rule, |rule: &CounterStyleRule| {
3422         match *rule.resolved_system() {
3423             counter_style::System::Extends(ref name) => name.0.as_ptr(),
3424             _ => {
3425                 debug_assert!(false, "Not extends system");
3426                 ptr::null_mut()
3427             },
3428         }
3429     })
3430 }
3431 
3432 #[no_mangle]
Servo_CounterStyleRule_GetFixedFirstValue( rule: &RawServoCounterStyleRule, ) -> i323433 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFixedFirstValue(
3434     rule: &RawServoCounterStyleRule,
3435 ) -> i32 {
3436     read_locked_arc(rule, |rule: &CounterStyleRule| {
3437         match *rule.resolved_system() {
3438             counter_style::System::Fixed { first_symbol_value } => {
3439                 first_symbol_value.map_or(1, |v| v.value())
3440             },
3441             _ => {
3442                 debug_assert!(false, "Not fixed system");
3443                 0
3444             },
3445         }
3446     })
3447 }
3448 
3449 #[no_mangle]
Servo_CounterStyleRule_GetFallback( rule: &RawServoCounterStyleRule, ) -> *mut nsAtom3450 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFallback(
3451     rule: &RawServoCounterStyleRule,
3452 ) -> *mut nsAtom {
3453     read_locked_arc(rule, |rule: &CounterStyleRule| {
3454         rule.fallback().map_or(ptr::null_mut(), |i| i.0 .0.as_ptr())
3455     })
3456 }
3457 
3458 macro_rules! counter_style_descriptors {
3459     {
3460         valid: [
3461             $($desc:ident => $getter:ident / $setter:ident,)+
3462         ]
3463         invalid: [
3464             $($i_desc:ident,)+
3465         ]
3466     } => {
3467         #[no_mangle]
3468         pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptorCssText(
3469             rule: &RawServoCounterStyleRule,
3470             desc: nsCSSCounterDesc,
3471             result: &mut nsAString,
3472         ) {
3473             let mut writer = CssWriter::new(result);
3474             read_locked_arc(rule, |rule: &CounterStyleRule| {
3475                 match desc {
3476                     $(nsCSSCounterDesc::$desc => {
3477                         if let Some(value) = rule.$getter() {
3478                             value.to_css(&mut writer).unwrap();
3479                         }
3480                     })+
3481                     $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3482                 }
3483             });
3484         }
3485 
3486         #[no_mangle]
3487         pub unsafe extern "C" fn Servo_CounterStyleRule_SetDescriptor(
3488             rule: &RawServoCounterStyleRule,
3489             desc: nsCSSCounterDesc,
3490             value: &nsACString,
3491         ) -> bool {
3492             let value = value.as_str_unchecked();
3493             let mut input = ParserInput::new(&value);
3494             let mut parser = Parser::new(&mut input);
3495             let url_data = dummy_url_data();
3496             let context = ParserContext::new(
3497                 Origin::Author,
3498                 url_data,
3499                 Some(CssRuleType::CounterStyle),
3500                 ParsingMode::DEFAULT,
3501                 QuirksMode::NoQuirks,
3502                 None,
3503                 None,
3504             );
3505 
3506             write_locked_arc(rule, |rule: &mut CounterStyleRule| {
3507                 match desc {
3508                     $(nsCSSCounterDesc::$desc => {
3509                         match parser.parse_entirely(|i| Parse::parse(&context, i)) {
3510                             Ok(value) => rule.$setter(value),
3511                             Err(_) => false,
3512                         }
3513                     })+
3514                     $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3515                 }
3516             })
3517         }
3518     }
3519 }
3520 
3521 counter_style_descriptors! {
3522     valid: [
3523         eCSSCounterDesc_System => system / set_system,
3524         eCSSCounterDesc_Symbols => symbols / set_symbols,
3525         eCSSCounterDesc_AdditiveSymbols => additive_symbols / set_additive_symbols,
3526         eCSSCounterDesc_Negative => negative / set_negative,
3527         eCSSCounterDesc_Prefix => prefix / set_prefix,
3528         eCSSCounterDesc_Suffix => suffix / set_suffix,
3529         eCSSCounterDesc_Range => range / set_range,
3530         eCSSCounterDesc_Pad => pad / set_pad,
3531         eCSSCounterDesc_Fallback => fallback / set_fallback,
3532         eCSSCounterDesc_SpeakAs => speak_as / set_speak_as,
3533     ]
3534     invalid: [
3535         eCSSCounterDesc_UNKNOWN,
3536         eCSSCounterDesc_COUNT,
3537     ]
3538 }
3539 
3540 #[no_mangle]
Servo_ComputedValues_GetForAnonymousBox( parent_style_or_null: Option<&ComputedValues>, pseudo: PseudoStyleType, raw_data: &RawServoStyleSet, ) -> Strong<ComputedValues>3541 pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox(
3542     parent_style_or_null: Option<&ComputedValues>,
3543     pseudo: PseudoStyleType,
3544     raw_data: &RawServoStyleSet,
3545 ) -> Strong<ComputedValues> {
3546     let global_style_data = &*GLOBAL_STYLE_DATA;
3547     let guard = global_style_data.shared_lock.read();
3548     let guards = StylesheetGuards::same(&guard);
3549     let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
3550     let pseudo = PseudoElement::from_pseudo_type(pseudo).unwrap();
3551     debug_assert!(pseudo.is_anon_box());
3552 
3553     let metrics = get_metrics_provider_for_product();
3554 
3555     // If the pseudo element is PageContent, we should append the precomputed
3556     // pseudo element declerations with specified page rules.
3557     let page_decls = match pseudo {
3558         PseudoElement::PageContent => {
3559             let mut declarations = vec![];
3560             let iter = data.stylist.iter_extra_data_origins_rev();
3561             for (data, origin) in iter {
3562                 let level = match origin {
3563                     Origin::UserAgent => CascadeLevel::UANormal,
3564                     Origin::User => CascadeLevel::UserNormal,
3565                     Origin::Author => CascadeLevel::same_tree_author_normal(),
3566                 };
3567                 for rule in data.pages.iter() {
3568                     declarations.push(ApplicableDeclarationBlock::from_declarations(
3569                         rule.read_with(level.guard(&guards)).block.clone(),
3570                         level,
3571                     ));
3572                 }
3573             }
3574             Some(declarations)
3575         },
3576         _ => None,
3577     };
3578 
3579     let rule_node = data
3580         .stylist
3581         .rule_node_for_precomputed_pseudo(&guards, &pseudo, page_decls);
3582 
3583     data.stylist
3584         .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
3585             &guards,
3586             &pseudo,
3587             parent_style_or_null.map(|x| &*x),
3588             &metrics,
3589             rule_node,
3590         )
3591         .into()
3592 }
3593 
3594 #[no_mangle]
Servo_ResolvePseudoStyle( element: &RawGeckoElement, pseudo_type: PseudoStyleType, is_probe: bool, inherited_style: Option<&ComputedValues>, raw_data: &RawServoStyleSet, ) -> Strong<ComputedValues>3595 pub extern "C" fn Servo_ResolvePseudoStyle(
3596     element: &RawGeckoElement,
3597     pseudo_type: PseudoStyleType,
3598     is_probe: bool,
3599     inherited_style: Option<&ComputedValues>,
3600     raw_data: &RawServoStyleSet,
3601 ) -> Strong<ComputedValues> {
3602     let element = GeckoElement(element);
3603     let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
3604 
3605     debug!(
3606         "Servo_ResolvePseudoStyle: {:?} {:?}, is_probe: {}",
3607         element,
3608         PseudoElement::from_pseudo_type(pseudo_type),
3609         is_probe
3610     );
3611 
3612     let data = element.borrow_data();
3613 
3614     let data = match data.as_ref() {
3615         Some(data) if data.has_styles() => data,
3616         _ => {
3617             // FIXME(bholley, emilio): Assert against this.
3618             //
3619             // Known offender is nsMathMLmoFrame::MarkIntrinsicISizesDirty,
3620             // which goes and does a bunch of work involving style resolution.
3621             //
3622             // Bug 1403865 tracks fixing it, and potentially adding an assert
3623             // here instead.
3624             warn!("Calling Servo_ResolvePseudoStyle on unstyled element");
3625             return if is_probe {
3626                 Strong::null()
3627             } else {
3628                 doc_data.default_computed_values().clone().into()
3629             };
3630         },
3631     };
3632 
3633     let pseudo = PseudoElement::from_pseudo_type(pseudo_type)
3634         .expect("ResolvePseudoStyle with a non-pseudo?");
3635 
3636     let global_style_data = &*GLOBAL_STYLE_DATA;
3637     let guard = global_style_data.shared_lock.read();
3638     let style = get_pseudo_style(
3639         &guard,
3640         element,
3641         &pseudo,
3642         RuleInclusion::All,
3643         &data.styles,
3644         inherited_style,
3645         &*doc_data,
3646         is_probe,
3647         /* matching_func = */ None,
3648     );
3649 
3650     match style {
3651         Some(s) => s.into(),
3652         None => {
3653             debug_assert!(is_probe);
3654             Strong::null()
3655         },
3656     }
3657 }
3658 
debug_atom_array(atoms: &AtomArray) -> String3659 fn debug_atom_array(atoms: &AtomArray) -> String {
3660     let mut result = String::from("[");
3661     for atom in atoms.iter() {
3662         if atom.mRawPtr.is_null() {
3663             result += "(null), ";
3664         } else {
3665             let atom = unsafe { WeakAtom::new(atom.mRawPtr) };
3666             write!(result, "{}, ", atom).unwrap();
3667         }
3668     }
3669     result.push(']');
3670     result
3671 }
3672 
3673 #[no_mangle]
Servo_ComputedValues_ResolveXULTreePseudoStyle( element: &RawGeckoElement, pseudo_tag: *mut nsAtom, inherited_style: &ComputedValues, input_word: &AtomArray, raw_data: &RawServoStyleSet, ) -> Strong<ComputedValues>3674 pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle(
3675     element: &RawGeckoElement,
3676     pseudo_tag: *mut nsAtom,
3677     inherited_style: &ComputedValues,
3678     input_word: &AtomArray,
3679     raw_data: &RawServoStyleSet,
3680 ) -> Strong<ComputedValues> {
3681     let element = GeckoElement(element);
3682     let data = element
3683         .borrow_data()
3684         .expect("Calling ResolveXULTreePseudoStyle on unstyled element?");
3685 
3686     let pseudo = unsafe {
3687         Atom::with(pseudo_tag, |atom| {
3688             PseudoElement::from_tree_pseudo_atom(atom, Box::new([]))
3689         })
3690         .expect("ResolveXULTreePseudoStyle with a non-tree pseudo?")
3691     };
3692     let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
3693 
3694     debug!(
3695         "ResolveXULTreePseudoStyle: {:?} {:?} {}",
3696         element,
3697         pseudo,
3698         debug_atom_array(input_word)
3699     );
3700 
3701     let matching_fn = |pseudo: &PseudoElement| {
3702         let args = pseudo
3703             .tree_pseudo_args()
3704             .expect("Not a tree pseudo-element?");
3705         args.iter()
3706             .all(|atom| input_word.iter().any(|item| atom.as_ptr() == item.mRawPtr))
3707     };
3708 
3709     let global_style_data = &*GLOBAL_STYLE_DATA;
3710     let guard = global_style_data.shared_lock.read();
3711     get_pseudo_style(
3712         &guard,
3713         element,
3714         &pseudo,
3715         RuleInclusion::All,
3716         &data.styles,
3717         Some(inherited_style),
3718         &*doc_data,
3719         /* is_probe = */ false,
3720         Some(&matching_fn),
3721     )
3722     .unwrap()
3723     .into()
3724 }
3725 
3726 #[no_mangle]
Servo_SetExplicitStyle(element: &RawGeckoElement, style: &ComputedValues)3727 pub extern "C" fn Servo_SetExplicitStyle(element: &RawGeckoElement, style: &ComputedValues) {
3728     let element = GeckoElement(element);
3729     debug!("Servo_SetExplicitStyle: {:?}", element);
3730     // We only support this API for initial styling. There's no reason it couldn't
3731     // work for other things, we just haven't had a reason to do so.
3732     debug_assert!(!element.has_data());
3733     let mut data = unsafe { element.ensure_data() };
3734     data.styles.primary = Some(unsafe { ArcBorrow::from_ref(style) }.clone_arc());
3735 }
3736 
get_pseudo_style( guard: &SharedRwLockReadGuard, element: GeckoElement, pseudo: &PseudoElement, rule_inclusion: RuleInclusion, styles: &ElementStyles, inherited_styles: Option<&ComputedValues>, doc_data: &PerDocumentStyleDataImpl, is_probe: bool, matching_func: Option<&dyn Fn(&PseudoElement) -> bool>, ) -> Option<Arc<ComputedValues>>3737 fn get_pseudo_style(
3738     guard: &SharedRwLockReadGuard,
3739     element: GeckoElement,
3740     pseudo: &PseudoElement,
3741     rule_inclusion: RuleInclusion,
3742     styles: &ElementStyles,
3743     inherited_styles: Option<&ComputedValues>,
3744     doc_data: &PerDocumentStyleDataImpl,
3745     is_probe: bool,
3746     matching_func: Option<&dyn Fn(&PseudoElement) -> bool>,
3747 ) -> Option<Arc<ComputedValues>> {
3748     let style = match pseudo.cascade_type() {
3749         PseudoElementCascadeType::Eager => {
3750             match *pseudo {
3751                 PseudoElement::FirstLetter => {
3752                     styles.pseudos.get(&pseudo).map(|pseudo_styles| {
3753                         // inherited_styles can be None when doing lazy resolution
3754                         // (e.g. for computed style) or when probing.  In that case
3755                         // we just inherit from our element, which is what Gecko
3756                         // does in that situation.  What should actually happen in
3757                         // the computed style case is a bit unclear.
3758                         let inherited_styles = inherited_styles.unwrap_or(styles.primary());
3759                         let guards = StylesheetGuards::same(guard);
3760                         let metrics = get_metrics_provider_for_product();
3761                         let inputs = CascadeInputs::new_from_style(pseudo_styles);
3762                         doc_data.stylist.compute_pseudo_element_style_with_inputs(
3763                             inputs,
3764                             pseudo,
3765                             &guards,
3766                             Some(inherited_styles),
3767                             &metrics,
3768                             Some(element),
3769                         )
3770                     })
3771                 },
3772                 _ => {
3773                     // Unfortunately, we can't assert that inherited_styles, if
3774                     // present, is pointer-equal to styles.primary(), or even
3775                     // equal in any meaningful way.  The way it can fail is as
3776                     // follows.  Say we append an element with a ::before,
3777                     // ::after, or ::first-line to a parent with a ::first-line,
3778                     // such that the element ends up on the first line of the
3779                     // parent (e.g. it's an inline-block in the case it has a
3780                     // ::first-line, or any container in the ::before/::after
3781                     // cases).  Then gecko will update its frame's style to
3782                     // inherit from the parent's ::first-line.  The next time we
3783                     // try to get the ::before/::after/::first-line style for
3784                     // the kid, we'll likely pass in the frame's style as
3785                     // inherited_styles, but that's not pointer-identical to
3786                     // styles.primary(), because it got reparented.
3787                     //
3788                     // Now in practice this turns out to be OK, because all the
3789                     // cases in which there's a mismatch go ahead and reparent
3790                     // styles again as needed to make sure the ::first-line
3791                     // affects all the things it should affect.  But it makes it
3792                     // impossible to assert anything about the two styles
3793                     // matching here, unfortunately.
3794                     styles.pseudos.get(&pseudo).cloned()
3795                 },
3796             }
3797         },
3798         PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
3799         PseudoElementCascadeType::Lazy => {
3800             debug_assert!(
3801                 inherited_styles.is_none() ||
3802                     ptr::eq(inherited_styles.unwrap(), &**styles.primary())
3803             );
3804             let base = if pseudo.inherits_from_default_values() {
3805                 doc_data.default_computed_values()
3806             } else {
3807                 styles.primary()
3808             };
3809             let guards = StylesheetGuards::same(guard);
3810             let metrics = get_metrics_provider_for_product();
3811             doc_data.stylist.lazily_compute_pseudo_element_style(
3812                 &guards,
3813                 element,
3814                 &pseudo,
3815                 rule_inclusion,
3816                 base,
3817                 is_probe,
3818                 &metrics,
3819                 matching_func,
3820             )
3821         },
3822     };
3823 
3824     if is_probe {
3825         return style;
3826     }
3827 
3828     Some(style.unwrap_or_else(|| {
3829         StyleBuilder::for_inheritance(
3830             doc_data.stylist.device(),
3831             Some(styles.primary()),
3832             Some(pseudo),
3833         )
3834         .build()
3835     }))
3836 }
3837 
3838 #[no_mangle]
Servo_ComputedValues_Inherit( raw_data: &RawServoStyleSet, pseudo: PseudoStyleType, parent_style_context: Option<&ComputedValues>, target: structs::InheritTarget, ) -> Strong<ComputedValues>3839 pub unsafe extern "C" fn Servo_ComputedValues_Inherit(
3840     raw_data: &RawServoStyleSet,
3841     pseudo: PseudoStyleType,
3842     parent_style_context: Option<&ComputedValues>,
3843     target: structs::InheritTarget,
3844 ) -> Strong<ComputedValues> {
3845     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
3846 
3847     let for_text = target == structs::InheritTarget::Text;
3848     let pseudo = PseudoElement::from_pseudo_type(pseudo).unwrap();
3849     debug_assert!(pseudo.is_anon_box());
3850 
3851     let mut style =
3852         StyleBuilder::for_inheritance(data.stylist.device(), parent_style_context, Some(&pseudo));
3853 
3854     if for_text {
3855         StyleAdjuster::new(&mut style).adjust_for_text();
3856     }
3857 
3858     style.build().into()
3859 }
3860 
3861 #[no_mangle]
Servo_ComputedValues_SpecifiesAnimationsOrTransitions( values: &ComputedValues, ) -> bool3862 pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions(
3863     values: &ComputedValues,
3864 ) -> bool {
3865     let b = values.get_box();
3866     b.specifies_animations() || b.specifies_transitions()
3867 }
3868 
3869 #[no_mangle]
Servo_ComputedValues_GetStyleRuleList( values: &ComputedValues, rules: &mut nsTArray<*const RawServoStyleRule>, )3870 pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
3871     values: &ComputedValues,
3872     rules: &mut nsTArray<*const RawServoStyleRule>,
3873 ) {
3874     let rule_node = match values.rules {
3875         Some(ref r) => r,
3876         None => return,
3877     };
3878 
3879     let mut result = SmallVec::<[_; 10]>::new();
3880     for node in rule_node.self_and_ancestors() {
3881         let style_rule = match node.style_source().and_then(|x| x.as_rule()) {
3882             Some(rule) => rule,
3883             _ => continue,
3884         };
3885 
3886         // For the rules with any important declaration, we insert them into
3887         // rule tree twice, one for normal level and another for important
3888         // level. So, we skip the important one to keep the specificity order of
3889         // rules.
3890         if node.importance().important() {
3891             continue;
3892         }
3893 
3894         result.push(style_rule);
3895     }
3896 
3897     rules.assign_from_iter_pod(result.into_iter().map(|src| {
3898         src.with_arc(|a| {
3899             a.with_raw_offset_arc(|arc| *Locked::<StyleRule>::arc_as_borrowed(arc) as *const _)
3900         })
3901     }))
3902 }
3903 
3904 /// println_stderr!() calls Gecko's printf_stderr(), which, unlike eprintln!(),
3905 /// will funnel output to Android logcat.
3906 #[cfg(feature = "gecko_debug")]
3907 macro_rules! println_stderr {
3908     ($($e:expr),+) => {
3909         {
3910             let mut s = nsCString::new();
3911             write!(s, $($e),+).unwrap();
3912             s.write_char('\n').unwrap();
3913             unsafe { bindings::Gecko_PrintfStderr(&s); }
3914         }
3915     }
3916 }
3917 
3918 #[cfg(feature = "gecko_debug")]
dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet)3919 fn dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet) {
3920     println_stderr!("  Properties:");
3921     for p in properties.iter() {
3922         let mut v = String::new();
3923         cv.get_longhand_property_value(p, &mut CssWriter::new(&mut v))
3924             .unwrap();
3925         println_stderr!("    {:?}: {}", p, v);
3926     }
3927     println_stderr!("  Rules:");
3928     let global_style_data = &*GLOBAL_STYLE_DATA;
3929     let guard = global_style_data.shared_lock.read();
3930     for rn in cv.rules().self_and_ancestors() {
3931         if rn.importance().important() {
3932             continue;
3933         }
3934         if let Some(d) = rn.style_source().and_then(|s| s.as_declarations()) {
3935             println_stderr!("    [DeclarationBlock: {:?}]", d);
3936         }
3937         if let Some(r) = rn.style_source().and_then(|s| s.as_rule()) {
3938             let mut s = nsString::new();
3939             r.read_with(&guard).to_css(&guard, &mut s).unwrap();
3940             println_stderr!("    {}", s);
3941         }
3942     }
3943 }
3944 
3945 #[cfg(feature = "gecko_debug")]
3946 #[no_mangle]
Servo_ComputedValues_EqualForCachedAnonymousContentStyle( a: &ComputedValues, b: &ComputedValues, ) -> bool3947 pub extern "C" fn Servo_ComputedValues_EqualForCachedAnonymousContentStyle(
3948     a: &ComputedValues,
3949     b: &ComputedValues,
3950 ) -> bool {
3951     let mut differing_properties = a.differing_properties(b);
3952 
3953     // Ignore any difference in -x-lang, which we can't override in the
3954     // rules in minimal-xul.css, but which makes no difference for the
3955     // anonymous content subtrees we cache style for.
3956     differing_properties.remove(LonghandId::XLang);
3957 
3958     // Ignore any difference in pref-controlled, inherited properties.  These
3959     // properties may or may not be set by the 'all' declaration in the
3960     // minimal-xul.css rule, depending on whether the pref was enabled at the
3961     // time the UA sheets were parsed.
3962     //
3963     // If you add a new pref-controlled, inherited property, it must be defined
3964     // with `has_effect_on_gecko_scrollbars=False` to declare that
3965     // different values of this property on a <scrollbar> element or its
3966     // descendant scrollbar part elements should have no effect on their
3967     // rendering and behavior.
3968     //
3969     // If you do need a pref-controlled, inherited property to have an effect
3970     // on these elements, then you will need to add some checks to the
3971     // nsIAnonymousContentCreator::CreateAnonymousContent implementations of
3972     // ScrollFrameHelper and nsScrollbarFrame to clear the AnonymousContentKey
3973     // if a non-initial value is used.
3974     differing_properties.remove_all(&LonghandIdSet::has_no_effect_on_gecko_scrollbars());
3975 
3976     if !differing_properties.is_empty() {
3977         println_stderr!("Actual style:");
3978         dump_properties_and_rules(a, &differing_properties);
3979         println_stderr!("Expected style:");
3980         dump_properties_and_rules(b, &differing_properties);
3981     }
3982 
3983     differing_properties.is_empty()
3984 }
3985 
3986 #[no_mangle]
Servo_StyleSet_Init(doc: &structs::Document) -> *mut RawServoStyleSet3987 pub extern "C" fn Servo_StyleSet_Init(doc: &structs::Document) -> *mut RawServoStyleSet {
3988     let data = Box::new(PerDocumentStyleData::new(doc));
3989 
3990     // Do this here rather than in Servo_Initialize since we need a document to
3991     // get the default computed values from.
3992     style::gecko_properties::assert_initial_values_match(&data);
3993 
3994     Box::into_raw(data) as *mut RawServoStyleSet
3995 }
3996 
3997 #[no_mangle]
Servo_StyleSet_RebuildCachedData(raw_data: &RawServoStyleSet)3998 pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: &RawServoStyleSet) {
3999     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
4000     data.stylist.device_mut().rebuild_cached_data();
4001 }
4002 
4003 #[no_mangle]
Servo_StyleSet_Drop(data: *mut RawServoStyleSet)4004 pub unsafe extern "C" fn Servo_StyleSet_Drop(data: *mut RawServoStyleSet) {
4005     PerDocumentStyleData::drop_ffi(data);
4006 }
4007 
4008 #[no_mangle]
Servo_StyleSet_CompatModeChanged(raw_data: &RawServoStyleSet)4009 pub unsafe extern "C" fn Servo_StyleSet_CompatModeChanged(raw_data: &RawServoStyleSet) {
4010     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
4011     let quirks_mode = data.stylist.device().document().mCompatMode;
4012     data.stylist.set_quirks_mode(quirks_mode.into());
4013 }
4014 
parse_property_into( declarations: &mut SourcePropertyDeclaration, property_id: PropertyId, value: &nsACString, data: *mut URLExtraData, parsing_mode: structs::ParsingMode, quirks_mode: QuirksMode, reporter: Option<&dyn ParseErrorReporter>, ) -> Result<(), ()>4015 fn parse_property_into(
4016     declarations: &mut SourcePropertyDeclaration,
4017     property_id: PropertyId,
4018     value: &nsACString,
4019     data: *mut URLExtraData,
4020     parsing_mode: structs::ParsingMode,
4021     quirks_mode: QuirksMode,
4022     reporter: Option<&dyn ParseErrorReporter>,
4023 ) -> Result<(), ()> {
4024     let value = unsafe { value.as_str_unchecked() };
4025     let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
4026     let parsing_mode = ParsingMode::from_bits_truncate(parsing_mode);
4027 
4028     parse_one_declaration_into(
4029         declarations,
4030         property_id,
4031         value,
4032         url_data,
4033         reporter,
4034         parsing_mode,
4035         quirks_mode,
4036     )
4037 }
4038 
4039 #[no_mangle]
Servo_ParseProperty( property: nsCSSPropertyID, value: &nsACString, data: *mut URLExtraData, parsing_mode: structs::ParsingMode, quirks_mode: nsCompatibility, loader: *mut Loader, ) -> Strong<RawServoDeclarationBlock>4040 pub extern "C" fn Servo_ParseProperty(
4041     property: nsCSSPropertyID,
4042     value: &nsACString,
4043     data: *mut URLExtraData,
4044     parsing_mode: structs::ParsingMode,
4045     quirks_mode: nsCompatibility,
4046     loader: *mut Loader,
4047 ) -> Strong<RawServoDeclarationBlock> {
4048     let id = get_property_id_from_nscsspropertyid!(property, Strong::null());
4049     let mut declarations = SourcePropertyDeclaration::new();
4050     let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
4051     let result = parse_property_into(
4052         &mut declarations,
4053         id,
4054         value,
4055         data,
4056         parsing_mode,
4057         quirks_mode.into(),
4058         reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4059     );
4060 
4061     match result {
4062         Ok(()) => {
4063             let global_style_data = &*GLOBAL_STYLE_DATA;
4064             let mut block = PropertyDeclarationBlock::new();
4065             block.extend(declarations.drain(), Importance::Normal);
4066             Arc::new(global_style_data.shared_lock.wrap(block)).into_strong()
4067         },
4068         Err(_) => Strong::null(),
4069     }
4070 }
4071 
4072 #[no_mangle]
Servo_ParseEasing( easing: &nsAString, data: *mut URLExtraData, output: &mut nsTimingFunction, ) -> bool4073 pub extern "C" fn Servo_ParseEasing(
4074     easing: &nsAString,
4075     data: *mut URLExtraData,
4076     output: &mut nsTimingFunction,
4077 ) -> bool {
4078     use style::properties::longhands::transition_timing_function;
4079 
4080     // FIXME Dummy URL data would work fine here.
4081     let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
4082     let context = ParserContext::new(
4083         Origin::Author,
4084         url_data,
4085         Some(CssRuleType::Style),
4086         ParsingMode::DEFAULT,
4087         QuirksMode::NoQuirks,
4088         None,
4089         None,
4090     );
4091     let easing = easing.to_string();
4092     let mut input = ParserInput::new(&easing);
4093     let mut parser = Parser::new(&mut input);
4094     let result =
4095         parser.parse_entirely(|p| transition_timing_function::single_value::parse(&context, p));
4096     match result {
4097         Ok(parsed_easing) => {
4098             // We store as computed value in nsTimingFunction.
4099             (*output).mTiming = parsed_easing.to_computed_value_without_context();
4100             true
4101         },
4102         Err(_) => false,
4103     }
4104 }
4105 
4106 #[no_mangle]
Servo_SerializeEasing(easing: &nsTimingFunction, output: &mut nsAString)4107 pub extern "C" fn Servo_SerializeEasing(easing: &nsTimingFunction, output: &mut nsAString) {
4108     easing.mTiming.to_css(&mut CssWriter::new(output)).unwrap();
4109 }
4110 
4111 #[no_mangle]
Servo_GetProperties_Overriding_Animation( element: &RawGeckoElement, list: &nsTArray<nsCSSPropertyID>, set: &mut structs::nsCSSPropertyIDSet, )4112 pub extern "C" fn Servo_GetProperties_Overriding_Animation(
4113     element: &RawGeckoElement,
4114     list: &nsTArray<nsCSSPropertyID>,
4115     set: &mut structs::nsCSSPropertyIDSet,
4116 ) {
4117     let element = GeckoElement(element);
4118     let element_data = match element.borrow_data() {
4119         Some(data) => data,
4120         None => return,
4121     };
4122     let global_style_data = &*GLOBAL_STYLE_DATA;
4123     let guard = global_style_data.shared_lock.read();
4124     let guards = StylesheetGuards::same(&guard);
4125     let (overridden, custom) = element_data
4126         .styles
4127         .primary()
4128         .rules()
4129         .get_properties_overriding_animations(&guards);
4130     for p in list.iter() {
4131         match PropertyId::from_nscsspropertyid(*p) {
4132             Ok(property) => {
4133                 if let PropertyId::Longhand(id) = property {
4134                     if overridden.contains(id) {
4135                         unsafe { Gecko_AddPropertyToSet(set, *p) };
4136                     }
4137                 }
4138             },
4139             Err(_) => {
4140                 if *p == nsCSSPropertyID::eCSSPropertyExtra_variable && custom {
4141                     unsafe { Gecko_AddPropertyToSet(set, *p) };
4142                 }
4143             },
4144         }
4145     }
4146 }
4147 
4148 #[no_mangle]
Servo_MatrixTransform_Operate( matrix_operator: MatrixTransformOperator, from: *const structs::Matrix4x4Components, to: *const structs::Matrix4x4Components, progress: f64, output: *mut structs::Matrix4x4Components, )4149 pub extern "C" fn Servo_MatrixTransform_Operate(
4150     matrix_operator: MatrixTransformOperator,
4151     from: *const structs::Matrix4x4Components,
4152     to: *const structs::Matrix4x4Components,
4153     progress: f64,
4154     output: *mut structs::Matrix4x4Components,
4155 ) {
4156     use self::MatrixTransformOperator::{Accumulate, Interpolate};
4157     use style::values::computed::transform::Matrix3D;
4158 
4159     let from = Matrix3D::from(unsafe { from.as_ref() }.expect("not a valid 'from' matrix"));
4160     let to = Matrix3D::from(unsafe { to.as_ref() }.expect("not a valid 'to' matrix"));
4161     let result = match matrix_operator {
4162         Interpolate => from.animate(&to, Procedure::Interpolate { progress }),
4163         Accumulate => from.animate(
4164             &to,
4165             Procedure::Accumulate {
4166                 count: progress as u64,
4167             },
4168         ),
4169     };
4170 
4171     let output = unsafe { output.as_mut() }.expect("not a valid 'output' matrix");
4172     if let Ok(result) = result {
4173         *output = result.into();
4174     } else if progress < 0.5 {
4175         *output = from.clone().into();
4176     } else {
4177         *output = to.clone().into();
4178     }
4179 }
4180 
4181 #[no_mangle]
Servo_ParseStyleAttribute( data: &nsACString, raw_extra_data: *mut URLExtraData, quirks_mode: nsCompatibility, loader: *mut Loader, ) -> Strong<RawServoDeclarationBlock>4182 pub unsafe extern "C" fn Servo_ParseStyleAttribute(
4183     data: &nsACString,
4184     raw_extra_data: *mut URLExtraData,
4185     quirks_mode: nsCompatibility,
4186     loader: *mut Loader,
4187 ) -> Strong<RawServoDeclarationBlock> {
4188     let global_style_data = &*GLOBAL_STYLE_DATA;
4189     let value = data.as_str_unchecked();
4190     let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data);
4191     let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
4192     Arc::new(global_style_data.shared_lock.wrap(parse_style_attribute(
4193         value,
4194         url_data,
4195         reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4196         quirks_mode.into(),
4197     )))
4198     .into_strong()
4199 }
4200 
4201 #[no_mangle]
Servo_DeclarationBlock_CreateEmpty() -> Strong<RawServoDeclarationBlock>4202 pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> Strong<RawServoDeclarationBlock> {
4203     let global_style_data = &*GLOBAL_STYLE_DATA;
4204     Arc::new(
4205         global_style_data
4206             .shared_lock
4207             .wrap(PropertyDeclarationBlock::new()),
4208     )
4209     .into_strong()
4210 }
4211 
4212 #[no_mangle]
Servo_DeclarationBlock_Clone( declarations: &RawServoDeclarationBlock, ) -> Strong<RawServoDeclarationBlock>4213 pub extern "C" fn Servo_DeclarationBlock_Clone(
4214     declarations: &RawServoDeclarationBlock,
4215 ) -> Strong<RawServoDeclarationBlock> {
4216     let global_style_data = &*GLOBAL_STYLE_DATA;
4217     let guard = global_style_data.shared_lock.read();
4218     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
4219     Arc::new(
4220         global_style_data
4221             .shared_lock
4222             .wrap(declarations.read_with(&guard).clone()),
4223     )
4224     .into_strong()
4225 }
4226 
4227 #[no_mangle]
Servo_DeclarationBlock_Equals( a: &RawServoDeclarationBlock, b: &RawServoDeclarationBlock, ) -> bool4228 pub extern "C" fn Servo_DeclarationBlock_Equals(
4229     a: &RawServoDeclarationBlock,
4230     b: &RawServoDeclarationBlock,
4231 ) -> bool {
4232     let global_style_data = &*GLOBAL_STYLE_DATA;
4233     let guard = global_style_data.shared_lock.read();
4234     *Locked::<PropertyDeclarationBlock>::as_arc(&a)
4235         .read_with(&guard)
4236         .declarations() ==
4237         *Locked::<PropertyDeclarationBlock>::as_arc(&b)
4238             .read_with(&guard)
4239             .declarations()
4240 }
4241 
4242 #[no_mangle]
Servo_DeclarationBlock_GetCssText( declarations: &RawServoDeclarationBlock, result: &mut nsAString, )4243 pub extern "C" fn Servo_DeclarationBlock_GetCssText(
4244     declarations: &RawServoDeclarationBlock,
4245     result: &mut nsAString,
4246 ) {
4247     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4248         decls.to_css(result).unwrap()
4249     })
4250 }
4251 
4252 #[no_mangle]
Servo_DeclarationBlock_SerializeOneValue( declarations: &RawServoDeclarationBlock, property_id: nsCSSPropertyID, buffer: &mut nsAString, computed_values: Option<&ComputedValues>, custom_properties: Option<&RawServoDeclarationBlock>, raw_data: &RawServoStyleSet, )4253 pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
4254     declarations: &RawServoDeclarationBlock,
4255     property_id: nsCSSPropertyID,
4256     buffer: &mut nsAString,
4257     computed_values: Option<&ComputedValues>,
4258     custom_properties: Option<&RawServoDeclarationBlock>,
4259     raw_data: &RawServoStyleSet,
4260 ) {
4261     let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
4262 
4263     let global_style_data = &*GLOBAL_STYLE_DATA;
4264     let guard = global_style_data.shared_lock.read();
4265     let decls = Locked::<PropertyDeclarationBlock>::as_arc(&declarations).read_with(&guard);
4266 
4267     let custom_properties =
4268         Locked::<PropertyDeclarationBlock>::arc_from_borrowed(&custom_properties);
4269     let custom_properties = custom_properties.map(|block| block.read_with(&guard));
4270     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
4271     let rv = decls.single_value_to_css(&property_id, buffer, computed_values, custom_properties, &data.stylist.device());
4272     debug_assert!(rv.is_ok());
4273 }
4274 
4275 #[no_mangle]
Servo_SerializeFontValueForCanvas( declarations: &RawServoDeclarationBlock, buffer: &mut nsAString, )4276 pub unsafe extern "C" fn Servo_SerializeFontValueForCanvas(
4277     declarations: &RawServoDeclarationBlock,
4278     buffer: &mut nsAString,
4279 ) {
4280     use style::properties::shorthands::font;
4281     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4282         let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) {
4283             Ok(l) => l,
4284             Err(()) => {
4285                 warn!("Unexpected property!");
4286                 return;
4287             },
4288         };
4289 
4290         let rv = longhands.to_css(&mut CssWriter::new(buffer));
4291         debug_assert!(rv.is_ok());
4292     })
4293 }
4294 
4295 #[no_mangle]
Servo_DeclarationBlock_Count(declarations: &RawServoDeclarationBlock) -> u324296 pub extern "C" fn Servo_DeclarationBlock_Count(declarations: &RawServoDeclarationBlock) -> u32 {
4297     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4298         decls.declarations().len() as u32
4299     })
4300 }
4301 
4302 #[no_mangle]
Servo_DeclarationBlock_GetNthProperty( declarations: &RawServoDeclarationBlock, index: u32, result: &mut nsACString, ) -> bool4303 pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(
4304     declarations: &RawServoDeclarationBlock,
4305     index: u32,
4306     result: &mut nsACString,
4307 ) -> bool {
4308     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4309         if let Some(decl) = decls.declarations().get(index as usize) {
4310             result.assign(&decl.id().name());
4311             true
4312         } else {
4313             false
4314         }
4315     })
4316 }
4317 
4318 macro_rules! get_property_id_from_property {
4319     ($property: ident, $ret: expr) => {{
4320         let property = $property.as_str_unchecked();
4321         match PropertyId::parse_enabled_for_all_content(property) {
4322             Ok(property_id) => property_id,
4323             Err(_) => return $ret,
4324         }
4325     }};
4326 }
4327 
get_property_value( declarations: &RawServoDeclarationBlock, property_id: PropertyId, value: &mut nsAString, )4328 unsafe fn get_property_value(
4329     declarations: &RawServoDeclarationBlock,
4330     property_id: PropertyId,
4331     value: &mut nsAString,
4332 ) {
4333     // This callsite is hot enough that the lock acquisition shows up in profiles.
4334     // Using an unchecked read here improves our performance by ~10% on the
4335     // microbenchmark in bug 1355599.
4336     read_locked_arc_unchecked(declarations, |decls: &PropertyDeclarationBlock| {
4337         decls.property_value_to_css(&property_id, value).unwrap();
4338     })
4339 }
4340 
4341 #[no_mangle]
Servo_DeclarationBlock_GetPropertyValue( declarations: &RawServoDeclarationBlock, property: &nsACString, value: &mut nsAString, )4342 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValue(
4343     declarations: &RawServoDeclarationBlock,
4344     property: &nsACString,
4345     value: &mut nsAString,
4346 ) {
4347     get_property_value(
4348         declarations,
4349         get_property_id_from_property!(property, ()),
4350         value,
4351     )
4352 }
4353 
4354 #[no_mangle]
Servo_DeclarationBlock_GetPropertyValueById( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: &mut nsAString, )4355 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(
4356     declarations: &RawServoDeclarationBlock,
4357     property: nsCSSPropertyID,
4358     value: &mut nsAString,
4359 ) {
4360     get_property_value(
4361         declarations,
4362         get_property_id_from_nscsspropertyid!(property, ()),
4363         value,
4364     )
4365 }
4366 
4367 #[no_mangle]
Servo_DeclarationBlock_GetPropertyIsImportant( declarations: &RawServoDeclarationBlock, property: &nsACString, ) -> bool4368 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(
4369     declarations: &RawServoDeclarationBlock,
4370     property: &nsACString,
4371 ) -> bool {
4372     let property_id = get_property_id_from_property!(property, false);
4373     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4374         decls.property_priority(&property_id).important()
4375     })
4376 }
4377 
4378 #[inline(always)]
set_property_to_declarations( block: &RawServoDeclarationBlock, parsed_declarations: &mut SourcePropertyDeclaration, before_change_closure: DeclarationBlockMutationClosure, importance: Importance, ) -> bool4379 fn set_property_to_declarations(
4380     block: &RawServoDeclarationBlock,
4381     parsed_declarations: &mut SourcePropertyDeclaration,
4382     before_change_closure: DeclarationBlockMutationClosure,
4383     importance: Importance,
4384 ) -> bool {
4385     let mut updates = Default::default();
4386     let will_change = read_locked_arc(block, |decls: &PropertyDeclarationBlock| {
4387         decls.prepare_for_update(&parsed_declarations, importance, &mut updates)
4388     });
4389     if !will_change {
4390         return false;
4391     }
4392 
4393     before_change_closure.invoke();
4394     write_locked_arc(block, |decls: &mut PropertyDeclarationBlock| {
4395         decls.update(parsed_declarations.drain(), importance, &mut updates)
4396     });
4397     true
4398 }
4399 
set_property( declarations: &RawServoDeclarationBlock, property_id: PropertyId, value: &nsACString, is_important: bool, data: *mut URLExtraData, parsing_mode: structs::ParsingMode, quirks_mode: QuirksMode, loader: *mut Loader, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4400 fn set_property(
4401     declarations: &RawServoDeclarationBlock,
4402     property_id: PropertyId,
4403     value: &nsACString,
4404     is_important: bool,
4405     data: *mut URLExtraData,
4406     parsing_mode: structs::ParsingMode,
4407     quirks_mode: QuirksMode,
4408     loader: *mut Loader,
4409     before_change_closure: DeclarationBlockMutationClosure,
4410 ) -> bool {
4411     let mut source_declarations = SourcePropertyDeclaration::new();
4412     let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
4413     let result = parse_property_into(
4414         &mut source_declarations,
4415         property_id,
4416         value,
4417         data,
4418         parsing_mode,
4419         quirks_mode,
4420         reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4421     );
4422 
4423     if result.is_err() {
4424         return false;
4425     }
4426 
4427     let importance = if is_important {
4428         Importance::Important
4429     } else {
4430         Importance::Normal
4431     };
4432 
4433     set_property_to_declarations(
4434         declarations,
4435         &mut source_declarations,
4436         before_change_closure,
4437         importance,
4438     )
4439 }
4440 
4441 #[no_mangle]
Servo_DeclarationBlock_SetProperty( declarations: &RawServoDeclarationBlock, property: &nsACString, value: &nsACString, is_important: bool, data: *mut URLExtraData, parsing_mode: structs::ParsingMode, quirks_mode: nsCompatibility, loader: *mut Loader, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4442 pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
4443     declarations: &RawServoDeclarationBlock,
4444     property: &nsACString,
4445     value: &nsACString,
4446     is_important: bool,
4447     data: *mut URLExtraData,
4448     parsing_mode: structs::ParsingMode,
4449     quirks_mode: nsCompatibility,
4450     loader: *mut Loader,
4451     before_change_closure: DeclarationBlockMutationClosure,
4452 ) -> bool {
4453     set_property(
4454         declarations,
4455         get_property_id_from_property!(property, false),
4456         value,
4457         is_important,
4458         data,
4459         parsing_mode,
4460         quirks_mode.into(),
4461         loader,
4462         before_change_closure,
4463     )
4464 }
4465 
4466 #[no_mangle]
Servo_DeclarationBlock_SetPropertyToAnimationValue( declarations: &RawServoDeclarationBlock, animation_value: &RawServoAnimationValue, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4467 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
4468     declarations: &RawServoDeclarationBlock,
4469     animation_value: &RawServoAnimationValue,
4470     before_change_closure: DeclarationBlockMutationClosure,
4471 ) -> bool {
4472     let mut source_declarations =
4473         SourcePropertyDeclaration::with_one(AnimationValue::as_arc(&animation_value).uncompute());
4474 
4475     set_property_to_declarations(
4476         declarations,
4477         &mut source_declarations,
4478         before_change_closure,
4479         Importance::Normal,
4480     )
4481 }
4482 
4483 #[no_mangle]
Servo_DeclarationBlock_SetPropertyById( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: &nsACString, is_important: bool, data: *mut URLExtraData, parsing_mode: structs::ParsingMode, quirks_mode: nsCompatibility, loader: *mut Loader, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4484 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
4485     declarations: &RawServoDeclarationBlock,
4486     property: nsCSSPropertyID,
4487     value: &nsACString,
4488     is_important: bool,
4489     data: *mut URLExtraData,
4490     parsing_mode: structs::ParsingMode,
4491     quirks_mode: nsCompatibility,
4492     loader: *mut Loader,
4493     before_change_closure: DeclarationBlockMutationClosure,
4494 ) -> bool {
4495     set_property(
4496         declarations,
4497         get_property_id_from_nscsspropertyid!(property, false),
4498         value,
4499         is_important,
4500         data,
4501         parsing_mode,
4502         quirks_mode.into(),
4503         loader,
4504         before_change_closure,
4505     )
4506 }
4507 
remove_property( declarations: &RawServoDeclarationBlock, property_id: PropertyId, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4508 fn remove_property(
4509     declarations: &RawServoDeclarationBlock,
4510     property_id: PropertyId,
4511     before_change_closure: DeclarationBlockMutationClosure,
4512 ) -> bool {
4513     let first_declaration = read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4514         decls.first_declaration_to_remove(&property_id)
4515     });
4516 
4517     let first_declaration = match first_declaration {
4518         Some(i) => i,
4519         None => return false,
4520     };
4521 
4522     before_change_closure.invoke();
4523     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4524         decls.remove_property(&property_id, first_declaration)
4525     });
4526 
4527     true
4528 }
4529 
4530 #[no_mangle]
Servo_DeclarationBlock_RemoveProperty( declarations: &RawServoDeclarationBlock, property: &nsACString, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4531 pub unsafe extern "C" fn Servo_DeclarationBlock_RemoveProperty(
4532     declarations: &RawServoDeclarationBlock,
4533     property: &nsACString,
4534     before_change_closure: DeclarationBlockMutationClosure,
4535 ) -> bool {
4536     remove_property(
4537         declarations,
4538         get_property_id_from_property!(property, false),
4539         before_change_closure,
4540     )
4541 }
4542 
4543 #[no_mangle]
Servo_DeclarationBlock_RemovePropertyById( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4544 pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(
4545     declarations: &RawServoDeclarationBlock,
4546     property: nsCSSPropertyID,
4547     before_change_closure: DeclarationBlockMutationClosure,
4548 ) -> bool {
4549     remove_property(
4550         declarations,
4551         get_property_id_from_nscsspropertyid!(property, false),
4552         before_change_closure,
4553     )
4554 }
4555 
4556 #[no_mangle]
Servo_MediaList_Create() -> Strong<RawServoMediaList>4557 pub extern "C" fn Servo_MediaList_Create() -> Strong<RawServoMediaList> {
4558     let global_style_data = &*GLOBAL_STYLE_DATA;
4559     Arc::new(global_style_data.shared_lock.wrap(MediaList::empty())).into_strong()
4560 }
4561 
4562 #[no_mangle]
Servo_MediaList_DeepClone(list: &RawServoMediaList) -> Strong<RawServoMediaList>4563 pub extern "C" fn Servo_MediaList_DeepClone(list: &RawServoMediaList) -> Strong<RawServoMediaList> {
4564     let global_style_data = &*GLOBAL_STYLE_DATA;
4565     read_locked_arc(list, |list: &MediaList| {
4566         Arc::new(global_style_data.shared_lock.wrap(list.clone())).into_strong()
4567     })
4568 }
4569 
4570 #[no_mangle]
Servo_MediaList_Matches( list: &RawServoMediaList, raw_data: &RawServoStyleSet, ) -> bool4571 pub extern "C" fn Servo_MediaList_Matches(
4572     list: &RawServoMediaList,
4573     raw_data: &RawServoStyleSet,
4574 ) -> bool {
4575     let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
4576     read_locked_arc(list, |list: &MediaList| {
4577         list.evaluate(
4578             per_doc_data.stylist.device(),
4579             per_doc_data.stylist.quirks_mode(),
4580         )
4581     })
4582 }
4583 
4584 #[no_mangle]
Servo_DeclarationBlock_HasCSSWideKeyword( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, ) -> bool4585 pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword(
4586     declarations: &RawServoDeclarationBlock,
4587     property: nsCSSPropertyID,
4588 ) -> bool {
4589     let property_id = get_property_id_from_nscsspropertyid!(property, false);
4590     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4591         decls.has_css_wide_keyword(&property_id)
4592     })
4593 }
4594 
4595 #[no_mangle]
Servo_MediaList_GetText(list: &RawServoMediaList, result: &mut nsAString)4596 pub extern "C" fn Servo_MediaList_GetText(list: &RawServoMediaList, result: &mut nsAString) {
4597     read_locked_arc(list, |list: &MediaList| {
4598         list.to_css(&mut CssWriter::new(result)).unwrap();
4599     })
4600 }
4601 
4602 #[no_mangle]
Servo_MediaList_SetText( list: &RawServoMediaList, text: &nsACString, caller_type: CallerType, )4603 pub unsafe extern "C" fn Servo_MediaList_SetText(
4604     list: &RawServoMediaList,
4605     text: &nsACString,
4606     caller_type: CallerType,
4607 ) {
4608     let text = text.as_str_unchecked();
4609 
4610     let mut input = ParserInput::new(&text);
4611     let mut parser = Parser::new(&mut input);
4612     let url_data = dummy_url_data();
4613 
4614     // TODO(emilio): If the need for `CallerType` appears in more places,
4615     // consider adding an explicit member in `ParserContext` instead of doing
4616     // this (or adding a dummy "chrome://" url data).
4617     //
4618     // For media query parsing it's effectively the same, so for now...
4619     let origin = match caller_type {
4620         CallerType::System => Origin::UserAgent,
4621         CallerType::NonSystem => Origin::Author,
4622     };
4623 
4624     let context = ParserContext::new(
4625         origin,
4626         url_data,
4627         Some(CssRuleType::Media),
4628         ParsingMode::DEFAULT,
4629         QuirksMode::NoQuirks,
4630         // TODO(emilio): Looks like error reporting could be useful here?
4631         None,
4632         None,
4633     );
4634 
4635     write_locked_arc(list, |list: &mut MediaList| {
4636         *list = MediaList::parse(&context, &mut parser);
4637     })
4638 }
4639 
4640 #[no_mangle]
Servo_MediaList_GetLength(list: &RawServoMediaList) -> u324641 pub extern "C" fn Servo_MediaList_GetLength(list: &RawServoMediaList) -> u32 {
4642     read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32)
4643 }
4644 
4645 #[no_mangle]
Servo_MediaList_GetMediumAt( list: &RawServoMediaList, index: u32, result: &mut nsAString, ) -> bool4646 pub extern "C" fn Servo_MediaList_GetMediumAt(
4647     list: &RawServoMediaList,
4648     index: u32,
4649     result: &mut nsAString,
4650 ) -> bool {
4651     read_locked_arc(list, |list: &MediaList| {
4652         let media_query = match list.media_queries.get(index as usize) {
4653             Some(mq) => mq,
4654             None => return false,
4655         };
4656         media_query.to_css(&mut CssWriter::new(result)).unwrap();
4657         true
4658     })
4659 }
4660 
4661 #[no_mangle]
Servo_MediaList_AppendMedium( list: &RawServoMediaList, new_medium: &nsACString, )4662 pub extern "C" fn Servo_MediaList_AppendMedium(
4663     list: &RawServoMediaList,
4664     new_medium: &nsACString,
4665 ) {
4666     let new_medium = unsafe { new_medium.as_str_unchecked() };
4667     let url_data = unsafe { dummy_url_data() };
4668     let context = ParserContext::new_for_cssom(
4669         url_data,
4670         Some(CssRuleType::Media),
4671         ParsingMode::DEFAULT,
4672         QuirksMode::NoQuirks,
4673         None,
4674         None,
4675     );
4676     write_locked_arc(list, |list: &mut MediaList| {
4677         list.append_medium(&context, new_medium);
4678     })
4679 }
4680 
4681 #[no_mangle]
Servo_MediaList_DeleteMedium( list: &RawServoMediaList, old_medium: &nsACString, ) -> bool4682 pub extern "C" fn Servo_MediaList_DeleteMedium(
4683     list: &RawServoMediaList,
4684     old_medium: &nsACString,
4685 ) -> bool {
4686     let old_medium = unsafe { old_medium.as_str_unchecked() };
4687     let url_data = unsafe { dummy_url_data() };
4688     let context = ParserContext::new_for_cssom(
4689         url_data,
4690         Some(CssRuleType::Media),
4691         ParsingMode::DEFAULT,
4692         QuirksMode::NoQuirks,
4693         None,
4694         None,
4695     );
4696     write_locked_arc(list, |list: &mut MediaList| {
4697         list.delete_medium(&context, old_medium)
4698     })
4699 }
4700 
4701 #[no_mangle]
Servo_MediaList_SizeOfIncludingThis( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, list: &RawServoMediaList, ) -> usize4702 pub extern "C" fn Servo_MediaList_SizeOfIncludingThis(
4703     malloc_size_of: GeckoMallocSizeOf,
4704     malloc_enclosing_size_of: GeckoMallocSizeOf,
4705     list: &RawServoMediaList,
4706 ) -> usize {
4707     use malloc_size_of::MallocSizeOf;
4708     use malloc_size_of::MallocUnconditionalShallowSizeOf;
4709 
4710     let global_style_data = &*GLOBAL_STYLE_DATA;
4711     let guard = global_style_data.shared_lock.read();
4712 
4713     let mut ops = MallocSizeOfOps::new(
4714         malloc_size_of.unwrap(),
4715         Some(malloc_enclosing_size_of.unwrap()),
4716         None,
4717     );
4718 
4719     Locked::<MediaList>::as_arc(&list).with_arc(|list| {
4720         let mut n = 0;
4721         n += list.unconditional_shallow_size_of(&mut ops);
4722         n += list.read_with(&guard).size_of(&mut ops);
4723         n
4724     })
4725 }
4726 
4727 macro_rules! get_longhand_from_id {
4728     ($id:expr) => {
4729         match PropertyId::from_nscsspropertyid($id) {
4730             Ok(PropertyId::Longhand(long)) => long,
4731             _ => {
4732                 panic!("stylo: unknown presentation property with id");
4733             },
4734         }
4735     };
4736 }
4737 
4738 macro_rules! match_wrap_declared {
4739     ($longhand:ident, $($property:ident => $inner:expr,)*) => (
4740         match $longhand {
4741             $(
4742                 LonghandId::$property => PropertyDeclaration::$property($inner),
4743             )*
4744             _ => {
4745                 panic!("stylo: Don't know how to handle presentation property");
4746             }
4747         }
4748     )
4749 }
4750 
4751 #[no_mangle]
Servo_DeclarationBlock_PropertyIsSet( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, ) -> bool4752 pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(
4753     declarations: &RawServoDeclarationBlock,
4754     property: nsCSSPropertyID,
4755 ) -> bool {
4756     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4757         decls.contains(get_longhand_from_id!(property))
4758     })
4759 }
4760 
4761 #[no_mangle]
Servo_DeclarationBlock_SetIdentStringValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: *mut nsAtom, )4762 pub unsafe extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(
4763     declarations: &RawServoDeclarationBlock,
4764     property: nsCSSPropertyID,
4765     value: *mut nsAtom,
4766 ) {
4767     use style::properties::longhands::_x_lang::computed_value::T as Lang;
4768     use style::properties::PropertyDeclaration;
4769 
4770     let long = get_longhand_from_id!(property);
4771     let prop = match_wrap_declared! { long,
4772         XLang => Lang(Atom::from_raw(value)),
4773     };
4774     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4775         decls.push(prop, Importance::Normal);
4776     })
4777 }
4778 
4779 #[no_mangle]
4780 #[allow(unreachable_code)]
Servo_DeclarationBlock_SetKeywordValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: i32, )4781 pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
4782     declarations: &RawServoDeclarationBlock,
4783     property: nsCSSPropertyID,
4784     value: i32,
4785 ) {
4786     use num_traits::FromPrimitive;
4787     use style::properties::longhands;
4788     use style::properties::PropertyDeclaration;
4789     use style::values::generics::box_::{VerticalAlign, VerticalAlignKeyword};
4790     use style::values::generics::font::FontStyle;
4791     use style::values::specified::{BorderStyle, Clear, Display, Float, TextAlign};
4792 
4793     fn get_from_computed<T>(value: u32) -> T
4794     where
4795         T: ToComputedValue,
4796         T::ComputedValue: FromPrimitive,
4797     {
4798         T::from_computed_value(&T::ComputedValue::from_u32(value).unwrap())
4799     }
4800 
4801     let long = get_longhand_from_id!(property);
4802     let value = value as u32;
4803 
4804     let prop = match_wrap_declared! { long,
4805         MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value),
4806         Direction => get_from_computed::<longhands::direction::SpecifiedValue>(value),
4807         Display => get_from_computed::<Display>(value),
4808         Float => get_from_computed::<Float>(value),
4809         Clear => get_from_computed::<Clear>(value),
4810         VerticalAlign => VerticalAlign::Keyword(VerticalAlignKeyword::from_u32(value).unwrap()),
4811         TextAlign => get_from_computed::<TextAlign>(value),
4812         TextEmphasisPosition => longhands::text_emphasis_position::SpecifiedValue::from_gecko_keyword(value),
4813         FontSize => {
4814             // We rely on Gecko passing in font-size values (0...7) here.
4815             longhands::font_size::SpecifiedValue::from_html_size(value as u8)
4816         },
4817         FontStyle => {
4818             let val = if value == structs::NS_FONT_STYLE_ITALIC {
4819                 FontStyle::Italic
4820             } else {
4821                 debug_assert_eq!(value, structs::NS_FONT_STYLE_NORMAL);
4822                 FontStyle::Normal
4823             };
4824 
4825             ToComputedValue::from_computed_value(&val)
4826         },
4827         FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value),
4828         ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
4829         MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
4830         WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value),
4831         CaptionSide => longhands::caption_side::SpecifiedValue::from_gecko_keyword(value),
4832         BorderTopStyle => get_from_computed::<BorderStyle>(value),
4833         BorderRightStyle => get_from_computed::<BorderStyle>(value),
4834         BorderBottomStyle => get_from_computed::<BorderStyle>(value),
4835         BorderLeftStyle => get_from_computed::<BorderStyle>(value),
4836     };
4837     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4838         decls.push(prop, Importance::Normal);
4839     })
4840 }
4841 
4842 #[no_mangle]
Servo_DeclarationBlock_SetIntValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: i32, )4843 pub extern "C" fn Servo_DeclarationBlock_SetIntValue(
4844     declarations: &RawServoDeclarationBlock,
4845     property: nsCSSPropertyID,
4846     value: i32,
4847 ) {
4848     use style::properties::longhands::_moz_script_level::SpecifiedValue as MozScriptLevel;
4849     use style::properties::PropertyDeclaration;
4850     use style::values::specified::Integer;
4851 
4852     let long = get_longhand_from_id!(property);
4853     let prop = match_wrap_declared! { long,
4854         XSpan => Integer::new(value),
4855         // Gecko uses Integer values to signal that it is relative
4856         MozScriptLevel => MozScriptLevel::Relative(value),
4857     };
4858     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4859         decls.push(prop, Importance::Normal);
4860     })
4861 }
4862 
4863 #[no_mangle]
Servo_DeclarationBlock_SetCounterResetListItem( declarations: &RawServoDeclarationBlock, counter_value: i32, )4864 pub extern "C" fn Servo_DeclarationBlock_SetCounterResetListItem(
4865     declarations: &RawServoDeclarationBlock,
4866     counter_value: i32,
4867 ) {
4868     use style::properties::PropertyDeclaration;
4869     use style::values::generics::counters::{CounterPair, CounterSetOrReset};
4870 
4871     let prop = PropertyDeclaration::CounterReset(CounterSetOrReset::new(vec![CounterPair {
4872         name: CustomIdent(atom!("list-item")),
4873         value: style::values::specified::Integer::new(counter_value),
4874     }]));
4875     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4876         decls.push(prop, Importance::Normal);
4877     })
4878 }
4879 
4880 #[no_mangle]
Servo_DeclarationBlock_SetCounterSetListItem( declarations: &RawServoDeclarationBlock, counter_value: i32, )4881 pub extern "C" fn Servo_DeclarationBlock_SetCounterSetListItem(
4882     declarations: &RawServoDeclarationBlock,
4883     counter_value: i32,
4884 ) {
4885     use style::properties::PropertyDeclaration;
4886     use style::values::generics::counters::{CounterPair, CounterSetOrReset};
4887 
4888     let prop = PropertyDeclaration::CounterSet(CounterSetOrReset::new(vec![CounterPair {
4889         name: CustomIdent(atom!("list-item")),
4890         value: style::values::specified::Integer::new(counter_value),
4891     }]));
4892     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4893         decls.push(prop, Importance::Normal);
4894     })
4895 }
4896 
4897 #[no_mangle]
Servo_DeclarationBlock_SetPixelValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: f32, )4898 pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
4899     declarations: &RawServoDeclarationBlock,
4900     property: nsCSSPropertyID,
4901     value: f32,
4902 ) {
4903     use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
4904     use style::properties::PropertyDeclaration;
4905     use style::values::generics::length::LengthPercentageOrAuto;
4906     use style::values::generics::length::Size;
4907     use style::values::generics::NonNegative;
4908     use style::values::specified::length::LengthPercentage;
4909     use style::values::specified::length::NonNegativeLengthPercentage;
4910     use style::values::specified::length::{NoCalcLength, NonNegativeLength};
4911     use style::values::specified::{BorderCornerRadius, BorderSideWidth};
4912 
4913     let long = get_longhand_from_id!(property);
4914     let nocalc = NoCalcLength::from_px(value);
4915     let lp = LengthPercentage::Length(nocalc);
4916     let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
4917     let prop = match_wrap_declared! { long,
4918         Height => Size::LengthPercentage(NonNegative(lp)),
4919         Width => Size::LengthPercentage(NonNegative(lp)),
4920         BorderTopWidth => BorderSideWidth::Length(nocalc.into()),
4921         BorderRightWidth => BorderSideWidth::Length(nocalc.into()),
4922         BorderBottomWidth => BorderSideWidth::Length(nocalc.into()),
4923         BorderLeftWidth => BorderSideWidth::Length(nocalc.into()),
4924         MarginTop => lp_or_auto,
4925         MarginRight => lp_or_auto,
4926         MarginBottom => lp_or_auto,
4927         MarginLeft => lp_or_auto,
4928         PaddingTop => NonNegative(lp),
4929         PaddingRight => NonNegative(lp),
4930         PaddingBottom => NonNegative(lp),
4931         PaddingLeft => NonNegative(lp),
4932         BorderSpacing => {
4933             let v = NonNegativeLength::from(nocalc);
4934             Box::new(BorderSpacing::new(v.clone(), v))
4935         },
4936         BorderTopLeftRadius => {
4937             let length = NonNegativeLengthPercentage::from(nocalc);
4938             Box::new(BorderCornerRadius::new(length.clone(), length))
4939         },
4940         BorderTopRightRadius => {
4941             let length = NonNegativeLengthPercentage::from(nocalc);
4942             Box::new(BorderCornerRadius::new(length.clone(), length))
4943         },
4944         BorderBottomLeftRadius => {
4945             let length = NonNegativeLengthPercentage::from(nocalc);
4946             Box::new(BorderCornerRadius::new(length.clone(), length))
4947         },
4948         BorderBottomRightRadius => {
4949             let length = NonNegativeLengthPercentage::from(nocalc);
4950             Box::new(BorderCornerRadius::new(length.clone(), length))
4951         },
4952     };
4953     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4954         decls.push(prop, Importance::Normal);
4955     })
4956 }
4957 
4958 #[no_mangle]
Servo_DeclarationBlock_SetLengthValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: f32, unit: structs::nsCSSUnit, )4959 pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
4960     declarations: &RawServoDeclarationBlock,
4961     property: nsCSSPropertyID,
4962     value: f32,
4963     unit: structs::nsCSSUnit,
4964 ) {
4965     use style::properties::longhands::_moz_script_min_size::SpecifiedValue as MozScriptMinSize;
4966     use style::properties::PropertyDeclaration;
4967     use style::values::generics::length::{LengthPercentageOrAuto, Size};
4968     use style::values::generics::NonNegative;
4969     use style::values::specified::length::{LengthPercentage, NoCalcLength};
4970     use style::values::specified::length::{AbsoluteLength, FontRelativeLength};
4971     use style::values::specified::FontSize;
4972 
4973     let long = get_longhand_from_id!(property);
4974     let nocalc = match unit {
4975         structs::nsCSSUnit::eCSSUnit_EM => {
4976             NoCalcLength::FontRelative(FontRelativeLength::Em(value))
4977         },
4978         structs::nsCSSUnit::eCSSUnit_XHeight => {
4979             NoCalcLength::FontRelative(FontRelativeLength::Ex(value))
4980         },
4981         structs::nsCSSUnit::eCSSUnit_Pixel => NoCalcLength::Absolute(AbsoluteLength::Px(value)),
4982         structs::nsCSSUnit::eCSSUnit_Inch => NoCalcLength::Absolute(AbsoluteLength::In(value)),
4983         structs::nsCSSUnit::eCSSUnit_Centimeter => {
4984             NoCalcLength::Absolute(AbsoluteLength::Cm(value))
4985         },
4986         structs::nsCSSUnit::eCSSUnit_Millimeter => {
4987             NoCalcLength::Absolute(AbsoluteLength::Mm(value))
4988         },
4989         structs::nsCSSUnit::eCSSUnit_Point => NoCalcLength::Absolute(AbsoluteLength::Pt(value)),
4990         structs::nsCSSUnit::eCSSUnit_Pica => NoCalcLength::Absolute(AbsoluteLength::Pc(value)),
4991         structs::nsCSSUnit::eCSSUnit_Quarter => NoCalcLength::Absolute(AbsoluteLength::Q(value)),
4992         _ => unreachable!("Unknown unit passed to SetLengthValue"),
4993     };
4994 
4995     let prop = match_wrap_declared! { long,
4996         Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
4997         Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
4998         X =>  LengthPercentage::Length(nocalc),
4999         Y =>  LengthPercentage::Length(nocalc),
5000         Cx => LengthPercentage::Length(nocalc),
5001         Cy => LengthPercentage::Length(nocalc),
5002         R =>  NonNegative(LengthPercentage::Length(nocalc)),
5003         Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5004         Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5005         FontSize => FontSize::Length(LengthPercentage::Length(nocalc)),
5006         MozScriptMinSize => MozScriptMinSize(nocalc),
5007     };
5008     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5009         decls.push(prop, Importance::Normal);
5010     })
5011 }
5012 
5013 #[no_mangle]
Servo_DeclarationBlock_SetNumberValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: f32, )5014 pub extern "C" fn Servo_DeclarationBlock_SetNumberValue(
5015     declarations: &RawServoDeclarationBlock,
5016     property: nsCSSPropertyID,
5017     value: f32,
5018 ) {
5019     use style::properties::longhands::_moz_script_level::SpecifiedValue as MozScriptLevel;
5020     use style::properties::longhands::_moz_script_size_multiplier::SpecifiedValue as MozScriptSizeMultiplier;
5021     use style::properties::PropertyDeclaration;
5022 
5023     let long = get_longhand_from_id!(property);
5024 
5025     let prop = match_wrap_declared! { long,
5026         MozScriptSizeMultiplier => MozScriptSizeMultiplier(value),
5027         // Gecko uses Number values to signal that it is absolute
5028         MozScriptLevel => MozScriptLevel::MozAbsolute(value as i32),
5029     };
5030     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5031         decls.push(prop, Importance::Normal);
5032     })
5033 }
5034 
5035 #[no_mangle]
Servo_DeclarationBlock_SetPercentValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: f32, )5036 pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
5037     declarations: &RawServoDeclarationBlock,
5038     property: nsCSSPropertyID,
5039     value: f32,
5040 ) {
5041     use style::properties::PropertyDeclaration;
5042     use style::values::computed::Percentage;
5043     use style::values::generics::length::{LengthPercentageOrAuto, Size};
5044     use style::values::generics::NonNegative;
5045     use style::values::specified::length::LengthPercentage;
5046     use style::values::specified::FontSize;
5047 
5048     let long = get_longhand_from_id!(property);
5049     let pc = Percentage(value);
5050     let lp = LengthPercentage::Percentage(pc);
5051     let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
5052 
5053     let prop = match_wrap_declared! { long,
5054         Height => Size::LengthPercentage(NonNegative(lp)),
5055         Width => Size::LengthPercentage(NonNegative(lp)),
5056         X =>  lp,
5057         Y =>  lp,
5058         Cx => lp,
5059         Cy => lp,
5060         R =>  NonNegative(lp),
5061         Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5062         Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5063         MarginTop => lp_or_auto,
5064         MarginRight => lp_or_auto,
5065         MarginBottom => lp_or_auto,
5066         MarginLeft => lp_or_auto,
5067         FontSize => FontSize::Length(LengthPercentage::Percentage(pc)),
5068     };
5069     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5070         decls.push(prop, Importance::Normal);
5071     })
5072 }
5073 
5074 #[no_mangle]
Servo_DeclarationBlock_SetAutoValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, )5075 pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(
5076     declarations: &RawServoDeclarationBlock,
5077     property: nsCSSPropertyID,
5078 ) {
5079     use style::properties::PropertyDeclaration;
5080     use style::values::generics::length::{LengthPercentageOrAuto, Size};
5081 
5082     let long = get_longhand_from_id!(property);
5083     let auto = LengthPercentageOrAuto::Auto;
5084 
5085     let prop = match_wrap_declared! { long,
5086         Height => Size::auto(),
5087         Width => Size::auto(),
5088         MarginTop => auto,
5089         MarginRight => auto,
5090         MarginBottom => auto,
5091         MarginLeft => auto,
5092     };
5093     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5094         decls.push(prop, Importance::Normal);
5095     })
5096 }
5097 
5098 #[no_mangle]
Servo_DeclarationBlock_SetCurrentColor( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, )5099 pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(
5100     declarations: &RawServoDeclarationBlock,
5101     property: nsCSSPropertyID,
5102 ) {
5103     use style::properties::PropertyDeclaration;
5104     use style::values::specified::Color;
5105 
5106     let long = get_longhand_from_id!(property);
5107     let cc = Color::currentcolor();
5108 
5109     let prop = match_wrap_declared! { long,
5110         BorderTopColor => cc,
5111         BorderRightColor => cc,
5112         BorderBottomColor => cc,
5113         BorderLeftColor => cc,
5114     };
5115     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5116         decls.push(prop, Importance::Normal);
5117     })
5118 }
5119 
5120 #[no_mangle]
Servo_DeclarationBlock_SetColorValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: structs::nscolor, )5121 pub extern "C" fn Servo_DeclarationBlock_SetColorValue(
5122     declarations: &RawServoDeclarationBlock,
5123     property: nsCSSPropertyID,
5124     value: structs::nscolor,
5125 ) {
5126     use style::gecko::values::convert_nscolor_to_rgba;
5127     use style::properties::longhands;
5128     use style::properties::PropertyDeclaration;
5129     use style::values::specified::Color;
5130 
5131     let long = get_longhand_from_id!(property);
5132     let rgba = convert_nscolor_to_rgba(value);
5133     let color = Color::rgba(rgba);
5134 
5135     let prop = match_wrap_declared! { long,
5136         BorderTopColor => color,
5137         BorderRightColor => color,
5138         BorderBottomColor => color,
5139         BorderLeftColor => color,
5140         Color => longhands::color::SpecifiedValue(color),
5141         BackgroundColor => color,
5142     };
5143     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5144         decls.push(prop, Importance::Normal);
5145     })
5146 }
5147 
5148 #[no_mangle]
Servo_DeclarationBlock_SetFontFamily( declarations: &RawServoDeclarationBlock, value: &nsAString, )5149 pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(
5150     declarations: &RawServoDeclarationBlock,
5151     value: &nsAString,
5152 ) {
5153     use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
5154     use style::properties::PropertyDeclaration;
5155 
5156     let string = value.to_string();
5157     let mut input = ParserInput::new(&string);
5158     let mut parser = Parser::new(&mut input);
5159     let result = FontFamily::parse_specified(&mut parser);
5160     if let Ok(family) = result {
5161         if parser.is_exhausted() {
5162             let decl = PropertyDeclaration::FontFamily(family);
5163             write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5164                 decls.push(decl, Importance::Normal);
5165             })
5166         }
5167     }
5168 }
5169 
5170 #[no_mangle]
Servo_DeclarationBlock_SetBackgroundImage( declarations: &RawServoDeclarationBlock, value: &nsAString, raw_extra_data: *mut URLExtraData, )5171 pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(
5172     declarations: &RawServoDeclarationBlock,
5173     value: &nsAString,
5174     raw_extra_data: *mut URLExtraData,
5175 ) {
5176     use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
5177     use style::properties::PropertyDeclaration;
5178     use style::stylesheets::CorsMode;
5179     use style::values::generics::image::Image;
5180     use style::values::specified::url::SpecifiedImageUrl;
5181 
5182     let url_data = unsafe { UrlExtraData::from_ptr_ref(&raw_extra_data) };
5183     let string = value.to_string();
5184     let context = ParserContext::new(
5185         Origin::Author,
5186         url_data,
5187         Some(CssRuleType::Style),
5188         ParsingMode::DEFAULT,
5189         QuirksMode::NoQuirks,
5190         None,
5191         None,
5192     );
5193     let url = SpecifiedImageUrl::parse_from_string(string.into(), &context, CorsMode::None);
5194     let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(
5195         vec![Image::Url(url)].into(),
5196     ));
5197     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5198         decls.push(decl, Importance::Normal);
5199     });
5200 }
5201 
5202 #[no_mangle]
Servo_DeclarationBlock_SetTextDecorationColorOverride( declarations: &RawServoDeclarationBlock, )5203 pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(
5204     declarations: &RawServoDeclarationBlock,
5205 ) {
5206     use style::properties::PropertyDeclaration;
5207     use style::values::specified::text::TextDecorationLine;
5208 
5209     let decoration = TextDecorationLine::COLOR_OVERRIDE;
5210     let decl = PropertyDeclaration::TextDecorationLine(decoration);
5211     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5212         decls.push(decl, Importance::Normal);
5213     })
5214 }
5215 
5216 #[no_mangle]
Servo_DeclarationBlock_SetAspectRatio( declarations: &RawServoDeclarationBlock, width: f32, height: f32, )5217 pub extern "C" fn Servo_DeclarationBlock_SetAspectRatio(
5218     declarations: &RawServoDeclarationBlock,
5219     width: f32,
5220     height: f32,
5221 ) {
5222     use style::properties::PropertyDeclaration;
5223     use style::values::generics::position::AspectRatio;
5224 
5225     let decl = PropertyDeclaration::AspectRatio(AspectRatio::from_mapped_ratio(width, height));
5226     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5227         decls.push(decl, Importance::Normal);
5228     })
5229 }
5230 
5231 #[no_mangle]
Servo_CSSSupports2( property: &nsACString, value: &nsACString, ) -> bool5232 pub unsafe extern "C" fn Servo_CSSSupports2(
5233     property: &nsACString,
5234     value: &nsACString,
5235 ) -> bool {
5236     let id = get_property_id_from_property!(property, false);
5237 
5238     let mut declarations = SourcePropertyDeclaration::new();
5239     parse_property_into(
5240         &mut declarations,
5241         id,
5242         value,
5243         DUMMY_URL_DATA,
5244         structs::ParsingMode_Default,
5245         QuirksMode::NoQuirks,
5246         None,
5247     )
5248     .is_ok()
5249 }
5250 
5251 #[no_mangle]
Servo_CSSSupports(cond: &nsACString) -> bool5252 pub extern "C" fn Servo_CSSSupports(cond: &nsACString) -> bool {
5253     let condition = unsafe { cond.as_str_unchecked() };
5254     let mut input = ParserInput::new(&condition);
5255     let mut input = Parser::new(&mut input);
5256     let cond = match input.parse_entirely(parse_condition_or_declaration) {
5257         Ok(c) => c,
5258         Err(..) => return false,
5259     };
5260 
5261     let url_data = unsafe { dummy_url_data() };
5262 
5263     // NOTE(emilio): The supports API is not associated to any stylesheet,
5264     // so the fact that there is no namespace map here is fine.
5265     let context = ParserContext::new_for_cssom(
5266         url_data,
5267         Some(CssRuleType::Style),
5268         ParsingMode::DEFAULT,
5269         QuirksMode::NoQuirks,
5270         None,
5271         None,
5272     );
5273 
5274     let namespaces = Default::default();
5275     cond.eval(&context, &namespaces)
5276 }
5277 
5278 #[no_mangle]
Servo_NoteExplicitHints( element: &RawGeckoElement, restyle_hint: RestyleHint, change_hint: nsChangeHint, )5279 pub unsafe extern "C" fn Servo_NoteExplicitHints(
5280     element: &RawGeckoElement,
5281     restyle_hint: RestyleHint,
5282     change_hint: nsChangeHint,
5283 ) {
5284     GeckoElement(element).note_explicit_hints(restyle_hint, change_hint);
5285 }
5286 
5287 #[no_mangle]
Servo_TakeChangeHint(element: &RawGeckoElement, was_restyled: *mut bool) -> u325288 pub extern "C" fn Servo_TakeChangeHint(element: &RawGeckoElement, was_restyled: *mut bool) -> u32 {
5289     let was_restyled = unsafe { was_restyled.as_mut().unwrap() };
5290     let element = GeckoElement(element);
5291 
5292     let damage = match element.mutate_data() {
5293         Some(mut data) => {
5294             *was_restyled = data.is_restyle();
5295 
5296             let damage = data.damage;
5297             data.clear_restyle_state();
5298             damage
5299         },
5300         None => {
5301             warn!("Trying to get change hint from unstyled element");
5302             *was_restyled = false;
5303             GeckoRestyleDamage::empty()
5304         },
5305     };
5306 
5307     debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
5308     // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
5309     // work as return values with the Linux 32-bit ABI at the moment because
5310     // they wrap the value in a struct, so for now just unwrap it.
5311     damage.as_change_hint().0
5312 }
5313 
5314 #[no_mangle]
Servo_ResolveStyle(element: &RawGeckoElement) -> Strong<ComputedValues>5315 pub extern "C" fn Servo_ResolveStyle(element: &RawGeckoElement) -> Strong<ComputedValues> {
5316     let element = GeckoElement(element);
5317     debug!("Servo_ResolveStyle: {:?}", element);
5318     let data = element
5319         .borrow_data()
5320         .expect("Resolving style on unstyled element");
5321 
5322     debug_assert!(
5323         element.has_current_styles(&*data),
5324         "Resolving style on {:?} without current styles: {:?}",
5325         element,
5326         data
5327     );
5328     data.styles.primary().clone().into()
5329 }
5330 
5331 #[no_mangle]
Servo_ResolveStyleLazily( element: &RawGeckoElement, pseudo_type: PseudoStyleType, rule_inclusion: StyleRuleInclusion, snapshots: *const ServoElementSnapshotTable, raw_data: &RawServoStyleSet, ) -> Strong<ComputedValues>5332 pub extern "C" fn Servo_ResolveStyleLazily(
5333     element: &RawGeckoElement,
5334     pseudo_type: PseudoStyleType,
5335     rule_inclusion: StyleRuleInclusion,
5336     snapshots: *const ServoElementSnapshotTable,
5337     raw_data: &RawServoStyleSet,
5338 ) -> Strong<ComputedValues> {
5339     debug_assert!(!snapshots.is_null());
5340     let global_style_data = &*GLOBAL_STYLE_DATA;
5341     let guard = global_style_data.shared_lock.read();
5342     let element = GeckoElement(element);
5343     let doc_data = PerDocumentStyleData::from_ffi(raw_data);
5344     let data = doc_data.borrow();
5345     let rule_inclusion = RuleInclusion::from(rule_inclusion);
5346     let pseudo = PseudoElement::from_pseudo_type(pseudo_type);
5347     let finish = |styles: &ElementStyles, is_probe: bool| -> Option<Arc<ComputedValues>> {
5348         match pseudo {
5349             Some(ref pseudo) => {
5350                 get_pseudo_style(
5351                     &guard,
5352                     element,
5353                     pseudo,
5354                     rule_inclusion,
5355                     styles,
5356                     /* inherited_styles = */ None,
5357                     &*data,
5358                     is_probe,
5359                     /* matching_func = */ None,
5360                 )
5361             },
5362             None => Some(styles.primary().clone()),
5363         }
5364     };
5365 
5366     let is_before_or_after = pseudo.as_ref().map_or(false, |p| p.is_before_or_after());
5367 
5368     // In the common case we already have the style. Check that before setting
5369     // up all the computation machinery.
5370     //
5371     // Also, only probe in the ::before or ::after case, since their styles may
5372     // not be in the `ElementData`, given they may exist but not be applicable
5373     // to generate an actual pseudo-element (like, having a `content: none`).
5374     if rule_inclusion == RuleInclusion::All {
5375         let styles = element.mutate_data().and_then(|d| {
5376             if d.has_styles() {
5377                 finish(&d.styles, is_before_or_after)
5378             } else {
5379                 None
5380             }
5381         });
5382         if let Some(result) = styles {
5383             return result.into();
5384         }
5385     }
5386 
5387     // We don't have the style ready. Go ahead and compute it as necessary.
5388     let shared = create_shared_context(
5389         &global_style_data,
5390         &guard,
5391         &data,
5392         TraversalFlags::empty(),
5393         unsafe { &*snapshots },
5394     );
5395     let mut tlc = ThreadLocalStyleContext::new(&shared);
5396     let mut context = StyleContext {
5397         shared: &shared,
5398         thread_local: &mut tlc,
5399     };
5400 
5401     let styles = resolve_style(&mut context, element, rule_inclusion, pseudo.as_ref());
5402 
5403     finish(&styles, /* is_probe = */ false)
5404         .expect("We're not probing, so we should always get a style back")
5405         .into()
5406 }
5407 
5408 #[no_mangle]
Servo_ReparentStyle( style_to_reparent: &ComputedValues, parent_style: &ComputedValues, parent_style_ignoring_first_line: &ComputedValues, layout_parent_style: &ComputedValues, element: Option<&RawGeckoElement>, raw_data: &RawServoStyleSet, ) -> Strong<ComputedValues>5409 pub extern "C" fn Servo_ReparentStyle(
5410     style_to_reparent: &ComputedValues,
5411     parent_style: &ComputedValues,
5412     parent_style_ignoring_first_line: &ComputedValues,
5413     layout_parent_style: &ComputedValues,
5414     element: Option<&RawGeckoElement>,
5415     raw_data: &RawServoStyleSet,
5416 ) -> Strong<ComputedValues> {
5417     let global_style_data = &*GLOBAL_STYLE_DATA;
5418     let guard = global_style_data.shared_lock.read();
5419     let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
5420     let inputs = CascadeInputs::new_from_style(style_to_reparent);
5421     let metrics = get_metrics_provider_for_product();
5422     let pseudo = style_to_reparent.pseudo();
5423     let element = element.map(GeckoElement);
5424 
5425     doc_data
5426         .stylist
5427         .cascade_style_and_visited(
5428             element,
5429             pseudo.as_ref(),
5430             inputs,
5431             &StylesheetGuards::same(&guard),
5432             Some(parent_style),
5433             Some(parent_style_ignoring_first_line),
5434             Some(layout_parent_style),
5435             &metrics,
5436             /* rule_cache = */ None,
5437             &mut RuleCacheConditions::default(),
5438         )
5439         .into()
5440 }
5441 
5442 #[cfg(feature = "gecko_debug")]
simulate_compute_values_failure(property: &PropertyValuePair) -> bool5443 fn simulate_compute_values_failure(property: &PropertyValuePair) -> bool {
5444     let p = property.mProperty;
5445     let id = get_property_id_from_nscsspropertyid!(p, false);
5446     id.as_shorthand().is_ok() && property.mSimulateComputeValuesFailure
5447 }
5448 
5449 #[cfg(not(feature = "gecko_debug"))]
simulate_compute_values_failure(_: &PropertyValuePair) -> bool5450 fn simulate_compute_values_failure(_: &PropertyValuePair) -> bool {
5451     false
5452 }
5453 
create_context_for_animation<'a>( per_doc_data: &'a PerDocumentStyleDataImpl, font_metrics_provider: &'a dyn FontMetricsProvider, style: &'a ComputedValues, parent_style: Option<&'a ComputedValues>, for_smil_animation: bool, rule_cache_conditions: &'a mut RuleCacheConditions, ) -> Context<'a>5454 fn create_context_for_animation<'a>(
5455     per_doc_data: &'a PerDocumentStyleDataImpl,
5456     font_metrics_provider: &'a dyn FontMetricsProvider,
5457     style: &'a ComputedValues,
5458     parent_style: Option<&'a ComputedValues>,
5459     for_smil_animation: bool,
5460     rule_cache_conditions: &'a mut RuleCacheConditions,
5461 ) -> Context<'a> {
5462     Context {
5463         builder: StyleBuilder::for_animation(per_doc_data.stylist.device(), style, parent_style),
5464         font_metrics_provider: font_metrics_provider,
5465         cached_system_font: None,
5466         in_media_query: false,
5467         quirks_mode: per_doc_data.stylist.quirks_mode(),
5468         for_smil_animation,
5469         for_non_inherited_property: None,
5470         rule_cache_conditions: RefCell::new(rule_cache_conditions),
5471     }
5472 }
5473 
5474 struct PropertyAndIndex {
5475     property: PropertyId,
5476     index: usize,
5477 }
5478 
5479 struct PrioritizedPropertyIter<'a> {
5480     properties: &'a [PropertyValuePair],
5481     sorted_property_indices: Vec<PropertyAndIndex>,
5482     curr: usize,
5483 }
5484 
5485 impl<'a> PrioritizedPropertyIter<'a> {
new(properties: &'a [PropertyValuePair]) -> PrioritizedPropertyIter5486     fn new(properties: &'a [PropertyValuePair]) -> PrioritizedPropertyIter {
5487         use style::values::animated::compare_property_priority;
5488 
5489         // If we fail to convert a nsCSSPropertyID into a PropertyId we
5490         // shouldn't fail outright but instead by treating that property as the
5491         // 'all' property we make it sort last.
5492         let mut sorted_property_indices: Vec<PropertyAndIndex> = properties
5493             .iter()
5494             .enumerate()
5495             .map(|(index, pair)| {
5496                 let property = PropertyId::from_nscsspropertyid(pair.mProperty)
5497                     .unwrap_or(PropertyId::Shorthand(ShorthandId::All));
5498 
5499                 PropertyAndIndex { property, index }
5500             })
5501             .collect();
5502         sorted_property_indices.sort_by(|a, b| compare_property_priority(&a.property, &b.property));
5503 
5504         PrioritizedPropertyIter {
5505             properties,
5506             sorted_property_indices,
5507             curr: 0,
5508         }
5509     }
5510 }
5511 
5512 impl<'a> Iterator for PrioritizedPropertyIter<'a> {
5513     type Item = &'a PropertyValuePair;
5514 
next(&mut self) -> Option<&'a PropertyValuePair>5515     fn next(&mut self) -> Option<&'a PropertyValuePair> {
5516         if self.curr >= self.sorted_property_indices.len() {
5517             return None;
5518         }
5519         self.curr += 1;
5520         Some(&self.properties[self.sorted_property_indices[self.curr - 1].index])
5521     }
5522 }
5523 
5524 #[no_mangle]
Servo_GetComputedKeyframeValues( keyframes: &nsTArray<structs::Keyframe>, element: &RawGeckoElement, style: &ComputedValues, raw_data: &RawServoStyleSet, computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>, )5525 pub extern "C" fn Servo_GetComputedKeyframeValues(
5526     keyframes: &nsTArray<structs::Keyframe>,
5527     element: &RawGeckoElement,
5528     style: &ComputedValues,
5529     raw_data: &RawServoStyleSet,
5530     computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>,
5531 ) {
5532     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
5533     let metrics = get_metrics_provider_for_product();
5534 
5535     let element = GeckoElement(element);
5536     let parent_element = element.inheritance_parent();
5537     let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
5538     let parent_style = parent_data
5539         .as_ref()
5540         .map(|d| d.styles.primary())
5541         .map(|x| &**x);
5542 
5543     let mut conditions = Default::default();
5544     let mut context = create_context_for_animation(
5545         &data,
5546         &metrics,
5547         &style,
5548         parent_style,
5549         /* for_smil_animation = */ false,
5550         &mut conditions,
5551     );
5552 
5553     let global_style_data = &*GLOBAL_STYLE_DATA;
5554     let guard = global_style_data.shared_lock.read();
5555     let default_values = data.default_computed_values();
5556 
5557     let mut raw_custom_properties_block; // To make the raw block alive in the scope.
5558     for (index, keyframe) in keyframes.iter().enumerate() {
5559         let mut custom_properties = None;
5560         for property in keyframe.mPropertyValues.iter() {
5561             // Find the block for custom properties first.
5562             if property.mProperty == nsCSSPropertyID::eCSSPropertyExtra_variable {
5563                 raw_custom_properties_block =
5564                     unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() };
5565                 let guard =
5566                     Locked::<PropertyDeclarationBlock>::as_arc(&raw_custom_properties_block)
5567                         .read_with(&guard);
5568                 custom_properties = guard.cascade_custom_properties_with_context(&context);
5569                 // There should be one PropertyDeclarationBlock for custom properties.
5570                 break;
5571             }
5572         }
5573 
5574         let ref mut animation_values = computed_keyframes[index];
5575 
5576         let mut seen = LonghandIdSet::new();
5577 
5578         let mut property_index = 0;
5579         for property in PrioritizedPropertyIter::new(&keyframe.mPropertyValues) {
5580             if simulate_compute_values_failure(property) {
5581                 continue;
5582             }
5583 
5584             let mut maybe_append_animation_value =
5585                 |property: LonghandId, value: Option<AnimationValue>| {
5586                     debug_assert!(!property.is_logical());
5587                     debug_assert!(property.is_animatable());
5588 
5589                     // 'display' is only animatable from SMIL
5590                     if property == LonghandId::Display {
5591                         return;
5592                     }
5593 
5594                     if seen.contains(property) {
5595                         return;
5596                     }
5597                     seen.insert(property);
5598 
5599                     // This is safe since we immediately write to the uninitialized values.
5600                     unsafe { animation_values.set_len((property_index + 1) as u32) };
5601                     animation_values[property_index].mProperty = property.to_nscsspropertyid();
5602                     match value {
5603                         Some(v) => {
5604                             animation_values[property_index]
5605                                 .mValue
5606                                 .mServo
5607                                 .set_arc_leaky(Arc::new(v));
5608                         },
5609                         None => {
5610                             animation_values[property_index].mValue.mServo.mRawPtr =
5611                                 ptr::null_mut();
5612                         },
5613                     }
5614                     property_index += 1;
5615                 };
5616 
5617             if property.mServoDeclarationBlock.mRawPtr.is_null() {
5618                 let property = LonghandId::from_nscsspropertyid(property.mProperty);
5619                 if let Ok(prop) = property {
5620                     maybe_append_animation_value(prop, None);
5621                 }
5622                 continue;
5623             }
5624 
5625             let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() };
5626             let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
5627             let guard = declarations.read_with(&guard);
5628             let iter = guard.to_animation_value_iter(
5629                 &mut context,
5630                 &default_values,
5631                 custom_properties.as_ref(),
5632             );
5633 
5634             for value in iter {
5635                 let id = value.id();
5636                 maybe_append_animation_value(id, Some(value));
5637             }
5638         }
5639     }
5640 }
5641 
5642 #[no_mangle]
Servo_GetAnimationValues( declarations: &RawServoDeclarationBlock, element: &RawGeckoElement, style: &ComputedValues, raw_data: &RawServoStyleSet, animation_values: &mut nsTArray<structs::RefPtr<structs::RawServoAnimationValue>>, )5643 pub extern "C" fn Servo_GetAnimationValues(
5644     declarations: &RawServoDeclarationBlock,
5645     element: &RawGeckoElement,
5646     style: &ComputedValues,
5647     raw_data: &RawServoStyleSet,
5648     animation_values: &mut nsTArray<structs::RefPtr<structs::RawServoAnimationValue>>,
5649 ) {
5650     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
5651     let metrics = get_metrics_provider_for_product();
5652 
5653     let element = GeckoElement(element);
5654     let parent_element = element.inheritance_parent();
5655     let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
5656     let parent_style = parent_data
5657         .as_ref()
5658         .map(|d| d.styles.primary())
5659         .map(|x| &**x);
5660 
5661     let mut conditions = Default::default();
5662     let mut context = create_context_for_animation(
5663         &data,
5664         &metrics,
5665         &style,
5666         parent_style,
5667         /* for_smil_animation = */ true,
5668         &mut conditions,
5669     );
5670 
5671     let default_values = data.default_computed_values();
5672     let global_style_data = &*GLOBAL_STYLE_DATA;
5673     let guard = global_style_data.shared_lock.read();
5674 
5675     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
5676     let guard = declarations.read_with(&guard);
5677     let iter = guard.to_animation_value_iter(
5678         &mut context,
5679         &default_values,
5680         None, // SMIL has no extra custom properties.
5681     );
5682     for (index, anim) in iter.enumerate() {
5683         unsafe { animation_values.set_len((index + 1) as u32) };
5684         animation_values[index].set_arc_leaky(Arc::new(anim));
5685     }
5686 }
5687 
5688 #[no_mangle]
Servo_AnimationValue_GetPropertyId( value: &RawServoAnimationValue, ) -> nsCSSPropertyID5689 pub extern "C" fn Servo_AnimationValue_GetPropertyId(
5690     value: &RawServoAnimationValue,
5691 ) -> nsCSSPropertyID {
5692     let value = AnimationValue::as_arc(&value);
5693     value.id().to_nscsspropertyid()
5694 }
5695 
5696 #[no_mangle]
Servo_AnimationValue_Compute( element: &RawGeckoElement, declarations: &RawServoDeclarationBlock, style: &ComputedValues, raw_data: &RawServoStyleSet, ) -> Strong<RawServoAnimationValue>5697 pub extern "C" fn Servo_AnimationValue_Compute(
5698     element: &RawGeckoElement,
5699     declarations: &RawServoDeclarationBlock,
5700     style: &ComputedValues,
5701     raw_data: &RawServoStyleSet,
5702 ) -> Strong<RawServoAnimationValue> {
5703     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
5704     let metrics = get_metrics_provider_for_product();
5705 
5706     let element = GeckoElement(element);
5707     let parent_element = element.inheritance_parent();
5708     let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
5709     let parent_style = parent_data
5710         .as_ref()
5711         .map(|d| d.styles.primary())
5712         .map(|x| &**x);
5713 
5714     let mut conditions = Default::default();
5715     let mut context = create_context_for_animation(
5716         &data,
5717         &metrics,
5718         style,
5719         parent_style,
5720         /* for_smil_animation = */ false,
5721         &mut conditions,
5722     );
5723 
5724     let default_values = data.default_computed_values();
5725     let global_style_data = &*GLOBAL_STYLE_DATA;
5726     let guard = global_style_data.shared_lock.read();
5727     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
5728     // We only compute the first element in declarations.
5729     match declarations
5730         .read_with(&guard)
5731         .declaration_importance_iter()
5732         .next()
5733     {
5734         Some((decl, imp)) if imp == Importance::Normal => {
5735             let animation = AnimationValue::from_declaration(
5736                 decl,
5737                 &mut context,
5738                 None, // No extra custom properties for devtools.
5739                 default_values,
5740             );
5741             animation.map_or(Strong::null(), |value| Arc::new(value).into_strong())
5742         },
5743         _ => Strong::null(),
5744     }
5745 }
5746 
5747 #[no_mangle]
Servo_AssertTreeIsClean(root: &RawGeckoElement)5748 pub extern "C" fn Servo_AssertTreeIsClean(root: &RawGeckoElement) {
5749     if !cfg!(feature = "gecko_debug") {
5750         panic!("Calling Servo_AssertTreeIsClean in release build");
5751     }
5752 
5753     let root = GeckoElement(root);
5754     debug!("Servo_AssertTreeIsClean: ");
5755     debug!("{:?}", ShowSubtreeData(root.as_node()));
5756 
5757     fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) {
5758         debug_assert!(
5759             !el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants(),
5760             "{:?} has still dirty bit {:?} or animation-only dirty bit {:?}",
5761             el,
5762             el.has_dirty_descendants(),
5763             el.has_animation_only_dirty_descendants()
5764         );
5765         for child in el.traversal_children() {
5766             if let Some(child) = child.as_element() {
5767                 assert_subtree_is_clean(child);
5768             }
5769         }
5770     }
5771 
5772     assert_subtree_is_clean(root);
5773 }
5774 
5775 #[no_mangle]
Servo_IsWorkerThread() -> bool5776 pub extern "C" fn Servo_IsWorkerThread() -> bool {
5777     thread_state::get().is_worker()
5778 }
5779 
5780 enum Offset {
5781     Zero,
5782     One,
5783 }
5784 
fill_in_missing_keyframe_values( all_properties: &LonghandIdSet, timing_function: &nsTimingFunction, longhands_at_offset: &LonghandIdSet, offset: Offset, keyframes: &mut nsTArray<structs::Keyframe>, )5785 fn fill_in_missing_keyframe_values(
5786     all_properties: &LonghandIdSet,
5787     timing_function: &nsTimingFunction,
5788     longhands_at_offset: &LonghandIdSet,
5789     offset: Offset,
5790     keyframes: &mut nsTArray<structs::Keyframe>,
5791 ) {
5792     // Return early if all animated properties are already set.
5793     if longhands_at_offset.contains_all(all_properties) {
5794         return;
5795     }
5796 
5797     let keyframe = match offset {
5798         Offset::Zero => unsafe { Gecko_GetOrCreateInitialKeyframe(keyframes, timing_function) },
5799         Offset::One => unsafe { Gecko_GetOrCreateFinalKeyframe(keyframes, timing_function) },
5800     };
5801 
5802     // Append properties that have not been set at this offset.
5803     for property in all_properties.iter() {
5804         if !longhands_at_offset.contains(property) {
5805             unsafe {
5806                 Gecko_AppendPropertyValuePair(
5807                     &mut *(*keyframe).mPropertyValues,
5808                     property.to_nscsspropertyid(),
5809                 );
5810             }
5811         }
5812     }
5813 }
5814 
5815 #[no_mangle]
Servo_StyleSet_GetKeyframesForName( raw_data: &RawServoStyleSet, element: &RawGeckoElement, style: &ComputedValues, name: *mut nsAtom, inherited_timing_function: &nsTimingFunction, keyframes: &mut nsTArray<structs::Keyframe>, ) -> bool5816 pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
5817     raw_data: &RawServoStyleSet,
5818     element: &RawGeckoElement,
5819     style: &ComputedValues,
5820     name: *mut nsAtom,
5821     inherited_timing_function: &nsTimingFunction,
5822     keyframes: &mut nsTArray<structs::Keyframe>,
5823 ) -> bool {
5824     debug_assert!(keyframes.len() == 0, "keyframes should be initially empty");
5825 
5826     let element = GeckoElement(element);
5827     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
5828     let name = Atom::from_raw(name);
5829 
5830     let animation = match data.stylist.get_animation(&name, element) {
5831         Some(animation) => animation,
5832         None => return false,
5833     };
5834 
5835     let global_style_data = &*GLOBAL_STYLE_DATA;
5836     let guard = global_style_data.shared_lock.read();
5837 
5838     let mut properties_set_at_current_offset = LonghandIdSet::new();
5839     let mut properties_set_at_start = LonghandIdSet::new();
5840     let mut properties_set_at_end = LonghandIdSet::new();
5841     let mut has_complete_initial_keyframe = false;
5842     let mut has_complete_final_keyframe = false;
5843     let mut current_offset = -1.;
5844 
5845     let writing_mode = style.writing_mode;
5846 
5847     // Iterate over the keyframe rules backwards so we can drop overridden
5848     // properties (since declarations in later rules override those in earlier
5849     // ones).
5850     for step in animation.steps.iter().rev() {
5851         if step.start_percentage.0 != current_offset {
5852             properties_set_at_current_offset.clear();
5853             current_offset = step.start_percentage.0;
5854         }
5855 
5856         // Override timing_function if the keyframe has an animation-timing-function.
5857         let timing_function = nsTimingFunction {
5858             mTiming: match step.get_animation_timing_function(&guard) {
5859                 Some(val) => val.to_computed_value_without_context(),
5860                 None => (*inherited_timing_function).mTiming,
5861             },
5862         };
5863 
5864         // Look for an existing keyframe with the same offset and timing
5865         // function or else add a new keyframe at the beginning of the keyframe
5866         // array.
5867         let keyframe = Gecko_GetOrCreateKeyframeAtStart(
5868             keyframes,
5869             step.start_percentage.0 as f32,
5870             &timing_function,
5871         );
5872 
5873         match step.value {
5874             KeyframesStepValue::ComputedValues => {
5875                 // In KeyframesAnimation::from_keyframes if there is no 0% or
5876                 // 100% keyframe at all, we will create a 'ComputedValues' step
5877                 // to represent that all properties animated by the keyframes
5878                 // animation should be set to the underlying computed value for
5879                 // that keyframe.
5880                 let mut seen = LonghandIdSet::new();
5881                 for property in animation.properties_changed.iter() {
5882                     let property = property.to_physical(writing_mode);
5883                     if seen.contains(property) {
5884                         continue;
5885                     }
5886                     seen.insert(property);
5887 
5888                     Gecko_AppendPropertyValuePair(
5889                         &mut *(*keyframe).mPropertyValues,
5890                         property.to_nscsspropertyid(),
5891                     );
5892                 }
5893                 if current_offset == 0.0 {
5894                     has_complete_initial_keyframe = true;
5895                 } else if current_offset == 1.0 {
5896                     has_complete_final_keyframe = true;
5897                 }
5898             },
5899             KeyframesStepValue::Declarations { ref block } => {
5900                 let guard = block.read_with(&guard);
5901 
5902                 let mut custom_properties = PropertyDeclarationBlock::new();
5903 
5904                 // Filter out non-animatable properties and properties with
5905                 // !important.
5906                 //
5907                 // Also, iterate in reverse to respect the source order in case
5908                 // there are logical and physical longhands in the same block.
5909                 for declaration in guard.normal_declaration_iter().rev() {
5910                     let id = declaration.id();
5911 
5912                     let id = match id {
5913                         PropertyDeclarationId::Longhand(id) => {
5914                             // Skip the 'display' property because although it
5915                             // is animatable from SMIL, it should not be
5916                             // animatable from CSS Animations.
5917                             if id == LonghandId::Display {
5918                                 continue;
5919                             }
5920 
5921                             if !id.is_animatable() {
5922                                 continue;
5923                             }
5924 
5925                             id.to_physical(writing_mode)
5926                         },
5927                         PropertyDeclarationId::Custom(..) => {
5928                             custom_properties.push(declaration.clone(), Importance::Normal);
5929                             continue;
5930                         },
5931                     };
5932 
5933                     if properties_set_at_current_offset.contains(id) {
5934                         continue;
5935                     }
5936 
5937                     let pair = Gecko_AppendPropertyValuePair(
5938                         &mut *(*keyframe).mPropertyValues,
5939                         id.to_nscsspropertyid(),
5940                     );
5941 
5942                     (*pair).mServoDeclarationBlock.set_arc_leaky(Arc::new(
5943                         global_style_data
5944                             .shared_lock
5945                             .wrap(PropertyDeclarationBlock::with_one(
5946                                 declaration.to_physical(writing_mode),
5947                                 Importance::Normal,
5948                             )),
5949                     ));
5950 
5951                     if current_offset == 0.0 {
5952                         properties_set_at_start.insert(id);
5953                     } else if current_offset == 1.0 {
5954                         properties_set_at_end.insert(id);
5955                     }
5956                     properties_set_at_current_offset.insert(id);
5957                 }
5958 
5959                 if custom_properties.any_normal() {
5960                     let pair = Gecko_AppendPropertyValuePair(
5961                         &mut *(*keyframe).mPropertyValues,
5962                         nsCSSPropertyID::eCSSPropertyExtra_variable,
5963                     );
5964 
5965                     (*pair).mServoDeclarationBlock.set_arc_leaky(Arc::new(
5966                         global_style_data.shared_lock.wrap(custom_properties),
5967                     ));
5968                 }
5969             },
5970         }
5971     }
5972 
5973     let mut properties_changed = LonghandIdSet::new();
5974     for property in animation.properties_changed.iter() {
5975         properties_changed.insert(property.to_physical(writing_mode));
5976     }
5977 
5978     // Append property values that are missing in the initial or the final keyframes.
5979     if !has_complete_initial_keyframe {
5980         fill_in_missing_keyframe_values(
5981             &properties_changed,
5982             inherited_timing_function,
5983             &properties_set_at_start,
5984             Offset::Zero,
5985             keyframes,
5986         );
5987     }
5988     if !has_complete_final_keyframe {
5989         fill_in_missing_keyframe_values(
5990             &properties_changed,
5991             inherited_timing_function,
5992             &properties_set_at_end,
5993             Offset::One,
5994             keyframes,
5995         );
5996     }
5997     true
5998 }
5999 
6000 #[no_mangle]
Servo_StyleSet_GetFontFaceRules( raw_data: &RawServoStyleSet, rules: &mut nsTArray<structs::nsFontFaceRuleContainer>, )6001 pub extern "C" fn Servo_StyleSet_GetFontFaceRules(
6002     raw_data: &RawServoStyleSet,
6003     rules: &mut nsTArray<structs::nsFontFaceRuleContainer>,
6004 ) {
6005     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6006     debug_assert_eq!(rules.len(), 0);
6007 
6008     let len: u32 = data
6009         .stylist
6010         .iter_extra_data_origins()
6011         .map(|(d, _)| d.font_faces.len() as u32)
6012         .sum();
6013 
6014     // Reversed iterator because Gecko expects rules to appear sorted
6015     // UserAgent first, Author last.
6016     let font_face_iter = data
6017         .stylist
6018         .iter_extra_data_origins_rev()
6019         .flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o)));
6020 
6021     unsafe { rules.set_len(len) };
6022     for ((rule, origin), dest) in font_face_iter.zip(rules.iter_mut()) {
6023         dest.mRule.set_arc_leaky(rule.clone());
6024         dest.mOrigin = origin;
6025     }
6026 }
6027 
6028 // XXX Ideally this should return a Option<&RawServoCounterStyleRule>,
6029 // but we cannot, because the value from AtomicRefCell::borrow() can only
6030 // live in this function, and thus anything derived from it cannot get the
6031 // same lifetime as raw_data in parameter. See bug 1451543.
6032 #[no_mangle]
Servo_StyleSet_GetCounterStyleRule( raw_data: &RawServoStyleSet, name: *mut nsAtom, ) -> *const RawServoCounterStyleRule6033 pub unsafe extern "C" fn Servo_StyleSet_GetCounterStyleRule(
6034     raw_data: &RawServoStyleSet,
6035     name: *mut nsAtom,
6036 ) -> *const RawServoCounterStyleRule {
6037     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6038     Atom::with(name, |name| {
6039         data.stylist
6040             .iter_extra_data_origins()
6041             .filter_map(|(d, _)| d.counter_styles.get(name))
6042             .next()
6043             .map_or(ptr::null(), |rule| rule.as_borrowed())
6044     })
6045 }
6046 
6047 #[no_mangle]
Servo_StyleSet_BuildFontFeatureValueSet( raw_data: &RawServoStyleSet, ) -> *mut gfxFontFeatureValueSet6048 pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet(
6049     raw_data: &RawServoStyleSet,
6050 ) -> *mut gfxFontFeatureValueSet {
6051     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6052 
6053     let global_style_data = &*GLOBAL_STYLE_DATA;
6054     let guard = global_style_data.shared_lock.read();
6055 
6056     let has_rule = data
6057         .stylist
6058         .iter_extra_data_origins()
6059         .any(|(d, _)| !d.font_feature_values.is_empty());
6060 
6061     if !has_rule {
6062         return ptr::null_mut();
6063     }
6064 
6065     let font_feature_values_iter = data
6066         .stylist
6067         .iter_extra_data_origins_rev()
6068         .flat_map(|(d, _)| d.font_feature_values.iter());
6069 
6070     let set = unsafe { Gecko_ConstructFontFeatureValueSet() };
6071     for src in font_feature_values_iter {
6072         let rule = src.read_with(&guard);
6073         rule.set_at_rules(set);
6074     }
6075     set
6076 }
6077 
6078 #[no_mangle]
Servo_StyleSet_ResolveForDeclarations( raw_data: &RawServoStyleSet, parent_style_context: Option<&ComputedValues>, declarations: &RawServoDeclarationBlock, ) -> Strong<ComputedValues>6079 pub extern "C" fn Servo_StyleSet_ResolveForDeclarations(
6080     raw_data: &RawServoStyleSet,
6081     parent_style_context: Option<&ComputedValues>,
6082     declarations: &RawServoDeclarationBlock,
6083 ) -> Strong<ComputedValues> {
6084     let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6085     let global_style_data = &*GLOBAL_STYLE_DATA;
6086     let guard = global_style_data.shared_lock.read();
6087     let guards = StylesheetGuards::same(&guard);
6088 
6089     let parent_style = match parent_style_context {
6090         Some(parent) => &*parent,
6091         None => doc_data.default_computed_values(),
6092     };
6093 
6094     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
6095 
6096     doc_data
6097         .stylist
6098         .compute_for_declarations::<GeckoElement>(&guards, parent_style, declarations.clone_arc())
6099         .into()
6100 }
6101 
6102 #[no_mangle]
Servo_StyleSet_AddSizeOfExcludingThis( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, sizes: *mut ServoStyleSetSizes, raw_data: &RawServoStyleSet, )6103 pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis(
6104     malloc_size_of: GeckoMallocSizeOf,
6105     malloc_enclosing_size_of: GeckoMallocSizeOf,
6106     sizes: *mut ServoStyleSetSizes,
6107     raw_data: &RawServoStyleSet,
6108 ) {
6109     let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
6110     let mut ops = MallocSizeOfOps::new(
6111         malloc_size_of.unwrap(),
6112         Some(malloc_enclosing_size_of.unwrap()),
6113         None,
6114     );
6115     let sizes = unsafe { sizes.as_mut() }.unwrap();
6116     data.add_size_of(&mut ops, sizes);
6117 }
6118 
6119 #[no_mangle]
Servo_UACache_AddSizeOf( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, sizes: *mut ServoStyleSetSizes, )6120 pub extern "C" fn Servo_UACache_AddSizeOf(
6121     malloc_size_of: GeckoMallocSizeOf,
6122     malloc_enclosing_size_of: GeckoMallocSizeOf,
6123     sizes: *mut ServoStyleSetSizes,
6124 ) {
6125     let mut ops = MallocSizeOfOps::new(
6126         malloc_size_of.unwrap(),
6127         Some(malloc_enclosing_size_of.unwrap()),
6128         None,
6129     );
6130     let sizes = unsafe { sizes.as_mut() }.unwrap();
6131     add_size_of_ua_cache(&mut ops, sizes);
6132 }
6133 
6134 #[no_mangle]
Servo_StyleSet_MightHaveAttributeDependency( raw_data: &RawServoStyleSet, element: &RawGeckoElement, local_name: *mut nsAtom, ) -> bool6135 pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
6136     raw_data: &RawServoStyleSet,
6137     element: &RawGeckoElement,
6138     local_name: *mut nsAtom,
6139 ) -> bool {
6140     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6141     let element = GeckoElement(element);
6142 
6143     unsafe {
6144         Atom::with(local_name, |atom| {
6145             data.stylist.any_applicable_rule_data(element, |data| {
6146                 data.might_have_attribute_dependency(atom)
6147             })
6148         })
6149     }
6150 }
6151 
6152 #[no_mangle]
Servo_StyleSet_HasStateDependency( raw_data: &RawServoStyleSet, element: &RawGeckoElement, state: u64, ) -> bool6153 pub extern "C" fn Servo_StyleSet_HasStateDependency(
6154     raw_data: &RawServoStyleSet,
6155     element: &RawGeckoElement,
6156     state: u64,
6157 ) -> bool {
6158     let element = GeckoElement(element);
6159 
6160     let state = ElementState::from_bits_truncate(state);
6161     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6162 
6163     data.stylist
6164         .any_applicable_rule_data(element, |data| data.has_state_dependency(state))
6165 }
6166 
6167 #[no_mangle]
Servo_StyleSet_HasDocumentStateDependency( raw_data: &RawServoStyleSet, state: u64, ) -> bool6168 pub extern "C" fn Servo_StyleSet_HasDocumentStateDependency(
6169     raw_data: &RawServoStyleSet,
6170     state: u64,
6171 ) -> bool {
6172     let state = DocumentState::from_bits_truncate(state);
6173     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6174 
6175     data.stylist.has_document_state_dependency(state)
6176 }
6177 
6178 #[no_mangle]
Servo_GetPropertyValue( style: &ComputedValues, prop: nsCSSPropertyID, value: &mut nsAString, )6179 pub unsafe extern "C" fn Servo_GetPropertyValue(
6180     style: &ComputedValues,
6181     prop: nsCSSPropertyID,
6182     value: &mut nsAString,
6183 ) {
6184     if let Ok(longhand) = LonghandId::from_nscsspropertyid(prop) {
6185         style
6186             .get_longhand_property_value(longhand, &mut CssWriter::new(value))
6187             .unwrap();
6188         return;
6189     }
6190 
6191     let shorthand =
6192         ShorthandId::from_nscsspropertyid(prop).expect("Not a shorthand nor a longhand?");
6193     let mut block = PropertyDeclarationBlock::new();
6194     // NOTE(emilio): We reuse the animation value machinery to avoid blowing up
6195     // code size, but may need to come up with something different if ever care
6196     // about supporting the cases that assert below. Fortunately we don't right
6197     // now.
6198     for longhand in shorthand.longhands() {
6199         debug_assert!(
6200             !longhand.is_logical(),
6201             "This won't quite do the right thing if we want to serialize \
6202              logical shorthands"
6203         );
6204         let animated = AnimationValue::from_computed_values(longhand, style).expect(
6205             "Somebody tried to serialize a shorthand with \
6206              non-animatable properties, would need more code \
6207              to do this",
6208         );
6209         block.push(animated.uncompute(), Importance::Normal);
6210     }
6211     block.shorthand_to_css(shorthand, value).unwrap();
6212 }
6213 
6214 #[no_mangle]
Servo_GetCustomPropertyValue( computed_values: &ComputedValues, name: &nsACString, value: &mut nsAString, ) -> bool6215 pub unsafe extern "C" fn Servo_GetCustomPropertyValue(
6216     computed_values: &ComputedValues,
6217     name: &nsACString,
6218     value: &mut nsAString,
6219 ) -> bool {
6220     let custom_properties = match computed_values.custom_properties() {
6221         Some(p) => p,
6222         None => return false,
6223     };
6224 
6225     let name = Atom::from(name.as_str_unchecked());
6226     let computed_value = match custom_properties.get(&name) {
6227         Some(v) => v,
6228         None => return false,
6229     };
6230 
6231     computed_value.to_css(&mut CssWriter::new(value)).unwrap();
6232     true
6233 }
6234 
6235 #[no_mangle]
Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u326236 pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u32 {
6237     match computed_values.custom_properties() {
6238         Some(p) => p.len() as u32,
6239         None => 0,
6240     }
6241 }
6242 
6243 #[no_mangle]
Servo_GetCustomPropertyNameAt( computed_values: &ComputedValues, index: u32, ) -> *mut nsAtom6244 pub extern "C" fn Servo_GetCustomPropertyNameAt(
6245     computed_values: &ComputedValues,
6246     index: u32,
6247 ) -> *mut nsAtom {
6248     let custom_properties = match computed_values.custom_properties() {
6249         Some(p) => p,
6250         None => return ptr::null_mut(),
6251     };
6252 
6253     let property_name = match custom_properties.get_index(index as usize) {
6254         Some((key, _value)) => key,
6255         None => return ptr::null_mut(),
6256     };
6257 
6258 
6259     property_name.as_ptr()
6260 }
6261 
6262 #[no_mangle]
Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool6263 pub extern "C" fn Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool {
6264     url.is_fragment()
6265 }
6266 
6267 #[no_mangle]
Servo_ProcessInvalidations( set: &RawServoStyleSet, element: &RawGeckoElement, snapshots: *const ServoElementSnapshotTable, )6268 pub extern "C" fn Servo_ProcessInvalidations(
6269     set: &RawServoStyleSet,
6270     element: &RawGeckoElement,
6271     snapshots: *const ServoElementSnapshotTable,
6272 ) {
6273     debug_assert!(!snapshots.is_null());
6274 
6275     let element = GeckoElement(element);
6276     debug_assert!(element.has_snapshot());
6277     debug_assert!(!element.handled_snapshot());
6278 
6279     let mut data = element.mutate_data();
6280     debug_assert!(data.is_some());
6281 
6282     let global_style_data = &*GLOBAL_STYLE_DATA;
6283     let guard = global_style_data.shared_lock.read();
6284     let per_doc_data = PerDocumentStyleData::from_ffi(set).borrow();
6285     let shared_style_context = create_shared_context(
6286         &global_style_data,
6287         &guard,
6288         &per_doc_data,
6289         TraversalFlags::empty(),
6290         unsafe { &*snapshots },
6291     );
6292     let mut data = data.as_mut().map(|d| &mut **d);
6293 
6294     if let Some(ref mut data) = data {
6295         // FIXME(emilio): Ideally we could share the nth-index-cache across all
6296         // the elements?
6297         let result = data.invalidate_style_if_needed(
6298             element,
6299             &shared_style_context,
6300             None,
6301             &mut NthIndexCache::default(),
6302         );
6303 
6304         if result.has_invalidated_siblings() {
6305             let parent = element
6306                 .traversal_parent()
6307                 .expect("How could we invalidate siblings without a common parent?");
6308             unsafe {
6309                 parent.set_dirty_descendants();
6310                 bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0);
6311             }
6312         } else if result.has_invalidated_descendants() {
6313             unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) };
6314         } else if result.has_invalidated_self() {
6315             unsafe { bindings::Gecko_NoteDirtyElement(element.0) };
6316         }
6317     }
6318 }
6319 
6320 #[no_mangle]
Servo_HasPendingRestyleAncestor( element: &RawGeckoElement, may_need_to_flush_layout: bool, ) -> bool6321 pub extern "C" fn Servo_HasPendingRestyleAncestor(
6322     element: &RawGeckoElement,
6323     may_need_to_flush_layout: bool,
6324 ) -> bool {
6325     let mut has_yet_to_be_styled = false;
6326     let mut element = Some(GeckoElement(element));
6327     while let Some(e) = element {
6328         if e.has_animations() {
6329             return true;
6330         }
6331 
6332         // If the element needs a frame, it means that we haven't styled it yet
6333         // after it got inserted in the document, and thus we may need to do
6334         // that for transitions and animations to trigger.
6335         //
6336         // This is a fast path in the common case, but `has_yet_to_be_styled` is
6337         // the real check for this.
6338         if e.needs_frame() {
6339             return true;
6340         }
6341 
6342         let data = e.borrow_data();
6343         if let Some(ref data) = data {
6344             if !data.hint.is_empty() {
6345                 return true;
6346             }
6347             if has_yet_to_be_styled && !data.styles.is_display_none() {
6348                 return true;
6349             }
6350             // Ideally, DOM mutations wouldn't affect layout trees of siblings.
6351             //
6352             // In practice, this can happen because Gecko deals pretty badly
6353             // with some kinds of content insertion and removals.
6354             //
6355             // If we may need to flush layout, we need frames to accurately
6356             // determine whether we'll actually flush, so if we have to
6357             // reconstruct we need to flush style, which is what will take care
6358             // of ensuring that frames are constructed, even if the style itself
6359             // is up-to-date.
6360             if may_need_to_flush_layout && data.damage.contains(GeckoRestyleDamage::reconstruct()) {
6361                 return true;
6362             }
6363         }
6364         has_yet_to_be_styled = data.is_none();
6365 
6366         element = e.traversal_parent();
6367     }
6368     false
6369 }
6370 
6371 #[no_mangle]
Servo_SelectorList_Parse( selector_list: &nsACString, ) -> OwnedOrNull<RawServoSelectorList>6372 pub unsafe extern "C" fn Servo_SelectorList_Parse(
6373     selector_list: &nsACString,
6374 ) -> OwnedOrNull<RawServoSelectorList> {
6375     use style::selector_parser::SelectorParser;
6376 
6377     let input = selector_list.as_str_unchecked();
6378     let selector_list = match SelectorParser::parse_author_origin_no_namespace(&input) {
6379         Ok(selector_list) => selector_list,
6380         Err(..) => return OwnedOrNull::null(),
6381     };
6382 
6383     Box::new(selector_list).into_ffi().maybe()
6384 }
6385 
6386 #[no_mangle]
Servo_SelectorList_Drop(list: *mut RawServoSelectorList)6387 pub unsafe extern "C" fn Servo_SelectorList_Drop(list: *mut RawServoSelectorList) {
6388     SelectorList::drop_ffi(list)
6389 }
6390 
parse_color( value: &str, error_reporter: Option<&dyn ParseErrorReporter>, ) -> Result<specified::Color, ()>6391 fn parse_color(
6392     value: &str,
6393     error_reporter: Option<&dyn ParseErrorReporter>,
6394 ) -> Result<specified::Color, ()> {
6395     let mut input = ParserInput::new(value);
6396     let mut parser = Parser::new(&mut input);
6397     let url_data = unsafe { dummy_url_data() };
6398     let context = ParserContext::new(
6399         Origin::Author,
6400         url_data,
6401         Some(CssRuleType::Style),
6402         ParsingMode::DEFAULT,
6403         QuirksMode::NoQuirks,
6404         error_reporter,
6405         None,
6406     );
6407 
6408     let start_position = parser.position();
6409     parser
6410         .parse_entirely(|i| specified::Color::parse(&context, i))
6411         .map_err(|err| {
6412             if error_reporter.is_some() {
6413                 match err.kind {
6414                     ParseErrorKind::Custom(StyleParseErrorKind::ValueError(..)) => {
6415                         let location = err.location.clone();
6416                         let error = ContextualParseError::UnsupportedValue(
6417                             parser.slice_from(start_position),
6418                             err,
6419                         );
6420                         context.log_css_error(location, error);
6421                     },
6422                     // Ignore other kinds of errors that might be reported, such as
6423                     // ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken),
6424                     // since Gecko doesn't report those to the error console.
6425                     _ => {},
6426                 }
6427             }
6428         })
6429 }
6430 
6431 #[no_mangle]
Servo_IsValidCSSColor(value: &nsACString) -> bool6432 pub unsafe extern "C" fn Servo_IsValidCSSColor(value: &nsACString) -> bool {
6433     parse_color(value.as_str_unchecked(), None).is_ok()
6434 }
6435 
6436 #[no_mangle]
Servo_ComputeColor( raw_data: Option<&RawServoStyleSet>, current_color: structs::nscolor, value: &nsACString, result_color: &mut structs::nscolor, was_current_color: *mut bool, loader: *mut Loader, ) -> bool6437 pub unsafe extern "C" fn Servo_ComputeColor(
6438     raw_data: Option<&RawServoStyleSet>,
6439     current_color: structs::nscolor,
6440     value: &nsACString,
6441     result_color: &mut structs::nscolor,
6442     was_current_color: *mut bool,
6443     loader: *mut Loader,
6444 ) -> bool {
6445     use style::gecko;
6446 
6447     let current_color = gecko::values::convert_nscolor_to_rgba(current_color);
6448 
6449     let reporter = loader.as_mut().and_then(|loader| {
6450         // Make an ErrorReporter that will report errors as being "from DOM".
6451         ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut())
6452     });
6453 
6454     let specified_color = match parse_color(
6455         value.as_str_unchecked(),
6456         reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
6457     ) {
6458         Ok(c) => c,
6459         Err(..) => return false,
6460     };
6461 
6462     let computed_color = match raw_data {
6463         Some(raw_data) => {
6464             let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6465             let device = data.stylist.device();
6466             let quirks_mode = data.stylist.quirks_mode();
6467             Context::for_media_query_evaluation(device, quirks_mode, |context| {
6468                 specified_color.to_computed_color(Some(&context))
6469             })
6470         },
6471         None => specified_color.to_computed_color(None),
6472     };
6473 
6474     let computed_color = match computed_color {
6475         Some(c) => c,
6476         None => return false,
6477     };
6478 
6479     let rgba = computed_color.to_rgba(current_color);
6480     *result_color = gecko::values::convert_rgba_to_nscolor(&rgba);
6481 
6482     if !was_current_color.is_null() {
6483         *was_current_color = computed_color.is_currentcolor();
6484     }
6485 
6486     true
6487 }
6488 
6489 #[no_mangle]
Servo_IntersectionObserverRootMargin_Parse( value: &nsAString, result: *mut IntersectionObserverRootMargin, ) -> bool6490 pub unsafe extern "C" fn Servo_IntersectionObserverRootMargin_Parse(
6491     value: &nsAString,
6492     result: *mut IntersectionObserverRootMargin,
6493 ) -> bool {
6494     let value = value.to_string();
6495     let result = result.as_mut().unwrap();
6496 
6497     let mut input = ParserInput::new(&value);
6498     let mut parser = Parser::new(&mut input);
6499 
6500     let url_data = dummy_url_data();
6501     let context = ParserContext::new(
6502         Origin::Author,
6503         url_data,
6504         Some(CssRuleType::Style),
6505         ParsingMode::DEFAULT,
6506         QuirksMode::NoQuirks,
6507         None,
6508         None,
6509     );
6510 
6511     let margin = parser.parse_entirely(|p| IntersectionObserverRootMargin::parse(&context, p));
6512     match margin {
6513         Ok(margin) => {
6514             *result = margin;
6515             true
6516         },
6517         Err(..) => false,
6518     }
6519 }
6520 
6521 #[no_mangle]
Servo_IntersectionObserverRootMargin_ToString( root_margin: &IntersectionObserverRootMargin, result: &mut nsAString, )6522 pub extern "C" fn Servo_IntersectionObserverRootMargin_ToString(
6523     root_margin: &IntersectionObserverRootMargin,
6524     result: &mut nsAString,
6525 ) {
6526     let mut writer = CssWriter::new(result);
6527     root_margin.to_css(&mut writer).unwrap();
6528 }
6529 
6530 #[no_mangle]
Servo_ParseTransformIntoMatrix( value: &nsACString, contain_3d: &mut bool, result: &mut structs::Matrix4x4Components, ) -> bool6531 pub extern "C" fn Servo_ParseTransformIntoMatrix(
6532     value: &nsACString,
6533     contain_3d: &mut bool,
6534     result: &mut structs::Matrix4x4Components,
6535 ) -> bool {
6536     use style::properties::longhands::transform;
6537 
6538     let string = unsafe { value.as_str_unchecked() };
6539     let mut input = ParserInput::new(&string);
6540     let mut parser = Parser::new(&mut input);
6541     let context = ParserContext::new(
6542         Origin::Author,
6543         unsafe { dummy_url_data() },
6544         Some(CssRuleType::Style),
6545         ParsingMode::DEFAULT,
6546         QuirksMode::NoQuirks,
6547         None,
6548         None,
6549     );
6550 
6551     let transform = match parser.parse_entirely(|t| transform::parse(&context, t)) {
6552         Ok(t) => t,
6553         Err(..) => return false,
6554     };
6555 
6556     let (m, is_3d) = match transform.to_transform_3d_matrix(None) {
6557         Ok(result) => result,
6558         Err(..) => return false,
6559     };
6560 
6561     *result = m.to_row_major_array();
6562     *contain_3d = is_3d;
6563     true
6564 }
6565 
6566 #[no_mangle]
Servo_ParseFontShorthandForMatching( value: &nsAString, data: *mut URLExtraData, family: &mut structs::RefPtr<structs::SharedFontList>, style: &mut ComputedFontStyleDescriptor, stretch: &mut f32, weight: &mut f32, ) -> bool6567 pub unsafe extern "C" fn Servo_ParseFontShorthandForMatching(
6568     value: &nsAString,
6569     data: *mut URLExtraData,
6570     family: &mut structs::RefPtr<structs::SharedFontList>,
6571     style: &mut ComputedFontStyleDescriptor,
6572     stretch: &mut f32,
6573     weight: &mut f32,
6574 ) -> bool {
6575     use style::properties::shorthands::font;
6576     use style::values::computed::font::FontFamilyList;
6577     use style::values::computed::font::FontWeight as ComputedFontWeight;
6578     use style::values::generics::font::FontStyle as GenericFontStyle;
6579     use style::values::specified::font::{
6580         FontFamily, FontStretch, FontStyle, FontWeight, SpecifiedFontStyle,
6581     };
6582 
6583     let string = value.to_string();
6584     let mut input = ParserInput::new(&string);
6585     let mut parser = Parser::new(&mut input);
6586     let url_data = UrlExtraData::from_ptr_ref(&data);
6587     let context = ParserContext::new(
6588         Origin::Author,
6589         url_data,
6590         Some(CssRuleType::FontFace),
6591         ParsingMode::DEFAULT,
6592         QuirksMode::NoQuirks,
6593         None,
6594         None,
6595     );
6596 
6597     let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) {
6598         Ok(f) => f,
6599         Err(..) => return false,
6600     };
6601 
6602     // The system font is not acceptable, so we return false.
6603     match font.font_family {
6604         FontFamily::Values(FontFamilyList::SharedFontList(list)) => family.set_move(list),
6605         FontFamily::Values(list) => family.set_move(list.shared_font_list().clone()),
6606         FontFamily::System(_) => return false,
6607     }
6608 
6609     let specified_font_style = match font.font_style {
6610         FontStyle::Specified(ref s) => s,
6611         FontStyle::System(_) => return false,
6612     };
6613 
6614     *style = match *specified_font_style {
6615         GenericFontStyle::Normal => ComputedFontStyleDescriptor::Normal,
6616         GenericFontStyle::Italic => ComputedFontStyleDescriptor::Italic,
6617         GenericFontStyle::Oblique(ref angle) => {
6618             let angle = SpecifiedFontStyle::compute_angle_degrees(angle);
6619             ComputedFontStyleDescriptor::Oblique(angle, angle)
6620         },
6621     };
6622 
6623     *stretch = match font.font_stretch {
6624         FontStretch::Keyword(ref k) => k.compute().0,
6625         FontStretch::Stretch(ref p) => p.get(),
6626         FontStretch::System(_) => return false,
6627     };
6628 
6629     *weight = match font.font_weight {
6630         FontWeight::Absolute(w) => w.compute().0,
6631         // Resolve relative font weights against the initial of font-weight
6632         // (normal, which is equivalent to 400).
6633         FontWeight::Bolder => ComputedFontWeight::normal().bolder().0,
6634         FontWeight::Lighter => ComputedFontWeight::normal().lighter().0,
6635         FontWeight::System(_) => return false,
6636     };
6637 
6638     true
6639 }
6640 
6641 #[no_mangle]
Servo_SourceSizeList_Parse( value: &nsACString, ) -> Owned<RawServoSourceSizeList>6642 pub unsafe extern "C" fn Servo_SourceSizeList_Parse(
6643     value: &nsACString,
6644 ) -> Owned<RawServoSourceSizeList> {
6645     let value = value.as_str_unchecked();
6646     let mut input = ParserInput::new(value);
6647     let mut parser = Parser::new(&mut input);
6648 
6649     let context = ParserContext::new(
6650         Origin::Author,
6651         dummy_url_data(),
6652         Some(CssRuleType::Style),
6653         ParsingMode::DEFAULT,
6654         QuirksMode::NoQuirks,
6655         None,
6656         None,
6657     );
6658 
6659     // NB: Intentionally not calling parse_entirely.
6660     let list = SourceSizeList::parse(&context, &mut parser);
6661     Box::new(list).into_ffi()
6662 }
6663 
6664 #[no_mangle]
Servo_SourceSizeList_Evaluate( raw_data: &RawServoStyleSet, list: Option<&RawServoSourceSizeList>, ) -> i326665 pub unsafe extern "C" fn Servo_SourceSizeList_Evaluate(
6666     raw_data: &RawServoStyleSet,
6667     list: Option<&RawServoSourceSizeList>,
6668 ) -> i32 {
6669     let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6670     let device = doc_data.stylist.device();
6671     let quirks_mode = doc_data.stylist.quirks_mode();
6672 
6673     let result = match list {
6674         Some(list) => SourceSizeList::from_ffi(list).evaluate(device, quirks_mode),
6675         None => SourceSizeList::empty().evaluate(device, quirks_mode),
6676     };
6677 
6678     result.0
6679 }
6680 
6681 #[no_mangle]
Servo_SourceSizeList_Drop(list: *mut RawServoSourceSizeList)6682 pub unsafe extern "C" fn Servo_SourceSizeList_Drop(list: *mut RawServoSourceSizeList) {
6683     SourceSizeList::drop_ffi(list);
6684 }
6685 
6686 #[no_mangle]
Servo_InvalidateStyleForDocStateChanges( root: &RawGeckoElement, document_style: &RawServoStyleSet, non_document_styles: &nsTArray<&RawServoAuthorStyles>, states_changed: u64, )6687 pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges(
6688     root: &RawGeckoElement,
6689     document_style: &RawServoStyleSet,
6690     non_document_styles: &nsTArray<&RawServoAuthorStyles>,
6691     states_changed: u64,
6692 ) {
6693     use style::invalidation::element::document_state::DocumentStateInvalidationProcessor;
6694     use style::invalidation::element::invalidator::TreeStyleInvalidator;
6695 
6696     let document_data = PerDocumentStyleData::from_ffi(document_style).borrow();
6697 
6698     let iter = document_data
6699         .stylist
6700         .iter_origins()
6701         .map(|(data, _origin)| data)
6702         .chain(non_document_styles.iter().map(|author_styles| {
6703             let styles: &_ = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
6704             &styles.data
6705         }));
6706 
6707     let root = GeckoElement(root);
6708     let mut processor = DocumentStateInvalidationProcessor::new(
6709         iter,
6710         DocumentState::from_bits_truncate(states_changed),
6711         root.as_node().owner_doc().quirks_mode(),
6712     );
6713 
6714     let result =
6715         TreeStyleInvalidator::new(root, /* stack_limit_checker = */ None, &mut processor)
6716             .invalidate();
6717 
6718     debug_assert!(!result.has_invalidated_siblings(), "How in the world?");
6719     if result.has_invalidated_descendants() {
6720         bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0);
6721     } else if result.has_invalidated_self() {
6722         bindings::Gecko_NoteDirtyElement(root.0);
6723     }
6724 }
6725 
6726 #[no_mangle]
Servo_PseudoClass_GetStates(name: &nsACString) -> u646727 pub unsafe extern "C" fn Servo_PseudoClass_GetStates(name: &nsACString) -> u64 {
6728     let name = name.as_str_unchecked();
6729     match NonTSPseudoClass::parse_non_functional(name) {
6730         None => 0,
6731         // Ignore :any-link since it contains both visited and unvisited state.
6732         Some(NonTSPseudoClass::AnyLink) => 0,
6733         Some(pseudo_class) => pseudo_class.state_flag().bits(),
6734     }
6735 }
6736 
6737 #[no_mangle]
Servo_UseCounters_Create() -> Owned<structs::StyleUseCounters>6738 pub unsafe extern "C" fn Servo_UseCounters_Create() -> Owned<structs::StyleUseCounters> {
6739     Box::<UseCounters>::default().into_ffi()
6740 }
6741 
6742 #[no_mangle]
Servo_UseCounters_Drop(c: *mut structs::StyleUseCounters)6743 pub unsafe extern "C" fn Servo_UseCounters_Drop(c: *mut structs::StyleUseCounters) {
6744     UseCounters::drop_ffi(c);
6745 }
6746 
6747 #[no_mangle]
Servo_UseCounters_Merge( doc_counters: &UseCounters, sheet_counters: &UseCounters, )6748 pub unsafe extern "C" fn Servo_UseCounters_Merge(
6749     doc_counters: &UseCounters,
6750     sheet_counters: &UseCounters,
6751 ) {
6752     doc_counters.merge(sheet_counters)
6753 }
6754 
6755 #[no_mangle]
Servo_IsPropertyIdRecordedInUseCounter( use_counters: &UseCounters, id: nsCSSPropertyID, ) -> bool6756 pub unsafe extern "C" fn Servo_IsPropertyIdRecordedInUseCounter(
6757     use_counters: &UseCounters,
6758     id: nsCSSPropertyID,
6759 ) -> bool {
6760     let id = NonCustomPropertyId::from_nscsspropertyid(id).unwrap();
6761     use_counters.non_custom_properties.recorded(id)
6762 }
6763 
6764 #[no_mangle]
Servo_IsUnknownPropertyRecordedInUseCounter( use_counters: &UseCounters, p: CountedUnknownProperty, ) -> bool6765 pub unsafe extern "C" fn Servo_IsUnknownPropertyRecordedInUseCounter(
6766     use_counters: &UseCounters,
6767     p: CountedUnknownProperty,
6768 ) -> bool {
6769     use_counters.counted_unknown_properties.recorded(p)
6770 }
6771 
6772 #[no_mangle]
Servo_IsCssPropertyRecordedInUseCounter( use_counters: &UseCounters, property: &nsACString, known_prop: *mut bool, ) -> bool6773 pub unsafe extern "C" fn Servo_IsCssPropertyRecordedInUseCounter(
6774     use_counters: &UseCounters,
6775     property: &nsACString,
6776     known_prop: *mut bool,
6777 ) -> bool {
6778     *known_prop = false;
6779 
6780     let prop_name = property.as_str_unchecked();
6781     if let Ok(p) = PropertyId::parse_unchecked_for_testing(prop_name) {
6782         if let Some(id) = p.non_custom_id() {
6783             *known_prop = true;
6784             return use_counters.non_custom_properties.recorded(id);
6785         }
6786     }
6787 
6788     if let Some(p) = CountedUnknownProperty::parse_for_testing(prop_name) {
6789         *known_prop = true;
6790         return use_counters.counted_unknown_properties.recorded(p)
6791     }
6792 
6793     false
6794 }
6795 
6796 #[no_mangle]
Servo_SharedMemoryBuilder_Create( buffer: *mut u8, len: usize, ) -> *mut RawServoSharedMemoryBuilder6797 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Create(
6798     buffer: *mut u8,
6799     len: usize,
6800 ) -> *mut RawServoSharedMemoryBuilder {
6801     let mut builder = Box::new(SharedMemoryBuilder::new(buffer, len));
6802 
6803     // We have Arc<UnparsedValue>s in style sheets due to CSS variables being
6804     // used in shorthand property declarations.  There aren't many, though,
6805     // and they aren't big, so we just allow their duplication for now.
6806     builder.add_allowed_duplication_type::<UnparsedValue>();
6807 
6808     Box::into_raw(builder) as *mut _
6809 }
6810 
6811 #[no_mangle]
Servo_SharedMemoryBuilder_AddStylesheet( builder: &mut RawServoSharedMemoryBuilder, raw_contents: &RawServoStyleSheetContents, error_message: &mut nsACString, ) -> *const ServoCssRules6812 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_AddStylesheet(
6813     builder: &mut RawServoSharedMemoryBuilder,
6814     raw_contents: &RawServoStyleSheetContents,
6815     error_message: &mut nsACString,
6816 ) -> *const ServoCssRules {
6817     let builder = SharedMemoryBuilder::from_ffi_mut(builder);
6818     let contents = StylesheetContents::as_arc(&raw_contents);
6819 
6820     // Assert some things we assume when we create a style sheet from shared
6821     // memory.
6822     debug_assert_eq!(contents.origin, Origin::UserAgent);
6823     debug_assert_eq!(contents.quirks_mode, QuirksMode::NoQuirks);
6824     debug_assert!(contents.source_map_url.read().is_none());
6825     debug_assert!(contents.source_url.read().is_none());
6826 
6827     match builder.write(&contents.rules) {
6828         Ok(rules_ptr) => {
6829             (*rules_ptr).with_raw_offset_arc(|arc| *Locked::arc_as_borrowed(arc) as *const _)
6830         },
6831         Err(message) => {
6832             error_message.assign(&message);
6833             ptr::null()
6834         },
6835     }
6836 }
6837 
6838 #[no_mangle]
Servo_SharedMemoryBuilder_GetLength( builder: &mut RawServoSharedMemoryBuilder, ) -> usize6839 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_GetLength(
6840     builder: &mut RawServoSharedMemoryBuilder,
6841 ) -> usize {
6842     let builder = SharedMemoryBuilder::from_ffi_mut(builder);
6843     builder.len()
6844 }
6845 
6846 #[no_mangle]
Servo_SharedMemoryBuilder_Drop(builder: *mut RawServoSharedMemoryBuilder)6847 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Drop(builder: *mut RawServoSharedMemoryBuilder) {
6848     SharedMemoryBuilder::drop_ffi(builder)
6849 }
6850 
6851 /// Returns a unique pointer to a clone of the shape image.
6852 ///
6853 /// Probably temporary, as we move more stuff to cbindgen.
6854 #[no_mangle]
6855 #[must_use]
Servo_CloneBasicShape( v: &computed::basic_shape::BasicShape, ) -> *mut computed::basic_shape::BasicShape6856 pub unsafe extern "C" fn Servo_CloneBasicShape(
6857     v: &computed::basic_shape::BasicShape,
6858 ) -> *mut computed::basic_shape::BasicShape {
6859     Box::into_raw(Box::new(v.clone()))
6860 }
6861 
6862 #[no_mangle]
Servo_StyleArcSlice_EmptyPtr() -> *mut c_void6863 pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void {
6864     style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr()
6865 }
6866 
6867 #[no_mangle]
Servo_LoadData_GetLazy( source: &url::LoadDataSource, ) -> *const url::LoadData6868 pub unsafe extern "C" fn Servo_LoadData_GetLazy(
6869     source: &url::LoadDataSource,
6870 ) -> *const url::LoadData {
6871     source.get()
6872 }
6873 
6874 #[no_mangle]
Servo_LengthPercentage_ToCss( lp: &computed::LengthPercentage, result: &mut nsAString )6875 pub extern "C" fn Servo_LengthPercentage_ToCss(
6876     lp: &computed::LengthPercentage,
6877     result: &mut nsAString
6878 ) {
6879     lp.to_css(&mut CssWriter::new(result)).unwrap();
6880 }
6881 
6882 #[no_mangle]
Servo_CursorKind_Parse( cursor: &nsACString, result: &mut computed::ui::CursorKind, ) -> bool6883 pub unsafe extern "C" fn Servo_CursorKind_Parse(
6884     cursor: &nsACString,
6885     result: &mut computed::ui::CursorKind,
6886 ) -> bool {
6887     match computed::ui::CursorKind::from_ident(cursor.as_str_unchecked()) {
6888         Ok(c) => {
6889             *result = c;
6890             true
6891         }
6892         Err(..) => false,
6893     }
6894 }
6895