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::{BasicParseError, ParseError as CssParseError, Parser, ParserInput, SourceLocation, UnicodeRange, Token};
10 use dom::{DocumentState, ElementState};
11 use malloc_size_of::MallocSizeOfOps;
12 use nsstring::{nsCString, nsString};
13 use selectors::matching::{ElementSelectorFlags, MatchingForInvalidation, SelectorCaches};
14 use selectors::{Element, OpaqueElement};
15 use servo_arc::{Arc, ArcBorrow};
16 use smallvec::SmallVec;
17 use std::collections::BTreeSet;
20 use std::os::raw::c_void;
22 use style::color::mix::ColorInterpolationMethod;
23 use style::color::{AbsoluteColor, ColorSpace};
24 use style::computed_value_flags::ComputedValueFlags;
25 use style::context::ThreadLocalStyleContext;
26 use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
27 use style::counter_style;
28 use style::custom_properties::DeferFontRelativeCustomPropertyResolution;
29 use style::data::{self, ElementStyles};
30 use style::dom::{ShowSubtreeData, TDocument, TElement, TNode};
32 use style::error_reporting::{ParseErrorReporter, SelectorWarningKind};
33 use style::font_face::{self, FontFaceSourceFormat, FontFaceSourceListComponent, Source};
34 use style::gecko::arc_types::{
35 LockedCounterStyleRule, LockedCssRules, LockedDeclarationBlock, LockedFontFaceRule,
36 LockedImportRule, LockedKeyframe, LockedKeyframesRule, LockedMediaList, LockedPageRule,
39 use style::gecko::data::{
40 AuthorStyles, GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl,
42 use style::gecko::restyle_damage::GeckoRestyleDamage;
43 use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement};
44 use style::gecko::snapshot_helpers::classes_changed;
45 use style::gecko::traversal::RecalcStyleOnly;
46 use style::gecko::url;
47 use style::gecko::wrapper::{
48 slow_selector_flags_from_node_selector_flags, GeckoElement, GeckoNode,
50 use style::gecko_bindings::bindings;
51 use style::gecko_bindings::bindings::nsACString;
52 use style::gecko_bindings::bindings::nsAString;
53 use style::gecko_bindings::bindings::Gecko_AddPropertyToSet;
54 use style::gecko_bindings::bindings::Gecko_AppendPropertyValuePair;
55 use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet;
56 use style::gecko_bindings::bindings::Gecko_ConstructFontPaletteValueSet;
57 use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
58 use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
59 use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
60 use style::gecko_bindings::bindings::Gecko_HaveSeenPtr;
61 use style::gecko_bindings::structs;
62 use style::gecko_bindings::structs::gfx::FontPaletteValueSet;
63 use style::gecko_bindings::structs::gfxFontFeatureValueSet;
64 use style::gecko_bindings::structs::ipc::ByteBuf;
65 use style::gecko_bindings::structs::nsAtom;
66 use style::gecko_bindings::structs::nsCSSCounterDesc;
67 use style::gecko_bindings::structs::nsCSSFontDesc;
68 use style::gecko_bindings::structs::nsCSSPropertyID;
69 use style::gecko_bindings::structs::nsChangeHint;
70 use style::gecko_bindings::structs::nsCompatibility;
71 use style::gecko_bindings::structs::nsStyleTransformMatrix::MatrixTransformOperator;
72 use style::gecko_bindings::structs::nsTArray;
73 use style::gecko_bindings::structs::nsresult;
74 use style::gecko_bindings::structs::CallerType;
75 use style::gecko_bindings::structs::CompositeOperation;
76 use style::gecko_bindings::structs::DeclarationBlockMutationClosure;
77 use style::gecko_bindings::structs::GeckoFontMetrics;
78 use style::gecko_bindings::structs::IterationCompositeOperation;
79 use style::gecko_bindings::structs::Loader;
80 use style::gecko_bindings::structs::LoaderReusableStyleSheets;
81 use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf;
82 use style::gecko_bindings::structs::OriginFlags;
83 use style::gecko_bindings::structs::PropertyValuePair;
84 use style::gecko_bindings::structs::PseudoStyleType;
85 use style::gecko_bindings::structs::SeenPtrs;
86 use style::gecko_bindings::structs::ServoElementSnapshotTable;
87 use style::gecko_bindings::structs::ServoStyleSetSizes;
88 use style::gecko_bindings::structs::ServoTraversalFlags;
89 use style::gecko_bindings::structs::SheetLoadData;
90 use style::gecko_bindings::structs::SheetLoadDataHolder;
91 use style::gecko_bindings::structs::SheetParsingMode;
92 use style::gecko_bindings::structs::StyleRuleInclusion;
93 use style::gecko_bindings::structs::StyleSheet as DomStyleSheet;
94 use style::gecko_bindings::structs::URLExtraData;
95 use style::gecko_bindings::structs::{nsINode as RawGeckoNode, Element as RawGeckoElement};
96 use style::gecko_bindings::sugar::ownership::Strong;
97 use style::gecko_bindings::sugar::refptr::RefPtr;
98 use style::global_style_data::{
99 GlobalStyleData, PlatformThreadHandle, StyleThreadPool, GLOBAL_STYLE_DATA, STYLE_THREAD_POOL,
101 use style::invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
102 use style::invalidation::element::invalidation_map::{
103 RelativeSelectorInvalidationMap, TSStateForInvalidation,
105 use style::invalidation::element::invalidator::{InvalidationResult, SiblingTraversalMap};
106 use style::invalidation::element::relative_selector::{
107 DomMutationOperation, RelativeSelectorDependencyCollector, RelativeSelectorInvalidator,
109 use style::invalidation::element::restyle_hints::RestyleHint;
110 use style::invalidation::stylesheets::RuleChangeKind;
111 use style::media_queries::MediaList;
112 use style::parser::{Parse, ParserContext};
113 #[cfg(feature = "gecko_debug")]
114 use style::properties::LonghandIdSet;
115 use style::properties::{
116 animated_properties::{AnimationValue, AnimationValueMap},
117 parse_one_declaration_into, parse_style_attribute, ComputedValues, CountedUnknownProperty,
118 Importance, LonghandId, NonCustomPropertyId, OwnedPropertyDeclarationId,
119 PropertyDeclarationBlock, PropertyDeclarationId, PropertyDeclarationIdSet, PropertyId,
120 ShorthandId, SourcePropertyDeclaration, StyleBuilder,
122 use style::properties_and_values::registry::{PropertyRegistration, PropertyRegistrationData};
123 use style::properties_and_values::rule::Inherits as PropertyInherits;
124 use style::rule_cache::RuleCacheConditions;
125 use style::rule_tree::StrongRuleNode;
126 use style::selector_parser::PseudoElementCascadeType;
127 use style::shared_lock::{
128 Locked, SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard,
130 use style::string_cache::{Atom, WeakAtom};
131 use style::style_adjuster::StyleAdjuster;
132 use style::stylesheets::container_rule::ContainerSizeQuery;
133 use style::stylesheets::import_rule::{ImportLayer, ImportSheet};
134 use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
135 use style::stylesheets::supports_rule::parse_condition_or_declaration;
136 use style::stylesheets::{
137 AllowImportRules, ContainerRule, CounterStyleRule, CssRule, CssRuleType, CssRuleTypes,
138 CssRules, CssRulesHelpers, DocumentRule, FontFaceRule, FontFeatureValuesRule,
139 FontPaletteValuesRule, ImportRule, KeyframesRule, LayerBlockRule, LayerStatementRule,
140 MediaRule, NamespaceRule, Origin, OriginSet, PagePseudoClassFlags, PageRule, PropertyRule,
141 SanitizationData, SanitizationKind, StyleRule, StylesheetContents,
142 StylesheetLoader as StyleStylesheetLoader, SupportsRule, UrlExtraData,
144 use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
145 use style::thread_state;
146 use style::traversal::resolve_style;
147 use style::traversal::DomTraversal;
148 use style::traversal_flags::{self, TraversalFlags};
149 use style::use_counters::UseCounters;
150 use style::values::animated::{Animate, Procedure, ToAnimatedZero};
151 use style::values::computed::easing::ComputedTimingFunction;
152 use style::values::computed::effects::Filter;
153 use style::values::computed::font::{
154 FamilyName, FontFamily, FontFamilyList, FontStretch, FontStyle, FontWeight, GenericFontFamily,
156 use style::values::computed::{self, Context, ToComputedValue};
157 use style::values::distance::ComputeSquaredDistance;
158 use style::values::generics::color::ColorMixFlags;
159 use style::values::generics::easing::BeforeFlag;
160 use style::values::specified::gecko::IntersectionObserverRootMargin;
161 use style::values::specified::source_size_list::SourceSizeList;
162 use style::values::specified::{AbsoluteLength, NoCalcLength};
163 use style::values::{specified, AtomIdent, CustomIdent, KeyframesName};
164 use style_traits::{CssWriter, ParseError, ParsingMode, ToCss};
165 use thin_vec::ThinVec;
166 use to_shmem::SharedMemoryBuilder;
168 trait ClosureHelper {
169 fn invoke(&self, property_id: Option<NonCustomPropertyId>);
172 impl ClosureHelper for DeclarationBlockMutationClosure {
174 fn invoke(&self, property_id: Option<NonCustomPropertyId>) {
175 if let Some(function) = self.function.as_ref() {
176 let gecko_prop_id = match property_id {
177 Some(p) => p.to_nscsspropertyid(),
178 None => nsCSSPropertyID::eCSSPropertyExtra_variable,
180 unsafe { function(self.data, gecko_prop_id) }
186 * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
187 * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
188 * those signatures as well, giving us a second declaration of all the Servo_* functions in this
189 * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
190 * depend on but good enough for our purposes.
193 // A dummy url data for where we don't pass url data in.
194 static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut _;
195 static mut DUMMY_CHROME_URL_DATA: *mut URLExtraData = 0 as *mut _;
198 pub unsafe extern "C" fn Servo_Initialize(
199 dummy_url_data: *mut URLExtraData,
200 dummy_chrome_url_data: *mut URLExtraData,
202 use style::gecko_bindings::sugar::origin_flags;
204 // Pretend that we're a Servo Layout thread, to make some assertions happy.
205 thread_state::initialize(thread_state::ThreadState::LAYOUT);
207 debug_assert!(is_main_thread());
208 lazy_static::initialize(&STYLE_THREAD_POOL);
210 // Perform some debug-only runtime assertions.
211 origin_flags::assert_flags_match();
212 traversal_flags::assert_traversal_flags_match();
213 specified::font::assert_variant_east_asian_matches();
214 specified::font::assert_variant_ligatures_matches();
216 DUMMY_URL_DATA = dummy_url_data;
217 DUMMY_CHROME_URL_DATA = dummy_chrome_url_data;
221 pub unsafe extern "C" fn Servo_Shutdown() {
222 DUMMY_URL_DATA = ptr::null_mut();
223 DUMMY_CHROME_URL_DATA = ptr::null_mut();
229 unsafe fn dummy_url_data() -> &'static UrlExtraData {
230 UrlExtraData::from_ptr_ref(&DUMMY_URL_DATA)
234 fn is_main_thread() -> bool {
235 unsafe { bindings::Gecko_IsMainThread() }
239 fn is_dom_worker_thread() -> bool {
240 unsafe { bindings::Gecko_IsDOMWorkerThread() }
244 /// Thread-local style data for DOM workers
245 static DOM_WORKER_RWLOCK: SharedRwLock = SharedRwLock::new();
249 fn is_in_servo_traversal() -> bool {
250 unsafe { bindings::Gecko_IsInServoTraversal() }
253 fn create_shared_context<'a>(
254 global_style_data: &GlobalStyleData,
255 guard: &'a SharedRwLockReadGuard,
256 stylist: &'a Stylist,
257 traversal_flags: TraversalFlags,
258 snapshot_map: &'a ServoElementSnapshotTable,
259 ) -> SharedStyleContext<'a> {
262 visited_styles_enabled: stylist.device().visited_styles_enabled(),
263 options: global_style_data.options.clone(),
264 guards: StylesheetGuards::same(guard),
265 current_time_for_animations: 0.0, // Unused for Gecko, at least for now.
272 element: GeckoElement,
273 global_style_data: &GlobalStyleData,
274 per_doc_data: &PerDocumentStyleDataImpl,
275 guard: &SharedRwLockReadGuard,
276 traversal_flags: TraversalFlags,
277 snapshots: &ServoElementSnapshotTable,
279 let shared_style_context = create_shared_context(
282 &per_doc_data.stylist,
287 let token = RecalcStyleOnly::pre_traverse(element, &shared_style_context);
289 if !token.should_traverse() {
293 debug!("Traversing subtree from {:?}", element);
295 let thread_pool_holder = &*STYLE_THREAD_POOL;
297 let thread_pool = if traversal_flags.contains(TraversalFlags::ParallelTraversal) {
298 pool = thread_pool_holder.pool();
304 let traversal = RecalcStyleOnly::new(shared_style_context);
305 driver::traverse_dom(&traversal, token, thread_pool);
308 /// Traverses the subtree rooted at `root` for restyling.
310 /// Returns whether the root was restyled. Whether anything else was restyled or
311 /// not can be inferred from the dirty bits in the rest of the tree.
313 pub extern "C" fn Servo_TraverseSubtree(
314 root: &RawGeckoElement,
315 raw_data: &PerDocumentStyleData,
316 snapshots: *const ServoElementSnapshotTable,
317 raw_flags: ServoTraversalFlags,
319 let traversal_flags = TraversalFlags::from_bits_retain(raw_flags);
320 debug_assert!(!snapshots.is_null());
322 let element = GeckoElement(root);
324 debug!("Servo_TraverseSubtree (flags={:?})", traversal_flags);
325 debug!("{:?}", ShowSubtreeData(element.as_node()));
327 if cfg!(debug_assertions) {
328 if let Some(parent) = element.traversal_parent() {
331 .expect("Styling element with unstyled parent");
333 !data.styles.is_display_none(),
334 "Styling element with display: none parent"
339 let needs_animation_only_restyle =
340 element.has_animation_only_dirty_descendants() || element.has_animation_restyle_hints();
342 let per_doc_data = raw_data.borrow();
343 debug_assert!(!per_doc_data.stylist.stylesheets_have_changed());
345 let global_style_data = &*GLOBAL_STYLE_DATA;
346 let guard = global_style_data.shared_lock.read();
348 let was_initial_style = !element.has_data();
350 if needs_animation_only_restyle {
352 "Servo_TraverseSubtree doing animation-only restyle (aodd={})",
353 element.has_animation_only_dirty_descendants()
360 traversal_flags | TraversalFlags::AnimationOnly,
361 unsafe { &*snapshots },
371 unsafe { &*snapshots },
375 "Servo_TraverseSubtree complete (dd={}, aodd={}, lfcd={}, lfc={}, data={:?})",
376 element.has_dirty_descendants(),
377 element.has_animation_only_dirty_descendants(),
378 element.descendants_need_frames(),
379 element.needs_frame(),
380 element.borrow_data().unwrap()
383 if was_initial_style {
384 debug_assert!(!element.borrow_data().unwrap().contains_restyle_data());
387 let element_was_restyled = element.borrow_data().unwrap().contains_restyle_data();
392 /// Checks whether the rule tree has crossed its threshold for unused nodes, and
393 /// if so, frees them.
395 pub extern "C" fn Servo_MaybeGCRuleTree(raw_data: &PerDocumentStyleData) {
396 let per_doc_data = raw_data.borrow_mut();
397 per_doc_data.stylist.rule_tree().maybe_gc();
401 pub extern "C" fn Servo_AnimationValues_Interpolate(
402 from: &AnimationValue,
405 ) -> Strong<AnimationValue> {
406 if let Ok(value) = from.animate(to, Procedure::Interpolate { progress }) {
407 Arc::new(value).into()
414 pub extern "C" fn Servo_AnimationValues_IsInterpolable(
415 from: &AnimationValue,
418 from.interpolable_with(to)
422 pub extern "C" fn Servo_AnimationValues_Add(
425 ) -> Strong<AnimationValue> {
426 if let Ok(value) = a.animate(b, Procedure::Add) {
427 Arc::new(value).into()
434 pub extern "C" fn Servo_AnimationValues_Accumulate(
438 ) -> Strong<AnimationValue> {
439 if let Ok(value) = a.animate(b, Procedure::Accumulate { count }) {
440 Arc::new(value).into()
447 pub extern "C" fn Servo_AnimationValues_GetZeroValue(
448 value_to_match: &AnimationValue,
449 ) -> Strong<AnimationValue> {
450 if let Ok(zero_value) = value_to_match.to_animated_zero() {
451 Arc::new(zero_value).into()
458 pub extern "C" fn Servo_AnimationValues_ComputeDistance(
459 from: &AnimationValue,
462 // If compute_squared_distance() failed, this function will return negative value
463 // in order to check whether we support the specified paced animation values.
464 from.compute_squared_distance(to).map_or(-1.0, |d| d.sqrt())
467 /// Compute one of the endpoints for the interpolation interval, compositing it with the
468 /// underlying value if needed.
469 /// An None returned value means, "Just use endpoint_value as-is."
470 /// It is the responsibility of the caller to ensure that |underlying_value| is provided
471 /// when it will be used.
472 fn composite_endpoint(
473 endpoint_value: Option<&AnimationValue>,
474 composite: CompositeOperation,
475 underlying_value: Option<&AnimationValue>,
476 ) -> Option<AnimationValue> {
477 match endpoint_value {
478 Some(endpoint_value) => match composite {
479 CompositeOperation::Add => underlying_value
480 .expect("We should have an underlying_value")
481 .animate(endpoint_value, Procedure::Add)
483 CompositeOperation::Accumulate => underlying_value
484 .expect("We should have an underlying value")
485 .animate(endpoint_value, Procedure::Accumulate { count: 1 })
489 None => underlying_value.map(|v| v.clone()),
493 /// Accumulate one of the endpoints of the animation interval.
494 /// A returned value of None means, "Just use endpoint_value as-is."
495 fn accumulate_endpoint(
496 endpoint_value: Option<&AnimationValue>,
497 composited_value: Option<AnimationValue>,
498 last_value: &AnimationValue,
499 current_iteration: u64,
500 ) -> Option<AnimationValue> {
502 endpoint_value.is_some() || composited_value.is_some(),
503 "Should have a suitable value to use"
506 let count = current_iteration;
507 match composited_value {
508 Some(endpoint) => last_value
509 .animate(&endpoint, Procedure::Accumulate { count })
513 .animate(endpoint_value.unwrap(), Procedure::Accumulate { count })
518 /// Compose the animation segment. We composite it with the underlying_value and last_value if
520 /// The caller is responsible for providing an underlying value and last value
521 /// in all situations where there are needed.
522 fn compose_animation_segment(
523 segment: &structs::AnimationPropertySegment,
524 underlying_value: Option<&AnimationValue>,
525 last_value: Option<&AnimationValue>,
526 iteration_composite: IterationCompositeOperation,
527 current_iteration: u64,
529 segment_progress: f64,
530 ) -> AnimationValue {
531 // Extract keyframe values.
532 let keyframe_from_value = unsafe { segment.mFromValue.mServo.mRawPtr.as_ref() };
533 let keyframe_to_value = unsafe { segment.mToValue.mServo.mRawPtr.as_ref() };
534 let mut composited_from_value = composite_endpoint(
536 segment.mFromComposite,
539 let mut composited_to_value =
540 composite_endpoint(keyframe_to_value, segment.mToComposite, underlying_value);
543 keyframe_from_value.is_some() || composited_from_value.is_some(),
544 "Should have a suitable from value to use"
547 keyframe_to_value.is_some() || composited_to_value.is_some(),
548 "Should have a suitable to value to use"
551 // Apply iteration composite behavior.
552 if iteration_composite == IterationCompositeOperation::Accumulate && current_iteration > 0 {
553 let last_value = last_value
554 .unwrap_or_else(|| underlying_value.expect("Should have a valid underlying value"));
556 composited_from_value = accumulate_endpoint(
558 composited_from_value,
562 composited_to_value = accumulate_endpoint(
570 // Use the composited value if there is one, otherwise, use the original keyframe value.
571 let from = composited_from_value
573 .unwrap_or_else(|| keyframe_from_value.unwrap());
574 let to = composited_to_value
576 .unwrap_or_else(|| keyframe_to_value.unwrap());
578 if segment.mToKey == segment.mFromKey {
579 return if total_progress < 0. {
588 Procedure::Interpolate {
589 progress: segment_progress,
594 if segment_progress < 0.5 {
604 pub extern "C" fn Servo_ComposeAnimationSegment(
605 segment: &structs::AnimationPropertySegment,
606 underlying_value: Option<&AnimationValue>,
607 last_value: Option<&AnimationValue>,
608 iteration_composite: IterationCompositeOperation,
610 current_iteration: u64,
611 ) -> Strong<AnimationValue> {
612 let result = compose_animation_segment(
621 Arc::new(result).into()
625 pub extern "C" fn Servo_AnimationCompose(
626 value_map: &mut AnimationValueMap,
627 base_values: &structs::RawServoAnimationValueTable,
628 css_property: &structs::AnimatedPropertyID,
629 segment: &structs::AnimationPropertySegment,
630 last_segment: &structs::AnimationPropertySegment,
631 computed_timing: &structs::ComputedTiming,
632 iteration_composite: IterationCompositeOperation,
634 use style::gecko_bindings::bindings::Gecko_AnimationGetBaseStyle;
635 use style::gecko_bindings::bindings::Gecko_GetPositionInSegment;
636 use style::gecko_bindings::bindings::Gecko_GetProgressFromComputedTiming;
638 let property = match OwnedPropertyDeclarationId::from_gecko_animated_property_id(css_property) {
639 Some(property) if property.as_borrowed().is_animatable() => property,
643 // We will need an underlying value if either of the endpoints is null...
644 let need_underlying_value = segment.mFromValue.mServo.mRawPtr.is_null() ||
645 segment.mToValue.mServo.mRawPtr.is_null() ||
646 // ... or if they have a non-replace composite mode ...
647 segment.mFromComposite != CompositeOperation::Replace ||
648 segment.mToComposite != CompositeOperation::Replace ||
649 // ... or if we accumulate onto the last value and it is null.
650 (iteration_composite == IterationCompositeOperation::Accumulate &&
651 computed_timing.mCurrentIteration > 0 &&
652 last_segment.mToValue.mServo.mRawPtr.is_null());
654 // If either of the segment endpoints are null, get the underlying value to
655 // use from the current value in the values map (set by a lower-priority
656 // effect), or, if there is no current value, look up the cached base value
657 // for this property.
658 let underlying_value = if need_underlying_value {
659 let previous_composed_value = value_map.get(&property).map(|v| &*v);
660 previous_composed_value
661 .or_else(|| unsafe { Gecko_AnimationGetBaseStyle(base_values, css_property).as_ref() })
666 if need_underlying_value && underlying_value.is_none() {
667 warn!("Underlying value should be valid when we expect to use it");
671 let last_value = unsafe { last_segment.mToValue.mServo.mRawPtr.as_ref() };
672 let progress = unsafe { Gecko_GetProgressFromComputedTiming(computed_timing) };
673 let position = if segment.mToKey == segment.mFromKey {
674 // Note: compose_animation_segment doesn't use this value
675 // if segment.mFromKey == segment.mToKey, so assigning |progress| directly is fine.
678 unsafe { Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag) }
681 let result = compose_animation_segment(
686 computed_timing.mCurrentIteration,
690 value_map.insert(property, result);
693 macro_rules! get_property_id_from_nscsspropertyid {
694 ($property_id: ident, $ret: expr) => {{
695 match PropertyId::from_nscsspropertyid($property_id) {
696 Some(property_id) => property_id,
704 macro_rules! get_property_id_from_animatedpropertyid {
705 ($property_id: ident, $ret: expr) => {{
706 match PropertyId::from_gecko_animated_property_id($property_id) {
707 Some(property_id) => property_id,
716 pub extern "C" fn Servo_AnimationValue_Serialize(
717 value: &AnimationValue,
718 property: &structs::AnimatedPropertyID,
719 raw_data: &PerDocumentStyleData,
720 buffer: &mut nsACString,
722 let uncomputed_value = value.uncompute();
723 let data = raw_data.borrow();
724 let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
725 .single_value_to_css(
726 &get_property_id_from_animatedpropertyid!(property, ()),
731 debug_assert!(rv.is_ok());
734 /// Debug: MOZ_DBG for AnimationValue.
736 pub extern "C" fn Servo_AnimationValue_Dump(value: &AnimationValue, result: &mut nsACString) {
737 write!(result, "{:?}", value).unwrap();
741 pub extern "C" fn Servo_AnimationValue_GetColor(
742 value: &AnimationValue,
743 foreground_color: structs::nscolor,
744 ) -> structs::nscolor {
745 use style::gecko::values::{
746 convert_absolute_color_to_nscolor, convert_nscolor_to_absolute_color,
748 use style::values::computed::color::Color as ComputedColor;
750 AnimationValue::BackgroundColor(ref color) => {
751 let computed: ComputedColor = color.clone();
752 let foreground_color = convert_nscolor_to_absolute_color(foreground_color);
753 convert_absolute_color_to_nscolor(&computed.resolve_to_absolute(&foreground_color))
755 _ => panic!("Other color properties are not supported yet"),
760 pub extern "C" fn Servo_AnimationValue_IsCurrentColor(value: &AnimationValue) -> bool {
762 AnimationValue::BackgroundColor(ref color) => color.is_currentcolor(),
764 debug_assert!(false, "Other color properties are not supported yet");
771 pub extern "C" fn Servo_AnimationValue_GetOpacity(value: &AnimationValue) -> f32 {
772 if let AnimationValue::Opacity(opacity) = *value {
775 panic!("The AnimationValue should be Opacity");
780 pub extern "C" fn Servo_AnimationValue_Opacity(opacity: f32) -> Strong<AnimationValue> {
781 Arc::new(AnimationValue::Opacity(opacity)).into()
785 pub extern "C" fn Servo_AnimationValue_Color(
786 color_property: nsCSSPropertyID,
787 color: structs::nscolor,
788 ) -> Strong<AnimationValue> {
789 use style::gecko::values::convert_nscolor_to_absolute_color;
790 use style::values::animated::color::Color;
792 let property = LonghandId::from_nscsspropertyid(color_property)
793 .expect("We don't have shorthand property animation value");
795 let animated = convert_nscolor_to_absolute_color(color);
798 LonghandId::BackgroundColor => {
799 Arc::new(AnimationValue::BackgroundColor(Color::Absolute(animated))).into()
801 _ => panic!("Should be background-color property"),
806 pub unsafe extern "C" fn Servo_AnimationValue_GetScale(
807 value: &AnimationValue,
808 ) -> *const computed::Scale {
810 AnimationValue::Scale(ref value) => value,
811 _ => unreachable!("Expected scale"),
816 pub unsafe extern "C" fn Servo_AnimationValue_GetTranslate(
817 value: &AnimationValue,
818 ) -> *const computed::Translate {
820 AnimationValue::Translate(ref value) => value,
821 _ => unreachable!("Expected translate"),
826 pub unsafe extern "C" fn Servo_AnimationValue_GetRotate(
827 value: &AnimationValue,
828 ) -> *const computed::Rotate {
830 AnimationValue::Rotate(ref value) => value,
831 _ => unreachable!("Expected rotate"),
836 pub unsafe extern "C" fn Servo_AnimationValue_GetTransform(
837 value: &AnimationValue,
838 ) -> *const computed::Transform {
840 AnimationValue::Transform(ref value) => value,
841 _ => unreachable!("Unsupported transform animation value"),
846 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPath(
847 value: &AnimationValue,
848 output: &mut computed::motion::OffsetPath,
850 use style::values::animated::ToAnimatedValue;
852 AnimationValue::OffsetPath(ref value) => {
853 *output = ToAnimatedValue::from_animated_value(value.clone())
855 _ => unreachable!("Expected offset-path"),
860 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetDistance(
861 value: &AnimationValue,
862 ) -> *const computed::LengthPercentage {
864 AnimationValue::OffsetDistance(ref value) => value,
865 _ => unreachable!("Expected offset-distance"),
870 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetRotate(
871 value: &AnimationValue,
872 ) -> *const computed::motion::OffsetRotate {
874 AnimationValue::OffsetRotate(ref value) => value,
875 _ => unreachable!("Expected offset-rotate"),
880 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetAnchor(
881 value: &AnimationValue,
882 ) -> *const computed::position::PositionOrAuto {
884 AnimationValue::OffsetAnchor(ref value) => value,
885 _ => unreachable!("Expected offset-anchor"),
890 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPosition(
891 value: &AnimationValue,
892 ) -> *const computed::motion::OffsetPosition {
894 AnimationValue::OffsetPosition(ref value) => value,
895 _ => unreachable!("Expected offset-position"),
900 pub unsafe extern "C" fn Servo_AnimationValue_IsOffsetPathUrl(value: &AnimationValue) -> bool {
901 use style::values::generics::motion::{GenericOffsetPath, GenericOffsetPathFunction};
902 if let AnimationValue::OffsetPath(ref op) = value {
903 if let GenericOffsetPath::OffsetPath { path, coord_box: _ } = op {
904 return matches!(**path, GenericOffsetPathFunction::Url(_));
911 pub unsafe extern "C" fn Servo_AnimationValue_Rotate(
912 r: &computed::Rotate,
913 ) -> Strong<AnimationValue> {
914 Arc::new(AnimationValue::Rotate(r.clone())).into()
918 pub unsafe extern "C" fn Servo_AnimationValue_Translate(
919 t: &computed::Translate,
920 ) -> Strong<AnimationValue> {
921 Arc::new(AnimationValue::Translate(t.clone())).into()
925 pub unsafe extern "C" fn Servo_AnimationValue_Scale(s: &computed::Scale) -> Strong<AnimationValue> {
926 Arc::new(AnimationValue::Scale(s.clone())).into()
930 pub unsafe extern "C" fn Servo_AnimationValue_Transform(
931 transform: &computed::Transform,
932 ) -> Strong<AnimationValue> {
933 Arc::new(AnimationValue::Transform(transform.clone())).into()
937 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPath(
938 p: &computed::motion::OffsetPath,
939 ) -> Strong<AnimationValue> {
940 use style::values::animated::ToAnimatedValue;
941 Arc::new(AnimationValue::OffsetPath(p.clone().to_animated_value())).into()
945 pub unsafe extern "C" fn Servo_AnimationValue_OffsetDistance(
946 d: &computed::LengthPercentage,
947 ) -> Strong<AnimationValue> {
948 Arc::new(AnimationValue::OffsetDistance(d.clone())).into()
952 pub unsafe extern "C" fn Servo_AnimationValue_OffsetRotate(
953 r: &computed::motion::OffsetRotate,
954 ) -> Strong<AnimationValue> {
955 Arc::new(AnimationValue::OffsetRotate(*r)).into()
959 pub unsafe extern "C" fn Servo_AnimationValue_OffsetAnchor(
960 p: &computed::position::PositionOrAuto,
961 ) -> Strong<AnimationValue> {
962 Arc::new(AnimationValue::OffsetAnchor(p.clone())).into()
966 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPosition(
967 p: &computed::motion::OffsetPosition,
968 ) -> Strong<AnimationValue> {
969 Arc::new(AnimationValue::OffsetPosition(p.clone())).into()
973 pub extern "C" fn Servo_AnimationValue_DeepEqual(
974 this: &AnimationValue,
975 other: &AnimationValue,
981 pub extern "C" fn Servo_AnimationValue_Uncompute(
982 value: &AnimationValue,
983 ) -> Strong<LockedDeclarationBlock> {
984 let global_style_data = &*GLOBAL_STYLE_DATA;
988 .wrap(PropertyDeclarationBlock::with_one(
997 fn create_byte_buf_from_vec(mut v: Vec<u8>) -> ByteBuf {
999 mData: v.as_mut_ptr(),
1001 mCapacity: v.capacity(),
1003 std::mem::forget(v);
1008 fn view_byte_buf(b: &ByteBuf) -> &[u8] {
1009 if b.mData.is_null() {
1010 debug_assert_eq!(b.mCapacity, 0);
1013 unsafe { std::slice::from_raw_parts(b.mData, b.mLen) }
1016 macro_rules! impl_basic_serde_funcs {
1017 ($ser_name:ident, $de_name:ident, $computed_type:ty) => {
1019 pub extern "C" fn $ser_name(v: &$computed_type, output: &mut ByteBuf) -> bool {
1020 let buf = match serialize(v) {
1022 Err(..) => return false,
1025 *output = create_byte_buf_from_vec(buf);
1030 pub unsafe extern "C" fn $de_name(input: &ByteBuf, v: *mut $computed_type) -> bool {
1031 let buf = match deserialize(view_byte_buf(input)) {
1033 Err(..) => return false,
1036 std::ptr::write(v, buf);
1042 impl_basic_serde_funcs!(
1043 Servo_LengthPercentage_Serialize,
1044 Servo_LengthPercentage_Deserialize,
1045 computed::LengthPercentage
1048 impl_basic_serde_funcs!(
1049 Servo_StyleRotate_Serialize,
1050 Servo_StyleRotate_Deserialize,
1051 computed::transform::Rotate
1054 impl_basic_serde_funcs!(
1055 Servo_StyleScale_Serialize,
1056 Servo_StyleScale_Deserialize,
1057 computed::transform::Scale
1060 impl_basic_serde_funcs!(
1061 Servo_StyleTranslate_Serialize,
1062 Servo_StyleTranslate_Deserialize,
1063 computed::transform::Translate
1066 impl_basic_serde_funcs!(
1067 Servo_StyleTransform_Serialize,
1068 Servo_StyleTransform_Deserialize,
1069 computed::transform::Transform
1072 impl_basic_serde_funcs!(
1073 Servo_StyleOffsetPath_Serialize,
1074 Servo_StyleOffsetPath_Deserialize,
1075 computed::motion::OffsetPath
1078 impl_basic_serde_funcs!(
1079 Servo_StyleOffsetRotate_Serialize,
1080 Servo_StyleOffsetRotate_Deserialize,
1081 computed::motion::OffsetRotate
1084 impl_basic_serde_funcs!(
1085 Servo_StylePositionOrAuto_Serialize,
1086 Servo_StylePositionOrAuto_Deserialize,
1087 computed::position::PositionOrAuto
1090 impl_basic_serde_funcs!(
1091 Servo_StyleOffsetPosition_Serialize,
1092 Servo_StyleOffsetPosition_Deserialize,
1093 computed::motion::OffsetPosition
1096 impl_basic_serde_funcs!(
1097 Servo_StyleComputedTimingFunction_Serialize,
1098 Servo_StyleComputedTimingFunction_Deserialize,
1099 ComputedTimingFunction
1102 // Return the ComputedValues by a base ComputedValues and the rules.
1103 fn resolve_rules_for_element_with_context<'a>(
1104 element: GeckoElement<'a>,
1105 mut context: StyleContext<GeckoElement<'a>>,
1106 rules: StrongRuleNode,
1107 original_computed_values: &ComputedValues,
1108 ) -> Arc<ComputedValues> {
1109 use style::style_resolver::{PseudoElementResolution, StyleResolverForElement};
1111 // This currently ignores visited styles, which seems acceptable, as
1112 // existing browsers don't appear to animate visited styles.
1113 let inputs = CascadeInputs {
1115 visited_rules: None,
1116 flags: original_computed_values.flags.for_cascade_inputs(),
1119 // Actually `PseudoElementResolution` doesn't matter.
1120 let mut resolver = StyleResolverForElement::new(
1124 PseudoElementResolution::IfApplicable,
1127 .cascade_style_and_visited_with_default_parents(inputs)
1132 pub extern "C" fn Servo_AnimationValueMap_Create() -> *mut AnimationValueMap {
1133 Box::into_raw(Box::default())
1137 pub unsafe extern "C" fn Servo_AnimationValueMap_Drop(value_map: *mut AnimationValueMap) {
1138 let _ = Box::from_raw(value_map);
1142 pub extern "C" fn Servo_AnimationValueMap_GetValue(
1143 value_map: &AnimationValueMap,
1144 property_id: &structs::AnimatedPropertyID,
1145 ) -> Strong<AnimationValue> {
1146 let property = match OwnedPropertyDeclarationId::from_gecko_animated_property_id(property_id) {
1147 Some(property) => property,
1148 None => return Strong::null(),
1152 .map_or(Strong::null(), |value| Arc::new(value.clone()).into())
1156 pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(
1157 raw_style_set: &PerDocumentStyleData,
1158 element: &RawGeckoElement,
1159 computed_values: &ComputedValues,
1160 snapshots: *const ServoElementSnapshotTable,
1161 ) -> Strong<ComputedValues> {
1162 debug_assert!(!snapshots.is_null());
1163 let computed_values = unsafe { ArcBorrow::from_ref(computed_values) };
1165 let rules = match computed_values.rules {
1166 None => return computed_values.clone_arc().into(),
1167 Some(ref rules) => rules,
1170 let doc_data = raw_style_set.borrow();
1171 let without_animations_rules = doc_data.stylist.rule_tree().remove_animation_rules(rules);
1172 if without_animations_rules == *rules {
1173 return computed_values.clone_arc().into();
1176 let element = GeckoElement(element);
1178 let global_style_data = &*GLOBAL_STYLE_DATA;
1179 let guard = global_style_data.shared_lock.read();
1180 let shared = create_shared_context(
1184 TraversalFlags::empty(),
1185 unsafe { &*snapshots },
1187 let mut tlc = ThreadLocalStyleContext::new();
1188 let context = StyleContext {
1190 thread_local: &mut tlc,
1193 resolve_rules_for_element_with_context(
1196 without_animations_rules,
1204 pub struct ShouldTransitionResult {
1205 should_animate: bool,
1206 old_transition_value_matches: bool,
1210 fn is_transitionable(prop: PropertyDeclarationId, behavior: computed::TransitionBehavior) -> bool {
1211 if !prop.is_animatable() {
1216 computed::TransitionBehavior::Normal => !prop.is_discrete_animatable(),
1217 // If transition-behavior is allow-discrete, transitionable is the same as animatable.
1218 computed::TransitionBehavior::AllowDiscrete => true,
1223 pub extern "C" fn Servo_ComputedValues_ShouldTransition(
1224 old: &ComputedValues,
1225 new: &ComputedValues,
1226 prop: &structs::AnimatedPropertyID,
1227 behavior: computed::TransitionBehavior,
1228 old_transition_value: Option<&AnimationValue>,
1229 start: &mut structs::RefPtr<AnimationValue>,
1230 end: &mut structs::RefPtr<AnimationValue>,
1231 ) -> ShouldTransitionResult {
1232 let Some(prop) = OwnedPropertyDeclarationId::from_gecko_animated_property_id(prop) else {
1233 return Default::default();
1235 let prop = prop.as_borrowed();
1236 if !is_transitionable(prop, behavior) {
1237 return Default::default();
1240 let Some(new_value) = AnimationValue::from_computed_values(prop, new) else {
1241 return Default::default();
1244 if let Some(old_transition_value) = old_transition_value {
1245 if *old_transition_value == new_value {
1246 return ShouldTransitionResult {
1247 should_animate: false,
1248 old_transition_value_matches: true,
1253 let Some(old_value) = AnimationValue::from_computed_values(prop, old) else {
1254 return Default::default();
1256 if old_value == new_value
1257 || (matches!(behavior, computed::TransitionBehavior::Normal)
1258 && !old_value.interpolable_with(&new_value))
1260 return Default::default();
1263 start.set_arc(Arc::new(old_value));
1264 end.set_arc(Arc::new(new_value));
1266 ShouldTransitionResult {
1267 should_animate: true,
1268 old_transition_value_matches: false,
1273 pub extern "C" fn Servo_ComputedValues_TransitionValueMatches(
1274 style: &ComputedValues,
1275 prop: &structs::AnimatedPropertyID,
1276 transition_value: &AnimationValue,
1278 let Some(prop) = OwnedPropertyDeclarationId::from_gecko_animated_property_id(prop) else {
1281 // Note: the running transitions should be transitionable, so it is always allow-discrete.
1282 let prop = prop.as_borrowed();
1283 if !is_transitionable(prop, computed::TransitionBehavior::AllowDiscrete) {
1286 let Some(value) = AnimationValue::from_computed_values(prop, style) else {
1289 value == *transition_value
1293 pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue(
1294 computed_values: &ComputedValues,
1295 property_id: &structs::AnimatedPropertyID,
1296 ) -> Strong<AnimationValue> {
1297 let property = match OwnedPropertyDeclarationId::from_gecko_animated_property_id(property_id) {
1298 Some(property) => property,
1299 None => return Strong::null(),
1301 match AnimationValue::from_computed_values(property.as_borrowed(), &computed_values) {
1302 Some(v) => Arc::new(v).into(),
1303 None => Strong::null(),
1308 pub extern "C" fn Servo_ResolveLogicalProperty(
1309 property_id: nsCSSPropertyID,
1310 style: &ComputedValues,
1311 ) -> nsCSSPropertyID {
1312 let longhand = LonghandId::from_nscsspropertyid(property_id)
1313 .expect("We shouldn't need to care about shorthands");
1316 .to_physical(style.writing_mode)
1317 .to_nscsspropertyid()
1321 pub unsafe extern "C" fn Servo_Property_LookupEnabledForAllContent(
1323 ) -> nsCSSPropertyID {
1324 match PropertyId::parse_enabled_for_all_content(prop.as_str_unchecked()) {
1325 Ok(p) => p.to_nscsspropertyid_resolving_aliases(),
1326 Err(..) => nsCSSPropertyID::eCSSProperty_UNKNOWN,
1331 pub unsafe extern "C" fn Servo_Property_GetName(
1332 prop: nsCSSPropertyID,
1333 out_length: *mut u32,
1335 let (ptr, len) = match NonCustomPropertyId::from_nscsspropertyid(prop) {
1337 let name = p.name();
1338 (name.as_bytes().as_ptr(), name.len())
1340 None => (ptr::null(), 0),
1343 *out_length = len as u32;
1347 macro_rules! parse_enabled_property_name {
1348 ($prop_name:ident, $found:ident, $default:expr) => {{
1349 let prop_name = $prop_name.as_str_unchecked();
1350 match PropertyId::parse_enabled_for_all_content(prop_name) {
1364 pub unsafe extern "C" fn Servo_Property_IsShorthand(
1365 prop_name: &nsACString,
1368 let prop_id = parse_enabled_property_name!(prop_name, found, false);
1369 prop_id.is_shorthand()
1373 pub unsafe extern "C" fn Servo_Property_IsInherited(
1374 per_doc_data: &PerDocumentStyleData,
1375 prop_name: &nsACString,
1377 let prop_name = prop_name.as_str_unchecked();
1378 let prop_id = match PropertyId::parse_enabled_for_all_content(prop_name) {
1380 Err(_) => return false,
1382 let longhand_id = match prop_id {
1383 PropertyId::Custom(property_name) => {
1384 let stylist = &per_doc_data.borrow().stylist;
1386 .get_custom_property_registration(&property_name)
1389 PropertyId::NonCustom(id) => match id.longhand_or_shorthand() {
1391 Err(sh) => sh.longhands().next().unwrap(),
1394 longhand_id.inherited()
1398 pub unsafe extern "C" fn Servo_Property_SupportsType(
1399 prop_name: &nsACString,
1403 let prop_id = parse_enabled_property_name!(prop_name, found, false);
1404 prop_id.supports_type(ty)
1407 // TODO(emilio): We could use ThinVec instead of nsTArray.
1409 pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty(
1410 prop_name: &nsACString,
1412 result: &mut nsTArray<nsString>,
1414 let prop_id = parse_enabled_property_name!(prop_name, found, ());
1415 // Use B-tree set for unique and sorted result.
1416 let mut values = BTreeSet::<&'static str>::new();
1417 prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter()));
1419 let mut extras = vec![];
1420 if values.contains("transparent") {
1421 // This is a special value devtools use to avoid inserting the
1422 // long list of color keywords. We need to prepend it to values.
1423 extras.push("COLOR");
1426 let len = extras.len() + values.len();
1427 bindings::Gecko_ResizeTArrayForStrings(result, len as u32);
1429 for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) {
1430 dest.write_str(src).unwrap();
1435 pub extern "C" fn Servo_Property_IsAnimatable(prop: &structs::AnimatedPropertyID) -> bool {
1436 PropertyId::from_gecko_animated_property_id(prop).map_or(false, |p| p.is_animatable())
1440 pub extern "C" fn Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID) -> bool {
1441 match LonghandId::from_nscsspropertyid(property) {
1442 Some(longhand) => longhand.is_discrete_animatable(),
1443 None => return false,
1448 pub extern "C" fn Servo_Element_ClearData(element: &RawGeckoElement) {
1449 unsafe { GeckoElement(element).clear_data() };
1453 pub extern "C" fn Servo_Element_SizeOfExcludingThisAndCVs(
1454 malloc_size_of: GeckoMallocSizeOf,
1455 malloc_enclosing_size_of: GeckoMallocSizeOf,
1456 seen_ptrs: *mut SeenPtrs,
1457 element: &RawGeckoElement,
1459 let element = GeckoElement(element);
1460 let borrow = element.borrow_data();
1461 if let Some(data) = borrow {
1462 let have_seen_ptr = move |ptr| unsafe { Gecko_HaveSeenPtr(seen_ptrs, ptr) };
1463 let mut ops = MallocSizeOfOps::new(
1464 malloc_size_of.unwrap(),
1465 Some(malloc_enclosing_size_of.unwrap()),
1466 Some(Box::new(have_seen_ptr)),
1468 (*data).size_of_excluding_cvs(&mut ops)
1475 pub extern "C" fn Servo_Element_GetMaybeOutOfDateStyle(
1476 element: &RawGeckoElement,
1477 ) -> *const ComputedValues {
1478 let element = GeckoElement(element);
1479 let data = match element.borrow_data() {
1481 None => return ptr::null(),
1483 &**data.styles.primary() as *const _
1487 pub extern "C" fn Servo_Element_GetMaybeOutOfDatePseudoStyle(
1488 element: &RawGeckoElement,
1490 ) -> *const ComputedValues {
1491 let element = GeckoElement(element);
1492 let data = match element.borrow_data() {
1494 None => return ptr::null(),
1496 match data.styles.pseudos.as_array()[index].as_ref() {
1497 Some(style) => &**style as *const _,
1498 None => ptr::null(),
1503 pub extern "C" fn Servo_Element_IsDisplayNone(element: &RawGeckoElement) -> bool {
1504 let element = GeckoElement(element);
1507 .expect("Invoking Servo_Element_IsDisplayNone on unstyled element");
1509 // This function is hot, so we bypass the AtomicRefCell.
1511 // It would be nice to also assert that we're not in the servo traversal,
1512 // but this function is called at various intermediate checkpoints when
1513 // managing the traversal on the Gecko side.
1514 debug_assert!(is_main_thread());
1515 unsafe { &*data.as_ptr() }.styles.is_display_none()
1519 pub extern "C" fn Servo_Element_IsDisplayContents(element: &RawGeckoElement) -> bool {
1520 let element = GeckoElement(element);
1523 .expect("Invoking Servo_Element_IsDisplayContents on unstyled element");
1525 debug_assert!(is_main_thread());
1526 unsafe { &*data.as_ptr() }
1535 pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGeckoElement) -> bool {
1536 let element = GeckoElement(element);
1539 .expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element");
1541 .contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
1544 fn mode_to_origin(mode: SheetParsingMode) -> Origin {
1546 SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
1547 SheetParsingMode::eUserSheetFeatures => Origin::User,
1548 SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
1553 pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> Strong<StylesheetContents> {
1554 let global_style_data = &*GLOBAL_STYLE_DATA;
1555 let origin = mode_to_origin(mode);
1556 let shared_lock = &global_style_data.shared_lock;
1557 StylesheetContents::from_str(
1559 unsafe { dummy_url_data() }.clone(),
1562 /* loader = */ None,
1564 QuirksMode::NoQuirks,
1565 /* use_counters = */ None,
1566 AllowImportRules::Yes,
1567 /* sanitization_data = */ None,
1572 /// Note: The load_data corresponds to this sheet, and is passed as the parent
1573 /// load data for child sheet loads. It may be null for certain cases where we
1574 /// know we won't have child loads.
1576 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8Bytes(
1577 loader: *mut Loader,
1578 stylesheet: *mut DomStyleSheet,
1579 load_data: *mut SheetLoadData,
1581 mode: SheetParsingMode,
1582 extra_data: *mut URLExtraData,
1583 quirks_mode: nsCompatibility,
1584 reusable_sheets: *mut LoaderReusableStyleSheets,
1585 use_counters: Option<&UseCounters>,
1586 allow_import_rules: AllowImportRules,
1587 sanitization_kind: SanitizationKind,
1588 sanitized_output: Option<&mut nsAString>,
1589 ) -> Strong<StylesheetContents> {
1590 let global_style_data = &*GLOBAL_STYLE_DATA;
1591 let input = bytes.as_str_unchecked();
1593 let reporter = ErrorReporter::new(stylesheet, loader, extra_data);
1594 let url_data = UrlExtraData::from_ptr_ref(&extra_data);
1595 let loader = if loader.is_null() {
1599 sanitized_output.is_none(),
1600 "Shouldn't trigger @import loads for sanitization",
1602 Some(StylesheetLoader::new(
1610 // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
1611 let loader: Option<&dyn StyleStylesheetLoader> = match loader {
1613 Some(ref s) => Some(s),
1616 let mut sanitization_data = SanitizationData::new(sanitization_kind);
1618 let contents = StylesheetContents::from_str(
1621 mode_to_origin(mode),
1622 &global_style_data.shared_lock,
1624 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
1628 sanitization_data.as_mut(),
1631 if let Some(data) = sanitization_data {
1634 .assign_utf8(data.take().as_bytes());
1641 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
1642 load_data: *mut SheetLoadDataHolder,
1643 extra_data: *mut URLExtraData,
1645 mode: SheetParsingMode,
1646 quirks_mode: nsCompatibility,
1647 should_record_use_counters: bool,
1648 allow_import_rules: AllowImportRules,
1650 let load_data = RefPtr::new(load_data);
1651 let extra_data = UrlExtraData::new(extra_data);
1653 let mut sheet_bytes = nsCString::new();
1654 sheet_bytes.assign(bytes);
1656 let async_parser = AsyncStylesheetParser::new(
1660 mode_to_origin(mode),
1662 should_record_use_counters,
1666 if let Some(thread_pool) = STYLE_THREAD_POOL.pool().as_ref() {
1667 thread_pool.spawn(|| {
1668 gecko_profiler_label!(Layout, CSSParsing);
1669 async_parser.parse();
1672 async_parser.parse();
1677 pub unsafe extern "C" fn Servo_ShutdownThreadPool() {
1678 debug_assert!(is_main_thread() && !is_in_servo_traversal());
1679 StyleThreadPool::shutdown();
1683 pub unsafe extern "C" fn Servo_ThreadPool_GetThreadHandles(
1684 handles: &mut ThinVec<PlatformThreadHandle>,
1686 StyleThreadPool::get_thread_handles(handles);
1690 pub unsafe extern "C" fn Servo_StyleSheet_FromSharedData(
1691 extra_data: *mut URLExtraData,
1692 shared_rules: &LockedCssRules,
1693 ) -> Strong<StylesheetContents> {
1694 StylesheetContents::from_shared_data(
1695 Arc::from_raw_addrefed(shared_rules),
1697 UrlExtraData::new(extra_data),
1698 QuirksMode::NoQuirks,
1704 pub extern "C" fn Servo_StyleSet_AppendStyleSheet(
1705 raw_data: &PerDocumentStyleData,
1706 sheet: *const DomStyleSheet,
1708 let global_style_data = &*GLOBAL_STYLE_DATA;
1709 let mut data = raw_data.borrow_mut();
1710 let data = &mut *data;
1711 let guard = global_style_data.shared_lock.read();
1712 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1713 data.stylist.append_stylesheet(sheet, &guard);
1717 pub extern "C" fn Servo_AuthorStyles_Create() -> *mut AuthorStyles {
1718 Box::into_raw(Box::new(AuthorStyles::new()))
1722 pub unsafe extern "C" fn Servo_AuthorStyles_Drop(styles: *mut AuthorStyles) {
1723 let _ = Box::from_raw(styles);
1727 pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet(
1728 styles: &mut AuthorStyles,
1729 sheet: *const DomStyleSheet,
1731 let global_style_data = &*GLOBAL_STYLE_DATA;
1732 let guard = global_style_data.shared_lock.read();
1733 let sheet = GeckoStyleSheet::new(sheet);
1734 styles.stylesheets.append_stylesheet(None, sheet, &guard);
1738 pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore(
1739 styles: &mut AuthorStyles,
1740 sheet: *const DomStyleSheet,
1741 before_sheet: *const DomStyleSheet,
1743 let global_style_data = &*GLOBAL_STYLE_DATA;
1744 let guard = global_style_data.shared_lock.read();
1745 styles.stylesheets.insert_stylesheet_before(
1747 GeckoStyleSheet::new(sheet),
1748 GeckoStyleSheet::new(before_sheet),
1754 pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet(
1755 styles: &mut AuthorStyles,
1756 sheet: *const DomStyleSheet,
1758 let global_style_data = &*GLOBAL_STYLE_DATA;
1759 let guard = global_style_data.shared_lock.read();
1762 .remove_stylesheet(None, GeckoStyleSheet::new(sheet), &guard);
1766 pub extern "C" fn Servo_AuthorStyles_ForceDirty(styles: &mut AuthorStyles) {
1767 styles.stylesheets.force_dirty();
1771 pub extern "C" fn Servo_AuthorStyles_IsDirty(styles: &AuthorStyles) -> bool {
1772 styles.stylesheets.dirty()
1776 pub extern "C" fn Servo_AuthorStyles_Flush(
1777 styles: &mut AuthorStyles,
1778 document_set: &PerDocumentStyleData,
1780 // Try to avoid the atomic borrow below if possible.
1781 if !styles.stylesheets.dirty() {
1785 let global_style_data = &*GLOBAL_STYLE_DATA;
1786 let guard = global_style_data.shared_lock.read();
1788 let mut document_data = document_set.borrow_mut();
1790 // TODO(emilio): This is going to need an element or something to do proper
1791 // invalidation in Shadow roots.
1792 styles.flush::<GeckoElement>(&mut document_data.stylist, &guard);
1796 pub extern "C" fn Servo_StyleSet_RemoveUniqueEntriesFromAuthorStylesCache(
1797 document_set: &PerDocumentStyleData,
1799 let mut document_data = document_set.borrow_mut();
1802 .remove_unique_author_data_cache_entries();
1806 pub unsafe extern "C" fn Servo_DeclarationBlock_SizeOfIncludingThis(
1807 malloc_size_of: GeckoMallocSizeOf,
1808 malloc_enclosing_size_of: GeckoMallocSizeOf,
1809 declarations: &LockedDeclarationBlock,
1811 use malloc_size_of::MallocSizeOf;
1812 use malloc_size_of::MallocUnconditionalShallowSizeOf;
1814 let global_style_data = &*GLOBAL_STYLE_DATA;
1815 let guard = global_style_data.shared_lock.read();
1817 let mut ops = MallocSizeOfOps::new(
1818 malloc_size_of.unwrap(),
1819 Some(malloc_enclosing_size_of.unwrap()),
1823 ArcBorrow::from_ref(declarations).with_arc(|declarations| {
1825 n += declarations.unconditional_shallow_size_of(&mut ops);
1826 n += declarations.read_with(&guard).size_of(&mut ops);
1832 pub unsafe extern "C" fn Servo_AuthorStyles_SizeOfIncludingThis(
1833 malloc_size_of: GeckoMallocSizeOf,
1834 malloc_enclosing_size_of: GeckoMallocSizeOf,
1835 styles: &AuthorStyles,
1837 // We cannot `use` MallocSizeOf at the top level, otherwise the compiler
1838 // would complain in `Servo_StyleSheet_SizeOfIncludingThis` for `size_of`
1840 use malloc_size_of::MallocSizeOf;
1841 let malloc_size_of = malloc_size_of.unwrap();
1842 let malloc_size_of_this = malloc_size_of(styles as *const AuthorStyles as *const c_void);
1844 let mut ops = MallocSizeOfOps::new(
1846 Some(malloc_enclosing_size_of.unwrap()),
1849 malloc_size_of_this + styles.size_of(&mut ops)
1853 pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged(
1854 document_set: &PerDocumentStyleData,
1855 non_document_styles: &mut nsTArray<&mut AuthorStyles>,
1856 may_affect_default_style: bool,
1857 ) -> structs::MediumFeaturesChangedResult {
1858 let global_style_data = &*GLOBAL_STYLE_DATA;
1859 let guard = global_style_data.shared_lock.read();
1861 // NOTE(emilio): We don't actually need to flush the stylist here and ensure
1864 // In case it isn't we would trigger a rebuild + restyle as needed too.
1866 // We need to ensure the default computed values are up to date though,
1867 // because those can influence the result of media query evaluation.
1868 let mut document_data = document_set.borrow_mut();
1870 if may_affect_default_style {
1871 document_data.stylist.device_mut().reset_computed_values();
1873 let guards = StylesheetGuards::same(&guard);
1875 let origins_in_which_rules_changed = document_data
1877 .media_features_change_changed_style(&guards, document_data.stylist.device());
1879 let affects_document_rules = !origins_in_which_rules_changed.is_empty();
1880 if affects_document_rules {
1883 .force_stylesheet_origins_dirty(origins_in_which_rules_changed);
1886 let mut affects_non_document_rules = false;
1887 for author_styles in &mut **non_document_styles {
1888 let affected_style = author_styles.stylesheets.iter().any(|sheet| {
1889 !author_styles.data.media_feature_affected_matches(
1892 document_data.stylist.device(),
1893 document_data.stylist.quirks_mode(),
1897 affects_non_document_rules = true;
1898 author_styles.stylesheets.force_dirty();
1902 structs::MediumFeaturesChangedResult {
1903 mAffectsDocumentRules: affects_document_rules,
1904 mAffectsNonDocumentRules: affects_non_document_rules,
1909 pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(
1910 raw_data: &PerDocumentStyleData,
1911 sheet: *const DomStyleSheet,
1912 before_sheet: *const DomStyleSheet,
1914 let global_style_data = &*GLOBAL_STYLE_DATA;
1915 let mut data = raw_data.borrow_mut();
1916 let data = &mut *data;
1917 let guard = global_style_data.shared_lock.read();
1918 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1919 data.stylist.insert_stylesheet_before(
1921 unsafe { GeckoStyleSheet::new(before_sheet) },
1927 pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(
1928 raw_data: &PerDocumentStyleData,
1929 sheet: *const DomStyleSheet,
1931 let global_style_data = &*GLOBAL_STYLE_DATA;
1932 let mut data = raw_data.borrow_mut();
1933 let data = &mut *data;
1934 let guard = global_style_data.shared_lock.read();
1935 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1936 data.stylist.remove_stylesheet(sheet, &guard);
1940 pub unsafe extern "C" fn Servo_StyleSet_GetSheetAt(
1941 raw_data: &PerDocumentStyleData,
1944 ) -> *const DomStyleSheet {
1945 let data = raw_data.borrow();
1947 .sheet_at(origin, index)
1948 .map_or(ptr::null(), |s| s.raw())
1952 pub unsafe extern "C" fn Servo_StyleSet_GetSheetCount(
1953 raw_data: &PerDocumentStyleData,
1956 let data = raw_data.borrow();
1957 data.stylist.sheet_count(origin)
1961 pub unsafe extern "C" fn Servo_StyleSet_FlushStyleSheets(
1962 raw_data: &PerDocumentStyleData,
1963 doc_element: Option<&RawGeckoElement>,
1964 snapshots: *const ServoElementSnapshotTable,
1966 let global_style_data = &*GLOBAL_STYLE_DATA;
1967 let guard = global_style_data.shared_lock.read();
1968 let mut data = raw_data.borrow_mut();
1969 let doc_element = doc_element.map(GeckoElement);
1971 let have_invalidations = data.flush_stylesheets(&guard, doc_element, snapshots.as_ref());
1973 if have_invalidations && doc_element.is_some() {
1974 // The invalidation machinery propagates the bits up, but we still need
1975 // to tell the Gecko restyle root machinery about it.
1976 bindings::Gecko_NoteDirtySubtreeForInvalidation(doc_element.unwrap().0);
1981 pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(
1982 raw_data: &PerDocumentStyleData,
1983 changed_origins: OriginFlags,
1985 let mut data = raw_data.borrow_mut();
1987 .force_stylesheet_origins_dirty(OriginSet::from(changed_origins));
1991 pub extern "C" fn Servo_StyleSet_SetAuthorStyleDisabled(
1992 raw_data: &PerDocumentStyleData,
1993 author_style_disabled: bool,
1995 let mut data = raw_data.borrow_mut();
1996 let enabled = if author_style_disabled {
1997 AuthorStylesEnabled::No
1999 AuthorStylesEnabled::Yes
2001 data.stylist.set_author_styles_enabled(enabled);
2005 pub extern "C" fn Servo_StyleSet_UsesFontMetrics(raw_data: &PerDocumentStyleData) -> bool {
2006 let doc_data = raw_data;
2007 doc_data.borrow().stylist.device().used_font_metrics()
2011 pub extern "C" fn Servo_StyleSheet_HasRules(raw_contents: &StylesheetContents) -> bool {
2012 let global_style_data = &*GLOBAL_STYLE_DATA;
2013 let guard = global_style_data.shared_lock.read();
2014 !raw_contents.rules.read_with(&guard).0.is_empty()
2018 pub extern "C" fn Servo_StyleSheet_GetRules(sheet: &StylesheetContents) -> Strong<LockedCssRules> {
2019 sheet.rules.clone().into()
2023 pub extern "C" fn Servo_StyleSheet_Clone(
2024 contents: &StylesheetContents,
2025 reference_sheet: *const DomStyleSheet,
2026 ) -> Strong<StylesheetContents> {
2027 use style::shared_lock::{DeepCloneParams, DeepCloneWithLock};
2028 let global_style_data = &*GLOBAL_STYLE_DATA;
2029 let guard = global_style_data.shared_lock.read();
2030 let params = DeepCloneParams { reference_sheet };
2032 Arc::new(contents.deep_clone_with_lock(&global_style_data.shared_lock, &guard, ¶ms)).into()
2036 pub extern "C" fn Servo_StyleSheet_SizeOfIncludingThis(
2037 malloc_size_of: GeckoMallocSizeOf,
2038 malloc_enclosing_size_of: GeckoMallocSizeOf,
2039 sheet: &StylesheetContents,
2041 let global_style_data = &*GLOBAL_STYLE_DATA;
2042 let guard = global_style_data.shared_lock.read();
2043 let mut ops = MallocSizeOfOps::new(
2044 malloc_size_of.unwrap(),
2045 Some(malloc_enclosing_size_of.unwrap()),
2048 // TODO(emilio): We're not measuring the size of the Arc<StylesheetContents>
2049 // allocation itself here.
2050 sheet.size_of(&guard, &mut ops)
2054 pub extern "C" fn Servo_StyleSheet_GetOrigin(sheet: &StylesheetContents) -> Origin {
2059 pub extern "C" fn Servo_StyleSheet_GetSourceMapURL(
2060 contents: &StylesheetContents,
2061 result: &mut nsACString,
2063 let url_opt = contents.source_map_url.read();
2064 if let Some(ref url) = *url_opt {
2070 pub extern "C" fn Servo_StyleSheet_GetSourceURL(
2071 contents: &StylesheetContents,
2072 result: &mut nsACString,
2074 let url_opt = contents.source_url.read();
2075 if let Some(ref url) = *url_opt {
2080 fn with_maybe_worker_shared_lock<R>(func: impl FnOnce(&SharedRwLock) -> R) -> R {
2081 if is_dom_worker_thread() {
2082 DOM_WORKER_RWLOCK.with(func)
2084 func(&GLOBAL_STYLE_DATA.shared_lock)
2088 fn read_locked_arc<T, R, F>(raw: &Locked<T>, func: F) -> R
2092 debug_assert!(!is_dom_worker_thread());
2093 let global_style_data = &*GLOBAL_STYLE_DATA;
2094 let guard = global_style_data.shared_lock.read();
2095 func(raw.read_with(&guard))
2098 fn read_locked_arc_worker<T, R, F>(raw: &Locked<T>, func: F) -> R
2102 with_maybe_worker_shared_lock(|lock| {
2103 let guard = lock.read();
2104 func(raw.read_with(&guard))
2108 #[cfg(debug_assertions)]
2109 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &Locked<T>, func: F) -> R
2113 debug_assert!(is_main_thread() && !is_in_servo_traversal());
2114 read_locked_arc(raw, func)
2117 #[cfg(not(debug_assertions))]
2118 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &Locked<T>, func: F) -> R
2122 debug_assert!(!is_dom_worker_thread());
2123 func(raw.read_unchecked())
2126 fn write_locked_arc<T, R, F>(raw: &Locked<T>, func: F) -> R
2128 F: FnOnce(&mut T) -> R,
2130 debug_assert!(!is_dom_worker_thread());
2131 let global_style_data = &*GLOBAL_STYLE_DATA;
2132 let mut guard = global_style_data.shared_lock.write();
2133 func(raw.write_with(&mut guard))
2136 fn write_locked_arc_worker<T, R, F>(raw: &Locked<T>, func: F) -> R
2138 F: FnOnce(&mut T) -> R,
2140 with_maybe_worker_shared_lock(|lock| {
2141 let mut guard = lock.write();
2142 func(raw.write_with(&mut guard))
2147 pub extern "C" fn Servo_CssRules_ListTypes(rules: &LockedCssRules, result: &mut nsTArray<usize>) {
2148 read_locked_arc(rules, |rules: &CssRules| {
2149 result.assign_from_iter_pod(rules.0.iter().map(|rule| rule.rule_type() as usize));
2154 pub extern "C" fn Servo_CssRules_InsertRule(
2155 rules: &LockedCssRules,
2156 contents: &StylesheetContents,
2159 containing_rule_types: u32,
2160 loader: *mut Loader,
2161 allow_import_rules: AllowImportRules,
2162 gecko_stylesheet: *mut DomStyleSheet,
2163 rule_type: &mut CssRuleType,
2165 let loader = if loader.is_null() {
2168 Some(StylesheetLoader::new(
2177 .map(|loader| loader as &dyn StyleStylesheetLoader);
2178 let rule = unsafe { rule.as_str_unchecked() };
2180 let global_style_data = &*GLOBAL_STYLE_DATA;
2181 let result = rules.insert_rule(
2182 &global_style_data.shared_lock,
2186 CssRuleTypes::from_bits(containing_rule_types),
2193 *rule_type = new_rule.rule_type();
2196 Err(err) => err.into(),
2201 pub extern "C" fn Servo_CssRules_DeleteRule(rules: &LockedCssRules, index: u32) -> nsresult {
2202 write_locked_arc(rules, |rules: &mut CssRules| {
2203 match rules.remove_rule(index as usize) {
2204 Ok(_) => nsresult::NS_OK,
2205 Err(err) => err.into(),
2210 trait MaybeLocked<Target> {
2211 fn maybe_locked_read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a Target;
2214 impl<T> MaybeLocked<T> for T {
2215 fn maybe_locked_read<'a>(&'a self, _: &'a SharedRwLockReadGuard) -> &'a T {
2220 impl<T> MaybeLocked<T> for Locked<T> {
2221 fn maybe_locked_read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
2222 self.read_with(guard)
2226 macro_rules! impl_basic_rule_funcs_without_getter {
2228 ($rule_type:ty, $maybe_locked_rule_type:ty),
2229 debug: $debug:ident,
2230 to_css: $to_css:ident,
2232 #[cfg(debug_assertions)]
2234 pub extern "C" fn $debug(rule: &$maybe_locked_rule_type, result: &mut nsACString) {
2235 let global_style_data = &*GLOBAL_STYLE_DATA;
2236 let guard = global_style_data.shared_lock.read();
2237 let rule: &$rule_type = rule.maybe_locked_read(&guard);
2238 write!(result, "{:?}", *rule).unwrap();
2241 #[cfg(not(debug_assertions))]
2243 pub extern "C" fn $debug(_: &$maybe_locked_rule_type, _: &mut nsACString) {
2248 pub extern "C" fn $to_css(rule: &$maybe_locked_rule_type, result: &mut nsACString) {
2249 let global_style_data = &*GLOBAL_STYLE_DATA;
2250 let guard = global_style_data.shared_lock.read();
2251 let rule: &$rule_type = rule.maybe_locked_read(&guard);
2252 rule.to_css(&guard, result).unwrap();
2257 macro_rules! impl_basic_rule_funcs {
2258 { ($name:ident, $rule_type:ty, $maybe_locked_rule_type:ty),
2259 getter: $getter:ident,
2260 debug: $debug:ident,
2261 to_css: $to_css:ident,
2262 changed: $changed:ident,
2265 pub extern "C" fn $getter(
2266 rules: &LockedCssRules,
2270 ) -> Strong<$maybe_locked_rule_type> {
2271 let global_style_data = &*GLOBAL_STYLE_DATA;
2272 let guard = global_style_data.shared_lock.read();
2273 let rules = rules.read_with(&guard);
2274 let index = index as usize;
2276 if index >= rules.0.len() {
2277 return Strong::null();
2280 match rules.0[index] {
2281 CssRule::$name(ref arc) => {
2282 let rule: &$rule_type = (&**arc).maybe_locked_read(&guard);
2283 let location = rule.source_location;
2284 *line = location.line as u32;
2285 *column = location.column as u32;
2295 pub extern "C" fn $changed(
2296 styleset: &PerDocumentStyleData,
2297 rule: &$maybe_locked_rule_type,
2298 sheet: &DomStyleSheet,
2299 change_kind: RuleChangeKind,
2301 let mut data = styleset.borrow_mut();
2302 let data = &mut *data;
2303 let global_style_data = &*GLOBAL_STYLE_DATA;
2304 let guard = global_style_data.shared_lock.read();
2305 // TODO(emilio): Would be nice not to deal with refcount bumps here,
2306 // but it's probably not a huge deal.
2307 let rule = unsafe { CssRule::$name(Arc::from_raw_addrefed(rule)) };
2308 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
2309 data.stylist.rule_changed(&sheet, &rule, &guard, change_kind);
2312 impl_basic_rule_funcs_without_getter! {
2313 ($rule_type, $maybe_locked_rule_type),
2320 macro_rules! impl_group_rule_funcs {
2321 { ($name:ident, $rule_type:ty, $maybe_locked_rule_type:ty),
2322 get_rules: $get_rules:ident,
2325 impl_basic_rule_funcs! { ($name, $rule_type, $maybe_locked_rule_type), $($basic)+ }
2328 pub extern "C" fn $get_rules(rule: &$maybe_locked_rule_type) -> Strong<LockedCssRules> {
2329 let global_style_data = &*GLOBAL_STYLE_DATA;
2330 let guard = global_style_data.shared_lock.read();
2331 let rule: &$rule_type = rule.maybe_locked_read(&guard);
2332 rule.rules.clone().into()
2337 impl_basic_rule_funcs! { (Style, StyleRule, Locked<StyleRule>),
2338 getter: Servo_CssRules_GetStyleRuleAt,
2339 debug: Servo_StyleRule_Debug,
2340 to_css: Servo_StyleRule_GetCssText,
2341 changed: Servo_StyleSet_StyleRuleChanged,
2345 pub extern "C" fn Servo_StyleRule_EnsureRules(
2346 rule: &LockedStyleRule,
2348 ) -> Strong<LockedCssRules> {
2349 let global_style_data = &*GLOBAL_STYLE_DATA;
2350 let lock = &global_style_data.shared_lock;
2352 let guard = lock.read();
2353 if let Some(ref rules) = rule.read_with(&guard).rules {
2354 return rules.clone().into();
2356 return CssRules::new(vec![], lock).into();
2358 let mut guard = lock.write();
2359 rule.write_with(&mut guard)
2361 .get_or_insert_with(|| CssRules::new(vec![], lock))
2366 impl_basic_rule_funcs! { (Import, ImportRule, Locked<ImportRule>),
2367 getter: Servo_CssRules_GetImportRuleAt,
2368 debug: Servo_ImportRule_Debug,
2369 to_css: Servo_ImportRule_GetCssText,
2370 changed: Servo_StyleSet_ImportRuleChanged,
2373 impl_basic_rule_funcs_without_getter! { (Keyframe, Locked<Keyframe>),
2374 debug: Servo_Keyframe_Debug,
2375 to_css: Servo_Keyframe_GetCssText,
2378 impl_basic_rule_funcs! { (Keyframes, KeyframesRule, Locked<KeyframesRule>),
2379 getter: Servo_CssRules_GetKeyframesRuleAt,
2380 debug: Servo_KeyframesRule_Debug,
2381 to_css: Servo_KeyframesRule_GetCssText,
2382 changed: Servo_StyleSet_KeyframesRuleChanged,
2385 impl_group_rule_funcs! { (Media, MediaRule, MediaRule),
2386 get_rules: Servo_MediaRule_GetRules,
2387 getter: Servo_CssRules_GetMediaRuleAt,
2388 debug: Servo_MediaRule_Debug,
2389 to_css: Servo_MediaRule_GetCssText,
2390 changed: Servo_StyleSet_MediaRuleChanged,
2393 impl_basic_rule_funcs! { (Namespace, NamespaceRule, NamespaceRule),
2394 getter: Servo_CssRules_GetNamespaceRuleAt,
2395 debug: Servo_NamespaceRule_Debug,
2396 to_css: Servo_NamespaceRule_GetCssText,
2397 changed: Servo_StyleSet_NamespaceRuleChanged,
2400 impl_basic_rule_funcs! { (Page, PageRule, Locked<PageRule>),
2401 getter: Servo_CssRules_GetPageRuleAt,
2402 debug: Servo_PageRule_Debug,
2403 to_css: Servo_PageRule_GetCssText,
2404 changed: Servo_StyleSet_PageRuleChanged,
2407 impl_basic_rule_funcs! { (Property, PropertyRule, PropertyRule),
2408 getter: Servo_CssRules_GetPropertyRuleAt,
2409 debug: Servo_PropertyRule_Debug,
2410 to_css: Servo_PropertyRule_GetCssText,
2411 changed: Servo_StyleSet_PropertyRuleChanged,
2414 impl_group_rule_funcs! { (Supports, SupportsRule, SupportsRule),
2415 get_rules: Servo_SupportsRule_GetRules,
2416 getter: Servo_CssRules_GetSupportsRuleAt,
2417 debug: Servo_SupportsRule_Debug,
2418 to_css: Servo_SupportsRule_GetCssText,
2419 changed: Servo_StyleSet_SupportsRuleChanged,
2422 impl_group_rule_funcs! { (Container, ContainerRule, ContainerRule),
2423 get_rules: Servo_ContainerRule_GetRules,
2424 getter: Servo_CssRules_GetContainerRuleAt,
2425 debug: Servo_ContainerRule_Debug,
2426 to_css: Servo_ContainerRule_GetCssText,
2427 changed: Servo_StyleSet_ContainerRuleChanged,
2430 impl_group_rule_funcs! { (LayerBlock, LayerBlockRule, LayerBlockRule),
2431 get_rules: Servo_LayerBlockRule_GetRules,
2432 getter: Servo_CssRules_GetLayerBlockRuleAt,
2433 debug: Servo_LayerBlockRule_Debug,
2434 to_css: Servo_LayerBlockRule_GetCssText,
2435 changed: Servo_StyleSet_LayerBlockRuleChanged,
2438 impl_basic_rule_funcs! { (LayerStatement, LayerStatementRule, LayerStatementRule),
2439 getter: Servo_CssRules_GetLayerStatementRuleAt,
2440 debug: Servo_LayerStatementRule_Debug,
2441 to_css: Servo_LayerStatementRule_GetCssText,
2442 changed: Servo_StyleSet_LayerStatementRuleChanged,
2445 impl_group_rule_funcs! { (Document, DocumentRule, DocumentRule),
2446 get_rules: Servo_DocumentRule_GetRules,
2447 getter: Servo_CssRules_GetDocumentRuleAt,
2448 debug: Servo_DocumentRule_Debug,
2449 to_css: Servo_DocumentRule_GetCssText,
2450 changed: Servo_StyleSet_DocumentRuleChanged,
2453 impl_basic_rule_funcs! { (FontFeatureValues, FontFeatureValuesRule, FontFeatureValuesRule),
2454 getter: Servo_CssRules_GetFontFeatureValuesRuleAt,
2455 debug: Servo_FontFeatureValuesRule_Debug,
2456 to_css: Servo_FontFeatureValuesRule_GetCssText,
2457 changed: Servo_StyleSet_FontFeatureValuesRuleChanged,
2460 impl_basic_rule_funcs! { (FontPaletteValues, FontPaletteValuesRule, FontPaletteValuesRule),
2461 getter: Servo_CssRules_GetFontPaletteValuesRuleAt,
2462 debug: Servo_FontPaletteValuesRule_Debug,
2463 to_css: Servo_FontPaletteValuesRule_GetCssText,
2464 changed: Servo_StyleSet_FontPaletteValuesRuleChanged,
2467 impl_basic_rule_funcs! { (FontFace, FontFaceRule, Locked<FontFaceRule>),
2468 getter: Servo_CssRules_GetFontFaceRuleAt,
2469 debug: Servo_FontFaceRule_Debug,
2470 to_css: Servo_FontFaceRule_GetCssText,
2471 changed: Servo_StyleSet_FontFaceRuleChanged,
2474 impl_basic_rule_funcs! { (CounterStyle, CounterStyleRule, Locked<CounterStyleRule>),
2475 getter: Servo_CssRules_GetCounterStyleRuleAt,
2476 debug: Servo_CounterStyleRule_Debug,
2477 to_css: Servo_CounterStyleRule_GetCssText,
2478 changed: Servo_StyleSet_CounterStyleRuleChanged,
2482 pub extern "C" fn Servo_StyleRule_GetStyle(
2483 rule: &LockedStyleRule,
2484 ) -> Strong<LockedDeclarationBlock> {
2485 read_locked_arc(rule, |rule: &StyleRule| rule.block.clone().into())
2489 pub extern "C" fn Servo_StyleRule_SetStyle(
2490 rule: &LockedStyleRule,
2491 declarations: &LockedDeclarationBlock,
2493 write_locked_arc(rule, |rule: &mut StyleRule| {
2494 rule.block = unsafe { Arc::from_raw_addrefed(declarations) };
2499 pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: &LockedStyleRule, result: &mut nsACString) {
2500 read_locked_arc(rule, |rule| rule.selectors.to_css(result).unwrap());
2503 fn desugared_selector_list(rules: &ThinVec<&LockedStyleRule>) -> SelectorList {
2504 let mut selectors: Option<SelectorList> = None;
2505 for rule in rules.iter().rev() {
2506 selectors = Some(read_locked_arc(rule, |rule| match selectors {
2507 Some(ref s) => rule.selectors.replace_parent_selector(s),
2508 None => rule.selectors.clone(),
2511 selectors.expect("Empty rule chain?")
2515 pub extern "C" fn Servo_StyleRule_GetSelectorDataAtIndex(
2516 rules: &ThinVec<&LockedStyleRule>,
2518 text: Option<&mut nsACString>,
2519 specificity: Option<&mut u64>,
2521 let selectors = desugared_selector_list(rules);
2522 let Some(selector) = selectors.slice().get(index as usize) else {
2525 if let Some(text) = text {
2526 selector.to_css(text).unwrap();
2528 if let Some(specificity) = specificity {
2529 *specificity = selector.specificity() as u64;
2534 pub extern "C" fn Servo_StyleRule_GetSelectorCount(rule: &LockedStyleRule) -> u32 {
2535 read_locked_arc(rule, |rule| rule.selectors.len() as u32)
2539 pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(
2540 rules: &ThinVec<&LockedStyleRule>,
2541 element: &RawGeckoElement,
2543 host: Option<&RawGeckoElement>,
2544 pseudo_type: PseudoStyleType,
2545 relevant_link_visited: bool,
2547 use selectors::matching::{
2548 matches_selector, MatchingContext, MatchingMode, NeedsSelectorFlags, VisitedHandlingMode,
2550 let selectors = desugared_selector_list(rules);
2551 let Some(selector) = selectors.slice().get(index as usize) else {
2554 let mut matching_mode = MatchingMode::Normal;
2555 match PseudoElement::from_pseudo_type(pseudo_type, None) {
2557 // We need to make sure that the requested pseudo element type
2558 // matches the selector pseudo element type before proceeding.
2559 match selector.pseudo_element() {
2560 Some(selector_pseudo) if *selector_pseudo == pseudo => {
2561 matching_mode = MatchingMode::ForStatelessPseudoElement
2567 // Do not attempt to match if a pseudo element is requested and
2568 // this is not a pseudo element selector, or vice versa.
2569 if selector.has_pseudo_element() {
2575 let element = GeckoElement(element);
2576 let host = host.map(GeckoElement);
2577 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2578 let mut selector_caches = SelectorCaches::default();
2579 let visited_mode = if relevant_link_visited {
2580 VisitedHandlingMode::RelevantLinkVisited
2582 VisitedHandlingMode::AllLinksUnvisited
2584 let mut ctx = MatchingContext::new_for_visited(
2586 /* bloom_filter = */ None,
2587 &mut selector_caches,
2590 NeedsSelectorFlags::No,
2591 MatchingForInvalidation::No,
2593 ctx.with_shadow_host(host, |ctx| {
2594 matches_selector(selector, 0, None, &element, ctx)
2598 pub type SelectorList = selectors::SelectorList<style::gecko::selector_parser::SelectorImpl>;
2601 pub extern "C" fn Servo_StyleRule_SetSelectorText(
2602 contents: &StylesheetContents,
2603 rule: &LockedStyleRule,
2606 let value_str = unsafe { text.as_str_unchecked() };
2608 write_locked_arc(rule, |rule: &mut StyleRule| {
2609 use selectors::parser::ParseRelative;
2610 use style::selector_parser::SelectorParser;
2612 let namespaces = contents.namespaces.read();
2613 let url_data = contents.url_data.read();
2614 let parser = SelectorParser {
2615 stylesheet_origin: contents.origin,
2616 namespaces: &namespaces,
2617 url_data: &url_data,
2618 for_supports_rule: false,
2621 // TODO: Maybe allow setting relative selectors from the OM, if we're in a nested style
2623 let mut parser_input = ParserInput::new(&value_str);
2624 match SelectorList::parse(
2626 &mut Parser::new(&mut parser_input),
2630 rule.selectors = selectors;
2639 pub unsafe extern "C" fn Servo_SelectorList_Closest(
2640 element: &RawGeckoElement,
2641 selectors: &SelectorList,
2642 ) -> *const RawGeckoElement {
2643 use style::dom_apis;
2645 let element = GeckoElement(element);
2646 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2647 dom_apis::element_closest(element, &selectors, quirks_mode).map_or(ptr::null(), |e| e.0)
2651 pub unsafe extern "C" fn Servo_SelectorList_Matches(
2652 element: &RawGeckoElement,
2653 selectors: &SelectorList,
2655 use style::dom_apis;
2657 let element = GeckoElement(element);
2658 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2659 dom_apis::element_matches(&element, &selectors, quirks_mode)
2663 pub unsafe extern "C" fn Servo_SelectorList_QueryFirst(
2664 node: &RawGeckoNode,
2665 selectors: &SelectorList,
2666 may_use_invalidation: bool,
2667 ) -> *const RawGeckoElement {
2668 use style::dom_apis::{self, MayUseInvalidation, QueryFirst};
2670 let node = GeckoNode(node);
2671 let mut result = None;
2673 let may_use_invalidation = if may_use_invalidation {
2674 MayUseInvalidation::Yes
2676 MayUseInvalidation::No
2679 dom_apis::query_selector::<GeckoElement, QueryFirst>(
2683 may_use_invalidation,
2686 result.map_or(ptr::null(), |e| e.0)
2690 pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
2691 node: &RawGeckoNode,
2692 selectors: &SelectorList,
2693 content_list: *mut structs::nsSimpleContentList,
2694 may_use_invalidation: bool,
2696 use style::dom_apis::{self, MayUseInvalidation, QueryAll};
2698 let node = GeckoNode(node);
2699 let mut result = SmallVec::new();
2701 let may_use_invalidation = if may_use_invalidation {
2702 MayUseInvalidation::Yes
2704 MayUseInvalidation::No
2707 dom_apis::query_selector::<GeckoElement, QueryAll>(
2711 may_use_invalidation,
2714 if !result.is_empty() {
2715 // NOTE(emilio): This relies on a slice of GeckoElement having the same
2716 // memory representation than a slice of element pointers.
2717 bindings::Gecko_ContentList_AppendAll(
2719 result.as_ptr() as *mut *const _,
2726 pub extern "C" fn Servo_ImportRule_GetHref(rule: &LockedImportRule, result: &mut nsAString) {
2727 read_locked_arc(rule, |rule: &ImportRule| {
2728 write!(result, "{}", rule.url.as_str()).unwrap();
2733 pub extern "C" fn Servo_ImportRule_GetLayerName(rule: &LockedImportRule, result: &mut nsACString) {
2734 // https://w3c.github.io/csswg-drafts/cssom/#dom-cssimportrule-layername
2735 read_locked_arc(rule, |rule: &ImportRule| match rule.layer {
2736 ImportLayer::Named(ref name) => name.to_css(&mut CssWriter::new(result)).unwrap(), // "return the layer name declared in the at-rule itself"
2737 ImportLayer::Anonymous => {}, // "or an empty string if the layer is anonymous"
2738 ImportLayer::None => result.set_is_void(true), // "or null if the at-rule does not declare a layer"
2743 pub extern "C" fn Servo_ImportRule_GetSupportsText(
2744 rule: &LockedImportRule,
2745 result: &mut nsACString,
2747 read_locked_arc(rule, |rule: &ImportRule| match rule.supports {
2748 Some(ref supports) => supports
2750 .to_css(&mut CssWriter::new(result))
2752 None => result.set_is_void(true),
2757 pub extern "C" fn Servo_ImportRule_GetSheet(rule: &LockedImportRule) -> *const DomStyleSheet {
2758 read_locked_arc(rule, |rule: &ImportRule| {
2761 .map_or(ptr::null(), |s| s.raw() as *const DomStyleSheet)
2766 pub unsafe extern "C" fn Servo_ImportRule_SetSheet(
2767 rule: &LockedImportRule,
2768 sheet: *mut DomStyleSheet,
2770 write_locked_arc(rule, |rule: &mut ImportRule| {
2771 rule.stylesheet = ImportSheet::new(GeckoStyleSheet::new(sheet));
2776 pub extern "C" fn Servo_Keyframe_GetKeyText(keyframe: &LockedKeyframe, result: &mut nsACString) {
2777 read_locked_arc(keyframe, |keyframe: &Keyframe| {
2780 .to_css(&mut CssWriter::new(result))
2786 pub extern "C" fn Servo_Keyframe_SetKeyText(keyframe: &LockedKeyframe, text: &nsACString) -> bool {
2787 let text = unsafe { text.as_str_unchecked() };
2788 let mut input = ParserInput::new(&text);
2789 if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
2790 write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2791 keyframe.selector = selector;
2800 pub extern "C" fn Servo_Keyframe_GetStyle(
2801 keyframe: &LockedKeyframe,
2802 ) -> Strong<LockedDeclarationBlock> {
2803 read_locked_arc(keyframe, |keyframe: &Keyframe| {
2804 keyframe.block.clone().into()
2809 pub extern "C" fn Servo_Keyframe_SetStyle(
2810 keyframe: &LockedKeyframe,
2811 declarations: &LockedDeclarationBlock,
2813 write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2814 keyframe.block = unsafe { Arc::from_raw_addrefed(declarations) };
2819 pub extern "C" fn Servo_KeyframesRule_GetName(rule: &LockedKeyframesRule) -> *mut nsAtom {
2820 read_locked_arc(rule, |rule: &KeyframesRule| rule.name.as_atom().as_ptr())
2824 pub unsafe extern "C" fn Servo_KeyframesRule_SetName(
2825 rule: &LockedKeyframesRule,
2828 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2829 rule.name = KeyframesName::from_atom(Atom::from_addrefed(name));
2834 pub extern "C" fn Servo_KeyframesRule_GetCount(rule: &LockedKeyframesRule) -> u32 {
2835 read_locked_arc(rule, |rule: &KeyframesRule| rule.keyframes.len() as u32)
2839 pub extern "C" fn Servo_KeyframesRule_GetKeyframeAt(
2840 rule: &LockedKeyframesRule,
2844 ) -> Strong<LockedKeyframe> {
2845 let global_style_data = &*GLOBAL_STYLE_DATA;
2846 let guard = global_style_data.shared_lock.read();
2847 let key = rule.read_with(&guard).keyframes[index as usize].clone();
2848 let location = key.read_with(&guard).source_location;
2849 *line = location.line as u32;
2850 *column = location.column as u32;
2855 pub extern "C" fn Servo_KeyframesRule_FindRule(
2856 rule: &LockedKeyframesRule,
2859 let key = unsafe { key.as_str_unchecked() };
2860 let global_style_data = &*GLOBAL_STYLE_DATA;
2861 let guard = global_style_data.shared_lock.read();
2862 rule.read_with(&guard)
2863 .find_rule(&guard, key)
2864 .map(|index| index as u32)
2865 .unwrap_or(u32::max_value())
2869 pub extern "C" fn Servo_KeyframesRule_AppendRule(
2870 rule: &LockedKeyframesRule,
2871 contents: &StylesheetContents,
2874 let css = unsafe { css.as_str_unchecked() };
2875 let global_style_data = &*GLOBAL_STYLE_DATA;
2877 match Keyframe::parse(css, &contents, &global_style_data.shared_lock) {
2879 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2880 rule.keyframes.push(keyframe);
2889 pub extern "C" fn Servo_KeyframesRule_DeleteRule(rule: &LockedKeyframesRule, index: u32) {
2890 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2891 rule.keyframes.remove(index as usize);
2896 pub extern "C" fn Servo_MediaRule_GetMedia(rule: &MediaRule) -> Strong<LockedMediaList> {
2897 rule.media_queries.clone().into()
2901 pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: &NamespaceRule) -> *mut nsAtom {
2904 .map_or(atom!("").as_ptr(), |a| a.as_ptr())
2908 pub extern "C" fn Servo_NamespaceRule_GetURI(rule: &NamespaceRule) -> *mut nsAtom {
2913 pub extern "C" fn Servo_PageRule_GetStyle(rule: &LockedPageRule) -> Strong<LockedDeclarationBlock> {
2914 read_locked_arc(rule, |rule: &PageRule| rule.block.clone().into())
2918 pub extern "C" fn Servo_PageRule_SetStyle(
2919 rule: &LockedPageRule,
2920 declarations: &LockedDeclarationBlock,
2922 write_locked_arc(rule, |rule: &mut PageRule| {
2923 rule.block = unsafe { Arc::from_raw_addrefed(declarations) };
2928 pub extern "C" fn Servo_PageRule_GetSelectorText(rule: &LockedPageRule, result: &mut nsACString) {
2929 read_locked_arc(rule, |rule: &PageRule| {
2930 rule.selectors.to_css(&mut CssWriter::new(result)).unwrap();
2935 pub extern "C" fn Servo_PageRule_SetSelectorText(
2936 contents: &StylesheetContents,
2937 rule: &LockedPageRule,
2940 let value_str = unsafe { text.as_str_unchecked() };
2942 write_locked_arc(rule, |rule: &mut PageRule| {
2943 use style::stylesheets::PageSelectors;
2945 let mut parser_input = ParserInput::new(&value_str);
2946 let mut parser = Parser::new(&mut parser_input);
2948 // Ensure that a blank input results in empty page selectors
2949 if parser.is_exhausted() {
2950 rule.selectors = PageSelectors::default();
2954 let url_data = contents.url_data.read();
2955 let context = ParserContext::new(
2959 ParsingMode::DEFAULT,
2960 QuirksMode::NoQuirks,
2961 /* namespaces = */ Default::default(),
2966 match parser.parse_entirely(|i| PageSelectors::parse(&context, i)) {
2968 rule.selectors = selectors;
2977 pub extern "C" fn Servo_PropertyRule_GetName(rule: &PropertyRule, result: &mut nsACString) {
2978 write!(result, "--{}", rule.name.0).unwrap();
2982 pub extern "C" fn Servo_PropertyRule_GetSyntax(rule: &PropertyRule, result: &mut nsACString) {
2983 if let Some(syntax) = rule.data.syntax.specified_string() {
2984 result.assign(syntax);
2986 debug_assert!(false, "Rule without specified syntax?");
2991 pub extern "C" fn Servo_PropertyRule_GetInherits(rule: &PropertyRule) -> bool {
2996 pub extern "C" fn Servo_PropertyRule_GetInitialValue(
2997 rule: &PropertyRule,
2998 result: &mut nsACString,
3002 .to_css(&mut CssWriter::new(result))
3004 rule.data.initial_value.is_some()
3008 pub extern "C" fn Servo_SupportsRule_GetConditionText(
3009 rule: &SupportsRule,
3010 result: &mut nsACString,
3012 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
3016 pub extern "C" fn Servo_ContainerRule_GetConditionText(
3017 rule: &ContainerRule,
3018 result: &mut nsACString,
3020 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
3024 pub extern "C" fn Servo_ContainerRule_GetContainerQuery(
3025 rule: &ContainerRule,
3026 result: &mut nsACString,
3028 rule.query_condition()
3029 .to_css(&mut CssWriter::new(result))
3034 pub extern "C" fn Servo_ContainerRule_QueryContainerFor(
3035 rule: &ContainerRule,
3036 element: &RawGeckoElement,
3037 ) -> *const RawGeckoElement {
3039 .find_container(GeckoElement(element), None)
3040 .map_or(ptr::null(), |result| result.element.0)
3044 pub extern "C" fn Servo_ContainerRule_GetContainerName(
3045 rule: &ContainerRule,
3046 result: &mut nsACString,
3048 let name = rule.container_name();
3049 if !name.is_none() {
3050 name.to_css(&mut CssWriter::new(result)).unwrap();
3055 pub extern "C" fn Servo_DocumentRule_GetConditionText(
3056 rule: &DocumentRule,
3057 result: &mut nsACString,
3059 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
3063 pub extern "C" fn Servo_FontFeatureValuesRule_GetFontFamily(
3064 rule: &FontFeatureValuesRule,
3065 result: &mut nsACString,
3068 .to_css(&mut CssWriter::new(result))
3073 pub extern "C" fn Servo_FontFeatureValuesRule_GetValueText(
3074 rule: &FontFeatureValuesRule,
3075 result: &mut nsACString,
3077 rule.value_to_css(&mut CssWriter::new(result)).unwrap();
3081 pub extern "C" fn Servo_FontPaletteValuesRule_GetName(
3082 rule: &FontPaletteValuesRule,
3083 result: &mut nsACString,
3085 rule.name.to_css(&mut CssWriter::new(result)).unwrap()
3089 pub extern "C" fn Servo_FontPaletteValuesRule_GetFontFamily(
3090 rule: &FontPaletteValuesRule,
3091 result: &mut nsACString,
3093 if !rule.family_names.is_empty() {
3095 .to_css(&mut CssWriter::new(result))
3101 pub extern "C" fn Servo_FontPaletteValuesRule_GetBasePalette(
3102 rule: &FontPaletteValuesRule,
3103 result: &mut nsACString,
3106 .to_css(&mut CssWriter::new(result))
3111 pub extern "C" fn Servo_FontPaletteValuesRule_GetOverrideColors(
3112 rule: &FontPaletteValuesRule,
3113 result: &mut nsACString,
3115 if !rule.override_colors.is_empty() {
3116 rule.override_colors
3117 .to_css(&mut CssWriter::new(result))
3123 pub extern "C" fn Servo_FontFaceRule_CreateEmpty() -> Strong<LockedFontFaceRule> {
3124 // XXX This is not great. We should split FontFace descriptor data
3125 // from the rule, so that we don't need to create the rule like this
3126 // and the descriptor data itself can be hold in UniquePtr from the
3127 // Gecko side. See bug 1450904.
3128 with_maybe_worker_shared_lock(|lock| {
3129 Arc::new(lock.wrap(FontFaceRule::empty(SourceLocation { line: 0, column: 0 }))).into()
3134 pub unsafe extern "C" fn Servo_FontFaceRule_Clone(
3135 rule: &LockedFontFaceRule,
3136 ) -> Strong<LockedFontFaceRule> {
3137 let clone = read_locked_arc_worker(rule, |rule: &FontFaceRule| rule.clone());
3138 with_maybe_worker_shared_lock(|lock| Arc::new(lock.wrap(clone)).into())
3142 pub unsafe extern "C" fn Servo_FontFaceRule_GetSourceLocation(
3143 rule: &LockedFontFaceRule,
3147 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3148 let location = rule.source_location;
3149 *line.as_mut().unwrap() = location.line as u32;
3150 *column.as_mut().unwrap() = location.column as u32;
3154 macro_rules! apply_font_desc_list {
3155 ($apply_macro:ident) => {
3158 eCSSFontDesc_Family => family,
3159 eCSSFontDesc_Style => style,
3160 eCSSFontDesc_Weight => weight,
3161 eCSSFontDesc_Stretch => stretch,
3162 eCSSFontDesc_Src => sources,
3163 eCSSFontDesc_UnicodeRange => unicode_range,
3164 eCSSFontDesc_FontFeatureSettings => feature_settings,
3165 eCSSFontDesc_FontVariationSettings => variation_settings,
3166 eCSSFontDesc_FontLanguageOverride => language_override,
3167 eCSSFontDesc_Display => display,
3168 eCSSFontDesc_AscentOverride => ascent_override,
3169 eCSSFontDesc_DescentOverride => descent_override,
3170 eCSSFontDesc_LineGapOverride => line_gap_override,
3171 eCSSFontDesc_SizeAdjust => size_adjust,
3174 eCSSFontDesc_UNKNOWN,
3182 pub unsafe extern "C" fn Servo_FontFaceRule_Length(rule: &LockedFontFaceRule) -> u32 {
3183 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3185 macro_rules! count_values {
3187 valid: [$($v_enum_name:ident => $field:ident,)*]
3188 invalid: [$($i_enum_name:ident,)*]
3190 $(if rule.$field.is_some() {
3195 apply_font_desc_list!(count_values);
3201 pub unsafe extern "C" fn Servo_FontFaceRule_IndexGetter(
3202 rule: &LockedFontFaceRule,
3204 ) -> nsCSSFontDesc {
3205 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3207 macro_rules! lookup_index {
3209 valid: [$($v_enum_name:ident => $field:ident,)*]
3210 invalid: [$($i_enum_name:ident,)*]
3212 $(if rule.$field.is_some() {
3214 if count - 1 == index {
3215 return nsCSSFontDesc::$v_enum_name;
3220 apply_font_desc_list!(lookup_index);
3221 return nsCSSFontDesc::eCSSFontDesc_UNKNOWN;
3226 pub unsafe extern "C" fn Servo_FontFaceRule_GetDeclCssText(
3227 rule: &LockedFontFaceRule,
3228 result: &mut nsACString,
3230 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3231 rule.decl_to_css(result).unwrap();
3235 macro_rules! simple_font_descriptor_getter_impl {
3236 ($rule:ident, $out:ident, $field:ident, $compute:ident) => {
3237 read_locked_arc_worker($rule, |rule: &FontFaceRule| {
3239 None => return false,
3240 Some(ref f) => *$out = f.$compute(),
3248 pub extern "C" fn Servo_FontFaceRule_GetFontWeight(
3249 rule: &LockedFontFaceRule,
3250 out: &mut font_face::ComputedFontWeightRange,
3252 simple_font_descriptor_getter_impl!(rule, out, weight, compute)
3256 pub extern "C" fn Servo_FontFaceRule_GetFontStretch(
3257 rule: &LockedFontFaceRule,
3258 out: &mut font_face::ComputedFontStretchRange,
3260 simple_font_descriptor_getter_impl!(rule, out, stretch, compute)
3264 pub extern "C" fn Servo_FontFaceRule_GetFontStyle(
3265 rule: &LockedFontFaceRule,
3266 out: &mut font_face::ComputedFontStyleDescriptor,
3268 simple_font_descriptor_getter_impl!(rule, out, style, compute)
3272 pub extern "C" fn Servo_FontFaceRule_GetFontDisplay(
3273 rule: &LockedFontFaceRule,
3274 out: &mut font_face::FontDisplay,
3276 simple_font_descriptor_getter_impl!(rule, out, display, clone)
3280 pub extern "C" fn Servo_FontFaceRule_GetFontLanguageOverride(
3281 rule: &LockedFontFaceRule,
3282 out: &mut computed::FontLanguageOverride,
3284 simple_font_descriptor_getter_impl!(rule, out, language_override, clone)
3287 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3288 // rather than an actual percentage value.
3290 pub extern "C" fn Servo_FontFaceRule_GetAscentOverride(
3291 rule: &LockedFontFaceRule,
3292 out: &mut computed::Percentage,
3294 simple_font_descriptor_getter_impl!(rule, out, ascent_override, compute)
3297 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3298 // rather than an actual percentage value.
3300 pub extern "C" fn Servo_FontFaceRule_GetDescentOverride(
3301 rule: &LockedFontFaceRule,
3302 out: &mut computed::Percentage,
3304 simple_font_descriptor_getter_impl!(rule, out, descent_override, compute)
3307 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3308 // rather than an actual percentage value.
3310 pub extern "C" fn Servo_FontFaceRule_GetLineGapOverride(
3311 rule: &LockedFontFaceRule,
3312 out: &mut computed::Percentage,
3314 simple_font_descriptor_getter_impl!(rule, out, line_gap_override, compute)
3318 pub extern "C" fn Servo_FontFaceRule_GetSizeAdjust(
3319 rule: &LockedFontFaceRule,
3320 out: &mut computed::Percentage,
3322 simple_font_descriptor_getter_impl!(rule, out, size_adjust, compute)
3326 pub unsafe extern "C" fn Servo_FontFaceRule_GetFamilyName(
3327 rule: &LockedFontFaceRule,
3329 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3330 // TODO(emilio): font-family is a mandatory descriptor, can't we unwrap
3331 // here, and remove the null-checks in Gecko?
3334 .map_or(ptr::null_mut(), |f| f.name.as_ptr())
3339 pub unsafe extern "C" fn Servo_FontFaceRule_GetUnicodeRanges(
3340 rule: &LockedFontFaceRule,
3341 out_len: *mut usize,
3342 ) -> *const UnicodeRange {
3344 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3345 let ranges = match rule.unicode_range {
3346 Some(ref ranges) => ranges,
3347 None => return ptr::null(),
3349 *out_len = ranges.len();
3350 ranges.as_ptr() as *const _
3355 pub unsafe extern "C" fn Servo_FontFaceRule_GetSources(
3356 rule: &LockedFontFaceRule,
3357 out: *mut nsTArray<FontFaceSourceListComponent>,
3359 let out = &mut *out;
3360 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3361 let sources = match rule.sources {
3365 let len = sources.0.iter().fold(0, |acc, src| {
3367 Source::Url(ref url) => {
3368 (if url.format_hint.is_some() { 2 } else { 1 }) +
3369 (if url.tech_flags.is_empty() { 0 } else { 1 })
3371 Source::Local(_) => 1,
3375 out.set_len(len as u32);
3377 let mut iter = out.iter_mut();
3380 let mut set_next = |component: FontFaceSourceListComponent| {
3381 *iter.next().expect("miscalculated length") = component;
3384 for source in sources.0.iter() {
3386 Source::Url(ref url) => {
3387 set_next(FontFaceSourceListComponent::Url(&url.url));
3388 if let Some(hint) = &url.format_hint {
3390 FontFaceSourceFormat::Keyword(kw) => {
3391 set_next(FontFaceSourceListComponent::FormatHintKeyword(*kw))
3393 FontFaceSourceFormat::String(s) => {
3394 set_next(FontFaceSourceListComponent::FormatHintString {
3396 utf8_bytes: s.as_ptr(),
3401 if !url.tech_flags.is_empty() {
3402 set_next(FontFaceSourceListComponent::TechFlags(url.tech_flags));
3405 Source::Local(ref name) => {
3406 set_next(FontFaceSourceListComponent::Local(name.name.as_ptr()));
3412 assert!(iter.next().is_none(), "miscalculated");
3417 pub unsafe extern "C" fn Servo_FontFaceRule_GetVariationSettings(
3418 rule: &LockedFontFaceRule,
3419 variations: *mut nsTArray<structs::gfxFontVariation>,
3421 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3422 let source_variations = match rule.variation_settings {
3427 (*variations).set_len(source_variations.0.len() as u32);
3428 for (target, source) in (*variations).iter_mut().zip(source_variations.0.iter()) {
3429 *target = structs::gfxFontVariation {
3431 mValue: source.value.get(),
3438 pub unsafe extern "C" fn Servo_FontFaceRule_GetFeatureSettings(
3439 rule: &LockedFontFaceRule,
3440 features: *mut nsTArray<structs::gfxFontFeature>,
3442 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3443 let source_features = match rule.feature_settings {
3448 (*features).set_len(source_features.0.len() as u32);
3449 for (target, source) in (*features).iter_mut().zip(source_features.0.iter()) {
3450 *target = structs::gfxFontFeature {
3452 mValue: source.value.value() as u32,
3459 pub extern "C" fn Servo_FontFaceRule_GetDescriptorCssText(
3460 rule: &LockedFontFaceRule,
3461 desc: nsCSSFontDesc,
3462 result: &mut nsACString,
3464 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3465 let mut writer = CssWriter::new(result);
3466 macro_rules! to_css_text {
3468 valid: [$($v_enum_name:ident => $field:ident,)*]
3469 invalid: [$($i_enum_name:ident,)*]
3473 nsCSSFontDesc::$v_enum_name => {
3474 if let Some(ref value) = rule.$field {
3475 value.to_css(&mut writer).unwrap();
3480 nsCSSFontDesc::$i_enum_name => {
3481 debug_assert!(false, "not a valid font descriptor");
3487 apply_font_desc_list!(to_css_text)
3492 pub unsafe extern "C" fn Servo_FontFaceRule_SetDescriptor(
3493 rule: &LockedFontFaceRule,
3494 desc: nsCSSFontDesc,
3496 data: *mut URLExtraData,
3497 out_changed: *mut bool,
3499 let value = value.as_str_unchecked();
3500 let mut input = ParserInput::new(&value);
3501 let mut parser = Parser::new(&mut input);
3502 let url_data = UrlExtraData::from_ptr_ref(&data);
3503 let context = ParserContext::new(
3506 Some(CssRuleType::FontFace),
3507 ParsingMode::DEFAULT,
3508 QuirksMode::NoQuirks,
3509 /* namespaces = */ Default::default(),
3514 write_locked_arc_worker(rule, |rule: &mut FontFaceRule| {
3515 macro_rules! to_css_text {
3517 valid: [$($v_enum_name:ident => $field:ident,)*]
3518 invalid: [$($i_enum_name:ident,)*]
3522 nsCSSFontDesc::$v_enum_name => {
3523 if let Ok(value) = parser.parse_entirely(|i| Parse::parse(&context, i)) {
3524 let result = Some(value);
3525 *out_changed = result != rule.$field;
3526 rule.$field = result;
3534 nsCSSFontDesc::$i_enum_name => {
3535 debug_assert!(false, "not a valid font descriptor");
3542 apply_font_desc_list!(to_css_text)
3547 pub unsafe extern "C" fn Servo_FontFaceRule_ResetDescriptor(
3548 rule: &LockedFontFaceRule,
3549 desc: nsCSSFontDesc,
3551 write_locked_arc_worker(rule, |rule: &mut FontFaceRule| {
3552 macro_rules! reset_desc {
3554 valid: [$($v_enum_name:ident => $field:ident,)*]
3555 invalid: [$($i_enum_name:ident,)*]
3558 $(nsCSSFontDesc::$v_enum_name => rule.$field = None,)*
3559 $(nsCSSFontDesc::$i_enum_name => debug_assert!(false, "not a valid font descriptor"),)*
3563 apply_font_desc_list!(reset_desc)
3568 pub unsafe extern "C" fn Servo_CounterStyleRule_GetName(
3569 rule: &LockedCounterStyleRule,
3571 read_locked_arc(rule, |rule: &CounterStyleRule| rule.name().0.as_ptr())
3575 pub unsafe extern "C" fn Servo_CounterStyleRule_SetName(
3576 rule: &LockedCounterStyleRule,
3579 let value = value.as_str_unchecked();
3580 let mut input = ParserInput::new(&value);
3581 let mut parser = Parser::new(&mut input);
3582 match parser.parse_entirely(counter_style::parse_counter_style_name_definition) {
3584 write_locked_arc(rule, |rule: &mut CounterStyleRule| rule.set_name(name));
3592 pub unsafe extern "C" fn Servo_CounterStyleRule_GetGeneration(
3593 rule: &LockedCounterStyleRule,
3595 read_locked_arc(rule, |rule: &CounterStyleRule| rule.generation())
3598 fn symbol_to_string(s: &counter_style::Symbol) -> nsString {
3600 counter_style::Symbol::String(ref s) => nsString::from(&**s),
3601 counter_style::Symbol::Ident(ref i) => nsString::from(i.0.as_slice()),
3605 // TODO(emilio): Cbindgen could be used to simplify a bunch of code here.
3607 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPad(
3608 rule: &LockedCounterStyleRule,
3610 symbol: &mut nsString,
3612 read_locked_arc(rule, |rule: &CounterStyleRule| {
3613 let pad = match rule.pad() {
3615 None => return false,
3617 *width = pad.0.value();
3618 *symbol = symbol_to_string(&pad.1);
3623 fn get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool {
3626 None => return false,
3628 *out = symbol_to_string(s);
3633 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPrefix(
3634 rule: &LockedCounterStyleRule,
3637 read_locked_arc(rule, |rule: &CounterStyleRule| {
3638 get_symbol(rule.prefix(), out)
3643 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSuffix(
3644 rule: &LockedCounterStyleRule,
3647 read_locked_arc(rule, |rule: &CounterStyleRule| {
3648 get_symbol(rule.suffix(), out)
3653 pub unsafe extern "C" fn Servo_CounterStyleRule_GetNegative(
3654 rule: &LockedCounterStyleRule,
3655 prefix: &mut nsString,
3656 suffix: &mut nsString,
3658 read_locked_arc(rule, |rule: &CounterStyleRule| {
3659 let negative = match rule.negative() {
3661 None => return false,
3663 *prefix = symbol_to_string(&negative.0);
3664 *suffix = match negative.1 {
3665 Some(ref s) => symbol_to_string(s),
3666 None => nsString::new(),
3673 pub enum IsOrdinalInRange {
3681 pub unsafe extern "C" fn Servo_CounterStyleRule_IsInRange(
3682 rule: &LockedCounterStyleRule,
3684 ) -> IsOrdinalInRange {
3685 use style::counter_style::CounterBound;
3686 read_locked_arc(rule, |rule: &CounterStyleRule| {
3687 let range = match rule.range() {
3689 None => return IsOrdinalInRange::NoOrdinalSpecified,
3692 if range.0.is_empty() {
3693 return IsOrdinalInRange::Auto;
3696 let in_range = range.0.iter().any(|r| {
3697 if let CounterBound::Integer(start) = r.start {
3698 if start.value() > ordinal {
3703 if let CounterBound::Integer(end) = r.end {
3704 if end.value() < ordinal {
3713 IsOrdinalInRange::InRange
3715 IsOrdinalInRange::NotInRange
3721 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols(
3722 rule: &LockedCounterStyleRule,
3723 symbols: &mut style::OwnedSlice<nsString>,
3725 read_locked_arc(rule, |rule: &CounterStyleRule| {
3726 *symbols = match rule.symbols() {
3727 Some(s) => s.0.iter().map(symbol_to_string).collect(),
3728 None => style::OwnedSlice::default(),
3734 pub struct AdditiveSymbol {
3736 pub symbol: nsString,
3740 pub unsafe extern "C" fn Servo_CounterStyleRule_GetAdditiveSymbols(
3741 rule: &LockedCounterStyleRule,
3742 symbols: &mut style::OwnedSlice<AdditiveSymbol>,
3744 read_locked_arc(rule, |rule: &CounterStyleRule| {
3745 *symbols = match rule.additive_symbols() {
3748 .map(|s| AdditiveSymbol {
3749 weight: s.weight.value(),
3750 symbol: symbol_to_string(&s.symbol),
3754 None => style::OwnedSlice::default(),
3760 pub enum CounterSpeakAs {
3770 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSpeakAs(
3771 rule: &LockedCounterStyleRule,
3772 out: &mut CounterSpeakAs,
3774 use style::counter_style::SpeakAs;
3775 *out = read_locked_arc(rule, |rule: &CounterStyleRule| {
3776 let speak_as = match rule.speak_as() {
3778 None => return CounterSpeakAs::None,
3781 SpeakAs::Auto => CounterSpeakAs::Auto,
3782 SpeakAs::Bullets => CounterSpeakAs::Bullets,
3783 SpeakAs::Numbers => CounterSpeakAs::Numbers,
3784 SpeakAs::Words => CounterSpeakAs::Words,
3785 SpeakAs::Other(ref other) => CounterSpeakAs::Ident(other.0.as_ptr()),
3791 pub enum CounterSystem {
3802 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSystem(
3803 rule: &LockedCounterStyleRule,
3804 ) -> CounterSystem {
3805 use style::counter_style::System;
3806 read_locked_arc(rule, |rule: &CounterStyleRule| {
3807 match *rule.resolved_system() {
3808 System::Cyclic => CounterSystem::Cyclic,
3809 System::Numeric => CounterSystem::Numeric,
3810 System::Alphabetic => CounterSystem::Alphabetic,
3811 System::Symbolic => CounterSystem::Symbolic,
3812 System::Additive => CounterSystem::Additive,
3813 System::Fixed { .. } => CounterSystem::Fixed,
3814 System::Extends(_) => CounterSystem::Extends,
3820 pub unsafe extern "C" fn Servo_CounterStyleRule_GetExtended(
3821 rule: &LockedCounterStyleRule,
3823 read_locked_arc(rule, |rule: &CounterStyleRule| {
3824 match *rule.resolved_system() {
3825 counter_style::System::Extends(ref name) => name.0.as_ptr(),
3827 debug_assert!(false, "Not extends system");
3835 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFixedFirstValue(
3836 rule: &LockedCounterStyleRule,
3838 read_locked_arc(rule, |rule: &CounterStyleRule| {
3839 match *rule.resolved_system() {
3840 counter_style::System::Fixed { first_symbol_value } => {
3841 first_symbol_value.map_or(1, |v| v.value())
3844 debug_assert!(false, "Not fixed system");
3852 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFallback(
3853 rule: &LockedCounterStyleRule,
3855 read_locked_arc(rule, |rule: &CounterStyleRule| {
3856 rule.fallback().map_or(ptr::null_mut(), |i| i.0 .0.as_ptr())
3860 macro_rules! counter_style_descriptors {
3863 $($desc:ident => $getter:ident / $setter:ident,)+
3870 pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptorCssText(
3871 rule: &LockedCounterStyleRule,
3872 desc: nsCSSCounterDesc,
3873 result: &mut nsACString,
3875 let mut writer = CssWriter::new(result);
3876 read_locked_arc(rule, |rule: &CounterStyleRule| {
3878 $(nsCSSCounterDesc::$desc => {
3879 if let Some(value) = rule.$getter() {
3880 value.to_css(&mut writer).unwrap();
3883 $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3889 pub unsafe extern "C" fn Servo_CounterStyleRule_SetDescriptor(
3890 rule: &LockedCounterStyleRule,
3891 desc: nsCSSCounterDesc,
3894 let value = value.as_str_unchecked();
3895 let mut input = ParserInput::new(&value);
3896 let mut parser = Parser::new(&mut input);
3897 let url_data = dummy_url_data();
3898 let context = ParserContext::new(
3901 Some(CssRuleType::CounterStyle),
3902 ParsingMode::DEFAULT,
3903 QuirksMode::NoQuirks,
3904 /* namespaces = */ Default::default(),
3909 write_locked_arc(rule, |rule: &mut CounterStyleRule| {
3911 $(nsCSSCounterDesc::$desc => {
3912 match parser.parse_entirely(|i| Parse::parse(&context, i)) {
3913 Ok(value) => rule.$setter(value),
3917 $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3924 counter_style_descriptors! {
3926 eCSSCounterDesc_System => system / set_system,
3927 eCSSCounterDesc_Symbols => symbols / set_symbols,
3928 eCSSCounterDesc_AdditiveSymbols => additive_symbols / set_additive_symbols,
3929 eCSSCounterDesc_Negative => negative / set_negative,
3930 eCSSCounterDesc_Prefix => prefix / set_prefix,
3931 eCSSCounterDesc_Suffix => suffix / set_suffix,
3932 eCSSCounterDesc_Range => range / set_range,
3933 eCSSCounterDesc_Pad => pad / set_pad,
3934 eCSSCounterDesc_Fallback => fallback / set_fallback,
3935 eCSSCounterDesc_SpeakAs => speak_as / set_speak_as,
3938 eCSSCounterDesc_UNKNOWN,
3939 eCSSCounterDesc_COUNT,
3944 pub unsafe extern "C" fn Servo_ComputedValues_GetForPageContent(
3945 raw_data: &PerDocumentStyleData,
3946 page_name: *const nsAtom,
3947 pseudos: PagePseudoClassFlags,
3948 ) -> Strong<ComputedValues> {
3949 let global_style_data = &*GLOBAL_STYLE_DATA;
3950 let guard = global_style_data.shared_lock.read();
3951 let guards = StylesheetGuards::same(&guard);
3952 let data = raw_data.borrow_mut();
3953 let cascade_data = data.stylist.cascade_data();
3955 let mut extra_declarations = vec![];
3956 let iter = data.stylist.iter_extra_data_origins_rev();
3957 let name = if !page_name.is_null() {
3958 Some(Atom::from_raw(page_name as *mut nsAtom))
3962 for (data, origin) in iter {
3963 data.pages.match_and_append_rules(
3964 &mut extra_declarations,
3973 let rule_node = data.stylist.rule_node_for_precomputed_pseudo(
3975 &PseudoElement::PageContent,
3980 .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
3982 &PseudoElement::PageContent,
3990 pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox(
3991 parent_style_or_null: Option<&ComputedValues>,
3992 pseudo: PseudoStyleType,
3993 raw_data: &PerDocumentStyleData,
3994 ) -> Strong<ComputedValues> {
3995 let pseudo = PseudoElement::from_pseudo_type(pseudo, None).unwrap();
3996 debug_assert!(pseudo.is_anon_box());
3997 debug_assert_ne!(pseudo, PseudoElement::PageContent);
3998 let global_style_data = &*GLOBAL_STYLE_DATA;
3999 let guard = global_style_data.shared_lock.read();
4000 let guards = StylesheetGuards::same(&guard);
4001 let data = raw_data.borrow_mut();
4002 let rule_node = data
4004 .rule_node_for_precomputed_pseudo(&guards, &pseudo, vec![]);
4007 .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
4010 parent_style_or_null.map(|x| &*x),
4016 fn get_functional_pseudo_parameter_atom(
4017 functional_pseudo_parameter: *mut nsAtom,
4018 ) -> Option<AtomIdent> {
4019 if functional_pseudo_parameter.is_null() {
4022 Some(AtomIdent::new(unsafe {
4023 Atom::from_raw(functional_pseudo_parameter)
4029 pub extern "C" fn Servo_ResolvePseudoStyle(
4030 element: &RawGeckoElement,
4031 pseudo_type: PseudoStyleType,
4032 functional_pseudo_parameter: *mut nsAtom,
4034 inherited_style: Option<&ComputedValues>,
4035 raw_data: &PerDocumentStyleData,
4036 ) -> Strong<ComputedValues> {
4037 let element = GeckoElement(element);
4038 let doc_data = raw_data.borrow();
4041 "Servo_ResolvePseudoStyle: {:?} {:?}, is_probe: {}",
4043 PseudoElement::from_pseudo_type(
4045 get_functional_pseudo_parameter_atom(functional_pseudo_parameter)
4050 let data = element.borrow_data();
4052 let data = match data.as_ref() {
4053 Some(data) if data.has_styles() => data,
4055 // FIXME(bholley, emilio): Assert against this.
4057 // Known offender is nsMathMLmoFrame::MarkIntrinsicISizesDirty,
4058 // which goes and does a bunch of work involving style resolution.
4060 // Bug 1403865 tracks fixing it, and potentially adding an assert
4062 warn!("Calling Servo_ResolvePseudoStyle on unstyled element");
4063 return if is_probe {
4066 doc_data.default_computed_values().clone().into()
4071 let pseudo_element = PseudoElement::from_pseudo_type(
4073 get_functional_pseudo_parameter_atom(functional_pseudo_parameter),
4075 .expect("ResolvePseudoStyle with a non-pseudo?");
4077 let matching_fn = |pseudo: &PseudoElement| *pseudo == pseudo_element;
4079 let global_style_data = &*GLOBAL_STYLE_DATA;
4080 let guard = global_style_data.shared_lock.read();
4081 let style = get_pseudo_style(
4090 /* matching_func = */
4091 if pseudo_element.is_highlight() {
4099 Some(s) => s.into(),
4101 debug_assert!(is_probe);
4107 fn debug_atom_array(atoms: &nsTArray<structs::RefPtr<nsAtom>>) -> String {
4108 let mut result = String::from("[");
4109 for atom in atoms.iter() {
4110 if atom.mRawPtr.is_null() {
4111 result += "(null), ";
4113 let atom = unsafe { WeakAtom::new(atom.mRawPtr) };
4114 write!(result, "{}, ", atom).unwrap();
4122 pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle(
4123 element: &RawGeckoElement,
4124 pseudo_tag: *mut nsAtom,
4125 inherited_style: &ComputedValues,
4126 input_word: &nsTArray<structs::RefPtr<nsAtom>>,
4127 raw_data: &PerDocumentStyleData,
4128 ) -> Strong<ComputedValues> {
4129 let element = GeckoElement(element);
4132 .expect("Calling ResolveXULTreePseudoStyle on unstyled element?");
4134 let pseudo = unsafe {
4135 Atom::with(pseudo_tag, |atom| {
4136 PseudoElement::from_tree_pseudo_atom(atom, Box::new([]))
4138 .expect("ResolveXULTreePseudoStyle with a non-tree pseudo?")
4140 let doc_data = raw_data.borrow();
4143 "ResolveXULTreePseudoStyle: {:?} {:?} {}",
4146 debug_atom_array(input_word)
4149 let matching_fn = |pseudo: &PseudoElement| {
4152 .expect("Not a tree pseudo-element?");
4154 .all(|atom| input_word.iter().any(|item| atom.as_ptr() == item.mRawPtr))
4157 let global_style_data = &*GLOBAL_STYLE_DATA;
4158 let guard = global_style_data.shared_lock.read();
4165 Some(inherited_style),
4167 /* is_probe = */ false,
4175 pub extern "C" fn Servo_SetExplicitStyle(element: &RawGeckoElement, style: &ComputedValues) {
4176 let element = GeckoElement(element);
4177 debug!("Servo_SetExplicitStyle: {:?}", element);
4178 // We only support this API for initial styling. There's no reason it couldn't
4179 // work for other things, we just haven't had a reason to do so.
4180 debug_assert!(!element.has_data());
4181 let mut data = unsafe { element.ensure_data() };
4182 data.styles.primary = Some(unsafe { Arc::from_raw_addrefed(style) });
4185 fn get_pseudo_style(
4186 guard: &SharedRwLockReadGuard,
4187 element: GeckoElement,
4188 pseudo: &PseudoElement,
4189 rule_inclusion: RuleInclusion,
4190 styles: &ElementStyles,
4191 inherited_styles: Option<&ComputedValues>,
4194 matching_func: Option<&dyn Fn(&PseudoElement) -> bool>,
4195 ) -> Option<Arc<ComputedValues>> {
4196 let style = match pseudo.cascade_type() {
4197 PseudoElementCascadeType::Eager => {
4199 PseudoElement::FirstLetter => {
4200 styles.pseudos.get(&pseudo).map(|pseudo_styles| {
4201 // inherited_styles can be None when doing lazy resolution
4202 // (e.g. for computed style) or when probing. In that case
4203 // we just inherit from our element, which is what Gecko
4204 // does in that situation. What should actually happen in
4205 // the computed style case is a bit unclear.
4206 let inherited_styles = inherited_styles.unwrap_or(styles.primary());
4207 let guards = StylesheetGuards::same(guard);
4208 let inputs = CascadeInputs::new_from_style(pseudo_styles);
4209 stylist.compute_pseudo_element_style_with_inputs(
4213 Some(inherited_styles),
4219 // Unfortunately, we can't assert that inherited_styles, if
4220 // present, is pointer-equal to styles.primary(), or even
4221 // equal in any meaningful way. The way it can fail is as
4222 // follows. Say we append an element with a ::before,
4223 // ::after, or ::first-line to a parent with a ::first-line,
4224 // such that the element ends up on the first line of the
4225 // parent (e.g. it's an inline-block in the case it has a
4226 // ::first-line, or any container in the ::before/::after
4227 // cases). Then gecko will update its frame's style to
4228 // inherit from the parent's ::first-line. The next time we
4229 // try to get the ::before/::after/::first-line style for
4230 // the kid, we'll likely pass in the frame's style as
4231 // inherited_styles, but that's not pointer-identical to
4232 // styles.primary(), because it got reparented.
4234 // Now in practice this turns out to be OK, because all the
4235 // cases in which there's a mismatch go ahead and reparent
4236 // styles again as needed to make sure the ::first-line
4237 // affects all the things it should affect. But it makes it
4238 // impossible to assert anything about the two styles
4239 // matching here, unfortunately.
4240 styles.pseudos.get(&pseudo).cloned()
4244 PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
4245 PseudoElementCascadeType::Lazy => {
4247 inherited_styles.is_none() ||
4248 ptr::eq(inherited_styles.unwrap(), &**styles.primary())
4250 let originating_element_style = styles.primary();
4251 let guards = StylesheetGuards::same(guard);
4252 stylist.lazily_compute_pseudo_element_style(
4257 originating_element_style,
4268 Some(style.unwrap_or_else(|| {
4269 StyleBuilder::for_inheritance(
4272 Some(styles.primary()),
4280 pub unsafe extern "C" fn Servo_ComputedValues_Inherit(
4281 raw_data: &PerDocumentStyleData,
4282 pseudo: PseudoStyleType,
4283 parent_style_context: Option<&ComputedValues>,
4284 target: structs::InheritTarget,
4285 ) -> Strong<ComputedValues> {
4286 let data = raw_data.borrow();
4288 let for_text = target == structs::InheritTarget::Text;
4289 let pseudo = PseudoElement::from_pseudo_type(pseudo, None).unwrap();
4290 debug_assert!(pseudo.is_anon_box());
4292 let mut style = StyleBuilder::for_inheritance(
4293 data.stylist.device(),
4294 Some(&data.stylist),
4295 parent_style_context,
4300 StyleAdjuster::new(&mut style).adjust_for_text();
4303 style.build().into()
4307 pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions(
4308 values: &ComputedValues,
4310 let ui = values.get_ui();
4311 ui.specifies_animations() || ui.specifies_transitions()
4315 pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
4316 values: &ComputedValues,
4317 rules: &mut ThinVec<*const LockedStyleRule>,
4319 let rule_node = match values.rules {
4324 for node in rule_node.self_and_ancestors() {
4325 let style_rule = match node.style_source().and_then(|x| x.as_rule()) {
4330 // For the rules with any important declaration, we insert them into
4331 // rule tree twice, one for normal level and another for important
4332 // level. So, we skip the important one to keep the specificity order of
4334 if node.importance().important() {
4338 rules.push(&*style_rule);
4342 /// println_stderr!() calls Gecko's printf_stderr(), which, unlike eprintln!(),
4343 /// will funnel output to Android logcat.
4344 #[cfg(feature = "gecko_debug")]
4345 macro_rules! println_stderr {
4348 let mut s = nsCString::new();
4349 write!(s, $($e),+).unwrap();
4350 s.write_char('\n').unwrap();
4351 unsafe { bindings::Gecko_PrintfStderr(&s); }
4356 #[cfg(feature = "gecko_debug")]
4357 fn dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet) {
4358 println_stderr!(" Properties:");
4359 for p in properties.iter() {
4360 let mut v = nsCString::new();
4361 cv.computed_or_resolved_value(p, None, &mut v).unwrap();
4362 println_stderr!(" {:?}: {}", p, v);
4367 #[cfg(feature = "gecko_debug")]
4368 fn dump_rules(cv: &ComputedValues) {
4369 println_stderr!(" Rules({:?}):", cv.pseudo());
4370 let global_style_data = &*GLOBAL_STYLE_DATA;
4371 let guard = global_style_data.shared_lock.read();
4372 if let Some(rules) = cv.rules.as_ref() {
4373 for rn in rules.self_and_ancestors() {
4374 if rn.importance().important() {
4377 if let Some(d) = rn.style_source().and_then(|s| s.as_declarations()) {
4378 println_stderr!(" [DeclarationBlock: {:?}]", d);
4380 if let Some(r) = rn.style_source().and_then(|s| s.as_rule()) {
4381 let mut s = nsCString::new();
4382 r.read_with(&guard).to_css(&guard, &mut s).unwrap();
4383 println_stderr!(" {}", s);
4389 #[cfg(feature = "gecko_debug")]
4391 pub extern "C" fn Servo_ComputedValues_EqualForCachedAnonymousContentStyle(
4395 let mut differing_properties = a.differing_properties(b);
4397 // Ignore any difference in -x-lang, which we can't override in the rules in scrollbars.css,
4398 // but which makes no difference for the anonymous content subtrees we cache style for.
4399 differing_properties.remove(LonghandId::XLang);
4400 // Similarly, -x-lang can influence the font-family fallback we have for the initial
4401 // font-family so remove it as well.
4402 differing_properties.remove(LonghandId::FontFamily);
4403 // We reset font-size to an explicit pixel value, and thus it can get affected by our inherited
4404 // effective zoom. But we don't care about it for the same reason as above.
4405 differing_properties.remove(LonghandId::FontSize);
4407 // Ignore any difference in pref-controlled, inherited properties. These properties may or may
4408 // not be set by the 'all' declaration in scrollbars.css, depending on whether the pref was
4409 // enabled at the time the UA sheets were parsed.
4411 // If you add a new pref-controlled, inherited property, it must be defined with
4412 // `has_effect_on_gecko_scrollbars=False` to declare that different values of this property on
4413 // a <scrollbar> element or its descendant scrollbar part elements should have no effect on
4414 // their rendering and behavior.
4416 // If you do need a pref-controlled, inherited property to have an effect on these elements,
4417 // then you will need to add some checks to the
4418 // nsIAnonymousContentCreator::CreateAnonymousContent implementations of nsHTMLScrollFrame and
4419 // nsScrollbarFrame to clear the AnonymousContentKey if a non-initial value is used.
4420 differing_properties.remove_all(&LonghandIdSet::has_no_effect_on_gecko_scrollbars());
4422 if !differing_properties.is_empty() {
4423 println_stderr!("Actual style:");
4424 dump_properties_and_rules(a, &differing_properties);
4425 println_stderr!("Expected style:");
4426 dump_properties_and_rules(b, &differing_properties);
4429 differing_properties.is_empty()
4432 #[cfg(feature = "gecko_debug")]
4434 pub extern "C" fn Servo_ComputedValues_DumpMatchedRules(s: &ComputedValues) {
4439 pub extern "C" fn Servo_ComputedValues_BlockifiedDisplay(
4440 style: &ComputedValues,
4441 is_root_element: bool,
4443 let display = style.get_box().clone_display();
4444 let blockified_display = display.equivalent_block_display(is_root_element);
4445 blockified_display.to_u16()
4449 pub extern "C" fn Servo_StyleSet_Init(doc: &structs::Document) -> *mut PerDocumentStyleData {
4450 let data = Box::new(PerDocumentStyleData::new(doc));
4452 // Do this here rather than in Servo_Initialize since we need a document to
4453 // get the default computed values from.
4454 style::properties::generated::gecko::assert_initial_values_match(&data);
4456 Box::into_raw(data) as *mut PerDocumentStyleData
4460 pub unsafe extern "C" fn Servo_StyleSet_Drop(data: *mut PerDocumentStyleData) {
4461 let _ = Box::from_raw(data);
4465 pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: &PerDocumentStyleData) {
4466 let mut data = raw_data.borrow_mut();
4467 data.stylist.device_mut().rebuild_cached_data();
4468 data.undisplayed_style_cache.clear();
4472 pub unsafe extern "C" fn Servo_StyleSet_CompatModeChanged(raw_data: &PerDocumentStyleData) {
4473 let mut data = raw_data.borrow_mut();
4474 let quirks_mode = data.stylist.device().document().mCompatMode;
4475 data.stylist.set_quirks_mode(quirks_mode.into());
4478 fn parse_property_into(
4479 declarations: &mut SourcePropertyDeclaration,
4480 property_id: PropertyId,
4483 url_data: &UrlExtraData,
4484 parsing_mode: ParsingMode,
4485 quirks_mode: QuirksMode,
4486 rule_type: CssRuleType,
4487 reporter: Option<&dyn ParseErrorReporter>,
4488 ) -> Result<(), ()> {
4489 let value = unsafe { value.as_str_unchecked() };
4491 if let Some(non_custom) = property_id.non_custom_id() {
4492 if !non_custom.allowed_in_rule(rule_type.into()) {
4497 parse_one_declaration_into(
4511 pub unsafe extern "C" fn Servo_ParseProperty(
4512 property: &structs::AnimatedPropertyID,
4514 data: *mut URLExtraData,
4515 parsing_mode: ParsingMode,
4516 quirks_mode: nsCompatibility,
4517 loader: *mut Loader,
4518 rule_type: CssRuleType,
4519 ) -> Strong<LockedDeclarationBlock> {
4520 let id = get_property_id_from_animatedpropertyid!(property, Strong::null());
4521 let mut declarations = SourcePropertyDeclaration::default();
4522 let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
4523 let data = UrlExtraData::from_ptr_ref(&data);
4524 let result = parse_property_into(
4533 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4538 let global_style_data = &*GLOBAL_STYLE_DATA;
4539 let mut block = PropertyDeclarationBlock::new();
4540 block.extend(declarations.drain(), Importance::Normal);
4541 Arc::new(global_style_data.shared_lock.wrap(block)).into()
4543 Err(_) => Strong::null(),
4548 pub extern "C" fn Servo_ParseEasing(
4549 easing: &nsACString,
4550 output: &mut ComputedTimingFunction,
4552 use style::properties::longhands::transition_timing_function;
4554 let context = ParserContext::new(
4556 unsafe { dummy_url_data() },
4557 Some(CssRuleType::Style),
4558 ParsingMode::DEFAULT,
4559 QuirksMode::NoQuirks,
4560 /* namespaces = */ Default::default(),
4564 let easing = easing.to_string();
4565 let mut input = ParserInput::new(&easing);
4566 let mut parser = Parser::new(&mut input);
4568 parser.parse_entirely(|p| transition_timing_function::single_value::parse(&context, p));
4570 Ok(parsed_easing) => {
4571 *output = parsed_easing.to_computed_value_without_context();
4579 pub extern "C" fn Servo_SerializeEasing(easing: &ComputedTimingFunction, output: &mut nsACString) {
4580 easing.to_css(&mut CssWriter::new(output)).unwrap();
4584 pub extern "C" fn Servo_GetProperties_Overriding_Animation(
4585 element: &RawGeckoElement,
4586 list: &nsTArray<nsCSSPropertyID>,
4587 set: &mut structs::nsCSSPropertyIDSet,
4589 let element = GeckoElement(element);
4590 let element_data = match element.borrow_data() {
4594 let global_style_data = &*GLOBAL_STYLE_DATA;
4595 let guard = global_style_data.shared_lock.read();
4596 let guards = StylesheetGuards::same(&guard);
4597 let (overridden, custom) = element_data
4601 .get_properties_overriding_animations(&guards);
4602 for p in list.iter() {
4603 match NonCustomPropertyId::from_nscsspropertyid(*p) {
4605 if let Some(id) = property.as_longhand() {
4606 if overridden.contains(id) {
4607 unsafe { Gecko_AddPropertyToSet(set, *p) };
4612 if *p == nsCSSPropertyID::eCSSPropertyExtra_variable && custom {
4613 unsafe { Gecko_AddPropertyToSet(set, *p) };
4621 pub extern "C" fn Servo_MatrixTransform_Operate(
4622 matrix_operator: MatrixTransformOperator,
4623 from: *const structs::Matrix4x4Components,
4624 to: *const structs::Matrix4x4Components,
4626 output: *mut structs::Matrix4x4Components,
4628 use self::MatrixTransformOperator::{Accumulate, Interpolate};
4629 use style::values::computed::transform::Matrix3D;
4631 let from = Matrix3D::from(unsafe { from.as_ref() }.expect("not a valid 'from' matrix"));
4632 let to = Matrix3D::from(unsafe { to.as_ref() }.expect("not a valid 'to' matrix"));
4633 let result = match matrix_operator {
4634 Interpolate => from.animate(&to, Procedure::Interpolate { progress }),
4635 Accumulate => from.animate(
4637 Procedure::Accumulate {
4638 count: progress as u64,
4643 let output = unsafe { output.as_mut() }.expect("not a valid 'output' matrix");
4644 if let Ok(result) = result {
4645 *output = result.into();
4646 } else if progress < 0.5 {
4647 *output = from.clone().into();
4649 *output = to.clone().into();
4654 pub unsafe extern "C" fn Servo_ParseStyleAttribute(
4656 raw_extra_data: *mut URLExtraData,
4657 quirks_mode: nsCompatibility,
4658 loader: *mut Loader,
4659 rule_type: CssRuleType,
4660 ) -> Strong<LockedDeclarationBlock> {
4661 let global_style_data = &*GLOBAL_STYLE_DATA;
4662 let value = data.as_str_unchecked();
4663 let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data);
4664 let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
4665 Arc::new(global_style_data.shared_lock.wrap(parse_style_attribute(
4668 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4676 pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> Strong<LockedDeclarationBlock> {
4677 let global_style_data = &*GLOBAL_STYLE_DATA;
4681 .wrap(PropertyDeclarationBlock::new()),
4687 pub extern "C" fn Servo_DeclarationBlock_Clear(declarations: &LockedDeclarationBlock) {
4688 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4694 pub extern "C" fn Servo_DeclarationBlock_Clone(
4695 declarations: &LockedDeclarationBlock,
4696 ) -> Strong<LockedDeclarationBlock> {
4697 let global_style_data = &*GLOBAL_STYLE_DATA;
4698 let guard = global_style_data.shared_lock.read();
4702 .wrap(declarations.read_with(&guard).clone()),
4708 pub extern "C" fn Servo_DeclarationBlock_Equals(
4709 a: &LockedDeclarationBlock,
4710 b: &LockedDeclarationBlock,
4712 let global_style_data = &*GLOBAL_STYLE_DATA;
4713 let guard = global_style_data.shared_lock.read();
4714 a.read_with(&guard).declarations() == b.read_with(&guard).declarations()
4718 pub extern "C" fn Servo_DeclarationBlock_GetCssText(
4719 declarations: &LockedDeclarationBlock,
4720 result: &mut nsACString,
4722 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4723 decls.to_css(result).unwrap()
4728 pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
4729 decls: &LockedDeclarationBlock,
4730 property_id: &structs::AnimatedPropertyID,
4731 buffer: &mut nsACString,
4732 computed_values: Option<&ComputedValues>,
4733 data: &PerDocumentStyleData,
4735 let property_id = get_property_id_from_animatedpropertyid!(property_id, ());
4737 let global_style_data = &*GLOBAL_STYLE_DATA;
4738 let guard = global_style_data.shared_lock.read();
4739 let data = data.borrow();
4740 let rv = decls.read_with(&guard).single_value_to_css(
4746 debug_assert!(rv.is_ok());
4750 pub unsafe extern "C" fn Servo_SerializeFontValueForCanvas(
4751 declarations: &LockedDeclarationBlock,
4752 buffer: &mut nsACString,
4754 use style::properties::shorthands::font;
4755 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4756 let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) {
4759 warn!("Unexpected property!");
4764 let rv = longhands.to_css(&mut CssWriter::new(buffer));
4765 debug_assert!(rv.is_ok());
4770 pub extern "C" fn Servo_DeclarationBlock_Count(declarations: &LockedDeclarationBlock) -> u32 {
4771 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4772 decls.declarations().len() as u32
4777 pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(
4778 declarations: &LockedDeclarationBlock,
4780 result: &mut nsACString,
4782 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4783 if let Some(decl) = decls.declarations().get(index as usize) {
4784 result.assign(&decl.id().name());
4792 macro_rules! get_property_id_from_property {
4793 ($property: ident, $ret: expr) => {{
4794 let property = $property.as_str_unchecked();
4795 match PropertyId::parse_enabled_for_all_content(property) {
4796 Ok(property_id) => property_id,
4797 Err(_) => return $ret,
4802 unsafe fn get_property_value(
4803 declarations: &LockedDeclarationBlock,
4804 property_id: PropertyId,
4805 value: &mut nsACString,
4807 // This callsite is hot enough that the lock acquisition shows up in profiles.
4808 // Using an unchecked read here improves our performance by ~10% on the
4809 // microbenchmark in bug 1355599.
4810 read_locked_arc_unchecked(declarations, |decls: &PropertyDeclarationBlock| {
4811 decls.property_value_to_css(&property_id, value).unwrap();
4816 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValue(
4817 declarations: &LockedDeclarationBlock,
4818 property: &nsACString,
4819 value: &mut nsACString,
4823 get_property_id_from_property!(property, ()),
4829 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(
4830 declarations: &LockedDeclarationBlock,
4831 property: nsCSSPropertyID,
4832 value: &mut nsACString,
4836 get_property_id_from_nscsspropertyid!(property, ()),
4842 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(
4843 declarations: &LockedDeclarationBlock,
4844 property: &nsACString,
4846 let property_id = get_property_id_from_property!(property, false);
4847 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4848 decls.property_priority(&property_id).important()
4853 fn set_property_to_declarations(
4854 non_custom_property_id: Option<NonCustomPropertyId>,
4855 block: &LockedDeclarationBlock,
4856 parsed_declarations: &mut SourcePropertyDeclaration,
4857 before_change_closure: DeclarationBlockMutationClosure,
4858 importance: Importance,
4860 let mut updates = Default::default();
4861 let will_change = read_locked_arc(block, |decls: &PropertyDeclarationBlock| {
4862 decls.prepare_for_update(&parsed_declarations, importance, &mut updates)
4868 before_change_closure.invoke(non_custom_property_id);
4869 write_locked_arc(block, |decls: &mut PropertyDeclarationBlock| {
4870 decls.update(parsed_declarations.drain(), importance, &mut updates)
4876 declarations: &LockedDeclarationBlock,
4877 property_id: PropertyId,
4880 data: &UrlExtraData,
4881 parsing_mode: ParsingMode,
4882 quirks_mode: QuirksMode,
4883 loader: *mut Loader,
4884 rule_type: CssRuleType,
4885 before_change_closure: DeclarationBlockMutationClosure,
4887 let mut source_declarations = SourcePropertyDeclaration::default();
4888 let reporter = ErrorReporter::new(ptr::null_mut(), loader, data.ptr());
4889 let non_custom_property_id = property_id.non_custom_id();
4890 let result = parse_property_into(
4891 &mut source_declarations,
4899 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4902 if result.is_err() {
4906 let importance = if is_important {
4907 Importance::Important
4912 set_property_to_declarations(
4913 non_custom_property_id,
4915 &mut source_declarations,
4916 before_change_closure,
4922 pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
4923 declarations: &LockedDeclarationBlock,
4924 property: &nsACString,
4927 data: *mut URLExtraData,
4928 parsing_mode: ParsingMode,
4929 quirks_mode: nsCompatibility,
4930 loader: *mut Loader,
4931 rule_type: CssRuleType,
4932 before_change_closure: DeclarationBlockMutationClosure,
4936 get_property_id_from_property!(property, false),
4939 UrlExtraData::from_ptr_ref(&data),
4944 before_change_closure,
4949 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
4950 declarations: &LockedDeclarationBlock,
4951 animation_value: &AnimationValue,
4952 before_change_closure: DeclarationBlockMutationClosure,
4954 let non_custom_property_id = match animation_value.id() {
4955 PropertyDeclarationId::Longhand(id) => Some(id.into()),
4956 PropertyDeclarationId::Custom(_) => None,
4958 let mut source_declarations = SourcePropertyDeclaration::with_one(animation_value.uncompute());
4960 set_property_to_declarations(
4961 non_custom_property_id,
4963 &mut source_declarations,
4964 before_change_closure,
4970 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
4971 declarations: &LockedDeclarationBlock,
4972 property: nsCSSPropertyID,
4975 data: *mut URLExtraData,
4976 parsing_mode: ParsingMode,
4977 quirks_mode: nsCompatibility,
4978 loader: *mut Loader,
4979 rule_type: CssRuleType,
4980 before_change_closure: DeclarationBlockMutationClosure,
4984 get_property_id_from_nscsspropertyid!(property, false),
4987 UrlExtraData::from_ptr_ref(&data),
4992 before_change_closure,
4997 declarations: &LockedDeclarationBlock,
4998 property_id: PropertyId,
4999 before_change_closure: DeclarationBlockMutationClosure,
5001 let first_declaration = read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
5002 decls.first_declaration_to_remove(&property_id)
5005 let first_declaration = match first_declaration {
5007 None => return false,
5010 before_change_closure.invoke(property_id.non_custom_id());
5011 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5012 decls.remove_property(&property_id, first_declaration)
5019 pub unsafe extern "C" fn Servo_DeclarationBlock_RemoveProperty(
5020 declarations: &LockedDeclarationBlock,
5021 property: &nsACString,
5022 before_change_closure: DeclarationBlockMutationClosure,
5026 get_property_id_from_property!(property, false),
5027 before_change_closure,
5032 pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(
5033 declarations: &LockedDeclarationBlock,
5034 property: nsCSSPropertyID,
5035 before_change_closure: DeclarationBlockMutationClosure,
5039 get_property_id_from_nscsspropertyid!(property, false),
5040 before_change_closure,
5045 pub extern "C" fn Servo_MediaList_Create() -> Strong<LockedMediaList> {
5046 let global_style_data = &*GLOBAL_STYLE_DATA;
5047 Arc::new(global_style_data.shared_lock.wrap(MediaList::empty())).into()
5051 pub extern "C" fn Servo_MediaList_DeepClone(list: &LockedMediaList) -> Strong<LockedMediaList> {
5052 let global_style_data = &*GLOBAL_STYLE_DATA;
5053 read_locked_arc(list, |list: &MediaList| {
5054 Arc::new(global_style_data.shared_lock.wrap(list.clone())).into()
5059 pub extern "C" fn Servo_MediaList_Matches(
5060 list: &LockedMediaList,
5061 raw_data: &PerDocumentStyleData,
5063 let per_doc_data = raw_data.borrow();
5064 read_locked_arc(list, |list: &MediaList| {
5066 per_doc_data.stylist.device(),
5067 per_doc_data.stylist.quirks_mode(),
5073 pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword(
5074 declarations: &LockedDeclarationBlock,
5075 property: nsCSSPropertyID,
5077 let property_id = get_property_id_from_nscsspropertyid!(property, false);
5078 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
5079 decls.has_css_wide_keyword(&property_id)
5084 pub extern "C" fn Servo_MediaList_GetText(list: &LockedMediaList, result: &mut nsACString) {
5085 read_locked_arc(list, |list: &MediaList| {
5086 list.to_css(&mut CssWriter::new(result)).unwrap();
5091 pub unsafe extern "C" fn Servo_MediaList_SetText(
5092 list: &LockedMediaList,
5094 caller_type: CallerType,
5096 let text = text.as_str_unchecked();
5098 let mut input = ParserInput::new(&text);
5099 let mut parser = Parser::new(&mut input);
5100 let url_data = dummy_url_data();
5102 // TODO(emilio): If the need for `CallerType` appears in more places,
5103 // consider adding an explicit member in `ParserContext` instead of doing
5104 // this (or adding a dummy "chrome://" url data).
5106 // For media query parsing it's effectively the same, so for now...
5107 let origin = match caller_type {
5108 CallerType::System => Origin::UserAgent,
5109 CallerType::NonSystem => Origin::Author,
5112 let context = ParserContext::new(
5115 Some(CssRuleType::Media),
5116 ParsingMode::DEFAULT,
5117 QuirksMode::NoQuirks,
5118 /* namespaces = */ Default::default(),
5119 // TODO(emilio): Looks like error reporting could be useful here?
5124 write_locked_arc(list, |list: &mut MediaList| {
5125 *list = MediaList::parse(&context, &mut parser);
5130 pub extern "C" fn Servo_MediaList_IsViewportDependent(list: &LockedMediaList) -> bool {
5131 read_locked_arc(list, |list: &MediaList| list.is_viewport_dependent())
5135 pub extern "C" fn Servo_MediaList_GetLength(list: &LockedMediaList) -> u32 {
5136 read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32)
5140 pub extern "C" fn Servo_MediaList_GetMediumAt(
5141 list: &LockedMediaList,
5143 result: &mut nsACString,
5145 read_locked_arc(list, |list: &MediaList| {
5146 let media_query = match list.media_queries.get(index as usize) {
5148 None => return false,
5150 media_query.to_css(&mut CssWriter::new(result)).unwrap();
5156 pub extern "C" fn Servo_MediaList_AppendMedium(list: &LockedMediaList, new_medium: &nsACString) {
5157 let new_medium = unsafe { new_medium.as_str_unchecked() };
5158 let url_data = unsafe { dummy_url_data() };
5159 let context = ParserContext::new(
5162 Some(CssRuleType::Media),
5163 ParsingMode::DEFAULT,
5164 QuirksMode::NoQuirks,
5165 /* namespaces = */ Default::default(),
5169 write_locked_arc(list, |list: &mut MediaList| {
5170 list.append_medium(&context, new_medium);
5175 pub extern "C" fn Servo_MediaList_DeleteMedium(
5176 list: &LockedMediaList,
5177 old_medium: &nsACString,
5179 let old_medium = unsafe { old_medium.as_str_unchecked() };
5180 let url_data = unsafe { dummy_url_data() };
5181 let context = ParserContext::new(
5184 Some(CssRuleType::Media),
5185 ParsingMode::DEFAULT,
5186 QuirksMode::NoQuirks,
5187 /* namespaces = */ Default::default(),
5191 write_locked_arc(list, |list: &mut MediaList| {
5192 list.delete_medium(&context, old_medium)
5197 pub extern "C" fn Servo_MediaList_SizeOfIncludingThis(
5198 malloc_size_of: GeckoMallocSizeOf,
5199 malloc_enclosing_size_of: GeckoMallocSizeOf,
5200 list: &LockedMediaList,
5202 use malloc_size_of::MallocSizeOf;
5203 use malloc_size_of::MallocUnconditionalShallowSizeOf;
5205 let global_style_data = &*GLOBAL_STYLE_DATA;
5206 let guard = global_style_data.shared_lock.read();
5208 let mut ops = MallocSizeOfOps::new(
5209 malloc_size_of.unwrap(),
5210 Some(malloc_enclosing_size_of.unwrap()),
5214 unsafe { ArcBorrow::from_ref(list) }.with_arc(|list| {
5216 n += list.unconditional_shallow_size_of(&mut ops);
5217 n += list.read_with(&guard).size_of(&mut ops);
5222 macro_rules! get_longhand_from_id {
5224 match LonghandId::from_nscsspropertyid($id) {
5226 _ => panic!("stylo: unknown presentation property with id"),
5231 macro_rules! match_wrap_declared {
5232 ($longhand:ident, $($property:ident => $inner:expr,)*) => (
5235 LonghandId::$property => PropertyDeclaration::$property($inner),
5238 panic!("stylo: Don't know how to handle presentation property");
5245 pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(
5246 declarations: &LockedDeclarationBlock,
5247 property: nsCSSPropertyID,
5249 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
5250 decls.contains(PropertyDeclarationId::Longhand(get_longhand_from_id!(
5257 pub unsafe extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(
5258 declarations: &LockedDeclarationBlock,
5259 property: nsCSSPropertyID,
5262 use style::properties::longhands::_x_lang::computed_value::T as Lang;
5263 use style::properties::PropertyDeclaration;
5265 let long = get_longhand_from_id!(property);
5266 let prop = match_wrap_declared! { long,
5267 XLang => Lang(Atom::from_raw(value)),
5269 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5270 decls.push(prop, Importance::Normal);
5275 #[allow(unreachable_code)]
5276 pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
5277 declarations: &LockedDeclarationBlock,
5278 property: nsCSSPropertyID,
5281 use num_traits::FromPrimitive;
5282 use style::properties::longhands;
5283 use style::properties::PropertyDeclaration;
5284 use style::values::generics::box_::{VerticalAlign, VerticalAlignKeyword};
5285 use style::values::generics::font::FontStyle;
5286 use style::values::specified::{
5287 table::CaptionSide, BorderStyle, Clear, Display, Float, TextAlign, TextEmphasisPosition,
5291 fn get_from_computed<T>(value: u32) -> T
5294 T::ComputedValue: FromPrimitive,
5296 T::from_computed_value(&T::ComputedValue::from_u32(value).unwrap())
5299 let long = get_longhand_from_id!(property);
5300 let value = value as u32;
5302 let prop = match_wrap_declared! { long,
5303 MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value),
5304 Direction => get_from_computed::<longhands::direction::SpecifiedValue>(value),
5305 Display => get_from_computed::<Display>(value),
5306 Float => get_from_computed::<Float>(value),
5307 Clear => get_from_computed::<Clear>(value),
5308 VerticalAlign => VerticalAlign::Keyword(VerticalAlignKeyword::from_u32(value).unwrap()),
5309 TextAlign => get_from_computed::<TextAlign>(value),
5310 TextEmphasisPosition => TextEmphasisPosition::from_bits_retain(value as u8),
5312 // We rely on Gecko passing in font-size values (0...7) here.
5313 longhands::font_size::SpecifiedValue::from_html_size(value as u8)
5316 style::values::specified::FontStyle::Specified(if value == structs::NS_FONT_STYLE_ITALIC {
5319 debug_assert_eq!(value, structs::NS_FONT_STYLE_NORMAL);
5323 FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value),
5324 ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
5325 MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value),
5326 MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
5327 WhiteSpaceCollapse => get_from_computed::<longhands::white_space_collapse::SpecifiedValue>(value),
5328 TextWrapMode => get_from_computed::<longhands::text_wrap_mode::SpecifiedValue>(value),
5329 CaptionSide => get_from_computed::<CaptionSide>(value),
5330 BorderTopStyle => get_from_computed::<BorderStyle>(value),
5331 BorderRightStyle => get_from_computed::<BorderStyle>(value),
5332 BorderBottomStyle => get_from_computed::<BorderStyle>(value),
5333 BorderLeftStyle => get_from_computed::<BorderStyle>(value),
5335 debug_assert_eq!(value, structs::StyleTextTransformCase_None as u32);
5336 TextTransform::none()
5339 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5340 decls.push(prop, Importance::Normal);
5345 pub extern "C" fn Servo_DeclarationBlock_SetIntValue(
5346 declarations: &LockedDeclarationBlock,
5347 property: nsCSSPropertyID,
5350 use style::properties::PropertyDeclaration;
5351 use style::values::specified::Integer;
5353 let long = get_longhand_from_id!(property);
5354 let prop = match_wrap_declared! { long,
5355 XSpan => Integer::new(value),
5357 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5358 decls.push(prop, Importance::Normal);
5363 pub extern "C" fn Servo_DeclarationBlock_SetMathDepthValue(
5364 declarations: &LockedDeclarationBlock,
5368 use style::properties::longhands::math_depth::SpecifiedValue as MathDepth;
5369 use style::properties::PropertyDeclaration;
5371 let integer_value = style::values::specified::Integer::new(value);
5372 let prop = PropertyDeclaration::MathDepth(if is_relative {
5373 MathDepth::Add(integer_value)
5375 MathDepth::Absolute(integer_value)
5377 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5378 decls.push(prop, Importance::Normal);
5383 pub extern "C" fn Servo_DeclarationBlock_SetCounterResetListItem(
5384 declarations: &LockedDeclarationBlock,
5388 use style::properties::PropertyDeclaration;
5389 use style::values::generics::counters::{CounterPair, CounterReset};
5391 let prop = PropertyDeclaration::CounterReset(CounterReset::new(vec![CounterPair {
5392 name: CustomIdent(atom!("list-item")),
5393 value: style::values::specified::Integer::new(counter_value),
5396 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5397 decls.push(prop, Importance::Normal);
5402 pub extern "C" fn Servo_DeclarationBlock_SetCounterSetListItem(
5403 declarations: &LockedDeclarationBlock,
5406 use style::properties::PropertyDeclaration;
5407 use style::values::generics::counters::{CounterPair, CounterSet};
5409 let prop = PropertyDeclaration::CounterSet(CounterSet::new(vec![CounterPair {
5410 name: CustomIdent(atom!("list-item")),
5411 value: style::values::specified::Integer::new(counter_value),
5414 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5415 decls.push(prop, Importance::Normal);
5420 pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
5421 declarations: &LockedDeclarationBlock,
5422 property: nsCSSPropertyID,
5425 use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
5426 use style::properties::PropertyDeclaration;
5427 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5428 use style::values::generics::NonNegative;
5429 use style::values::specified::length::{
5430 LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage,
5432 use style::values::specified::{BorderCornerRadius, BorderSideWidth};
5434 let long = get_longhand_from_id!(property);
5435 let nocalc = NoCalcLength::from_px(value);
5436 let lp = LengthPercentage::Length(nocalc);
5437 let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
5438 let prop = match_wrap_declared! { long,
5439 Height => Size::LengthPercentage(NonNegative(lp)),
5440 Width => Size::LengthPercentage(NonNegative(lp)),
5441 BorderTopWidth => BorderSideWidth::from_px(value),
5442 BorderRightWidth => BorderSideWidth::from_px(value),
5443 BorderBottomWidth => BorderSideWidth::from_px(value),
5444 BorderLeftWidth => BorderSideWidth::from_px(value),
5445 MarginTop => lp_or_auto,
5446 MarginRight => lp_or_auto,
5447 MarginBottom => lp_or_auto,
5448 MarginLeft => lp_or_auto,
5449 PaddingTop => NonNegative(lp),
5450 PaddingRight => NonNegative(lp),
5451 PaddingBottom => NonNegative(lp),
5452 PaddingLeft => NonNegative(lp),
5454 let v = NonNegativeLength::from(nocalc);
5455 Box::new(BorderSpacing::new(v.clone(), v))
5457 BorderTopLeftRadius => {
5458 let length = NonNegativeLengthPercentage::from(nocalc);
5459 Box::new(BorderCornerRadius::new(length.clone(), length))
5461 BorderTopRightRadius => {
5462 let length = NonNegativeLengthPercentage::from(nocalc);
5463 Box::new(BorderCornerRadius::new(length.clone(), length))
5465 BorderBottomLeftRadius => {
5466 let length = NonNegativeLengthPercentage::from(nocalc);
5467 Box::new(BorderCornerRadius::new(length.clone(), length))
5469 BorderBottomRightRadius => {
5470 let length = NonNegativeLengthPercentage::from(nocalc);
5471 Box::new(BorderCornerRadius::new(length.clone(), length))
5474 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5475 decls.push(prop, Importance::Normal);
5480 pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
5481 declarations: &LockedDeclarationBlock,
5482 property: nsCSSPropertyID,
5484 unit: structs::nsCSSUnit,
5486 use style::properties::PropertyDeclaration;
5487 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5488 use style::values::generics::NonNegative;
5489 use style::values::specified::length::{
5490 FontRelativeLength, LengthPercentage, ViewportPercentageLength,
5492 use style::values::specified::FontSize;
5494 let long = get_longhand_from_id!(property);
5495 let nocalc = match unit {
5496 structs::nsCSSUnit::eCSSUnit_EM => {
5497 NoCalcLength::FontRelative(FontRelativeLength::Em(value))
5499 structs::nsCSSUnit::eCSSUnit_XHeight => {
5500 NoCalcLength::FontRelative(FontRelativeLength::Ex(value))
5502 structs::nsCSSUnit::eCSSUnit_RootEM => {
5503 NoCalcLength::FontRelative(FontRelativeLength::Rem(value))
5505 structs::nsCSSUnit::eCSSUnit_Char => {
5506 NoCalcLength::FontRelative(FontRelativeLength::Ch(value))
5508 structs::nsCSSUnit::eCSSUnit_Ideographic => {
5509 NoCalcLength::FontRelative(FontRelativeLength::Ic(value))
5511 structs::nsCSSUnit::eCSSUnit_CapHeight => {
5512 NoCalcLength::FontRelative(FontRelativeLength::Cap(value))
5514 structs::nsCSSUnit::eCSSUnit_Pixel => NoCalcLength::Absolute(AbsoluteLength::Px(value)),
5515 structs::nsCSSUnit::eCSSUnit_Inch => NoCalcLength::Absolute(AbsoluteLength::In(value)),
5516 structs::nsCSSUnit::eCSSUnit_Centimeter => {
5517 NoCalcLength::Absolute(AbsoluteLength::Cm(value))
5519 structs::nsCSSUnit::eCSSUnit_Millimeter => {
5520 NoCalcLength::Absolute(AbsoluteLength::Mm(value))
5522 structs::nsCSSUnit::eCSSUnit_Point => NoCalcLength::Absolute(AbsoluteLength::Pt(value)),
5523 structs::nsCSSUnit::eCSSUnit_Pica => NoCalcLength::Absolute(AbsoluteLength::Pc(value)),
5524 structs::nsCSSUnit::eCSSUnit_Quarter => NoCalcLength::Absolute(AbsoluteLength::Q(value)),
5525 structs::nsCSSUnit::eCSSUnit_VW => {
5526 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(value))
5528 structs::nsCSSUnit::eCSSUnit_VH => {
5529 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vh(value))
5531 structs::nsCSSUnit::eCSSUnit_VMin => {
5532 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmin(value))
5534 structs::nsCSSUnit::eCSSUnit_VMax => {
5535 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmax(value))
5537 _ => unreachable!("Unknown unit passed to SetLengthValue"),
5540 let prop = match_wrap_declared! { long,
5541 Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5542 Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5543 X => LengthPercentage::Length(nocalc),
5544 Y => LengthPercentage::Length(nocalc),
5545 Cx => LengthPercentage::Length(nocalc),
5546 Cy => LengthPercentage::Length(nocalc),
5547 R => NonNegative(LengthPercentage::Length(nocalc)),
5548 Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5549 Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5550 FontSize => FontSize::Length(LengthPercentage::Length(nocalc)),
5552 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5553 decls.push(prop, Importance::Normal);
5558 pub extern "C" fn Servo_DeclarationBlock_SetPathValue(
5559 declarations: &LockedDeclarationBlock,
5560 property: nsCSSPropertyID,
5561 path: &nsTArray<f32>,
5563 use style::properties::PropertyDeclaration;
5564 use style::values::specified::DProperty;
5566 // 1. Decode the path data from SVG.
5567 let path = match specified::SVGPathData::decode_from_f32_array(path) {
5572 // 2. Set decoded path into style.
5573 let long = get_longhand_from_id!(property);
5574 let prop = match_wrap_declared! { long,
5575 D => if path.0.is_empty() { DProperty::None } else { DProperty::Path(path) },
5577 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5578 decls.push(prop, Importance::Normal);
5583 pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
5584 declarations: &LockedDeclarationBlock,
5585 property: nsCSSPropertyID,
5588 use style::properties::PropertyDeclaration;
5589 use style::values::computed::Percentage;
5590 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5591 use style::values::generics::NonNegative;
5592 use style::values::specified::length::LengthPercentage;
5593 use style::values::specified::FontSize;
5595 let long = get_longhand_from_id!(property);
5596 let pc = Percentage(value);
5597 let lp = LengthPercentage::Percentage(pc);
5598 let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
5600 let prop = match_wrap_declared! { long,
5601 Height => Size::LengthPercentage(NonNegative(lp)),
5602 Width => Size::LengthPercentage(NonNegative(lp)),
5607 R => NonNegative(lp),
5608 Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5609 Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5610 MarginTop => lp_or_auto,
5611 MarginRight => lp_or_auto,
5612 MarginBottom => lp_or_auto,
5613 MarginLeft => lp_or_auto,
5614 FontSize => FontSize::Length(LengthPercentage::Percentage(pc)),
5616 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5617 decls.push(prop, Importance::Normal);
5622 pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(
5623 declarations: &LockedDeclarationBlock,
5624 property: nsCSSPropertyID,
5626 use style::properties::PropertyDeclaration;
5627 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5629 let long = get_longhand_from_id!(property);
5630 let auto = LengthPercentageOrAuto::Auto;
5632 let prop = match_wrap_declared! { long,
5633 Height => Size::auto(),
5634 Width => Size::auto(),
5636 MarginRight => auto,
5637 MarginBottom => auto,
5639 AspectRatio => specified::AspectRatio::auto(),
5641 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5642 decls.push(prop, Importance::Normal);
5647 pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(
5648 declarations: &LockedDeclarationBlock,
5649 property: nsCSSPropertyID,
5651 use style::properties::PropertyDeclaration;
5652 use style::values::specified::Color;
5654 let long = get_longhand_from_id!(property);
5655 let cc = Color::currentcolor();
5657 let prop = match_wrap_declared! { long,
5658 BorderTopColor => cc,
5659 BorderRightColor => cc,
5660 BorderBottomColor => cc,
5661 BorderLeftColor => cc,
5663 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5664 decls.push(prop, Importance::Normal);
5669 pub extern "C" fn Servo_DeclarationBlock_SetColorValue(
5670 declarations: &LockedDeclarationBlock,
5671 property: nsCSSPropertyID,
5672 value: structs::nscolor,
5674 use style::gecko::values::convert_nscolor_to_absolute_color;
5675 use style::properties::longhands;
5676 use style::properties::PropertyDeclaration;
5677 use style::values::specified::Color;
5679 let long = get_longhand_from_id!(property);
5680 let rgba = convert_nscolor_to_absolute_color(value);
5681 let color = Color::from_absolute_color(rgba);
5683 let prop = match_wrap_declared! { long,
5684 BorderTopColor => color,
5685 BorderRightColor => color,
5686 BorderBottomColor => color,
5687 BorderLeftColor => color,
5688 Color => longhands::color::SpecifiedValue(color),
5689 BackgroundColor => color,
5691 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5692 decls.push(prop, Importance::Normal);
5697 pub unsafe extern "C" fn Servo_DeclarationBlock_SetFontFamily(
5698 declarations: &LockedDeclarationBlock,
5701 use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
5702 use style::properties::PropertyDeclaration;
5704 let string = value.as_str_unchecked();
5705 let mut input = ParserInput::new(&string);
5706 let mut parser = Parser::new(&mut input);
5707 let context = ParserContext::new(
5710 Some(CssRuleType::Style),
5711 ParsingMode::DEFAULT,
5712 QuirksMode::NoQuirks,
5713 /* namespaces = */ Default::default(),
5717 let result = FontFamily::parse(&context, &mut parser);
5718 if let Ok(family) = result {
5719 if parser.is_exhausted() {
5720 let decl = PropertyDeclaration::FontFamily(family);
5721 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5722 decls.push(decl, Importance::Normal);
5729 pub unsafe extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(
5730 declarations: &LockedDeclarationBlock,
5732 raw_extra_data: *mut URLExtraData,
5734 use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
5735 use style::properties::PropertyDeclaration;
5736 use style::stylesheets::CorsMode;
5737 use style::values::generics::image::Image;
5738 use style::values::specified::url::SpecifiedImageUrl;
5740 let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
5741 let string = value.as_str_unchecked();
5742 let context = ParserContext::new(
5745 Some(CssRuleType::Style),
5746 ParsingMode::DEFAULT,
5747 QuirksMode::NoQuirks,
5748 /* namespaces = */ Default::default(),
5752 let url = SpecifiedImageUrl::parse_from_string(string.into(), &context, CorsMode::None);
5753 let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(vec![Image::Url(url)].into()));
5754 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5755 decls.push(decl, Importance::Normal);
5760 pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(
5761 declarations: &LockedDeclarationBlock,
5763 use style::properties::PropertyDeclaration;
5764 use style::values::specified::text::TextDecorationLine;
5766 let decoration = TextDecorationLine::COLOR_OVERRIDE;
5767 let decl = PropertyDeclaration::TextDecorationLine(decoration);
5768 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5769 decls.push(decl, Importance::Normal);
5774 pub extern "C" fn Servo_DeclarationBlock_SetAspectRatio(
5775 declarations: &LockedDeclarationBlock,
5779 use style::properties::PropertyDeclaration;
5780 use style::values::generics::position::AspectRatio;
5782 let decl = PropertyDeclaration::AspectRatio(AspectRatio::from_mapped_ratio(width, height));
5783 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5784 decls.push(decl, Importance::Normal);
5789 pub extern "C" fn Servo_CSSSupports2(property: &nsACString, value: &nsACString) -> bool {
5790 let id = unsafe { get_property_id_from_property!(property, false) };
5792 let mut declarations = SourcePropertyDeclaration::default();
5793 parse_property_into(
5798 unsafe { dummy_url_data() },
5799 ParsingMode::DEFAULT,
5800 QuirksMode::NoQuirks,
5808 pub extern "C" fn Servo_CSSSupports(
5814 let condition = unsafe { cond.as_str_unchecked() };
5815 let mut input = ParserInput::new(&condition);
5816 let mut input = Parser::new(&mut input);
5817 let cond = match input.parse_entirely(parse_condition_or_declaration) {
5819 Err(..) => return false,
5822 let origin = if ua_origin {
5827 let url_data = unsafe {
5828 UrlExtraData::from_ptr_ref(if chrome_sheet {
5829 &DUMMY_CHROME_URL_DATA
5834 let quirks_mode = if quirks {
5837 QuirksMode::NoQuirks
5840 // NOTE(emilio): The supports API is not associated to any stylesheet,
5841 // so the fact that there is no namespace map here is fine.
5842 let context = ParserContext::new(
5845 Some(CssRuleType::Style),
5846 ParsingMode::DEFAULT,
5848 /* namespaces = */ Default::default(),
5857 pub extern "C" fn Servo_CSSSupportsForImport(after_rule: &nsACString) -> bool {
5858 let condition = unsafe { after_rule.as_str_unchecked() };
5859 let mut input = ParserInput::new(&condition);
5860 let mut input = Parser::new(&mut input);
5862 // NOTE(emilio): The supports API is not associated to any stylesheet,
5863 // so the fact that there is no namespace map here is fine.
5864 let mut context = ParserContext::new(
5866 unsafe { dummy_url_data() },
5867 Some(CssRuleType::Style),
5868 ParsingMode::DEFAULT,
5869 QuirksMode::NoQuirks,
5870 /* namespaces = */ Default::default(),
5875 let (_layer, supports) = ImportRule::parse_layer_and_supports(&mut input, &mut context);
5877 supports.map_or(true, |s| s.enabled)
5881 pub unsafe extern "C" fn Servo_NoteExplicitHints(
5882 element: &RawGeckoElement,
5883 restyle_hint: RestyleHint,
5884 change_hint: nsChangeHint,
5886 GeckoElement(element).note_explicit_hints(restyle_hint, change_hint);
5890 pub extern "C" fn Servo_TakeChangeHint(element: &RawGeckoElement, was_restyled: &mut bool) -> u32 {
5891 let element = GeckoElement(element);
5893 let damage = match element.mutate_data() {
5895 *was_restyled = data.is_restyle();
5897 let damage = data.damage;
5898 data.clear_restyle_state();
5902 warn!("Trying to get change hint from unstyled element");
5903 *was_restyled = false;
5904 GeckoRestyleDamage::empty()
5908 debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
5909 // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
5910 // work as return values with the Linux 32-bit ABI at the moment because
5911 // they wrap the value in a struct, so for now just unwrap it.
5912 damage.as_change_hint().0
5916 pub extern "C" fn Servo_ResolveStyle(element: &RawGeckoElement) -> Strong<ComputedValues> {
5917 let element = GeckoElement(element);
5918 debug!("Servo_ResolveStyle: {:?}", element);
5921 .expect("Resolving style on unstyled element");
5924 element.has_current_styles(&*data),
5925 "Resolving style on {:?} without current styles: {:?}",
5929 data.styles.primary().clone().into()
5933 pub extern "C" fn Servo_ResolveStyleLazily(
5934 element: &RawGeckoElement,
5935 pseudo_type: PseudoStyleType,
5936 functional_pseudo_parameter: *mut nsAtom,
5937 rule_inclusion: StyleRuleInclusion,
5938 snapshots: *const ServoElementSnapshotTable,
5939 cache_generation: u64,
5940 can_use_cache: bool,
5941 raw_data: &PerDocumentStyleData,
5942 ) -> Strong<ComputedValues> {
5943 debug_assert!(!snapshots.is_null());
5944 let global_style_data = &*GLOBAL_STYLE_DATA;
5945 let guard = global_style_data.shared_lock.read();
5946 let element = GeckoElement(element);
5947 let mut data = raw_data.borrow_mut();
5948 let data = &mut *data;
5949 let rule_inclusion = RuleInclusion::from(rule_inclusion);
5950 let pseudo_element = PseudoElement::from_pseudo_type(
5952 get_functional_pseudo_parameter_atom(functional_pseudo_parameter),
5955 let matching_fn = |pseudo: &PseudoElement| match pseudo_element {
5956 Some(ref p) => *pseudo == *p,
5960 if cache_generation != data.undisplayed_style_cache_generation {
5961 data.undisplayed_style_cache.clear();
5962 data.undisplayed_style_cache_generation = cache_generation;
5965 let stylist = &data.stylist;
5966 let finish = |styles: &ElementStyles, is_probe: bool| -> Option<Arc<ComputedValues>> {
5967 match pseudo_element {
5968 Some(ref pseudo) => {
5975 /* inherited_styles = */ None,
5978 if pseudo.is_highlight() {
5985 None => Some(styles.primary().clone()),
5989 let is_before_or_after = pseudo_element
5991 .map_or(false, |p| p.is_before_or_after());
5993 // In the common case we already have the style. Check that before setting
5994 // up all the computation machinery.
5996 // Also, only probe in the ::before or ::after case, since their styles may
5997 // not be in the `ElementData`, given they may exist but not be applicable
5998 // to generate an actual pseudo-element (like, having a `content: none`).
5999 if rule_inclusion == RuleInclusion::All {
6000 let styles = element.borrow_data().and_then(|d| {
6002 finish(&d.styles, is_before_or_after)
6007 if let Some(result) = styles {
6008 return result.into();
6010 if pseudo_element.is_none() && can_use_cache {
6011 if let Some(style) = data.undisplayed_style_cache.get(&element.opaque()) {
6012 return style.clone().into();
6017 // We don't have the style ready. Go ahead and compute it as necessary.
6018 let shared = create_shared_context(
6022 TraversalFlags::empty(),
6023 unsafe { &*snapshots },
6025 let mut tlc = ThreadLocalStyleContext::new();
6026 let mut context = StyleContext {
6028 thread_local: &mut tlc,
6031 let styles = resolve_style(
6035 pseudo_element.as_ref(),
6037 Some(&mut data.undisplayed_style_cache)
6043 finish(&styles, /* is_probe = */ false)
6044 .expect("We're not probing, so we should always get a style back")
6049 pub extern "C" fn Servo_ReparentStyle(
6050 style_to_reparent: &ComputedValues,
6051 parent_style: &ComputedValues,
6052 layout_parent_style: &ComputedValues,
6053 element: Option<&RawGeckoElement>,
6054 raw_data: &PerDocumentStyleData,
6055 ) -> Strong<ComputedValues> {
6056 use style::properties::FirstLineReparenting;
6058 let global_style_data = &*GLOBAL_STYLE_DATA;
6059 let guard = global_style_data.shared_lock.read();
6060 let doc_data = raw_data.borrow();
6061 let inputs = CascadeInputs::new_from_style(style_to_reparent);
6062 let pseudo = style_to_reparent.pseudo();
6063 let element = element.map(GeckoElement);
6067 .cascade_style_and_visited(
6071 &StylesheetGuards::same(&guard),
6073 Some(layout_parent_style),
6074 FirstLineReparenting::Yes { style_to_reparent },
6075 /* rule_cache = */ None,
6076 &mut RuleCacheConditions::default(),
6081 #[cfg(feature = "gecko_debug")]
6082 fn simulate_compute_values_failure(property: &PropertyValuePair) -> bool {
6083 let p = &property.mProperty;
6084 let id = get_property_id_from_animatedpropertyid!(p, false);
6085 id.as_shorthand().is_ok() && property.mSimulateComputeValuesFailure
6088 #[cfg(not(feature = "gecko_debug"))]
6089 fn simulate_compute_values_failure(_: &PropertyValuePair) -> bool {
6093 fn create_context_for_animation<'a>(
6094 per_doc_data: &'a PerDocumentStyleDataImpl,
6095 style: &'a ComputedValues,
6096 parent_style: Option<&'a ComputedValues>,
6097 for_smil_animation: bool,
6098 rule_cache_conditions: &'a mut RuleCacheConditions,
6099 container_size_query: ContainerSizeQuery<'a>,
6101 Context::new_for_animation(
6102 StyleBuilder::for_animation(
6103 per_doc_data.stylist.device(),
6104 Some(&per_doc_data.stylist),
6109 per_doc_data.stylist.quirks_mode(),
6110 rule_cache_conditions,
6111 container_size_query,
6115 struct PropertyAndIndex {
6116 property: PropertyId,
6120 struct PrioritizedPropertyIter<'a> {
6121 properties: &'a [PropertyValuePair],
6122 sorted_property_indices: Vec<PropertyAndIndex>,
6126 impl<'a> PrioritizedPropertyIter<'a> {
6127 fn new(properties: &'a [PropertyValuePair]) -> PrioritizedPropertyIter {
6128 use style::values::animated::compare_property_priority;
6130 // If we fail to convert a nsCSSPropertyID into a PropertyId we
6131 // shouldn't fail outright but instead by treating that property as the
6132 // 'all' property we make it sort last.
6133 let mut sorted_property_indices: Vec<PropertyAndIndex> = properties
6136 .map(|(index, pair)| {
6137 let property = PropertyId::from_gecko_animated_property_id(&pair.mProperty)
6138 .unwrap_or(PropertyId::NonCustom(ShorthandId::All.into()));
6139 PropertyAndIndex { property, index }
6142 sorted_property_indices.sort_by(|a, b| compare_property_priority(&a.property, &b.property));
6144 PrioritizedPropertyIter {
6146 sorted_property_indices,
6151 fn reset(&mut self) {
6156 impl<'a> Iterator for PrioritizedPropertyIter<'a> {
6157 type Item = &'a PropertyValuePair;
6159 fn next(&mut self) -> Option<&'a PropertyValuePair> {
6160 if self.curr >= self.sorted_property_indices.len() {
6164 Some(&self.properties[self.sorted_property_indices[self.curr - 1].index])
6169 pub extern "C" fn Servo_GetComputedKeyframeValues(
6170 keyframes: &nsTArray<structs::Keyframe>,
6171 element: &RawGeckoElement,
6172 pseudo_type: PseudoStyleType,
6173 style: &ComputedValues,
6174 raw_data: &PerDocumentStyleData,
6175 computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>,
6177 use style::applicable_declarations::CascadePriority;
6178 use style::custom_properties::CustomPropertiesBuilder;
6179 use style::properties::PropertyDeclaration;
6180 let data = raw_data.borrow();
6181 let element = GeckoElement(element);
6182 let pseudo = PseudoElement::from_pseudo_type(pseudo_type, None);
6183 let parent_element = if pseudo.is_none() {
6184 element.inheritance_parent()
6188 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6189 let parent_style = parent_data
6191 .map(|d| d.styles.primary())
6194 let container_size_query =
6195 ContainerSizeQuery::for_element(element, parent_style, pseudo.is_some());
6196 let mut conditions = Default::default();
6197 let mut context = create_context_for_animation(
6201 /* for_smil_animation = */ false,
6203 container_size_query,
6206 let restriction = pseudo.and_then(|p| p.property_restriction());
6208 let global_style_data = &*GLOBAL_STYLE_DATA;
6209 let guard = global_style_data.shared_lock.read();
6210 let default_values = data.default_computed_values();
6212 for (index, keyframe) in keyframes.iter().enumerate() {
6213 let ref mut animation_values = computed_keyframes[index];
6215 let mut seen = PropertyDeclarationIdSet::default();
6216 let mut iter = PrioritizedPropertyIter::new(&keyframe.mPropertyValues);
6218 // FIXME (bug 1883255): This is pretty much a hack. Instead, the AnimatedValue should be
6219 // better integrated in the cascade.
6221 let mut builder = CustomPropertiesBuilder::new_with_properties(
6223 style.custom_properties().clone(),
6226 let priority = CascadePriority::same_tree_author_normal_at_root_layer();
6227 for property in &mut iter {
6229 match PropertyId::from_gecko_animated_property_id(&property.mProperty) {
6230 Some(PropertyId::Custom(..)) => true,
6234 break; // Custom props are guaranteed to sort earlier.
6236 if property.mServoDeclarationBlock.mRawPtr.is_null() {
6239 let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr };
6240 let guard = declarations.read_with(&guard);
6241 for decl in guard.normal_declaration_iter() {
6242 if let PropertyDeclaration::Custom(ref declaration) = *decl {
6243 builder.cascade(declaration, priority);
6248 let _deferred = builder.build(DeferFontRelativeCustomPropertyResolution::No);
6250 _deferred.is_none(),
6251 "Custom property processing deferred despite specifying otherwise?"
6255 let mut property_index = 0;
6256 for property in iter {
6257 if simulate_compute_values_failure(property) {
6261 let mut maybe_append_animation_value =
6262 |property: PropertyDeclarationId, value: Option<AnimationValue>| {
6263 debug_assert!(!property.is_logical());
6264 debug_assert!(property.is_animatable());
6266 // 'display' is only animatable from SMIL
6267 if property == PropertyDeclarationId::Longhand(LonghandId::Display) {
6271 // Skip restricted properties
6272 if restriction.map_or(false, |r| !property.flags().contains(r)) {
6276 if seen.contains(property) {
6279 seen.insert(property);
6281 // This is safe since we immediately write to the uninitialized values.
6283 animation_values.set_len((property_index + 1) as u32);
6285 &mut animation_values[property_index],
6286 structs::PropertyStyleAnimationValuePair {
6288 .to_gecko_animated_property_id(/* owned = */ true),
6289 mValue: structs::AnimationValue {
6290 mServo: value.map_or(structs::RefPtr::null(), |v| {
6291 structs::RefPtr::from_arc(Arc::new(v))
6297 property_index += 1;
6300 if property.mServoDeclarationBlock.mRawPtr.is_null() {
6302 OwnedPropertyDeclarationId::from_gecko_animated_property_id(&property.mProperty)
6304 maybe_append_animation_value(prop.as_borrowed(), None);
6309 let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr };
6310 let guard = declarations.read_with(&guard);
6311 let iter = guard.to_animation_value_iter(&mut context, &default_values);
6314 maybe_append_animation_value(value.id(), Some(value.clone()));
6321 pub extern "C" fn Servo_GetAnimationValues(
6322 declarations: &LockedDeclarationBlock,
6323 element: &RawGeckoElement,
6324 style: &ComputedValues,
6325 raw_data: &PerDocumentStyleData,
6326 animation_values: &mut ThinVec<structs::RefPtr<AnimationValue>>,
6328 let data = raw_data.borrow();
6329 let element = GeckoElement(element);
6330 let parent_element = element.inheritance_parent();
6331 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6332 let parent_style = parent_data
6334 .map(|d| d.styles.primary())
6337 let container_size_query =
6338 ContainerSizeQuery::for_element(element, None, /* is_pseudo = */ false);
6339 let mut conditions = Default::default();
6340 let mut context = create_context_for_animation(
6344 /* for_smil_animation = */ true,
6346 container_size_query,
6349 let default_values = data.default_computed_values();
6350 let global_style_data = &*GLOBAL_STYLE_DATA;
6351 let guard = global_style_data.shared_lock.read();
6353 let guard = declarations.read_with(&guard);
6354 let iter = guard.to_animation_value_iter(&mut context, &default_values);
6355 animation_values.extend(iter.map(|v| structs::RefPtr::from_arc(Arc::new(v))));
6359 pub extern "C" fn Servo_AnimationValue_GetPropertyId(
6360 value: &AnimationValue,
6361 property_id: &mut structs::AnimatedPropertyID,
6363 *property_id = value.id().to_gecko_animated_property_id(/* owned = */ true);
6367 pub extern "C" fn Servo_AnimationValue_Compute(
6368 element: &RawGeckoElement,
6369 declarations: &LockedDeclarationBlock,
6370 style: &ComputedValues,
6371 raw_data: &PerDocumentStyleData,
6372 ) -> Strong<AnimationValue> {
6373 let data = raw_data.borrow();
6375 let element = GeckoElement(element);
6376 let parent_element = element.inheritance_parent();
6377 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6378 let parent_style = parent_data
6380 .map(|d| d.styles.primary())
6383 let container_size_query =
6384 ContainerSizeQuery::for_element(element, None, /* is_pseudo = */ false);
6385 let mut conditions = Default::default();
6386 let mut context = create_context_for_animation(
6390 /* for_smil_animation = */ false,
6392 container_size_query,
6395 let default_values = data.default_computed_values();
6396 let global_style_data = &*GLOBAL_STYLE_DATA;
6397 let guard = global_style_data.shared_lock.read();
6398 // We only compute the first element in declarations.
6401 .declaration_importance_iter()
6404 Some((decl, imp)) if imp == Importance::Normal => {
6405 let animation = AnimationValue::from_declaration(decl, &mut context, default_values);
6406 animation.map_or(Strong::null(), |value| Arc::new(value).into())
6408 _ => Strong::null(),
6413 pub extern "C" fn Servo_AssertTreeIsClean(root: &RawGeckoElement) {
6414 if !cfg!(feature = "gecko_debug") {
6415 panic!("Calling Servo_AssertTreeIsClean in release build");
6418 let root = GeckoElement(root);
6419 debug!("Servo_AssertTreeIsClean: ");
6420 debug!("{:?}", ShowSubtreeData(root.as_node()));
6422 fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) {
6424 !el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants(),
6425 "{:?} has still dirty bit {:?} or animation-only dirty bit {:?}",
6427 el.has_dirty_descendants(),
6428 el.has_animation_only_dirty_descendants()
6430 for child in el.traversal_children() {
6431 if let Some(child) = child.as_element() {
6432 assert_subtree_is_clean(child);
6437 assert_subtree_is_clean(root);
6441 pub extern "C" fn Servo_IsWorkerThread() -> bool {
6442 thread_state::get().is_worker()
6450 fn fill_in_missing_keyframe_values(
6451 all_properties: &PropertyDeclarationIdSet,
6452 timing_function: &ComputedTimingFunction,
6453 properties_at_offset: &PropertyDeclarationIdSet,
6455 keyframes: &mut nsTArray<structs::Keyframe>,
6457 // Return early if all animated properties are already set.
6458 if properties_at_offset.contains_all(all_properties) {
6462 // Use auto for missing keyframes.
6463 // FIXME: This may be a spec issue in css-animations-2 because the spec says the default
6464 // keyframe-specific composite is replace, but web-animations-1 uses auto. Use auto now so we
6465 // use the value of animation-composition of the element, for missing keyframes.
6466 // https://github.com/w3c/csswg-drafts/issues/7476
6467 let composition = structs::CompositeOperationOrAuto::Auto;
6468 let keyframe = match offset {
6469 Offset::Zero => unsafe {
6470 Gecko_GetOrCreateInitialKeyframe(keyframes, timing_function, composition)
6472 Offset::One => unsafe {
6473 Gecko_GetOrCreateFinalKeyframe(keyframes, timing_function, composition)
6477 // Append properties that have not been set at this offset.
6478 for property in all_properties.iter() {
6479 if !properties_at_offset.contains(property) {
6481 Gecko_AppendPropertyValuePair(
6482 &mut *(*keyframe).mPropertyValues,
6483 &property.to_gecko_animated_property_id(/* owned = */ false),
6491 pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
6492 raw_data: &PerDocumentStyleData,
6493 element: &RawGeckoElement,
6494 style: &ComputedValues,
6496 inherited_timing_function: &ComputedTimingFunction,
6497 keyframes: &mut nsTArray<structs::Keyframe>,
6499 use style::gecko_bindings::structs::CompositeOperationOrAuto;
6500 use style::values::computed::AnimationComposition;
6502 debug_assert!(keyframes.len() == 0, "keyframes should be initially empty");
6504 let element = GeckoElement(element);
6505 let data = raw_data.borrow();
6506 let name = Atom::from_raw(name);
6508 let animation = match data.stylist.get_animation(&name, element) {
6509 Some(animation) => animation,
6510 None => return false,
6513 let global_style_data = &*GLOBAL_STYLE_DATA;
6514 let guard = global_style_data.shared_lock.read();
6516 let mut properties_set_at_current_offset = PropertyDeclarationIdSet::default();
6517 let mut properties_set_at_start = PropertyDeclarationIdSet::default();
6518 let mut properties_set_at_end = PropertyDeclarationIdSet::default();
6519 let mut has_complete_initial_keyframe = false;
6520 let mut has_complete_final_keyframe = false;
6521 let mut current_offset = -1.;
6523 let writing_mode = style.writing_mode;
6525 // Iterate over the keyframe rules backwards so we can drop overridden
6526 // properties (since declarations in later rules override those in earlier
6528 for step in animation.steps.iter().rev() {
6529 if step.start_percentage.0 != current_offset {
6530 properties_set_at_current_offset.clear();
6531 current_offset = step.start_percentage.0;
6534 // Override timing_function if the keyframe has an animation-timing-function.
6535 let timing_function = match step.get_animation_timing_function(&guard) {
6536 Some(val) => val.to_computed_value_without_context(),
6537 None => (*inherited_timing_function).clone(),
6540 // Override composite operation if the keyframe has an animation-composition.
6542 step.get_animation_composition(&guard)
6543 .map_or(CompositeOperationOrAuto::Auto, |val| match val {
6544 AnimationComposition::Replace => CompositeOperationOrAuto::Replace,
6545 AnimationComposition::Add => CompositeOperationOrAuto::Add,
6546 AnimationComposition::Accumulate => CompositeOperationOrAuto::Accumulate,
6549 // Look for an existing keyframe with the same offset, timing function, and compsition, or
6550 // else add a new keyframe at the beginning of the keyframe array.
6551 let keyframe = Gecko_GetOrCreateKeyframeAtStart(
6553 step.start_percentage.0 as f32,
6559 KeyframesStepValue::ComputedValues => {
6560 // In KeyframesAnimation::from_keyframes if there is no 0% or
6561 // 100% keyframe at all, we will create a 'ComputedValues' step
6562 // to represent that all properties animated by the keyframes
6563 // animation should be set to the underlying computed value for
6565 let mut seen = PropertyDeclarationIdSet::default();
6566 for property in animation.properties_changed.iter() {
6567 let property = property.to_physical(writing_mode);
6568 if seen.contains(property) {
6571 seen.insert(property);
6573 Gecko_AppendPropertyValuePair(
6574 &mut *(*keyframe).mPropertyValues,
6575 &property.to_gecko_animated_property_id(/* owned = */ false),
6578 if current_offset == 0.0 {
6579 has_complete_initial_keyframe = true;
6580 } else if current_offset == 1.0 {
6581 has_complete_final_keyframe = true;
6584 KeyframesStepValue::Declarations { ref block } => {
6585 let guard = block.read_with(&guard);
6587 // Filter out non-animatable properties and properties with
6590 // Also, iterate in reverse to respect the source order in case
6591 // there are logical and physical longhands in the same block.
6592 for declaration in guard.normal_declaration_iter().rev() {
6593 let id = declaration.id().to_physical(writing_mode);
6595 // Skip non-animatable properties, including the 'display' property because
6596 // although it is animatable from SMIL, it should not be animatable from CSS
6598 if !id.is_animatable() ||
6599 id == PropertyDeclarationId::Longhand(LonghandId::Display)
6604 if properties_set_at_current_offset.contains(id) {
6608 let pair = Gecko_AppendPropertyValuePair(
6609 &mut *(*keyframe).mPropertyValues,
6610 &id.to_gecko_animated_property_id(/* owned = */ false),
6613 (*pair).mServoDeclarationBlock.set_arc(Arc::new(
6616 .wrap(PropertyDeclarationBlock::with_one(
6617 declaration.to_physical(writing_mode),
6622 if current_offset == 0.0 {
6623 properties_set_at_start.insert(id);
6624 } else if current_offset == 1.0 {
6625 properties_set_at_end.insert(id);
6627 properties_set_at_current_offset.insert(id);
6633 let mut properties_changed = PropertyDeclarationIdSet::default();
6634 for property in animation.properties_changed.iter() {
6635 properties_changed.insert(property.to_physical(writing_mode));
6638 // Append property values that are missing in the initial or the final keyframes.
6639 if !has_complete_initial_keyframe {
6640 fill_in_missing_keyframe_values(
6641 &properties_changed,
6642 inherited_timing_function,
6643 &properties_set_at_start,
6648 if !has_complete_final_keyframe {
6649 fill_in_missing_keyframe_values(
6650 &properties_changed,
6651 inherited_timing_function,
6652 &properties_set_at_end,
6661 pub extern "C" fn Servo_StyleSet_GetFontFaceRules(
6662 raw_data: &PerDocumentStyleData,
6663 rules: &mut ThinVec<structs::nsFontFaceRuleContainer>,
6665 let data = raw_data.borrow();
6666 debug_assert_eq!(rules.len(), 0);
6668 // Reversed iterator because Gecko expects rules to appear sorted
6669 // UserAgent first, Author last.
6670 let font_face_iter = data
6672 .iter_extra_data_origins_rev()
6673 .flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o)));
6675 rules.extend(font_face_iter.map(|(&(ref rule, _layer_id), origin)| {
6676 structs::nsFontFaceRuleContainer {
6677 mRule: structs::RefPtr::from_arc(rule.clone()),
6683 // XXX Ideally this should return a Option<&LockedCounterStyleRule>,
6684 // but we cannot, because the value from AtomicRefCell::borrow() can only
6685 // live in this function, and thus anything derived from it cannot get the
6686 // same lifetime as raw_data in parameter. See bug 1451543.
6688 pub unsafe extern "C" fn Servo_StyleSet_GetCounterStyleRule(
6689 raw_data: &PerDocumentStyleData,
6691 ) -> *const LockedCounterStyleRule {
6692 let data = raw_data.borrow();
6693 Atom::with(name, |name| {
6695 .iter_extra_data_origins()
6696 .find_map(|(d, _)| d.counter_styles.get(name))
6697 .map_or(ptr::null(), |rule| &**rule as *const _)
6702 pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet(
6703 raw_data: &PerDocumentStyleData,
6704 ) -> *mut gfxFontFeatureValueSet {
6705 let data = raw_data.borrow();
6709 .iter_extra_data_origins()
6710 .any(|(d, _)| !d.font_feature_values.is_empty());
6713 return ptr::null_mut();
6716 let font_feature_values_iter = data
6718 .iter_extra_data_origins_rev()
6719 .flat_map(|(d, _)| d.font_feature_values.iter());
6721 let set = unsafe { Gecko_ConstructFontFeatureValueSet() };
6722 for &(ref rule, _) in font_feature_values_iter {
6723 rule.set_at_rules(set);
6729 pub extern "C" fn Servo_StyleSet_BuildFontPaletteValueSet(
6730 raw_data: &PerDocumentStyleData,
6731 ) -> *mut FontPaletteValueSet {
6732 let data = raw_data.borrow();
6736 .iter_extra_data_origins()
6737 .any(|(d, _)| !d.font_palette_values.is_empty());
6740 return ptr::null_mut();
6743 let font_palette_values_iter = data
6745 .iter_extra_data_origins_rev()
6746 .flat_map(|(d, _)| d.font_palette_values.iter());
6748 let set = unsafe { Gecko_ConstructFontPaletteValueSet() };
6749 for &(ref rule, _) in font_palette_values_iter {
6750 rule.to_gecko_palette_value_set(set);
6756 pub extern "C" fn Servo_StyleSet_ResolveForDeclarations(
6757 raw_data: &PerDocumentStyleData,
6758 parent_style_context: Option<&ComputedValues>,
6759 declarations: &LockedDeclarationBlock,
6760 ) -> Strong<ComputedValues> {
6761 let doc_data = raw_data.borrow();
6762 let global_style_data = &*GLOBAL_STYLE_DATA;
6763 let guard = global_style_data.shared_lock.read();
6764 let guards = StylesheetGuards::same(&guard);
6766 let parent_style = match parent_style_context {
6767 Some(parent) => &*parent,
6768 None => doc_data.default_computed_values(),
6773 .compute_for_declarations::<GeckoElement>(&guards, parent_style, unsafe {
6774 Arc::from_raw_addrefed(declarations)
6780 pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis(
6781 malloc_size_of: GeckoMallocSizeOf,
6782 malloc_enclosing_size_of: GeckoMallocSizeOf,
6783 sizes: *mut ServoStyleSetSizes,
6784 raw_data: &PerDocumentStyleData,
6786 let data = raw_data.borrow_mut();
6787 let mut ops = MallocSizeOfOps::new(
6788 malloc_size_of.unwrap(),
6789 Some(malloc_enclosing_size_of.unwrap()),
6792 let sizes = unsafe { sizes.as_mut() }.unwrap();
6793 data.add_size_of(&mut ops, sizes);
6797 pub extern "C" fn Servo_UACache_AddSizeOf(
6798 malloc_size_of: GeckoMallocSizeOf,
6799 malloc_enclosing_size_of: GeckoMallocSizeOf,
6800 sizes: *mut ServoStyleSetSizes,
6802 let mut ops = MallocSizeOfOps::new(
6803 malloc_size_of.unwrap(),
6804 Some(malloc_enclosing_size_of.unwrap()),
6807 let sizes = unsafe { sizes.as_mut() }.unwrap();
6808 add_size_of_ua_cache(&mut ops, sizes);
6812 pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
6813 raw_data: &PerDocumentStyleData,
6814 element: &RawGeckoElement,
6815 local_name: *mut nsAtom,
6817 let data = raw_data.borrow();
6818 let element = GeckoElement(element);
6821 AtomIdent::with(local_name, |atom| {
6822 data.stylist.any_applicable_rule_data(element, |data| {
6823 data.might_have_attribute_dependency(atom)
6830 pub extern "C" fn Servo_StyleSet_MightHaveNthOfIDDependency(
6831 raw_data: &PerDocumentStyleData,
6832 element: &RawGeckoElement,
6833 old_id: *mut nsAtom,
6834 new_id: *mut nsAtom,
6836 let data = raw_data.borrow();
6837 let element = GeckoElement(element);
6839 data.stylist.any_applicable_rule_data(element, |data| {
6842 .filter(|id| !id.is_null())
6844 AtomIdent::with(*id, |atom| data.might_have_nth_of_id_dependency(atom))
6846 data.might_have_nth_of_attribute_dependency(&AtomIdent(atom!("id")))
6851 pub extern "C" fn Servo_StyleSet_MightHaveNthOfClassDependency(
6852 raw_data: &PerDocumentStyleData,
6853 element: &RawGeckoElement,
6854 snapshots: &ServoElementSnapshotTable,
6856 let data = raw_data.borrow();
6857 let element = GeckoElement(element);
6859 data.stylist.any_applicable_rule_data(element, |data| {
6860 classes_changed(&element, snapshots)
6862 .any(|atom| data.might_have_nth_of_class_dependency(atom)) ||
6863 data.might_have_nth_of_attribute_dependency(&AtomIdent(atom!("class")))
6868 pub extern "C" fn Servo_StyleSet_MightHaveNthOfAttributeDependency(
6869 raw_data: &PerDocumentStyleData,
6870 element: &RawGeckoElement,
6871 local_name: *mut nsAtom,
6873 let data = raw_data.borrow();
6874 let element = GeckoElement(element);
6877 AtomIdent::with(local_name, |atom| {
6878 data.stylist.any_applicable_rule_data(element, |data| {
6879 data.might_have_nth_of_attribute_dependency(atom)
6885 fn on_siblings_invalidated(element: GeckoElement) {
6886 let parent = element
6888 .expect("How could we invalidate siblings without a common parent?");
6890 parent.set_dirty_descendants();
6891 bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0);
6895 fn restyle_for_nth_of(element: GeckoElement, flags: ElementSelectorFlags) {
6898 "Calling restyle for nth but no relevant flag is set."
6900 fn invalidate_siblings_of(
6901 element: GeckoElement,
6902 get_sibling: fn(GeckoElement) -> Option<GeckoElement>,
6904 let mut sibling = get_sibling(element);
6905 while let Some(sib) = sibling {
6906 if let Some(mut data) = sib.mutate_data() {
6907 data.hint.insert(RestyleHint::restyle_subtree());
6909 sibling = get_sibling(sib);
6913 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
6914 invalidate_siblings_of(element, |e| e.prev_sibling_element());
6916 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
6917 invalidate_siblings_of(element, |e| e.next_sibling_element());
6919 on_siblings_invalidated(element);
6922 fn relative_selector_invalidated_at(element: GeckoElement, result: &InvalidationResult) {
6923 if result.has_invalidated_siblings() {
6924 on_siblings_invalidated(element);
6925 } else if result.has_invalidated_descendants() {
6926 unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) };
6927 } else if result.has_invalidated_self() {
6928 unsafe { bindings::Gecko_NoteDirtyElement(element.0) };
6931 .map_or(ElementSelectorFlags::empty(), |e| e.slow_selector_flags());
6932 // We invalidated up to the anchor, and it has a flag for nth-of invalidation.
6933 if !flags.is_empty() {
6934 restyle_for_nth_of(element, flags);
6939 fn add_relative_selector_attribute_dependency<'a>(
6940 element: &GeckoElement<'a>,
6941 scope: &Option<OpaqueElement>,
6942 invalidation_map: &'a RelativeSelectorInvalidationMap,
6943 attribute: &AtomIdent,
6944 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>,
6946 match invalidation_map
6948 .other_attribute_affecting_selectors
6952 for dependency in v {
6953 collector.add_dependency(dependency, *element, *scope);
6960 fn inherit_relative_selector_search_direction(
6961 parent: Option<GeckoElement>,
6962 prev_sibling: Option<GeckoElement>,
6963 ) -> ElementSelectorFlags {
6964 let mut inherited = ElementSelectorFlags::empty();
6965 if let Some(parent) = parent {
6966 if let Some(direction) = parent.relative_selector_search_direction() {
6967 inherited |= direction
6968 .intersection(ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR);
6971 if let Some(sibling) = prev_sibling {
6972 if let Some(direction) = sibling.relative_selector_search_direction() {
6973 // Inherit both, for e.g. a sibling with `:has(~.sibling .descendant)`
6974 inherited |= direction.intersection(
6975 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING,
6983 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorIDDependency(
6984 raw_data: &PerDocumentStyleData,
6985 element: &RawGeckoElement,
6986 old_id: *mut nsAtom,
6987 new_id: *mut nsAtom,
6988 snapshots: &ServoElementSnapshotTable,
6990 let data = raw_data.borrow();
6991 let element = GeckoElement(element);
6993 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
6994 let invalidator = RelativeSelectorInvalidator {
6997 snapshot_table: Some(snapshots),
6998 invalidated: relative_selector_invalidated_at,
6999 sibling_traversal_map: SiblingTraversalMap::default(),
7000 _marker: std::marker::PhantomData,
7003 invalidator.invalidate_relative_selectors_for_this(
7005 |element, scope, data, quirks_mode, collector| {
7006 let invalidation_map = data.relative_selector_invalidation_map();
7007 relative_selector_dependencies_for_id(
7016 add_relative_selector_attribute_dependency(
7020 &AtomIdent(atom!("id")),
7028 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorClassDependency(
7029 raw_data: &PerDocumentStyleData,
7030 element: &RawGeckoElement,
7031 snapshots: &ServoElementSnapshotTable,
7033 let data = raw_data.borrow();
7034 let element = GeckoElement(element);
7035 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7036 let invalidator = RelativeSelectorInvalidator {
7039 snapshot_table: Some(snapshots),
7040 invalidated: relative_selector_invalidated_at,
7041 sibling_traversal_map: SiblingTraversalMap::default(),
7042 _marker: std::marker::PhantomData,
7045 invalidator.invalidate_relative_selectors_for_this(
7047 |element, scope, data, quirks_mode, mut collector| {
7048 let invalidation_map = data.relative_selector_invalidation_map();
7050 relative_selector_dependencies_for_class(
7051 &classes_changed(element, snapshots),
7058 add_relative_selector_attribute_dependency(
7062 &AtomIdent(atom!("class")),
7070 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorAttributeDependency(
7071 raw_data: &PerDocumentStyleData,
7072 element: &RawGeckoElement,
7073 local_name: *mut nsAtom,
7074 snapshots: &ServoElementSnapshotTable,
7076 let data = raw_data.borrow();
7077 let element = GeckoElement(element);
7079 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7081 AtomIdent::with(local_name, |atom| {
7082 let invalidator = RelativeSelectorInvalidator {
7085 snapshot_table: Some(snapshots),
7086 invalidated: relative_selector_invalidated_at,
7087 sibling_traversal_map: SiblingTraversalMap::default(),
7088 _marker: std::marker::PhantomData,
7091 invalidator.invalidate_relative_selectors_for_this(
7093 |element, scope, data, _quirks_mode, mut collector| {
7094 add_relative_selector_attribute_dependency(
7097 data.relative_selector_invalidation_map(),
7108 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorStateDependency(
7109 raw_data: &PerDocumentStyleData,
7110 element: &RawGeckoElement,
7112 snapshots: &ServoElementSnapshotTable,
7114 let element = GeckoElement(element);
7116 let state = match ElementState::from_bits(state) {
7117 Some(state) => state,
7120 let data = raw_data.borrow();
7121 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7123 let invalidator = RelativeSelectorInvalidator {
7126 snapshot_table: Some(snapshots),
7127 invalidated: relative_selector_invalidated_at,
7128 sibling_traversal_map: SiblingTraversalMap::default(),
7129 _marker: std::marker::PhantomData,
7132 invalidator.invalidate_relative_selectors_for_this(
7134 |element, scope, data, quirks_mode, collector| {
7135 let invalidation_map = data.relative_selector_invalidation_map();
7138 .state_affecting_selectors
7139 .lookup_with_additional(*element, quirks_mode, None, &[], state, |dependency| {
7140 if !dependency.state.intersects(state) {
7143 collector.add_dependency(&dependency.dep, *element, scope);
7150 fn invalidate_relative_selector_prev_sibling_side_effect(
7151 prev_sibling: GeckoElement,
7152 quirks_mode: QuirksMode,
7153 sibling_traversal_map: SiblingTraversalMap<GeckoElement>,
7156 let invalidator = RelativeSelectorInvalidator {
7157 element: prev_sibling,
7159 snapshot_table: None,
7160 invalidated: relative_selector_invalidated_at,
7161 sibling_traversal_map,
7162 _marker: std::marker::PhantomData,
7164 invalidator.invalidate_relative_selectors_for_dom_mutation(
7167 ElementSelectorFlags::empty(),
7168 DomMutationOperation::SideEffectPrevSibling,
7172 fn invalidate_relative_selector_next_sibling_side_effect(
7173 next_sibling: GeckoElement,
7174 quirks_mode: QuirksMode,
7175 sibling_traversal_map: SiblingTraversalMap<GeckoElement>,
7178 let invalidator = RelativeSelectorInvalidator {
7179 element: next_sibling,
7181 snapshot_table: None,
7182 invalidated: relative_selector_invalidated_at,
7183 sibling_traversal_map,
7184 _marker: std::marker::PhantomData,
7186 invalidator.invalidate_relative_selectors_for_dom_mutation(
7189 ElementSelectorFlags::empty(),
7190 DomMutationOperation::SideEffectNextSibling,
7194 fn invalidate_relative_selector_ts_dependency(
7195 raw_data: &PerDocumentStyleData,
7196 element: GeckoElement,
7197 state: TSStateForInvalidation,
7199 let data = raw_data.borrow();
7200 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7202 let invalidator = RelativeSelectorInvalidator {
7205 snapshot_table: None,
7206 invalidated: relative_selector_invalidated_at,
7207 sibling_traversal_map: SiblingTraversalMap::default(),
7208 _marker: std::marker::PhantomData,
7211 invalidator.invalidate_relative_selectors_for_this(
7213 |element, scope, data, quirks_mode, collector| {
7214 let invalidation_map = data.relative_selector_invalidation_map();
7216 .ts_state_to_selector
7217 .lookup_with_additional(
7222 ElementState::empty(),
7224 if !dependency.state.intersects(state) {
7227 collector.add_dependency(&dependency.dep, *element, scope);
7236 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorEmptyDependency(
7237 raw_data: &PerDocumentStyleData,
7238 element: &RawGeckoElement,
7240 invalidate_relative_selector_ts_dependency(
7242 GeckoElement(element),
7243 TSStateForInvalidation::EMPTY,
7248 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorNthEdgeDependency(
7249 raw_data: &PerDocumentStyleData,
7250 element: &RawGeckoElement,
7252 invalidate_relative_selector_ts_dependency(
7254 GeckoElement(element),
7255 TSStateForInvalidation::NTH_EDGE,
7260 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorNthDependencyFromSibling(
7261 raw_data: &PerDocumentStyleData,
7262 element: &RawGeckoElement,
7264 let mut element = Some(GeckoElement(element));
7266 // Short of doing the actual matching, any of the siblings can match the selector, so we
7267 // have to try invalidating against all of them.
7268 while let Some(sibling) = element {
7269 invalidate_relative_selector_ts_dependency(raw_data, sibling, TSStateForInvalidation::NTH);
7270 element = sibling.next_sibling_element();
7275 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForInsertion(
7276 raw_data: &PerDocumentStyleData,
7277 element: &RawGeckoElement,
7279 let element = GeckoElement(element);
7280 let data = raw_data.borrow();
7281 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7283 let inherited = inherit_relative_selector_search_direction(
7284 element.parent_element(),
7285 element.prev_sibling_element(),
7287 // Technically, we're not handling breakouts, where the anchor is a (later-sibling) descendant.
7288 // For descendant case, we're ok since it's a descendant of an element yet to be styled.
7289 // For later-sibling descendant, `HAS_SLOW_SELECTOR_LATER_SIBLINGS` is set anyway.
7290 if inherited.is_empty() {
7294 // Ok, we could've been inserted between two sibling elements that were connected
7295 // through next sibling. This can happen in two ways:
7297 // * `:has(.. .a + .b ..)`
7298 // Note that the previous sibling may be the anchor, and not part of the invalidation chain.
7299 // Either way, there must be siblings to both sides of the element being inserted
7302 element.prev_sibling_element(),
7303 element.next_sibling_element(),
7305 (Some(prev_sibling), Some(next_sibling)) => 'sibling: {
7306 // If the prev sibling is not on the sibling search path, skip.
7308 .relative_selector_search_direction()
7309 .map_or(true, |direction| {
7310 !direction.intersects(
7311 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
7317 element.apply_selector_flags(
7318 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
7320 invalidate_relative_selector_prev_sibling_side_effect(
7323 SiblingTraversalMap::new(
7325 prev_sibling.prev_sibling_element(),
7326 element.next_sibling_element(),
7327 ), // Pretend this inserted element isn't here.
7330 invalidate_relative_selector_next_sibling_side_effect(
7333 SiblingTraversalMap::new(
7336 next_sibling.next_sibling_element(),
7344 let invalidator = RelativeSelectorInvalidator {
7347 snapshot_table: None,
7348 invalidated: relative_selector_invalidated_at,
7349 sibling_traversal_map: SiblingTraversalMap::default(),
7350 _marker: std::marker::PhantomData,
7353 invalidator.invalidate_relative_selectors_for_dom_mutation(
7357 DomMutationOperation::Insert,
7362 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForAppend(
7363 raw_data: &PerDocumentStyleData,
7364 first_node: &RawGeckoNode,
7366 let first_node = GeckoNode(first_node);
7367 let inherited = inherit_relative_selector_search_direction(
7368 first_node.parent_element(),
7369 first_node.prev_sibling_element(),
7371 if inherited.is_empty() {
7374 let first_element = if let Some(e) = first_node.as_element() {
7376 } else if let Some(e) = first_node.next_sibling_element() {
7381 let data = raw_data.borrow();
7382 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7384 let mut element = Some(first_element);
7385 while let Some(e) = element {
7386 let invalidator = RelativeSelectorInvalidator {
7389 snapshot_table: None,
7390 sibling_traversal_map: SiblingTraversalMap::default(),
7391 invalidated: relative_selector_invalidated_at,
7392 _marker: std::marker::PhantomData,
7394 invalidator.invalidate_relative_selectors_for_dom_mutation(
7398 DomMutationOperation::Append,
7400 element = e.next_sibling_element();
7404 fn get_siblings_of_element<'e>(
7405 element: GeckoElement<'e>,
7406 following_node: &'e Option<GeckoNode<'e>>,
7407 ) -> (Option<GeckoElement<'e>>, Option<GeckoElement<'e>>) {
7408 let node = match following_node {
7411 return match element.as_node().parent_node() {
7412 Some(p) => (p.last_child_element(), None),
7413 None => (None, None),
7418 (node.prev_sibling_element(), node.next_sibling_element())
7422 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForRemoval(
7423 raw_data: &PerDocumentStyleData,
7424 element: &RawGeckoElement,
7425 following_node: Option<&RawGeckoNode>,
7427 let element = GeckoElement(element);
7429 // This element was in-tree, so we can safely say that if it was not on
7430 // the relative selector search path, its removal will not invalidate any
7431 // relative selector.
7432 if element.relative_selector_search_direction().is_none() {
7435 let following_node = following_node.map(GeckoNode);
7436 let (prev_sibling, next_sibling) = get_siblings_of_element(element, &following_node);
7437 let data = raw_data.borrow();
7438 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7441 inherit_relative_selector_search_direction(element.parent_element(), prev_sibling);
7442 if inherited.is_empty() {
7446 // Same comment as insertion applies.
7447 match (prev_sibling, next_sibling) {
7448 (Some(prev_sibling), Some(next_sibling)) => {
7449 invalidate_relative_selector_prev_sibling_side_effect(
7452 SiblingTraversalMap::default(),
7455 invalidate_relative_selector_next_sibling_side_effect(
7458 SiblingTraversalMap::default(),
7464 let invalidator = RelativeSelectorInvalidator {
7467 snapshot_table: None,
7468 sibling_traversal_map: SiblingTraversalMap::new(element, prev_sibling, next_sibling),
7469 invalidated: relative_selector_invalidated_at,
7470 _marker: std::marker::PhantomData,
7472 invalidator.invalidate_relative_selectors_for_dom_mutation(
7476 DomMutationOperation::Remove,
7481 pub extern "C" fn Servo_StyleSet_HasStateDependency(
7482 raw_data: &PerDocumentStyleData,
7483 element: &RawGeckoElement,
7486 let element = GeckoElement(element);
7488 let state = ElementState::from_bits_retain(state);
7489 let data = raw_data.borrow();
7492 .any_applicable_rule_data(element, |data| data.has_state_dependency(state))
7496 pub extern "C" fn Servo_StyleSet_HasNthOfStateDependency(
7497 raw_data: &PerDocumentStyleData,
7498 element: &RawGeckoElement,
7501 let element = GeckoElement(element);
7503 let state = ElementState::from_bits_retain(state);
7504 let data = raw_data.borrow();
7507 .any_applicable_rule_data(element, |data| data.has_nth_of_state_dependency(state))
7511 pub extern "C" fn Servo_StyleSet_RestyleSiblingsForNthOf(element: &RawGeckoElement, flags: u32) {
7512 let flags = slow_selector_flags_from_node_selector_flags(flags);
7513 let element = GeckoElement(element);
7514 restyle_for_nth_of(element, flags);
7518 pub extern "C" fn Servo_StyleSet_HasDocumentStateDependency(
7519 raw_data: &PerDocumentStyleData,
7522 let state = DocumentState::from_bits_retain(state);
7523 let data = raw_data.borrow();
7525 data.stylist.has_document_state_dependency(state)
7528 fn computed_or_resolved_value(
7529 style: &ComputedValues,
7530 prop: nsCSSPropertyID,
7531 context: Option<&style::values::resolved::Context>,
7532 value: &mut nsACString,
7534 if let Some(longhand) = LonghandId::from_nscsspropertyid(prop) {
7536 .computed_or_resolved_value(longhand, context, value)
7541 ShorthandId::from_nscsspropertyid(prop).expect("Not a shorthand nor a longhand?");
7542 let mut block = PropertyDeclarationBlock::new();
7543 for longhand in shorthand.longhands() {
7545 style.computed_or_resolved_declaration(longhand, context),
7549 block.shorthand_to_css(shorthand, value).unwrap();
7553 pub unsafe extern "C" fn Servo_GetComputedValue(
7554 style: &ComputedValues,
7555 prop: nsCSSPropertyID,
7556 value: &mut nsACString,
7558 computed_or_resolved_value(style, prop, None, value)
7562 pub unsafe extern "C" fn Servo_GetResolvedValue(
7563 style: &ComputedValues,
7564 prop: nsCSSPropertyID,
7565 raw_data: &PerDocumentStyleData,
7566 element: &RawGeckoElement,
7567 value: &mut nsACString,
7569 use style::values::resolved;
7571 let data = raw_data.borrow();
7572 let device = data.stylist.device();
7573 let context = resolved::Context {
7576 element_info: resolved::ResolvedElementInfo {
7577 element: GeckoElement(element),
7581 computed_or_resolved_value(style, prop, Some(&context), value)
7585 pub unsafe extern "C" fn Servo_GetCustomPropertyValue(
7586 computed_values: &ComputedValues,
7587 raw_style_set: &PerDocumentStyleData,
7589 value: &mut nsACString,
7591 let doc_data = raw_style_set.borrow();
7592 let name = Atom::from(name.as_str_unchecked());
7593 let custom_registration = doc_data.stylist.get_custom_property_registration(&name);
7594 let computed_value = if custom_registration.inherits() {
7595 computed_values.custom_properties.inherited.get(&name)
7597 computed_values.custom_properties.non_inherited.get(&name)
7600 if let Some(v) = computed_value {
7601 v.to_css(&mut CssWriter::new(value)).unwrap();
7609 pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u32 {
7610 // Just expose the custom property items from custom_properties.inherited
7611 // and custom_properties.non_inherited.
7612 let properties = computed_values.custom_properties();
7613 properties.inherited.len() as u32 + properties.non_inherited.len() as u32
7617 pub extern "C" fn Servo_GetCustomPropertyNameAt(
7618 computed_values: &ComputedValues,
7621 match &computed_values
7623 .property_at(index as usize)
7625 Some((name, _value)) => name.as_ptr(),
7626 None => ptr::null_mut(),
7631 pub extern "C" fn Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool {
7635 fn relative_selector_dependencies_for_id<'a>(
7636 old_id: *const nsAtom,
7637 new_id: *const nsAtom,
7638 element: &GeckoElement<'a>,
7639 scope: Option<OpaqueElement>,
7640 quirks_mode: QuirksMode,
7641 invalidation_map: &'a RelativeSelectorInvalidationMap,
7642 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>,
7646 .filter(|id| !id.is_null())
7647 .for_each(|id| unsafe {
7648 AtomIdent::with(*id, |atom| {
7649 match invalidation_map.map.id_to_selector.get(atom, quirks_mode) {
7651 for dependency in v {
7652 collector.add_dependency(dependency, *element, scope);
7661 fn relative_selector_dependencies_for_class<'a>(
7662 classes_changed: &SmallVec<[Atom; 8]>,
7663 element: &GeckoElement<'a>,
7664 scope: Option<OpaqueElement>,
7665 quirks_mode: QuirksMode,
7666 invalidation_map: &'a RelativeSelectorInvalidationMap,
7667 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>,
7669 classes_changed.iter().for_each(|atom| {
7670 match invalidation_map
7673 .get(atom, quirks_mode)
7676 for dependency in v {
7677 collector.add_dependency(dependency, *element, scope);
7685 fn process_relative_selector_invalidations(
7686 element: &GeckoElement,
7687 snapshot_table: &ServoElementSnapshotTable,
7688 data: &PerDocumentStyleDataImpl,
7690 let snapshot = match snapshot_table.get(element) {
7694 let mut states = None;
7695 let mut classes = None;
7697 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7698 let invalidator = RelativeSelectorInvalidator {
7701 invalidated: relative_selector_invalidated_at,
7702 sibling_traversal_map: SiblingTraversalMap::default(),
7703 snapshot_table: Some(snapshot_table),
7704 _marker: std::marker::PhantomData,
7707 invalidator.invalidate_relative_selectors_for_this(
7709 |element, scope, data, quirks_mode, collector| {
7710 let invalidation_map = data.relative_selector_invalidation_map();
7711 let states = *states.get_or_insert_with(|| {
7712 ElementWrapper::new(*element, snapshot_table).state_changes()
7714 let classes = classes.get_or_insert_with(|| classes_changed(element, snapshot_table));
7715 if snapshot.id_changed() {
7716 relative_selector_dependencies_for_id(
7719 .map(|id| id.as_ptr().cast_const())
7720 .unwrap_or(ptr::null()),
7723 .map(|id| id.as_ptr().cast_const())
7724 .unwrap_or(ptr::null()),
7732 relative_selector_dependencies_for_class(
7740 snapshot.each_attr_changed(|attr| {
7741 add_relative_selector_attribute_dependency(
7751 .state_affecting_selectors
7752 .lookup_with_additional(*element, quirks_mode, None, &[], states, |dependency| {
7753 if !dependency.state.intersects(states) {
7756 collector.add_dependency(&dependency.dep, *element, scope);
7764 pub extern "C" fn Servo_ProcessInvalidations(
7765 set: &PerDocumentStyleData,
7766 element: &RawGeckoElement,
7767 snapshots: *const ServoElementSnapshotTable,
7769 debug_assert!(!snapshots.is_null());
7771 let element = GeckoElement(element);
7772 debug_assert!(element.has_snapshot());
7773 debug_assert!(!element.handled_snapshot());
7775 let snapshot_table = unsafe { &*snapshots };
7776 let per_doc_data = set.borrow();
7777 process_relative_selector_invalidations(&element, snapshot_table, &per_doc_data);
7779 let mut data = element.mutate_data();
7781 // Snapshot for unstyled element is really only meant for relative selector
7782 // invalidation, so this is fine.
7786 let global_style_data = &*GLOBAL_STYLE_DATA;
7787 let guard = global_style_data.shared_lock.read();
7788 let per_doc_data = set.borrow();
7789 let shared_style_context = create_shared_context(
7792 &per_doc_data.stylist,
7793 TraversalFlags::empty(),
7796 let mut data = data.as_mut().map(|d| &mut **d);
7798 let mut selector_caches = SelectorCaches::default();
7799 if let Some(ref mut data) = data {
7800 // FIXME(emilio): Ideally we could share the nth-index-cache across all
7802 let result = data.invalidate_style_if_needed(
7804 &shared_style_context,
7806 &mut selector_caches,
7809 if result.has_invalidated_siblings() {
7810 let parent = element
7812 .expect("How could we invalidate siblings without a common parent?");
7814 parent.set_dirty_descendants();
7815 bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0);
7817 } else if result.has_invalidated_descendants() {
7818 unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) };
7819 } else if result.has_invalidated_self() {
7820 unsafe { bindings::Gecko_NoteDirtyElement(element.0) };
7826 pub extern "C" fn Servo_HasPendingRestyleAncestor(
7827 element: &RawGeckoElement,
7828 may_need_to_flush_layout: bool,
7830 let mut has_yet_to_be_styled = false;
7831 let mut element = Some(GeckoElement(element));
7832 while let Some(e) = element {
7833 if e.has_any_animation() {
7837 // If the element needs a frame, it means that we haven't styled it yet
7838 // after it got inserted in the document, and thus we may need to do
7839 // that for transitions and animations to trigger.
7841 // This is a fast path in the common case, but `has_yet_to_be_styled` is
7842 // the real check for this.
7843 if e.needs_frame() {
7847 let data = e.borrow_data();
7848 if let Some(ref data) = data {
7849 if !data.hint.is_empty() {
7852 if has_yet_to_be_styled && !data.styles.is_display_none() {
7855 // Ideally, DOM mutations wouldn't affect layout trees of siblings.
7857 // In practice, this can happen because Gecko deals pretty badly
7858 // with some kinds of content insertion and removals.
7860 // If we may need to flush layout, we need frames to accurately
7861 // determine whether we'll actually flush, so if we have to
7862 // reconstruct we need to flush style, which is what will take care
7863 // of ensuring that frames are constructed, even if the style itself
7865 if may_need_to_flush_layout && data.damage.contains(GeckoRestyleDamage::reconstruct()) {
7869 has_yet_to_be_styled = data.is_none();
7871 element = e.traversal_parent();
7877 pub unsafe extern "C" fn Servo_SelectorList_Parse(
7878 selector_list: &nsACString,
7880 ) -> *mut SelectorList {
7881 use style::selector_parser::SelectorParser;
7883 let url_data = UrlExtraData::from_ptr_ref(if is_chrome {
7884 &DUMMY_CHROME_URL_DATA
7889 let input = selector_list.as_str_unchecked();
7890 let selector_list = match SelectorParser::parse_author_origin_no_namespace(&input, url_data) {
7891 Ok(selector_list) => selector_list,
7892 Err(..) => return ptr::null_mut(),
7895 Box::into_raw(Box::new(selector_list))
7899 pub unsafe extern "C" fn Servo_SelectorList_Drop(list: *mut SelectorList) {
7900 let _ = Box::from_raw(list);
7904 pub unsafe extern "C" fn Servo_IsValidCSSColor(value: &nsACString) -> bool {
7905 let mut input = ParserInput::new(value.as_str_unchecked());
7906 let mut input = Parser::new(&mut input);
7907 let context = ParserContext::new(
7910 Some(CssRuleType::Style),
7911 ParsingMode::DEFAULT,
7912 QuirksMode::NoQuirks,
7913 /* namespaces = */ Default::default(),
7917 specified::Color::is_valid(&context, &mut input)
7921 pub unsafe extern "C" fn Servo_ComputeColor(
7922 raw_data: Option<&PerDocumentStyleData>,
7923 current_color: structs::nscolor,
7925 result_color: &mut structs::nscolor,
7926 was_current_color: *mut bool,
7927 loader: *mut Loader,
7929 let mut input = ParserInput::new(value.as_str_unchecked());
7930 let mut input = Parser::new(&mut input);
7931 let reporter = loader.as_mut().and_then(|loader| {
7932 // Make an ErrorReporter that will report errors as being "from DOM".
7933 ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut())
7936 let context = ParserContext::new(
7939 Some(CssRuleType::Style),
7940 ParsingMode::DEFAULT,
7941 QuirksMode::NoQuirks,
7942 /* namespaces = */ Default::default(),
7943 reporter.as_ref().map(|e| e as &dyn ParseErrorReporter),
7948 let device = match raw_data {
7951 Some(data.stylist.device())
7956 let computed = match specified::Color::parse_and_compute(&context, &mut input, device) {
7958 None => return false,
7961 let current_color = style::gecko::values::convert_nscolor_to_absolute_color(current_color);
7962 if !was_current_color.is_null() {
7963 *was_current_color = computed.is_currentcolor();
7966 let rgba = computed.resolve_to_absolute(¤t_color);
7967 *result_color = style::gecko::values::convert_absolute_color_to_nscolor(&rgba);
7972 pub unsafe extern "C" fn Servo_ColorTo(
7973 from_color: &nsACString,
7974 to_color_space: &nsACString,
7975 result_color: &mut nsACString,
7976 result_components: &mut nsTArray<f32>,
7977 result_adjusted: &mut bool,
7978 loader: *mut Loader,
7980 // Figure out the color space.
7981 let mut input = ParserInput::new(to_color_space.as_str_unchecked());
7982 let mut input = Parser::new(&mut input);
7983 let to_color_space = match ColorSpace::parse(&mut input) {
7984 Ok(color_space) => color_space,
7986 // Can't parse the color space? Fail the conversion.
7991 let mut input = ParserInput::new(from_color.as_str_unchecked());
7992 let mut input = Parser::new(&mut input);
7994 let reporter = loader.as_mut().and_then(|loader| {
7995 // Make an ErrorReporter that will report errors as being "from DOM".
7996 ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut())
7999 let context = ParserContext::new(
8002 Some(CssRuleType::Style),
8003 ParsingMode::DEFAULT,
8004 QuirksMode::NoQuirks,
8005 /* namespaces = */ Default::default(),
8006 reporter.as_ref().map(|e| e as &dyn ParseErrorReporter),
8010 let specified = match specified::Color::parse(&context, &mut input) {
8012 Err(_) => return false,
8015 let color = match specified {
8016 specified::Color::Absolute(ref absolute) => &absolute.color,
8018 // Can't do anything with a non-absolute color from here, so we
8019 // fail the conversion.
8024 let color = color.to_color_space(to_color_space);
8025 let mut s = String::new();
8027 .write_author_preferred_value(&mut CssWriter::new(&mut s))
8029 result_color.assign(&s);
8031 result_components.assign_from_iter_pod(color.raw_components().iter().copied());
8033 // For now we don't do gamut mapping, so always false.
8034 *result_adjusted = false;
8040 pub extern "C" fn Servo_ResolveColor(
8041 color: &computed::Color,
8042 foreground: &style::color::AbsoluteColor,
8043 ) -> style::color::AbsoluteColor {
8044 color.resolve_to_absolute(foreground)
8048 pub extern "C" fn Servo_ResolveCalcLengthPercentage(
8049 calc: &computed::length_percentage::CalcLengthPercentage,
8052 calc.resolve(computed::Length::new(basis)).px()
8056 pub extern "C" fn Servo_ConvertColorSpace(
8057 color: &AbsoluteColor,
8058 color_space: ColorSpace,
8059 ) -> AbsoluteColor {
8060 color.to_color_space(color_space)
8064 pub unsafe extern "C" fn Servo_IntersectionObserverRootMargin_Parse(
8066 result: *mut IntersectionObserverRootMargin,
8068 let value = value.as_str_unchecked();
8069 let result = result.as_mut().unwrap();
8071 let mut input = ParserInput::new(&value);
8072 let mut parser = Parser::new(&mut input);
8074 let url_data = dummy_url_data();
8075 let context = ParserContext::new(
8078 Some(CssRuleType::Style),
8079 ParsingMode::DEFAULT,
8080 QuirksMode::NoQuirks,
8081 /* namespaces = */ Default::default(),
8086 let margin = parser.parse_entirely(|p| IntersectionObserverRootMargin::parse(&context, p));
8097 pub extern "C" fn Servo_IntersectionObserverRootMargin_ToString(
8098 root_margin: &IntersectionObserverRootMargin,
8099 result: &mut nsACString,
8101 let mut writer = CssWriter::new(result);
8102 root_margin.to_css(&mut writer).unwrap();
8106 pub extern "C" fn Servo_ParseTransformIntoMatrix(
8108 contain_3d: &mut bool,
8109 result: &mut structs::Matrix4x4Components,
8111 use style::properties::longhands::transform;
8113 let string = unsafe { value.as_str_unchecked() };
8114 let mut input = ParserInput::new(&string);
8115 let mut parser = Parser::new(&mut input);
8116 let context = ParserContext::new(
8118 unsafe { dummy_url_data() },
8119 Some(CssRuleType::Style),
8120 ParsingMode::DEFAULT,
8121 QuirksMode::NoQuirks,
8122 /* namespaces = */ Default::default(),
8127 let transform = match parser.parse_entirely(|t| transform::parse(&context, t)) {
8129 Err(..) => return false,
8132 let (m, is_3d) = match transform.to_transform_3d_matrix(None) {
8133 Ok(result) => result,
8134 Err(..) => return false,
8137 *result = m.to_array();
8138 *contain_3d = is_3d;
8143 pub extern "C" fn Servo_ParseFilters(
8146 data: *mut URLExtraData,
8147 out: &mut style::OwnedSlice<Filter>,
8149 use style::values::specified::effects::SpecifiedFilter;
8151 let string = unsafe { value.as_str_unchecked() };
8152 let mut input = ParserInput::new(&string);
8153 let mut parser = Parser::new(&mut input);
8154 let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
8155 let context = ParserContext::new(
8159 ParsingMode::DEFAULT,
8160 QuirksMode::NoQuirks,
8161 /* namespaces = */ Default::default(),
8166 let mut filters = vec![];
8169 .try_parse(|i| i.expect_ident_matching("none"))
8172 return parser.expect_exhausted().is_ok();
8175 if parser.is_exhausted() {
8179 while !parser.is_exhausted() {
8180 let specified_filter = match SpecifiedFilter::parse(&context, &mut parser) {
8182 Err(..) => return false,
8185 let filter = match specified_filter.to_computed_value_without_context() {
8187 Err(..) => return false,
8190 if ignore_urls && matches!(filter, Filter::Url(_)) {
8194 filters.push(filter);
8197 *out = style::OwnedSlice::from(filters);
8202 pub unsafe extern "C" fn Servo_ParseFontShorthandForMatching(
8204 data: *mut URLExtraData,
8205 family: &mut FontFamilyList,
8206 style: &mut FontStyle,
8207 stretch: &mut FontStretch,
8208 weight: &mut FontWeight,
8209 size: Option<&mut f32>,
8210 small_caps: Option<&mut bool>,
8212 use style::properties::shorthands::font;
8213 use style::values::generics::font::FontStyle as GenericFontStyle;
8214 use style::values::specified::font as specified;
8216 let string = value.as_str_unchecked();
8217 let mut input = ParserInput::new(&string);
8218 let mut parser = Parser::new(&mut input);
8219 let url_data = UrlExtraData::from_ptr_ref(&data);
8220 let context = ParserContext::new(
8223 Some(CssRuleType::FontFace),
8224 ParsingMode::DEFAULT,
8225 QuirksMode::NoQuirks,
8226 /* namespaces = */ Default::default(),
8231 let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) {
8233 Err(..) => return false,
8236 // The system font is not acceptable, so we return false.
8237 match font.font_family {
8238 specified::FontFamily::Values(list) => *family = list,
8239 specified::FontFamily::System(_) => return false,
8242 let specified_font_style = match font.font_style {
8243 specified::FontStyle::Specified(ref s) => s,
8244 specified::FontStyle::System(_) => return false,
8247 *style = match *specified_font_style {
8248 GenericFontStyle::Normal => FontStyle::NORMAL,
8249 GenericFontStyle::Italic => FontStyle::ITALIC,
8250 GenericFontStyle::Oblique(ref angle) => FontStyle::oblique(angle.degrees()),
8253 *stretch = match font.font_stretch {
8254 specified::FontStretch::Keyword(ref k) => k.compute(),
8255 specified::FontStretch::Stretch(ref p) => FontStretch::from_percentage(p.0.get()),
8256 specified::FontStretch::System(_) => return false,
8259 *weight = match font.font_weight {
8260 specified::FontWeight::Absolute(w) => w.compute(),
8261 // Resolve relative font weights against the initial of font-weight
8262 // (normal, which is equivalent to 400).
8263 specified::FontWeight::Bolder => FontWeight::normal().bolder(),
8264 specified::FontWeight::Lighter => FontWeight::normal().lighter(),
8265 specified::FontWeight::System(_) => return false,
8268 // XXX This is unfinished; see values::specified::FontSize::ToComputedValue
8269 // for a more complete implementation (but we can't use it as-is).
8270 if let Some(size) = size {
8271 *size = match font.font_size {
8272 specified::FontSize::Length(lp) => {
8273 use style::values::generics::transform::ToAbsoluteLength;
8274 match lp.to_pixel_length(None) {
8276 Err(..) => return false,
8279 specified::FontSize::Keyword(info) => {
8280 let keyword = if info.kw != specified::FontSizeKeyword::Math {
8283 specified::FontSizeKeyword::Medium
8285 // Map absolute-size keywords to sizes.
8286 // TODO: Maybe get a meaningful quirks / base size from the caller?
8287 let quirks_mode = QuirksMode::NoQuirks;
8289 .to_length_without_context(
8291 computed::Length::new(specified::FONT_MEDIUM_PX),
8296 // smaller, larger not currently supported
8297 specified::FontSize::Smaller |
8298 specified::FontSize::Larger |
8299 specified::FontSize::System(_) => {
8305 if let Some(small_caps) = small_caps {
8306 use style::computed_values::font_variant_caps::T::SmallCaps;
8307 *small_caps = font.font_variant_caps == SmallCaps;
8314 pub unsafe extern "C" fn Servo_SourceSizeList_Parse(value: &nsACString) -> *mut SourceSizeList {
8315 let value = value.as_str_unchecked();
8316 let mut input = ParserInput::new(value);
8317 let mut parser = Parser::new(&mut input);
8319 let context = ParserContext::new(
8322 Some(CssRuleType::Style),
8323 ParsingMode::DEFAULT,
8324 QuirksMode::NoQuirks,
8325 /* namespaces = */ Default::default(),
8330 // NB: Intentionally not calling parse_entirely.
8331 let list = SourceSizeList::parse(&context, &mut parser);
8332 Box::into_raw(Box::new(list))
8336 pub unsafe extern "C" fn Servo_SourceSizeList_Evaluate(
8337 raw_data: &PerDocumentStyleData,
8338 list: Option<&SourceSizeList>,
8340 let doc_data = raw_data.borrow();
8341 let device = doc_data.stylist.device();
8342 let quirks_mode = doc_data.stylist.quirks_mode();
8344 let result = match list {
8345 Some(list) => list.evaluate(device, quirks_mode),
8346 None => SourceSizeList::empty().evaluate(device, quirks_mode),
8353 pub unsafe extern "C" fn Servo_SourceSizeList_Drop(list: *mut SourceSizeList) {
8354 let _ = Box::from_raw(list);
8358 pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges(
8359 root: &RawGeckoElement,
8360 document_style: &PerDocumentStyleData,
8361 non_document_styles: &nsTArray<&AuthorStyles>,
8362 states_changed: u64,
8364 use style::invalidation::element::document_state::DocumentStateInvalidationProcessor;
8365 use style::invalidation::element::invalidator::TreeStyleInvalidator;
8367 let document_data = document_style.borrow();
8369 let iter = document_data
8372 .map(|(data, _origin)| data)
8376 .map(|author_styles| &*author_styles.data),
8379 let mut selector_caches = SelectorCaches::default();
8380 let root = GeckoElement(root);
8381 let mut processor = DocumentStateInvalidationProcessor::new(
8383 DocumentState::from_bits_retain(states_changed),
8384 &mut selector_caches,
8385 root.as_node().owner_doc().quirks_mode(),
8389 TreeStyleInvalidator::new(root, /* stack_limit_checker = */ None, &mut processor)
8392 debug_assert!(!result.has_invalidated_siblings(), "How in the world?");
8393 if result.has_invalidated_descendants() {
8394 bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0);
8395 } else if result.has_invalidated_self() {
8396 bindings::Gecko_NoteDirtyElement(root.0);
8401 pub unsafe extern "C" fn Servo_PseudoClass_GetStates(name: &nsACString) -> u64 {
8402 let name = name.as_str_unchecked();
8403 match NonTSPseudoClass::parse_non_functional(name) {
8405 // Ignore :any-link since it contains both visited and unvisited state.
8406 Some(NonTSPseudoClass::AnyLink) => 0,
8407 Some(pseudo_class) => pseudo_class.state_flag().bits(),
8412 pub unsafe extern "C" fn Servo_UseCounters_Create() -> *mut UseCounters {
8413 Box::into_raw(Box::<UseCounters>::default())
8417 pub unsafe extern "C" fn Servo_UseCounters_Drop(c: *mut UseCounters) {
8418 let _ = Box::from_raw(c);
8422 pub unsafe extern "C" fn Servo_UseCounters_Merge(
8423 doc_counters: &UseCounters,
8424 sheet_counters: &UseCounters,
8426 doc_counters.merge(sheet_counters)
8430 pub unsafe extern "C" fn Servo_IsPropertyIdRecordedInUseCounter(
8431 use_counters: &UseCounters,
8432 id: nsCSSPropertyID,
8434 let id = NonCustomPropertyId::from_nscsspropertyid(id).unwrap();
8435 use_counters.non_custom_properties.recorded(id)
8439 pub unsafe extern "C" fn Servo_IsUnknownPropertyRecordedInUseCounter(
8440 use_counters: &UseCounters,
8441 p: CountedUnknownProperty,
8443 use_counters.counted_unknown_properties.recorded(p)
8447 pub unsafe extern "C" fn Servo_IsCssPropertyRecordedInUseCounter(
8448 use_counters: &UseCounters,
8449 property: &nsACString,
8450 known_prop: *mut bool,
8452 *known_prop = false;
8454 let prop_name = property.as_str_unchecked();
8455 if let Ok(p) = PropertyId::parse_unchecked_for_testing(prop_name) {
8456 if let Some(id) = p.non_custom_id() {
8458 return use_counters.non_custom_properties.recorded(id);
8462 if let Some(p) = CountedUnknownProperty::parse_for_testing(prop_name) {
8464 return use_counters.counted_unknown_properties.recorded(p);
8471 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Create(
8474 ) -> *mut SharedMemoryBuilder {
8475 Box::into_raw(Box::new(SharedMemoryBuilder::new(buffer, len)))
8479 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_AddStylesheet(
8480 builder: &mut SharedMemoryBuilder,
8481 contents: &StylesheetContents,
8482 error_message: &mut nsACString,
8483 ) -> *const LockedCssRules {
8484 // Assert some things we assume when we create a style sheet from shared
8486 debug_assert_eq!(contents.origin, Origin::UserAgent);
8487 debug_assert_eq!(contents.quirks_mode, QuirksMode::NoQuirks);
8488 debug_assert!(contents.source_map_url.read().is_none());
8489 debug_assert!(contents.source_url.read().is_none());
8491 match builder.write(&contents.rules) {
8492 Ok(rules_ptr) => &**rules_ptr,
8494 error_message.assign(&message);
8501 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_GetLength(
8502 builder: &SharedMemoryBuilder,
8508 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Drop(builder: *mut SharedMemoryBuilder) {
8509 let _ = Box::from_raw(builder);
8513 pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void {
8514 style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr()
8518 pub unsafe extern "C" fn Servo_LoadData_GetLazy(
8519 source: &url::LoadDataSource,
8520 ) -> *const url::LoadData {
8525 pub extern "C" fn Servo_LengthPercentage_ToCss(
8526 lp: &computed::LengthPercentage,
8527 result: &mut nsACString,
8529 lp.to_css(&mut CssWriter::new(result)).unwrap();
8533 pub extern "C" fn Servo_FontStyle_ToCss(s: &FontStyle, result: &mut nsACString) {
8534 s.to_css(&mut CssWriter::new(result)).unwrap()
8538 pub extern "C" fn Servo_FontWeight_ToCss(w: &FontWeight, result: &mut nsACString) {
8539 w.to_css(&mut CssWriter::new(result)).unwrap()
8543 pub extern "C" fn Servo_FontStretch_ToCss(s: &FontStretch, result: &mut nsACString) {
8544 s.to_css(&mut CssWriter::new(result)).unwrap()
8548 pub extern "C" fn Servo_FontStretch_SerializeKeyword(
8550 result: &mut nsACString,
8552 let kw = match s.as_keyword() {
8554 None => return false,
8556 kw.to_css(&mut CssWriter::new(result)).unwrap();
8561 pub unsafe extern "C" fn Servo_CursorKind_Parse(
8562 cursor: &nsACString,
8563 result: &mut computed::ui::CursorKind,
8565 match computed::ui::CursorKind::from_ident(cursor.as_str_unchecked()) {
8575 pub extern "C" fn Servo_FontFamily_Generic(generic: GenericFontFamily) -> &'static FontFamily {
8576 FontFamily::generic(generic)
8580 pub extern "C" fn Servo_FontFamily_ForSystemFont(name: &nsACString, out: &mut FontFamily) {
8581 *out = FontFamily::for_system_font(&name.to_utf8());
8585 pub extern "C" fn Servo_FontFamilyList_WithNames(
8586 names: &nsTArray<computed::font::SingleFontFamily>,
8587 out: &mut FontFamilyList,
8589 *out = FontFamilyList {
8590 list: style_traits::arc_slice::ArcSlice::from_iter(names.iter().cloned()),
8595 pub extern "C" fn Servo_FamilyName_Serialize(name: &FamilyName, result: &mut nsACString) {
8596 name.to_css(&mut CssWriter::new(result)).unwrap()
8600 pub extern "C" fn Servo_GenericFontFamily_Parse(input: &nsACString) -> GenericFontFamily {
8601 let context = ParserContext::new(
8603 unsafe { dummy_url_data() },
8604 Some(CssRuleType::Style),
8605 ParsingMode::DEFAULT,
8606 QuirksMode::NoQuirks,
8607 /* namespaces = */ Default::default(),
8611 let value = input.to_utf8();
8612 let mut input = ParserInput::new(&value);
8613 let mut input = Parser::new(&mut input);
8614 GenericFontFamily::parse(&context, &mut input).unwrap_or(GenericFontFamily::None)
8618 pub extern "C" fn Servo_ColorScheme_Parse(input: &nsACString, out: &mut u8) -> bool {
8619 use style::values::specified::ColorScheme;
8621 let context = ParserContext::new(
8623 unsafe { dummy_url_data() },
8624 Some(CssRuleType::Style),
8625 ParsingMode::DEFAULT,
8626 QuirksMode::NoQuirks,
8627 /* namespaces = */ Default::default(),
8631 let input = unsafe { input.as_str_unchecked() };
8632 let mut input = ParserInput::new(&input);
8633 let mut input = Parser::new(&mut input);
8634 let scheme = match input.parse_entirely(|i| ColorScheme::parse(&context, i)) {
8635 Ok(scheme) => scheme,
8636 Err(..) => return false,
8638 *out = scheme.raw_bits();
8643 pub extern "C" fn Servo_LayerBlockRule_GetName(rule: &LayerBlockRule, result: &mut nsACString) {
8644 if let Some(ref name) = rule.name {
8645 name.to_css(&mut CssWriter::new(result)).unwrap()
8650 pub extern "C" fn Servo_LayerStatementRule_GetNameCount(rule: &LayerStatementRule) -> usize {
8655 pub extern "C" fn Servo_LayerStatementRule_GetNameAt(
8656 rule: &LayerStatementRule,
8658 result: &mut nsACString,
8660 if let Some(ref name) = rule.names.get(index) {
8661 name.to_css(&mut CssWriter::new(result)).unwrap()
8666 pub unsafe extern "C" fn Servo_InvalidateForViewportUnits(
8667 document_style: &PerDocumentStyleData,
8668 root: &RawGeckoElement,
8671 let mut document_data = document_style.borrow_mut();
8672 let ref mut stylist = document_data.stylist;
8673 let device = stylist.device();
8675 if !device.used_viewport_size() {
8679 if dynamic_only && !device.used_dynamic_viewport_size() {
8683 // If the viewport changed, then initial values containing viewport units need to be recomputed.
8685 .get_custom_property_initial_values_flags()
8686 .intersects(ComputedValueFlags::USES_VIEWPORT_UNITS)
8688 stylist.rebuild_initial_values_for_custom_properties();
8691 if style::invalidation::viewport_units::invalidate(GeckoElement(root)) {
8692 // The invalidation machinery propagates the bits up, but we still need
8693 // to tell the Gecko restyle root machinery about it.
8694 bindings::Gecko_NoteDirtySubtreeForInvalidation(root);
8699 pub extern "C" fn Servo_InterpolateColor(
8700 interpolation: ColorInterpolationMethod,
8701 left: &AbsoluteColor,
8702 right: &AbsoluteColor,
8704 ) -> AbsoluteColor {
8705 style::color::mix::mix(
8711 ColorMixFlags::empty(),
8716 pub extern "C" fn Servo_EasingFunctionAt(
8717 easing_function: &ComputedTimingFunction,
8719 before_flag: BeforeFlag,
8721 easing_function.calculate_output(progress, before_flag, 1e-7)
8724 fn parse_no_context<'i, F, R>(string: &'i str, parse: F) -> Result<R, ()>
8726 F: FnOnce(&ParserContext, &mut Parser<'i, '_>) -> Result<R, ParseError<'i>>,
8728 let context = ParserContext::new(
8730 unsafe { dummy_url_data() },
8732 ParsingMode::DEFAULT,
8733 QuirksMode::NoQuirks,
8734 /* namespaces = */ Default::default(),
8738 let mut input = ParserInput::new(string);
8739 Parser::new(&mut input)
8740 .parse_entirely(|i| parse(&context, i))
8745 // Parse a length without style context (for canvas2d letterSpacing/wordSpacing attributes).
8746 // This accepts absolute lengths, and if a font-metrics-getter function is passed, also
8747 // font-relative ones, but not other units (such as percentages, viewport-relative, etc)
8748 // that would require a full style context to resolve.
8749 pub extern "C" fn Servo_ParseLengthWithoutStyleContext(
8752 get_font_metrics: Option<unsafe extern "C" fn(*mut c_void) -> GeckoFontMetrics>,
8753 getter_context: *mut c_void,
8755 let metrics_getter = if let Some(getter) = get_font_metrics {
8756 Some(move || -> GeckoFontMetrics { unsafe { getter(getter_context) } })
8760 let value = parse_no_context(unsafe { len.as_str_unchecked() }, specified::Length::parse)
8761 .and_then(|p| p.to_computed_pixel_length_with_font_metrics(metrics_getter));
8772 pub extern "C" fn Servo_SlowRgbToColorName(r: u8, g: u8, b: u8, result: &mut nsACString) -> bool {
8773 let mut candidates = SmallVec::<[&'static str; 5]>::new();
8774 for (name, color) in cssparser::color::all_named_colors() {
8775 if color == (r, g, b) {
8776 candidates.push(name);
8779 if candidates.is_empty() {
8782 // DevTools expect the first alphabetically.
8784 result.assign(candidates[0]);
8789 pub extern "C" fn Servo_ColorNameToRgb(name: &nsACString, out: &mut structs::nscolor) -> bool {
8790 match cssparser::color::parse_named_color(unsafe { name.as_str_unchecked() }) {
8792 *out = style::gecko::values::convert_absolute_color_to_nscolor(&AbsoluteColor::new(
8806 pub enum RegisterCustomPropertyResult {
8807 SuccessfullyRegistered,
8812 InvalidInitialValue,
8813 InitialValueNotComputationallyIndependent,
8816 /// https://drafts.css-houdini.org/css-properties-values-api-1/#the-registerproperty-function
8818 pub extern "C" fn Servo_RegisterCustomProperty(
8819 per_doc_data: &PerDocumentStyleData,
8820 extra_data: *mut URLExtraData,
8822 syntax: &nsACString,
8824 initial_value: Option<&nsACString>,
8825 ) -> RegisterCustomPropertyResult {
8826 use self::RegisterCustomPropertyResult::*;
8827 use style::custom_properties::SpecifiedValue;
8828 use style::properties_and_values::rule::{PropertyRegistrationError, PropertyRuleName};
8829 use style::properties_and_values::syntax::Descriptor;
8831 let mut per_doc_data = per_doc_data.borrow_mut();
8832 let url_data = unsafe { UrlExtraData::from_ptr_ref(&extra_data) };
8833 let name = unsafe { name.as_str_unchecked() };
8834 let syntax = unsafe { syntax.as_str_unchecked() };
8835 let initial_value = initial_value.map(|v| unsafe { v.as_str_unchecked() });
8837 // If name is not a custom property name string, throw a SyntaxError and exit this algorithm.
8838 let name = match style::custom_properties::parse_name(name) {
8839 Ok(n) => Atom::from(n),
8840 Err(()) => return InvalidName,
8843 // If property set already contains an entry with name as its property name (compared
8844 // codepoint-wise), throw an InvalidModificationError and exit this algorithm.
8847 .custom_property_script_registry()
8851 return AlreadyRegistered;
8853 // Attempt to consume a syntax definition from syntax. If it returns failure, throw a
8854 // SyntaxError. Otherwise, let syntax definition be the returned syntax definition.
8855 let Ok(syntax) = Descriptor::from_str(syntax, /* preserve_specified = */ false) else {
8856 return InvalidSyntax;
8859 let initial_value = match initial_value {
8861 let mut input = ParserInput::new(v);
8862 let parsed = Parser::new(&mut input)
8863 .parse_entirely(|input| {
8864 input.skip_whitespace();
8865 SpecifiedValue::parse(input, url_data).map(Arc::new)
8868 if parsed.is_none() {
8869 return InvalidInitialValue;
8877 PropertyRegistration::validate_initial_value(&syntax, initial_value.as_deref())
8879 return match error {
8880 PropertyRegistrationError::InitialValueNotComputationallyIndependent => {
8881 InitialValueNotComputationallyIndependent
8883 PropertyRegistrationError::InvalidInitialValue => InvalidInitialValue,
8884 PropertyRegistrationError::NoInitialValue => NoInitialValue,
8890 .custom_property_script_registry_mut()
8891 .register(PropertyRegistration {
8892 name: PropertyRuleName(name),
8893 data: PropertyRegistrationData {
8895 inherits: if inherits {
8896 PropertyInherits::True
8898 PropertyInherits::False
8902 url_data: url_data.clone(),
8903 source_location: SourceLocation { line: 0, column: 0 },
8908 .rebuild_initial_values_for_custom_properties();
8910 SuccessfullyRegistered
8914 pub struct PropDef {
8915 // The name of the property.
8917 // The syntax of the property.
8918 pub syntax: nsCString,
8919 // Whether the property inherits.
8921 pub has_initial_value: bool,
8922 pub initial_value: nsCString,
8923 // True if the property was set with CSS.registerProperty
8928 /// Creates a PropDef from a name and a PropertyRegistration.
8929 pub fn new(name: Atom, property_registration: &PropertyRegistration, from_js: bool) -> Self {
8930 let mut syntax = nsCString::new();
8931 if let Some(spec) = property_registration.data.syntax.specified_string() {
8932 syntax.assign(spec);
8934 // FIXME: Descriptor::to_css should behave consistently (probably this shouldn't use
8935 // the ToCss trait).
8936 property_registration
8939 .to_css(&mut CssWriter::new(&mut syntax))
8942 let initial_value = property_registration.data.initial_value.to_css_nscstring();
8946 inherits: property_registration.data.inherits(),
8947 has_initial_value: property_registration.data.initial_value.is_some(),
8955 pub extern "C" fn Servo_GetRegisteredCustomProperties(
8956 per_doc_data: &PerDocumentStyleData,
8957 custom_properties: &mut ThinVec<PropDef>,
8959 let stylist = &per_doc_data.borrow().stylist;
8961 custom_properties.extend(
8963 .custom_property_script_registry()
8966 .map(|(name, property_registration)| {
8967 PropDef::new(name.clone(), property_registration, /* from_js */ true)
8971 for (cascade_data, _origin) in stylist.iter_origins() {
8972 custom_properties.extend(cascade_data.custom_property_registrations().iter().map(
8974 let property_registration = &value.last().unwrap().0;
8977 property_registration,
8987 pub struct SelectorWarningData {
8988 /// Index to the selector generating the warning.
8990 /// Kind of the warning.
8991 pub kind: SelectorWarningKind,
8995 pub extern "C" fn Servo_GetSelectorWarnings(
8996 rule: &LockedStyleRule,
8997 warnings: &mut ThinVec<SelectorWarningData>,
8999 read_locked_arc(rule, |r| {
9000 for (i, selector) in r.selectors.slice().iter().enumerate() {
9001 for k in SelectorWarningKind::from_selector(selector) {
9002 warnings.push(SelectorWarningData { index: i, kind: k });
9009 pub extern "C" fn Servo_GetRuleBodyTextOffsets(
9010 initial_text: &nsACString,
9011 result_start_offset: &mut u32,
9012 result_end_offset: &mut u32,
9014 let css_text = unsafe { initial_text.as_str_unchecked() };
9015 let mut input = ParserInput::new(&css_text);
9016 let mut input = Parser::new(&mut input);
9018 let mut start_offset = 0;
9019 let mut found_start = false;
9021 // Search forward for the opening brace.
9022 while let Ok(token) = input.next() {
9024 Token::CurlyBracketBlock => {
9025 start_offset = input.position().byte_index();
9032 if token.is_parse_error() {
9042 let token_start = input.position();
9043 // Parse the nested block to move the parser to the end of the block
9044 let _ = input.parse_nested_block(
9045 |_i| -> Result<(), CssParseError<'_, BasicParseError>> {
9049 let mut end_offset = input.position().byte_index();
9050 // We're not guaranteed to have a closing bracket, but when we do, we need to move
9051 // the end offset before it.
9052 let token_slice = input.slice_from(token_start);
9053 if token_slice.ends_with("}") {
9054 end_offset = end_offset - 1;
9057 *result_start_offset = start_offset as u32;
9058 *result_end_offset = end_offset as u32;