Backed out 2 changesets (bug 1287054) for causing Android wpt failures in SVGLength...
[gecko.git] / servo / ports / geckolib / glue.rs
blob4810ff1891f2386b8745b55e4b1490c1ca2309f9
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/. */
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::{Parser, ParserInput, SourceLocation, UnicodeRange};
10 use dom::{DocumentState, ElementState};
11 use malloc_size_of::MallocSizeOfOps;
12 use nsstring::{nsCString, nsString};
13 use selectors::matching::{MatchingForInvalidation, SelectorCaches};
14 use servo_arc::{Arc, ArcBorrow};
15 use smallvec::SmallVec;
16 use style::values::generics::color::ColorMixFlags;
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::color::mix::ColorInterpolationMethod;
23 use style::color::{AbsoluteColor, ColorSpace};
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::error_reporting::ParseErrorReporter;
31 use style::font_face::{self, FontFaceSourceFormat, FontFaceSourceListComponent, Source};
32 use style::gecko::arc_types::{
33     LockedCounterStyleRule, LockedCssRules, LockedDeclarationBlock, LockedFontFaceRule,
34     LockedImportRule, LockedKeyframe, LockedKeyframesRule, LockedMediaList, LockedPageRule,
35     LockedStyleRule,
37 use style::gecko::data::{
38     AuthorStyles, GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl,
40 use style::gecko::restyle_damage::GeckoRestyleDamage;
41 use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement};
42 use style::gecko::snapshot_helpers::classes_changed;
43 use style::gecko::traversal::RecalcStyleOnly;
44 use style::gecko::url;
45 use style::gecko::wrapper::{GeckoElement, GeckoNode};
46 use style::gecko_bindings::bindings;
47 use style::gecko_bindings::bindings::nsACString;
48 use style::gecko_bindings::bindings::nsAString;
49 use style::gecko_bindings::bindings::Gecko_AddPropertyToSet;
50 use style::gecko_bindings::bindings::Gecko_AppendPropertyValuePair;
51 use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet;
52 use style::gecko_bindings::bindings::Gecko_ConstructFontPaletteValueSet;
53 use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
54 use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
55 use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
56 use style::gecko_bindings::bindings::Gecko_HaveSeenPtr;
57 use style::gecko_bindings::structs;
58 use style::gecko_bindings::structs::GeckoFontMetrics;
59 use style::gecko_bindings::structs::gfx::FontPaletteValueSet;
60 use style::gecko_bindings::structs::gfxFontFeatureValueSet;
61 use style::gecko_bindings::structs::ipc::ByteBuf;
62 use style::gecko_bindings::structs::nsAtom;
63 use style::gecko_bindings::structs::nsCSSCounterDesc;
64 use style::gecko_bindings::structs::nsCSSFontDesc;
65 use style::gecko_bindings::structs::nsCSSPropertyID;
66 use style::gecko_bindings::structs::nsChangeHint;
67 use style::gecko_bindings::structs::nsCompatibility;
68 use style::gecko_bindings::structs::nsStyleTransformMatrix::MatrixTransformOperator;
69 use style::gecko_bindings::structs::nsTArray;
70 use style::gecko_bindings::structs::nsresult;
71 use style::gecko_bindings::structs::CallerType;
72 use style::gecko_bindings::structs::CompositeOperation;
73 use style::gecko_bindings::structs::DeclarationBlockMutationClosure;
74 use style::gecko_bindings::structs::IterationCompositeOperation;
75 use style::gecko_bindings::structs::Loader;
76 use style::gecko_bindings::structs::LoaderReusableStyleSheets;
77 use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf;
78 use style::gecko_bindings::structs::OriginFlags;
79 use style::gecko_bindings::structs::PropertyValuePair;
80 use style::gecko_bindings::structs::PseudoStyleType;
81 use style::gecko_bindings::structs::SeenPtrs;
82 use style::gecko_bindings::structs::ServoElementSnapshotTable;
83 use style::gecko_bindings::structs::ServoStyleSetSizes;
84 use style::gecko_bindings::structs::ServoTraversalFlags;
85 use style::gecko_bindings::structs::SheetLoadData;
86 use style::gecko_bindings::structs::SheetLoadDataHolder;
87 use style::gecko_bindings::structs::SheetParsingMode;
88 use style::gecko_bindings::structs::StyleRuleInclusion;
89 use style::gecko_bindings::structs::StyleSheet as DomStyleSheet;
90 use style::gecko_bindings::structs::URLExtraData;
91 use style::gecko_bindings::structs::{nsINode as RawGeckoNode, Element as RawGeckoElement};
92 use style::gecko_bindings::sugar::ownership::Strong;
93 use style::gecko_bindings::sugar::refptr::RefPtr;
94 use style::global_style_data::{
95     GlobalStyleData, PlatformThreadHandle, StyleThreadPool, GLOBAL_STYLE_DATA, STYLE_THREAD_POOL,
97 use style::invalidation::element::restyle_hints::RestyleHint;
98 use style::invalidation::stylesheets::RuleChangeKind;
99 use style::media_queries::MediaList;
100 use style::parser::{Parse, ParserContext};
101 use style::properties::animated_properties::{AnimationValue, AnimationValueMap};
102 use style::properties::{parse_one_declaration_into, parse_style_attribute};
103 use style::properties::{ComputedValues, CountedUnknownProperty, Importance, NonCustomPropertyId};
104 use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId};
105 use style::properties::{PropertyDeclarationId, ShorthandId};
106 use style::properties::{SourcePropertyDeclaration, StyleBuilder};
107 use style::properties_and_values::rule::Inherits as PropertyInherits;
108 use style::rule_cache::RuleCacheConditions;
109 use style::rule_tree::StrongRuleNode;
110 use style::selector_parser::PseudoElementCascadeType;
111 use style::shared_lock::{
112     Locked, SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard,
114 use style::string_cache::{Atom, WeakAtom};
115 use style::style_adjuster::StyleAdjuster;
116 use style::stylesheets::container_rule::ContainerSizeQuery;
117 use style::stylesheets::import_rule::{ImportLayer, ImportSheet};
118 use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
119 use style::stylesheets::supports_rule::parse_condition_or_declaration;
120 use style::stylesheets::{
121     AllowImportRules, ContainerRule, CounterStyleRule, CssRule, CssRuleType, CssRuleTypes,
122     CssRules, CssRulesHelpers, DocumentRule, FontFaceRule, FontFeatureValuesRule,
123     FontPaletteValuesRule, ImportRule, KeyframesRule, LayerBlockRule, LayerStatementRule,
124     MediaRule, NamespaceRule, Origin, OriginSet, PagePseudoClassFlags, PageRule, PropertyRule,
125     SanitizationData, SanitizationKind, StyleRule, StylesheetContents, StylesheetLoader as
126     StyleStylesheetLoader, SupportsRule, UrlExtraData,
128 use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
129 use style::thread_state;
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::easing::ComputedTimingFunction;
136 use style::values::computed::effects::Filter;
137 use style::values::computed::font::{
138     FamilyName, FontFamily, FontFamilyList, FontStretch, FontStyle, FontWeight, GenericFontFamily,
140 use style::values::computed::{self, Context, ToComputedValue};
141 use style::values::distance::ComputeSquaredDistance;
142 use style::values::generics::easing::BeforeFlag;
143 use style::values::specified::gecko::IntersectionObserverRootMargin;
144 use style::values::specified::source_size_list::SourceSizeList;
145 use style::values::specified::{AbsoluteLength, NoCalcLength};
146 use style::values::{specified, AtomIdent, CustomIdent, KeyframesName};
147 use style_traits::{CssWriter, ParseError, ParsingMode, ToCss};
148 use thin_vec::ThinVec;
149 use to_shmem::SharedMemoryBuilder;
151 trait ClosureHelper {
152     fn invoke(&self, property_id: Option<NonCustomPropertyId>);
155 impl ClosureHelper for DeclarationBlockMutationClosure {
156     #[inline]
157     fn invoke(&self, property_id: Option<NonCustomPropertyId>) {
158         if let Some(function) = self.function.as_ref() {
159             let gecko_prop_id = match property_id {
160                 Some(p) => p.to_nscsspropertyid(),
161                 None => nsCSSPropertyID::eCSSPropertyExtra_variable,
162             };
163             unsafe { function(self.data, gecko_prop_id) }
164         }
165     }
169  * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
170  * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
171  * those signatures as well, giving us a second declaration of all the Servo_* functions in this
172  * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
173  * depend on but good enough for our purposes.
174  */
176 // A dummy url data for where we don't pass url data in.
177 static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut _;
178 static mut DUMMY_CHROME_URL_DATA: *mut URLExtraData = 0 as *mut _;
180 #[no_mangle]
181 pub unsafe extern "C" fn Servo_Initialize(
182     dummy_url_data: *mut URLExtraData,
183     dummy_chrome_url_data: *mut URLExtraData,
184 ) {
185     use style::gecko_bindings::sugar::origin_flags;
187     // Pretend that we're a Servo Layout thread, to make some assertions happy.
188     thread_state::initialize(thread_state::ThreadState::LAYOUT);
190     // Perform some debug-only runtime assertions.
191     origin_flags::assert_flags_match();
192     traversal_flags::assert_traversal_flags_match();
193     specified::font::assert_variant_east_asian_matches();
194     specified::font::assert_variant_ligatures_matches();
196     DUMMY_URL_DATA = dummy_url_data;
197     DUMMY_CHROME_URL_DATA = dummy_chrome_url_data;
200 #[no_mangle]
201 pub unsafe extern "C" fn Servo_Shutdown() {
202     DUMMY_URL_DATA = ptr::null_mut();
203     DUMMY_CHROME_URL_DATA = ptr::null_mut();
204     Stylist::shutdown();
205     url::shutdown();
208 #[inline(always)]
209 unsafe fn dummy_url_data() -> &'static UrlExtraData {
210     UrlExtraData::from_ptr_ref(&DUMMY_URL_DATA)
213 #[allow(dead_code)]
214 fn is_main_thread() -> bool {
215     unsafe { bindings::Gecko_IsMainThread() }
218 #[allow(dead_code)]
219 fn is_dom_worker_thread() -> bool {
220     unsafe { bindings::Gecko_IsDOMWorkerThread() }
223 thread_local! {
224     /// Thread-local style data for DOM workers
225     static DOM_WORKER_RWLOCK: SharedRwLock = SharedRwLock::new();
228 #[allow(dead_code)]
229 fn is_in_servo_traversal() -> bool {
230     unsafe { bindings::Gecko_IsInServoTraversal() }
233 fn create_shared_context<'a>(
234     global_style_data: &GlobalStyleData,
235     guard: &'a SharedRwLockReadGuard,
236     stylist: &'a Stylist,
237     traversal_flags: TraversalFlags,
238     snapshot_map: &'a ServoElementSnapshotTable,
239 ) -> SharedStyleContext<'a> {
240     SharedStyleContext {
241         stylist: &stylist,
242         visited_styles_enabled: stylist.device().visited_styles_enabled(),
243         options: global_style_data.options.clone(),
244         guards: StylesheetGuards::same(guard),
245         current_time_for_animations: 0.0, // Unused for Gecko, at least for now.
246         traversal_flags,
247         snapshot_map,
248     }
251 fn traverse_subtree(
252     element: GeckoElement,
253     global_style_data: &GlobalStyleData,
254     per_doc_data: &PerDocumentStyleDataImpl,
255     guard: &SharedRwLockReadGuard,
256     traversal_flags: TraversalFlags,
257     snapshots: &ServoElementSnapshotTable,
258 ) {
259     let shared_style_context = create_shared_context(
260         &global_style_data,
261         &guard,
262         &per_doc_data.stylist,
263         traversal_flags,
264         snapshots,
265     );
267     let token = RecalcStyleOnly::pre_traverse(element, &shared_style_context);
269     if !token.should_traverse() {
270         return;
271     }
273     debug!("Traversing subtree from {:?}", element);
275     let thread_pool_holder = &*STYLE_THREAD_POOL;
276     let pool;
277     let thread_pool = if traversal_flags.contains(TraversalFlags::ParallelTraversal) {
278         pool = thread_pool_holder.pool();
279         pool.as_ref()
280     } else {
281         None
282     };
284     let traversal = RecalcStyleOnly::new(shared_style_context);
285     driver::traverse_dom(&traversal, token, thread_pool);
288 /// Traverses the subtree rooted at `root` for restyling.
290 /// Returns whether the root was restyled. Whether anything else was restyled or
291 /// not can be inferred from the dirty bits in the rest of the tree.
292 #[no_mangle]
293 pub extern "C" fn Servo_TraverseSubtree(
294     root: &RawGeckoElement,
295     raw_data: &PerDocumentStyleData,
296     snapshots: *const ServoElementSnapshotTable,
297     raw_flags: ServoTraversalFlags,
298 ) -> bool {
299     let traversal_flags = TraversalFlags::from_bits_truncate(raw_flags);
300     debug_assert!(!snapshots.is_null());
302     let element = GeckoElement(root);
304     debug!("Servo_TraverseSubtree (flags={:?})", traversal_flags);
305     debug!("{:?}", ShowSubtreeData(element.as_node()));
307     if cfg!(debug_assertions) {
308         if let Some(parent) = element.traversal_parent() {
309             let data = parent
310                 .borrow_data()
311                 .expect("Styling element with unstyled parent");
312             assert!(
313                 !data.styles.is_display_none(),
314                 "Styling element with display: none parent"
315             );
316         }
317     }
319     let needs_animation_only_restyle =
320         element.has_animation_only_dirty_descendants() || element.has_animation_restyle_hints();
322     let per_doc_data = raw_data.borrow();
323     debug_assert!(!per_doc_data.stylist.stylesheets_have_changed());
325     let global_style_data = &*GLOBAL_STYLE_DATA;
326     let guard = global_style_data.shared_lock.read();
328     let was_initial_style = !element.has_data();
330     if needs_animation_only_restyle {
331         debug!(
332             "Servo_TraverseSubtree doing animation-only restyle (aodd={})",
333             element.has_animation_only_dirty_descendants()
334         );
335         traverse_subtree(
336             element,
337             &global_style_data,
338             &per_doc_data,
339             &guard,
340             traversal_flags | TraversalFlags::AnimationOnly,
341             unsafe { &*snapshots },
342         );
343     }
345     traverse_subtree(
346         element,
347         &global_style_data,
348         &per_doc_data,
349         &guard,
350         traversal_flags,
351         unsafe { &*snapshots },
352     );
354     debug!(
355         "Servo_TraverseSubtree complete (dd={}, aodd={}, lfcd={}, lfc={}, data={:?})",
356         element.has_dirty_descendants(),
357         element.has_animation_only_dirty_descendants(),
358         element.descendants_need_frames(),
359         element.needs_frame(),
360         element.borrow_data().unwrap()
361     );
363     if was_initial_style {
364         debug_assert!(!element.borrow_data().unwrap().contains_restyle_data());
365         false
366     } else {
367         let element_was_restyled = element.borrow_data().unwrap().contains_restyle_data();
368         element_was_restyled
369     }
372 /// Checks whether the rule tree has crossed its threshold for unused nodes, and
373 /// if so, frees them.
374 #[no_mangle]
375 pub extern "C" fn Servo_MaybeGCRuleTree(raw_data: &PerDocumentStyleData) {
376     let per_doc_data = raw_data.borrow_mut();
377     per_doc_data.stylist.rule_tree().maybe_gc();
380 #[no_mangle]
381 pub extern "C" fn Servo_AnimationValues_Interpolate(
382     from: &AnimationValue,
383     to: &AnimationValue,
384     progress: f64,
385 ) -> Strong<AnimationValue> {
386     if let Ok(value) = from.animate(to, Procedure::Interpolate { progress }) {
387         Arc::new(value).into()
388     } else {
389         Strong::null()
390     }
393 #[no_mangle]
394 pub extern "C" fn Servo_AnimationValues_IsInterpolable(
395     from: &AnimationValue,
396     to: &AnimationValue,
397 ) -> bool {
398     from.animate(to, Procedure::Interpolate { progress: 0.5 })
399         .is_ok()
402 #[no_mangle]
403 pub extern "C" fn Servo_AnimationValues_Add(
404     a: &AnimationValue,
405     b: &AnimationValue,
406 ) -> Strong<AnimationValue> {
407     if let Ok(value) = a.animate(b, Procedure::Add) {
408         Arc::new(value).into()
409     } else {
410         Strong::null()
411     }
414 #[no_mangle]
415 pub extern "C" fn Servo_AnimationValues_Accumulate(
416     a: &AnimationValue,
417     b: &AnimationValue,
418     count: u64,
419 ) -> Strong<AnimationValue> {
420     if let Ok(value) = a.animate(b, Procedure::Accumulate { count }) {
421         Arc::new(value).into()
422     } else {
423         Strong::null()
424     }
427 #[no_mangle]
428 pub extern "C" fn Servo_AnimationValues_GetZeroValue(
429     value_to_match: &AnimationValue,
430 ) -> Strong<AnimationValue> {
431     if let Ok(zero_value) = value_to_match.to_animated_zero() {
432         Arc::new(zero_value).into()
433     } else {
434         Strong::null()
435     }
438 #[no_mangle]
439 pub extern "C" fn Servo_AnimationValues_ComputeDistance(
440     from: &AnimationValue,
441     to: &AnimationValue,
442 ) -> f64 {
443     // If compute_squared_distance() failed, this function will return negative value
444     // in order to check whether we support the specified paced animation values.
445     from.compute_squared_distance(to).map_or(-1.0, |d| d.sqrt())
448 /// Compute one of the endpoints for the interpolation interval, compositing it with the
449 /// underlying value if needed.
450 /// An None returned value means, "Just use endpoint_value as-is."
451 /// It is the responsibility of the caller to ensure that |underlying_value| is provided
452 /// when it will be used.
453 fn composite_endpoint(
454     endpoint_value: Option<&AnimationValue>,
455     composite: CompositeOperation,
456     underlying_value: Option<&AnimationValue>,
457 ) -> Option<AnimationValue> {
458     match endpoint_value {
459         Some(endpoint_value) => match composite {
460             CompositeOperation::Add => underlying_value
461                 .expect("We should have an underlying_value")
462                 .animate(endpoint_value, Procedure::Add)
463                 .ok(),
464             CompositeOperation::Accumulate => underlying_value
465                 .expect("We should have an underlying value")
466                 .animate(endpoint_value, Procedure::Accumulate { count: 1 })
467                 .ok(),
468             _ => None,
469         },
470         None => underlying_value.map(|v| v.clone()),
471     }
474 /// Accumulate one of the endpoints of the animation interval.
475 /// A returned value of None means, "Just use endpoint_value as-is."
476 fn accumulate_endpoint(
477     endpoint_value: Option<&AnimationValue>,
478     composited_value: Option<AnimationValue>,
479     last_value: &AnimationValue,
480     current_iteration: u64,
481 ) -> Option<AnimationValue> {
482     debug_assert!(
483         endpoint_value.is_some() || composited_value.is_some(),
484         "Should have a suitable value to use"
485     );
487     let count = current_iteration;
488     match composited_value {
489         Some(endpoint) => last_value
490             .animate(&endpoint, Procedure::Accumulate { count })
491             .ok()
492             .or(Some(endpoint)),
493         None => last_value
494             .animate(endpoint_value.unwrap(), Procedure::Accumulate { count })
495             .ok(),
496     }
499 /// Compose the animation segment. We composite it with the underlying_value and last_value if
500 /// needed.
501 /// The caller is responsible for providing an underlying value and last value
502 /// in all situations where there are needed.
503 fn compose_animation_segment(
504     segment: &structs::AnimationPropertySegment,
505     underlying_value: Option<&AnimationValue>,
506     last_value: Option<&AnimationValue>,
507     iteration_composite: IterationCompositeOperation,
508     current_iteration: u64,
509     total_progress: f64,
510     segment_progress: f64,
511 ) -> AnimationValue {
512     // Extract keyframe values.
513     let keyframe_from_value = unsafe { segment.mFromValue.mServo.mRawPtr.as_ref() };
514     let keyframe_to_value = unsafe { segment.mToValue.mServo.mRawPtr.as_ref() };
515     let mut composited_from_value = composite_endpoint(
516         keyframe_from_value,
517         segment.mFromComposite,
518         underlying_value,
519     );
520     let mut composited_to_value =
521         composite_endpoint(keyframe_to_value, segment.mToComposite, underlying_value);
523     debug_assert!(
524         keyframe_from_value.is_some() || composited_from_value.is_some(),
525         "Should have a suitable from value to use"
526     );
527     debug_assert!(
528         keyframe_to_value.is_some() || composited_to_value.is_some(),
529         "Should have a suitable to value to use"
530     );
532     // Apply iteration composite behavior.
533     if iteration_composite == IterationCompositeOperation::Accumulate && current_iteration > 0 {
534         let last_value = last_value
535             .unwrap_or_else(|| underlying_value.expect("Should have a valid underlying value"));
537         composited_from_value = accumulate_endpoint(
538             keyframe_from_value,
539             composited_from_value,
540             last_value,
541             current_iteration,
542         );
543         composited_to_value = accumulate_endpoint(
544             keyframe_to_value,
545             composited_to_value,
546             last_value,
547             current_iteration,
548         );
549     }
551     // Use the composited value if there is one, otherwise, use the original keyframe value.
552     let from = composited_from_value
553         .as_ref()
554         .unwrap_or_else(|| keyframe_from_value.unwrap());
555     let to = composited_to_value
556         .as_ref()
557         .unwrap_or_else(|| keyframe_to_value.unwrap());
559     if segment.mToKey == segment.mFromKey {
560         return if total_progress < 0. {
561             from.clone()
562         } else {
563             to.clone()
564         };
565     }
567     match from.animate(
568         to,
569         Procedure::Interpolate {
570             progress: segment_progress,
571         },
572     ) {
573         Ok(value) => value,
574         _ => {
575             if segment_progress < 0.5 {
576                 from.clone()
577             } else {
578                 to.clone()
579             }
580         },
581     }
584 #[no_mangle]
585 pub extern "C" fn Servo_ComposeAnimationSegment(
586     segment: &structs::AnimationPropertySegment,
587     underlying_value: Option<&AnimationValue>,
588     last_value: Option<&AnimationValue>,
589     iteration_composite: IterationCompositeOperation,
590     progress: f64,
591     current_iteration: u64,
592 ) -> Strong<AnimationValue> {
593     let result = compose_animation_segment(
594         segment,
595         underlying_value,
596         last_value,
597         iteration_composite,
598         current_iteration,
599         progress,
600         progress,
601     );
602     Arc::new(result).into()
605 #[no_mangle]
606 pub extern "C" fn Servo_AnimationCompose(
607     value_map: &mut AnimationValueMap,
608     base_values: &structs::RawServoAnimationValueTable,
609     css_property: nsCSSPropertyID,
610     segment: &structs::AnimationPropertySegment,
611     last_segment: &structs::AnimationPropertySegment,
612     computed_timing: &structs::ComputedTiming,
613     iteration_composite: IterationCompositeOperation,
614 ) {
615     use style::gecko_bindings::bindings::Gecko_AnimationGetBaseStyle;
616     use style::gecko_bindings::bindings::Gecko_GetPositionInSegment;
617     use style::gecko_bindings::bindings::Gecko_GetProgressFromComputedTiming;
619     let property = match LonghandId::from_nscsspropertyid(css_property) {
620         Ok(longhand) if longhand.is_animatable() => longhand,
621         _ => return,
622     };
624     // We will need an underlying value if either of the endpoints is null...
625     let need_underlying_value = segment.mFromValue.mServo.mRawPtr.is_null() ||
626                                 segment.mToValue.mServo.mRawPtr.is_null() ||
627                                 // ... or if they have a non-replace composite mode ...
628                                 segment.mFromComposite != CompositeOperation::Replace ||
629                                 segment.mToComposite != CompositeOperation::Replace ||
630                                 // ... or if we accumulate onto the last value and it is null.
631                                 (iteration_composite == IterationCompositeOperation::Accumulate &&
632                                  computed_timing.mCurrentIteration > 0 &&
633                                  last_segment.mToValue.mServo.mRawPtr.is_null());
635     // If either of the segment endpoints are null, get the underlying value to
636     // use from the current value in the values map (set by a lower-priority
637     // effect), or, if there is no current value, look up the cached base value
638     // for this property.
639     let underlying_value = if need_underlying_value {
640         let previous_composed_value = value_map.get(&property).map(|v| &*v);
641         previous_composed_value
642             .or_else(|| unsafe { Gecko_AnimationGetBaseStyle(base_values, css_property).as_ref() })
643     } else {
644         None
645     };
647     if need_underlying_value && underlying_value.is_none() {
648         warn!("Underlying value should be valid when we expect to use it");
649         return;
650     }
652     let last_value = unsafe { last_segment.mToValue.mServo.mRawPtr.as_ref() };
653     let progress = unsafe { Gecko_GetProgressFromComputedTiming(computed_timing) };
654     let position = if segment.mToKey == segment.mFromKey {
655         // Note: compose_animation_segment doesn't use this value
656         // if segment.mFromKey == segment.mToKey, so assigning |progress| directly is fine.
657         progress
658     } else {
659         unsafe { Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag) }
660     };
662     let result = compose_animation_segment(
663         segment,
664         underlying_value,
665         last_value,
666         iteration_composite,
667         computed_timing.mCurrentIteration,
668         progress,
669         position,
670     );
671     value_map.insert(property, result);
674 macro_rules! get_property_id_from_nscsspropertyid {
675     ($property_id: ident, $ret: expr) => {{
676         match PropertyId::from_nscsspropertyid($property_id) {
677             Ok(property_id) => property_id,
678             Err(()) => {
679                 return $ret;
680             },
681         }
682     }};
685 #[no_mangle]
686 pub extern "C" fn Servo_AnimationValue_Serialize(
687     value: &AnimationValue,
688     property: nsCSSPropertyID,
689     raw_data: &PerDocumentStyleData,
690     buffer: &mut nsACString,
691 ) {
692     let uncomputed_value = value.uncompute();
693     let data = raw_data.borrow();
694     let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
695         .single_value_to_css(
696             &get_property_id_from_nscsspropertyid!(property, ()),
697             buffer,
698             None,
699             None, /* No extra custom properties */
700             &data.stylist,
701         );
702     debug_assert!(rv.is_ok());
705 /// Debug: MOZ_DBG for AnimationValue.
706 #[no_mangle]
707 pub extern "C" fn Servo_AnimationValue_Dump(value: &AnimationValue, result: &mut nsACString) {
708     write!(result, "{:?}", value).unwrap();
711 #[no_mangle]
712 pub extern "C" fn Servo_AnimationValue_GetColor(
713     value: &AnimationValue,
714     foreground_color: structs::nscolor,
715 ) -> structs::nscolor {
716     use style::gecko::values::{
717         convert_absolute_color_to_nscolor, convert_nscolor_to_absolute_color,
718     };
719     use style::values::computed::color::Color as ComputedColor;
720     match *value {
721         AnimationValue::BackgroundColor(ref color) => {
722             let computed: ComputedColor = color.clone();
723             let foreground_color = convert_nscolor_to_absolute_color(foreground_color);
724             convert_absolute_color_to_nscolor(&computed.resolve_to_absolute(&foreground_color))
725         },
726         _ => panic!("Other color properties are not supported yet"),
727     }
730 #[no_mangle]
731 pub extern "C" fn Servo_AnimationValue_IsCurrentColor(value: &AnimationValue) -> bool {
732     match *value {
733         AnimationValue::BackgroundColor(ref color) => color.is_currentcolor(),
734         _ => {
735             debug_assert!(false, "Other color properties are not supported yet");
736             false
737         },
738     }
741 #[no_mangle]
742 pub extern "C" fn Servo_AnimationValue_GetOpacity(value: &AnimationValue) -> f32 {
743     if let AnimationValue::Opacity(opacity) = *value {
744         opacity
745     } else {
746         panic!("The AnimationValue should be Opacity");
747     }
750 #[no_mangle]
751 pub extern "C" fn Servo_AnimationValue_Opacity(opacity: f32) -> Strong<AnimationValue> {
752     Arc::new(AnimationValue::Opacity(opacity)).into()
755 #[no_mangle]
756 pub extern "C" fn Servo_AnimationValue_Color(
757     color_property: nsCSSPropertyID,
758     color: structs::nscolor,
759 ) -> Strong<AnimationValue> {
760     use style::gecko::values::convert_nscolor_to_absolute_color;
761     use style::values::animated::color::Color;
763     let property = LonghandId::from_nscsspropertyid(color_property)
764         .expect("We don't have shorthand property animation value");
766     let animated = convert_nscolor_to_absolute_color(color);
768     match property {
769         LonghandId::BackgroundColor => {
770             Arc::new(AnimationValue::BackgroundColor(Color::Absolute(animated))).into()
771         },
772         _ => panic!("Should be background-color property"),
773     }
776 #[no_mangle]
777 pub unsafe extern "C" fn Servo_AnimationValue_GetScale(
778     value: &AnimationValue,
779 ) -> *const computed::Scale {
780     match *value {
781         AnimationValue::Scale(ref value) => value,
782         _ => unreachable!("Expected scale"),
783     }
786 #[no_mangle]
787 pub unsafe extern "C" fn Servo_AnimationValue_GetTranslate(
788     value: &AnimationValue,
789 ) -> *const computed::Translate {
790     match *value {
791         AnimationValue::Translate(ref value) => value,
792         _ => unreachable!("Expected translate"),
793     }
796 #[no_mangle]
797 pub unsafe extern "C" fn Servo_AnimationValue_GetRotate(
798     value: &AnimationValue,
799 ) -> *const computed::Rotate {
800     match *value {
801         AnimationValue::Rotate(ref value) => value,
802         _ => unreachable!("Expected rotate"),
803     }
806 #[no_mangle]
807 pub unsafe extern "C" fn Servo_AnimationValue_GetTransform(
808     value: &AnimationValue,
809 ) -> *const computed::Transform {
810     match *value {
811         AnimationValue::Transform(ref value) => value,
812         _ => unreachable!("Unsupported transform animation value"),
813     }
816 #[no_mangle]
817 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPath(
818     value: &AnimationValue,
819     output: &mut computed::motion::OffsetPath,
820 ) {
821     use style::values::animated::ToAnimatedValue;
822     match *value {
823         AnimationValue::OffsetPath(ref value) => {
824             *output = ToAnimatedValue::from_animated_value(value.clone())
825         },
826         _ => unreachable!("Expected offset-path"),
827     }
830 #[no_mangle]
831 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetDistance(
832     value: &AnimationValue,
833 ) -> *const computed::LengthPercentage {
834     match *value {
835         AnimationValue::OffsetDistance(ref value) => value,
836         _ => unreachable!("Expected offset-distance"),
837     }
840 #[no_mangle]
841 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetRotate(
842     value: &AnimationValue,
843 ) -> *const computed::motion::OffsetRotate {
844     match *value {
845         AnimationValue::OffsetRotate(ref value) => value,
846         _ => unreachable!("Expected offset-rotate"),
847     }
850 #[no_mangle]
851 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetAnchor(
852     value: &AnimationValue,
853 ) -> *const computed::position::PositionOrAuto {
854     match *value {
855         AnimationValue::OffsetAnchor(ref value) => value,
856         _ => unreachable!("Expected offset-anchor"),
857     }
860 #[no_mangle]
861 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPosition(
862     value: &AnimationValue,
863 ) -> *const computed::motion::OffsetPosition {
864     match *value {
865         AnimationValue::OffsetPosition(ref value) => value,
866         _ => unreachable!("Expected offset-position"),
867     }
870 #[no_mangle]
871 pub unsafe extern "C" fn Servo_AnimationValue_IsOffsetPathUrl(
872     value: &AnimationValue,
873 ) -> bool {
874     use style::values::generics::motion::{GenericOffsetPath, GenericOffsetPathFunction};
875     if let AnimationValue::OffsetPath(ref op) = value {
876         if let GenericOffsetPath::OffsetPath { path, coord_box: _ } = op {
877             return matches!(**path, GenericOffsetPathFunction::Url(_));
878         }
879     }
880     false
883 #[no_mangle]
884 pub unsafe extern "C" fn Servo_AnimationValue_Rotate(
885     r: &computed::Rotate,
886 ) -> Strong<AnimationValue> {
887     Arc::new(AnimationValue::Rotate(r.clone())).into()
890 #[no_mangle]
891 pub unsafe extern "C" fn Servo_AnimationValue_Translate(
892     t: &computed::Translate,
893 ) -> Strong<AnimationValue> {
894     Arc::new(AnimationValue::Translate(t.clone())).into()
897 #[no_mangle]
898 pub unsafe extern "C" fn Servo_AnimationValue_Scale(s: &computed::Scale) -> Strong<AnimationValue> {
899     Arc::new(AnimationValue::Scale(s.clone())).into()
902 #[no_mangle]
903 pub unsafe extern "C" fn Servo_AnimationValue_Transform(
904     transform: &computed::Transform,
905 ) -> Strong<AnimationValue> {
906     Arc::new(AnimationValue::Transform(transform.clone())).into()
909 #[no_mangle]
910 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPath(
911     p: &computed::motion::OffsetPath,
912 ) -> Strong<AnimationValue> {
913     use style::values::animated::ToAnimatedValue;
914     Arc::new(AnimationValue::OffsetPath(p.clone().to_animated_value())).into()
917 #[no_mangle]
918 pub unsafe extern "C" fn Servo_AnimationValue_OffsetDistance(
919     d: &computed::LengthPercentage,
920 ) -> Strong<AnimationValue> {
921     Arc::new(AnimationValue::OffsetDistance(d.clone())).into()
924 #[no_mangle]
925 pub unsafe extern "C" fn Servo_AnimationValue_OffsetRotate(
926     r: &computed::motion::OffsetRotate,
927 ) -> Strong<AnimationValue> {
928     Arc::new(AnimationValue::OffsetRotate(*r)).into()
931 #[no_mangle]
932 pub unsafe extern "C" fn Servo_AnimationValue_OffsetAnchor(
933     p: &computed::position::PositionOrAuto,
934 ) -> Strong<AnimationValue> {
935     Arc::new(AnimationValue::OffsetAnchor(p.clone())).into()
938 #[no_mangle]
939 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPosition(
940     p: &computed::motion::OffsetPosition,
941 ) -> Strong<AnimationValue> {
942     Arc::new(AnimationValue::OffsetPosition(p.clone())).into()
945 #[no_mangle]
946 pub extern "C" fn Servo_AnimationValue_DeepEqual(
947     this: &AnimationValue,
948     other: &AnimationValue,
949 ) -> bool {
950     this == other
953 #[no_mangle]
954 pub extern "C" fn Servo_AnimationValue_Uncompute(
955     value: &AnimationValue,
956 ) -> Strong<LockedDeclarationBlock> {
957     let global_style_data = &*GLOBAL_STYLE_DATA;
958     Arc::new(
959         global_style_data
960             .shared_lock
961             .wrap(PropertyDeclarationBlock::with_one(
962                 value.uncompute(),
963                 Importance::Normal,
964             )),
965     )
966     .into()
969 #[inline]
970 fn create_byte_buf_from_vec(mut v: Vec<u8>) -> ByteBuf {
971     let w = ByteBuf {
972         mData: v.as_mut_ptr(),
973         mLen: v.len(),
974         mCapacity: v.capacity(),
975     };
976     std::mem::forget(v);
977     w
980 #[inline]
981 fn view_byte_buf(b: &ByteBuf) -> &[u8] {
982     if b.mData.is_null() {
983         debug_assert_eq!(b.mCapacity, 0);
984         return &[];
985     }
986     unsafe { std::slice::from_raw_parts(b.mData, b.mLen) }
989 macro_rules! impl_basic_serde_funcs {
990     ($ser_name:ident, $de_name:ident, $computed_type:ty) => {
991         #[no_mangle]
992         pub extern "C" fn $ser_name(v: &$computed_type, output: &mut ByteBuf) -> bool {
993             let buf = match serialize(v) {
994                 Ok(buf) => buf,
995                 Err(..) => return false,
996             };
998             *output = create_byte_buf_from_vec(buf);
999             true
1000         }
1002         #[no_mangle]
1003         pub unsafe extern "C" fn $de_name(input: &ByteBuf, v: *mut $computed_type) -> bool {
1004             let buf = match deserialize(view_byte_buf(input)) {
1005                 Ok(buf) => buf,
1006                 Err(..) => return false,
1007             };
1009             std::ptr::write(v, buf);
1010             true
1011         }
1012     };
1015 impl_basic_serde_funcs!(
1016     Servo_LengthPercentage_Serialize,
1017     Servo_LengthPercentage_Deserialize,
1018     computed::LengthPercentage
1021 impl_basic_serde_funcs!(
1022     Servo_StyleRotate_Serialize,
1023     Servo_StyleRotate_Deserialize,
1024     computed::transform::Rotate
1027 impl_basic_serde_funcs!(
1028     Servo_StyleScale_Serialize,
1029     Servo_StyleScale_Deserialize,
1030     computed::transform::Scale
1033 impl_basic_serde_funcs!(
1034     Servo_StyleTranslate_Serialize,
1035     Servo_StyleTranslate_Deserialize,
1036     computed::transform::Translate
1039 impl_basic_serde_funcs!(
1040     Servo_StyleTransform_Serialize,
1041     Servo_StyleTransform_Deserialize,
1042     computed::transform::Transform
1045 impl_basic_serde_funcs!(
1046     Servo_StyleOffsetPath_Serialize,
1047     Servo_StyleOffsetPath_Deserialize,
1048     computed::motion::OffsetPath
1051 impl_basic_serde_funcs!(
1052     Servo_StyleOffsetRotate_Serialize,
1053     Servo_StyleOffsetRotate_Deserialize,
1054     computed::motion::OffsetRotate
1057 impl_basic_serde_funcs!(
1058     Servo_StylePositionOrAuto_Serialize,
1059     Servo_StylePositionOrAuto_Deserialize,
1060     computed::position::PositionOrAuto
1063 impl_basic_serde_funcs!(
1064     Servo_StyleOffsetPosition_Serialize,
1065     Servo_StyleOffsetPosition_Deserialize,
1066     computed::motion::OffsetPosition
1069 impl_basic_serde_funcs!(
1070     Servo_StyleComputedTimingFunction_Serialize,
1071     Servo_StyleComputedTimingFunction_Deserialize,
1072     ComputedTimingFunction
1075 // Return the ComputedValues by a base ComputedValues and the rules.
1076 fn resolve_rules_for_element_with_context<'a>(
1077     element: GeckoElement<'a>,
1078     mut context: StyleContext<GeckoElement<'a>>,
1079     rules: StrongRuleNode,
1080     original_computed_values: &ComputedValues,
1081 ) -> Arc<ComputedValues> {
1082     use style::style_resolver::{PseudoElementResolution, StyleResolverForElement};
1084     // This currently ignores visited styles, which seems acceptable, as
1085     // existing browsers don't appear to animate visited styles.
1086     let inputs = CascadeInputs {
1087         rules: Some(rules),
1088         visited_rules: None,
1089         flags: original_computed_values.flags.for_cascade_inputs(),
1090     };
1092     // Actually `PseudoElementResolution` doesn't matter.
1093     let mut resolver = StyleResolverForElement::new(
1094         element,
1095         &mut context,
1096         RuleInclusion::All,
1097         PseudoElementResolution::IfApplicable,
1098     );
1099     resolver
1100         .cascade_style_and_visited_with_default_parents(inputs)
1101         .0
1104 #[no_mangle]
1105 pub extern "C" fn Servo_AnimationValueMap_Create() -> *mut AnimationValueMap {
1106     Box::into_raw(Box::default())
1109 #[no_mangle]
1110 pub unsafe extern "C" fn Servo_AnimationValueMap_Drop(value_map: *mut AnimationValueMap) {
1111     let _ = Box::from_raw(value_map);
1114 #[no_mangle]
1115 pub extern "C" fn Servo_AnimationValueMap_GetValue(
1116     value_map: &AnimationValueMap,
1117     property_id: nsCSSPropertyID,
1118 ) -> Strong<AnimationValue> {
1119     let property = match LonghandId::from_nscsspropertyid(property_id) {
1120         Ok(longhand) => longhand,
1121         Err(()) => return Strong::null(),
1122     };
1123     value_map
1124         .get(&property)
1125         .map_or(Strong::null(), |value| Arc::new(value.clone()).into())
1128 #[no_mangle]
1129 pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(
1130     raw_style_set: &PerDocumentStyleData,
1131     element: &RawGeckoElement,
1132     computed_values: &ComputedValues,
1133     snapshots: *const ServoElementSnapshotTable,
1134 ) -> Strong<ComputedValues> {
1135     debug_assert!(!snapshots.is_null());
1136     let computed_values = unsafe { ArcBorrow::from_ref(computed_values) };
1138     let rules = match computed_values.rules {
1139         None => return computed_values.clone_arc().into(),
1140         Some(ref rules) => rules,
1141     };
1143     let doc_data = raw_style_set.borrow();
1144     let without_animations_rules = doc_data.stylist.rule_tree().remove_animation_rules(rules);
1145     if without_animations_rules == *rules {
1146         return computed_values.clone_arc().into();
1147     }
1149     let element = GeckoElement(element);
1151     let global_style_data = &*GLOBAL_STYLE_DATA;
1152     let guard = global_style_data.shared_lock.read();
1153     let shared = create_shared_context(
1154         &global_style_data,
1155         &guard,
1156         &doc_data.stylist,
1157         TraversalFlags::empty(),
1158         unsafe { &*snapshots },
1159     );
1160     let mut tlc = ThreadLocalStyleContext::new();
1161     let context = StyleContext {
1162         shared: &shared,
1163         thread_local: &mut tlc,
1164     };
1166     resolve_rules_for_element_with_context(
1167         element,
1168         context,
1169         without_animations_rules,
1170         &computed_values,
1171     )
1172     .into()
1175 #[no_mangle]
1176 pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue(
1177     computed_values: &ComputedValues,
1178     property_id: nsCSSPropertyID,
1179 ) -> Strong<AnimationValue> {
1180     let property = match LonghandId::from_nscsspropertyid(property_id) {
1181         Ok(longhand) => longhand,
1182         Err(()) => return Strong::null(),
1183     };
1184     match AnimationValue::from_computed_values(property, &computed_values) {
1185         Some(v) => Arc::new(v).into(),
1186         None => Strong::null(),
1187     }
1190 #[no_mangle]
1191 pub extern "C" fn Servo_ResolveLogicalProperty(
1192     property_id: nsCSSPropertyID,
1193     style: &ComputedValues,
1194 ) -> nsCSSPropertyID {
1195     let longhand = LonghandId::from_nscsspropertyid(property_id)
1196         .expect("We shouldn't need to care about shorthands");
1198     longhand
1199         .to_physical(style.writing_mode)
1200         .to_nscsspropertyid()
1203 #[no_mangle]
1204 pub unsafe extern "C" fn Servo_Property_LookupEnabledForAllContent(
1205     prop: &nsACString,
1206 ) -> nsCSSPropertyID {
1207     match PropertyId::parse_enabled_for_all_content(prop.as_str_unchecked()) {
1208         Ok(p) => p.to_nscsspropertyid_resolving_aliases(),
1209         Err(..) => nsCSSPropertyID::eCSSProperty_UNKNOWN,
1210     }
1213 #[no_mangle]
1214 pub unsafe extern "C" fn Servo_Property_GetName(
1215     prop: nsCSSPropertyID,
1216     out_length: *mut u32,
1217 ) -> *const u8 {
1218     let (ptr, len) = match NonCustomPropertyId::from_nscsspropertyid(prop) {
1219         Ok(p) => {
1220             let name = p.name();
1221             (name.as_bytes().as_ptr(), name.len())
1222         },
1223         Err(..) => (ptr::null(), 0),
1224     };
1226     *out_length = len as u32;
1227     ptr
1230 macro_rules! parse_enabled_property_name {
1231     ($prop_name:ident, $found:ident, $default:expr) => {{
1232         let prop_name = $prop_name.as_str_unchecked();
1233         match PropertyId::parse_enabled_for_all_content(prop_name) {
1234             Ok(p) => {
1235                 *$found = true;
1236                 p
1237             },
1238             Err(..) => {
1239                 *$found = false;
1240                 return $default;
1241             },
1242         }
1243     }};
1246 #[no_mangle]
1247 pub unsafe extern "C" fn Servo_Property_IsShorthand(
1248     prop_name: &nsACString,
1249     found: *mut bool,
1250 ) -> bool {
1251     let prop_id = parse_enabled_property_name!(prop_name, found, false);
1252     prop_id.is_shorthand()
1255 #[no_mangle]
1256 pub unsafe extern "C" fn Servo_Property_IsInherited(prop_name: &nsACString) -> bool {
1257     let prop_name = prop_name.as_str_unchecked();
1258     let prop_id = match PropertyId::parse_enabled_for_all_content(prop_name) {
1259         Ok(id) => id,
1260         Err(_) => return false,
1261     };
1262     let longhand_id = match prop_id {
1263         PropertyId::Custom(_) => return true,
1264         PropertyId::Longhand(id) | PropertyId::LonghandAlias(id, _) => id,
1265         PropertyId::Shorthand(id) | PropertyId::ShorthandAlias(id, _) => {
1266             id.longhands().next().unwrap()
1267         },
1268     };
1269     longhand_id.inherited()
1272 #[no_mangle]
1273 pub unsafe extern "C" fn Servo_Property_SupportsType(
1274     prop_name: &nsACString,
1275     ty: u8,
1276     found: *mut bool,
1277 ) -> bool {
1278     let prop_id = parse_enabled_property_name!(prop_name, found, false);
1279     prop_id.supports_type(ty)
1282 // TODO(emilio): We could use ThinVec instead of nsTArray.
1283 #[no_mangle]
1284 pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty(
1285     prop_name: &nsACString,
1286     found: *mut bool,
1287     result: &mut nsTArray<nsString>,
1288 ) {
1289     let prop_id = parse_enabled_property_name!(prop_name, found, ());
1290     // Use B-tree set for unique and sorted result.
1291     let mut values = BTreeSet::<&'static str>::new();
1292     prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter()));
1294     let mut extras = vec![];
1295     if values.contains("transparent") {
1296         // This is a special value devtools use to avoid inserting the
1297         // long list of color keywords. We need to prepend it to values.
1298         extras.push("COLOR");
1299     }
1301     let len = extras.len() + values.len();
1302     bindings::Gecko_ResizeTArrayForStrings(result, len as u32);
1304     for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) {
1305         dest.write_str(src).unwrap();
1306     }
1309 #[no_mangle]
1310 pub extern "C" fn Servo_Property_IsAnimatable(prop: nsCSSPropertyID) -> bool {
1311     NonCustomPropertyId::from_nscsspropertyid(prop)
1312         .ok()
1313         .map_or(false, |p| p.is_animatable())
1316 #[no_mangle]
1317 pub extern "C" fn Servo_Property_IsTransitionable(prop: nsCSSPropertyID) -> bool {
1318     NonCustomPropertyId::from_nscsspropertyid(prop)
1319         .ok()
1320         .map_or(false, |p| p.is_transitionable())
1323 #[no_mangle]
1324 pub extern "C" fn Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID) -> bool {
1325     match LonghandId::from_nscsspropertyid(property) {
1326         Ok(longhand) => longhand.is_discrete_animatable(),
1327         Err(()) => return false,
1328     }
1331 #[no_mangle]
1332 pub extern "C" fn Servo_Element_ClearData(element: &RawGeckoElement) {
1333     unsafe { GeckoElement(element).clear_data() };
1336 #[no_mangle]
1337 pub extern "C" fn Servo_Element_SizeOfExcludingThisAndCVs(
1338     malloc_size_of: GeckoMallocSizeOf,
1339     malloc_enclosing_size_of: GeckoMallocSizeOf,
1340     seen_ptrs: *mut SeenPtrs,
1341     element: &RawGeckoElement,
1342 ) -> usize {
1343     let element = GeckoElement(element);
1344     let borrow = element.borrow_data();
1345     if let Some(data) = borrow {
1346         let have_seen_ptr = move |ptr| unsafe { Gecko_HaveSeenPtr(seen_ptrs, ptr) };
1347         let mut ops = MallocSizeOfOps::new(
1348             malloc_size_of.unwrap(),
1349             Some(malloc_enclosing_size_of.unwrap()),
1350             Some(Box::new(have_seen_ptr)),
1351         );
1352         (*data).size_of_excluding_cvs(&mut ops)
1353     } else {
1354         0
1355     }
1358 #[no_mangle]
1359 pub extern "C" fn Servo_Element_GetMaybeOutOfDateStyle(
1360     element: &RawGeckoElement,
1361 ) -> *const ComputedValues {
1362     let element = GeckoElement(element);
1363     let data = match element.borrow_data() {
1364         Some(d) => d,
1365         None => return ptr::null(),
1366     };
1367     &**data.styles.primary() as *const _
1370 #[no_mangle]
1371 pub extern "C" fn Servo_Element_GetMaybeOutOfDatePseudoStyle(
1372     element: &RawGeckoElement,
1373     index: usize,
1374 ) -> *const ComputedValues {
1375     let element = GeckoElement(element);
1376     let data = match element.borrow_data() {
1377         Some(d) => d,
1378         None => return ptr::null(),
1379     };
1380     match data.styles.pseudos.as_array()[index].as_ref() {
1381         Some(style) => &**style as *const _,
1382         None => ptr::null(),
1383     }
1386 #[no_mangle]
1387 pub extern "C" fn Servo_Element_IsDisplayNone(element: &RawGeckoElement) -> bool {
1388     let element = GeckoElement(element);
1389     let data = element
1390         .get_data()
1391         .expect("Invoking Servo_Element_IsDisplayNone on unstyled element");
1393     // This function is hot, so we bypass the AtomicRefCell.
1394     //
1395     // It would be nice to also assert that we're not in the servo traversal,
1396     // but this function is called at various intermediate checkpoints when
1397     // managing the traversal on the Gecko side.
1398     debug_assert!(is_main_thread());
1399     unsafe { &*data.as_ptr() }.styles.is_display_none()
1402 #[no_mangle]
1403 pub extern "C" fn Servo_Element_IsDisplayContents(element: &RawGeckoElement) -> bool {
1404     let element = GeckoElement(element);
1405     let data = element
1406         .get_data()
1407         .expect("Invoking Servo_Element_IsDisplayContents on unstyled element");
1409     debug_assert!(is_main_thread());
1410     unsafe { &*data.as_ptr() }
1411         .styles
1412         .primary()
1413         .get_box()
1414         .clone_display()
1415         .is_contents()
1418 #[no_mangle]
1419 pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGeckoElement) -> bool {
1420     let element = GeckoElement(element);
1421     let data = element
1422         .borrow_data()
1423         .expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element");
1424     data.flags
1425         .contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
1428 fn mode_to_origin(mode: SheetParsingMode) -> Origin {
1429     match mode {
1430         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
1431         SheetParsingMode::eUserSheetFeatures => Origin::User,
1432         SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
1433     }
1436 #[no_mangle]
1437 pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> Strong<StylesheetContents> {
1438     let global_style_data = &*GLOBAL_STYLE_DATA;
1439     let origin = mode_to_origin(mode);
1440     let shared_lock = &global_style_data.shared_lock;
1441     StylesheetContents::from_str(
1442         "",
1443         unsafe { dummy_url_data() }.clone(),
1444         origin,
1445         shared_lock,
1446         /* loader = */ None,
1447         None,
1448         QuirksMode::NoQuirks,
1449         /* use_counters = */ None,
1450         AllowImportRules::Yes,
1451         /* sanitization_data = */ None,
1452     )
1453     .into()
1456 /// Note: The load_data corresponds to this sheet, and is passed as the parent
1457 /// load data for child sheet loads. It may be null for certain cases where we
1458 /// know we won't have child loads.
1459 #[no_mangle]
1460 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8Bytes(
1461     loader: *mut Loader,
1462     stylesheet: *mut DomStyleSheet,
1463     load_data: *mut SheetLoadData,
1464     bytes: &nsACString,
1465     mode: SheetParsingMode,
1466     extra_data: *mut URLExtraData,
1467     quirks_mode: nsCompatibility,
1468     reusable_sheets: *mut LoaderReusableStyleSheets,
1469     use_counters: Option<&UseCounters>,
1470     allow_import_rules: AllowImportRules,
1471     sanitization_kind: SanitizationKind,
1472     sanitized_output: Option<&mut nsAString>,
1473 ) -> Strong<StylesheetContents> {
1474     let global_style_data = &*GLOBAL_STYLE_DATA;
1475     let input = bytes.as_str_unchecked();
1477     let reporter = ErrorReporter::new(stylesheet, loader, extra_data);
1478     let url_data = UrlExtraData::from_ptr_ref(&extra_data);
1479     let loader = if loader.is_null() {
1480         None
1481     } else {
1482         debug_assert!(
1483             sanitized_output.is_none(),
1484             "Shouldn't trigger @import loads for sanitization",
1485         );
1486         Some(StylesheetLoader::new(
1487             loader,
1488             stylesheet,
1489             load_data,
1490             reusable_sheets,
1491         ))
1492     };
1494     // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
1495     let loader: Option<&dyn StyleStylesheetLoader> = match loader {
1496         None => None,
1497         Some(ref s) => Some(s),
1498     };
1500     let mut sanitization_data = SanitizationData::new(sanitization_kind);
1502     let contents = StylesheetContents::from_str(
1503         input,
1504         url_data.clone(),
1505         mode_to_origin(mode),
1506         &global_style_data.shared_lock,
1507         loader,
1508         reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
1509         quirks_mode.into(),
1510         use_counters,
1511         allow_import_rules,
1512         sanitization_data.as_mut(),
1513     );
1515     if let Some(data) = sanitization_data {
1516         sanitized_output
1517             .unwrap()
1518             .assign_utf8(data.take().as_bytes());
1519     }
1521     contents.into()
1524 #[no_mangle]
1525 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
1526     load_data: *mut SheetLoadDataHolder,
1527     extra_data: *mut URLExtraData,
1528     bytes: &nsACString,
1529     mode: SheetParsingMode,
1530     quirks_mode: nsCompatibility,
1531     should_record_use_counters: bool,
1532     allow_import_rules: AllowImportRules,
1533 ) {
1534     let load_data = RefPtr::new(load_data);
1535     let extra_data = UrlExtraData::new(extra_data);
1537     let mut sheet_bytes = nsCString::new();
1538     sheet_bytes.assign(bytes);
1540     let async_parser = AsyncStylesheetParser::new(
1541         load_data,
1542         extra_data,
1543         sheet_bytes,
1544         mode_to_origin(mode),
1545         quirks_mode.into(),
1546         should_record_use_counters,
1547         allow_import_rules,
1548     );
1550     if let Some(thread_pool) = STYLE_THREAD_POOL.pool().as_ref() {
1551         thread_pool.spawn(|| {
1552             gecko_profiler_label!(Layout, CSSParsing);
1553             async_parser.parse();
1554         });
1555     } else {
1556         async_parser.parse();
1557     }
1560 #[no_mangle]
1561 pub unsafe extern "C" fn Servo_ShutdownThreadPool() {
1562     debug_assert!(is_main_thread() && !is_in_servo_traversal());
1563     StyleThreadPool::shutdown();
1566 #[no_mangle]
1567 pub unsafe extern "C" fn Servo_ThreadPool_GetThreadHandles(handles: &mut ThinVec<PlatformThreadHandle>) {
1568     StyleThreadPool::get_thread_handles(handles);
1571 #[no_mangle]
1572 pub unsafe extern "C" fn Servo_StyleSheet_FromSharedData(
1573     extra_data: *mut URLExtraData,
1574     shared_rules: &LockedCssRules,
1575 ) -> Strong<StylesheetContents> {
1576     StylesheetContents::from_shared_data(
1577         Arc::from_raw_addrefed(shared_rules),
1578         Origin::UserAgent,
1579         UrlExtraData::new(extra_data),
1580         QuirksMode::NoQuirks,
1581     )
1582     .into()
1585 #[no_mangle]
1586 pub extern "C" fn Servo_StyleSet_AppendStyleSheet(
1587     raw_data: &PerDocumentStyleData,
1588     sheet: *const DomStyleSheet,
1589 ) {
1590     let global_style_data = &*GLOBAL_STYLE_DATA;
1591     let mut data = raw_data.borrow_mut();
1592     let data = &mut *data;
1593     let guard = global_style_data.shared_lock.read();
1594     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1595     data.stylist.append_stylesheet(sheet, &guard);
1598 #[no_mangle]
1599 pub extern "C" fn Servo_AuthorStyles_Create() -> *mut AuthorStyles {
1600     Box::into_raw(Box::new(AuthorStyles::new()))
1603 #[no_mangle]
1604 pub unsafe extern "C" fn Servo_AuthorStyles_Drop(styles: *mut AuthorStyles) {
1605     let _ = Box::from_raw(styles);
1608 #[no_mangle]
1609 pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet(
1610     styles: &mut AuthorStyles,
1611     sheet: *const DomStyleSheet,
1612 ) {
1613     let global_style_data = &*GLOBAL_STYLE_DATA;
1614     let guard = global_style_data.shared_lock.read();
1615     let sheet = GeckoStyleSheet::new(sheet);
1616     styles.stylesheets.append_stylesheet(None, sheet, &guard);
1619 #[no_mangle]
1620 pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore(
1621     styles: &mut AuthorStyles,
1622     sheet: *const DomStyleSheet,
1623     before_sheet: *const DomStyleSheet,
1624 ) {
1625     let global_style_data = &*GLOBAL_STYLE_DATA;
1626     let guard = global_style_data.shared_lock.read();
1627     styles.stylesheets.insert_stylesheet_before(
1628         None,
1629         GeckoStyleSheet::new(sheet),
1630         GeckoStyleSheet::new(before_sheet),
1631         &guard,
1632     );
1635 #[no_mangle]
1636 pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet(
1637     styles: &mut AuthorStyles,
1638     sheet: *const DomStyleSheet,
1639 ) {
1640     let global_style_data = &*GLOBAL_STYLE_DATA;
1641     let guard = global_style_data.shared_lock.read();
1642     styles
1643         .stylesheets
1644         .remove_stylesheet(None, GeckoStyleSheet::new(sheet), &guard);
1647 #[no_mangle]
1648 pub extern "C" fn Servo_AuthorStyles_ForceDirty(styles: &mut AuthorStyles) {
1649     styles.stylesheets.force_dirty();
1652 #[no_mangle]
1653 pub extern "C" fn Servo_AuthorStyles_IsDirty(styles: &AuthorStyles) -> bool {
1654     styles.stylesheets.dirty()
1657 #[no_mangle]
1658 pub extern "C" fn Servo_AuthorStyles_Flush(
1659     styles: &mut AuthorStyles,
1660     document_set: &PerDocumentStyleData,
1661 ) {
1662     // Try to avoid the atomic borrow below if possible.
1663     if !styles.stylesheets.dirty() {
1664         return;
1665     }
1667     let global_style_data = &*GLOBAL_STYLE_DATA;
1668     let guard = global_style_data.shared_lock.read();
1670     let mut document_data = document_set.borrow_mut();
1672     // TODO(emilio): This is going to need an element or something to do proper
1673     // invalidation in Shadow roots.
1674     styles.flush::<GeckoElement>(&mut document_data.stylist, &guard);
1677 #[no_mangle]
1678 pub extern "C" fn Servo_StyleSet_RemoveUniqueEntriesFromAuthorStylesCache(
1679     document_set: &PerDocumentStyleData,
1680 ) {
1681     let mut document_data = document_set.borrow_mut();
1682     document_data
1683         .stylist
1684         .remove_unique_author_data_cache_entries();
1687 #[no_mangle]
1688 pub unsafe extern "C" fn Servo_DeclarationBlock_SizeOfIncludingThis(
1689     malloc_size_of: GeckoMallocSizeOf,
1690     malloc_enclosing_size_of: GeckoMallocSizeOf,
1691     declarations: &LockedDeclarationBlock,
1692 ) -> usize {
1693     use malloc_size_of::MallocSizeOf;
1694     use malloc_size_of::MallocUnconditionalShallowSizeOf;
1696     let global_style_data = &*GLOBAL_STYLE_DATA;
1697     let guard = global_style_data.shared_lock.read();
1699     let mut ops = MallocSizeOfOps::new(
1700         malloc_size_of.unwrap(),
1701         Some(malloc_enclosing_size_of.unwrap()),
1702         None,
1703     );
1705     ArcBorrow::from_ref(declarations).with_arc(|declarations| {
1706         let mut n = 0;
1707         n += declarations.unconditional_shallow_size_of(&mut ops);
1708         n += declarations.read_with(&guard).size_of(&mut ops);
1709         n
1710     })
1713 #[no_mangle]
1714 pub unsafe extern "C" fn Servo_AuthorStyles_SizeOfIncludingThis(
1715     malloc_size_of: GeckoMallocSizeOf,
1716     malloc_enclosing_size_of: GeckoMallocSizeOf,
1717     styles: &AuthorStyles,
1718 ) -> usize {
1719     // We cannot `use` MallocSizeOf at the top level, otherwise the compiler
1720     // would complain in `Servo_StyleSheet_SizeOfIncludingThis` for `size_of`
1721     // there.
1722     use malloc_size_of::MallocSizeOf;
1723     let malloc_size_of = malloc_size_of.unwrap();
1724     let malloc_size_of_this = malloc_size_of(styles as *const AuthorStyles as *const c_void);
1726     let mut ops = MallocSizeOfOps::new(
1727         malloc_size_of,
1728         Some(malloc_enclosing_size_of.unwrap()),
1729         None,
1730     );
1731     malloc_size_of_this + styles.size_of(&mut ops)
1734 #[no_mangle]
1735 pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged(
1736     document_set: &PerDocumentStyleData,
1737     non_document_styles: &mut nsTArray<&mut AuthorStyles>,
1738     may_affect_default_style: bool,
1739 ) -> structs::MediumFeaturesChangedResult {
1740     let global_style_data = &*GLOBAL_STYLE_DATA;
1741     let guard = global_style_data.shared_lock.read();
1743     // NOTE(emilio): We don't actually need to flush the stylist here and ensure
1744     // it's up to date.
1745     //
1746     // In case it isn't we would trigger a rebuild + restyle as needed too.
1747     //
1748     // We need to ensure the default computed values are up to date though,
1749     // because those can influence the result of media query evaluation.
1750     let mut document_data = document_set.borrow_mut();
1752     if may_affect_default_style {
1753         document_data.stylist.device_mut().reset_computed_values();
1754     }
1755     let guards = StylesheetGuards::same(&guard);
1757     let origins_in_which_rules_changed = document_data
1758         .stylist
1759         .media_features_change_changed_style(&guards, document_data.stylist.device());
1761     let affects_document_rules = !origins_in_which_rules_changed.is_empty();
1762     if affects_document_rules {
1763         document_data
1764             .stylist
1765             .force_stylesheet_origins_dirty(origins_in_which_rules_changed);
1766     }
1768     let mut affects_non_document_rules = false;
1769     for author_styles in &mut **non_document_styles {
1770         let affected_style = author_styles.stylesheets.iter().any(|sheet| {
1771             !author_styles.data.media_feature_affected_matches(
1772                 sheet,
1773                 &guards.author,
1774                 document_data.stylist.device(),
1775                 document_data.stylist.quirks_mode(),
1776             )
1777         });
1778         if affected_style {
1779             affects_non_document_rules = true;
1780             author_styles.stylesheets.force_dirty();
1781         }
1782     }
1784     structs::MediumFeaturesChangedResult {
1785         mAffectsDocumentRules: affects_document_rules,
1786         mAffectsNonDocumentRules: affects_non_document_rules,
1787     }
1790 #[no_mangle]
1791 pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(
1792     raw_data: &PerDocumentStyleData,
1793     sheet: *const DomStyleSheet,
1794     before_sheet: *const DomStyleSheet,
1795 ) {
1796     let global_style_data = &*GLOBAL_STYLE_DATA;
1797     let mut data = raw_data.borrow_mut();
1798     let data = &mut *data;
1799     let guard = global_style_data.shared_lock.read();
1800     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1801     data.stylist.insert_stylesheet_before(
1802         sheet,
1803         unsafe { GeckoStyleSheet::new(before_sheet) },
1804         &guard,
1805     );
1808 #[no_mangle]
1809 pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(
1810     raw_data: &PerDocumentStyleData,
1811     sheet: *const DomStyleSheet,
1812 ) {
1813     let global_style_data = &*GLOBAL_STYLE_DATA;
1814     let mut data = raw_data.borrow_mut();
1815     let data = &mut *data;
1816     let guard = global_style_data.shared_lock.read();
1817     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1818     data.stylist.remove_stylesheet(sheet, &guard);
1821 #[no_mangle]
1822 pub unsafe extern "C" fn Servo_StyleSet_GetSheetAt(
1823     raw_data: &PerDocumentStyleData,
1824     origin: Origin,
1825     index: usize,
1826 ) -> *const DomStyleSheet {
1827     let data = raw_data.borrow();
1828     data.stylist
1829         .sheet_at(origin, index)
1830         .map_or(ptr::null(), |s| s.raw())
1833 #[no_mangle]
1834 pub unsafe extern "C" fn Servo_StyleSet_GetSheetCount(
1835     raw_data: &PerDocumentStyleData,
1836     origin: Origin,
1837 ) -> usize {
1838     let data = raw_data.borrow();
1839     data.stylist.sheet_count(origin)
1842 #[no_mangle]
1843 pub unsafe extern "C" fn Servo_StyleSet_FlushStyleSheets(
1844     raw_data: &PerDocumentStyleData,
1845     doc_element: Option<&RawGeckoElement>,
1846     snapshots: *const ServoElementSnapshotTable,
1847 ) {
1848     let global_style_data = &*GLOBAL_STYLE_DATA;
1849     let guard = global_style_data.shared_lock.read();
1850     let mut data = raw_data.borrow_mut();
1851     let doc_element = doc_element.map(GeckoElement);
1853     let have_invalidations = data.flush_stylesheets(&guard, doc_element, snapshots.as_ref());
1855     if have_invalidations && doc_element.is_some() {
1856         // The invalidation machinery propagates the bits up, but we still need
1857         // to tell the Gecko restyle root machinery about it.
1858         bindings::Gecko_NoteDirtySubtreeForInvalidation(doc_element.unwrap().0);
1859     }
1862 #[no_mangle]
1863 pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(
1864     raw_data: &PerDocumentStyleData,
1865     changed_origins: OriginFlags,
1866 ) {
1867     let mut data = raw_data.borrow_mut();
1868     data.stylist
1869         .force_stylesheet_origins_dirty(OriginSet::from(changed_origins));
1872 #[no_mangle]
1873 pub extern "C" fn Servo_StyleSet_SetAuthorStyleDisabled(
1874     raw_data: &PerDocumentStyleData,
1875     author_style_disabled: bool,
1876 ) {
1877     let mut data = raw_data.borrow_mut();
1878     let enabled = if author_style_disabled {
1879         AuthorStylesEnabled::No
1880     } else {
1881         AuthorStylesEnabled::Yes
1882     };
1883     data.stylist.set_author_styles_enabled(enabled);
1886 #[no_mangle]
1887 pub extern "C" fn Servo_StyleSet_UsesFontMetrics(raw_data: &PerDocumentStyleData) -> bool {
1888     let doc_data = raw_data;
1889     doc_data.borrow().stylist.device().used_font_metrics()
1892 #[no_mangle]
1893 pub extern "C" fn Servo_StyleSheet_HasRules(raw_contents: &StylesheetContents) -> bool {
1894     let global_style_data = &*GLOBAL_STYLE_DATA;
1895     let guard = global_style_data.shared_lock.read();
1896     !raw_contents.rules.read_with(&guard).0.is_empty()
1899 #[no_mangle]
1900 pub extern "C" fn Servo_StyleSheet_GetRules(sheet: &StylesheetContents) -> Strong<LockedCssRules> {
1901     sheet.rules.clone().into()
1904 #[no_mangle]
1905 pub extern "C" fn Servo_StyleSheet_Clone(
1906     contents: &StylesheetContents,
1907     reference_sheet: *const DomStyleSheet,
1908 ) -> Strong<StylesheetContents> {
1909     use style::shared_lock::{DeepCloneParams, DeepCloneWithLock};
1910     let global_style_data = &*GLOBAL_STYLE_DATA;
1911     let guard = global_style_data.shared_lock.read();
1912     let params = DeepCloneParams { reference_sheet };
1914     Arc::new(contents.deep_clone_with_lock(&global_style_data.shared_lock, &guard, &params)).into()
1917 #[no_mangle]
1918 pub extern "C" fn Servo_StyleSheet_SizeOfIncludingThis(
1919     malloc_size_of: GeckoMallocSizeOf,
1920     malloc_enclosing_size_of: GeckoMallocSizeOf,
1921     sheet: &StylesheetContents,
1922 ) -> usize {
1923     let global_style_data = &*GLOBAL_STYLE_DATA;
1924     let guard = global_style_data.shared_lock.read();
1925     let mut ops = MallocSizeOfOps::new(
1926         malloc_size_of.unwrap(),
1927         Some(malloc_enclosing_size_of.unwrap()),
1928         None,
1929     );
1930     // TODO(emilio): We're not measuring the size of the Arc<StylesheetContents>
1931     // allocation itself here.
1932     sheet.size_of(&guard, &mut ops)
1935 #[no_mangle]
1936 pub extern "C" fn Servo_StyleSheet_GetOrigin(sheet: &StylesheetContents) -> Origin {
1937     sheet.origin
1940 #[no_mangle]
1941 pub extern "C" fn Servo_StyleSheet_GetSourceMapURL(
1942     contents: &StylesheetContents,
1943     result: &mut nsACString,
1944 ) {
1945     let url_opt = contents.source_map_url.read();
1946     if let Some(ref url) = *url_opt {
1947         result.assign(url);
1948     }
1951 #[no_mangle]
1952 pub extern "C" fn Servo_StyleSheet_GetSourceURL(
1953     contents: &StylesheetContents,
1954     result: &mut nsACString,
1955 ) {
1956     let url_opt = contents.source_url.read();
1957     if let Some(ref url) = *url_opt {
1958         result.assign(url);
1959     }
1962 fn with_maybe_worker_shared_lock<R>(func: impl FnOnce(&SharedRwLock) -> R) -> R {
1963     if is_dom_worker_thread() {
1964         DOM_WORKER_RWLOCK.with(func)
1965     } else {
1966         func(&GLOBAL_STYLE_DATA.shared_lock)
1967     }
1970 fn read_locked_arc<T, R, F>(raw: &Locked<T>, func: F) -> R
1971 where
1972     F: FnOnce(&T) -> R,
1974     debug_assert!(!is_dom_worker_thread());
1975     let global_style_data = &*GLOBAL_STYLE_DATA;
1976     let guard = global_style_data.shared_lock.read();
1977     func(raw.read_with(&guard))
1980 fn read_locked_arc_worker<T, R, F>(raw: &Locked<T>, func: F) -> R
1981 where
1982     F: FnOnce(&T) -> R,
1984     with_maybe_worker_shared_lock(|lock| {
1985         let guard = lock.read();
1986         func(raw.read_with(&guard))
1987     })
1990 #[cfg(debug_assertions)]
1991 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &Locked<T>, func: F) -> R
1992 where
1993     F: FnOnce(&T) -> R,
1995     debug_assert!(is_main_thread() && !is_in_servo_traversal());
1996     read_locked_arc(raw, func)
1999 #[cfg(not(debug_assertions))]
2000 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &Locked<T>, func: F) -> R
2001 where
2002     F: FnOnce(&T) -> R,
2004     debug_assert!(!is_dom_worker_thread());
2005     func(raw.read_unchecked())
2008 fn write_locked_arc<T, R, F>(raw: &Locked<T>, func: F) -> R
2009 where
2010     F: FnOnce(&mut T) -> R,
2012     debug_assert!(!is_dom_worker_thread());
2013     let global_style_data = &*GLOBAL_STYLE_DATA;
2014     let mut guard = global_style_data.shared_lock.write();
2015     func(raw.write_with(&mut guard))
2018 fn write_locked_arc_worker<T, R, F>(raw: &Locked<T>, func: F) -> R
2019 where
2020     F: FnOnce(&mut T) -> R,
2022     with_maybe_worker_shared_lock(|lock| {
2023         let mut guard = lock.write();
2024         func(raw.write_with(&mut guard))
2025     })
2028 #[no_mangle]
2029 pub extern "C" fn Servo_CssRules_ListTypes(rules: &LockedCssRules, result: &mut nsTArray<usize>) {
2030     read_locked_arc(rules, |rules: &CssRules| {
2031         result.assign_from_iter_pod(rules.0.iter().map(|rule| rule.rule_type() as usize));
2032     })
2035 #[no_mangle]
2036 pub extern "C" fn Servo_CssRules_InsertRule(
2037     rules: &LockedCssRules,
2038     contents: &StylesheetContents,
2039     rule: &nsACString,
2040     index: u32,
2041     containing_rule_types: u32,
2042     loader: *mut Loader,
2043     allow_import_rules: AllowImportRules,
2044     gecko_stylesheet: *mut DomStyleSheet,
2045     rule_type: &mut CssRuleType,
2046 ) -> nsresult {
2047     let loader = if loader.is_null() {
2048         None
2049     } else {
2050         Some(StylesheetLoader::new(
2051             loader,
2052             gecko_stylesheet,
2053             ptr::null_mut(),
2054             ptr::null_mut(),
2055         ))
2056     };
2057     let loader = loader
2058         .as_ref()
2059         .map(|loader| loader as &dyn StyleStylesheetLoader);
2060     let rule = unsafe { rule.as_str_unchecked() };
2062     let global_style_data = &*GLOBAL_STYLE_DATA;
2063     let result = rules.insert_rule(
2064         &global_style_data.shared_lock,
2065         rule,
2066         contents,
2067         index as usize,
2068         CssRuleTypes::from_bits(containing_rule_types),
2069         loader,
2070         allow_import_rules,
2071     );
2073     match result {
2074         Ok(new_rule) => {
2075             *rule_type = new_rule.rule_type();
2076             nsresult::NS_OK
2077         },
2078         Err(err) => err.into(),
2079     }
2082 #[no_mangle]
2083 pub extern "C" fn Servo_CssRules_DeleteRule(rules: &LockedCssRules, index: u32) -> nsresult {
2084     write_locked_arc(rules, |rules: &mut CssRules| {
2085         match rules.remove_rule(index as usize) {
2086             Ok(_) => nsresult::NS_OK,
2087             Err(err) => err.into(),
2088         }
2089     })
2092 trait MaybeLocked<Target> {
2093     fn maybe_locked_read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a Target;
2096 impl<T> MaybeLocked<T> for T {
2097     fn maybe_locked_read<'a>(&'a self, _: &'a SharedRwLockReadGuard) -> &'a T {
2098         self
2099     }
2102 impl<T> MaybeLocked<T> for Locked<T> {
2103     fn maybe_locked_read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
2104         self.read_with(guard)
2105     }
2108 macro_rules! impl_basic_rule_funcs_without_getter {
2109     {
2110         ($rule_type:ty, $maybe_locked_rule_type:ty),
2111         debug: $debug:ident,
2112         to_css: $to_css:ident,
2113     } => {
2114         #[cfg(debug_assertions)]
2115         #[no_mangle]
2116         pub extern "C" fn $debug(rule: &$maybe_locked_rule_type, result: &mut nsACString) {
2117             let global_style_data = &*GLOBAL_STYLE_DATA;
2118             let guard = global_style_data.shared_lock.read();
2119             let rule: &$rule_type = rule.maybe_locked_read(&guard);
2120             write!(result, "{:?}", *rule).unwrap();
2121         }
2123         #[cfg(not(debug_assertions))]
2124         #[no_mangle]
2125         pub extern "C" fn $debug(_: &$maybe_locked_rule_type, _: &mut nsACString) {
2126             unreachable!()
2127         }
2129         #[no_mangle]
2130         pub extern "C" fn $to_css(rule: &$maybe_locked_rule_type, result: &mut nsACString) {
2131             let global_style_data = &*GLOBAL_STYLE_DATA;
2132             let guard = global_style_data.shared_lock.read();
2133             let rule: &$rule_type = rule.maybe_locked_read(&guard);
2134             rule.to_css(&guard, result).unwrap();
2135         }
2136     }
2139 macro_rules! impl_basic_rule_funcs {
2140     { ($name:ident, $rule_type:ty, $maybe_locked_rule_type:ty),
2141         getter: $getter:ident,
2142         debug: $debug:ident,
2143         to_css: $to_css:ident,
2144         changed: $changed:ident,
2145     } => {
2146         #[no_mangle]
2147         pub extern "C" fn $getter(
2148             rules: &LockedCssRules,
2149             index: u32,
2150             line: &mut u32,
2151             column: &mut u32,
2152         ) -> Strong<$maybe_locked_rule_type> {
2153             let global_style_data = &*GLOBAL_STYLE_DATA;
2154             let guard = global_style_data.shared_lock.read();
2155             let rules = rules.read_with(&guard);
2156             let index = index as usize;
2158             if index >= rules.0.len() {
2159                 return Strong::null();
2160             }
2162             match rules.0[index] {
2163                 CssRule::$name(ref arc) => {
2164                     let rule: &$rule_type = (&**arc).maybe_locked_read(&guard);
2165                     let location = rule.source_location;
2166                     *line = location.line as u32;
2167                     *column = location.column as u32;
2168                     arc.clone().into()
2169                 },
2170                 _ => {
2171                     Strong::null()
2172                 }
2173             }
2174         }
2176         #[no_mangle]
2177         pub extern "C" fn $changed(
2178             styleset: &PerDocumentStyleData,
2179             rule: &$maybe_locked_rule_type,
2180             sheet: &DomStyleSheet,
2181             change_kind: RuleChangeKind,
2182         ) {
2183             let mut data = styleset.borrow_mut();
2184             let data = &mut *data;
2185             let global_style_data = &*GLOBAL_STYLE_DATA;
2186             let guard = global_style_data.shared_lock.read();
2187             // TODO(emilio): Would be nice not to deal with refcount bumps here,
2188             // but it's probably not a huge deal.
2189             let rule = unsafe { CssRule::$name(Arc::from_raw_addrefed(rule)) };
2190             let sheet = unsafe { GeckoStyleSheet::new(sheet) };
2191             data.stylist.rule_changed(&sheet, &rule, &guard, change_kind);
2192         }
2194         impl_basic_rule_funcs_without_getter! {
2195             ($rule_type, $maybe_locked_rule_type),
2196             debug: $debug,
2197             to_css: $to_css,
2198         }
2199     }
2202 macro_rules! impl_group_rule_funcs {
2203     { ($name:ident, $rule_type:ty, $maybe_locked_rule_type:ty),
2204       get_rules: $get_rules:ident,
2205       $($basic:tt)+
2206     } => {
2207         impl_basic_rule_funcs! { ($name, $rule_type, $maybe_locked_rule_type), $($basic)+ }
2209         #[no_mangle]
2210         pub extern "C" fn $get_rules(rule: &$maybe_locked_rule_type) -> Strong<LockedCssRules> {
2211             let global_style_data = &*GLOBAL_STYLE_DATA;
2212             let guard = global_style_data.shared_lock.read();
2213             let rule: &$rule_type = rule.maybe_locked_read(&guard);
2214             rule.rules.clone().into()
2215         }
2216     }
2219 impl_basic_rule_funcs! { (Style, StyleRule, Locked<StyleRule>),
2220     getter: Servo_CssRules_GetStyleRuleAt,
2221     debug: Servo_StyleRule_Debug,
2222     to_css: Servo_StyleRule_GetCssText,
2223     changed: Servo_StyleSet_StyleRuleChanged,
2226 #[no_mangle]
2227 pub extern "C" fn Servo_StyleRule_EnsureRules(rule: &LockedStyleRule, read_only: bool) -> Strong<LockedCssRules> {
2228     let global_style_data = &*GLOBAL_STYLE_DATA;
2229     let lock = &global_style_data.shared_lock;
2230     if read_only {
2231         let guard = lock.read();
2232         if let Some(ref rules) = rule.read_with(&guard).rules {
2233             return rules.clone().into();
2234         }
2235         return CssRules::new(vec![], lock).into();
2236     }
2237     let mut guard = lock.write();
2238     rule.write_with(&mut guard)
2239         .rules
2240         .get_or_insert_with(|| CssRules::new(vec![], lock))
2241         .clone()
2242         .into()
2245 impl_basic_rule_funcs! { (Import, ImportRule, Locked<ImportRule>),
2246     getter: Servo_CssRules_GetImportRuleAt,
2247     debug: Servo_ImportRule_Debug,
2248     to_css: Servo_ImportRule_GetCssText,
2249     changed: Servo_StyleSet_ImportRuleChanged,
2252 impl_basic_rule_funcs_without_getter! { (Keyframe, Locked<Keyframe>),
2253     debug: Servo_Keyframe_Debug,
2254     to_css: Servo_Keyframe_GetCssText,
2257 impl_basic_rule_funcs! { (Keyframes, KeyframesRule, Locked<KeyframesRule>),
2258     getter: Servo_CssRules_GetKeyframesRuleAt,
2259     debug: Servo_KeyframesRule_Debug,
2260     to_css: Servo_KeyframesRule_GetCssText,
2261     changed: Servo_StyleSet_KeyframesRuleChanged,
2264 impl_group_rule_funcs! { (Media, MediaRule, MediaRule),
2265     get_rules: Servo_MediaRule_GetRules,
2266     getter: Servo_CssRules_GetMediaRuleAt,
2267     debug: Servo_MediaRule_Debug,
2268     to_css: Servo_MediaRule_GetCssText,
2269     changed: Servo_StyleSet_MediaRuleChanged,
2272 impl_basic_rule_funcs! { (Namespace, NamespaceRule, NamespaceRule),
2273     getter: Servo_CssRules_GetNamespaceRuleAt,
2274     debug: Servo_NamespaceRule_Debug,
2275     to_css: Servo_NamespaceRule_GetCssText,
2276     changed: Servo_StyleSet_NamespaceRuleChanged,
2279 impl_basic_rule_funcs! { (Page, PageRule, Locked<PageRule>),
2280     getter: Servo_CssRules_GetPageRuleAt,
2281     debug: Servo_PageRule_Debug,
2282     to_css: Servo_PageRule_GetCssText,
2283     changed: Servo_StyleSet_PageRuleChanged,
2286 impl_basic_rule_funcs! { (Property, PropertyRule, PropertyRule),
2287     getter: Servo_CssRules_GetPropertyRuleAt,
2288     debug: Servo_PropertyRule_Debug,
2289     to_css: Servo_PropertyRule_GetCssText,
2290     changed: Servo_StyleSet_PropertyRuleChanged,
2293 impl_group_rule_funcs! { (Supports, SupportsRule, SupportsRule),
2294     get_rules: Servo_SupportsRule_GetRules,
2295     getter: Servo_CssRules_GetSupportsRuleAt,
2296     debug: Servo_SupportsRule_Debug,
2297     to_css: Servo_SupportsRule_GetCssText,
2298     changed: Servo_StyleSet_SupportsRuleChanged,
2301 impl_group_rule_funcs! { (Container, ContainerRule, ContainerRule),
2302     get_rules: Servo_ContainerRule_GetRules,
2303     getter: Servo_CssRules_GetContainerRuleAt,
2304     debug: Servo_ContainerRule_Debug,
2305     to_css: Servo_ContainerRule_GetCssText,
2306     changed: Servo_StyleSet_ContainerRuleChanged,
2309 impl_group_rule_funcs! { (LayerBlock, LayerBlockRule, LayerBlockRule),
2310     get_rules: Servo_LayerBlockRule_GetRules,
2311     getter: Servo_CssRules_GetLayerBlockRuleAt,
2312     debug: Servo_LayerBlockRule_Debug,
2313     to_css: Servo_LayerBlockRule_GetCssText,
2314     changed: Servo_StyleSet_LayerBlockRuleChanged,
2317 impl_basic_rule_funcs! { (LayerStatement, LayerStatementRule, LayerStatementRule),
2318     getter: Servo_CssRules_GetLayerStatementRuleAt,
2319     debug: Servo_LayerStatementRule_Debug,
2320     to_css: Servo_LayerStatementRule_GetCssText,
2321     changed: Servo_StyleSet_LayerStatementRuleChanged,
2324 impl_group_rule_funcs! { (Document, DocumentRule, DocumentRule),
2325     get_rules: Servo_DocumentRule_GetRules,
2326     getter: Servo_CssRules_GetDocumentRuleAt,
2327     debug: Servo_DocumentRule_Debug,
2328     to_css: Servo_DocumentRule_GetCssText,
2329     changed: Servo_StyleSet_DocumentRuleChanged,
2332 impl_basic_rule_funcs! { (FontFeatureValues, FontFeatureValuesRule, FontFeatureValuesRule),
2333     getter: Servo_CssRules_GetFontFeatureValuesRuleAt,
2334     debug: Servo_FontFeatureValuesRule_Debug,
2335     to_css: Servo_FontFeatureValuesRule_GetCssText,
2336     changed: Servo_StyleSet_FontFeatureValuesRuleChanged,
2339 impl_basic_rule_funcs! { (FontPaletteValues, FontPaletteValuesRule, FontPaletteValuesRule),
2340     getter: Servo_CssRules_GetFontPaletteValuesRuleAt,
2341     debug: Servo_FontPaletteValuesRule_Debug,
2342     to_css: Servo_FontPaletteValuesRule_GetCssText,
2343     changed: Servo_StyleSet_FontPaletteValuesRuleChanged,
2346 impl_basic_rule_funcs! { (FontFace, FontFaceRule, Locked<FontFaceRule>),
2347     getter: Servo_CssRules_GetFontFaceRuleAt,
2348     debug: Servo_FontFaceRule_Debug,
2349     to_css: Servo_FontFaceRule_GetCssText,
2350     changed: Servo_StyleSet_FontFaceRuleChanged,
2353 impl_basic_rule_funcs! { (CounterStyle, CounterStyleRule, Locked<CounterStyleRule>),
2354     getter: Servo_CssRules_GetCounterStyleRuleAt,
2355     debug: Servo_CounterStyleRule_Debug,
2356     to_css: Servo_CounterStyleRule_GetCssText,
2357     changed: Servo_StyleSet_CounterStyleRuleChanged,
2360 #[no_mangle]
2361 pub extern "C" fn Servo_StyleRule_GetStyle(
2362     rule: &LockedStyleRule,
2363 ) -> Strong<LockedDeclarationBlock> {
2364     read_locked_arc(rule, |rule: &StyleRule| rule.block.clone().into())
2367 #[no_mangle]
2368 pub extern "C" fn Servo_StyleRule_SetStyle(
2369     rule: &LockedStyleRule,
2370     declarations: &LockedDeclarationBlock,
2371 ) {
2372     write_locked_arc(rule, |rule: &mut StyleRule| {
2373         rule.block = unsafe { Arc::from_raw_addrefed(declarations) };
2374     })
2377 #[no_mangle]
2378 pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: &LockedStyleRule, result: &mut nsACString) {
2379     read_locked_arc(rule, |rule| rule.selectors.to_css(result).unwrap());
2382 fn desugared_selector_list(rules: &ThinVec<&LockedStyleRule>) -> SelectorList {
2383     let mut selectors: Option<SelectorList> = None;
2384     for rule in rules.iter().rev() {
2385         selectors = Some(read_locked_arc(rule, |rule| match selectors {
2386             Some(s) => rule.selectors.replace_parent_selector(&s.to_shared()),
2387             None => rule.selectors.clone(),
2388         }));
2389     }
2390     selectors.expect("Empty rule chain?")
2393 #[no_mangle]
2394 pub extern "C" fn Servo_StyleRule_GetSelectorDataAtIndex(
2395     rules: &ThinVec<&LockedStyleRule>,
2396     index: u32,
2397     text: Option<&mut nsACString>,
2398     specificity: Option<&mut u64>,
2399 ) {
2400     let selectors = desugared_selector_list(rules);
2401     let Some(selector) = selectors.0.get(index as usize) else { return };
2402     if let Some(text) = text {
2403         selector.to_css(text).unwrap();
2404     }
2405     if let Some(specificity) = specificity {
2406         *specificity = selector.specificity() as u64;
2407     }
2410 #[no_mangle]
2411 pub extern "C" fn Servo_StyleRule_GetSelectorCount(rule: &LockedStyleRule) -> u32 {
2412     read_locked_arc(rule, |rule| rule.selectors.0.len() as u32)
2415 #[no_mangle]
2416 pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(
2417     rules: &ThinVec<&LockedStyleRule>,
2418     element: &RawGeckoElement,
2419     index: u32,
2420     host: Option<&RawGeckoElement>,
2421     pseudo_type: PseudoStyleType,
2422     relevant_link_visited: bool,
2423 ) -> bool {
2424     use selectors::matching::{
2425         matches_selector, MatchingContext, MatchingMode, NeedsSelectorFlags, VisitedHandlingMode,
2426     };
2427     let selectors = desugared_selector_list(rules);
2428     let Some(selector) = selectors.0.get(index as usize) else { return false };
2429     let mut matching_mode = MatchingMode::Normal;
2430     match PseudoElement::from_pseudo_type(pseudo_type, None) {
2431         Some(pseudo) => {
2432             // We need to make sure that the requested pseudo element type
2433             // matches the selector pseudo element type before proceeding.
2434             match selector.pseudo_element() {
2435                 Some(selector_pseudo) if *selector_pseudo == pseudo => {
2436                     matching_mode = MatchingMode::ForStatelessPseudoElement
2437                 },
2438                 _ => return false,
2439             };
2440         },
2441         None => {
2442             // Do not attempt to match if a pseudo element is requested and
2443             // this is not a pseudo element selector, or vice versa.
2444             if selector.has_pseudo_element() {
2445                 return false;
2446             }
2447         },
2448     };
2450     let element = GeckoElement(element);
2451     let host = host.map(GeckoElement);
2452     let quirks_mode = element.as_node().owner_doc().quirks_mode();
2453     let mut selector_caches = SelectorCaches::default();
2454     let visited_mode = if relevant_link_visited {
2455         VisitedHandlingMode::RelevantLinkVisited
2456     } else {
2457         VisitedHandlingMode::AllLinksUnvisited
2458     };
2459     let mut ctx = MatchingContext::new_for_visited(
2460         matching_mode,
2461         /* bloom_filter = */ None,
2462         &mut selector_caches,
2463         visited_mode,
2464         quirks_mode,
2465         NeedsSelectorFlags::No,
2466         MatchingForInvalidation::No,
2467     );
2468     ctx.with_shadow_host(host, |ctx| {
2469         matches_selector(selector, 0, None, &element, ctx)
2470     })
2473 pub type SelectorList = selectors::SelectorList<style::gecko::selector_parser::SelectorImpl>;
2475 #[no_mangle]
2476 pub extern "C" fn Servo_StyleRule_SetSelectorText(
2477     contents: &StylesheetContents,
2478     rule: &LockedStyleRule,
2479     text: &nsACString,
2480 ) -> bool {
2481     let value_str = unsafe { text.as_str_unchecked() };
2483     write_locked_arc(rule, |rule: &mut StyleRule| {
2484         use style::selector_parser::SelectorParser;
2485         use selectors::parser::ParseRelative;
2487         let namespaces = contents.namespaces.read();
2488         let url_data = contents.url_data.read();
2489         let parser = SelectorParser {
2490             stylesheet_origin: contents.origin,
2491             namespaces: &namespaces,
2492             url_data: &url_data,
2493             for_supports_rule: false,
2494         };
2496         // TODO: Maybe allow setting relative selectors from the OM, if we're in a nested style
2497         // rule?
2498         let mut parser_input = ParserInput::new(&value_str);
2499         match SelectorList::parse(&parser, &mut Parser::new(&mut parser_input), ParseRelative::No) {
2500             Ok(selectors) => {
2501                 rule.selectors = selectors;
2502                 true
2503             },
2504             Err(_) => false,
2505         }
2506     })
2509 #[no_mangle]
2510 pub unsafe extern "C" fn Servo_SelectorList_Closest(
2511     element: &RawGeckoElement,
2512     selectors: &SelectorList,
2513 ) -> *const RawGeckoElement {
2514     use style::dom_apis;
2516     let element = GeckoElement(element);
2517     let quirks_mode = element.as_node().owner_doc().quirks_mode();
2518     dom_apis::element_closest(element, &selectors, quirks_mode).map_or(ptr::null(), |e| e.0)
2521 #[no_mangle]
2522 pub unsafe extern "C" fn Servo_SelectorList_Matches(
2523     element: &RawGeckoElement,
2524     selectors: &SelectorList,
2525 ) -> bool {
2526     use style::dom_apis;
2528     let element = GeckoElement(element);
2529     let quirks_mode = element.as_node().owner_doc().quirks_mode();
2530     dom_apis::element_matches(&element, &selectors, quirks_mode)
2533 #[no_mangle]
2534 pub unsafe extern "C" fn Servo_SelectorList_QueryFirst(
2535     node: &RawGeckoNode,
2536     selectors: &SelectorList,
2537     may_use_invalidation: bool,
2538 ) -> *const RawGeckoElement {
2539     use style::dom_apis::{self, MayUseInvalidation, QueryFirst};
2541     let node = GeckoNode(node);
2542     let mut result = None;
2544     let may_use_invalidation = if may_use_invalidation {
2545         MayUseInvalidation::Yes
2546     } else {
2547         MayUseInvalidation::No
2548     };
2550     dom_apis::query_selector::<GeckoElement, QueryFirst>(
2551         node,
2552         &selectors,
2553         &mut result,
2554         may_use_invalidation,
2555     );
2557     result.map_or(ptr::null(), |e| e.0)
2560 #[no_mangle]
2561 pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
2562     node: &RawGeckoNode,
2563     selectors: &SelectorList,
2564     content_list: *mut structs::nsSimpleContentList,
2565     may_use_invalidation: bool,
2566 ) {
2567     use style::dom_apis::{self, MayUseInvalidation, QueryAll};
2569     let node = GeckoNode(node);
2570     let mut result = SmallVec::new();
2572     let may_use_invalidation = if may_use_invalidation {
2573         MayUseInvalidation::Yes
2574     } else {
2575         MayUseInvalidation::No
2576     };
2578     dom_apis::query_selector::<GeckoElement, QueryAll>(
2579         node,
2580         &selectors,
2581         &mut result,
2582         may_use_invalidation,
2583     );
2585     if !result.is_empty() {
2586         // NOTE(emilio): This relies on a slice of GeckoElement having the same
2587         // memory representation than a slice of element pointers.
2588         bindings::Gecko_ContentList_AppendAll(
2589             content_list,
2590             result.as_ptr() as *mut *const _,
2591             result.len(),
2592         )
2593     }
2596 #[no_mangle]
2597 pub extern "C" fn Servo_ImportRule_GetHref(rule: &LockedImportRule, result: &mut nsAString) {
2598     read_locked_arc(rule, |rule: &ImportRule| {
2599         write!(result, "{}", rule.url.as_str()).unwrap();
2600     })
2603 #[no_mangle]
2604 pub extern "C" fn Servo_ImportRule_GetLayerName(rule: &LockedImportRule, result: &mut nsACString) {
2605     // https://w3c.github.io/csswg-drafts/cssom/#dom-cssimportrule-layername
2606     read_locked_arc(rule, |rule: &ImportRule| match rule.layer {
2607         ImportLayer::Named(ref name) => name.to_css(&mut CssWriter::new(result)).unwrap(), // "return the layer name declared in the at-rule itself"
2608         ImportLayer::Anonymous => {}, // "or an empty string if the layer is anonymous"
2609         ImportLayer::None => result.set_is_void(true), // "or null if the at-rule does not declare a layer"
2610     })
2613 #[no_mangle]
2614 pub extern "C" fn Servo_ImportRule_GetSupportsText(
2615     rule: &LockedImportRule,
2616     result: &mut nsACString,
2617 ) {
2618     read_locked_arc(rule, |rule: &ImportRule| match rule.supports {
2619         Some(ref supports) => supports
2620             .condition
2621             .to_css(&mut CssWriter::new(result))
2622             .unwrap(),
2623         None => result.set_is_void(true),
2624     })
2627 #[no_mangle]
2628 pub extern "C" fn Servo_ImportRule_GetSheet(rule: &LockedImportRule) -> *const DomStyleSheet {
2629     read_locked_arc(rule, |rule: &ImportRule| {
2630         rule.stylesheet
2631             .as_sheet()
2632             .map_or(ptr::null(), |s| s.raw() as *const DomStyleSheet)
2633     })
2636 #[no_mangle]
2637 pub unsafe extern "C" fn Servo_ImportRule_SetSheet(
2638     rule: &LockedImportRule,
2639     sheet: *mut DomStyleSheet,
2640 ) {
2641     write_locked_arc(rule, |rule: &mut ImportRule| {
2642         rule.stylesheet = ImportSheet::new(GeckoStyleSheet::new(sheet));
2643     })
2646 #[no_mangle]
2647 pub extern "C" fn Servo_Keyframe_GetKeyText(keyframe: &LockedKeyframe, result: &mut nsACString) {
2648     read_locked_arc(keyframe, |keyframe: &Keyframe| {
2649         keyframe
2650             .selector
2651             .to_css(&mut CssWriter::new(result))
2652             .unwrap()
2653     })
2656 #[no_mangle]
2657 pub extern "C" fn Servo_Keyframe_SetKeyText(keyframe: &LockedKeyframe, text: &nsACString) -> bool {
2658     let text = unsafe { text.as_str_unchecked() };
2659     let mut input = ParserInput::new(&text);
2660     if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
2661         write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2662             keyframe.selector = selector;
2663         });
2664         true
2665     } else {
2666         false
2667     }
2670 #[no_mangle]
2671 pub extern "C" fn Servo_Keyframe_GetStyle(
2672     keyframe: &LockedKeyframe,
2673 ) -> Strong<LockedDeclarationBlock> {
2674     read_locked_arc(keyframe, |keyframe: &Keyframe| {
2675         keyframe.block.clone().into()
2676     })
2679 #[no_mangle]
2680 pub extern "C" fn Servo_Keyframe_SetStyle(
2681     keyframe: &LockedKeyframe,
2682     declarations: &LockedDeclarationBlock,
2683 ) {
2684     write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2685         keyframe.block = unsafe { Arc::from_raw_addrefed(declarations) };
2686     })
2689 #[no_mangle]
2690 pub extern "C" fn Servo_KeyframesRule_GetName(rule: &LockedKeyframesRule) -> *mut nsAtom {
2691     read_locked_arc(rule, |rule: &KeyframesRule| rule.name.as_atom().as_ptr())
2694 #[no_mangle]
2695 pub unsafe extern "C" fn Servo_KeyframesRule_SetName(
2696     rule: &LockedKeyframesRule,
2697     name: *mut nsAtom,
2698 ) {
2699     write_locked_arc(rule, |rule: &mut KeyframesRule| {
2700         rule.name = KeyframesName::from_atom(Atom::from_addrefed(name));
2701     })
2704 #[no_mangle]
2705 pub extern "C" fn Servo_KeyframesRule_GetCount(rule: &LockedKeyframesRule) -> u32 {
2706     read_locked_arc(rule, |rule: &KeyframesRule| rule.keyframes.len() as u32)
2709 #[no_mangle]
2710 pub extern "C" fn Servo_KeyframesRule_GetKeyframeAt(
2711     rule: &LockedKeyframesRule,
2712     index: u32,
2713     line: &mut u32,
2714     column: &mut u32,
2715 ) -> Strong<LockedKeyframe> {
2716     let global_style_data = &*GLOBAL_STYLE_DATA;
2717     let guard = global_style_data.shared_lock.read();
2718     let key = rule.read_with(&guard).keyframes[index as usize].clone();
2719     let location = key.read_with(&guard).source_location;
2720     *line = location.line as u32;
2721     *column = location.column as u32;
2722     key.into()
2725 #[no_mangle]
2726 pub extern "C" fn Servo_KeyframesRule_FindRule(
2727     rule: &LockedKeyframesRule,
2728     key: &nsACString,
2729 ) -> u32 {
2730     let key = unsafe { key.as_str_unchecked() };
2731     let global_style_data = &*GLOBAL_STYLE_DATA;
2732     let guard = global_style_data.shared_lock.read();
2733     rule.read_with(&guard)
2734         .find_rule(&guard, key)
2735         .map(|index| index as u32)
2736         .unwrap_or(u32::max_value())
2739 #[no_mangle]
2740 pub extern "C" fn Servo_KeyframesRule_AppendRule(
2741     rule: &LockedKeyframesRule,
2742     contents: &StylesheetContents,
2743     css: &nsACString,
2744 ) -> bool {
2745     let css = unsafe { css.as_str_unchecked() };
2746     let global_style_data = &*GLOBAL_STYLE_DATA;
2748     match Keyframe::parse(css, &contents, &global_style_data.shared_lock) {
2749         Ok(keyframe) => {
2750             write_locked_arc(rule, |rule: &mut KeyframesRule| {
2751                 rule.keyframes.push(keyframe);
2752             });
2753             true
2754         },
2755         Err(..) => false,
2756     }
2759 #[no_mangle]
2760 pub extern "C" fn Servo_KeyframesRule_DeleteRule(rule: &LockedKeyframesRule, index: u32) {
2761     write_locked_arc(rule, |rule: &mut KeyframesRule| {
2762         rule.keyframes.remove(index as usize);
2763     })
2766 #[no_mangle]
2767 pub extern "C" fn Servo_MediaRule_GetMedia(rule: &MediaRule) -> Strong<LockedMediaList> {
2768     rule.media_queries.clone().into()
2771 #[no_mangle]
2772 pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: &NamespaceRule) -> *mut nsAtom {
2773     rule.prefix
2774         .as_ref()
2775         .map_or(atom!("").as_ptr(), |a| a.as_ptr())
2778 #[no_mangle]
2779 pub extern "C" fn Servo_NamespaceRule_GetURI(rule: &NamespaceRule) -> *mut nsAtom {
2780     rule.url.0.as_ptr()
2783 #[no_mangle]
2784 pub extern "C" fn Servo_PageRule_GetStyle(rule: &LockedPageRule) -> Strong<LockedDeclarationBlock> {
2785     read_locked_arc(rule, |rule: &PageRule| rule.block.clone().into())
2788 #[no_mangle]
2789 pub extern "C" fn Servo_PageRule_SetStyle(
2790     rule: &LockedPageRule,
2791     declarations: &LockedDeclarationBlock,
2792 ) {
2793     write_locked_arc(rule, |rule: &mut PageRule| {
2794         rule.block = unsafe { Arc::from_raw_addrefed(declarations) };
2795     })
2798 #[no_mangle]
2799 pub extern "C" fn Servo_PageRule_GetSelectorText(rule: &LockedPageRule, result: &mut nsACString) {
2800     read_locked_arc(rule, |rule: &PageRule| {
2801         rule.selectors.to_css(&mut CssWriter::new(result)).unwrap();
2802     })
2805 #[no_mangle]
2806 pub extern "C" fn Servo_PageRule_SetSelectorText(
2807     contents: &StylesheetContents,
2808     rule: &LockedPageRule,
2809     text: &nsACString,
2810 ) -> bool {
2811     let value_str = unsafe { text.as_str_unchecked() };
2813     write_locked_arc(rule, |rule: &mut PageRule| {
2814         use style::stylesheets::PageSelectors;
2816         let mut parser_input = ParserInput::new(&value_str);
2817         let mut parser = Parser::new(&mut parser_input);
2819         // Ensure that a blank input results in empty page selectors
2820         if parser.is_exhausted() {
2821             rule.selectors = PageSelectors::default();
2822             return true;
2823         }
2825         let url_data = contents.url_data.read();
2826         let context = ParserContext::new(
2827             Origin::Author,
2828             &url_data,
2829             None,
2830             ParsingMode::DEFAULT,
2831             QuirksMode::NoQuirks,
2832             /* namespaces = */ Default::default(),
2833             None,
2834             None,
2835         );
2837         match parser.parse_entirely(|i| PageSelectors::parse(&context, i)) {
2838             Ok(selectors) => {
2839                 rule.selectors = selectors;
2840                 true
2841             },
2842             Err(_) => false,
2843         }
2844     })
2847 #[no_mangle]
2848 pub extern "C" fn Servo_PropertyRule_GetName(rule: &PropertyRule, result: &mut nsACString) {
2849     rule.name.to_css(&mut CssWriter::new(result)).unwrap()
2852 #[no_mangle]
2853 pub extern "C" fn Servo_PropertyRule_GetSyntax(rule: &PropertyRule, result: &mut nsACString) {
2854     if let Some(ref syntax) = rule.syntax {
2855         CssWriter::new(result).write_str(syntax.as_str()).unwrap()
2856     }
2859 #[no_mangle]
2860 pub extern "C" fn Servo_PropertyRule_GetInherits(rule: &PropertyRule) -> bool {
2861     matches!(rule.inherits, Some(PropertyInherits::True))
2864 #[no_mangle]
2865 pub extern "C" fn Servo_PropertyRule_GetInitialValue(
2866     rule: &PropertyRule,
2867     result: &mut nsACString,
2868 ) -> bool {
2869     rule.initial_value
2870         .to_css(&mut CssWriter::new(result))
2871         .unwrap();
2872     rule.initial_value.is_some()
2875 #[no_mangle]
2876 pub extern "C" fn Servo_SupportsRule_GetConditionText(
2877     rule: &SupportsRule,
2878     result: &mut nsACString,
2879 ) {
2880     rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
2883 #[no_mangle]
2884 pub extern "C" fn Servo_ContainerRule_GetConditionText(
2885     rule: &ContainerRule,
2886     result: &mut nsACString,
2887 ) {
2888     rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
2891 #[no_mangle]
2892 pub extern "C" fn Servo_ContainerRule_GetContainerQuery(
2893     rule: &ContainerRule,
2894     result: &mut nsACString,
2895 ) {
2896     rule.query_condition()
2897         .to_css(&mut CssWriter::new(result))
2898         .unwrap();
2901 #[no_mangle]
2902 pub extern "C" fn Servo_ContainerRule_QueryContainerFor(
2903     rule: &ContainerRule,
2904     element: &RawGeckoElement,
2905 ) -> *const RawGeckoElement {
2906     rule.condition
2907         .find_container(GeckoElement(element), None)
2908         .map_or(ptr::null(), |result| result.element.0)
2911 #[no_mangle]
2912 pub extern "C" fn Servo_ContainerRule_GetContainerName(
2913     rule: &ContainerRule,
2914     result: &mut nsACString,
2915 ) {
2916     let name = rule.container_name();
2917     if !name.is_none() {
2918         name.to_css(&mut CssWriter::new(result)).unwrap();
2919     }
2922 #[no_mangle]
2923 pub extern "C" fn Servo_DocumentRule_GetConditionText(
2924     rule: &DocumentRule,
2925     result: &mut nsACString,
2926 ) {
2927     rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
2930 #[no_mangle]
2931 pub extern "C" fn Servo_FontFeatureValuesRule_GetFontFamily(
2932     rule: &FontFeatureValuesRule,
2933     result: &mut nsACString,
2934 ) {
2935     rule.family_names
2936         .to_css(&mut CssWriter::new(result))
2937         .unwrap();
2940 #[no_mangle]
2941 pub extern "C" fn Servo_FontFeatureValuesRule_GetValueText(
2942     rule: &FontFeatureValuesRule,
2943     result: &mut nsACString,
2944 ) {
2945     rule.value_to_css(&mut CssWriter::new(result)).unwrap();
2948 #[no_mangle]
2949 pub extern "C" fn Servo_FontPaletteValuesRule_GetName(
2950     rule: &FontPaletteValuesRule,
2951     result: &mut nsACString,
2952 ) {
2953     rule.name.to_css(&mut CssWriter::new(result)).unwrap()
2956 #[no_mangle]
2957 pub extern "C" fn Servo_FontPaletteValuesRule_GetFontFamily(
2958     rule: &FontPaletteValuesRule,
2959     result: &mut nsACString,
2960 ) {
2961     if !rule.family_names.is_empty() {
2962         rule.family_names
2963             .to_css(&mut CssWriter::new(result))
2964             .unwrap()
2965     }
2968 #[no_mangle]
2969 pub extern "C" fn Servo_FontPaletteValuesRule_GetBasePalette(
2970     rule: &FontPaletteValuesRule,
2971     result: &mut nsACString,
2972 ) {
2973     rule.base_palette
2974         .to_css(&mut CssWriter::new(result))
2975         .unwrap()
2978 #[no_mangle]
2979 pub extern "C" fn Servo_FontPaletteValuesRule_GetOverrideColors(
2980     rule: &FontPaletteValuesRule,
2981     result: &mut nsACString,
2982 ) {
2983     if !rule.override_colors.is_empty() {
2984         rule.override_colors
2985             .to_css(&mut CssWriter::new(result))
2986             .unwrap()
2987     }
2990 #[no_mangle]
2991 pub extern "C" fn Servo_FontFaceRule_CreateEmpty() -> Strong<LockedFontFaceRule> {
2992     // XXX This is not great. We should split FontFace descriptor data
2993     // from the rule, so that we don't need to create the rule like this
2994     // and the descriptor data itself can be hold in UniquePtr from the
2995     // Gecko side. See bug 1450904.
2996     with_maybe_worker_shared_lock(|lock| {
2997         Arc::new(lock.wrap(FontFaceRule::empty(SourceLocation { line: 0, column: 0 }))).into()
2998     })
3001 #[no_mangle]
3002 pub unsafe extern "C" fn Servo_FontFaceRule_Clone(
3003     rule: &LockedFontFaceRule,
3004 ) -> Strong<LockedFontFaceRule> {
3005     let clone = read_locked_arc_worker(rule, |rule: &FontFaceRule| rule.clone());
3006     with_maybe_worker_shared_lock(|lock| Arc::new(lock.wrap(clone)).into())
3009 #[no_mangle]
3010 pub unsafe extern "C" fn Servo_FontFaceRule_GetSourceLocation(
3011     rule: &LockedFontFaceRule,
3012     line: *mut u32,
3013     column: *mut u32,
3014 ) {
3015     read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3016         let location = rule.source_location;
3017         *line.as_mut().unwrap() = location.line as u32;
3018         *column.as_mut().unwrap() = location.column as u32;
3019     });
3022 macro_rules! apply_font_desc_list {
3023     ($apply_macro:ident) => {
3024         $apply_macro! {
3025             valid: [
3026                 eCSSFontDesc_Family => family,
3027                 eCSSFontDesc_Style => style,
3028                 eCSSFontDesc_Weight => weight,
3029                 eCSSFontDesc_Stretch => stretch,
3030                 eCSSFontDesc_Src => sources,
3031                 eCSSFontDesc_UnicodeRange => unicode_range,
3032                 eCSSFontDesc_FontFeatureSettings => feature_settings,
3033                 eCSSFontDesc_FontVariationSettings => variation_settings,
3034                 eCSSFontDesc_FontLanguageOverride => language_override,
3035                 eCSSFontDesc_Display => display,
3036                 eCSSFontDesc_AscentOverride => ascent_override,
3037                 eCSSFontDesc_DescentOverride => descent_override,
3038                 eCSSFontDesc_LineGapOverride => line_gap_override,
3039                 eCSSFontDesc_SizeAdjust => size_adjust,
3040             ]
3041             invalid: [
3042                 eCSSFontDesc_UNKNOWN,
3043                 eCSSFontDesc_COUNT,
3044             ]
3045         }
3046     };
3049 #[no_mangle]
3050 pub unsafe extern "C" fn Servo_FontFaceRule_Length(rule: &LockedFontFaceRule) -> u32 {
3051     read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3052         let mut result = 0;
3053         macro_rules! count_values {
3054             (
3055                 valid: [$($v_enum_name:ident => $field:ident,)*]
3056                 invalid: [$($i_enum_name:ident,)*]
3057             ) => {
3058                 $(if rule.$field.is_some() {
3059                     result += 1;
3060                 })*
3061             }
3062         }
3063         apply_font_desc_list!(count_values);
3064         result
3065     })
3068 #[no_mangle]
3069 pub unsafe extern "C" fn Servo_FontFaceRule_IndexGetter(
3070     rule: &LockedFontFaceRule,
3071     index: u32,
3072 ) -> nsCSSFontDesc {
3073     read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3074         let mut count = 0;
3075         macro_rules! lookup_index {
3076             (
3077                 valid: [$($v_enum_name:ident => $field:ident,)*]
3078                 invalid: [$($i_enum_name:ident,)*]
3079             ) => {
3080                 $(if rule.$field.is_some() {
3081                     count += 1;
3082                     if count - 1 == index {
3083                         return nsCSSFontDesc::$v_enum_name;
3084                     }
3085                 })*
3086             }
3087         }
3088         apply_font_desc_list!(lookup_index);
3089         return nsCSSFontDesc::eCSSFontDesc_UNKNOWN;
3090     })
3093 #[no_mangle]
3094 pub unsafe extern "C" fn Servo_FontFaceRule_GetDeclCssText(
3095     rule: &LockedFontFaceRule,
3096     result: &mut nsACString,
3097 ) {
3098     read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3099         rule.decl_to_css(result).unwrap();
3100     })
3103 macro_rules! simple_font_descriptor_getter_impl {
3104     ($rule:ident, $out:ident, $field:ident, $compute:ident) => {
3105         read_locked_arc_worker($rule, |rule: &FontFaceRule| {
3106             match rule.$field {
3107                 None => return false,
3108                 Some(ref f) => *$out = f.$compute(),
3109             }
3110             true
3111         })
3112     };
3115 #[no_mangle]
3116 pub extern "C" fn Servo_FontFaceRule_GetFontWeight(
3117     rule: &LockedFontFaceRule,
3118     out: &mut font_face::ComputedFontWeightRange,
3119 ) -> bool {
3120     simple_font_descriptor_getter_impl!(rule, out, weight, compute)
3123 #[no_mangle]
3124 pub extern "C" fn Servo_FontFaceRule_GetFontStretch(
3125     rule: &LockedFontFaceRule,
3126     out: &mut font_face::ComputedFontStretchRange,
3127 ) -> bool {
3128     simple_font_descriptor_getter_impl!(rule, out, stretch, compute)
3131 #[no_mangle]
3132 pub extern "C" fn Servo_FontFaceRule_GetFontStyle(
3133     rule: &LockedFontFaceRule,
3134     out: &mut font_face::ComputedFontStyleDescriptor,
3135 ) -> bool {
3136     simple_font_descriptor_getter_impl!(rule, out, style, compute)
3139 #[no_mangle]
3140 pub extern "C" fn Servo_FontFaceRule_GetFontDisplay(
3141     rule: &LockedFontFaceRule,
3142     out: &mut font_face::FontDisplay,
3143 ) -> bool {
3144     simple_font_descriptor_getter_impl!(rule, out, display, clone)
3147 #[no_mangle]
3148 pub extern "C" fn Servo_FontFaceRule_GetFontLanguageOverride(
3149     rule: &LockedFontFaceRule,
3150     out: &mut computed::FontLanguageOverride,
3151 ) -> bool {
3152     simple_font_descriptor_getter_impl!(rule, out, language_override, clone)
3155 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3156 // rather than an actual percentage value.
3157 #[no_mangle]
3158 pub extern "C" fn Servo_FontFaceRule_GetAscentOverride(
3159     rule: &LockedFontFaceRule,
3160     out: &mut computed::Percentage,
3161 ) -> bool {
3162     simple_font_descriptor_getter_impl!(rule, out, ascent_override, compute)
3165 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3166 // rather than an actual percentage value.
3167 #[no_mangle]
3168 pub extern "C" fn Servo_FontFaceRule_GetDescentOverride(
3169     rule: &LockedFontFaceRule,
3170     out: &mut computed::Percentage,
3171 ) -> bool {
3172     simple_font_descriptor_getter_impl!(rule, out, descent_override, compute)
3175 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3176 // rather than an actual percentage value.
3177 #[no_mangle]
3178 pub extern "C" fn Servo_FontFaceRule_GetLineGapOverride(
3179     rule: &LockedFontFaceRule,
3180     out: &mut computed::Percentage,
3181 ) -> bool {
3182     simple_font_descriptor_getter_impl!(rule, out, line_gap_override, compute)
3185 #[no_mangle]
3186 pub extern "C" fn Servo_FontFaceRule_GetSizeAdjust(
3187     rule: &LockedFontFaceRule,
3188     out: &mut computed::Percentage,
3189 ) -> bool {
3190     simple_font_descriptor_getter_impl!(rule, out, size_adjust, compute)
3193 #[no_mangle]
3194 pub unsafe extern "C" fn Servo_FontFaceRule_GetFamilyName(
3195     rule: &LockedFontFaceRule,
3196 ) -> *mut nsAtom {
3197     read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3198         // TODO(emilio): font-family is a mandatory descriptor, can't we unwrap
3199         // here, and remove the null-checks in Gecko?
3200         rule.family
3201             .as_ref()
3202             .map_or(ptr::null_mut(), |f| f.name.as_ptr())
3203     })
3206 #[no_mangle]
3207 pub unsafe extern "C" fn Servo_FontFaceRule_GetUnicodeRanges(
3208     rule: &LockedFontFaceRule,
3209     out_len: *mut usize,
3210 ) -> *const UnicodeRange {
3211     *out_len = 0;
3212     read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3213         let ranges = match rule.unicode_range {
3214             Some(ref ranges) => ranges,
3215             None => return ptr::null(),
3216         };
3217         *out_len = ranges.len();
3218         ranges.as_ptr() as *const _
3219     })
3222 #[no_mangle]
3223 pub unsafe extern "C" fn Servo_FontFaceRule_GetSources(
3224     rule: &LockedFontFaceRule,
3225     out: *mut nsTArray<FontFaceSourceListComponent>,
3226 ) {
3227     let out = &mut *out;
3228     read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3229         let sources = match rule.sources {
3230             Some(ref s) => s,
3231             None => return,
3232         };
3233         let len = sources.0.iter().fold(0, |acc, src| {
3234             acc + match *src {
3235                 Source::Url(ref url) => {
3236                     (if url.format_hint.is_some() { 2 } else { 1 }) +
3237                         (if url.tech_flags.is_empty() { 0 } else { 1 })
3238                 },
3239                 Source::Local(_) => 1,
3240             }
3241         });
3243         out.set_len(len as u32);
3245         let mut iter = out.iter_mut();
3247         {
3248             let mut set_next = |component: FontFaceSourceListComponent| {
3249                 *iter.next().expect("miscalculated length") = component;
3250             };
3252             for source in sources.0.iter() {
3253                 match *source {
3254                     Source::Url(ref url) => {
3255                         set_next(FontFaceSourceListComponent::Url(&url.url));
3256                         if let Some(hint) = &url.format_hint {
3257                             match hint {
3258                                 FontFaceSourceFormat::Keyword(kw) => {
3259                                     set_next(FontFaceSourceListComponent::FormatHintKeyword(*kw))
3260                                 },
3261                                 FontFaceSourceFormat::String(s) => {
3262                                     set_next(FontFaceSourceListComponent::FormatHintString {
3263                                         length: s.len(),
3264                                         utf8_bytes: s.as_ptr(),
3265                                     })
3266                                 },
3267                             }
3268                         }
3269                         if !url.tech_flags.is_empty() {
3270                             set_next(FontFaceSourceListComponent::TechFlags(url.tech_flags));
3271                         }
3272                     },
3273                     Source::Local(ref name) => {
3274                         set_next(FontFaceSourceListComponent::Local(name.name.as_ptr()));
3275                     },
3276                 }
3277             }
3278         }
3280         assert!(iter.next().is_none(), "miscalculated");
3281     })
3284 #[no_mangle]
3285 pub unsafe extern "C" fn Servo_FontFaceRule_GetVariationSettings(
3286     rule: &LockedFontFaceRule,
3287     variations: *mut nsTArray<structs::gfxFontVariation>,
3288 ) {
3289     read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3290         let source_variations = match rule.variation_settings {
3291             Some(ref v) => v,
3292             None => return,
3293         };
3295         (*variations).set_len(source_variations.0.len() as u32);
3296         for (target, source) in (*variations).iter_mut().zip(source_variations.0.iter()) {
3297             *target = structs::gfxFontVariation {
3298                 mTag: source.tag.0,
3299                 mValue: source.value.get(),
3300             };
3301         }
3302     });
3305 #[no_mangle]
3306 pub unsafe extern "C" fn Servo_FontFaceRule_GetFeatureSettings(
3307     rule: &LockedFontFaceRule,
3308     features: *mut nsTArray<structs::gfxFontFeature>,
3309 ) {
3310     read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3311         let source_features = match rule.feature_settings {
3312             Some(ref v) => v,
3313             None => return,
3314         };
3316         (*features).set_len(source_features.0.len() as u32);
3317         for (target, source) in (*features).iter_mut().zip(source_features.0.iter()) {
3318             *target = structs::gfxFontFeature {
3319                 mTag: source.tag.0,
3320                 mValue: source.value.value() as u32,
3321             };
3322         }
3323     });
3326 #[no_mangle]
3327 pub extern "C" fn Servo_FontFaceRule_GetDescriptorCssText(
3328     rule: &LockedFontFaceRule,
3329     desc: nsCSSFontDesc,
3330     result: &mut nsACString,
3331 ) {
3332     read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3333         let mut writer = CssWriter::new(result);
3334         macro_rules! to_css_text {
3335             (
3336                 valid: [$($v_enum_name:ident => $field:ident,)*]
3337                 invalid: [$($i_enum_name:ident,)*]
3338             ) => {
3339                 match desc {
3340                     $(
3341                         nsCSSFontDesc::$v_enum_name => {
3342                             if let Some(ref value) = rule.$field {
3343                                 value.to_css(&mut writer).unwrap();
3344                             }
3345                         }
3346                     )*
3347                     $(
3348                         nsCSSFontDesc::$i_enum_name => {
3349                             debug_assert!(false, "not a valid font descriptor");
3350                         }
3351                     )*
3352                 }
3353             }
3354         }
3355         apply_font_desc_list!(to_css_text)
3356     })
3359 #[no_mangle]
3360 pub unsafe extern "C" fn Servo_FontFaceRule_SetDescriptor(
3361     rule: &LockedFontFaceRule,
3362     desc: nsCSSFontDesc,
3363     value: &nsACString,
3364     data: *mut URLExtraData,
3365     out_changed: *mut bool,
3366 ) -> bool {
3367     let value = value.as_str_unchecked();
3368     let mut input = ParserInput::new(&value);
3369     let mut parser = Parser::new(&mut input);
3370     let url_data = UrlExtraData::from_ptr_ref(&data);
3371     let context = ParserContext::new(
3372         Origin::Author,
3373         url_data,
3374         Some(CssRuleType::FontFace),
3375         ParsingMode::DEFAULT,
3376         QuirksMode::NoQuirks,
3377         /* namespaces = */ Default::default(),
3378         None,
3379         None,
3380     );
3382     write_locked_arc_worker(rule, |rule: &mut FontFaceRule| {
3383         macro_rules! to_css_text {
3384             (
3385                 valid: [$($v_enum_name:ident => $field:ident,)*]
3386                 invalid: [$($i_enum_name:ident,)*]
3387             ) => {
3388                 match desc {
3389                     $(
3390                         nsCSSFontDesc::$v_enum_name => {
3391                             if let Ok(value) = parser.parse_entirely(|i| Parse::parse(&context, i)) {
3392                                 let result = Some(value);
3393                                 *out_changed = result != rule.$field;
3394                                 rule.$field = result;
3395                                 true
3396                             } else {
3397                                 false
3398                             }
3399                         }
3400                     )*
3401                     $(
3402                         nsCSSFontDesc::$i_enum_name => {
3403                             debug_assert!(false, "not a valid font descriptor");
3404                             false
3405                         }
3406                     )*
3407                 }
3408             }
3409         }
3410         apply_font_desc_list!(to_css_text)
3411     })
3414 #[no_mangle]
3415 pub unsafe extern "C" fn Servo_FontFaceRule_ResetDescriptor(
3416     rule: &LockedFontFaceRule,
3417     desc: nsCSSFontDesc,
3418 ) {
3419     write_locked_arc_worker(rule, |rule: &mut FontFaceRule| {
3420         macro_rules! reset_desc {
3421             (
3422                 valid: [$($v_enum_name:ident => $field:ident,)*]
3423                 invalid: [$($i_enum_name:ident,)*]
3424             ) => {
3425                 match desc {
3426                     $(nsCSSFontDesc::$v_enum_name => rule.$field = None,)*
3427                     $(nsCSSFontDesc::$i_enum_name => debug_assert!(false, "not a valid font descriptor"),)*
3428                 }
3429             }
3430         }
3431         apply_font_desc_list!(reset_desc)
3432     })
3435 #[no_mangle]
3436 pub unsafe extern "C" fn Servo_CounterStyleRule_GetName(
3437     rule: &LockedCounterStyleRule,
3438 ) -> *mut nsAtom {
3439     read_locked_arc(rule, |rule: &CounterStyleRule| rule.name().0.as_ptr())
3442 #[no_mangle]
3443 pub unsafe extern "C" fn Servo_CounterStyleRule_SetName(
3444     rule: &LockedCounterStyleRule,
3445     value: &nsACString,
3446 ) -> bool {
3447     let value = value.as_str_unchecked();
3448     let mut input = ParserInput::new(&value);
3449     let mut parser = Parser::new(&mut input);
3450     match parser.parse_entirely(counter_style::parse_counter_style_name_definition) {
3451         Ok(name) => {
3452             write_locked_arc(rule, |rule: &mut CounterStyleRule| rule.set_name(name));
3453             true
3454         },
3455         Err(_) => false,
3456     }
3459 #[no_mangle]
3460 pub unsafe extern "C" fn Servo_CounterStyleRule_GetGeneration(
3461     rule: &LockedCounterStyleRule,
3462 ) -> u32 {
3463     read_locked_arc(rule, |rule: &CounterStyleRule| rule.generation())
3466 fn symbol_to_string(s: &counter_style::Symbol) -> nsString {
3467     match *s {
3468         counter_style::Symbol::String(ref s) => nsString::from(&**s),
3469         counter_style::Symbol::Ident(ref i) => nsString::from(i.0.as_slice()),
3470     }
3473 // TODO(emilio): Cbindgen could be used to simplify a bunch of code here.
3474 #[no_mangle]
3475 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPad(
3476     rule: &LockedCounterStyleRule,
3477     width: &mut i32,
3478     symbol: &mut nsString,
3479 ) -> bool {
3480     read_locked_arc(rule, |rule: &CounterStyleRule| {
3481         let pad = match rule.pad() {
3482             Some(pad) => pad,
3483             None => return false,
3484         };
3485         *width = pad.0.value();
3486         *symbol = symbol_to_string(&pad.1);
3487         true
3488     })
3491 fn get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool {
3492     let s = match s {
3493         Some(s) => s,
3494         None => return false,
3495     };
3496     *out = symbol_to_string(s);
3497     true
3500 #[no_mangle]
3501 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPrefix(
3502     rule: &LockedCounterStyleRule,
3503     out: &mut nsString,
3504 ) -> bool {
3505     read_locked_arc(rule, |rule: &CounterStyleRule| {
3506         get_symbol(rule.prefix(), out)
3507     })
3510 #[no_mangle]
3511 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSuffix(
3512     rule: &LockedCounterStyleRule,
3513     out: &mut nsString,
3514 ) -> bool {
3515     read_locked_arc(rule, |rule: &CounterStyleRule| {
3516         get_symbol(rule.suffix(), out)
3517     })
3520 #[no_mangle]
3521 pub unsafe extern "C" fn Servo_CounterStyleRule_GetNegative(
3522     rule: &LockedCounterStyleRule,
3523     prefix: &mut nsString,
3524     suffix: &mut nsString,
3525 ) -> bool {
3526     read_locked_arc(rule, |rule: &CounterStyleRule| {
3527         let negative = match rule.negative() {
3528             Some(n) => n,
3529             None => return false,
3530         };
3531         *prefix = symbol_to_string(&negative.0);
3532         *suffix = match negative.1 {
3533             Some(ref s) => symbol_to_string(s),
3534             None => nsString::new(),
3535         };
3536         true
3537     })
3540 #[repr(u8)]
3541 pub enum IsOrdinalInRange {
3542     Auto,
3543     InRange,
3544     NotInRange,
3545     NoOrdinalSpecified,
3548 #[no_mangle]
3549 pub unsafe extern "C" fn Servo_CounterStyleRule_IsInRange(
3550     rule: &LockedCounterStyleRule,
3551     ordinal: i32,
3552 ) -> IsOrdinalInRange {
3553     use style::counter_style::CounterBound;
3554     read_locked_arc(rule, |rule: &CounterStyleRule| {
3555         let range = match rule.range() {
3556             Some(r) => r,
3557             None => return IsOrdinalInRange::NoOrdinalSpecified,
3558         };
3560         if range.0.is_empty() {
3561             return IsOrdinalInRange::Auto;
3562         }
3564         let in_range = range.0.iter().any(|r| {
3565             if let CounterBound::Integer(start) = r.start {
3566                 if start.value() > ordinal {
3567                     return false;
3568                 }
3569             }
3571             if let CounterBound::Integer(end) = r.end {
3572                 if end.value() < ordinal {
3573                     return false;
3574                 }
3575             }
3577             true
3578         });
3580         if in_range {
3581             IsOrdinalInRange::InRange
3582         } else {
3583             IsOrdinalInRange::NotInRange
3584         }
3585     })
3588 #[no_mangle]
3589 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols(
3590     rule: &LockedCounterStyleRule,
3591     symbols: &mut style::OwnedSlice<nsString>,
3592 ) {
3593     read_locked_arc(rule, |rule: &CounterStyleRule| {
3594         *symbols = match rule.symbols() {
3595             Some(s) => s.0.iter().map(symbol_to_string).collect(),
3596             None => style::OwnedSlice::default(),
3597         };
3598     })
3601 #[repr(C)]
3602 pub struct AdditiveSymbol {
3603     pub weight: i32,
3604     pub symbol: nsString,
3607 #[no_mangle]
3608 pub unsafe extern "C" fn Servo_CounterStyleRule_GetAdditiveSymbols(
3609     rule: &LockedCounterStyleRule,
3610     symbols: &mut style::OwnedSlice<AdditiveSymbol>,
3611 ) {
3612     read_locked_arc(rule, |rule: &CounterStyleRule| {
3613         *symbols = match rule.additive_symbols() {
3614             Some(s) => {
3615                 s.0.iter()
3616                     .map(|s| AdditiveSymbol {
3617                         weight: s.weight.value(),
3618                         symbol: symbol_to_string(&s.symbol),
3619                     })
3620                     .collect()
3621             },
3622             None => style::OwnedSlice::default(),
3623         };
3624     })
3627 #[repr(C, u8)]
3628 pub enum CounterSpeakAs {
3629     None,
3630     Auto,
3631     Bullets,
3632     Numbers,
3633     Words,
3634     Ident(*mut nsAtom),
3637 #[no_mangle]
3638 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSpeakAs(
3639     rule: &LockedCounterStyleRule,
3640     out: &mut CounterSpeakAs,
3641 ) {
3642     use style::counter_style::SpeakAs;
3643     *out = read_locked_arc(rule, |rule: &CounterStyleRule| {
3644         let speak_as = match rule.speak_as() {
3645             Some(s) => s,
3646             None => return CounterSpeakAs::None,
3647         };
3648         match *speak_as {
3649             SpeakAs::Auto => CounterSpeakAs::Auto,
3650             SpeakAs::Bullets => CounterSpeakAs::Bullets,
3651             SpeakAs::Numbers => CounterSpeakAs::Numbers,
3652             SpeakAs::Words => CounterSpeakAs::Words,
3653             SpeakAs::Other(ref other) => CounterSpeakAs::Ident(other.0.as_ptr()),
3654         }
3655     });
3658 #[repr(u8)]
3659 pub enum CounterSystem {
3660     Cyclic = 0,
3661     Numeric,
3662     Alphabetic,
3663     Symbolic,
3664     Additive,
3665     Fixed,
3666     Extends,
3669 #[no_mangle]
3670 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSystem(
3671     rule: &LockedCounterStyleRule,
3672 ) -> CounterSystem {
3673     use style::counter_style::System;
3674     read_locked_arc(rule, |rule: &CounterStyleRule| {
3675         match *rule.resolved_system() {
3676             System::Cyclic => CounterSystem::Cyclic,
3677             System::Numeric => CounterSystem::Numeric,
3678             System::Alphabetic => CounterSystem::Alphabetic,
3679             System::Symbolic => CounterSystem::Symbolic,
3680             System::Additive => CounterSystem::Additive,
3681             System::Fixed { .. } => CounterSystem::Fixed,
3682             System::Extends(_) => CounterSystem::Extends,
3683         }
3684     })
3687 #[no_mangle]
3688 pub unsafe extern "C" fn Servo_CounterStyleRule_GetExtended(
3689     rule: &LockedCounterStyleRule,
3690 ) -> *mut nsAtom {
3691     read_locked_arc(rule, |rule: &CounterStyleRule| {
3692         match *rule.resolved_system() {
3693             counter_style::System::Extends(ref name) => name.0.as_ptr(),
3694             _ => {
3695                 debug_assert!(false, "Not extends system");
3696                 ptr::null_mut()
3697             },
3698         }
3699     })
3702 #[no_mangle]
3703 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFixedFirstValue(
3704     rule: &LockedCounterStyleRule,
3705 ) -> i32 {
3706     read_locked_arc(rule, |rule: &CounterStyleRule| {
3707         match *rule.resolved_system() {
3708             counter_style::System::Fixed { first_symbol_value } => {
3709                 first_symbol_value.map_or(1, |v| v.value())
3710             },
3711             _ => {
3712                 debug_assert!(false, "Not fixed system");
3713                 0
3714             },
3715         }
3716     })
3719 #[no_mangle]
3720 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFallback(
3721     rule: &LockedCounterStyleRule,
3722 ) -> *mut nsAtom {
3723     read_locked_arc(rule, |rule: &CounterStyleRule| {
3724         rule.fallback().map_or(ptr::null_mut(), |i| i.0 .0.as_ptr())
3725     })
3728 macro_rules! counter_style_descriptors {
3729     {
3730         valid: [
3731             $($desc:ident => $getter:ident / $setter:ident,)+
3732         ]
3733         invalid: [
3734             $($i_desc:ident,)+
3735         ]
3736     } => {
3737         #[no_mangle]
3738         pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptorCssText(
3739             rule: &LockedCounterStyleRule,
3740             desc: nsCSSCounterDesc,
3741             result: &mut nsACString,
3742         ) {
3743             let mut writer = CssWriter::new(result);
3744             read_locked_arc(rule, |rule: &CounterStyleRule| {
3745                 match desc {
3746                     $(nsCSSCounterDesc::$desc => {
3747                         if let Some(value) = rule.$getter() {
3748                             value.to_css(&mut writer).unwrap();
3749                         }
3750                     })+
3751                     $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3752                 }
3753             });
3754         }
3756         #[no_mangle]
3757         pub unsafe extern "C" fn Servo_CounterStyleRule_SetDescriptor(
3758             rule: &LockedCounterStyleRule,
3759             desc: nsCSSCounterDesc,
3760             value: &nsACString,
3761         ) -> bool {
3762             let value = value.as_str_unchecked();
3763             let mut input = ParserInput::new(&value);
3764             let mut parser = Parser::new(&mut input);
3765             let url_data = dummy_url_data();
3766             let context = ParserContext::new(
3767                 Origin::Author,
3768                 url_data,
3769                 Some(CssRuleType::CounterStyle),
3770                 ParsingMode::DEFAULT,
3771                 QuirksMode::NoQuirks,
3772                 /* namespaces = */ Default::default(),
3773                 None,
3774                 None,
3775             );
3777             write_locked_arc(rule, |rule: &mut CounterStyleRule| {
3778                 match desc {
3779                     $(nsCSSCounterDesc::$desc => {
3780                         match parser.parse_entirely(|i| Parse::parse(&context, i)) {
3781                             Ok(value) => rule.$setter(value),
3782                             Err(_) => false,
3783                         }
3784                     })+
3785                     $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3786                 }
3787             })
3788         }
3789     }
3792 counter_style_descriptors! {
3793     valid: [
3794         eCSSCounterDesc_System => system / set_system,
3795         eCSSCounterDesc_Symbols => symbols / set_symbols,
3796         eCSSCounterDesc_AdditiveSymbols => additive_symbols / set_additive_symbols,
3797         eCSSCounterDesc_Negative => negative / set_negative,
3798         eCSSCounterDesc_Prefix => prefix / set_prefix,
3799         eCSSCounterDesc_Suffix => suffix / set_suffix,
3800         eCSSCounterDesc_Range => range / set_range,
3801         eCSSCounterDesc_Pad => pad / set_pad,
3802         eCSSCounterDesc_Fallback => fallback / set_fallback,
3803         eCSSCounterDesc_SpeakAs => speak_as / set_speak_as,
3804     ]
3805     invalid: [
3806         eCSSCounterDesc_UNKNOWN,
3807         eCSSCounterDesc_COUNT,
3808     ]
3811 #[no_mangle]
3812 pub unsafe extern "C" fn Servo_ComputedValues_GetForPageContent(
3813     raw_data: &PerDocumentStyleData,
3814     page_name: *const nsAtom,
3815     pseudos: PagePseudoClassFlags,
3816 ) -> Strong<ComputedValues> {
3817     let global_style_data = &*GLOBAL_STYLE_DATA;
3818     let guard = global_style_data.shared_lock.read();
3819     let guards = StylesheetGuards::same(&guard);
3820     let data = raw_data.borrow_mut();
3821     let cascade_data = data.stylist.cascade_data();
3823     let mut extra_declarations = vec![];
3824     let iter = data.stylist.iter_extra_data_origins_rev();
3825     let name = if !page_name.is_null() {
3826         Some(Atom::from_raw(page_name as *mut nsAtom))
3827     } else {
3828         None
3829     };
3830     for (data, origin) in iter {
3831         data.pages.match_and_append_rules(
3832             &mut extra_declarations,
3833             origin,
3834             &guards,
3835             cascade_data,
3836             &name,
3837             pseudos,
3838         );
3839     }
3841     let rule_node = data.stylist.rule_node_for_precomputed_pseudo(
3842         &guards,
3843         &PseudoElement::PageContent,
3844         extra_declarations,
3845     );
3847     data.stylist
3848         .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
3849             &guards,
3850             &PseudoElement::PageContent,
3851             None,
3852             rule_node,
3853         )
3854         .into()
3857 #[no_mangle]
3858 pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox(
3859     parent_style_or_null: Option<&ComputedValues>,
3860     pseudo: PseudoStyleType,
3861     raw_data: &PerDocumentStyleData,
3862 ) -> Strong<ComputedValues> {
3863     let pseudo = PseudoElement::from_pseudo_type(pseudo, None).unwrap();
3864     debug_assert!(pseudo.is_anon_box());
3865     debug_assert_ne!(pseudo, PseudoElement::PageContent);
3866     let global_style_data = &*GLOBAL_STYLE_DATA;
3867     let guard = global_style_data.shared_lock.read();
3868     let guards = StylesheetGuards::same(&guard);
3869     let data = raw_data.borrow_mut();
3870     let rule_node = data
3871         .stylist
3872         .rule_node_for_precomputed_pseudo(&guards, &pseudo, vec![]);
3874     data.stylist
3875         .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
3876             &guards,
3877             &pseudo,
3878             parent_style_or_null.map(|x| &*x),
3879             rule_node,
3880         )
3881         .into()
3884 fn get_functional_pseudo_parameter_atom(
3885     functional_pseudo_parameter: *mut nsAtom,
3886 ) -> Option<AtomIdent> {
3887     if functional_pseudo_parameter.is_null() {
3888         None
3889     } else {
3890         Some(AtomIdent::new(unsafe {
3891             Atom::from_raw(functional_pseudo_parameter)
3892         }))
3893     }
3896 #[no_mangle]
3897 pub extern "C" fn Servo_ResolvePseudoStyle(
3898     element: &RawGeckoElement,
3899     pseudo_type: PseudoStyleType,
3900     functional_pseudo_parameter: *mut nsAtom,
3901     is_probe: bool,
3902     inherited_style: Option<&ComputedValues>,
3903     raw_data: &PerDocumentStyleData,
3904 ) -> Strong<ComputedValues> {
3905     let element = GeckoElement(element);
3906     let doc_data = raw_data.borrow();
3908     debug!(
3909         "Servo_ResolvePseudoStyle: {:?} {:?}, is_probe: {}",
3910         element,
3911         PseudoElement::from_pseudo_type(
3912             pseudo_type,
3913             get_functional_pseudo_parameter_atom(functional_pseudo_parameter)
3914         ),
3915         is_probe
3916     );
3918     let data = element.borrow_data();
3920     let data = match data.as_ref() {
3921         Some(data) if data.has_styles() => data,
3922         _ => {
3923             // FIXME(bholley, emilio): Assert against this.
3924             //
3925             // Known offender is nsMathMLmoFrame::MarkIntrinsicISizesDirty,
3926             // which goes and does a bunch of work involving style resolution.
3927             //
3928             // Bug 1403865 tracks fixing it, and potentially adding an assert
3929             // here instead.
3930             warn!("Calling Servo_ResolvePseudoStyle on unstyled element");
3931             return if is_probe {
3932                 Strong::null()
3933             } else {
3934                 doc_data.default_computed_values().clone().into()
3935             };
3936         },
3937     };
3939     let pseudo_element = PseudoElement::from_pseudo_type(
3940         pseudo_type,
3941         get_functional_pseudo_parameter_atom(functional_pseudo_parameter),
3942     )
3943     .expect("ResolvePseudoStyle with a non-pseudo?");
3945     let matching_fn = |pseudo: &PseudoElement| *pseudo == pseudo_element;
3947     let global_style_data = &*GLOBAL_STYLE_DATA;
3948     let guard = global_style_data.shared_lock.read();
3949     let style = get_pseudo_style(
3950         &guard,
3951         element,
3952         &pseudo_element,
3953         RuleInclusion::All,
3954         &data.styles,
3955         inherited_style,
3956         &doc_data.stylist,
3957         is_probe,
3958         /* matching_func = */ if pseudo_element.is_highlight() {Some(&matching_fn)} else {None},
3959     );
3961     match style {
3962         Some(s) => s.into(),
3963         None => {
3964             debug_assert!(is_probe);
3965             Strong::null()
3966         },
3967     }
3970 fn debug_atom_array(atoms: &nsTArray<structs::RefPtr<nsAtom>>) -> String {
3971     let mut result = String::from("[");
3972     for atom in atoms.iter() {
3973         if atom.mRawPtr.is_null() {
3974             result += "(null), ";
3975         } else {
3976             let atom = unsafe { WeakAtom::new(atom.mRawPtr) };
3977             write!(result, "{}, ", atom).unwrap();
3978         }
3979     }
3980     result.push(']');
3981     result
3984 #[no_mangle]
3985 pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle(
3986     element: &RawGeckoElement,
3987     pseudo_tag: *mut nsAtom,
3988     inherited_style: &ComputedValues,
3989     input_word: &nsTArray<structs::RefPtr<nsAtom>>,
3990     raw_data: &PerDocumentStyleData,
3991 ) -> Strong<ComputedValues> {
3992     let element = GeckoElement(element);
3993     let data = element
3994         .borrow_data()
3995         .expect("Calling ResolveXULTreePseudoStyle on unstyled element?");
3997     let pseudo = unsafe {
3998         Atom::with(pseudo_tag, |atom| {
3999             PseudoElement::from_tree_pseudo_atom(atom, Box::new([]))
4000         })
4001         .expect("ResolveXULTreePseudoStyle with a non-tree pseudo?")
4002     };
4003     let doc_data = raw_data.borrow();
4005     debug!(
4006         "ResolveXULTreePseudoStyle: {:?} {:?} {}",
4007         element,
4008         pseudo,
4009         debug_atom_array(input_word)
4010     );
4012     let matching_fn = |pseudo: &PseudoElement| {
4013         let args = pseudo
4014             .tree_pseudo_args()
4015             .expect("Not a tree pseudo-element?");
4016         args.iter()
4017             .all(|atom| input_word.iter().any(|item| atom.as_ptr() == item.mRawPtr))
4018     };
4020     let global_style_data = &*GLOBAL_STYLE_DATA;
4021     let guard = global_style_data.shared_lock.read();
4022     get_pseudo_style(
4023         &guard,
4024         element,
4025         &pseudo,
4026         RuleInclusion::All,
4027         &data.styles,
4028         Some(inherited_style),
4029         &doc_data.stylist,
4030         /* is_probe = */ false,
4031         Some(&matching_fn),
4032     )
4033     .unwrap()
4034     .into()
4037 #[no_mangle]
4038 pub extern "C" fn Servo_SetExplicitStyle(element: &RawGeckoElement, style: &ComputedValues) {
4039     let element = GeckoElement(element);
4040     debug!("Servo_SetExplicitStyle: {:?}", element);
4041     // We only support this API for initial styling. There's no reason it couldn't
4042     // work for other things, we just haven't had a reason to do so.
4043     debug_assert!(!element.has_data());
4044     let mut data = unsafe { element.ensure_data() };
4045     data.styles.primary = Some(unsafe { Arc::from_raw_addrefed(style) });
4048 fn get_pseudo_style(
4049     guard: &SharedRwLockReadGuard,
4050     element: GeckoElement,
4051     pseudo: &PseudoElement,
4052     rule_inclusion: RuleInclusion,
4053     styles: &ElementStyles,
4054     inherited_styles: Option<&ComputedValues>,
4055     stylist: &Stylist,
4056     is_probe: bool,
4057     matching_func: Option<&dyn Fn(&PseudoElement) -> bool>,
4058 ) -> Option<Arc<ComputedValues>> {
4059     let style = match pseudo.cascade_type() {
4060         PseudoElementCascadeType::Eager => {
4061             match *pseudo {
4062                 PseudoElement::FirstLetter => {
4063                     styles.pseudos.get(&pseudo).map(|pseudo_styles| {
4064                         // inherited_styles can be None when doing lazy resolution
4065                         // (e.g. for computed style) or when probing.  In that case
4066                         // we just inherit from our element, which is what Gecko
4067                         // does in that situation.  What should actually happen in
4068                         // the computed style case is a bit unclear.
4069                         let inherited_styles = inherited_styles.unwrap_or(styles.primary());
4070                         let guards = StylesheetGuards::same(guard);
4071                         let inputs = CascadeInputs::new_from_style(pseudo_styles);
4072                         stylist.compute_pseudo_element_style_with_inputs(
4073                             inputs,
4074                             pseudo,
4075                             &guards,
4076                             Some(styles.primary()),
4077                             Some(inherited_styles),
4078                             Some(element),
4079                         )
4080                     })
4081                 },
4082                 _ => {
4083                     // Unfortunately, we can't assert that inherited_styles, if
4084                     // present, is pointer-equal to styles.primary(), or even
4085                     // equal in any meaningful way.  The way it can fail is as
4086                     // follows.  Say we append an element with a ::before,
4087                     // ::after, or ::first-line to a parent with a ::first-line,
4088                     // such that the element ends up on the first line of the
4089                     // parent (e.g. it's an inline-block in the case it has a
4090                     // ::first-line, or any container in the ::before/::after
4091                     // cases).  Then gecko will update its frame's style to
4092                     // inherit from the parent's ::first-line.  The next time we
4093                     // try to get the ::before/::after/::first-line style for
4094                     // the kid, we'll likely pass in the frame's style as
4095                     // inherited_styles, but that's not pointer-identical to
4096                     // styles.primary(), because it got reparented.
4097                     //
4098                     // Now in practice this turns out to be OK, because all the
4099                     // cases in which there's a mismatch go ahead and reparent
4100                     // styles again as needed to make sure the ::first-line
4101                     // affects all the things it should affect.  But it makes it
4102                     // impossible to assert anything about the two styles
4103                     // matching here, unfortunately.
4104                     styles.pseudos.get(&pseudo).cloned()
4105                 },
4106             }
4107         },
4108         PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
4109         PseudoElementCascadeType::Lazy => {
4110             debug_assert!(
4111                 inherited_styles.is_none() ||
4112                     ptr::eq(inherited_styles.unwrap(), &**styles.primary())
4113             );
4114             let base = if pseudo.inherits_from_default_values() {
4115                 stylist.device().default_computed_values_arc()
4116             } else {
4117                 styles.primary()
4118             };
4119             let guards = StylesheetGuards::same(guard);
4120             stylist.lazily_compute_pseudo_element_style(
4121                 &guards,
4122                 element,
4123                 &pseudo,
4124                 rule_inclusion,
4125                 styles.primary(),
4126                 base,
4127                 is_probe,
4128                 matching_func,
4129             )
4130         },
4131     };
4133     if is_probe {
4134         return style;
4135     }
4137     Some(style.unwrap_or_else(|| {
4138         StyleBuilder::for_inheritance(stylist.device(), Some(stylist), Some(styles.primary()), Some(pseudo))
4139             .build()
4140     }))
4143 #[no_mangle]
4144 pub unsafe extern "C" fn Servo_ComputedValues_Inherit(
4145     raw_data: &PerDocumentStyleData,
4146     pseudo: PseudoStyleType,
4147     parent_style_context: Option<&ComputedValues>,
4148     target: structs::InheritTarget,
4149 ) -> Strong<ComputedValues> {
4150     let data = raw_data.borrow();
4152     let for_text = target == structs::InheritTarget::Text;
4153     let pseudo = PseudoElement::from_pseudo_type(pseudo, None).unwrap();
4154     debug_assert!(pseudo.is_anon_box());
4156     let mut style =
4157         StyleBuilder::for_inheritance(data.stylist.device(), Some(&data.stylist), parent_style_context, Some(&pseudo));
4159     if for_text {
4160         StyleAdjuster::new(&mut style).adjust_for_text();
4161     }
4163     style.build().into()
4166 #[no_mangle]
4167 pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions(
4168     values: &ComputedValues,
4169 ) -> bool {
4170     let ui = values.get_ui();
4171     ui.specifies_animations() || ui.specifies_transitions()
4174 #[no_mangle]
4175 pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
4176     values: &ComputedValues,
4177     rules: &mut ThinVec<*const LockedStyleRule>,
4178 ) {
4179     let rule_node = match values.rules {
4180         Some(ref r) => r,
4181         None => return,
4182     };
4184     for node in rule_node.self_and_ancestors() {
4185         let style_rule = match node.style_source().and_then(|x| x.as_rule()) {
4186             Some(rule) => rule,
4187             _ => continue,
4188         };
4190         // For the rules with any important declaration, we insert them into
4191         // rule tree twice, one for normal level and another for important
4192         // level. So, we skip the important one to keep the specificity order of
4193         // rules.
4194         if node.importance().important() {
4195             continue;
4196         }
4198         rules.push(&*style_rule);
4199     }
4202 /// println_stderr!() calls Gecko's printf_stderr(), which, unlike eprintln!(),
4203 /// will funnel output to Android logcat.
4204 #[cfg(feature = "gecko_debug")]
4205 macro_rules! println_stderr {
4206     ($($e:expr),+) => {
4207         {
4208             let mut s = nsCString::new();
4209             write!(s, $($e),+).unwrap();
4210             s.write_char('\n').unwrap();
4211             unsafe { bindings::Gecko_PrintfStderr(&s); }
4212         }
4213     }
4216 #[cfg(feature = "gecko_debug")]
4217 fn dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet) {
4218     println_stderr!("  Properties:");
4219     for p in properties.iter() {
4220         let mut v = nsCString::new();
4221         cv.computed_or_resolved_value(p, None, &mut v).unwrap();
4222         println_stderr!("    {:?}: {}", p, v);
4223     }
4224     dump_rules(cv);
4227 #[cfg(feature = "gecko_debug")]
4228 fn dump_rules(cv: &ComputedValues) {
4229     println_stderr!("  Rules({:?}):", cv.pseudo());
4230     let global_style_data = &*GLOBAL_STYLE_DATA;
4231     let guard = global_style_data.shared_lock.read();
4232     if let Some(rules) = cv.rules.as_ref() {
4233         for rn in rules.self_and_ancestors() {
4234             if rn.importance().important() {
4235                 continue;
4236             }
4237             if let Some(d) = rn.style_source().and_then(|s| s.as_declarations()) {
4238                 println_stderr!("    [DeclarationBlock: {:?}]", d);
4239             }
4240             if let Some(r) = rn.style_source().and_then(|s| s.as_rule()) {
4241                 let mut s = nsCString::new();
4242                 r.read_with(&guard).to_css(&guard, &mut s).unwrap();
4243                 println_stderr!("    {}", s);
4244             }
4245         }
4246     }
4249 #[cfg(feature = "gecko_debug")]
4250 #[no_mangle]
4251 pub extern "C" fn Servo_ComputedValues_EqualForCachedAnonymousContentStyle(
4252     a: &ComputedValues,
4253     b: &ComputedValues,
4254 ) -> bool {
4255     let mut differing_properties = a.differing_properties(b);
4257     // Ignore any difference in -x-lang, which we can't override in the rules in scrollbars.css,
4258     // but which makes no difference for the anonymous content subtrees we cache style for.
4259     differing_properties.remove(LonghandId::XLang);
4260     // Similarly, -x-lang can influence the font-family fallback we have for the initial
4261     // font-family so remove it as well.
4262     differing_properties.remove(LonghandId::FontFamily);
4264     // Ignore any difference in pref-controlled, inherited properties.  These properties may or may
4265     // not be set by the 'all' declaration in scrollbars.css, depending on whether the pref was
4266     // enabled at the time the UA sheets were parsed.
4267     //
4268     // If you add a new pref-controlled, inherited property, it must be defined with
4269     // `has_effect_on_gecko_scrollbars=False` to declare that different values of this property on
4270     // a <scrollbar> element or its descendant scrollbar part elements should have no effect on
4271     // their rendering and behavior.
4272     //
4273     // If you do need a pref-controlled, inherited property to have an effect on these elements,
4274     // then you will need to add some checks to the
4275     // nsIAnonymousContentCreator::CreateAnonymousContent implementations of nsHTMLScrollFrame and
4276     // nsScrollbarFrame to clear the AnonymousContentKey if a non-initial value is used.
4277     differing_properties.remove_all(&LonghandIdSet::has_no_effect_on_gecko_scrollbars());
4279     if !differing_properties.is_empty() {
4280         println_stderr!("Actual style:");
4281         dump_properties_and_rules(a, &differing_properties);
4282         println_stderr!("Expected style:");
4283         dump_properties_and_rules(b, &differing_properties);
4284     }
4286     differing_properties.is_empty()
4289 #[cfg(feature = "gecko_debug")]
4290 #[no_mangle]
4291 pub extern "C" fn Servo_ComputedValues_DumpMatchedRules(s: &ComputedValues) {
4292     dump_rules(s);
4295 #[no_mangle]
4296 pub extern "C" fn Servo_ComputedValues_BlockifiedDisplay(
4297     style: &ComputedValues,
4298     is_root_element: bool,
4299 ) -> u16 {
4300     let display = style.get_box().clone_display();
4301     let blockified_display = display.equivalent_block_display(is_root_element);
4302     blockified_display.to_u16()
4305 #[no_mangle]
4306 pub extern "C" fn Servo_StyleSet_Init(doc: &structs::Document) -> *mut PerDocumentStyleData {
4307     let data = Box::new(PerDocumentStyleData::new(doc));
4309     // Do this here rather than in Servo_Initialize since we need a document to
4310     // get the default computed values from.
4311     style::properties::generated::gecko::assert_initial_values_match(&data);
4313     Box::into_raw(data) as *mut PerDocumentStyleData
4316 #[no_mangle]
4317 pub unsafe extern "C" fn Servo_StyleSet_Drop(data: *mut PerDocumentStyleData) {
4318     let _ = Box::from_raw(data);
4321 #[no_mangle]
4322 pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: &PerDocumentStyleData) {
4323     let mut data = raw_data.borrow_mut();
4324     data.stylist.device_mut().rebuild_cached_data();
4325     data.undisplayed_style_cache.clear();
4328 #[no_mangle]
4329 pub unsafe extern "C" fn Servo_StyleSet_CompatModeChanged(raw_data: &PerDocumentStyleData) {
4330     let mut data = raw_data.borrow_mut();
4331     let quirks_mode = data.stylist.device().document().mCompatMode;
4332     data.stylist.set_quirks_mode(quirks_mode.into());
4335 fn parse_property_into(
4336     declarations: &mut SourcePropertyDeclaration,
4337     property_id: PropertyId,
4338     value: &nsACString,
4339     origin: Origin,
4340     url_data: &UrlExtraData,
4341     parsing_mode: ParsingMode,
4342     quirks_mode: QuirksMode,
4343     rule_type: CssRuleType,
4344     reporter: Option<&dyn ParseErrorReporter>,
4345 ) -> Result<(), ()> {
4346     let value = unsafe { value.as_str_unchecked() };
4348     if let Some(non_custom) = property_id.non_custom_id() {
4349         if !non_custom.allowed_in_rule(rule_type.into()) {
4350             return Err(());
4351         }
4352     }
4354     parse_one_declaration_into(
4355         declarations,
4356         property_id,
4357         value,
4358         origin,
4359         url_data,
4360         reporter,
4361         parsing_mode,
4362         quirks_mode,
4363         rule_type,
4364     )
4367 #[no_mangle]
4368 pub unsafe extern "C" fn Servo_ParseProperty(
4369     property: nsCSSPropertyID,
4370     value: &nsACString,
4371     data: *mut URLExtraData,
4372     parsing_mode: ParsingMode,
4373     quirks_mode: nsCompatibility,
4374     loader: *mut Loader,
4375     rule_type: CssRuleType,
4376 ) -> Strong<LockedDeclarationBlock> {
4377     let id = get_property_id_from_nscsspropertyid!(property, Strong::null());
4378     let mut declarations = SourcePropertyDeclaration::default();
4379     let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
4380     let data = UrlExtraData::from_ptr_ref(&data);
4381     let result = parse_property_into(
4382         &mut declarations,
4383         id,
4384         value,
4385         Origin::Author,
4386         data,
4387         parsing_mode,
4388         quirks_mode.into(),
4389         rule_type,
4390         reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4391     );
4393     match result {
4394         Ok(()) => {
4395             let global_style_data = &*GLOBAL_STYLE_DATA;
4396             let mut block = PropertyDeclarationBlock::new();
4397             block.extend(declarations.drain(), Importance::Normal);
4398             Arc::new(global_style_data.shared_lock.wrap(block)).into()
4399         },
4400         Err(_) => Strong::null(),
4401     }
4404 #[no_mangle]
4405 pub extern "C" fn Servo_ParseEasing(
4406     easing: &nsACString,
4407     output: &mut ComputedTimingFunction,
4408 ) -> bool {
4409     use style::properties::longhands::transition_timing_function;
4411     let context = ParserContext::new(
4412         Origin::Author,
4413         unsafe { dummy_url_data() },
4414         Some(CssRuleType::Style),
4415         ParsingMode::DEFAULT,
4416         QuirksMode::NoQuirks,
4417         /* namespaces = */ Default::default(),
4418         None,
4419         None,
4420     );
4421     let easing = easing.to_string();
4422     let mut input = ParserInput::new(&easing);
4423     let mut parser = Parser::new(&mut input);
4424     let result =
4425         parser.parse_entirely(|p| transition_timing_function::single_value::parse(&context, p));
4426     match result {
4427         Ok(parsed_easing) => {
4428             *output = parsed_easing.to_computed_value_without_context();
4429             true
4430         },
4431         Err(_) => false,
4432     }
4435 #[no_mangle]
4436 pub extern "C" fn Servo_SerializeEasing(easing: &ComputedTimingFunction, output: &mut nsACString) {
4437     easing.to_css(&mut CssWriter::new(output)).unwrap();
4440 #[no_mangle]
4441 pub extern "C" fn Servo_GetProperties_Overriding_Animation(
4442     element: &RawGeckoElement,
4443     list: &nsTArray<nsCSSPropertyID>,
4444     set: &mut structs::nsCSSPropertyIDSet,
4445 ) {
4446     let element = GeckoElement(element);
4447     let element_data = match element.borrow_data() {
4448         Some(data) => data,
4449         None => return,
4450     };
4451     let global_style_data = &*GLOBAL_STYLE_DATA;
4452     let guard = global_style_data.shared_lock.read();
4453     let guards = StylesheetGuards::same(&guard);
4454     let (overridden, custom) = element_data
4455         .styles
4456         .primary()
4457         .rules()
4458         .get_properties_overriding_animations(&guards);
4459     for p in list.iter() {
4460         match PropertyId::from_nscsspropertyid(*p) {
4461             Ok(property) => {
4462                 if let PropertyId::Longhand(id) = property {
4463                     if overridden.contains(id) {
4464                         unsafe { Gecko_AddPropertyToSet(set, *p) };
4465                     }
4466                 }
4467             },
4468             Err(_) => {
4469                 if *p == nsCSSPropertyID::eCSSPropertyExtra_variable && custom {
4470                     unsafe { Gecko_AddPropertyToSet(set, *p) };
4471                 }
4472             },
4473         }
4474     }
4477 #[no_mangle]
4478 pub extern "C" fn Servo_MatrixTransform_Operate(
4479     matrix_operator: MatrixTransformOperator,
4480     from: *const structs::Matrix4x4Components,
4481     to: *const structs::Matrix4x4Components,
4482     progress: f64,
4483     output: *mut structs::Matrix4x4Components,
4484 ) {
4485     use self::MatrixTransformOperator::{Accumulate, Interpolate};
4486     use style::values::computed::transform::Matrix3D;
4488     let from = Matrix3D::from(unsafe { from.as_ref() }.expect("not a valid 'from' matrix"));
4489     let to = Matrix3D::from(unsafe { to.as_ref() }.expect("not a valid 'to' matrix"));
4490     let result = match matrix_operator {
4491         Interpolate => from.animate(&to, Procedure::Interpolate { progress }),
4492         Accumulate => from.animate(
4493             &to,
4494             Procedure::Accumulate {
4495                 count: progress as u64,
4496             },
4497         ),
4498     };
4500     let output = unsafe { output.as_mut() }.expect("not a valid 'output' matrix");
4501     if let Ok(result) = result {
4502         *output = result.into();
4503     } else if progress < 0.5 {
4504         *output = from.clone().into();
4505     } else {
4506         *output = to.clone().into();
4507     }
4510 #[no_mangle]
4511 pub unsafe extern "C" fn Servo_ParseStyleAttribute(
4512     data: &nsACString,
4513     raw_extra_data: *mut URLExtraData,
4514     quirks_mode: nsCompatibility,
4515     loader: *mut Loader,
4516     rule_type: CssRuleType,
4517 ) -> Strong<LockedDeclarationBlock> {
4518     let global_style_data = &*GLOBAL_STYLE_DATA;
4519     let value = data.as_str_unchecked();
4520     let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data);
4521     let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
4522     Arc::new(global_style_data.shared_lock.wrap(parse_style_attribute(
4523         value,
4524         url_data,
4525         reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4526         quirks_mode.into(),
4527         rule_type,
4528     )))
4529     .into()
4532 #[no_mangle]
4533 pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> Strong<LockedDeclarationBlock> {
4534     let global_style_data = &*GLOBAL_STYLE_DATA;
4535     Arc::new(
4536         global_style_data
4537             .shared_lock
4538             .wrap(PropertyDeclarationBlock::new()),
4539     )
4540     .into()
4543 #[no_mangle]
4544 pub extern "C" fn Servo_DeclarationBlock_Clear(declarations: &LockedDeclarationBlock) {
4545     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4546         decls.clear();
4547     });
4550 #[no_mangle]
4551 pub extern "C" fn Servo_DeclarationBlock_Clone(
4552     declarations: &LockedDeclarationBlock,
4553 ) -> Strong<LockedDeclarationBlock> {
4554     let global_style_data = &*GLOBAL_STYLE_DATA;
4555     let guard = global_style_data.shared_lock.read();
4556     Arc::new(
4557         global_style_data
4558             .shared_lock
4559             .wrap(declarations.read_with(&guard).clone()),
4560     )
4561     .into()
4564 #[no_mangle]
4565 pub extern "C" fn Servo_DeclarationBlock_Equals(
4566     a: &LockedDeclarationBlock,
4567     b: &LockedDeclarationBlock,
4568 ) -> bool {
4569     let global_style_data = &*GLOBAL_STYLE_DATA;
4570     let guard = global_style_data.shared_lock.read();
4571     a.read_with(&guard).declarations() == b.read_with(&guard).declarations()
4574 #[no_mangle]
4575 pub extern "C" fn Servo_DeclarationBlock_GetCssText(
4576     declarations: &LockedDeclarationBlock,
4577     result: &mut nsACString,
4578 ) {
4579     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4580         decls.to_css(result).unwrap()
4581     })
4584 #[no_mangle]
4585 pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
4586     decls: &LockedDeclarationBlock,
4587     property_id: nsCSSPropertyID,
4588     buffer: &mut nsACString,
4589     computed_values: Option<&ComputedValues>,
4590     custom_properties: Option<&LockedDeclarationBlock>,
4591     data: &PerDocumentStyleData,
4592 ) {
4593     let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
4595     let global_style_data = &*GLOBAL_STYLE_DATA;
4596     let guard = global_style_data.shared_lock.read();
4597     let custom_properties = custom_properties.map(|block| block.read_with(&guard));
4598     let data = data.borrow();
4599     let rv = decls.read_with(&guard).single_value_to_css(
4600         &property_id,
4601         buffer,
4602         computed_values,
4603         custom_properties,
4604         &data.stylist,
4605     );
4606     debug_assert!(rv.is_ok());
4609 #[no_mangle]
4610 pub unsafe extern "C" fn Servo_SerializeFontValueForCanvas(
4611     declarations: &LockedDeclarationBlock,
4612     buffer: &mut nsACString,
4613 ) {
4614     use style::properties::shorthands::font;
4615     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4616         let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) {
4617             Ok(l) => l,
4618             Err(()) => {
4619                 warn!("Unexpected property!");
4620                 return;
4621             },
4622         };
4624         let rv = longhands.to_css(&mut CssWriter::new(buffer));
4625         debug_assert!(rv.is_ok());
4626     })
4629 #[no_mangle]
4630 pub extern "C" fn Servo_DeclarationBlock_Count(declarations: &LockedDeclarationBlock) -> u32 {
4631     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4632         decls.declarations().len() as u32
4633     })
4636 #[no_mangle]
4637 pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(
4638     declarations: &LockedDeclarationBlock,
4639     index: u32,
4640     result: &mut nsACString,
4641 ) -> bool {
4642     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4643         if let Some(decl) = decls.declarations().get(index as usize) {
4644             result.assign(&decl.id().name());
4645             true
4646         } else {
4647             false
4648         }
4649     })
4652 macro_rules! get_property_id_from_property {
4653     ($property: ident, $ret: expr) => {{
4654         let property = $property.as_str_unchecked();
4655         match PropertyId::parse_enabled_for_all_content(property) {
4656             Ok(property_id) => property_id,
4657             Err(_) => return $ret,
4658         }
4659     }};
4662 unsafe fn get_property_value(
4663     declarations: &LockedDeclarationBlock,
4664     property_id: PropertyId,
4665     value: &mut nsACString,
4666 ) {
4667     // This callsite is hot enough that the lock acquisition shows up in profiles.
4668     // Using an unchecked read here improves our performance by ~10% on the
4669     // microbenchmark in bug 1355599.
4670     read_locked_arc_unchecked(declarations, |decls: &PropertyDeclarationBlock| {
4671         decls.property_value_to_css(&property_id, value).unwrap();
4672     })
4675 #[no_mangle]
4676 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValue(
4677     declarations: &LockedDeclarationBlock,
4678     property: &nsACString,
4679     value: &mut nsACString,
4680 ) {
4681     get_property_value(
4682         declarations,
4683         get_property_id_from_property!(property, ()),
4684         value,
4685     )
4688 #[no_mangle]
4689 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(
4690     declarations: &LockedDeclarationBlock,
4691     property: nsCSSPropertyID,
4692     value: &mut nsACString,
4693 ) {
4694     get_property_value(
4695         declarations,
4696         get_property_id_from_nscsspropertyid!(property, ()),
4697         value,
4698     )
4701 #[no_mangle]
4702 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(
4703     declarations: &LockedDeclarationBlock,
4704     property: &nsACString,
4705 ) -> bool {
4706     let property_id = get_property_id_from_property!(property, false);
4707     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4708         decls.property_priority(&property_id).important()
4709     })
4712 #[inline(always)]
4713 fn set_property_to_declarations(
4714     non_custom_property_id: Option<NonCustomPropertyId>,
4715     block: &LockedDeclarationBlock,
4716     parsed_declarations: &mut SourcePropertyDeclaration,
4717     before_change_closure: DeclarationBlockMutationClosure,
4718     importance: Importance,
4719 ) -> bool {
4720     let mut updates = Default::default();
4721     let will_change = read_locked_arc(block, |decls: &PropertyDeclarationBlock| {
4722         decls.prepare_for_update(&parsed_declarations, importance, &mut updates)
4723     });
4724     if !will_change {
4725         return false;
4726     }
4728     before_change_closure.invoke(non_custom_property_id);
4729     write_locked_arc(block, |decls: &mut PropertyDeclarationBlock| {
4730         decls.update(parsed_declarations.drain(), importance, &mut updates)
4731     });
4732     true
4735 fn set_property(
4736     declarations: &LockedDeclarationBlock,
4737     property_id: PropertyId,
4738     value: &nsACString,
4739     is_important: bool,
4740     data: &UrlExtraData,
4741     parsing_mode: ParsingMode,
4742     quirks_mode: QuirksMode,
4743     loader: *mut Loader,
4744     rule_type: CssRuleType,
4745     before_change_closure: DeclarationBlockMutationClosure,
4746 ) -> bool {
4747     let mut source_declarations = SourcePropertyDeclaration::default();
4748     let reporter = ErrorReporter::new(ptr::null_mut(), loader, data.ptr());
4749     let non_custom_property_id = property_id.non_custom_id();
4750     let result = parse_property_into(
4751         &mut source_declarations,
4752         property_id,
4753         value,
4754         Origin::Author,
4755         data,
4756         parsing_mode,
4757         quirks_mode,
4758         rule_type,
4759         reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4760     );
4762     if result.is_err() {
4763         return false;
4764     }
4766     let importance = if is_important {
4767         Importance::Important
4768     } else {
4769         Importance::Normal
4770     };
4772     set_property_to_declarations(
4773         non_custom_property_id,
4774         declarations,
4775         &mut source_declarations,
4776         before_change_closure,
4777         importance,
4778     )
4781 #[no_mangle]
4782 pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
4783     declarations: &LockedDeclarationBlock,
4784     property: &nsACString,
4785     value: &nsACString,
4786     is_important: bool,
4787     data: *mut URLExtraData,
4788     parsing_mode: ParsingMode,
4789     quirks_mode: nsCompatibility,
4790     loader: *mut Loader,
4791     rule_type: CssRuleType,
4792     before_change_closure: DeclarationBlockMutationClosure,
4793 ) -> bool {
4794     set_property(
4795         declarations,
4796         get_property_id_from_property!(property, false),
4797         value,
4798         is_important,
4799         UrlExtraData::from_ptr_ref(&data),
4800         parsing_mode,
4801         quirks_mode.into(),
4802         loader,
4803         rule_type,
4804         before_change_closure,
4805     )
4808 #[no_mangle]
4809 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
4810     declarations: &LockedDeclarationBlock,
4811     animation_value: &AnimationValue,
4812     before_change_closure: DeclarationBlockMutationClosure,
4813 ) -> bool {
4814     let non_custom_property_id = animation_value.id().into();
4815     let mut source_declarations = SourcePropertyDeclaration::with_one(animation_value.uncompute());
4817     set_property_to_declarations(
4818         Some(non_custom_property_id),
4819         declarations,
4820         &mut source_declarations,
4821         before_change_closure,
4822         Importance::Normal,
4823     )
4826 #[no_mangle]
4827 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
4828     declarations: &LockedDeclarationBlock,
4829     property: nsCSSPropertyID,
4830     value: &nsACString,
4831     is_important: bool,
4832     data: *mut URLExtraData,
4833     parsing_mode: ParsingMode,
4834     quirks_mode: nsCompatibility,
4835     loader: *mut Loader,
4836     rule_type: CssRuleType,
4837     before_change_closure: DeclarationBlockMutationClosure,
4838 ) -> bool {
4839     set_property(
4840         declarations,
4841         get_property_id_from_nscsspropertyid!(property, false),
4842         value,
4843         is_important,
4844         UrlExtraData::from_ptr_ref(&data),
4845         parsing_mode,
4846         quirks_mode.into(),
4847         loader,
4848         rule_type,
4849         before_change_closure,
4850     )
4853 fn remove_property(
4854     declarations: &LockedDeclarationBlock,
4855     property_id: PropertyId,
4856     before_change_closure: DeclarationBlockMutationClosure,
4857 ) -> bool {
4858     let first_declaration = read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4859         decls.first_declaration_to_remove(&property_id)
4860     });
4862     let first_declaration = match first_declaration {
4863         Some(i) => i,
4864         None => return false,
4865     };
4867     before_change_closure.invoke(property_id.non_custom_id());
4868     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4869         decls.remove_property(&property_id, first_declaration)
4870     });
4872     true
4875 #[no_mangle]
4876 pub unsafe extern "C" fn Servo_DeclarationBlock_RemoveProperty(
4877     declarations: &LockedDeclarationBlock,
4878     property: &nsACString,
4879     before_change_closure: DeclarationBlockMutationClosure,
4880 ) -> bool {
4881     remove_property(
4882         declarations,
4883         get_property_id_from_property!(property, false),
4884         before_change_closure,
4885     )
4888 #[no_mangle]
4889 pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(
4890     declarations: &LockedDeclarationBlock,
4891     property: nsCSSPropertyID,
4892     before_change_closure: DeclarationBlockMutationClosure,
4893 ) -> bool {
4894     remove_property(
4895         declarations,
4896         get_property_id_from_nscsspropertyid!(property, false),
4897         before_change_closure,
4898     )
4901 #[no_mangle]
4902 pub extern "C" fn Servo_MediaList_Create() -> Strong<LockedMediaList> {
4903     let global_style_data = &*GLOBAL_STYLE_DATA;
4904     Arc::new(global_style_data.shared_lock.wrap(MediaList::empty())).into()
4907 #[no_mangle]
4908 pub extern "C" fn Servo_MediaList_DeepClone(list: &LockedMediaList) -> Strong<LockedMediaList> {
4909     let global_style_data = &*GLOBAL_STYLE_DATA;
4910     read_locked_arc(list, |list: &MediaList| {
4911         Arc::new(global_style_data.shared_lock.wrap(list.clone())).into()
4912     })
4915 #[no_mangle]
4916 pub extern "C" fn Servo_MediaList_Matches(
4917     list: &LockedMediaList,
4918     raw_data: &PerDocumentStyleData,
4919 ) -> bool {
4920     let per_doc_data = raw_data.borrow();
4921     read_locked_arc(list, |list: &MediaList| {
4922         list.evaluate(
4923             per_doc_data.stylist.device(),
4924             per_doc_data.stylist.quirks_mode(),
4925         )
4926     })
4929 #[no_mangle]
4930 pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword(
4931     declarations: &LockedDeclarationBlock,
4932     property: nsCSSPropertyID,
4933 ) -> bool {
4934     let property_id = get_property_id_from_nscsspropertyid!(property, false);
4935     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4936         decls.has_css_wide_keyword(&property_id)
4937     })
4940 #[no_mangle]
4941 pub extern "C" fn Servo_MediaList_GetText(list: &LockedMediaList, result: &mut nsACString) {
4942     read_locked_arc(list, |list: &MediaList| {
4943         list.to_css(&mut CssWriter::new(result)).unwrap();
4944     })
4947 #[no_mangle]
4948 pub unsafe extern "C" fn Servo_MediaList_SetText(
4949     list: &LockedMediaList,
4950     text: &nsACString,
4951     caller_type: CallerType,
4952 ) {
4953     let text = text.as_str_unchecked();
4955     let mut input = ParserInput::new(&text);
4956     let mut parser = Parser::new(&mut input);
4957     let url_data = dummy_url_data();
4959     // TODO(emilio): If the need for `CallerType` appears in more places,
4960     // consider adding an explicit member in `ParserContext` instead of doing
4961     // this (or adding a dummy "chrome://" url data).
4962     //
4963     // For media query parsing it's effectively the same, so for now...
4964     let origin = match caller_type {
4965         CallerType::System => Origin::UserAgent,
4966         CallerType::NonSystem => Origin::Author,
4967     };
4969     let context = ParserContext::new(
4970         origin,
4971         url_data,
4972         Some(CssRuleType::Media),
4973         ParsingMode::DEFAULT,
4974         QuirksMode::NoQuirks,
4975         /* namespaces = */ Default::default(),
4976         // TODO(emilio): Looks like error reporting could be useful here?
4977         None,
4978         None,
4979     );
4981     write_locked_arc(list, |list: &mut MediaList| {
4982         *list = MediaList::parse(&context, &mut parser);
4983     })
4986 #[no_mangle]
4987 pub extern "C" fn Servo_MediaList_IsViewportDependent(list: &LockedMediaList) -> bool {
4988     read_locked_arc(list, |list: &MediaList| list.is_viewport_dependent())
4991 #[no_mangle]
4992 pub extern "C" fn Servo_MediaList_GetLength(list: &LockedMediaList) -> u32 {
4993     read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32)
4996 #[no_mangle]
4997 pub extern "C" fn Servo_MediaList_GetMediumAt(
4998     list: &LockedMediaList,
4999     index: u32,
5000     result: &mut nsACString,
5001 ) -> bool {
5002     read_locked_arc(list, |list: &MediaList| {
5003         let media_query = match list.media_queries.get(index as usize) {
5004             Some(mq) => mq,
5005             None => return false,
5006         };
5007         media_query.to_css(&mut CssWriter::new(result)).unwrap();
5008         true
5009     })
5012 #[no_mangle]
5013 pub extern "C" fn Servo_MediaList_AppendMedium(list: &LockedMediaList, new_medium: &nsACString) {
5014     let new_medium = unsafe { new_medium.as_str_unchecked() };
5015     let url_data = unsafe { dummy_url_data() };
5016     let context = ParserContext::new(
5017         Origin::Author,
5018         url_data,
5019         Some(CssRuleType::Media),
5020         ParsingMode::DEFAULT,
5021         QuirksMode::NoQuirks,
5022         /* namespaces = */ Default::default(),
5023         None,
5024         None,
5025     );
5026     write_locked_arc(list, |list: &mut MediaList| {
5027         list.append_medium(&context, new_medium);
5028     })
5031 #[no_mangle]
5032 pub extern "C" fn Servo_MediaList_DeleteMedium(
5033     list: &LockedMediaList,
5034     old_medium: &nsACString,
5035 ) -> bool {
5036     let old_medium = unsafe { old_medium.as_str_unchecked() };
5037     let url_data = unsafe { dummy_url_data() };
5038     let context = ParserContext::new(
5039         Origin::Author,
5040         url_data,
5041         Some(CssRuleType::Media),
5042         ParsingMode::DEFAULT,
5043         QuirksMode::NoQuirks,
5044         /* namespaces = */ Default::default(),
5045         None,
5046         None,
5047     );
5048     write_locked_arc(list, |list: &mut MediaList| {
5049         list.delete_medium(&context, old_medium)
5050     })
5053 #[no_mangle]
5054 pub extern "C" fn Servo_MediaList_SizeOfIncludingThis(
5055     malloc_size_of: GeckoMallocSizeOf,
5056     malloc_enclosing_size_of: GeckoMallocSizeOf,
5057     list: &LockedMediaList,
5058 ) -> usize {
5059     use malloc_size_of::MallocSizeOf;
5060     use malloc_size_of::MallocUnconditionalShallowSizeOf;
5062     let global_style_data = &*GLOBAL_STYLE_DATA;
5063     let guard = global_style_data.shared_lock.read();
5065     let mut ops = MallocSizeOfOps::new(
5066         malloc_size_of.unwrap(),
5067         Some(malloc_enclosing_size_of.unwrap()),
5068         None,
5069     );
5071     unsafe { ArcBorrow::from_ref(list) }.with_arc(|list| {
5072         let mut n = 0;
5073         n += list.unconditional_shallow_size_of(&mut ops);
5074         n += list.read_with(&guard).size_of(&mut ops);
5075         n
5076     })
5079 macro_rules! get_longhand_from_id {
5080     ($id:expr) => {
5081         match PropertyId::from_nscsspropertyid($id) {
5082             Ok(PropertyId::Longhand(long)) => long,
5083             _ => panic!("stylo: unknown presentation property with id"),
5084         }
5085     };
5088 macro_rules! match_wrap_declared {
5089     ($longhand:ident, $($property:ident => $inner:expr,)*) => (
5090         match $longhand {
5091             $(
5092                 LonghandId::$property => PropertyDeclaration::$property($inner),
5093             )*
5094             _ => {
5095                 panic!("stylo: Don't know how to handle presentation property");
5096             }
5097         }
5098     )
5101 #[no_mangle]
5102 pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(
5103     declarations: &LockedDeclarationBlock,
5104     property: nsCSSPropertyID,
5105 ) -> bool {
5106     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
5107         decls.contains(PropertyDeclarationId::Longhand(get_longhand_from_id!(
5108             property
5109         )))
5110     })
5113 #[no_mangle]
5114 pub unsafe extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(
5115     declarations: &LockedDeclarationBlock,
5116     property: nsCSSPropertyID,
5117     value: *mut nsAtom,
5118 ) {
5119     use style::properties::longhands::_x_lang::computed_value::T as Lang;
5120     use style::properties::PropertyDeclaration;
5122     let long = get_longhand_from_id!(property);
5123     let prop = match_wrap_declared! { long,
5124         XLang => Lang(Atom::from_raw(value)),
5125     };
5126     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5127         decls.push(prop, Importance::Normal);
5128     })
5131 #[no_mangle]
5132 #[allow(unreachable_code)]
5133 pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
5134     declarations: &LockedDeclarationBlock,
5135     property: nsCSSPropertyID,
5136     value: i32,
5137 ) {
5138     use num_traits::FromPrimitive;
5139     use style::properties::longhands;
5140     use style::properties::PropertyDeclaration;
5141     use style::values::generics::box_::{VerticalAlign, VerticalAlignKeyword};
5142     use style::values::generics::font::FontStyle;
5143     use style::values::specified::{
5144         table::CaptionSide, BorderStyle, Clear, Display, Float, TextAlign, TextEmphasisPosition, TextTransform
5145     };
5147     fn get_from_computed<T>(value: u32) -> T
5148     where
5149         T: ToComputedValue,
5150         T::ComputedValue: FromPrimitive,
5151     {
5152         T::from_computed_value(&T::ComputedValue::from_u32(value).unwrap())
5153     }
5155     let long = get_longhand_from_id!(property);
5156     let value = value as u32;
5158     let prop = match_wrap_declared! { long,
5159         MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value),
5160         Direction => get_from_computed::<longhands::direction::SpecifiedValue>(value),
5161         Display => get_from_computed::<Display>(value),
5162         Float => get_from_computed::<Float>(value),
5163         Clear => get_from_computed::<Clear>(value),
5164         VerticalAlign => VerticalAlign::Keyword(VerticalAlignKeyword::from_u32(value).unwrap()),
5165         TextAlign => get_from_computed::<TextAlign>(value),
5166         TextEmphasisPosition => TextEmphasisPosition::from_bits_truncate(value as u8),
5167         FontSize => {
5168             // We rely on Gecko passing in font-size values (0...7) here.
5169             longhands::font_size::SpecifiedValue::from_html_size(value as u8)
5170         },
5171         FontStyle => {
5172             style::values::specified::FontStyle::Specified(if value == structs::NS_FONT_STYLE_ITALIC {
5173                 FontStyle::Italic
5174             } else {
5175                 debug_assert_eq!(value, structs::NS_FONT_STYLE_NORMAL);
5176                 FontStyle::Normal
5177             })
5178         },
5179         FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value),
5180         ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
5181         MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value),
5182         MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
5183         WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value),
5184         CaptionSide => get_from_computed::<CaptionSide>(value),
5185         BorderTopStyle => get_from_computed::<BorderStyle>(value),
5186         BorderRightStyle => get_from_computed::<BorderStyle>(value),
5187         BorderBottomStyle => get_from_computed::<BorderStyle>(value),
5188         BorderLeftStyle => get_from_computed::<BorderStyle>(value),
5189         TextTransform => {
5190             debug_assert_eq!(value, structs::StyleTextTransformCase_None as u32);
5191             TextTransform::none()
5192         },
5193     };
5194     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5195         decls.push(prop, Importance::Normal);
5196     })
5199 #[no_mangle]
5200 pub extern "C" fn Servo_DeclarationBlock_SetIntValue(
5201     declarations: &LockedDeclarationBlock,
5202     property: nsCSSPropertyID,
5203     value: i32,
5204 ) {
5205     use style::properties::PropertyDeclaration;
5206     use style::values::specified::Integer;
5208     let long = get_longhand_from_id!(property);
5209     let prop = match_wrap_declared! { long,
5210         XSpan => Integer::new(value),
5211     };
5212     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5213         decls.push(prop, Importance::Normal);
5214     })
5217 #[no_mangle]
5218 pub extern "C" fn Servo_DeclarationBlock_SetMathDepthValue(
5219     declarations: &LockedDeclarationBlock,
5220     value: i32,
5221     is_relative: bool,
5222 ) {
5223     use style::properties::longhands::math_depth::SpecifiedValue as MathDepth;
5224     use style::properties::PropertyDeclaration;
5226     let integer_value = style::values::specified::Integer::new(value);
5227     let prop = PropertyDeclaration::MathDepth(if is_relative {
5228         MathDepth::Add(integer_value)
5229     } else {
5230         MathDepth::Absolute(integer_value)
5231     });
5232     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5233         decls.push(prop, Importance::Normal);
5234     })
5237 #[no_mangle]
5238 pub extern "C" fn Servo_DeclarationBlock_SetCounterResetListItem(
5239     declarations: &LockedDeclarationBlock,
5240     counter_value: i32,
5241     is_reversed: bool,
5242 ) {
5243     use style::properties::PropertyDeclaration;
5244     use style::values::generics::counters::{CounterPair, CounterReset};
5246     let prop = PropertyDeclaration::CounterReset(CounterReset::new(vec![CounterPair {
5247         name: CustomIdent(atom!("list-item")),
5248         value: style::values::specified::Integer::new(counter_value),
5249         is_reversed,
5250     }]));
5251     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5252         decls.push(prop, Importance::Normal);
5253     })
5256 #[no_mangle]
5257 pub extern "C" fn Servo_DeclarationBlock_SetCounterSetListItem(
5258     declarations: &LockedDeclarationBlock,
5259     counter_value: i32,
5260 ) {
5261     use style::properties::PropertyDeclaration;
5262     use style::values::generics::counters::{CounterPair, CounterSet};
5264     let prop = PropertyDeclaration::CounterSet(CounterSet::new(vec![CounterPair {
5265         name: CustomIdent(atom!("list-item")),
5266         value: style::values::specified::Integer::new(counter_value),
5267         is_reversed: false,
5268     }]));
5269     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5270         decls.push(prop, Importance::Normal);
5271     })
5274 #[no_mangle]
5275 pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
5276     declarations: &LockedDeclarationBlock,
5277     property: nsCSSPropertyID,
5278     value: f32,
5279 ) {
5280     use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
5281     use style::properties::PropertyDeclaration;
5282     use style::values::generics::length::{LengthPercentageOrAuto, Size};
5283     use style::values::generics::NonNegative;
5284     use style::values::specified::length::{
5285         LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage,
5286     };
5287     use style::values::specified::{BorderCornerRadius, BorderSideWidth};
5289     let long = get_longhand_from_id!(property);
5290     let nocalc = NoCalcLength::from_px(value);
5291     let lp = LengthPercentage::Length(nocalc);
5292     let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
5293     let prop = match_wrap_declared! { long,
5294         Height => Size::LengthPercentage(NonNegative(lp)),
5295         Width => Size::LengthPercentage(NonNegative(lp)),
5296         BorderTopWidth => BorderSideWidth::from_px(value),
5297         BorderRightWidth => BorderSideWidth::from_px(value),
5298         BorderBottomWidth => BorderSideWidth::from_px(value),
5299         BorderLeftWidth => BorderSideWidth::from_px(value),
5300         MarginTop => lp_or_auto,
5301         MarginRight => lp_or_auto,
5302         MarginBottom => lp_or_auto,
5303         MarginLeft => lp_or_auto,
5304         PaddingTop => NonNegative(lp),
5305         PaddingRight => NonNegative(lp),
5306         PaddingBottom => NonNegative(lp),
5307         PaddingLeft => NonNegative(lp),
5308         BorderSpacing => {
5309             let v = NonNegativeLength::from(nocalc);
5310             Box::new(BorderSpacing::new(v.clone(), v))
5311         },
5312         BorderTopLeftRadius => {
5313             let length = NonNegativeLengthPercentage::from(nocalc);
5314             Box::new(BorderCornerRadius::new(length.clone(), length))
5315         },
5316         BorderTopRightRadius => {
5317             let length = NonNegativeLengthPercentage::from(nocalc);
5318             Box::new(BorderCornerRadius::new(length.clone(), length))
5319         },
5320         BorderBottomLeftRadius => {
5321             let length = NonNegativeLengthPercentage::from(nocalc);
5322             Box::new(BorderCornerRadius::new(length.clone(), length))
5323         },
5324         BorderBottomRightRadius => {
5325             let length = NonNegativeLengthPercentage::from(nocalc);
5326             Box::new(BorderCornerRadius::new(length.clone(), length))
5327         },
5328     };
5329     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5330         decls.push(prop, Importance::Normal);
5331     })
5334 #[no_mangle]
5335 pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
5336     declarations: &LockedDeclarationBlock,
5337     property: nsCSSPropertyID,
5338     value: f32,
5339     unit: structs::nsCSSUnit,
5340 ) {
5341     use style::properties::PropertyDeclaration;
5342     use style::values::generics::length::{LengthPercentageOrAuto, Size};
5343     use style::values::generics::NonNegative;
5344     use style::values::specified::length::{FontRelativeLength, LengthPercentage};
5345     use style::values::specified::FontSize;
5347     let long = get_longhand_from_id!(property);
5348     let nocalc = match unit {
5349         structs::nsCSSUnit::eCSSUnit_EM => {
5350             NoCalcLength::FontRelative(FontRelativeLength::Em(value))
5351         },
5352         structs::nsCSSUnit::eCSSUnit_XHeight => {
5353             NoCalcLength::FontRelative(FontRelativeLength::Ex(value))
5354         },
5355         structs::nsCSSUnit::eCSSUnit_Pixel => NoCalcLength::Absolute(AbsoluteLength::Px(value)),
5356         structs::nsCSSUnit::eCSSUnit_Inch => NoCalcLength::Absolute(AbsoluteLength::In(value)),
5357         structs::nsCSSUnit::eCSSUnit_Centimeter => {
5358             NoCalcLength::Absolute(AbsoluteLength::Cm(value))
5359         },
5360         structs::nsCSSUnit::eCSSUnit_Millimeter => {
5361             NoCalcLength::Absolute(AbsoluteLength::Mm(value))
5362         },
5363         structs::nsCSSUnit::eCSSUnit_Point => NoCalcLength::Absolute(AbsoluteLength::Pt(value)),
5364         structs::nsCSSUnit::eCSSUnit_Pica => NoCalcLength::Absolute(AbsoluteLength::Pc(value)),
5365         structs::nsCSSUnit::eCSSUnit_Quarter => NoCalcLength::Absolute(AbsoluteLength::Q(value)),
5366         _ => unreachable!("Unknown unit passed to SetLengthValue"),
5367     };
5369     let prop = match_wrap_declared! { long,
5370         Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5371         Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5372         X =>  LengthPercentage::Length(nocalc),
5373         Y =>  LengthPercentage::Length(nocalc),
5374         Cx => LengthPercentage::Length(nocalc),
5375         Cy => LengthPercentage::Length(nocalc),
5376         R =>  NonNegative(LengthPercentage::Length(nocalc)),
5377         Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5378         Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5379         FontSize => FontSize::Length(LengthPercentage::Length(nocalc)),
5380     };
5381     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5382         decls.push(prop, Importance::Normal);
5383     })
5386 #[no_mangle]
5387 pub extern "C" fn Servo_DeclarationBlock_SetPathValue(
5388     declarations: &LockedDeclarationBlock,
5389     property: nsCSSPropertyID,
5390     path: &nsTArray<f32>,
5391 ) {
5392     use style::properties::PropertyDeclaration;
5393     use style::values::specified::DProperty;
5395     // 1. Decode the path data from SVG.
5396     let path = match specified::SVGPathData::decode_from_f32_array(path) {
5397         Ok(p) => p,
5398         Err(()) => return,
5399     };
5401     // 2. Set decoded path into style.
5402     let long = get_longhand_from_id!(property);
5403     let prop = match_wrap_declared! { long,
5404         D => if path.0.is_empty() { DProperty::None } else { DProperty::Path(path) },
5405     };
5406     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5407         decls.push(prop, Importance::Normal);
5408     })
5411 #[no_mangle]
5412 pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
5413     declarations: &LockedDeclarationBlock,
5414     property: nsCSSPropertyID,
5415     value: f32,
5416 ) {
5417     use style::properties::PropertyDeclaration;
5418     use style::values::computed::Percentage;
5419     use style::values::generics::length::{LengthPercentageOrAuto, Size};
5420     use style::values::generics::NonNegative;
5421     use style::values::specified::length::LengthPercentage;
5422     use style::values::specified::FontSize;
5424     let long = get_longhand_from_id!(property);
5425     let pc = Percentage(value);
5426     let lp = LengthPercentage::Percentage(pc);
5427     let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
5429     let prop = match_wrap_declared! { long,
5430         Height => Size::LengthPercentage(NonNegative(lp)),
5431         Width => Size::LengthPercentage(NonNegative(lp)),
5432         X =>  lp,
5433         Y =>  lp,
5434         Cx => lp,
5435         Cy => lp,
5436         R =>  NonNegative(lp),
5437         Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5438         Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5439         MarginTop => lp_or_auto,
5440         MarginRight => lp_or_auto,
5441         MarginBottom => lp_or_auto,
5442         MarginLeft => lp_or_auto,
5443         FontSize => FontSize::Length(LengthPercentage::Percentage(pc)),
5444     };
5445     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5446         decls.push(prop, Importance::Normal);
5447     })
5450 #[no_mangle]
5451 pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(
5452     declarations: &LockedDeclarationBlock,
5453     property: nsCSSPropertyID,
5454 ) {
5455     use style::properties::PropertyDeclaration;
5456     use style::values::generics::length::{LengthPercentageOrAuto, Size};
5458     let long = get_longhand_from_id!(property);
5459     let auto = LengthPercentageOrAuto::Auto;
5461     let prop = match_wrap_declared! { long,
5462         Height => Size::auto(),
5463         Width => Size::auto(),
5464         MarginTop => auto,
5465         MarginRight => auto,
5466         MarginBottom => auto,
5467         MarginLeft => auto,
5468         AspectRatio => specified::AspectRatio::auto(),
5469     };
5470     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5471         decls.push(prop, Importance::Normal);
5472     })
5475 #[no_mangle]
5476 pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(
5477     declarations: &LockedDeclarationBlock,
5478     property: nsCSSPropertyID,
5479 ) {
5480     use style::properties::PropertyDeclaration;
5481     use style::values::specified::Color;
5483     let long = get_longhand_from_id!(property);
5484     let cc = Color::currentcolor();
5486     let prop = match_wrap_declared! { long,
5487         BorderTopColor => cc,
5488         BorderRightColor => cc,
5489         BorderBottomColor => cc,
5490         BorderLeftColor => cc,
5491     };
5492     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5493         decls.push(prop, Importance::Normal);
5494     })
5497 #[no_mangle]
5498 pub extern "C" fn Servo_DeclarationBlock_SetColorValue(
5499     declarations: &LockedDeclarationBlock,
5500     property: nsCSSPropertyID,
5501     value: structs::nscolor,
5502 ) {
5503     use style::gecko::values::convert_nscolor_to_absolute_color;
5504     use style::properties::longhands;
5505     use style::properties::PropertyDeclaration;
5506     use style::values::specified::Color;
5508     let long = get_longhand_from_id!(property);
5509     let rgba = convert_nscolor_to_absolute_color(value);
5510     let color = Color::from_absolute_color(rgba);
5512     let prop = match_wrap_declared! { long,
5513         BorderTopColor => color,
5514         BorderRightColor => color,
5515         BorderBottomColor => color,
5516         BorderLeftColor => color,
5517         Color => longhands::color::SpecifiedValue(color),
5518         BackgroundColor => color,
5519     };
5520     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5521         decls.push(prop, Importance::Normal);
5522     })
5525 #[no_mangle]
5526 pub unsafe extern "C" fn Servo_DeclarationBlock_SetFontFamily(
5527     declarations: &LockedDeclarationBlock,
5528     value: &nsACString,
5529 ) {
5530     use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
5531     use style::properties::PropertyDeclaration;
5533     let string = value.as_str_unchecked();
5534     let mut input = ParserInput::new(&string);
5535     let mut parser = Parser::new(&mut input);
5536     let context = ParserContext::new(
5537         Origin::Author,
5538         dummy_url_data(),
5539         Some(CssRuleType::Style),
5540         ParsingMode::DEFAULT,
5541         QuirksMode::NoQuirks,
5542         /* namespaces = */ Default::default(),
5543         None,
5544         None,
5545     );
5546     let result = FontFamily::parse(&context, &mut parser);
5547     if let Ok(family) = result {
5548         if parser.is_exhausted() {
5549             let decl = PropertyDeclaration::FontFamily(family);
5550             write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5551                 decls.push(decl, Importance::Normal);
5552             })
5553         }
5554     }
5557 #[no_mangle]
5558 pub unsafe extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(
5559     declarations: &LockedDeclarationBlock,
5560     value: &nsACString,
5561     raw_extra_data: *mut URLExtraData,
5562 ) {
5563     use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
5564     use style::properties::PropertyDeclaration;
5565     use style::stylesheets::CorsMode;
5566     use style::values::generics::image::Image;
5567     use style::values::specified::url::SpecifiedImageUrl;
5569     let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
5570     let string = value.as_str_unchecked();
5571     let context = ParserContext::new(
5572         Origin::Author,
5573         url_data,
5574         Some(CssRuleType::Style),
5575         ParsingMode::DEFAULT,
5576         QuirksMode::NoQuirks,
5577         /* namespaces = */ Default::default(),
5578         None,
5579         None,
5580     );
5581     let url = SpecifiedImageUrl::parse_from_string(string.into(), &context, CorsMode::None);
5582     let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(vec![Image::Url(url)].into()));
5583     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5584         decls.push(decl, Importance::Normal);
5585     });
5588 #[no_mangle]
5589 pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(
5590     declarations: &LockedDeclarationBlock,
5591 ) {
5592     use style::properties::PropertyDeclaration;
5593     use style::values::specified::text::TextDecorationLine;
5595     let decoration = TextDecorationLine::COLOR_OVERRIDE;
5596     let decl = PropertyDeclaration::TextDecorationLine(decoration);
5597     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5598         decls.push(decl, Importance::Normal);
5599     })
5602 #[no_mangle]
5603 pub extern "C" fn Servo_DeclarationBlock_SetAspectRatio(
5604     declarations: &LockedDeclarationBlock,
5605     width: f32,
5606     height: f32,
5607 ) {
5608     use style::properties::PropertyDeclaration;
5609     use style::values::generics::position::AspectRatio;
5611     let decl = PropertyDeclaration::AspectRatio(AspectRatio::from_mapped_ratio(width, height));
5612     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5613         decls.push(decl, Importance::Normal);
5614     })
5617 #[no_mangle]
5618 pub extern "C" fn Servo_CSSSupports2(property: &nsACString, value: &nsACString) -> bool {
5619     let id = unsafe { get_property_id_from_property!(property, false) };
5621     let mut declarations = SourcePropertyDeclaration::default();
5622     parse_property_into(
5623         &mut declarations,
5624         id,
5625         value,
5626         Origin::Author,
5627         unsafe { dummy_url_data() },
5628         ParsingMode::DEFAULT,
5629         QuirksMode::NoQuirks,
5630         CssRuleType::Style,
5631         None,
5632     )
5633     .is_ok()
5636 #[no_mangle]
5637 pub extern "C" fn Servo_CSSSupports(
5638     cond: &nsACString,
5639     ua_origin: bool,
5640     chrome_sheet: bool,
5641     quirks: bool,
5642 ) -> bool {
5643     let condition = unsafe { cond.as_str_unchecked() };
5644     let mut input = ParserInput::new(&condition);
5645     let mut input = Parser::new(&mut input);
5646     let cond = match input.parse_entirely(parse_condition_or_declaration) {
5647         Ok(c) => c,
5648         Err(..) => return false,
5649     };
5651     let origin = if ua_origin {
5652         Origin::UserAgent
5653     } else {
5654         Origin::Author
5655     };
5656     let url_data = unsafe {
5657         UrlExtraData::from_ptr_ref(if chrome_sheet {
5658             &DUMMY_CHROME_URL_DATA
5659         } else {
5660             &DUMMY_URL_DATA
5661         })
5662     };
5663     let quirks_mode = if quirks {
5664         QuirksMode::Quirks
5665     } else {
5666         QuirksMode::NoQuirks
5667     };
5669     // NOTE(emilio): The supports API is not associated to any stylesheet,
5670     // so the fact that there is no namespace map here is fine.
5671     let context = ParserContext::new(
5672         origin,
5673         url_data,
5674         Some(CssRuleType::Style),
5675         ParsingMode::DEFAULT,
5676         quirks_mode,
5677         /* namespaces = */ Default::default(),
5678         None,
5679         None,
5680     );
5682     cond.eval(&context)
5685 #[no_mangle]
5686 pub extern "C" fn Servo_CSSSupportsForImport(after_rule: &nsACString) -> bool {
5687     let condition = unsafe { after_rule.as_str_unchecked() };
5688     let mut input = ParserInput::new(&condition);
5689     let mut input = Parser::new(&mut input);
5691     // NOTE(emilio): The supports API is not associated to any stylesheet,
5692     // so the fact that there is no namespace map here is fine.
5693     let mut context = ParserContext::new(
5694         Origin::Author,
5695         unsafe { dummy_url_data() },
5696         Some(CssRuleType::Style),
5697         ParsingMode::DEFAULT,
5698         QuirksMode::NoQuirks,
5699         /* namespaces = */ Default::default(),
5700         None,
5701         None,
5702     );
5704     let (_layer, supports) = ImportRule::parse_layer_and_supports(&mut input, &mut context);
5706     supports.map_or(true, |s| s.enabled)
5709 #[no_mangle]
5710 pub unsafe extern "C" fn Servo_NoteExplicitHints(
5711     element: &RawGeckoElement,
5712     restyle_hint: RestyleHint,
5713     change_hint: nsChangeHint,
5714 ) {
5715     GeckoElement(element).note_explicit_hints(restyle_hint, change_hint);
5718 #[no_mangle]
5719 pub extern "C" fn Servo_TakeChangeHint(element: &RawGeckoElement, was_restyled: &mut bool) -> u32 {
5720     let element = GeckoElement(element);
5722     let damage = match element.mutate_data() {
5723         Some(mut data) => {
5724             *was_restyled = data.is_restyle();
5726             let damage = data.damage;
5727             data.clear_restyle_state();
5728             damage
5729         },
5730         None => {
5731             warn!("Trying to get change hint from unstyled element");
5732             *was_restyled = false;
5733             GeckoRestyleDamage::empty()
5734         },
5735     };
5737     debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
5738     // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
5739     // work as return values with the Linux 32-bit ABI at the moment because
5740     // they wrap the value in a struct, so for now just unwrap it.
5741     damage.as_change_hint().0
5744 #[no_mangle]
5745 pub extern "C" fn Servo_ResolveStyle(element: &RawGeckoElement) -> Strong<ComputedValues> {
5746     let element = GeckoElement(element);
5747     debug!("Servo_ResolveStyle: {:?}", element);
5748     let data = element
5749         .borrow_data()
5750         .expect("Resolving style on unstyled element");
5752     debug_assert!(
5753         element.has_current_styles(&*data),
5754         "Resolving style on {:?} without current styles: {:?}",
5755         element,
5756         data
5757     );
5758     data.styles.primary().clone().into()
5761 #[no_mangle]
5762 pub extern "C" fn Servo_ResolveStyleLazily(
5763     element: &RawGeckoElement,
5764     pseudo_type: PseudoStyleType,
5765     functional_pseudo_parameter: *mut nsAtom,
5766     rule_inclusion: StyleRuleInclusion,
5767     snapshots: *const ServoElementSnapshotTable,
5768     cache_generation: u64,
5769     can_use_cache: bool,
5770     raw_data: &PerDocumentStyleData,
5771 ) -> Strong<ComputedValues> {
5772     use selectors::Element;
5773     debug_assert!(!snapshots.is_null());
5774     let global_style_data = &*GLOBAL_STYLE_DATA;
5775     let guard = global_style_data.shared_lock.read();
5776     let element = GeckoElement(element);
5777     let mut data = raw_data.borrow_mut();
5778     let data = &mut *data;
5779     let rule_inclusion = RuleInclusion::from(rule_inclusion);
5780     let pseudo_element = PseudoElement::from_pseudo_type(
5781         pseudo_type,
5782         get_functional_pseudo_parameter_atom(functional_pseudo_parameter),
5783     );
5785     let matching_fn = |pseudo: &PseudoElement| match pseudo_element {
5786         Some(ref p) => *pseudo == *p,
5787         _ => false,
5788     };
5790     if cache_generation != data.undisplayed_style_cache_generation {
5791         data.undisplayed_style_cache.clear();
5792         data.undisplayed_style_cache_generation = cache_generation;
5793     }
5795     let stylist = &data.stylist;
5796     let finish = |styles: &ElementStyles, is_probe: bool| -> Option<Arc<ComputedValues>> {
5797         match pseudo_element {
5798             Some(ref pseudo) => {
5799                 get_pseudo_style(
5800                     &guard,
5801                     element,
5802                     pseudo,
5803                     rule_inclusion,
5804                     styles,
5805                     /* inherited_styles = */ None,
5806                     &stylist,
5807                     is_probe,
5808                     if pseudo.is_highlight() {
5809                         Some(&matching_fn)
5810                     } else {
5811                         None
5812                     },
5813                 )
5814             },
5815             None => Some(styles.primary().clone()),
5816         }
5817     };
5819     let is_before_or_after = pseudo_element
5820         .as_ref()
5821         .map_or(false, |p| p.is_before_or_after());
5823     // In the common case we already have the style. Check that before setting
5824     // up all the computation machinery.
5825     //
5826     // Also, only probe in the ::before or ::after case, since their styles may
5827     // not be in the `ElementData`, given they may exist but not be applicable
5828     // to generate an actual pseudo-element (like, having a `content: none`).
5829     if rule_inclusion == RuleInclusion::All {
5830         let styles = element.borrow_data().and_then(|d| {
5831             if d.has_styles() {
5832                 finish(&d.styles, is_before_or_after)
5833             } else {
5834                 None
5835             }
5836         });
5837         if let Some(result) = styles {
5838             return result.into();
5839         }
5840         if pseudo_element.is_none() && can_use_cache {
5841             if let Some(style) = data.undisplayed_style_cache.get(&element.opaque()) {
5842                 return style.clone().into();
5843             }
5844         }
5845     }
5847     // We don't have the style ready. Go ahead and compute it as necessary.
5848     let shared = create_shared_context(
5849         &global_style_data,
5850         &guard,
5851         &stylist,
5852         TraversalFlags::empty(),
5853         unsafe { &*snapshots },
5854     );
5855     let mut tlc = ThreadLocalStyleContext::new();
5856     let mut context = StyleContext {
5857         shared: &shared,
5858         thread_local: &mut tlc,
5859     };
5861     let styles = resolve_style(
5862         &mut context,
5863         element,
5864         rule_inclusion,
5865         pseudo_element.as_ref(),
5866         if can_use_cache {
5867             Some(&mut data.undisplayed_style_cache)
5868         } else {
5869             None
5870         },
5871     );
5873     finish(&styles, /* is_probe = */ false)
5874         .expect("We're not probing, so we should always get a style back")
5875         .into()
5878 #[no_mangle]
5879 pub extern "C" fn Servo_ReparentStyle(
5880     style_to_reparent: &ComputedValues,
5881     parent_style: &ComputedValues,
5882     layout_parent_style: &ComputedValues,
5883     element: Option<&RawGeckoElement>,
5884     raw_data: &PerDocumentStyleData,
5885 ) -> Strong<ComputedValues> {
5886     use style::properties::FirstLineReparenting;
5888     let global_style_data = &*GLOBAL_STYLE_DATA;
5889     let guard = global_style_data.shared_lock.read();
5890     let doc_data = raw_data.borrow();
5891     let inputs = CascadeInputs::new_from_style(style_to_reparent);
5892     let pseudo = style_to_reparent.pseudo();
5893     let element = element.map(GeckoElement);
5895     let is_pseudo_element = element.is_some() && pseudo.is_some();
5896     let originating_element_style = if is_pseudo_element {
5897         Some(parent_style)
5898     } else {
5899         None
5900     };
5902     doc_data
5903         .stylist
5904         .cascade_style_and_visited(
5905             element,
5906             pseudo.as_ref(),
5907             inputs,
5908             &StylesheetGuards::same(&guard),
5909             originating_element_style,
5910             Some(parent_style),
5911             Some(layout_parent_style),
5912             FirstLineReparenting::Yes { style_to_reparent },
5913             /* rule_cache = */ None,
5914             &mut RuleCacheConditions::default(),
5915         )
5916         .into()
5919 #[cfg(feature = "gecko_debug")]
5920 fn simulate_compute_values_failure(property: &PropertyValuePair) -> bool {
5921     let p = property.mProperty;
5922     let id = get_property_id_from_nscsspropertyid!(p, false);
5923     id.as_shorthand().is_ok() && property.mSimulateComputeValuesFailure
5926 #[cfg(not(feature = "gecko_debug"))]
5927 fn simulate_compute_values_failure(_: &PropertyValuePair) -> bool {
5928     false
5931 fn create_context_for_animation<'a>(
5932     per_doc_data: &'a PerDocumentStyleDataImpl,
5933     style: &'a ComputedValues,
5934     parent_style: Option<&'a ComputedValues>,
5935     for_smil_animation: bool,
5936     rule_cache_conditions: &'a mut RuleCacheConditions,
5937     container_size_query: ContainerSizeQuery<'a>,
5938 ) -> Context<'a> {
5939     Context::new_for_animation(
5940         StyleBuilder::for_animation(per_doc_data.stylist.device(), Some(&per_doc_data.stylist), style, parent_style),
5941         for_smil_animation,
5942         per_doc_data.stylist.quirks_mode(),
5943         rule_cache_conditions,
5944         container_size_query,
5945     )
5948 struct PropertyAndIndex {
5949     property: PropertyId,
5950     index: usize,
5953 struct PrioritizedPropertyIter<'a> {
5954     properties: &'a [PropertyValuePair],
5955     sorted_property_indices: Vec<PropertyAndIndex>,
5956     curr: usize,
5959 impl<'a> PrioritizedPropertyIter<'a> {
5960     fn new(properties: &'a [PropertyValuePair]) -> PrioritizedPropertyIter {
5961         use style::values::animated::compare_property_priority;
5963         // If we fail to convert a nsCSSPropertyID into a PropertyId we
5964         // shouldn't fail outright but instead by treating that property as the
5965         // 'all' property we make it sort last.
5966         let mut sorted_property_indices: Vec<PropertyAndIndex> = properties
5967             .iter()
5968             .enumerate()
5969             .map(|(index, pair)| {
5970                 let property = PropertyId::from_nscsspropertyid(pair.mProperty)
5971                     .unwrap_or(PropertyId::Shorthand(ShorthandId::All));
5973                 PropertyAndIndex { property, index }
5974             })
5975             .collect();
5976         sorted_property_indices.sort_by(|a, b| compare_property_priority(&a.property, &b.property));
5978         PrioritizedPropertyIter {
5979             properties,
5980             sorted_property_indices,
5981             curr: 0,
5982         }
5983     }
5986 impl<'a> Iterator for PrioritizedPropertyIter<'a> {
5987     type Item = &'a PropertyValuePair;
5989     fn next(&mut self) -> Option<&'a PropertyValuePair> {
5990         if self.curr >= self.sorted_property_indices.len() {
5991             return None;
5992         }
5993         self.curr += 1;
5994         Some(&self.properties[self.sorted_property_indices[self.curr - 1].index])
5995     }
5998 #[no_mangle]
5999 pub extern "C" fn Servo_GetComputedKeyframeValues(
6000     keyframes: &nsTArray<structs::Keyframe>,
6001     element: &RawGeckoElement,
6002     pseudo_type: PseudoStyleType,
6003     style: &ComputedValues,
6004     raw_data: &PerDocumentStyleData,
6005     computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>,
6006 ) {
6007     let data = raw_data.borrow();
6008     let element = GeckoElement(element);
6009     let pseudo = PseudoElement::from_pseudo_type(pseudo_type, None);
6010     let parent_element = if pseudo.is_none() {
6011         element.inheritance_parent()
6012     } else {
6013         Some(element)
6014     };
6015     let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6016     let parent_style = parent_data
6017         .as_ref()
6018         .map(|d| d.styles.primary())
6019         .map(|x| &**x);
6021     let container_size_query =
6022         ContainerSizeQuery::for_element(element, pseudo.as_ref().and(parent_style));
6023     let mut conditions = Default::default();
6024     let mut context = create_context_for_animation(
6025         &data,
6026         &style,
6027         parent_style,
6028         /* for_smil_animation = */ false,
6029         &mut conditions,
6030         container_size_query,
6031     );
6033     let restriction = pseudo.and_then(|p| p.property_restriction());
6035     let global_style_data = &*GLOBAL_STYLE_DATA;
6036     let guard = global_style_data.shared_lock.read();
6037     let default_values = data.default_computed_values();
6039     let mut raw_custom_properties_block; // To make the raw block alive in the scope.
6040     for (index, keyframe) in keyframes.iter().enumerate() {
6041         let mut custom_properties = None;
6042         for property in keyframe.mPropertyValues.iter() {
6043             // Find the block for custom properties first.
6044             if property.mProperty == nsCSSPropertyID::eCSSPropertyExtra_variable {
6045                 raw_custom_properties_block = unsafe { &*property.mServoDeclarationBlock.mRawPtr };
6046                 let guard = raw_custom_properties_block.read_with(&guard);
6047                 custom_properties = guard.cascade_custom_properties_with_context(&context);
6048                 // There should be one PropertyDeclarationBlock for custom properties.
6049                 break;
6050             }
6051         }
6053         let ref mut animation_values = computed_keyframes[index];
6055         let mut seen = LonghandIdSet::new();
6057         let mut property_index = 0;
6058         for property in PrioritizedPropertyIter::new(&keyframe.mPropertyValues) {
6059             if simulate_compute_values_failure(property) {
6060                 continue;
6061             }
6063             let mut maybe_append_animation_value =
6064                 |property: LonghandId, value: Option<AnimationValue>| {
6065                     debug_assert!(!property.is_logical());
6066                     debug_assert!(property.is_animatable());
6068                     // 'display' is only animatable from SMIL
6069                     if property == LonghandId::Display {
6070                         return;
6071                     }
6073                     // Skip restricted properties
6074                     if restriction.map_or(false, |r| !property.flags().contains(r)) {
6075                         return;
6076                     }
6078                     if seen.contains(property) {
6079                         return;
6080                     }
6081                     seen.insert(property);
6083                     // This is safe since we immediately write to the uninitialized values.
6084                     unsafe {
6085                         animation_values.set_len((property_index + 1) as u32);
6086                         ptr::write(
6087                             &mut animation_values[property_index],
6088                             structs::PropertyStyleAnimationValuePair {
6089                                 mProperty: property.to_nscsspropertyid(),
6090                                 mValue: structs::AnimationValue {
6091                                     mServo: value.map_or(structs::RefPtr::null(), |v| {
6092                                         structs::RefPtr::from_arc(Arc::new(v))
6093                                     }),
6094                                 },
6095                             },
6096                         );
6097                     }
6098                     property_index += 1;
6099                 };
6101             if property.mServoDeclarationBlock.mRawPtr.is_null() {
6102                 let property = LonghandId::from_nscsspropertyid(property.mProperty);
6103                 if let Ok(prop) = property {
6104                     maybe_append_animation_value(prop, None);
6105                 }
6106                 continue;
6107             }
6109             let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr };
6110             let guard = declarations.read_with(&guard);
6111             let iter = guard.to_animation_value_iter(
6112                 &mut context,
6113                 &default_values,
6114                 custom_properties.as_ref(),
6115             );
6117             for value in iter {
6118                 let id = value.id();
6119                 maybe_append_animation_value(id, Some(value));
6120             }
6121         }
6122     }
6125 #[no_mangle]
6126 pub extern "C" fn Servo_GetAnimationValues(
6127     declarations: &LockedDeclarationBlock,
6128     element: &RawGeckoElement,
6129     style: &ComputedValues,
6130     raw_data: &PerDocumentStyleData,
6131     animation_values: &mut ThinVec<structs::RefPtr<AnimationValue>>,
6132 ) {
6133     let data = raw_data.borrow();
6134     let element = GeckoElement(element);
6135     let parent_element = element.inheritance_parent();
6136     let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6137     let parent_style = parent_data
6138         .as_ref()
6139         .map(|d| d.styles.primary())
6140         .map(|x| &**x);
6142     let container_size_query = ContainerSizeQuery::for_element(element, None);
6143     let mut conditions = Default::default();
6144     let mut context = create_context_for_animation(
6145         &data,
6146         &style,
6147         parent_style,
6148         /* for_smil_animation = */ true,
6149         &mut conditions,
6150         container_size_query,
6151     );
6153     let default_values = data.default_computed_values();
6154     let global_style_data = &*GLOBAL_STYLE_DATA;
6155     let guard = global_style_data.shared_lock.read();
6157     let guard = declarations.read_with(&guard);
6158     let iter = guard.to_animation_value_iter(
6159         &mut context,
6160         &default_values,
6161         None, // SMIL has no extra custom properties.
6162     );
6163     animation_values.extend(iter.map(|v| structs::RefPtr::from_arc(Arc::new(v))));
6166 #[no_mangle]
6167 pub extern "C" fn Servo_AnimationValue_GetPropertyId(value: &AnimationValue) -> nsCSSPropertyID {
6168     value.id().to_nscsspropertyid()
6171 #[no_mangle]
6172 pub extern "C" fn Servo_AnimationValue_Compute(
6173     element: &RawGeckoElement,
6174     declarations: &LockedDeclarationBlock,
6175     style: &ComputedValues,
6176     raw_data: &PerDocumentStyleData,
6177 ) -> Strong<AnimationValue> {
6178     let data = raw_data.borrow();
6180     let element = GeckoElement(element);
6181     let parent_element = element.inheritance_parent();
6182     let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6183     let parent_style = parent_data
6184         .as_ref()
6185         .map(|d| d.styles.primary())
6186         .map(|x| &**x);
6188     let container_size_query = ContainerSizeQuery::for_element(element, None);
6189     let mut conditions = Default::default();
6190     let mut context = create_context_for_animation(
6191         &data,
6192         style,
6193         parent_style,
6194         /* for_smil_animation = */ false,
6195         &mut conditions,
6196         container_size_query,
6197     );
6199     let default_values = data.default_computed_values();
6200     let global_style_data = &*GLOBAL_STYLE_DATA;
6201     let guard = global_style_data.shared_lock.read();
6202     // We only compute the first element in declarations.
6203     match declarations
6204         .read_with(&guard)
6205         .declaration_importance_iter()
6206         .next()
6207     {
6208         Some((decl, imp)) if imp == Importance::Normal => {
6209             let animation = AnimationValue::from_declaration(
6210                 decl,
6211                 &mut context,
6212                 None, // No extra custom properties for devtools.
6213                 default_values,
6214             );
6215             animation.map_or(Strong::null(), |value| Arc::new(value).into())
6216         },
6217         _ => Strong::null(),
6218     }
6221 #[no_mangle]
6222 pub extern "C" fn Servo_AssertTreeIsClean(root: &RawGeckoElement) {
6223     if !cfg!(feature = "gecko_debug") {
6224         panic!("Calling Servo_AssertTreeIsClean in release build");
6225     }
6227     let root = GeckoElement(root);
6228     debug!("Servo_AssertTreeIsClean: ");
6229     debug!("{:?}", ShowSubtreeData(root.as_node()));
6231     fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) {
6232         debug_assert!(
6233             !el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants(),
6234             "{:?} has still dirty bit {:?} or animation-only dirty bit {:?}",
6235             el,
6236             el.has_dirty_descendants(),
6237             el.has_animation_only_dirty_descendants()
6238         );
6239         for child in el.traversal_children() {
6240             if let Some(child) = child.as_element() {
6241                 assert_subtree_is_clean(child);
6242             }
6243         }
6244     }
6246     assert_subtree_is_clean(root);
6249 #[no_mangle]
6250 pub extern "C" fn Servo_IsWorkerThread() -> bool {
6251     thread_state::get().is_worker()
6254 enum Offset {
6255     Zero,
6256     One,
6259 fn fill_in_missing_keyframe_values(
6260     all_properties: &LonghandIdSet,
6261     timing_function: &ComputedTimingFunction,
6262     longhands_at_offset: &LonghandIdSet,
6263     offset: Offset,
6264     keyframes: &mut nsTArray<structs::Keyframe>,
6265 ) {
6266     // Return early if all animated properties are already set.
6267     if longhands_at_offset.contains_all(all_properties) {
6268         return;
6269     }
6271     // Use auto for missing keyframes.
6272     // FIXME: This may be a spec issue in css-animations-2 because the spec says the default
6273     // keyframe-specific composite is replace, but web-animations-1 uses auto. Use auto now so we
6274     // use the value of animation-composition of the element, for missing keyframes.
6275     // https://github.com/w3c/csswg-drafts/issues/7476
6276     let composition = structs::CompositeOperationOrAuto::Auto;
6277     let keyframe = match offset {
6278         Offset::Zero => unsafe {
6279             Gecko_GetOrCreateInitialKeyframe(keyframes, timing_function, composition)
6280         },
6281         Offset::One => unsafe {
6282             Gecko_GetOrCreateFinalKeyframe(keyframes, timing_function, composition)
6283         },
6284     };
6286     // Append properties that have not been set at this offset.
6287     for property in all_properties.iter() {
6288         if !longhands_at_offset.contains(property) {
6289             unsafe {
6290                 Gecko_AppendPropertyValuePair(
6291                     &mut *(*keyframe).mPropertyValues,
6292                     property.to_nscsspropertyid(),
6293                 );
6294             }
6295         }
6296     }
6299 #[no_mangle]
6300 pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
6301     raw_data: &PerDocumentStyleData,
6302     element: &RawGeckoElement,
6303     style: &ComputedValues,
6304     name: *mut nsAtom,
6305     inherited_timing_function: &ComputedTimingFunction,
6306     keyframes: &mut nsTArray<structs::Keyframe>,
6307 ) -> bool {
6308     use style::gecko_bindings::structs::CompositeOperationOrAuto;
6309     use style::properties::longhands::animation_composition::single_value::computed_value::T as Composition;
6311     debug_assert!(keyframes.len() == 0, "keyframes should be initially empty");
6313     let element = GeckoElement(element);
6314     let data = raw_data.borrow();
6315     let name = Atom::from_raw(name);
6317     let animation = match data.stylist.get_animation(&name, element) {
6318         Some(animation) => animation,
6319         None => return false,
6320     };
6322     let global_style_data = &*GLOBAL_STYLE_DATA;
6323     let guard = global_style_data.shared_lock.read();
6325     let mut properties_set_at_current_offset = LonghandIdSet::new();
6326     let mut properties_set_at_start = LonghandIdSet::new();
6327     let mut properties_set_at_end = LonghandIdSet::new();
6328     let mut has_complete_initial_keyframe = false;
6329     let mut has_complete_final_keyframe = false;
6330     let mut current_offset = -1.;
6332     let writing_mode = style.writing_mode;
6334     // Iterate over the keyframe rules backwards so we can drop overridden
6335     // properties (since declarations in later rules override those in earlier
6336     // ones).
6337     for step in animation.steps.iter().rev() {
6338         if step.start_percentage.0 != current_offset {
6339             properties_set_at_current_offset.clear();
6340             current_offset = step.start_percentage.0;
6341         }
6343         // Override timing_function if the keyframe has an animation-timing-function.
6344         let timing_function = match step.get_animation_timing_function(&guard) {
6345             Some(val) => val.to_computed_value_without_context(),
6346             None => (*inherited_timing_function).clone(),
6347         };
6349         // Override composite operation if the keyframe has an animation-composition.
6350         let composition =
6351             step.get_animation_composition(&guard)
6352                 .map_or(CompositeOperationOrAuto::Auto, |val| match val {
6353                     Composition::Replace => CompositeOperationOrAuto::Replace,
6354                     Composition::Add => CompositeOperationOrAuto::Add,
6355                     Composition::Accumulate => CompositeOperationOrAuto::Accumulate,
6356                 });
6358         // Look for an existing keyframe with the same offset, timing function, and compsition, or
6359         // else add a new keyframe at the beginning of the keyframe array.
6360         let keyframe = Gecko_GetOrCreateKeyframeAtStart(
6361             keyframes,
6362             step.start_percentage.0 as f32,
6363             &timing_function,
6364             composition,
6365         );
6367         match step.value {
6368             KeyframesStepValue::ComputedValues => {
6369                 // In KeyframesAnimation::from_keyframes if there is no 0% or
6370                 // 100% keyframe at all, we will create a 'ComputedValues' step
6371                 // to represent that all properties animated by the keyframes
6372                 // animation should be set to the underlying computed value for
6373                 // that keyframe.
6374                 let mut seen = LonghandIdSet::new();
6375                 for property in animation.properties_changed.iter() {
6376                     let property = property.to_physical(writing_mode);
6377                     if seen.contains(property) {
6378                         continue;
6379                     }
6380                     seen.insert(property);
6382                     Gecko_AppendPropertyValuePair(
6383                         &mut *(*keyframe).mPropertyValues,
6384                         property.to_nscsspropertyid(),
6385                     );
6386                 }
6387                 if current_offset == 0.0 {
6388                     has_complete_initial_keyframe = true;
6389                 } else if current_offset == 1.0 {
6390                     has_complete_final_keyframe = true;
6391                 }
6392             },
6393             KeyframesStepValue::Declarations { ref block } => {
6394                 let guard = block.read_with(&guard);
6396                 let mut custom_properties = PropertyDeclarationBlock::new();
6398                 // Filter out non-animatable properties and properties with
6399                 // !important.
6400                 //
6401                 // Also, iterate in reverse to respect the source order in case
6402                 // there are logical and physical longhands in the same block.
6403                 for declaration in guard.normal_declaration_iter().rev() {
6404                     let id = declaration.id();
6406                     let id = match id {
6407                         PropertyDeclarationId::Longhand(id) => {
6408                             // Skip the 'display' property because although it
6409                             // is animatable from SMIL, it should not be
6410                             // animatable from CSS Animations.
6411                             if id == LonghandId::Display {
6412                                 continue;
6413                             }
6415                             if !id.is_animatable() {
6416                                 continue;
6417                             }
6419                             id.to_physical(writing_mode)
6420                         },
6421                         PropertyDeclarationId::Custom(..) => {
6422                             custom_properties.push(declaration.clone(), Importance::Normal);
6423                             continue;
6424                         },
6425                     };
6427                     if properties_set_at_current_offset.contains(id) {
6428                         continue;
6429                     }
6431                     let pair = Gecko_AppendPropertyValuePair(
6432                         &mut *(*keyframe).mPropertyValues,
6433                         id.to_nscsspropertyid(),
6434                     );
6436                     (*pair).mServoDeclarationBlock.set_arc(Arc::new(
6437                         global_style_data
6438                             .shared_lock
6439                             .wrap(PropertyDeclarationBlock::with_one(
6440                                 declaration.to_physical(writing_mode),
6441                                 Importance::Normal,
6442                             )),
6443                     ));
6445                     if current_offset == 0.0 {
6446                         properties_set_at_start.insert(id);
6447                     } else if current_offset == 1.0 {
6448                         properties_set_at_end.insert(id);
6449                     }
6450                     properties_set_at_current_offset.insert(id);
6451                 }
6453                 if custom_properties.any_normal() {
6454                     let pair = Gecko_AppendPropertyValuePair(
6455                         &mut *(*keyframe).mPropertyValues,
6456                         nsCSSPropertyID::eCSSPropertyExtra_variable,
6457                     );
6459                     (*pair).mServoDeclarationBlock.set_arc(Arc::new(
6460                         global_style_data.shared_lock.wrap(custom_properties),
6461                     ));
6462                 }
6463             },
6464         }
6465     }
6467     let mut properties_changed = LonghandIdSet::new();
6468     for property in animation.properties_changed.iter() {
6469         properties_changed.insert(property.to_physical(writing_mode));
6470     }
6472     // Append property values that are missing in the initial or the final keyframes.
6473     if !has_complete_initial_keyframe {
6474         fill_in_missing_keyframe_values(
6475             &properties_changed,
6476             inherited_timing_function,
6477             &properties_set_at_start,
6478             Offset::Zero,
6479             keyframes,
6480         );
6481     }
6482     if !has_complete_final_keyframe {
6483         fill_in_missing_keyframe_values(
6484             &properties_changed,
6485             inherited_timing_function,
6486             &properties_set_at_end,
6487             Offset::One,
6488             keyframes,
6489         );
6490     }
6491     true
6494 #[no_mangle]
6495 pub extern "C" fn Servo_StyleSet_GetFontFaceRules(
6496     raw_data: &PerDocumentStyleData,
6497     rules: &mut ThinVec<structs::nsFontFaceRuleContainer>,
6498 ) {
6499     let data = raw_data.borrow();
6500     debug_assert_eq!(rules.len(), 0);
6502     // Reversed iterator because Gecko expects rules to appear sorted
6503     // UserAgent first, Author last.
6504     let font_face_iter = data
6505         .stylist
6506         .iter_extra_data_origins_rev()
6507         .flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o)));
6509     rules.extend(font_face_iter.map(|(&(ref rule, _layer_id), origin)| {
6510         structs::nsFontFaceRuleContainer {
6511             mRule: structs::RefPtr::from_arc(rule.clone()),
6512             mOrigin: origin,
6513         }
6514     }))
6517 // XXX Ideally this should return a Option<&LockedCounterStyleRule>,
6518 // but we cannot, because the value from AtomicRefCell::borrow() can only
6519 // live in this function, and thus anything derived from it cannot get the
6520 // same lifetime as raw_data in parameter. See bug 1451543.
6521 #[no_mangle]
6522 pub unsafe extern "C" fn Servo_StyleSet_GetCounterStyleRule(
6523     raw_data: &PerDocumentStyleData,
6524     name: *mut nsAtom,
6525 ) -> *const LockedCounterStyleRule {
6526     let data = raw_data.borrow();
6527     Atom::with(name, |name| {
6528         data.stylist
6529             .iter_extra_data_origins()
6530             .find_map(|(d, _)| d.counter_styles.get(name))
6531             .map_or(ptr::null(), |rule| &**rule as *const _)
6532     })
6535 #[no_mangle]
6536 pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet(
6537     raw_data: &PerDocumentStyleData,
6538 ) -> *mut gfxFontFeatureValueSet {
6539     let data = raw_data.borrow();
6541     let has_rule = data
6542         .stylist
6543         .iter_extra_data_origins()
6544         .any(|(d, _)| !d.font_feature_values.is_empty());
6546     if !has_rule {
6547         return ptr::null_mut();
6548     }
6550     let font_feature_values_iter = data
6551         .stylist
6552         .iter_extra_data_origins_rev()
6553         .flat_map(|(d, _)| d.font_feature_values.iter());
6555     let set = unsafe { Gecko_ConstructFontFeatureValueSet() };
6556     for &(ref rule, _) in font_feature_values_iter {
6557         rule.set_at_rules(set);
6558     }
6559     set
6562 #[no_mangle]
6563 pub extern "C" fn Servo_StyleSet_BuildFontPaletteValueSet(
6564     raw_data: &PerDocumentStyleData,
6565 ) -> *mut FontPaletteValueSet {
6566     let data = raw_data.borrow();
6568     let has_rule = data
6569         .stylist
6570         .iter_extra_data_origins()
6571         .any(|(d, _)| !d.font_palette_values.is_empty());
6573     if !has_rule {
6574         return ptr::null_mut();
6575     }
6577     let font_palette_values_iter = data
6578         .stylist
6579         .iter_extra_data_origins_rev()
6580         .flat_map(|(d, _)| d.font_palette_values.iter());
6582     let set = unsafe { Gecko_ConstructFontPaletteValueSet() };
6583     for &(ref rule, _) in font_palette_values_iter {
6584         rule.to_gecko_palette_value_set(set);
6585     }
6586     set
6589 #[no_mangle]
6590 pub extern "C" fn Servo_StyleSet_ResolveForDeclarations(
6591     raw_data: &PerDocumentStyleData,
6592     parent_style_context: Option<&ComputedValues>,
6593     declarations: &LockedDeclarationBlock,
6594 ) -> Strong<ComputedValues> {
6595     let doc_data = raw_data.borrow();
6596     let global_style_data = &*GLOBAL_STYLE_DATA;
6597     let guard = global_style_data.shared_lock.read();
6598     let guards = StylesheetGuards::same(&guard);
6600     let parent_style = match parent_style_context {
6601         Some(parent) => &*parent,
6602         None => doc_data.default_computed_values(),
6603     };
6605     doc_data
6606         .stylist
6607         .compute_for_declarations::<GeckoElement>(&guards, parent_style, unsafe {
6608             Arc::from_raw_addrefed(declarations)
6609         })
6610         .into()
6613 #[no_mangle]
6614 pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis(
6615     malloc_size_of: GeckoMallocSizeOf,
6616     malloc_enclosing_size_of: GeckoMallocSizeOf,
6617     sizes: *mut ServoStyleSetSizes,
6618     raw_data: &PerDocumentStyleData,
6619 ) {
6620     let data = raw_data.borrow_mut();
6621     let mut ops = MallocSizeOfOps::new(
6622         malloc_size_of.unwrap(),
6623         Some(malloc_enclosing_size_of.unwrap()),
6624         None,
6625     );
6626     let sizes = unsafe { sizes.as_mut() }.unwrap();
6627     data.add_size_of(&mut ops, sizes);
6630 #[no_mangle]
6631 pub extern "C" fn Servo_UACache_AddSizeOf(
6632     malloc_size_of: GeckoMallocSizeOf,
6633     malloc_enclosing_size_of: GeckoMallocSizeOf,
6634     sizes: *mut ServoStyleSetSizes,
6635 ) {
6636     let mut ops = MallocSizeOfOps::new(
6637         malloc_size_of.unwrap(),
6638         Some(malloc_enclosing_size_of.unwrap()),
6639         None,
6640     );
6641     let sizes = unsafe { sizes.as_mut() }.unwrap();
6642     add_size_of_ua_cache(&mut ops, sizes);
6645 #[no_mangle]
6646 pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
6647     raw_data: &PerDocumentStyleData,
6648     element: &RawGeckoElement,
6649     local_name: *mut nsAtom,
6650 ) -> bool {
6651     let data = raw_data.borrow();
6652     let element = GeckoElement(element);
6654     unsafe {
6655         AtomIdent::with(local_name, |atom| {
6656             data.stylist.any_applicable_rule_data(element, |data| {
6657                 data.might_have_attribute_dependency(atom)
6658             })
6659         })
6660     }
6663 #[no_mangle]
6664 pub extern "C" fn Servo_StyleSet_MightHaveNthOfIDDependency(
6665     raw_data: &PerDocumentStyleData,
6666     element: &RawGeckoElement,
6667     old_id: *mut nsAtom,
6668     new_id: *mut nsAtom,
6669 ) -> bool {
6670     let data = raw_data.borrow();
6671     let element = GeckoElement(element);
6673     data.stylist.any_applicable_rule_data(element, |data| {
6674         [old_id, new_id]
6675             .iter()
6676             .filter(|id| !id.is_null())
6677             .any(|id| unsafe {
6678                 AtomIdent::with(*id, |atom| data.might_have_nth_of_id_dependency(atom))
6679             }) ||
6680             data.might_have_nth_of_attribute_dependency(&AtomIdent(atom!("id")))
6681     })
6684 #[no_mangle]
6685 pub extern "C" fn Servo_StyleSet_MightHaveNthOfClassDependency(
6686     raw_data: &PerDocumentStyleData,
6687     element: &RawGeckoElement,
6688     snapshots: &ServoElementSnapshotTable,
6689 ) -> bool {
6690     let data = raw_data.borrow();
6691     let element = GeckoElement(element);
6693     data.stylist.any_applicable_rule_data(element, |data| {
6694         classes_changed(&element, snapshots)
6695             .iter()
6696             .any(|atom| data.might_have_nth_of_class_dependency(atom)) ||
6697             data.might_have_nth_of_attribute_dependency(&AtomIdent(atom!("class")))
6698     })
6701 #[no_mangle]
6702 pub extern "C" fn Servo_StyleSet_MightHaveNthOfAttributeDependency(
6703     raw_data: &PerDocumentStyleData,
6704     element: &RawGeckoElement,
6705     local_name: *mut nsAtom,
6706 ) -> bool {
6707     let data = raw_data.borrow();
6708     let element = GeckoElement(element);
6710     unsafe {
6711         AtomIdent::with(local_name, |atom| {
6712             data.stylist.any_applicable_rule_data(element, |data| {
6713                 data.might_have_nth_of_attribute_dependency(atom)
6714             })
6715         })
6716     }
6719 #[no_mangle]
6720 pub extern "C" fn Servo_StyleSet_HasStateDependency(
6721     raw_data: &PerDocumentStyleData,
6722     element: &RawGeckoElement,
6723     state: u64,
6724 ) -> bool {
6725     let element = GeckoElement(element);
6727     let state = ElementState::from_bits_truncate(state);
6728     let data = raw_data.borrow();
6730     data.stylist
6731         .any_applicable_rule_data(element, |data| data.has_state_dependency(state))
6734 #[no_mangle]
6735 pub extern "C" fn Servo_StyleSet_HasNthOfStateDependency(
6736     raw_data: &PerDocumentStyleData,
6737     element: &RawGeckoElement,
6738     state: u64,
6739 ) -> bool {
6740     let element = GeckoElement(element);
6742     let state = ElementState::from_bits_truncate(state);
6743     let data = raw_data.borrow();
6745     data.stylist
6746         .any_applicable_rule_data(element, |data| data.has_nth_of_state_dependency(state))
6749 #[no_mangle]
6750 pub extern "C" fn Servo_StyleSet_HasDocumentStateDependency(
6751     raw_data: &PerDocumentStyleData,
6752     state: u64,
6753 ) -> bool {
6754     let state = DocumentState::from_bits_truncate(state);
6755     let data = raw_data.borrow();
6757     data.stylist.has_document_state_dependency(state)
6760 fn computed_or_resolved_value(
6761     style: &ComputedValues,
6762     prop: nsCSSPropertyID,
6763     context: Option<&style::values::resolved::Context>,
6764     value: &mut nsACString,
6765 ) {
6766     if let Ok(longhand) = LonghandId::from_nscsspropertyid(prop) {
6767         return style
6768             .computed_or_resolved_value(longhand, context, value)
6769             .unwrap();
6770     }
6772     let shorthand =
6773         ShorthandId::from_nscsspropertyid(prop).expect("Not a shorthand nor a longhand?");
6774     let mut block = PropertyDeclarationBlock::new();
6775     for longhand in shorthand.longhands() {
6776         block.push(
6777             style.computed_or_resolved_declaration(longhand, context),
6778             Importance::Normal,
6779         );
6780     }
6781     block.shorthand_to_css(shorthand, value).unwrap();
6784 #[no_mangle]
6785 pub unsafe extern "C" fn Servo_GetComputedValue(
6786     style: &ComputedValues,
6787     prop: nsCSSPropertyID,
6788     value: &mut nsACString,
6789 ) {
6790     computed_or_resolved_value(style, prop, None, value)
6793 #[no_mangle]
6794 pub unsafe extern "C" fn Servo_GetResolvedValue(
6795     style: &ComputedValues,
6796     prop: nsCSSPropertyID,
6797     raw_data: &PerDocumentStyleData,
6798     element: &RawGeckoElement,
6799     value: &mut nsACString,
6800 ) {
6801     use style::values::resolved;
6803     let data = raw_data.borrow();
6804     let device = data.stylist.device();
6805     let context = resolved::Context {
6806         style,
6807         device,
6808         element_info: resolved::ResolvedElementInfo {
6809             element: GeckoElement(element),
6810         },
6811     };
6813     computed_or_resolved_value(style, prop, Some(&context), value)
6816 #[no_mangle]
6817 pub unsafe extern "C" fn Servo_GetCustomPropertyValue(
6818     computed_values: &ComputedValues,
6819     name: &nsACString,
6820     value: &mut nsACString,
6821 ) -> bool {
6822     let custom_properties = match computed_values.custom_properties() {
6823         Some(p) => p,
6824         None => return false,
6825     };
6827     let name = Atom::from(name.as_str_unchecked());
6828     let computed_value = match custom_properties.get(&name) {
6829         Some(v) => v,
6830         None => return false,
6831     };
6833     computed_value.to_css(&mut CssWriter::new(value)).unwrap();
6834     true
6837 #[no_mangle]
6838 pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u32 {
6839     match computed_values.custom_properties() {
6840         Some(p) => p.len() as u32,
6841         None => 0,
6842     }
6845 #[no_mangle]
6846 pub extern "C" fn Servo_GetCustomPropertyNameAt(
6847     computed_values: &ComputedValues,
6848     index: u32,
6849 ) -> *mut nsAtom {
6850     let custom_properties = match computed_values.custom_properties() {
6851         Some(p) => p,
6852         None => return ptr::null_mut(),
6853     };
6855     let property_name = match custom_properties.get_index(index as usize) {
6856         Some((key, _value)) => key,
6857         None => return ptr::null_mut(),
6858     };
6860     property_name.as_ptr()
6863 #[no_mangle]
6864 pub extern "C" fn Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool {
6865     url.is_fragment()
6868 #[no_mangle]
6869 pub extern "C" fn Servo_ProcessInvalidations(
6870     set: &PerDocumentStyleData,
6871     element: &RawGeckoElement,
6872     snapshots: *const ServoElementSnapshotTable,
6873 ) {
6874     debug_assert!(!snapshots.is_null());
6876     let element = GeckoElement(element);
6877     debug_assert!(element.has_snapshot());
6878     debug_assert!(!element.handled_snapshot());
6880     let mut data = element.mutate_data();
6881     debug_assert!(data.is_some());
6883     let global_style_data = &*GLOBAL_STYLE_DATA;
6884     let guard = global_style_data.shared_lock.read();
6885     let per_doc_data = set.borrow();
6886     let shared_style_context = create_shared_context(
6887         &global_style_data,
6888         &guard,
6889         &per_doc_data.stylist,
6890         TraversalFlags::empty(),
6891         unsafe { &*snapshots },
6892     );
6893     let mut data = data.as_mut().map(|d| &mut **d);
6895     let mut selector_caches = SelectorCaches::default();
6896     if let Some(ref mut data) = data {
6897         // FIXME(emilio): Ideally we could share the nth-index-cache across all
6898         // the elements?
6899         let result = data.invalidate_style_if_needed(
6900             element,
6901             &shared_style_context,
6902             None,
6903             &mut selector_caches,
6904         );
6906         if result.has_invalidated_siblings() {
6907             let parent = element
6908                 .traversal_parent()
6909                 .expect("How could we invalidate siblings without a common parent?");
6910             unsafe {
6911                 parent.set_dirty_descendants();
6912                 bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0);
6913             }
6914         } else if result.has_invalidated_descendants() {
6915             unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) };
6916         } else if result.has_invalidated_self() {
6917             unsafe { bindings::Gecko_NoteDirtyElement(element.0) };
6918         }
6919     }
6922 #[no_mangle]
6923 pub extern "C" fn Servo_HasPendingRestyleAncestor(
6924     element: &RawGeckoElement,
6925     may_need_to_flush_layout: bool,
6926 ) -> bool {
6927     let mut has_yet_to_be_styled = false;
6928     let mut element = Some(GeckoElement(element));
6929     while let Some(e) = element {
6930         if e.has_any_animation() {
6931             return true;
6932         }
6934         // If the element needs a frame, it means that we haven't styled it yet
6935         // after it got inserted in the document, and thus we may need to do
6936         // that for transitions and animations to trigger.
6937         //
6938         // This is a fast path in the common case, but `has_yet_to_be_styled` is
6939         // the real check for this.
6940         if e.needs_frame() {
6941             return true;
6942         }
6944         let data = e.borrow_data();
6945         if let Some(ref data) = data {
6946             if !data.hint.is_empty() {
6947                 return true;
6948             }
6949             if has_yet_to_be_styled && !data.styles.is_display_none() {
6950                 return true;
6951             }
6952             // Ideally, DOM mutations wouldn't affect layout trees of siblings.
6953             //
6954             // In practice, this can happen because Gecko deals pretty badly
6955             // with some kinds of content insertion and removals.
6956             //
6957             // If we may need to flush layout, we need frames to accurately
6958             // determine whether we'll actually flush, so if we have to
6959             // reconstruct we need to flush style, which is what will take care
6960             // of ensuring that frames are constructed, even if the style itself
6961             // is up-to-date.
6962             if may_need_to_flush_layout && data.damage.contains(GeckoRestyleDamage::reconstruct()) {
6963                 return true;
6964             }
6965         }
6966         has_yet_to_be_styled = data.is_none();
6968         element = e.traversal_parent();
6969     }
6970     false
6973 #[no_mangle]
6974 pub unsafe extern "C" fn Servo_SelectorList_Parse(
6975     selector_list: &nsACString,
6976     is_chrome: bool,
6977 ) -> *mut SelectorList {
6978     use style::selector_parser::SelectorParser;
6980     let url_data = UrlExtraData::from_ptr_ref(if is_chrome {
6981         &DUMMY_CHROME_URL_DATA
6982     } else {
6983         &DUMMY_URL_DATA
6984     });
6986     let input = selector_list.as_str_unchecked();
6987     let selector_list = match SelectorParser::parse_author_origin_no_namespace(&input, url_data) {
6988         Ok(selector_list) => selector_list,
6989         Err(..) => return ptr::null_mut(),
6990     };
6992     Box::into_raw(Box::new(selector_list))
6995 #[no_mangle]
6996 pub unsafe extern "C" fn Servo_SelectorList_Drop(list: *mut SelectorList) {
6997     let _ = Box::from_raw(list);
7000 #[no_mangle]
7001 pub unsafe extern "C" fn Servo_IsValidCSSColor(value: &nsACString) -> bool {
7002     let mut input = ParserInput::new(value.as_str_unchecked());
7003     let mut input = Parser::new(&mut input);
7004     let context = ParserContext::new(
7005         Origin::Author,
7006         dummy_url_data(),
7007         Some(CssRuleType::Style),
7008         ParsingMode::DEFAULT,
7009         QuirksMode::NoQuirks,
7010         /* namespaces = */ Default::default(),
7011         None,
7012         None,
7013     );
7014     specified::Color::is_valid(&context, &mut input)
7017 #[no_mangle]
7018 pub unsafe extern "C" fn Servo_ComputeColor(
7019     raw_data: Option<&PerDocumentStyleData>,
7020     current_color: structs::nscolor,
7021     value: &nsACString,
7022     result_color: &mut structs::nscolor,
7023     was_current_color: *mut bool,
7024     loader: *mut Loader,
7025 ) -> bool {
7026     let mut input = ParserInput::new(value.as_str_unchecked());
7027     let mut input = Parser::new(&mut input);
7028     let reporter = loader.as_mut().and_then(|loader| {
7029         // Make an ErrorReporter that will report errors as being "from DOM".
7030         ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut())
7031     });
7033     let context = ParserContext::new(
7034         Origin::Author,
7035         dummy_url_data(),
7036         Some(CssRuleType::Style),
7037         ParsingMode::DEFAULT,
7038         QuirksMode::NoQuirks,
7039         /* namespaces = */ Default::default(),
7040         reporter.as_ref().map(|e| e as &dyn ParseErrorReporter),
7041         None,
7042     );
7044     let data;
7045     let device = match raw_data {
7046         Some(d) => {
7047             data = d.borrow();
7048             Some(data.stylist.device())
7049         },
7050         None => None,
7051     };
7053     let computed = match specified::Color::parse_and_compute(&context, &mut input, device) {
7054         Some(c) => c,
7055         None => return false,
7056     };
7058     let current_color = style::gecko::values::convert_nscolor_to_absolute_color(current_color);
7059     if !was_current_color.is_null() {
7060         *was_current_color = computed.is_currentcolor();
7061     }
7063     let rgba = computed.resolve_to_absolute(&current_color);
7064     *result_color = style::gecko::values::convert_absolute_color_to_nscolor(&rgba);
7065     true
7068 #[no_mangle]
7069 pub extern "C" fn Servo_ResolveColor(
7070     color: &computed::Color,
7071     foreground: &style::color::AbsoluteColor,
7072 ) -> style::color::AbsoluteColor {
7073     color.resolve_to_absolute(foreground)
7076 #[no_mangle]
7077 pub extern "C" fn Servo_ResolveCalcLengthPercentage(
7078     calc: &computed::length_percentage::CalcLengthPercentage,
7079     basis: f32,
7080 ) -> f32 {
7081     calc.resolve(computed::Length::new(basis)).px()
7084 #[no_mangle]
7085 pub extern "C" fn Servo_ConvertColorSpace(
7086     color: &AbsoluteColor,
7087     color_space: ColorSpace,
7088 ) -> AbsoluteColor {
7089     color.to_color_space(color_space)
7092 #[no_mangle]
7093 pub unsafe extern "C" fn Servo_IntersectionObserverRootMargin_Parse(
7094     value: &nsACString,
7095     result: *mut IntersectionObserverRootMargin,
7096 ) -> bool {
7097     let value = value.as_str_unchecked();
7098     let result = result.as_mut().unwrap();
7100     let mut input = ParserInput::new(&value);
7101     let mut parser = Parser::new(&mut input);
7103     let url_data = dummy_url_data();
7104     let context = ParserContext::new(
7105         Origin::Author,
7106         url_data,
7107         Some(CssRuleType::Style),
7108         ParsingMode::DEFAULT,
7109         QuirksMode::NoQuirks,
7110         /* namespaces = */ Default::default(),
7111         None,
7112         None,
7113     );
7115     let margin = parser.parse_entirely(|p| IntersectionObserverRootMargin::parse(&context, p));
7116     match margin {
7117         Ok(margin) => {
7118             *result = margin;
7119             true
7120         },
7121         Err(..) => false,
7122     }
7125 #[no_mangle]
7126 pub extern "C" fn Servo_IntersectionObserverRootMargin_ToString(
7127     root_margin: &IntersectionObserverRootMargin,
7128     result: &mut nsACString,
7129 ) {
7130     let mut writer = CssWriter::new(result);
7131     root_margin.to_css(&mut writer).unwrap();
7134 #[no_mangle]
7135 pub extern "C" fn Servo_ParseTransformIntoMatrix(
7136     value: &nsACString,
7137     contain_3d: &mut bool,
7138     result: &mut structs::Matrix4x4Components,
7139 ) -> bool {
7140     use style::properties::longhands::transform;
7142     let string = unsafe { value.as_str_unchecked() };
7143     let mut input = ParserInput::new(&string);
7144     let mut parser = Parser::new(&mut input);
7145     let context = ParserContext::new(
7146         Origin::Author,
7147         unsafe { dummy_url_data() },
7148         Some(CssRuleType::Style),
7149         ParsingMode::DEFAULT,
7150         QuirksMode::NoQuirks,
7151         /* namespaces = */ Default::default(),
7152         None,
7153         None,
7154     );
7156     let transform = match parser.parse_entirely(|t| transform::parse(&context, t)) {
7157         Ok(t) => t,
7158         Err(..) => return false,
7159     };
7161     let (m, is_3d) = match transform.to_transform_3d_matrix(None) {
7162         Ok(result) => result,
7163         Err(..) => return false,
7164     };
7166     *result = m.to_array();
7167     *contain_3d = is_3d;
7168     true
7171 #[no_mangle]
7172 pub extern "C" fn Servo_ParseFilters(
7173     value: &nsACString,
7174     ignore_urls: bool,
7175     data: *mut URLExtraData,
7176     out: &mut style::OwnedSlice<Filter>,
7177 ) -> bool {
7178     use style::values::specified::effects::SpecifiedFilter;
7180     let string = unsafe { value.as_str_unchecked() };
7181     let mut input = ParserInput::new(&string);
7182     let mut parser = Parser::new(&mut input);
7183     let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
7184     let context = ParserContext::new(
7185         Origin::Author,
7186         url_data,
7187         None,
7188         ParsingMode::DEFAULT,
7189         QuirksMode::NoQuirks,
7190         /* namespaces = */ Default::default(),
7191         None,
7192         None,
7193     );
7195     let mut filters = vec![];
7197     if parser.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
7198         return parser.expect_exhausted().is_ok();
7199     }
7201     if parser.is_exhausted() {
7202         return false;
7203     }
7205     while !parser.is_exhausted() {
7206         let specified_filter = match SpecifiedFilter::parse(&context, &mut parser) {
7207             Ok(f) => f,
7208             Err(..) => return false,
7209         };
7211         let filter = match specified_filter.to_computed_value_without_context() {
7212             Ok(f) => f,
7213             Err(..) => return false,
7214         };
7216         if ignore_urls && matches!(filter, Filter::Url(_)) {
7217             continue;
7218         }
7220         filters.push(filter);
7221     }
7223     *out = style::OwnedSlice::from(filters);
7224     true
7227 #[no_mangle]
7228 pub unsafe extern "C" fn Servo_ParseFontShorthandForMatching(
7229     value: &nsACString,
7230     data: *mut URLExtraData,
7231     family: &mut FontFamilyList,
7232     style: &mut FontStyle,
7233     stretch: &mut FontStretch,
7234     weight: &mut FontWeight,
7235     size: Option<&mut f32>,
7236     small_caps: Option<&mut bool>,
7237 ) -> bool {
7238     use style::properties::shorthands::font;
7239     use style::values::generics::font::FontStyle as GenericFontStyle;
7240     use style::values::specified::font as specified;
7242     let string = value.as_str_unchecked();
7243     let mut input = ParserInput::new(&string);
7244     let mut parser = Parser::new(&mut input);
7245     let url_data = UrlExtraData::from_ptr_ref(&data);
7246     let context = ParserContext::new(
7247         Origin::Author,
7248         url_data,
7249         Some(CssRuleType::FontFace),
7250         ParsingMode::DEFAULT,
7251         QuirksMode::NoQuirks,
7252         /* namespaces = */ Default::default(),
7253         None,
7254         None,
7255     );
7257     let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) {
7258         Ok(f) => f,
7259         Err(..) => return false,
7260     };
7262     // The system font is not acceptable, so we return false.
7263     match font.font_family {
7264         specified::FontFamily::Values(list) => *family = list,
7265         specified::FontFamily::System(_) => return false,
7266     }
7268     let specified_font_style = match font.font_style {
7269         specified::FontStyle::Specified(ref s) => s,
7270         specified::FontStyle::System(_) => return false,
7271     };
7273     *style = match *specified_font_style {
7274         GenericFontStyle::Normal => FontStyle::NORMAL,
7275         GenericFontStyle::Italic => FontStyle::ITALIC,
7276         GenericFontStyle::Oblique(ref angle) => FontStyle::oblique(angle.degrees()),
7277     };
7279     *stretch = match font.font_stretch {
7280         specified::FontStretch::Keyword(ref k) => k.compute(),
7281         specified::FontStretch::Stretch(ref p) => FontStretch::from_percentage(p.0.get()),
7282         specified::FontStretch::System(_) => return false,
7283     };
7285     *weight = match font.font_weight {
7286         specified::FontWeight::Absolute(w) => w.compute(),
7287         // Resolve relative font weights against the initial of font-weight
7288         // (normal, which is equivalent to 400).
7289         specified::FontWeight::Bolder => FontWeight::normal().bolder(),
7290         specified::FontWeight::Lighter => FontWeight::normal().lighter(),
7291         specified::FontWeight::System(_) => return false,
7292     };
7294     // XXX This is unfinished; see values::specified::FontSize::ToComputedValue
7295     // for a more complete implementation (but we can't use it as-is).
7296     if let Some(size) = size {
7297         *size = match font.font_size {
7298             specified::FontSize::Length(lp) => {
7299                 use style::values::generics::transform::ToAbsoluteLength;
7300                 match lp.to_pixel_length(None) {
7301                     Ok(len) => len,
7302                     Err(..) => return false,
7303                 }
7304             },
7305             specified::FontSize::Keyword(info) => {
7306                 let keyword = if info.kw != specified::FontSizeKeyword::Math {
7307                   info.kw
7308                 } else {
7309                   specified::FontSizeKeyword::Medium
7310                 };
7311                 // Map absolute-size keywords to sizes.
7312                 // TODO: Maybe get a meaningful quirks / base size from the caller?
7313                 let quirks_mode = QuirksMode::NoQuirks;
7314                 keyword
7315                     .to_length_without_context(
7316                         quirks_mode,
7317                         computed::Length::new(specified::FONT_MEDIUM_PX),
7318                     )
7319                     .0
7320                     .px()
7321             },
7322             // smaller, larger not currently supported
7323             specified::FontSize::Smaller |
7324             specified::FontSize::Larger |
7325             specified::FontSize::System(_) => {
7326                 return false;
7327             },
7328         };
7329     }
7331     if let Some(small_caps) = small_caps {
7332         use style::computed_values::font_variant_caps::T::SmallCaps;
7333         *small_caps = font.font_variant_caps == SmallCaps;
7334     }
7336     true
7339 #[no_mangle]
7340 pub unsafe extern "C" fn Servo_SourceSizeList_Parse(value: &nsACString) -> *mut SourceSizeList {
7341     let value = value.as_str_unchecked();
7342     let mut input = ParserInput::new(value);
7343     let mut parser = Parser::new(&mut input);
7345     let context = ParserContext::new(
7346         Origin::Author,
7347         dummy_url_data(),
7348         Some(CssRuleType::Style),
7349         ParsingMode::DEFAULT,
7350         QuirksMode::NoQuirks,
7351         /* namespaces = */ Default::default(),
7352         None,
7353         None,
7354     );
7356     // NB: Intentionally not calling parse_entirely.
7357     let list = SourceSizeList::parse(&context, &mut parser);
7358     Box::into_raw(Box::new(list))
7361 #[no_mangle]
7362 pub unsafe extern "C" fn Servo_SourceSizeList_Evaluate(
7363     raw_data: &PerDocumentStyleData,
7364     list: Option<&SourceSizeList>,
7365 ) -> i32 {
7366     let doc_data = raw_data.borrow();
7367     let device = doc_data.stylist.device();
7368     let quirks_mode = doc_data.stylist.quirks_mode();
7370     let result = match list {
7371         Some(list) => list.evaluate(device, quirks_mode),
7372         None => SourceSizeList::empty().evaluate(device, quirks_mode),
7373     };
7375     result.0
7378 #[no_mangle]
7379 pub unsafe extern "C" fn Servo_SourceSizeList_Drop(list: *mut SourceSizeList) {
7380     let _ = Box::from_raw(list);
7383 #[no_mangle]
7384 pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges(
7385     root: &RawGeckoElement,
7386     document_style: &PerDocumentStyleData,
7387     non_document_styles: &nsTArray<&AuthorStyles>,
7388     states_changed: u64,
7389 ) {
7390     use style::invalidation::element::document_state::DocumentStateInvalidationProcessor;
7391     use style::invalidation::element::invalidator::TreeStyleInvalidator;
7393     let document_data = document_style.borrow();
7395     let iter = document_data
7396         .stylist
7397         .iter_origins()
7398         .map(|(data, _origin)| data)
7399         .chain(
7400             non_document_styles
7401                 .iter()
7402                 .map(|author_styles| &*author_styles.data),
7403         );
7405     let mut selector_caches = SelectorCaches::default();
7406     let root = GeckoElement(root);
7407     let mut processor = DocumentStateInvalidationProcessor::new(
7408         iter,
7409         DocumentState::from_bits_truncate(states_changed),
7410         &mut selector_caches,
7411         root.as_node().owner_doc().quirks_mode(),
7412     );
7414     let result =
7415         TreeStyleInvalidator::new(root, /* stack_limit_checker = */ None, &mut processor)
7416             .invalidate();
7418     debug_assert!(!result.has_invalidated_siblings(), "How in the world?");
7419     if result.has_invalidated_descendants() {
7420         bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0);
7421     } else if result.has_invalidated_self() {
7422         bindings::Gecko_NoteDirtyElement(root.0);
7423     }
7426 #[no_mangle]
7427 pub unsafe extern "C" fn Servo_PseudoClass_GetStates(name: &nsACString) -> u64 {
7428     let name = name.as_str_unchecked();
7429     match NonTSPseudoClass::parse_non_functional(name) {
7430         None => 0,
7431         // Ignore :any-link since it contains both visited and unvisited state.
7432         Some(NonTSPseudoClass::AnyLink) => 0,
7433         Some(pseudo_class) => pseudo_class.state_flag().bits(),
7434     }
7437 #[no_mangle]
7438 pub unsafe extern "C" fn Servo_UseCounters_Create() -> *mut UseCounters {
7439     Box::into_raw(Box::<UseCounters>::default())
7442 #[no_mangle]
7443 pub unsafe extern "C" fn Servo_UseCounters_Drop(c: *mut UseCounters) {
7444     let _ = Box::from_raw(c);
7447 #[no_mangle]
7448 pub unsafe extern "C" fn Servo_UseCounters_Merge(
7449     doc_counters: &UseCounters,
7450     sheet_counters: &UseCounters,
7451 ) {
7452     doc_counters.merge(sheet_counters)
7455 #[no_mangle]
7456 pub unsafe extern "C" fn Servo_IsPropertyIdRecordedInUseCounter(
7457     use_counters: &UseCounters,
7458     id: nsCSSPropertyID,
7459 ) -> bool {
7460     let id = NonCustomPropertyId::from_nscsspropertyid(id).unwrap();
7461     use_counters.non_custom_properties.recorded(id)
7464 #[no_mangle]
7465 pub unsafe extern "C" fn Servo_IsUnknownPropertyRecordedInUseCounter(
7466     use_counters: &UseCounters,
7467     p: CountedUnknownProperty,
7468 ) -> bool {
7469     use_counters.counted_unknown_properties.recorded(p)
7472 #[no_mangle]
7473 pub unsafe extern "C" fn Servo_IsCssPropertyRecordedInUseCounter(
7474     use_counters: &UseCounters,
7475     property: &nsACString,
7476     known_prop: *mut bool,
7477 ) -> bool {
7478     *known_prop = false;
7480     let prop_name = property.as_str_unchecked();
7481     if let Ok(p) = PropertyId::parse_unchecked_for_testing(prop_name) {
7482         if let Some(id) = p.non_custom_id() {
7483             *known_prop = true;
7484             return use_counters.non_custom_properties.recorded(id);
7485         }
7486     }
7488     if let Some(p) = CountedUnknownProperty::parse_for_testing(prop_name) {
7489         *known_prop = true;
7490         return use_counters.counted_unknown_properties.recorded(p);
7491     }
7493     false
7496 #[no_mangle]
7497 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Create(
7498     buffer: *mut u8,
7499     len: usize,
7500 ) -> *mut SharedMemoryBuilder {
7501     Box::into_raw(Box::new(SharedMemoryBuilder::new(buffer, len)))
7504 #[no_mangle]
7505 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_AddStylesheet(
7506     builder: &mut SharedMemoryBuilder,
7507     contents: &StylesheetContents,
7508     error_message: &mut nsACString,
7509 ) -> *const LockedCssRules {
7510     // Assert some things we assume when we create a style sheet from shared
7511     // memory.
7512     debug_assert_eq!(contents.origin, Origin::UserAgent);
7513     debug_assert_eq!(contents.quirks_mode, QuirksMode::NoQuirks);
7514     debug_assert!(contents.source_map_url.read().is_none());
7515     debug_assert!(contents.source_url.read().is_none());
7517     match builder.write(&contents.rules) {
7518         Ok(rules_ptr) => &**rules_ptr,
7519         Err(message) => {
7520             error_message.assign(&message);
7521             ptr::null()
7522         },
7523     }
7526 #[no_mangle]
7527 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_GetLength(
7528     builder: &SharedMemoryBuilder,
7529 ) -> usize {
7530     builder.len()
7533 #[no_mangle]
7534 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Drop(builder: *mut SharedMemoryBuilder) {
7535     let _ = Box::from_raw(builder);
7538 #[no_mangle]
7539 pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void {
7540     style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr()
7543 #[no_mangle]
7544 pub unsafe extern "C" fn Servo_LoadData_GetLazy(
7545     source: &url::LoadDataSource,
7546 ) -> *const url::LoadData {
7547     source.get()
7550 #[no_mangle]
7551 pub extern "C" fn Servo_LengthPercentage_ToCss(
7552     lp: &computed::LengthPercentage,
7553     result: &mut nsACString,
7554 ) {
7555     lp.to_css(&mut CssWriter::new(result)).unwrap();
7558 #[no_mangle]
7559 pub extern "C" fn Servo_FontStyle_ToCss(s: &FontStyle, result: &mut nsACString) {
7560     s.to_css(&mut CssWriter::new(result)).unwrap()
7563 #[no_mangle]
7564 pub extern "C" fn Servo_FontWeight_ToCss(w: &FontWeight, result: &mut nsACString) {
7565     w.to_css(&mut CssWriter::new(result)).unwrap()
7568 #[no_mangle]
7569 pub extern "C" fn Servo_FontStretch_ToCss(s: &FontStretch, result: &mut nsACString) {
7570     s.to_css(&mut CssWriter::new(result)).unwrap()
7573 #[no_mangle]
7574 pub extern "C" fn Servo_FontStretch_SerializeKeyword(
7575     s: &FontStretch,
7576     result: &mut nsACString,
7577 ) -> bool {
7578     let kw = match s.as_keyword() {
7579         Some(kw) => kw,
7580         None => return false,
7581     };
7582     kw.to_css(&mut CssWriter::new(result)).unwrap();
7583     true
7586 #[no_mangle]
7587 pub unsafe extern "C" fn Servo_CursorKind_Parse(
7588     cursor: &nsACString,
7589     result: &mut computed::ui::CursorKind,
7590 ) -> bool {
7591     match computed::ui::CursorKind::from_ident(cursor.as_str_unchecked()) {
7592         Ok(c) => {
7593             *result = c;
7594             true
7595         },
7596         Err(..) => false,
7597     }
7600 #[no_mangle]
7601 pub extern "C" fn Servo_FontFamily_Generic(generic: GenericFontFamily) -> &'static FontFamily {
7602     FontFamily::generic(generic)
7605 #[no_mangle]
7606 pub extern "C" fn Servo_FontFamily_ForSystemFont(name: &nsACString, out: &mut FontFamily) {
7607     *out = FontFamily::for_system_font(&name.to_utf8());
7610 #[no_mangle]
7611 pub extern "C" fn Servo_FontFamilyList_WithNames(
7612     names: &nsTArray<computed::font::SingleFontFamily>,
7613     out: &mut FontFamilyList,
7614 ) {
7615     *out = FontFamilyList {
7616         list: style_traits::arc_slice::ArcSlice::from_iter(names.iter().cloned()),
7617     };
7620 #[no_mangle]
7621 pub extern "C" fn Servo_FamilyName_Serialize(name: &FamilyName, result: &mut nsACString) {
7622     name.to_css(&mut CssWriter::new(result)).unwrap()
7625 #[no_mangle]
7626 pub extern "C" fn Servo_GenericFontFamily_Parse(input: &nsACString) -> GenericFontFamily {
7627     let context = ParserContext::new(
7628         Origin::Author,
7629         unsafe { dummy_url_data() },
7630         Some(CssRuleType::Style),
7631         ParsingMode::DEFAULT,
7632         QuirksMode::NoQuirks,
7633         /* namespaces = */ Default::default(),
7634         None,
7635         None,
7636     );
7637     let value = input.to_utf8();
7638     let mut input = ParserInput::new(&value);
7639     let mut input = Parser::new(&mut input);
7640     GenericFontFamily::parse(&context, &mut input).unwrap_or(GenericFontFamily::None)
7643 #[no_mangle]
7644 pub extern "C" fn Servo_ColorScheme_Parse(input: &nsACString, out: &mut u8) -> bool {
7645     use style::values::specified::ColorScheme;
7647     let context = ParserContext::new(
7648         Origin::Author,
7649         unsafe { dummy_url_data() },
7650         Some(CssRuleType::Style),
7651         ParsingMode::DEFAULT,
7652         QuirksMode::NoQuirks,
7653         /* namespaces = */ Default::default(),
7654         None,
7655         None,
7656     );
7657     let input = unsafe { input.as_str_unchecked() };
7658     let mut input = ParserInput::new(&input);
7659     let mut input = Parser::new(&mut input);
7660     let scheme = match input.parse_entirely(|i| ColorScheme::parse(&context, i)) {
7661         Ok(scheme) => scheme,
7662         Err(..) => return false,
7663     };
7664     *out = scheme.raw_bits();
7665     true
7668 #[no_mangle]
7669 pub extern "C" fn Servo_LayerBlockRule_GetName(rule: &LayerBlockRule, result: &mut nsACString) {
7670     if let Some(ref name) = rule.name {
7671         name.to_css(&mut CssWriter::new(result)).unwrap()
7672     }
7675 #[no_mangle]
7676 pub extern "C" fn Servo_LayerStatementRule_GetNameCount(rule: &LayerStatementRule) -> usize {
7677     rule.names.len()
7680 #[no_mangle]
7681 pub extern "C" fn Servo_LayerStatementRule_GetNameAt(
7682     rule: &LayerStatementRule,
7683     index: usize,
7684     result: &mut nsACString,
7685 ) {
7686     if let Some(ref name) = rule.names.get(index) {
7687         name.to_css(&mut CssWriter::new(result)).unwrap()
7688     }
7691 #[no_mangle]
7692 pub unsafe extern "C" fn Servo_InvalidateForViewportUnits(
7693     document_style: &PerDocumentStyleData,
7694     root: &RawGeckoElement,
7695     dynamic_only: bool,
7696 ) {
7697     let document_data = document_style.borrow();
7698     let device = document_data.stylist.device();
7700     if !device.used_viewport_size() {
7701         return;
7702     }
7704     if dynamic_only && !device.used_dynamic_viewport_size() {
7705         return;
7706     }
7708     if style::invalidation::viewport_units::invalidate(GeckoElement(root)) {
7709         // The invalidation machinery propagates the bits up, but we still need
7710         // to tell the Gecko restyle root machinery about it.
7711         bindings::Gecko_NoteDirtySubtreeForInvalidation(root);
7712     }
7715 #[no_mangle]
7716 pub extern "C" fn Servo_InterpolateColor(
7717     interpolation: ColorInterpolationMethod,
7718     left: &AbsoluteColor,
7719     right: &AbsoluteColor,
7720     progress: f32,
7721 ) -> AbsoluteColor {
7722     style::color::mix::mix(
7723         interpolation,
7724         left,
7725         progress,
7726         right,
7727         1.0 - progress,
7728         ColorMixFlags::empty(),
7729     )
7732 #[no_mangle]
7733 pub extern "C" fn Servo_EasingFunctionAt(
7734     easing_function: &ComputedTimingFunction,
7735     progress: f64,
7736     before_flag: BeforeFlag,
7737 ) -> f64 {
7738     easing_function.calculate_output(progress, before_flag, 1e-7)
7741 fn parse_no_context<'i, F, R>(string: &'i str, parse: F) -> Result<R, ()>
7742 where
7743     F: FnOnce(&ParserContext, &mut Parser<'i, '_>) -> Result<R, ParseError<'i>>,
7745     let context = ParserContext::new(
7746         Origin::Author,
7747         unsafe { dummy_url_data() },
7748         None,
7749         ParsingMode::DEFAULT,
7750         QuirksMode::NoQuirks,
7751         /* namespaces = */ Default::default(),
7752         None,
7753         None,
7754     );
7755     let mut input = ParserInput::new(string);
7756     Parser::new(&mut input)
7757         .parse_entirely(|i| parse(&context, i))
7758         .map_err(|_| ())
7761 #[no_mangle]
7762 // Parse a length without style context (for canvas2d letterSpacing/wordSpacing attributes).
7763 // This accepts absolute lengths, and if a font-metrics-getter function is passed, also
7764 // font-relative ones, but not other units (such as percentages, viewport-relative, etc)
7765 // that would require a full style context to resolve.
7766 pub extern "C" fn Servo_ParseLengthWithoutStyleContext(
7767     len: &nsACString,
7768     out: &mut f32,
7769     get_font_metrics: Option<unsafe extern "C" fn(*mut c_void) -> GeckoFontMetrics>,
7770     getter_context: *mut c_void
7771 ) -> bool {
7772     let metrics_getter = if let Some(getter) = get_font_metrics {
7773         Some(move || -> GeckoFontMetrics {
7774             unsafe { getter(getter_context) }
7775         })
7776     } else {
7777         None
7778     };
7779     let value = parse_no_context(unsafe { len.as_str_unchecked() }, specified::Length::parse)
7780         .and_then(|p| p.to_computed_pixel_length_with_font_metrics(metrics_getter));
7781     match value {
7782         Ok(v) => {
7783             *out = v;
7784             true
7785         },
7786         Err(..) => false,
7787     }
7790 #[no_mangle]
7791 pub extern "C" fn Servo_SlowRgbToColorName(r: u8, g: u8, b: u8, result: &mut nsACString) -> bool {
7792     let mut candidates = SmallVec::<[&'static str; 5]>::new();
7793     for (name, color) in cssparser::all_named_colors() {
7794         if color == (r, g, b) {
7795             candidates.push(name);
7796         }
7797     }
7798     if candidates.is_empty() {
7799         return false;
7800     }
7801     // DevTools expect the first alphabetically.
7802     candidates.sort();
7803     result.assign(candidates[0]);
7804     true
7807 #[no_mangle]
7808 pub extern "C" fn Servo_ColorNameToRgb(name: &nsACString, out: &mut structs::nscolor) -> bool {
7809     match cssparser::parse_named_color::<specified::Color>(unsafe { name.as_str_unchecked() }) {
7810         Ok(specified::Color::Absolute(ref color)) => {
7811             *out = style::gecko::values::convert_absolute_color_to_nscolor(&color.color);
7812             true
7813         },
7814         _ => false,
7815     }
7818 #[repr(u8)]
7819 pub enum RegisterCustomPropertyResult {
7820     SuccessfullyRegistered,
7821     InvalidName,
7822     AlreadyRegistered,
7823     InvalidSyntax,
7824     NoInitialValue,
7825     InvalidInitialValue,
7826     InitialValueNotComputationallyIndependent,
7829 /// https://drafts.css-houdini.org/css-properties-values-api-1/#the-registerproperty-function
7830 #[no_mangle]
7831 pub extern "C" fn Servo_RegisterCustomProperty(
7832     per_doc_data: &PerDocumentStyleData,
7833     extra_data: *mut URLExtraData,
7834     name: &nsACString,
7835     syntax: &nsACString,
7836     inherits: bool,
7837     initial_value: Option<&nsACString>,
7838 ) -> RegisterCustomPropertyResult {
7839     use self::RegisterCustomPropertyResult::*;
7840     use style::custom_properties::SpecifiedValue;
7841     use style::properties_and_values::registry::PropertyRegistration;
7842     use style::properties_and_values::rule::{PropertyRuleData, ToRegistrationError};
7843     use style::properties_and_values::syntax::Descriptor;
7845     let mut per_doc_data = per_doc_data.borrow_mut();
7846     let url_data = unsafe { UrlExtraData::from_ptr_ref(&extra_data) };
7847     let name = unsafe { name.as_str_unchecked() };
7848     let syntax = unsafe { syntax.as_str_unchecked() };
7849     let initial_value = initial_value.map(|v| unsafe { v.as_str_unchecked() });
7851     // If name is not a custom property name string, throw a SyntaxError and exit this algorithm.
7852     let name = match style::custom_properties::parse_name(name) {
7853         Ok(n) => Atom::from(n),
7854         Err(()) => return InvalidName,
7855     };
7857     // If property set already contains an entry with name as its property name (compared
7858     // codepoint-wise), throw an InvalidModificationError and exit this algorithm.
7859     if per_doc_data.stylist.custom_property_script_registry().get(&name).is_some() {
7860         return AlreadyRegistered
7861     }
7862     // Attempt to consume a syntax definition from syntax. If it returns failure, throw a
7863     // SyntaxError. Otherwise, let syntax definition be the returned syntax definition.
7864     let Ok(syntax) = Descriptor::from_str(syntax) else { return InvalidSyntax };
7866     let initial_value = match initial_value {
7867         Some(v) => {
7868             let mut input = ParserInput::new(v);
7869             let parsed = Parser::new(&mut input).parse_entirely(|input| {
7870                 input.skip_whitespace();
7871                 SpecifiedValue::parse(input)
7872             }).ok();
7873             if parsed.is_none() {
7874                 return InvalidInitialValue
7875             }
7876             parsed
7877         }
7878         None => None,
7879     };
7881     if let Err(error) =
7882         PropertyRuleData::validate_initial_value(&syntax, initial_value.as_ref(), url_data)
7883     {
7884         return match error {
7885             ToRegistrationError::MissingInherits |
7886             ToRegistrationError::MissingSyntax => unreachable!(),
7887             ToRegistrationError::InitialValueNotComputationallyIndependent => InitialValueNotComputationallyIndependent,
7888             ToRegistrationError::InvalidInitialValue => InvalidInitialValue,
7889             ToRegistrationError::NoInitialValue=> NoInitialValue,
7890         }
7891     }
7893     per_doc_data
7894         .stylist
7895         .custom_property_script_registry_mut()
7896         .register(
7897             name,
7898             PropertyRegistration {
7899                 syntax,
7900                 inherits,
7901                 initial_value,
7902                 url_data: url_data.clone(),
7903             },
7904         );
7906     SuccessfullyRegistered