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, ParserState, 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 MarginRule, MediaRule, NamespaceRule, Origin, OriginSet, PagePseudoClassFlags, PageRule,
141 PropertyRule, SanitizationData, SanitizationKind, StartingStyleRule, StyleRule,
142 StylesheetContents, StylesheetLoader as StyleStylesheetLoader, SupportsRule, UrlExtraData,
145 use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
146 use style::thread_state;
147 use style::traversal::resolve_style;
148 use style::traversal::DomTraversal;
149 use style::traversal_flags::{self, TraversalFlags};
150 use style::use_counters::UseCounters;
151 use style::values::animated::{Animate, Procedure, ToAnimatedZero};
152 use style::values::computed::easing::ComputedTimingFunction;
153 use style::values::computed::effects::Filter;
154 use style::values::computed::font::{
155 FamilyName, FontFamily, FontFamilyList, FontStretch, FontStyle, FontWeight, GenericFontFamily,
157 use style::values::computed::{self, Context, ToComputedValue};
158 use style::values::distance::ComputeSquaredDistance;
159 use style::values::generics::color::ColorMixFlags;
160 use style::values::generics::easing::BeforeFlag;
161 use style::values::specified::gecko::IntersectionObserverRootMargin;
162 use style::values::specified::source_size_list::SourceSizeList;
163 use style::values::specified::{AbsoluteLength, NoCalcLength};
164 use style::values::{specified, AtomIdent, CustomIdent, KeyframesName};
165 use style_traits::{CssWriter, ParseError, ParsingMode, ToCss};
166 use thin_vec::ThinVec;
167 use to_shmem::SharedMemoryBuilder;
169 trait ClosureHelper {
170 fn invoke(&self, property_id: Option<NonCustomPropertyId>);
173 impl ClosureHelper for DeclarationBlockMutationClosure {
175 fn invoke(&self, property_id: Option<NonCustomPropertyId>) {
176 if let Some(function) = self.function.as_ref() {
177 let gecko_prop_id = match property_id {
178 Some(p) => p.to_nscsspropertyid(),
179 None => nsCSSPropertyID::eCSSPropertyExtra_variable,
181 unsafe { function(self.data, gecko_prop_id) }
187 * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
188 * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
189 * those signatures as well, giving us a second declaration of all the Servo_* functions in this
190 * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
191 * depend on but good enough for our purposes.
194 // A dummy url data for where we don't pass url data in.
195 static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut _;
196 static mut DUMMY_CHROME_URL_DATA: *mut URLExtraData = 0 as *mut _;
199 pub unsafe extern "C" fn Servo_Initialize(
200 dummy_url_data: *mut URLExtraData,
201 dummy_chrome_url_data: *mut URLExtraData,
203 use style::gecko_bindings::sugar::origin_flags;
205 // Pretend that we're a Servo Layout thread, to make some assertions happy.
206 thread_state::initialize(thread_state::ThreadState::LAYOUT);
208 debug_assert!(is_main_thread());
209 lazy_static::initialize(&STYLE_THREAD_POOL);
211 // Perform some debug-only runtime assertions.
212 origin_flags::assert_flags_match();
213 traversal_flags::assert_traversal_flags_match();
214 specified::font::assert_variant_east_asian_matches();
215 specified::font::assert_variant_ligatures_matches();
217 DUMMY_URL_DATA = dummy_url_data;
218 DUMMY_CHROME_URL_DATA = dummy_chrome_url_data;
222 pub unsafe extern "C" fn Servo_Shutdown() {
223 DUMMY_URL_DATA = ptr::null_mut();
224 DUMMY_CHROME_URL_DATA = ptr::null_mut();
230 unsafe fn dummy_url_data() -> &'static UrlExtraData {
231 UrlExtraData::from_ptr_ref(std::ptr::addr_of!(DUMMY_URL_DATA).as_ref().unwrap())
235 unsafe fn dummy_chrome_url_data() -> &'static UrlExtraData {
236 UrlExtraData::from_ptr_ref(std::ptr::addr_of!(DUMMY_CHROME_URL_DATA).as_ref().unwrap())
240 fn is_main_thread() -> bool {
241 unsafe { bindings::Gecko_IsMainThread() }
245 fn is_dom_worker_thread() -> bool {
246 unsafe { bindings::Gecko_IsDOMWorkerThread() }
250 /// Thread-local style data for DOM workers
251 static DOM_WORKER_RWLOCK: SharedRwLock = SharedRwLock::new();
255 fn is_in_servo_traversal() -> bool {
256 unsafe { bindings::Gecko_IsInServoTraversal() }
259 fn create_shared_context<'a>(
260 global_style_data: &GlobalStyleData,
261 guard: &'a SharedRwLockReadGuard,
262 stylist: &'a Stylist,
263 traversal_flags: TraversalFlags,
264 snapshot_map: &'a ServoElementSnapshotTable,
265 ) -> SharedStyleContext<'a> {
268 visited_styles_enabled: stylist.device().visited_styles_enabled(),
269 options: global_style_data.options.clone(),
270 guards: StylesheetGuards::same(guard),
271 current_time_for_animations: 0.0, // Unused for Gecko, at least for now.
278 element: GeckoElement,
279 global_style_data: &GlobalStyleData,
280 per_doc_data: &PerDocumentStyleDataImpl,
281 guard: &SharedRwLockReadGuard,
282 traversal_flags: TraversalFlags,
283 snapshots: &ServoElementSnapshotTable,
285 let shared_style_context = create_shared_context(
288 &per_doc_data.stylist,
293 let token = RecalcStyleOnly::pre_traverse(element, &shared_style_context);
295 if !token.should_traverse() {
299 debug!("Traversing subtree from {:?}", element);
301 let thread_pool_holder = &*STYLE_THREAD_POOL;
303 let thread_pool = if traversal_flags.contains(TraversalFlags::ParallelTraversal) {
304 pool = thread_pool_holder.pool();
310 let traversal = RecalcStyleOnly::new(shared_style_context);
311 driver::traverse_dom(&traversal, token, thread_pool);
314 /// Traverses the subtree rooted at `root` for restyling.
316 /// Returns whether the root was restyled. Whether anything else was restyled or
317 /// not can be inferred from the dirty bits in the rest of the tree.
319 pub extern "C" fn Servo_TraverseSubtree(
320 root: &RawGeckoElement,
321 raw_data: &PerDocumentStyleData,
322 snapshots: *const ServoElementSnapshotTable,
323 raw_flags: ServoTraversalFlags,
325 let traversal_flags = TraversalFlags::from_bits_retain(raw_flags);
326 debug_assert!(!snapshots.is_null());
328 let element = GeckoElement(root);
330 debug!("Servo_TraverseSubtree (flags={:?})", traversal_flags);
331 debug!("{:?}", ShowSubtreeData(element.as_node()));
333 if cfg!(debug_assertions) {
334 if let Some(parent) = element.traversal_parent() {
337 .expect("Styling element with unstyled parent");
339 !data.styles.is_display_none(),
340 "Styling element with display: none parent"
345 let needs_animation_only_restyle =
346 element.has_animation_only_dirty_descendants() || element.has_animation_restyle_hints();
348 let per_doc_data = raw_data.borrow();
349 debug_assert!(!per_doc_data.stylist.stylesheets_have_changed());
351 let global_style_data = &*GLOBAL_STYLE_DATA;
352 let guard = global_style_data.shared_lock.read();
354 let was_initial_style = !element.has_data();
356 if needs_animation_only_restyle {
358 "Servo_TraverseSubtree doing animation-only restyle (aodd={})",
359 element.has_animation_only_dirty_descendants()
366 traversal_flags | TraversalFlags::AnimationOnly,
367 unsafe { &*snapshots },
377 unsafe { &*snapshots },
381 "Servo_TraverseSubtree complete (dd={}, aodd={}, lfcd={}, lfc={}, data={:?})",
382 element.has_dirty_descendants(),
383 element.has_animation_only_dirty_descendants(),
384 element.descendants_need_frames(),
385 element.needs_frame(),
386 element.borrow_data().unwrap()
389 if was_initial_style {
390 debug_assert!(!element.borrow_data().unwrap().contains_restyle_data());
393 let element_was_restyled = element.borrow_data().unwrap().contains_restyle_data();
398 /// Checks whether the rule tree has crossed its threshold for unused nodes, and
399 /// if so, frees them.
401 pub extern "C" fn Servo_MaybeGCRuleTree(raw_data: &PerDocumentStyleData) {
402 let per_doc_data = raw_data.borrow_mut();
403 per_doc_data.stylist.rule_tree().maybe_gc();
407 pub extern "C" fn Servo_AnimationValues_Interpolate(
408 from: &AnimationValue,
411 ) -> Strong<AnimationValue> {
412 if let Ok(value) = from.animate(to, Procedure::Interpolate { progress }) {
413 Arc::new(value).into()
420 pub extern "C" fn Servo_AnimationValues_IsInterpolable(
421 from: &AnimationValue,
424 from.interpolable_with(to)
428 pub extern "C" fn Servo_AnimationValues_Add(
431 ) -> Strong<AnimationValue> {
432 if let Ok(value) = a.animate(b, Procedure::Add) {
433 Arc::new(value).into()
440 pub extern "C" fn Servo_AnimationValues_Accumulate(
444 ) -> Strong<AnimationValue> {
445 if let Ok(value) = a.animate(b, Procedure::Accumulate { count }) {
446 Arc::new(value).into()
453 pub extern "C" fn Servo_AnimationValues_GetZeroValue(
454 value_to_match: &AnimationValue,
455 ) -> Strong<AnimationValue> {
456 if let Ok(zero_value) = value_to_match.to_animated_zero() {
457 Arc::new(zero_value).into()
464 pub extern "C" fn Servo_AnimationValues_ComputeDistance(
465 from: &AnimationValue,
468 // If compute_squared_distance() failed, this function will return negative value
469 // in order to check whether we support the specified paced animation values.
470 from.compute_squared_distance(to).map_or(-1.0, |d| d.sqrt())
473 /// Compute one of the endpoints for the interpolation interval, compositing it with the
474 /// underlying value if needed.
475 /// An None returned value means, "Just use endpoint_value as-is."
476 /// It is the responsibility of the caller to ensure that |underlying_value| is provided
477 /// when it will be used.
478 fn composite_endpoint(
479 endpoint_value: Option<&AnimationValue>,
480 composite: CompositeOperation,
481 underlying_value: Option<&AnimationValue>,
482 ) -> Option<AnimationValue> {
483 match endpoint_value {
484 Some(endpoint_value) => match composite {
485 CompositeOperation::Add => underlying_value
486 .expect("We should have an underlying_value")
487 .animate(endpoint_value, Procedure::Add)
489 CompositeOperation::Accumulate => underlying_value
490 .expect("We should have an underlying value")
491 .animate(endpoint_value, Procedure::Accumulate { count: 1 })
495 None => underlying_value.map(|v| v.clone()),
499 /// Accumulate one of the endpoints of the animation interval.
500 /// A returned value of None means, "Just use endpoint_value as-is."
501 fn accumulate_endpoint(
502 endpoint_value: Option<&AnimationValue>,
503 composited_value: Option<AnimationValue>,
504 last_value: &AnimationValue,
505 current_iteration: u64,
506 ) -> Option<AnimationValue> {
508 endpoint_value.is_some() || composited_value.is_some(),
509 "Should have a suitable value to use"
512 let count = current_iteration;
513 match composited_value {
514 Some(endpoint) => last_value
515 .animate(&endpoint, Procedure::Accumulate { count })
519 .animate(endpoint_value.unwrap(), Procedure::Accumulate { count })
524 /// Compose the animation segment. We composite it with the underlying_value and last_value if
526 /// The caller is responsible for providing an underlying value and last value
527 /// in all situations where there are needed.
528 fn compose_animation_segment(
529 segment: &structs::AnimationPropertySegment,
530 underlying_value: Option<&AnimationValue>,
531 last_value: Option<&AnimationValue>,
532 iteration_composite: IterationCompositeOperation,
533 current_iteration: u64,
535 segment_progress: f64,
536 ) -> AnimationValue {
537 // Extract keyframe values.
538 let keyframe_from_value = unsafe { segment.mFromValue.mServo.mRawPtr.as_ref() };
539 let keyframe_to_value = unsafe { segment.mToValue.mServo.mRawPtr.as_ref() };
540 let mut composited_from_value = composite_endpoint(
542 segment.mFromComposite,
545 let mut composited_to_value =
546 composite_endpoint(keyframe_to_value, segment.mToComposite, underlying_value);
549 keyframe_from_value.is_some() || composited_from_value.is_some(),
550 "Should have a suitable from value to use"
553 keyframe_to_value.is_some() || composited_to_value.is_some(),
554 "Should have a suitable to value to use"
557 // Apply iteration composite behavior.
558 if iteration_composite == IterationCompositeOperation::Accumulate && current_iteration > 0 {
559 let last_value = last_value
560 .unwrap_or_else(|| underlying_value.expect("Should have a valid underlying value"));
562 composited_from_value = accumulate_endpoint(
564 composited_from_value,
568 composited_to_value = accumulate_endpoint(
576 // Use the composited value if there is one, otherwise, use the original keyframe value.
577 let from = composited_from_value
579 .unwrap_or_else(|| keyframe_from_value.unwrap());
580 let to = composited_to_value
582 .unwrap_or_else(|| keyframe_to_value.unwrap());
584 if segment.mToKey == segment.mFromKey {
585 return if total_progress < 0. {
594 Procedure::Interpolate {
595 progress: segment_progress,
600 if segment_progress < 0.5 {
610 pub extern "C" fn Servo_ComposeAnimationSegment(
611 segment: &structs::AnimationPropertySegment,
612 underlying_value: Option<&AnimationValue>,
613 last_value: Option<&AnimationValue>,
614 iteration_composite: IterationCompositeOperation,
616 current_iteration: u64,
617 ) -> Strong<AnimationValue> {
618 let result = compose_animation_segment(
627 Arc::new(result).into()
631 pub extern "C" fn Servo_AnimationCompose(
632 value_map: &mut AnimationValueMap,
633 base_values: &structs::RawServoAnimationValueTable,
634 css_property: &structs::AnimatedPropertyID,
635 segment: &structs::AnimationPropertySegment,
636 last_segment: &structs::AnimationPropertySegment,
637 computed_timing: &structs::ComputedTiming,
638 iteration_composite: IterationCompositeOperation,
640 use style::gecko_bindings::bindings::Gecko_AnimationGetBaseStyle;
641 use style::gecko_bindings::bindings::Gecko_GetPositionInSegment;
642 use style::gecko_bindings::bindings::Gecko_GetProgressFromComputedTiming;
644 let property = match OwnedPropertyDeclarationId::from_gecko_animated_property_id(css_property) {
645 Some(property) if property.as_borrowed().is_animatable() => property,
649 // We will need an underlying value if either of the endpoints is null...
650 let need_underlying_value = segment.mFromValue.mServo.mRawPtr.is_null() ||
651 segment.mToValue.mServo.mRawPtr.is_null() ||
652 // ... or if they have a non-replace composite mode ...
653 segment.mFromComposite != CompositeOperation::Replace ||
654 segment.mToComposite != CompositeOperation::Replace ||
655 // ... or if we accumulate onto the last value and it is null.
656 (iteration_composite == IterationCompositeOperation::Accumulate &&
657 computed_timing.mCurrentIteration > 0 &&
658 last_segment.mToValue.mServo.mRawPtr.is_null());
660 // If either of the segment endpoints are null, get the underlying value to
661 // use from the current value in the values map (set by a lower-priority
662 // effect), or, if there is no current value, look up the cached base value
663 // for this property.
664 let underlying_value = if need_underlying_value {
665 let previous_composed_value = value_map.get(&property).map(|v| &*v);
666 previous_composed_value
667 .or_else(|| unsafe { Gecko_AnimationGetBaseStyle(base_values, css_property).as_ref() })
672 if need_underlying_value && underlying_value.is_none() {
673 warn!("Underlying value should be valid when we expect to use it");
677 let last_value = unsafe { last_segment.mToValue.mServo.mRawPtr.as_ref() };
678 let progress = unsafe { Gecko_GetProgressFromComputedTiming(computed_timing) };
679 let position = if segment.mToKey == segment.mFromKey {
680 // Note: compose_animation_segment doesn't use this value
681 // if segment.mFromKey == segment.mToKey, so assigning |progress| directly is fine.
684 unsafe { Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag) }
687 let result = compose_animation_segment(
692 computed_timing.mCurrentIteration,
696 value_map.insert(property, result);
699 macro_rules! get_property_id_from_nscsspropertyid {
700 ($property_id: ident, $ret: expr) => {{
701 match PropertyId::from_nscsspropertyid($property_id) {
702 Some(property_id) => property_id,
710 macro_rules! get_property_id_from_animatedpropertyid {
711 ($property_id: ident, $ret: expr) => {{
712 match PropertyId::from_gecko_animated_property_id($property_id) {
713 Some(property_id) => property_id,
722 pub extern "C" fn Servo_AnimationValue_Serialize(
723 value: &AnimationValue,
724 property: &structs::AnimatedPropertyID,
725 raw_data: &PerDocumentStyleData,
726 buffer: &mut nsACString,
728 let uncomputed_value = value.uncompute();
729 let data = raw_data.borrow();
730 let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
731 .single_value_to_css(
732 &get_property_id_from_animatedpropertyid!(property, ()),
737 debug_assert!(rv.is_ok());
740 /// Debug: MOZ_DBG for AnimationValue.
742 pub extern "C" fn Servo_AnimationValue_Dump(value: &AnimationValue, result: &mut nsACString) {
743 write!(result, "{:?}", value).unwrap();
747 pub extern "C" fn Servo_AnimationValue_GetColor(
748 value: &AnimationValue,
749 foreground_color: structs::nscolor,
750 ) -> structs::nscolor {
751 use style::gecko::values::{
752 convert_absolute_color_to_nscolor, convert_nscolor_to_absolute_color,
754 use style::values::computed::color::Color as ComputedColor;
756 AnimationValue::BackgroundColor(ref color) => {
757 let computed: ComputedColor = color.clone();
758 let foreground_color = convert_nscolor_to_absolute_color(foreground_color);
759 convert_absolute_color_to_nscolor(&computed.resolve_to_absolute(&foreground_color))
761 _ => panic!("Other color properties are not supported yet"),
766 pub extern "C" fn Servo_AnimationValue_IsCurrentColor(value: &AnimationValue) -> bool {
768 AnimationValue::BackgroundColor(ref color) => color.is_currentcolor(),
770 debug_assert!(false, "Other color properties are not supported yet");
777 pub extern "C" fn Servo_AnimationValue_GetOpacity(value: &AnimationValue) -> f32 {
778 if let AnimationValue::Opacity(opacity) = *value {
781 panic!("The AnimationValue should be Opacity");
786 pub extern "C" fn Servo_AnimationValue_Opacity(opacity: f32) -> Strong<AnimationValue> {
787 Arc::new(AnimationValue::Opacity(opacity)).into()
791 pub extern "C" fn Servo_AnimationValue_Color(
792 color_property: nsCSSPropertyID,
793 color: structs::nscolor,
794 ) -> Strong<AnimationValue> {
795 use style::gecko::values::convert_nscolor_to_absolute_color;
796 use style::values::animated::color::Color;
798 let property = LonghandId::from_nscsspropertyid(color_property)
799 .expect("We don't have shorthand property animation value");
801 let animated = convert_nscolor_to_absolute_color(color);
804 LonghandId::BackgroundColor => {
805 Arc::new(AnimationValue::BackgroundColor(Color::Absolute(animated))).into()
807 _ => panic!("Should be background-color property"),
812 pub unsafe extern "C" fn Servo_AnimationValue_GetScale(
813 value: &AnimationValue,
814 ) -> *const computed::Scale {
816 AnimationValue::Scale(ref value) => value,
817 _ => unreachable!("Expected scale"),
822 pub unsafe extern "C" fn Servo_AnimationValue_GetTranslate(
823 value: &AnimationValue,
824 ) -> *const computed::Translate {
826 AnimationValue::Translate(ref value) => value,
827 _ => unreachable!("Expected translate"),
832 pub unsafe extern "C" fn Servo_AnimationValue_GetRotate(
833 value: &AnimationValue,
834 ) -> *const computed::Rotate {
836 AnimationValue::Rotate(ref value) => value,
837 _ => unreachable!("Expected rotate"),
842 pub unsafe extern "C" fn Servo_AnimationValue_GetTransform(
843 value: &AnimationValue,
844 ) -> *const computed::Transform {
846 AnimationValue::Transform(ref value) => value,
847 _ => unreachable!("Unsupported transform animation value"),
852 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPath(
853 value: &AnimationValue,
854 output: &mut computed::motion::OffsetPath,
856 use style::values::animated::ToAnimatedValue;
858 AnimationValue::OffsetPath(ref value) => {
859 *output = ToAnimatedValue::from_animated_value(value.clone())
861 _ => unreachable!("Expected offset-path"),
866 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetDistance(
867 value: &AnimationValue,
868 ) -> *const computed::LengthPercentage {
870 AnimationValue::OffsetDistance(ref value) => value,
871 _ => unreachable!("Expected offset-distance"),
876 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetRotate(
877 value: &AnimationValue,
878 ) -> *const computed::motion::OffsetRotate {
880 AnimationValue::OffsetRotate(ref value) => value,
881 _ => unreachable!("Expected offset-rotate"),
886 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetAnchor(
887 value: &AnimationValue,
888 ) -> *const computed::position::PositionOrAuto {
890 AnimationValue::OffsetAnchor(ref value) => value,
891 _ => unreachable!("Expected offset-anchor"),
896 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPosition(
897 value: &AnimationValue,
898 ) -> *const computed::motion::OffsetPosition {
900 AnimationValue::OffsetPosition(ref value) => value,
901 _ => unreachable!("Expected offset-position"),
906 pub unsafe extern "C" fn Servo_AnimationValue_IsOffsetPathUrl(value: &AnimationValue) -> bool {
907 use style::values::generics::motion::{GenericOffsetPath, GenericOffsetPathFunction};
908 if let AnimationValue::OffsetPath(ref op) = value {
909 if let GenericOffsetPath::OffsetPath { path, coord_box: _ } = op {
910 return matches!(**path, GenericOffsetPathFunction::Url(_));
917 pub unsafe extern "C" fn Servo_AnimationValue_Rotate(
918 r: &computed::Rotate,
919 ) -> Strong<AnimationValue> {
920 Arc::new(AnimationValue::Rotate(r.clone())).into()
924 pub unsafe extern "C" fn Servo_AnimationValue_Translate(
925 t: &computed::Translate,
926 ) -> Strong<AnimationValue> {
927 Arc::new(AnimationValue::Translate(t.clone())).into()
931 pub unsafe extern "C" fn Servo_AnimationValue_Scale(s: &computed::Scale) -> Strong<AnimationValue> {
932 Arc::new(AnimationValue::Scale(s.clone())).into()
936 pub unsafe extern "C" fn Servo_AnimationValue_Transform(
937 transform: &computed::Transform,
938 ) -> Strong<AnimationValue> {
939 Arc::new(AnimationValue::Transform(transform.clone())).into()
943 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPath(
944 p: &computed::motion::OffsetPath,
945 ) -> Strong<AnimationValue> {
946 use style::values::animated::ToAnimatedValue;
947 Arc::new(AnimationValue::OffsetPath(p.clone().to_animated_value())).into()
951 pub unsafe extern "C" fn Servo_AnimationValue_OffsetDistance(
952 d: &computed::LengthPercentage,
953 ) -> Strong<AnimationValue> {
954 Arc::new(AnimationValue::OffsetDistance(d.clone())).into()
958 pub unsafe extern "C" fn Servo_AnimationValue_OffsetRotate(
959 r: &computed::motion::OffsetRotate,
960 ) -> Strong<AnimationValue> {
961 Arc::new(AnimationValue::OffsetRotate(*r)).into()
965 pub unsafe extern "C" fn Servo_AnimationValue_OffsetAnchor(
966 p: &computed::position::PositionOrAuto,
967 ) -> Strong<AnimationValue> {
968 Arc::new(AnimationValue::OffsetAnchor(p.clone())).into()
972 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPosition(
973 p: &computed::motion::OffsetPosition,
974 ) -> Strong<AnimationValue> {
975 Arc::new(AnimationValue::OffsetPosition(p.clone())).into()
979 pub extern "C" fn Servo_AnimationValue_DeepEqual(
980 this: &AnimationValue,
981 other: &AnimationValue,
987 pub extern "C" fn Servo_AnimationValue_Uncompute(
988 value: &AnimationValue,
989 ) -> Strong<LockedDeclarationBlock> {
990 let global_style_data = &*GLOBAL_STYLE_DATA;
994 .wrap(PropertyDeclarationBlock::with_one(
1003 fn create_byte_buf_from_vec(mut v: Vec<u8>) -> ByteBuf {
1005 mData: v.as_mut_ptr(),
1007 mCapacity: v.capacity(),
1009 std::mem::forget(v);
1014 fn view_byte_buf(b: &ByteBuf) -> &[u8] {
1015 if b.mData.is_null() {
1016 debug_assert_eq!(b.mCapacity, 0);
1019 unsafe { std::slice::from_raw_parts(b.mData, b.mLen) }
1022 macro_rules! impl_basic_serde_funcs {
1023 ($ser_name:ident, $de_name:ident, $computed_type:ty) => {
1025 pub extern "C" fn $ser_name(v: &$computed_type, output: &mut ByteBuf) -> bool {
1026 let buf = match serialize(v) {
1028 Err(..) => return false,
1031 *output = create_byte_buf_from_vec(buf);
1036 pub unsafe extern "C" fn $de_name(input: &ByteBuf, v: *mut $computed_type) -> bool {
1037 let buf = match deserialize(view_byte_buf(input)) {
1039 Err(..) => return false,
1042 std::ptr::write(v, buf);
1048 impl_basic_serde_funcs!(
1049 Servo_LengthPercentage_Serialize,
1050 Servo_LengthPercentage_Deserialize,
1051 computed::LengthPercentage
1054 impl_basic_serde_funcs!(
1055 Servo_StyleRotate_Serialize,
1056 Servo_StyleRotate_Deserialize,
1057 computed::transform::Rotate
1060 impl_basic_serde_funcs!(
1061 Servo_StyleScale_Serialize,
1062 Servo_StyleScale_Deserialize,
1063 computed::transform::Scale
1066 impl_basic_serde_funcs!(
1067 Servo_StyleTranslate_Serialize,
1068 Servo_StyleTranslate_Deserialize,
1069 computed::transform::Translate
1072 impl_basic_serde_funcs!(
1073 Servo_StyleTransform_Serialize,
1074 Servo_StyleTransform_Deserialize,
1075 computed::transform::Transform
1078 impl_basic_serde_funcs!(
1079 Servo_StyleOffsetPath_Serialize,
1080 Servo_StyleOffsetPath_Deserialize,
1081 computed::motion::OffsetPath
1084 impl_basic_serde_funcs!(
1085 Servo_StyleOffsetRotate_Serialize,
1086 Servo_StyleOffsetRotate_Deserialize,
1087 computed::motion::OffsetRotate
1090 impl_basic_serde_funcs!(
1091 Servo_StylePositionOrAuto_Serialize,
1092 Servo_StylePositionOrAuto_Deserialize,
1093 computed::position::PositionOrAuto
1096 impl_basic_serde_funcs!(
1097 Servo_StyleOffsetPosition_Serialize,
1098 Servo_StyleOffsetPosition_Deserialize,
1099 computed::motion::OffsetPosition
1102 impl_basic_serde_funcs!(
1103 Servo_StyleComputedTimingFunction_Serialize,
1104 Servo_StyleComputedTimingFunction_Deserialize,
1105 ComputedTimingFunction
1108 // Return the ComputedValues by a base ComputedValues and the rules.
1109 fn resolve_rules_for_element_with_context<'a>(
1110 element: GeckoElement<'a>,
1111 mut context: StyleContext<GeckoElement<'a>>,
1112 rules: StrongRuleNode,
1113 original_computed_values: &ComputedValues,
1114 ) -> Arc<ComputedValues> {
1115 use style::style_resolver::{PseudoElementResolution, StyleResolverForElement};
1117 // This currently ignores visited styles, which seems acceptable, as
1118 // existing browsers don't appear to animate visited styles.
1119 let inputs = CascadeInputs {
1121 visited_rules: None,
1122 flags: original_computed_values.flags.for_cascade_inputs(),
1125 // Actually `PseudoElementResolution` doesn't matter.
1126 let mut resolver = StyleResolverForElement::new(
1130 PseudoElementResolution::IfApplicable,
1133 .cascade_style_and_visited_with_default_parents(inputs)
1138 pub extern "C" fn Servo_AnimationValueMap_Create() -> *mut AnimationValueMap {
1139 Box::into_raw(Box::default())
1143 pub unsafe extern "C" fn Servo_AnimationValueMap_Drop(value_map: *mut AnimationValueMap) {
1144 let _ = Box::from_raw(value_map);
1148 pub extern "C" fn Servo_AnimationValueMap_GetValue(
1149 value_map: &AnimationValueMap,
1150 property_id: &structs::AnimatedPropertyID,
1151 ) -> Strong<AnimationValue> {
1152 let property = match OwnedPropertyDeclarationId::from_gecko_animated_property_id(property_id) {
1153 Some(property) => property,
1154 None => return Strong::null(),
1158 .map_or(Strong::null(), |value| Arc::new(value.clone()).into())
1162 pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(
1163 raw_style_set: &PerDocumentStyleData,
1164 element: &RawGeckoElement,
1165 computed_values: &ComputedValues,
1166 snapshots: *const ServoElementSnapshotTable,
1167 ) -> Strong<ComputedValues> {
1168 debug_assert!(!snapshots.is_null());
1169 let computed_values = unsafe { ArcBorrow::from_ref(computed_values) };
1171 let rules = match computed_values.rules {
1172 None => return computed_values.clone_arc().into(),
1173 Some(ref rules) => rules,
1176 let doc_data = raw_style_set.borrow();
1177 let without_animations_rules = doc_data.stylist.rule_tree().remove_animation_rules(rules);
1178 if without_animations_rules == *rules {
1179 return computed_values.clone_arc().into();
1182 let element = GeckoElement(element);
1184 let global_style_data = &*GLOBAL_STYLE_DATA;
1185 let guard = global_style_data.shared_lock.read();
1186 let shared = create_shared_context(
1190 TraversalFlags::empty(),
1191 unsafe { &*snapshots },
1193 let mut tlc = ThreadLocalStyleContext::new();
1194 let context = StyleContext {
1196 thread_local: &mut tlc,
1199 resolve_rules_for_element_with_context(
1202 without_animations_rules,
1210 pub struct ShouldTransitionResult {
1211 should_animate: bool,
1212 old_transition_value_matches: bool,
1216 fn is_transitionable(prop: PropertyDeclarationId, behavior: computed::TransitionBehavior) -> bool {
1217 if !prop.is_animatable() {
1220 // TODO(bug 1885995): Return `false` in is_discrete_animatable for interpolatable custom
1222 if matches!(prop, PropertyDeclarationId::Custom(..)) {
1227 computed::TransitionBehavior::Normal => !prop.is_discrete_animatable(),
1228 // If transition-behavior is allow-discrete, transitionable is the same as animatable.
1229 computed::TransitionBehavior::AllowDiscrete => true,
1234 pub extern "C" fn Servo_ComputedValues_ShouldTransition(
1235 old: &ComputedValues,
1236 new: &ComputedValues,
1237 prop: &structs::AnimatedPropertyID,
1238 behavior: computed::TransitionBehavior,
1239 old_transition_value: Option<&AnimationValue>,
1240 start: &mut structs::RefPtr<AnimationValue>,
1241 end: &mut structs::RefPtr<AnimationValue>,
1242 ) -> ShouldTransitionResult {
1243 let Some(prop) = OwnedPropertyDeclarationId::from_gecko_animated_property_id(prop) else {
1244 return Default::default();
1246 let prop = prop.as_borrowed();
1247 if !is_transitionable(prop, behavior) {
1248 return Default::default();
1251 let Some(new_value) = AnimationValue::from_computed_values(prop, new) else {
1252 return Default::default();
1255 if let Some(old_transition_value) = old_transition_value {
1256 if *old_transition_value == new_value {
1257 return ShouldTransitionResult {
1258 should_animate: false,
1259 old_transition_value_matches: true,
1264 let Some(old_value) = AnimationValue::from_computed_values(prop, old) else {
1265 return Default::default();
1267 if old_value == new_value
1268 || (matches!(behavior, computed::TransitionBehavior::Normal)
1269 && !old_value.interpolable_with(&new_value))
1271 return Default::default();
1274 start.set_arc(Arc::new(old_value));
1275 end.set_arc(Arc::new(new_value));
1277 ShouldTransitionResult {
1278 should_animate: true,
1279 old_transition_value_matches: false,
1284 pub extern "C" fn Servo_ComputedValues_TransitionValueMatches(
1285 style: &ComputedValues,
1286 prop: &structs::AnimatedPropertyID,
1287 transition_value: &AnimationValue,
1289 let Some(prop) = OwnedPropertyDeclarationId::from_gecko_animated_property_id(prop) else {
1292 // Note: the running transitions should be transitionable, so it is always allow-discrete.
1293 let prop = prop.as_borrowed();
1294 if !is_transitionable(prop, computed::TransitionBehavior::AllowDiscrete) {
1297 let Some(value) = AnimationValue::from_computed_values(prop, style) else {
1300 value == *transition_value
1304 pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue(
1305 computed_values: &ComputedValues,
1306 property_id: &structs::AnimatedPropertyID,
1307 ) -> Strong<AnimationValue> {
1308 let property = match OwnedPropertyDeclarationId::from_gecko_animated_property_id(property_id) {
1309 Some(property) => property,
1310 None => return Strong::null(),
1312 match AnimationValue::from_computed_values(property.as_borrowed(), &computed_values) {
1313 Some(v) => Arc::new(v).into(),
1314 None => Strong::null(),
1319 pub extern "C" fn Servo_ResolveLogicalProperty(
1320 property_id: nsCSSPropertyID,
1321 style: &ComputedValues,
1322 ) -> nsCSSPropertyID {
1323 let longhand = LonghandId::from_nscsspropertyid(property_id)
1324 .expect("We shouldn't need to care about shorthands");
1327 .to_physical(style.writing_mode)
1328 .to_nscsspropertyid()
1332 pub unsafe extern "C" fn Servo_Property_LookupEnabledForAllContent(
1334 ) -> nsCSSPropertyID {
1335 match PropertyId::parse_enabled_for_all_content(prop.as_str_unchecked()) {
1336 Ok(p) => p.to_nscsspropertyid_resolving_aliases(),
1337 Err(..) => nsCSSPropertyID::eCSSProperty_UNKNOWN,
1342 pub unsafe extern "C" fn Servo_Property_GetName(
1343 prop: nsCSSPropertyID,
1344 out_length: *mut u32,
1346 let (ptr, len) = match NonCustomPropertyId::from_nscsspropertyid(prop) {
1348 let name = p.name();
1349 (name.as_bytes().as_ptr(), name.len())
1351 None => (ptr::null(), 0),
1354 *out_length = len as u32;
1358 macro_rules! parse_enabled_property_name {
1359 ($prop_name:ident, $found:ident, $default:expr) => {{
1360 let prop_name = $prop_name.as_str_unchecked();
1361 match PropertyId::parse_enabled_for_all_content(prop_name) {
1375 pub unsafe extern "C" fn Servo_Property_IsShorthand(
1376 prop_name: &nsACString,
1379 let prop_id = parse_enabled_property_name!(prop_name, found, false);
1380 prop_id.is_shorthand()
1384 pub unsafe extern "C" fn Servo_Property_IsInherited(
1385 per_doc_data: &PerDocumentStyleData,
1386 prop_name: &nsACString,
1388 let prop_name = prop_name.as_str_unchecked();
1389 let prop_id = match PropertyId::parse_enabled_for_all_content(prop_name) {
1391 Err(_) => return false,
1393 let longhand_id = match prop_id {
1394 PropertyId::Custom(property_name) => {
1395 let stylist = &per_doc_data.borrow().stylist;
1397 .get_custom_property_registration(&property_name)
1400 PropertyId::NonCustom(id) => match id.longhand_or_shorthand() {
1402 Err(sh) => sh.longhands().next().unwrap(),
1405 longhand_id.inherited()
1409 pub unsafe extern "C" fn Servo_Property_SupportsType(
1410 prop_name: &nsACString,
1414 let prop_id = parse_enabled_property_name!(prop_name, found, false);
1415 prop_id.supports_type(ty)
1418 // TODO(emilio): We could use ThinVec instead of nsTArray.
1420 pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty(
1421 prop_name: &nsACString,
1423 result: &mut nsTArray<nsString>,
1425 let prop_id = parse_enabled_property_name!(prop_name, found, ());
1426 // Use B-tree set for unique and sorted result.
1427 let mut values = BTreeSet::<&'static str>::new();
1428 prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter()));
1430 let mut extras = vec![];
1431 if values.contains("transparent") {
1432 // This is a special value devtools use to avoid inserting the
1433 // long list of color keywords. We need to prepend it to values.
1434 extras.push("COLOR");
1437 let len = extras.len() + values.len();
1438 bindings::Gecko_ResizeTArrayForStrings(result, len as u32);
1440 for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) {
1441 dest.write_str(src).unwrap();
1446 pub extern "C" fn Servo_Property_IsAnimatable(prop: &structs::AnimatedPropertyID) -> bool {
1447 PropertyId::from_gecko_animated_property_id(prop).map_or(false, |p| p.is_animatable())
1451 pub extern "C" fn Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID) -> bool {
1452 match LonghandId::from_nscsspropertyid(property) {
1453 Some(longhand) => longhand.is_discrete_animatable(),
1454 None => return false,
1459 pub extern "C" fn Servo_Element_ClearData(element: &RawGeckoElement) {
1460 unsafe { GeckoElement(element).clear_data() };
1464 pub extern "C" fn Servo_Element_SizeOfExcludingThisAndCVs(
1465 malloc_size_of: GeckoMallocSizeOf,
1466 malloc_enclosing_size_of: GeckoMallocSizeOf,
1467 seen_ptrs: *mut SeenPtrs,
1468 element: &RawGeckoElement,
1470 let element = GeckoElement(element);
1471 let borrow = element.borrow_data();
1472 if let Some(data) = borrow {
1473 let have_seen_ptr = move |ptr| unsafe { Gecko_HaveSeenPtr(seen_ptrs, ptr) };
1474 let mut ops = MallocSizeOfOps::new(
1475 malloc_size_of.unwrap(),
1476 Some(malloc_enclosing_size_of.unwrap()),
1477 Some(Box::new(have_seen_ptr)),
1479 (*data).size_of_excluding_cvs(&mut ops)
1486 pub extern "C" fn Servo_Element_GetMaybeOutOfDateStyle(
1487 element: &RawGeckoElement,
1488 ) -> *const ComputedValues {
1489 let element = GeckoElement(element);
1490 let data = match element.borrow_data() {
1492 None => return ptr::null(),
1494 &**data.styles.primary() as *const _
1498 pub extern "C" fn Servo_Element_GetMaybeOutOfDatePseudoStyle(
1499 element: &RawGeckoElement,
1501 ) -> *const ComputedValues {
1502 let element = GeckoElement(element);
1503 let data = match element.borrow_data() {
1505 None => return ptr::null(),
1507 match data.styles.pseudos.as_array()[index].as_ref() {
1508 Some(style) => &**style as *const _,
1509 None => ptr::null(),
1514 pub extern "C" fn Servo_Element_IsDisplayNone(element: &RawGeckoElement) -> bool {
1515 let element = GeckoElement(element);
1518 .expect("Invoking Servo_Element_IsDisplayNone on unstyled element");
1520 // This function is hot, so we bypass the AtomicRefCell.
1522 // It would be nice to also assert that we're not in the servo traversal,
1523 // but this function is called at various intermediate checkpoints when
1524 // managing the traversal on the Gecko side.
1525 debug_assert!(is_main_thread());
1526 unsafe { &*data.as_ptr() }.styles.is_display_none()
1530 pub extern "C" fn Servo_Element_IsDisplayContents(element: &RawGeckoElement) -> bool {
1531 let element = GeckoElement(element);
1534 .expect("Invoking Servo_Element_IsDisplayContents on unstyled element");
1536 debug_assert!(is_main_thread());
1537 unsafe { &*data.as_ptr() }
1546 pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGeckoElement) -> bool {
1547 let element = GeckoElement(element);
1550 .expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element");
1552 .contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
1555 fn mode_to_origin(mode: SheetParsingMode) -> Origin {
1557 SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
1558 SheetParsingMode::eUserSheetFeatures => Origin::User,
1559 SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
1564 pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> Strong<StylesheetContents> {
1565 let global_style_data = &*GLOBAL_STYLE_DATA;
1566 let origin = mode_to_origin(mode);
1567 let shared_lock = &global_style_data.shared_lock;
1568 StylesheetContents::from_str(
1570 unsafe { dummy_url_data() }.clone(),
1573 /* loader = */ None,
1575 QuirksMode::NoQuirks,
1576 /* use_counters = */ None,
1577 AllowImportRules::Yes,
1578 /* sanitization_data = */ None,
1583 /// Note: The load_data corresponds to this sheet, and is passed as the parent
1584 /// load data for child sheet loads. It may be null for certain cases where we
1585 /// know we won't have child loads.
1587 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8Bytes(
1588 loader: *mut Loader,
1589 stylesheet: *mut DomStyleSheet,
1590 load_data: *mut SheetLoadData,
1592 mode: SheetParsingMode,
1593 extra_data: *mut URLExtraData,
1594 quirks_mode: nsCompatibility,
1595 reusable_sheets: *mut LoaderReusableStyleSheets,
1596 use_counters: Option<&UseCounters>,
1597 allow_import_rules: AllowImportRules,
1598 sanitization_kind: SanitizationKind,
1599 sanitized_output: Option<&mut nsAString>,
1600 ) -> Strong<StylesheetContents> {
1601 let global_style_data = &*GLOBAL_STYLE_DATA;
1602 let input = bytes.as_str_unchecked();
1604 let reporter = ErrorReporter::new(stylesheet, loader, extra_data);
1605 let url_data = UrlExtraData::from_ptr_ref(&extra_data);
1606 let loader = if loader.is_null() {
1610 sanitized_output.is_none(),
1611 "Shouldn't trigger @import loads for sanitization",
1613 Some(StylesheetLoader::new(
1621 // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
1622 let loader: Option<&dyn StyleStylesheetLoader> = match loader {
1624 Some(ref s) => Some(s),
1627 let mut sanitization_data = SanitizationData::new(sanitization_kind);
1629 let contents = StylesheetContents::from_str(
1632 mode_to_origin(mode),
1633 &global_style_data.shared_lock,
1635 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
1639 sanitization_data.as_mut(),
1642 if let Some(data) = sanitization_data {
1645 .assign_utf8(data.take().as_bytes());
1652 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
1653 load_data: *mut SheetLoadDataHolder,
1654 extra_data: *mut URLExtraData,
1656 mode: SheetParsingMode,
1657 quirks_mode: nsCompatibility,
1658 should_record_use_counters: bool,
1659 allow_import_rules: AllowImportRules,
1661 let load_data = RefPtr::new(load_data);
1662 let extra_data = UrlExtraData::new(extra_data);
1664 let mut sheet_bytes = nsCString::new();
1665 sheet_bytes.assign(bytes);
1667 let async_parser = AsyncStylesheetParser::new(
1671 mode_to_origin(mode),
1673 should_record_use_counters,
1677 if let Some(thread_pool) = STYLE_THREAD_POOL.pool().as_ref() {
1678 thread_pool.spawn(|| {
1679 gecko_profiler_label!(Layout, CSSParsing);
1680 async_parser.parse();
1683 async_parser.parse();
1688 pub unsafe extern "C" fn Servo_ShutdownThreadPool() {
1689 debug_assert!(is_main_thread() && !is_in_servo_traversal());
1690 StyleThreadPool::shutdown();
1694 pub unsafe extern "C" fn Servo_ThreadPool_GetThreadHandles(
1695 handles: &mut ThinVec<PlatformThreadHandle>,
1697 StyleThreadPool::get_thread_handles(handles);
1701 pub unsafe extern "C" fn Servo_StyleSheet_FromSharedData(
1702 extra_data: *mut URLExtraData,
1703 shared_rules: &LockedCssRules,
1704 ) -> Strong<StylesheetContents> {
1705 StylesheetContents::from_shared_data(
1706 Arc::from_raw_addrefed(shared_rules),
1708 UrlExtraData::new(extra_data),
1709 QuirksMode::NoQuirks,
1715 pub extern "C" fn Servo_StyleSet_AppendStyleSheet(
1716 raw_data: &PerDocumentStyleData,
1717 sheet: *const DomStyleSheet,
1719 let global_style_data = &*GLOBAL_STYLE_DATA;
1720 let mut data = raw_data.borrow_mut();
1721 let data = &mut *data;
1722 let guard = global_style_data.shared_lock.read();
1723 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1724 data.stylist.append_stylesheet(sheet, &guard);
1728 pub extern "C" fn Servo_AuthorStyles_Create() -> *mut AuthorStyles {
1729 Box::into_raw(Box::new(AuthorStyles::new()))
1733 pub unsafe extern "C" fn Servo_AuthorStyles_Drop(styles: *mut AuthorStyles) {
1734 let _ = Box::from_raw(styles);
1738 pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet(
1739 styles: &mut AuthorStyles,
1740 sheet: *const DomStyleSheet,
1742 let global_style_data = &*GLOBAL_STYLE_DATA;
1743 let guard = global_style_data.shared_lock.read();
1744 let sheet = GeckoStyleSheet::new(sheet);
1745 styles.stylesheets.append_stylesheet(None, sheet, &guard);
1749 pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore(
1750 styles: &mut AuthorStyles,
1751 sheet: *const DomStyleSheet,
1752 before_sheet: *const DomStyleSheet,
1754 let global_style_data = &*GLOBAL_STYLE_DATA;
1755 let guard = global_style_data.shared_lock.read();
1756 styles.stylesheets.insert_stylesheet_before(
1758 GeckoStyleSheet::new(sheet),
1759 GeckoStyleSheet::new(before_sheet),
1765 pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet(
1766 styles: &mut AuthorStyles,
1767 sheet: *const DomStyleSheet,
1769 let global_style_data = &*GLOBAL_STYLE_DATA;
1770 let guard = global_style_data.shared_lock.read();
1773 .remove_stylesheet(None, GeckoStyleSheet::new(sheet), &guard);
1777 pub extern "C" fn Servo_AuthorStyles_ForceDirty(styles: &mut AuthorStyles) {
1778 styles.stylesheets.force_dirty();
1782 pub extern "C" fn Servo_AuthorStyles_IsDirty(styles: &AuthorStyles) -> bool {
1783 styles.stylesheets.dirty()
1787 pub extern "C" fn Servo_AuthorStyles_Flush(
1788 styles: &mut AuthorStyles,
1789 document_set: &PerDocumentStyleData,
1791 // Try to avoid the atomic borrow below if possible.
1792 if !styles.stylesheets.dirty() {
1796 let global_style_data = &*GLOBAL_STYLE_DATA;
1797 let guard = global_style_data.shared_lock.read();
1799 let mut document_data = document_set.borrow_mut();
1801 // TODO(emilio): This is going to need an element or something to do proper
1802 // invalidation in Shadow roots.
1803 styles.flush::<GeckoElement>(&mut document_data.stylist, &guard);
1807 pub extern "C" fn Servo_StyleSet_RemoveUniqueEntriesFromAuthorStylesCache(
1808 document_set: &PerDocumentStyleData,
1810 let mut document_data = document_set.borrow_mut();
1813 .remove_unique_author_data_cache_entries();
1817 pub unsafe extern "C" fn Servo_DeclarationBlock_SizeOfIncludingThis(
1818 malloc_size_of: GeckoMallocSizeOf,
1819 malloc_enclosing_size_of: GeckoMallocSizeOf,
1820 declarations: &LockedDeclarationBlock,
1822 use malloc_size_of::MallocSizeOf;
1823 use malloc_size_of::MallocUnconditionalShallowSizeOf;
1825 let global_style_data = &*GLOBAL_STYLE_DATA;
1826 let guard = global_style_data.shared_lock.read();
1828 let mut ops = MallocSizeOfOps::new(
1829 malloc_size_of.unwrap(),
1830 Some(malloc_enclosing_size_of.unwrap()),
1834 ArcBorrow::from_ref(declarations).with_arc(|declarations| {
1836 n += declarations.unconditional_shallow_size_of(&mut ops);
1837 n += declarations.read_with(&guard).size_of(&mut ops);
1843 pub unsafe extern "C" fn Servo_AuthorStyles_SizeOfIncludingThis(
1844 malloc_size_of: GeckoMallocSizeOf,
1845 malloc_enclosing_size_of: GeckoMallocSizeOf,
1846 styles: &AuthorStyles,
1848 // We cannot `use` MallocSizeOf at the top level, otherwise the compiler
1849 // would complain in `Servo_StyleSheet_SizeOfIncludingThis` for `size_of`
1851 use malloc_size_of::MallocSizeOf;
1852 let malloc_size_of = malloc_size_of.unwrap();
1853 let malloc_size_of_this = malloc_size_of(styles as *const AuthorStyles as *const c_void);
1855 let mut ops = MallocSizeOfOps::new(
1857 Some(malloc_enclosing_size_of.unwrap()),
1860 malloc_size_of_this + styles.size_of(&mut ops)
1864 pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged(
1865 document_set: &PerDocumentStyleData,
1866 non_document_styles: &mut nsTArray<&mut AuthorStyles>,
1867 may_affect_default_style: bool,
1868 ) -> structs::MediumFeaturesChangedResult {
1869 let global_style_data = &*GLOBAL_STYLE_DATA;
1870 let guard = global_style_data.shared_lock.read();
1872 // NOTE(emilio): We don't actually need to flush the stylist here and ensure
1875 // In case it isn't we would trigger a rebuild + restyle as needed too.
1877 // We need to ensure the default computed values are up to date though,
1878 // because those can influence the result of media query evaluation.
1879 let mut document_data = document_set.borrow_mut();
1881 if may_affect_default_style {
1882 document_data.stylist.device_mut().reset_computed_values();
1884 let guards = StylesheetGuards::same(&guard);
1886 let origins_in_which_rules_changed = document_data
1888 .media_features_change_changed_style(&guards, document_data.stylist.device());
1890 let affects_document_rules = !origins_in_which_rules_changed.is_empty();
1891 if affects_document_rules {
1894 .force_stylesheet_origins_dirty(origins_in_which_rules_changed);
1897 let mut affects_non_document_rules = false;
1898 for author_styles in &mut **non_document_styles {
1899 let affected_style = author_styles.stylesheets.iter().any(|sheet| {
1900 !author_styles.data.media_feature_affected_matches(
1903 document_data.stylist.device(),
1904 document_data.stylist.quirks_mode(),
1908 affects_non_document_rules = true;
1909 author_styles.stylesheets.force_dirty();
1913 structs::MediumFeaturesChangedResult {
1914 mAffectsDocumentRules: affects_document_rules,
1915 mAffectsNonDocumentRules: affects_non_document_rules,
1920 pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(
1921 raw_data: &PerDocumentStyleData,
1922 sheet: *const DomStyleSheet,
1923 before_sheet: *const DomStyleSheet,
1925 let global_style_data = &*GLOBAL_STYLE_DATA;
1926 let mut data = raw_data.borrow_mut();
1927 let data = &mut *data;
1928 let guard = global_style_data.shared_lock.read();
1929 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1930 data.stylist.insert_stylesheet_before(
1932 unsafe { GeckoStyleSheet::new(before_sheet) },
1938 pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(
1939 raw_data: &PerDocumentStyleData,
1940 sheet: *const DomStyleSheet,
1942 let global_style_data = &*GLOBAL_STYLE_DATA;
1943 let mut data = raw_data.borrow_mut();
1944 let data = &mut *data;
1945 let guard = global_style_data.shared_lock.read();
1946 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1947 data.stylist.remove_stylesheet(sheet, &guard);
1951 pub unsafe extern "C" fn Servo_StyleSet_GetSheetAt(
1952 raw_data: &PerDocumentStyleData,
1955 ) -> *const DomStyleSheet {
1956 let data = raw_data.borrow();
1958 .sheet_at(origin, index)
1959 .map_or(ptr::null(), |s| s.raw())
1963 pub unsafe extern "C" fn Servo_StyleSet_GetSheetCount(
1964 raw_data: &PerDocumentStyleData,
1967 let data = raw_data.borrow();
1968 data.stylist.sheet_count(origin)
1972 pub unsafe extern "C" fn Servo_StyleSet_FlushStyleSheets(
1973 raw_data: &PerDocumentStyleData,
1974 doc_element: Option<&RawGeckoElement>,
1975 snapshots: *const ServoElementSnapshotTable,
1977 let global_style_data = &*GLOBAL_STYLE_DATA;
1978 let guard = global_style_data.shared_lock.read();
1979 let mut data = raw_data.borrow_mut();
1980 let doc_element = doc_element.map(GeckoElement);
1982 let have_invalidations = data.flush_stylesheets(&guard, doc_element, snapshots.as_ref());
1984 if have_invalidations && doc_element.is_some() {
1985 // The invalidation machinery propagates the bits up, but we still need
1986 // to tell the Gecko restyle root machinery about it.
1987 bindings::Gecko_NoteDirtySubtreeForInvalidation(doc_element.unwrap().0);
1992 pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(
1993 raw_data: &PerDocumentStyleData,
1994 changed_origins: OriginFlags,
1996 let mut data = raw_data.borrow_mut();
1998 .force_stylesheet_origins_dirty(OriginSet::from(changed_origins));
2002 pub extern "C" fn Servo_StyleSet_SetAuthorStyleDisabled(
2003 raw_data: &PerDocumentStyleData,
2004 author_style_disabled: bool,
2006 let mut data = raw_data.borrow_mut();
2007 let enabled = if author_style_disabled {
2008 AuthorStylesEnabled::No
2010 AuthorStylesEnabled::Yes
2012 data.stylist.set_author_styles_enabled(enabled);
2016 pub extern "C" fn Servo_StyleSet_UsesFontMetrics(raw_data: &PerDocumentStyleData) -> bool {
2017 let doc_data = raw_data;
2018 doc_data.borrow().stylist.device().used_font_metrics()
2022 pub extern "C" fn Servo_StyleSheet_HasRules(raw_contents: &StylesheetContents) -> bool {
2023 let global_style_data = &*GLOBAL_STYLE_DATA;
2024 let guard = global_style_data.shared_lock.read();
2025 !raw_contents.rules.read_with(&guard).0.is_empty()
2029 pub extern "C" fn Servo_StyleSheet_GetRules(sheet: &StylesheetContents) -> Strong<LockedCssRules> {
2030 sheet.rules.clone().into()
2034 pub extern "C" fn Servo_StyleSheet_Clone(
2035 contents: &StylesheetContents,
2036 reference_sheet: *const DomStyleSheet,
2037 ) -> Strong<StylesheetContents> {
2038 use style::shared_lock::{DeepCloneParams, DeepCloneWithLock};
2039 let global_style_data = &*GLOBAL_STYLE_DATA;
2040 let guard = global_style_data.shared_lock.read();
2041 let params = DeepCloneParams { reference_sheet };
2043 Arc::new(contents.deep_clone_with_lock(&global_style_data.shared_lock, &guard, ¶ms)).into()
2047 pub extern "C" fn Servo_StyleSheet_SizeOfIncludingThis(
2048 malloc_size_of: GeckoMallocSizeOf,
2049 malloc_enclosing_size_of: GeckoMallocSizeOf,
2050 sheet: &StylesheetContents,
2052 let global_style_data = &*GLOBAL_STYLE_DATA;
2053 let guard = global_style_data.shared_lock.read();
2054 let mut ops = MallocSizeOfOps::new(
2055 malloc_size_of.unwrap(),
2056 Some(malloc_enclosing_size_of.unwrap()),
2059 // TODO(emilio): We're not measuring the size of the Arc<StylesheetContents>
2060 // allocation itself here.
2061 sheet.size_of(&guard, &mut ops)
2065 pub extern "C" fn Servo_StyleSheet_GetOrigin(sheet: &StylesheetContents) -> Origin {
2070 pub extern "C" fn Servo_StyleSheet_GetSourceMapURL(
2071 contents: &StylesheetContents,
2072 result: &mut nsACString,
2074 let url_opt = contents.source_map_url.read();
2075 if let Some(ref url) = *url_opt {
2081 pub extern "C" fn Servo_StyleSheet_GetSourceURL(
2082 contents: &StylesheetContents,
2083 result: &mut nsACString,
2085 let url_opt = contents.source_url.read();
2086 if let Some(ref url) = *url_opt {
2091 fn with_maybe_worker_shared_lock<R>(func: impl FnOnce(&SharedRwLock) -> R) -> R {
2092 if is_dom_worker_thread() {
2093 DOM_WORKER_RWLOCK.with(func)
2095 func(&GLOBAL_STYLE_DATA.shared_lock)
2099 fn read_locked_arc<T, R, F>(raw: &Locked<T>, func: F) -> R
2103 debug_assert!(!is_dom_worker_thread());
2104 let global_style_data = &*GLOBAL_STYLE_DATA;
2105 let guard = global_style_data.shared_lock.read();
2106 func(raw.read_with(&guard))
2109 fn read_locked_arc_worker<T, R, F>(raw: &Locked<T>, func: F) -> R
2113 with_maybe_worker_shared_lock(|lock| {
2114 let guard = lock.read();
2115 func(raw.read_with(&guard))
2119 #[cfg(debug_assertions)]
2120 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &Locked<T>, func: F) -> R
2124 debug_assert!(is_main_thread() && !is_in_servo_traversal());
2125 read_locked_arc(raw, func)
2128 #[cfg(not(debug_assertions))]
2129 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &Locked<T>, func: F) -> R
2133 debug_assert!(!is_dom_worker_thread());
2134 func(raw.read_unchecked())
2137 fn write_locked_arc<T, R, F>(raw: &Locked<T>, func: F) -> R
2139 F: FnOnce(&mut T) -> R,
2141 debug_assert!(!is_dom_worker_thread());
2142 let global_style_data = &*GLOBAL_STYLE_DATA;
2143 let mut guard = global_style_data.shared_lock.write();
2144 func(raw.write_with(&mut guard))
2147 fn write_locked_arc_worker<T, R, F>(raw: &Locked<T>, func: F) -> R
2149 F: FnOnce(&mut T) -> R,
2151 with_maybe_worker_shared_lock(|lock| {
2152 let mut guard = lock.write();
2153 func(raw.write_with(&mut guard))
2158 pub extern "C" fn Servo_CssRules_ListTypes(rules: &LockedCssRules, result: &mut nsTArray<usize>) {
2159 read_locked_arc(rules, |rules: &CssRules| {
2160 result.assign_from_iter_pod(rules.0.iter().map(|rule| rule.rule_type() as usize));
2165 pub extern "C" fn Servo_CssRules_InsertRule(
2166 rules: &LockedCssRules,
2167 contents: &StylesheetContents,
2170 containing_rule_types: u32,
2171 parse_relative_rule_type: Option<&CssRuleType>,
2172 loader: *mut Loader,
2173 allow_import_rules: AllowImportRules,
2174 gecko_stylesheet: *mut DomStyleSheet,
2175 rule_type: &mut CssRuleType,
2177 let loader = if loader.is_null() {
2180 Some(StylesheetLoader::new(
2189 .map(|loader| loader as &dyn StyleStylesheetLoader);
2190 let rule = unsafe { rule.as_str_unchecked() };
2192 let global_style_data = &*GLOBAL_STYLE_DATA;
2193 let result = rules.insert_rule(
2194 &global_style_data.shared_lock,
2198 CssRuleTypes::from_bits(containing_rule_types),
2199 parse_relative_rule_type.cloned(),
2206 *rule_type = new_rule.rule_type();
2209 Err(err) => err.into(),
2214 pub extern "C" fn Servo_CssRules_DeleteRule(rules: &LockedCssRules, index: u32) -> nsresult {
2215 write_locked_arc(rules, |rules: &mut CssRules| {
2216 match rules.remove_rule(index as usize) {
2217 Ok(_) => nsresult::NS_OK,
2218 Err(err) => err.into(),
2223 trait MaybeLocked<Target> {
2224 fn maybe_locked_read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a Target;
2227 impl<T> MaybeLocked<T> for T {
2228 fn maybe_locked_read<'a>(&'a self, _: &'a SharedRwLockReadGuard) -> &'a T {
2233 impl<T> MaybeLocked<T> for Locked<T> {
2234 fn maybe_locked_read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
2235 self.read_with(guard)
2239 macro_rules! impl_basic_rule_funcs_without_getter {
2241 ($rule_type:ty, $maybe_locked_rule_type:ty),
2242 debug: $debug:ident,
2243 to_css: $to_css:ident,
2245 #[cfg(debug_assertions)]
2247 pub extern "C" fn $debug(rule: &$maybe_locked_rule_type, result: &mut nsACString) {
2248 let global_style_data = &*GLOBAL_STYLE_DATA;
2249 let guard = global_style_data.shared_lock.read();
2250 let rule: &$rule_type = rule.maybe_locked_read(&guard);
2251 write!(result, "{:?}", *rule).unwrap();
2254 #[cfg(not(debug_assertions))]
2256 pub extern "C" fn $debug(_: &$maybe_locked_rule_type, _: &mut nsACString) {
2261 pub extern "C" fn $to_css(rule: &$maybe_locked_rule_type, result: &mut nsACString) {
2262 let global_style_data = &*GLOBAL_STYLE_DATA;
2263 let guard = global_style_data.shared_lock.read();
2264 let rule: &$rule_type = rule.maybe_locked_read(&guard);
2265 rule.to_css(&guard, result).unwrap();
2270 macro_rules! impl_basic_rule_funcs {
2271 { ($name:ident, $rule_type:ty, $maybe_locked_rule_type:ty),
2272 getter: $getter:ident,
2273 debug: $debug:ident,
2274 to_css: $to_css:ident,
2275 changed: $changed:ident,
2278 pub extern "C" fn $getter(
2279 rules: &LockedCssRules,
2283 ) -> Strong<$maybe_locked_rule_type> {
2284 let global_style_data = &*GLOBAL_STYLE_DATA;
2285 let guard = global_style_data.shared_lock.read();
2286 let rules = rules.read_with(&guard);
2287 let index = index as usize;
2289 if index >= rules.0.len() {
2290 return Strong::null();
2293 match rules.0[index] {
2294 CssRule::$name(ref arc) => {
2295 let rule: &$rule_type = (&**arc).maybe_locked_read(&guard);
2296 let location = rule.source_location;
2297 *line = location.line as u32;
2298 *column = location.column as u32;
2308 pub extern "C" fn $changed(
2309 styleset: &PerDocumentStyleData,
2310 rule: &$maybe_locked_rule_type,
2311 sheet: &DomStyleSheet,
2312 change_kind: RuleChangeKind,
2314 let mut data = styleset.borrow_mut();
2315 let data = &mut *data;
2316 let global_style_data = &*GLOBAL_STYLE_DATA;
2317 let guard = global_style_data.shared_lock.read();
2318 // TODO(emilio): Would be nice not to deal with refcount bumps here,
2319 // but it's probably not a huge deal.
2320 let rule = unsafe { CssRule::$name(Arc::from_raw_addrefed(rule)) };
2321 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
2322 data.stylist.rule_changed(&sheet, &rule, &guard, change_kind);
2325 impl_basic_rule_funcs_without_getter! {
2326 ($rule_type, $maybe_locked_rule_type),
2333 macro_rules! impl_group_rule_funcs {
2334 { ($name:ident, $rule_type:ty, $maybe_locked_rule_type:ty),
2335 get_rules: $get_rules:ident,
2338 impl_basic_rule_funcs! { ($name, $rule_type, $maybe_locked_rule_type), $($basic)+ }
2341 pub extern "C" fn $get_rules(rule: &$maybe_locked_rule_type) -> Strong<LockedCssRules> {
2342 let global_style_data = &*GLOBAL_STYLE_DATA;
2343 let guard = global_style_data.shared_lock.read();
2344 let rule: &$rule_type = rule.maybe_locked_read(&guard);
2345 rule.rules.clone().into()
2350 impl_basic_rule_funcs! { (Style, StyleRule, Locked<StyleRule>),
2351 getter: Servo_CssRules_GetStyleRuleAt,
2352 debug: Servo_StyleRule_Debug,
2353 to_css: Servo_StyleRule_GetCssText,
2354 changed: Servo_StyleSet_StyleRuleChanged,
2358 pub extern "C" fn Servo_StyleRule_EnsureRules(
2359 rule: &LockedStyleRule,
2361 ) -> Strong<LockedCssRules> {
2362 let global_style_data = &*GLOBAL_STYLE_DATA;
2363 let lock = &global_style_data.shared_lock;
2365 let guard = lock.read();
2366 if let Some(ref rules) = rule.read_with(&guard).rules {
2367 return rules.clone().into();
2369 return CssRules::new(vec![], lock).into();
2371 let mut guard = lock.write();
2372 rule.write_with(&mut guard)
2374 .get_or_insert_with(|| CssRules::new(vec![], lock))
2379 impl_basic_rule_funcs! { (Import, ImportRule, Locked<ImportRule>),
2380 getter: Servo_CssRules_GetImportRuleAt,
2381 debug: Servo_ImportRule_Debug,
2382 to_css: Servo_ImportRule_GetCssText,
2383 changed: Servo_StyleSet_ImportRuleChanged,
2386 impl_basic_rule_funcs_without_getter! { (Keyframe, Locked<Keyframe>),
2387 debug: Servo_Keyframe_Debug,
2388 to_css: Servo_Keyframe_GetCssText,
2391 impl_basic_rule_funcs! { (Keyframes, KeyframesRule, Locked<KeyframesRule>),
2392 getter: Servo_CssRules_GetKeyframesRuleAt,
2393 debug: Servo_KeyframesRule_Debug,
2394 to_css: Servo_KeyframesRule_GetCssText,
2395 changed: Servo_StyleSet_KeyframesRuleChanged,
2398 impl_group_rule_funcs! { (Media, MediaRule, MediaRule),
2399 get_rules: Servo_MediaRule_GetRules,
2400 getter: Servo_CssRules_GetMediaRuleAt,
2401 debug: Servo_MediaRule_Debug,
2402 to_css: Servo_MediaRule_GetCssText,
2403 changed: Servo_StyleSet_MediaRuleChanged,
2406 impl_basic_rule_funcs! { (Margin, MarginRule, MarginRule),
2407 getter: Servo_CssRules_GetMarginRuleAt,
2408 debug: Servo_MarginRule_Debug,
2409 to_css: Servo_MarginRule_GetCssText,
2410 changed: Servo_StyleSet_MarginRuleChanged,
2413 impl_basic_rule_funcs! { (Namespace, NamespaceRule, NamespaceRule),
2414 getter: Servo_CssRules_GetNamespaceRuleAt,
2415 debug: Servo_NamespaceRule_Debug,
2416 to_css: Servo_NamespaceRule_GetCssText,
2417 changed: Servo_StyleSet_NamespaceRuleChanged,
2420 impl_group_rule_funcs! { (Page, PageRule, Locked<PageRule>),
2421 get_rules: Servo_PageRule_GetRules,
2422 getter: Servo_CssRules_GetPageRuleAt,
2423 debug: Servo_PageRule_Debug,
2424 to_css: Servo_PageRule_GetCssText,
2425 changed: Servo_StyleSet_PageRuleChanged,
2428 impl_basic_rule_funcs! { (Property, PropertyRule, PropertyRule),
2429 getter: Servo_CssRules_GetPropertyRuleAt,
2430 debug: Servo_PropertyRule_Debug,
2431 to_css: Servo_PropertyRule_GetCssText,
2432 changed: Servo_StyleSet_PropertyRuleChanged,
2435 impl_group_rule_funcs! { (Supports, SupportsRule, SupportsRule),
2436 get_rules: Servo_SupportsRule_GetRules,
2437 getter: Servo_CssRules_GetSupportsRuleAt,
2438 debug: Servo_SupportsRule_Debug,
2439 to_css: Servo_SupportsRule_GetCssText,
2440 changed: Servo_StyleSet_SupportsRuleChanged,
2443 impl_group_rule_funcs! { (Container, ContainerRule, ContainerRule),
2444 get_rules: Servo_ContainerRule_GetRules,
2445 getter: Servo_CssRules_GetContainerRuleAt,
2446 debug: Servo_ContainerRule_Debug,
2447 to_css: Servo_ContainerRule_GetCssText,
2448 changed: Servo_StyleSet_ContainerRuleChanged,
2451 impl_group_rule_funcs! { (LayerBlock, LayerBlockRule, LayerBlockRule),
2452 get_rules: Servo_LayerBlockRule_GetRules,
2453 getter: Servo_CssRules_GetLayerBlockRuleAt,
2454 debug: Servo_LayerBlockRule_Debug,
2455 to_css: Servo_LayerBlockRule_GetCssText,
2456 changed: Servo_StyleSet_LayerBlockRuleChanged,
2459 impl_basic_rule_funcs! { (LayerStatement, LayerStatementRule, LayerStatementRule),
2460 getter: Servo_CssRules_GetLayerStatementRuleAt,
2461 debug: Servo_LayerStatementRule_Debug,
2462 to_css: Servo_LayerStatementRule_GetCssText,
2463 changed: Servo_StyleSet_LayerStatementRuleChanged,
2466 impl_group_rule_funcs! { (Document, DocumentRule, DocumentRule),
2467 get_rules: Servo_DocumentRule_GetRules,
2468 getter: Servo_CssRules_GetDocumentRuleAt,
2469 debug: Servo_DocumentRule_Debug,
2470 to_css: Servo_DocumentRule_GetCssText,
2471 changed: Servo_StyleSet_DocumentRuleChanged,
2474 impl_basic_rule_funcs! { (FontFeatureValues, FontFeatureValuesRule, FontFeatureValuesRule),
2475 getter: Servo_CssRules_GetFontFeatureValuesRuleAt,
2476 debug: Servo_FontFeatureValuesRule_Debug,
2477 to_css: Servo_FontFeatureValuesRule_GetCssText,
2478 changed: Servo_StyleSet_FontFeatureValuesRuleChanged,
2481 impl_basic_rule_funcs! { (FontPaletteValues, FontPaletteValuesRule, FontPaletteValuesRule),
2482 getter: Servo_CssRules_GetFontPaletteValuesRuleAt,
2483 debug: Servo_FontPaletteValuesRule_Debug,
2484 to_css: Servo_FontPaletteValuesRule_GetCssText,
2485 changed: Servo_StyleSet_FontPaletteValuesRuleChanged,
2488 impl_basic_rule_funcs! { (FontFace, FontFaceRule, Locked<FontFaceRule>),
2489 getter: Servo_CssRules_GetFontFaceRuleAt,
2490 debug: Servo_FontFaceRule_Debug,
2491 to_css: Servo_FontFaceRule_GetCssText,
2492 changed: Servo_StyleSet_FontFaceRuleChanged,
2495 impl_basic_rule_funcs! { (CounterStyle, CounterStyleRule, Locked<CounterStyleRule>),
2496 getter: Servo_CssRules_GetCounterStyleRuleAt,
2497 debug: Servo_CounterStyleRule_Debug,
2498 to_css: Servo_CounterStyleRule_GetCssText,
2499 changed: Servo_StyleSet_CounterStyleRuleChanged,
2502 impl_group_rule_funcs! { (Scope, ScopeRule, ScopeRule),
2503 get_rules: Servo_ScopeRule_GetRules,
2504 getter: Servo_CssRules_GetScopeRuleAt,
2505 debug: Servo_ScopeRule_Debug,
2506 to_css: Servo_ScopeRule_GetCssText,
2507 changed: Servo_StyleSet_ScopeRuleChanged,
2510 impl_group_rule_funcs! { (StartingStyle, StartingStyleRule, StartingStyleRule),
2511 get_rules: Servo_StartingStyleRule_GetRules,
2512 getter: Servo_CssRules_GetStartingStyleRuleAt,
2513 debug: Servo_StartingStyleRule_Debug,
2514 to_css: Servo_StartingStyleRule_GetCssText,
2515 changed: Servo_StyleSet_StartingStyleRuleChanged,
2519 pub extern "C" fn Servo_StyleRule_GetStyle(
2520 rule: &LockedStyleRule,
2521 ) -> Strong<LockedDeclarationBlock> {
2522 read_locked_arc(rule, |rule: &StyleRule| rule.block.clone().into())
2526 pub extern "C" fn Servo_StyleRule_SetStyle(
2527 rule: &LockedStyleRule,
2528 declarations: &LockedDeclarationBlock,
2530 write_locked_arc(rule, |rule: &mut StyleRule| {
2531 rule.block = unsafe { Arc::from_raw_addrefed(declarations) };
2536 pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: &LockedStyleRule, result: &mut nsACString) {
2537 read_locked_arc(rule, |rule| rule.selectors.to_css(result).unwrap());
2540 fn desugared_selector_list(rules: &ThinVec<&LockedStyleRule>) -> SelectorList {
2541 let mut selectors: Option<SelectorList> = None;
2542 for rule in rules.iter().rev() {
2543 selectors = Some(read_locked_arc(rule, |rule| match selectors {
2544 Some(ref s) => rule.selectors.replace_parent_selector(s),
2545 None => rule.selectors.clone(),
2548 selectors.expect("Empty rule chain?")
2552 pub extern "C" fn Servo_StyleRule_GetSelectorDataAtIndex(
2553 rules: &ThinVec<&LockedStyleRule>,
2555 text: Option<&mut nsACString>,
2556 specificity: Option<&mut u64>,
2558 let selectors = desugared_selector_list(rules);
2559 let Some(selector) = selectors.slice().get(index as usize) else {
2562 if let Some(text) = text {
2563 selector.to_css(text).unwrap();
2565 if let Some(specificity) = specificity {
2566 *specificity = selector.specificity() as u64;
2571 pub extern "C" fn Servo_StyleRule_GetSelectorCount(rule: &LockedStyleRule) -> u32 {
2572 read_locked_arc(rule, |rule| rule.selectors.len() as u32)
2576 pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(
2577 rules: &ThinVec<&LockedStyleRule>,
2578 element: &RawGeckoElement,
2580 host: Option<&RawGeckoElement>,
2581 pseudo_type: PseudoStyleType,
2582 relevant_link_visited: bool,
2584 use selectors::matching::{
2585 matches_selector, MatchingContext, MatchingMode, NeedsSelectorFlags, VisitedHandlingMode,
2587 let selectors = desugared_selector_list(rules);
2588 let Some(selector) = selectors.slice().get(index as usize) else {
2591 let mut matching_mode = MatchingMode::Normal;
2592 match PseudoElement::from_pseudo_type(pseudo_type, None) {
2594 // We need to make sure that the requested pseudo element type
2595 // matches the selector pseudo element type before proceeding.
2596 match selector.pseudo_element() {
2597 Some(selector_pseudo) if *selector_pseudo == pseudo => {
2598 matching_mode = MatchingMode::ForStatelessPseudoElement
2604 // Do not attempt to match if a pseudo element is requested and
2605 // this is not a pseudo element selector, or vice versa.
2606 if selector.has_pseudo_element() {
2612 let element = GeckoElement(element);
2613 let host = host.map(GeckoElement);
2614 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2615 let mut selector_caches = SelectorCaches::default();
2616 let visited_mode = if relevant_link_visited {
2617 VisitedHandlingMode::RelevantLinkVisited
2619 VisitedHandlingMode::AllLinksUnvisited
2621 let mut ctx = MatchingContext::new_for_visited(
2623 /* bloom_filter = */ None,
2624 &mut selector_caches,
2627 NeedsSelectorFlags::No,
2628 MatchingForInvalidation::No,
2630 ctx.with_shadow_host(host, |ctx| {
2631 matches_selector(selector, 0, None, &element, ctx)
2635 pub type SelectorList = selectors::SelectorList<style::gecko::selector_parser::SelectorImpl>;
2638 pub extern "C" fn Servo_StyleRule_SetSelectorText(
2639 contents: &StylesheetContents,
2640 rule: &LockedStyleRule,
2643 let value_str = unsafe { text.as_str_unchecked() };
2645 write_locked_arc(rule, |rule: &mut StyleRule| {
2646 use selectors::parser::ParseRelative;
2647 use style::selector_parser::SelectorParser;
2649 let namespaces = contents.namespaces.read();
2650 let url_data = contents.url_data.read();
2651 let parser = SelectorParser {
2652 stylesheet_origin: contents.origin,
2653 namespaces: &namespaces,
2654 url_data: &url_data,
2655 for_supports_rule: false,
2658 // TODO: Maybe allow setting relative selectors from the OM, if we're in a nested style
2660 let mut parser_input = ParserInput::new(&value_str);
2661 match SelectorList::parse(
2663 &mut Parser::new(&mut parser_input),
2667 rule.selectors = selectors;
2676 pub unsafe extern "C" fn Servo_SelectorList_Closest(
2677 element: &RawGeckoElement,
2678 selectors: &SelectorList,
2679 ) -> *const RawGeckoElement {
2680 use style::dom_apis;
2682 let element = GeckoElement(element);
2683 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2684 dom_apis::element_closest(element, &selectors, quirks_mode).map_or(ptr::null(), |e| e.0)
2688 pub unsafe extern "C" fn Servo_SelectorList_Matches(
2689 element: &RawGeckoElement,
2690 selectors: &SelectorList,
2692 use style::dom_apis;
2694 let element = GeckoElement(element);
2695 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2696 dom_apis::element_matches(&element, &selectors, quirks_mode)
2700 pub unsafe extern "C" fn Servo_SelectorList_QueryFirst(
2701 node: &RawGeckoNode,
2702 selectors: &SelectorList,
2703 may_use_invalidation: bool,
2704 ) -> *const RawGeckoElement {
2705 use style::dom_apis::{self, MayUseInvalidation, QueryFirst};
2707 let node = GeckoNode(node);
2708 let mut result = None;
2710 let may_use_invalidation = if may_use_invalidation {
2711 MayUseInvalidation::Yes
2713 MayUseInvalidation::No
2716 dom_apis::query_selector::<GeckoElement, QueryFirst>(
2720 may_use_invalidation,
2723 result.map_or(ptr::null(), |e| e.0)
2727 pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
2728 node: &RawGeckoNode,
2729 selectors: &SelectorList,
2730 content_list: *mut structs::nsSimpleContentList,
2731 may_use_invalidation: bool,
2733 use style::dom_apis::{self, MayUseInvalidation, QueryAll};
2735 let node = GeckoNode(node);
2736 let mut result = SmallVec::new();
2738 let may_use_invalidation = if may_use_invalidation {
2739 MayUseInvalidation::Yes
2741 MayUseInvalidation::No
2744 dom_apis::query_selector::<GeckoElement, QueryAll>(
2748 may_use_invalidation,
2751 if !result.is_empty() {
2752 // NOTE(emilio): This relies on a slice of GeckoElement having the same
2753 // memory representation than a slice of element pointers.
2754 bindings::Gecko_ContentList_AppendAll(
2756 result.as_ptr() as *mut *const _,
2763 pub extern "C" fn Servo_ImportRule_GetHref(rule: &LockedImportRule, result: &mut nsAString) {
2764 read_locked_arc(rule, |rule: &ImportRule| {
2765 write!(result, "{}", rule.url.as_str()).unwrap();
2770 pub extern "C" fn Servo_ImportRule_GetLayerName(rule: &LockedImportRule, result: &mut nsACString) {
2771 // https://w3c.github.io/csswg-drafts/cssom/#dom-cssimportrule-layername
2772 read_locked_arc(rule, |rule: &ImportRule| match rule.layer {
2773 ImportLayer::Named(ref name) => name.to_css(&mut CssWriter::new(result)).unwrap(), // "return the layer name declared in the at-rule itself"
2774 ImportLayer::Anonymous => {}, // "or an empty string if the layer is anonymous"
2775 ImportLayer::None => result.set_is_void(true), // "or null if the at-rule does not declare a layer"
2780 pub extern "C" fn Servo_ImportRule_GetSupportsText(
2781 rule: &LockedImportRule,
2782 result: &mut nsACString,
2784 read_locked_arc(rule, |rule: &ImportRule| match rule.supports {
2785 Some(ref supports) => supports
2787 .to_css(&mut CssWriter::new(result))
2789 None => result.set_is_void(true),
2794 pub extern "C" fn Servo_ImportRule_GetSheet(rule: &LockedImportRule) -> *const DomStyleSheet {
2795 read_locked_arc(rule, |rule: &ImportRule| {
2798 .map_or(ptr::null(), |s| s.raw() as *const DomStyleSheet)
2803 pub unsafe extern "C" fn Servo_ImportRule_SetSheet(
2804 rule: &LockedImportRule,
2805 sheet: *mut DomStyleSheet,
2807 write_locked_arc(rule, |rule: &mut ImportRule| {
2808 rule.stylesheet = ImportSheet::new(GeckoStyleSheet::new(sheet));
2813 pub extern "C" fn Servo_Keyframe_GetKeyText(keyframe: &LockedKeyframe, result: &mut nsACString) {
2814 read_locked_arc(keyframe, |keyframe: &Keyframe| {
2817 .to_css(&mut CssWriter::new(result))
2823 pub extern "C" fn Servo_Keyframe_SetKeyText(keyframe: &LockedKeyframe, text: &nsACString) -> bool {
2824 let text = unsafe { text.as_str_unchecked() };
2825 let mut input = ParserInput::new(&text);
2826 if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
2827 write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2828 keyframe.selector = selector;
2837 pub extern "C" fn Servo_Keyframe_GetStyle(
2838 keyframe: &LockedKeyframe,
2839 ) -> Strong<LockedDeclarationBlock> {
2840 read_locked_arc(keyframe, |keyframe: &Keyframe| {
2841 keyframe.block.clone().into()
2846 pub extern "C" fn Servo_Keyframe_SetStyle(
2847 keyframe: &LockedKeyframe,
2848 declarations: &LockedDeclarationBlock,
2850 write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2851 keyframe.block = unsafe { Arc::from_raw_addrefed(declarations) };
2856 pub extern "C" fn Servo_KeyframesRule_GetName(rule: &LockedKeyframesRule) -> *mut nsAtom {
2857 read_locked_arc(rule, |rule: &KeyframesRule| rule.name.as_atom().as_ptr())
2861 pub unsafe extern "C" fn Servo_KeyframesRule_SetName(
2862 rule: &LockedKeyframesRule,
2865 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2866 rule.name = KeyframesName::from_atom(Atom::from_addrefed(name));
2871 pub extern "C" fn Servo_KeyframesRule_GetCount(rule: &LockedKeyframesRule) -> u32 {
2872 read_locked_arc(rule, |rule: &KeyframesRule| rule.keyframes.len() as u32)
2876 pub extern "C" fn Servo_KeyframesRule_GetKeyframeAt(
2877 rule: &LockedKeyframesRule,
2881 ) -> Strong<LockedKeyframe> {
2882 let global_style_data = &*GLOBAL_STYLE_DATA;
2883 let guard = global_style_data.shared_lock.read();
2884 let key = rule.read_with(&guard).keyframes[index as usize].clone();
2885 let location = key.read_with(&guard).source_location;
2886 *line = location.line as u32;
2887 *column = location.column as u32;
2892 pub extern "C" fn Servo_KeyframesRule_FindRule(
2893 rule: &LockedKeyframesRule,
2896 let key = unsafe { key.as_str_unchecked() };
2897 let global_style_data = &*GLOBAL_STYLE_DATA;
2898 let guard = global_style_data.shared_lock.read();
2899 rule.read_with(&guard)
2900 .find_rule(&guard, key)
2901 .map(|index| index as u32)
2902 .unwrap_or(u32::max_value())
2906 pub extern "C" fn Servo_KeyframesRule_AppendRule(
2907 rule: &LockedKeyframesRule,
2908 contents: &StylesheetContents,
2911 let css = unsafe { css.as_str_unchecked() };
2912 let global_style_data = &*GLOBAL_STYLE_DATA;
2914 match Keyframe::parse(css, &contents, &global_style_data.shared_lock) {
2916 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2917 rule.keyframes.push(keyframe);
2926 pub extern "C" fn Servo_KeyframesRule_DeleteRule(rule: &LockedKeyframesRule, index: u32) {
2927 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2928 rule.keyframes.remove(index as usize);
2933 pub extern "C" fn Servo_MediaRule_GetMedia(rule: &MediaRule) -> Strong<LockedMediaList> {
2934 rule.media_queries.clone().into()
2938 pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: &NamespaceRule) -> *mut nsAtom {
2941 .map_or(atom!("").as_ptr(), |a| a.as_ptr())
2945 pub extern "C" fn Servo_NamespaceRule_GetURI(rule: &NamespaceRule) -> *mut nsAtom {
2950 pub extern "C" fn Servo_MarginRule_GetStyle(rule: &MarginRule) -> Strong<LockedDeclarationBlock> {
2951 rule.block.clone().into()
2955 pub extern "C" fn Servo_MarginRule_GetName(rule: &MarginRule, out: &mut nsACString) {
2956 out.assign(rule.name());
2960 pub extern "C" fn Servo_PageRule_GetStyle(rule: &LockedPageRule) -> Strong<LockedDeclarationBlock> {
2961 read_locked_arc(rule, |rule: &PageRule| rule.block.clone().into())
2965 pub extern "C" fn Servo_PageRule_SetStyle(
2966 rule: &LockedPageRule,
2967 declarations: &LockedDeclarationBlock,
2969 write_locked_arc(rule, |rule: &mut PageRule| {
2970 rule.block = unsafe { Arc::from_raw_addrefed(declarations) };
2975 pub extern "C" fn Servo_PageRule_GetSelectorText(rule: &LockedPageRule, result: &mut nsACString) {
2976 read_locked_arc(rule, |rule: &PageRule| {
2977 rule.selectors.to_css(&mut CssWriter::new(result)).unwrap();
2982 pub extern "C" fn Servo_PageRule_SetSelectorText(
2983 contents: &StylesheetContents,
2984 rule: &LockedPageRule,
2987 let value_str = unsafe { text.as_str_unchecked() };
2989 write_locked_arc(rule, |rule: &mut PageRule| {
2990 use style::stylesheets::PageSelectors;
2992 let mut parser_input = ParserInput::new(&value_str);
2993 let mut parser = Parser::new(&mut parser_input);
2995 // Ensure that a blank input results in empty page selectors
2996 if parser.is_exhausted() {
2997 rule.selectors = PageSelectors::default();
3001 let url_data = contents.url_data.read();
3002 let context = ParserContext::new(
3006 ParsingMode::DEFAULT,
3007 QuirksMode::NoQuirks,
3008 /* namespaces = */ Default::default(),
3013 match parser.parse_entirely(|i| PageSelectors::parse(&context, i)) {
3015 rule.selectors = selectors;
3024 pub extern "C" fn Servo_PropertyRule_GetName(rule: &PropertyRule, result: &mut nsACString) {
3025 write!(result, "--{}", rule.name.0).unwrap();
3029 pub extern "C" fn Servo_PropertyRule_GetSyntax(rule: &PropertyRule, result: &mut nsACString) {
3030 if let Some(syntax) = rule.data.syntax.specified_string() {
3031 result.assign(syntax);
3033 debug_assert!(false, "Rule without specified syntax?");
3038 pub extern "C" fn Servo_PropertyRule_GetInherits(rule: &PropertyRule) -> bool {
3043 pub extern "C" fn Servo_PropertyRule_GetInitialValue(
3044 rule: &PropertyRule,
3045 result: &mut nsACString,
3049 .to_css(&mut CssWriter::new(result))
3051 rule.data.initial_value.is_some()
3055 pub extern "C" fn Servo_SupportsRule_GetConditionText(
3056 rule: &SupportsRule,
3057 result: &mut nsACString,
3059 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
3063 pub extern "C" fn Servo_ContainerRule_GetConditionText(
3064 rule: &ContainerRule,
3065 result: &mut nsACString,
3067 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
3071 pub extern "C" fn Servo_ContainerRule_GetContainerQuery(
3072 rule: &ContainerRule,
3073 result: &mut nsACString,
3075 rule.query_condition()
3076 .to_css(&mut CssWriter::new(result))
3081 pub extern "C" fn Servo_ContainerRule_QueryContainerFor(
3082 rule: &ContainerRule,
3083 element: &RawGeckoElement,
3084 ) -> *const RawGeckoElement {
3086 .find_container(GeckoElement(element), None)
3087 .map_or(ptr::null(), |result| result.element.0)
3091 pub extern "C" fn Servo_ContainerRule_GetContainerName(
3092 rule: &ContainerRule,
3093 result: &mut nsACString,
3095 let name = rule.container_name();
3096 if !name.is_none() {
3097 name.to_css(&mut CssWriter::new(result)).unwrap();
3102 pub extern "C" fn Servo_DocumentRule_GetConditionText(
3103 rule: &DocumentRule,
3104 result: &mut nsACString,
3106 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
3110 pub extern "C" fn Servo_FontFeatureValuesRule_GetFontFamily(
3111 rule: &FontFeatureValuesRule,
3112 result: &mut nsACString,
3115 .to_css(&mut CssWriter::new(result))
3120 pub extern "C" fn Servo_FontFeatureValuesRule_GetValueText(
3121 rule: &FontFeatureValuesRule,
3122 result: &mut nsACString,
3124 rule.value_to_css(&mut CssWriter::new(result)).unwrap();
3128 pub extern "C" fn Servo_FontPaletteValuesRule_GetName(
3129 rule: &FontPaletteValuesRule,
3130 result: &mut nsACString,
3132 rule.name.to_css(&mut CssWriter::new(result)).unwrap()
3136 pub extern "C" fn Servo_FontPaletteValuesRule_GetFontFamily(
3137 rule: &FontPaletteValuesRule,
3138 result: &mut nsACString,
3140 if !rule.family_names.is_empty() {
3142 .to_css(&mut CssWriter::new(result))
3148 pub extern "C" fn Servo_FontPaletteValuesRule_GetBasePalette(
3149 rule: &FontPaletteValuesRule,
3150 result: &mut nsACString,
3153 .to_css(&mut CssWriter::new(result))
3158 pub extern "C" fn Servo_FontPaletteValuesRule_GetOverrideColors(
3159 rule: &FontPaletteValuesRule,
3160 result: &mut nsACString,
3162 if !rule.override_colors.is_empty() {
3163 rule.override_colors
3164 .to_css(&mut CssWriter::new(result))
3170 pub extern "C" fn Servo_FontFaceRule_CreateEmpty() -> Strong<LockedFontFaceRule> {
3171 // XXX This is not great. We should split FontFace descriptor data
3172 // from the rule, so that we don't need to create the rule like this
3173 // and the descriptor data itself can be hold in UniquePtr from the
3174 // Gecko side. See bug 1450904.
3175 with_maybe_worker_shared_lock(|lock| {
3176 Arc::new(lock.wrap(FontFaceRule::empty(SourceLocation { line: 0, column: 0 }))).into()
3181 pub unsafe extern "C" fn Servo_FontFaceRule_Clone(
3182 rule: &LockedFontFaceRule,
3183 ) -> Strong<LockedFontFaceRule> {
3184 let clone = read_locked_arc_worker(rule, |rule: &FontFaceRule| rule.clone());
3185 with_maybe_worker_shared_lock(|lock| Arc::new(lock.wrap(clone)).into())
3189 pub unsafe extern "C" fn Servo_FontFaceRule_GetSourceLocation(
3190 rule: &LockedFontFaceRule,
3194 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3195 let location = rule.source_location;
3196 *line.as_mut().unwrap() = location.line as u32;
3197 *column.as_mut().unwrap() = location.column as u32;
3201 macro_rules! apply_font_desc_list {
3202 ($apply_macro:ident) => {
3205 eCSSFontDesc_Family => family,
3206 eCSSFontDesc_Style => style,
3207 eCSSFontDesc_Weight => weight,
3208 eCSSFontDesc_Stretch => stretch,
3209 eCSSFontDesc_Src => sources,
3210 eCSSFontDesc_UnicodeRange => unicode_range,
3211 eCSSFontDesc_FontFeatureSettings => feature_settings,
3212 eCSSFontDesc_FontVariationSettings => variation_settings,
3213 eCSSFontDesc_FontLanguageOverride => language_override,
3214 eCSSFontDesc_Display => display,
3215 eCSSFontDesc_AscentOverride => ascent_override,
3216 eCSSFontDesc_DescentOverride => descent_override,
3217 eCSSFontDesc_LineGapOverride => line_gap_override,
3218 eCSSFontDesc_SizeAdjust => size_adjust,
3221 eCSSFontDesc_UNKNOWN,
3229 pub unsafe extern "C" fn Servo_FontFaceRule_Length(rule: &LockedFontFaceRule) -> u32 {
3230 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3232 macro_rules! count_values {
3234 valid: [$($v_enum_name:ident => $field:ident,)*]
3235 invalid: [$($i_enum_name:ident,)*]
3237 $(if rule.$field.is_some() {
3242 apply_font_desc_list!(count_values);
3248 pub unsafe extern "C" fn Servo_FontFaceRule_IndexGetter(
3249 rule: &LockedFontFaceRule,
3251 ) -> nsCSSFontDesc {
3252 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3254 macro_rules! lookup_index {
3256 valid: [$($v_enum_name:ident => $field:ident,)*]
3257 invalid: [$($i_enum_name:ident,)*]
3259 $(if rule.$field.is_some() {
3261 if count - 1 == index {
3262 return nsCSSFontDesc::$v_enum_name;
3267 apply_font_desc_list!(lookup_index);
3268 return nsCSSFontDesc::eCSSFontDesc_UNKNOWN;
3273 pub unsafe extern "C" fn Servo_FontFaceRule_GetDeclCssText(
3274 rule: &LockedFontFaceRule,
3275 result: &mut nsACString,
3277 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3278 rule.decl_to_css(result).unwrap();
3282 macro_rules! simple_font_descriptor_getter_impl {
3283 ($rule:ident, $out:ident, $field:ident, $compute:ident) => {
3284 read_locked_arc_worker($rule, |rule: &FontFaceRule| {
3286 None => return false,
3287 Some(ref f) => *$out = f.$compute(),
3295 pub extern "C" fn Servo_FontFaceRule_GetFontWeight(
3296 rule: &LockedFontFaceRule,
3297 out: &mut font_face::ComputedFontWeightRange,
3299 simple_font_descriptor_getter_impl!(rule, out, weight, compute)
3303 pub extern "C" fn Servo_FontFaceRule_GetFontStretch(
3304 rule: &LockedFontFaceRule,
3305 out: &mut font_face::ComputedFontStretchRange,
3307 simple_font_descriptor_getter_impl!(rule, out, stretch, compute)
3311 pub extern "C" fn Servo_FontFaceRule_GetFontStyle(
3312 rule: &LockedFontFaceRule,
3313 out: &mut font_face::ComputedFontStyleDescriptor,
3315 simple_font_descriptor_getter_impl!(rule, out, style, compute)
3319 pub extern "C" fn Servo_FontFaceRule_GetFontDisplay(
3320 rule: &LockedFontFaceRule,
3321 out: &mut font_face::FontDisplay,
3323 simple_font_descriptor_getter_impl!(rule, out, display, clone)
3327 pub extern "C" fn Servo_FontFaceRule_GetFontLanguageOverride(
3328 rule: &LockedFontFaceRule,
3329 out: &mut computed::FontLanguageOverride,
3331 simple_font_descriptor_getter_impl!(rule, out, language_override, clone)
3334 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3335 // rather than an actual percentage value.
3337 pub extern "C" fn Servo_FontFaceRule_GetAscentOverride(
3338 rule: &LockedFontFaceRule,
3339 out: &mut computed::Percentage,
3341 simple_font_descriptor_getter_impl!(rule, out, ascent_override, compute)
3344 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3345 // rather than an actual percentage value.
3347 pub extern "C" fn Servo_FontFaceRule_GetDescentOverride(
3348 rule: &LockedFontFaceRule,
3349 out: &mut computed::Percentage,
3351 simple_font_descriptor_getter_impl!(rule, out, descent_override, compute)
3354 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3355 // rather than an actual percentage value.
3357 pub extern "C" fn Servo_FontFaceRule_GetLineGapOverride(
3358 rule: &LockedFontFaceRule,
3359 out: &mut computed::Percentage,
3361 simple_font_descriptor_getter_impl!(rule, out, line_gap_override, compute)
3365 pub extern "C" fn Servo_FontFaceRule_GetSizeAdjust(
3366 rule: &LockedFontFaceRule,
3367 out: &mut computed::Percentage,
3369 simple_font_descriptor_getter_impl!(rule, out, size_adjust, compute)
3373 pub unsafe extern "C" fn Servo_FontFaceRule_GetFamilyName(
3374 rule: &LockedFontFaceRule,
3376 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3377 // TODO(emilio): font-family is a mandatory descriptor, can't we unwrap
3378 // here, and remove the null-checks in Gecko?
3381 .map_or(ptr::null_mut(), |f| f.name.as_ptr())
3386 pub unsafe extern "C" fn Servo_FontFaceRule_GetUnicodeRanges(
3387 rule: &LockedFontFaceRule,
3388 out_len: *mut usize,
3389 ) -> *const UnicodeRange {
3391 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3392 let ranges = match rule.unicode_range {
3393 Some(ref ranges) => ranges,
3394 None => return ptr::null(),
3396 *out_len = ranges.len();
3397 ranges.as_ptr() as *const _
3402 pub unsafe extern "C" fn Servo_FontFaceRule_GetSources(
3403 rule: &LockedFontFaceRule,
3404 out: *mut nsTArray<FontFaceSourceListComponent>,
3406 let out = &mut *out;
3407 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3408 let sources = match rule.sources {
3412 let len = sources.0.iter().fold(0, |acc, src| {
3414 Source::Url(ref url) => {
3415 (if url.format_hint.is_some() { 2 } else { 1 }) +
3416 (if url.tech_flags.is_empty() { 0 } else { 1 })
3418 Source::Local(_) => 1,
3422 out.set_len(len as u32);
3424 let mut iter = out.iter_mut();
3427 let mut set_next = |component: FontFaceSourceListComponent| {
3428 *iter.next().expect("miscalculated length") = component;
3431 for source in sources.0.iter() {
3433 Source::Url(ref url) => {
3434 set_next(FontFaceSourceListComponent::Url(&url.url));
3435 if let Some(hint) = &url.format_hint {
3437 FontFaceSourceFormat::Keyword(kw) => {
3438 set_next(FontFaceSourceListComponent::FormatHintKeyword(*kw))
3440 FontFaceSourceFormat::String(s) => {
3441 set_next(FontFaceSourceListComponent::FormatHintString {
3443 utf8_bytes: s.as_ptr(),
3448 if !url.tech_flags.is_empty() {
3449 set_next(FontFaceSourceListComponent::TechFlags(url.tech_flags));
3452 Source::Local(ref name) => {
3453 set_next(FontFaceSourceListComponent::Local(name.name.as_ptr()));
3459 assert!(iter.next().is_none(), "miscalculated");
3464 pub unsafe extern "C" fn Servo_FontFaceRule_GetVariationSettings(
3465 rule: &LockedFontFaceRule,
3466 variations: *mut nsTArray<structs::gfxFontVariation>,
3468 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3469 let source_variations = match rule.variation_settings {
3474 (*variations).set_len(source_variations.0.len() as u32);
3475 for (target, source) in (*variations).iter_mut().zip(source_variations.0.iter()) {
3476 *target = structs::gfxFontVariation {
3478 mValue: source.value.get(),
3485 pub unsafe extern "C" fn Servo_FontFaceRule_GetFeatureSettings(
3486 rule: &LockedFontFaceRule,
3487 features: *mut nsTArray<structs::gfxFontFeature>,
3489 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3490 let source_features = match rule.feature_settings {
3495 (*features).set_len(source_features.0.len() as u32);
3496 for (target, source) in (*features).iter_mut().zip(source_features.0.iter()) {
3497 *target = structs::gfxFontFeature {
3499 mValue: source.value.value() as u32,
3506 pub extern "C" fn Servo_FontFaceRule_GetDescriptorCssText(
3507 rule: &LockedFontFaceRule,
3508 desc: nsCSSFontDesc,
3509 result: &mut nsACString,
3511 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3512 let mut writer = CssWriter::new(result);
3513 macro_rules! to_css_text {
3515 valid: [$($v_enum_name:ident => $field:ident,)*]
3516 invalid: [$($i_enum_name:ident,)*]
3520 nsCSSFontDesc::$v_enum_name => {
3521 if let Some(ref value) = rule.$field {
3522 value.to_css(&mut writer).unwrap();
3527 nsCSSFontDesc::$i_enum_name => {
3528 debug_assert!(false, "not a valid font descriptor");
3534 apply_font_desc_list!(to_css_text)
3539 pub unsafe extern "C" fn Servo_FontFaceRule_SetDescriptor(
3540 rule: &LockedFontFaceRule,
3541 desc: nsCSSFontDesc,
3543 data: *mut URLExtraData,
3544 out_changed: *mut bool,
3546 let value = value.as_str_unchecked();
3547 let mut input = ParserInput::new(&value);
3548 let mut parser = Parser::new(&mut input);
3549 let url_data = UrlExtraData::from_ptr_ref(&data);
3550 let context = ParserContext::new(
3553 Some(CssRuleType::FontFace),
3554 ParsingMode::DEFAULT,
3555 QuirksMode::NoQuirks,
3556 /* namespaces = */ Default::default(),
3561 write_locked_arc_worker(rule, |rule: &mut FontFaceRule| {
3562 macro_rules! to_css_text {
3564 valid: [$($v_enum_name:ident => $field:ident,)*]
3565 invalid: [$($i_enum_name:ident,)*]
3569 nsCSSFontDesc::$v_enum_name => {
3570 if let Ok(value) = parser.parse_entirely(|i| Parse::parse(&context, i)) {
3571 let result = Some(value);
3572 *out_changed = result != rule.$field;
3573 rule.$field = result;
3581 nsCSSFontDesc::$i_enum_name => {
3582 debug_assert!(false, "not a valid font descriptor");
3589 apply_font_desc_list!(to_css_text)
3594 pub unsafe extern "C" fn Servo_FontFaceRule_ResetDescriptor(
3595 rule: &LockedFontFaceRule,
3596 desc: nsCSSFontDesc,
3598 write_locked_arc_worker(rule, |rule: &mut FontFaceRule| {
3599 macro_rules! reset_desc {
3601 valid: [$($v_enum_name:ident => $field:ident,)*]
3602 invalid: [$($i_enum_name:ident,)*]
3605 $(nsCSSFontDesc::$v_enum_name => rule.$field = None,)*
3606 $(nsCSSFontDesc::$i_enum_name => debug_assert!(false, "not a valid font descriptor"),)*
3610 apply_font_desc_list!(reset_desc)
3615 pub unsafe extern "C" fn Servo_CounterStyleRule_GetName(
3616 rule: &LockedCounterStyleRule,
3618 read_locked_arc(rule, |rule: &CounterStyleRule| rule.name().0.as_ptr())
3622 pub unsafe extern "C" fn Servo_CounterStyleRule_SetName(
3623 rule: &LockedCounterStyleRule,
3626 let value = value.as_str_unchecked();
3627 let mut input = ParserInput::new(&value);
3628 let mut parser = Parser::new(&mut input);
3629 match parser.parse_entirely(counter_style::parse_counter_style_name_definition) {
3631 write_locked_arc(rule, |rule: &mut CounterStyleRule| rule.set_name(name));
3639 pub unsafe extern "C" fn Servo_CounterStyleRule_GetGeneration(
3640 rule: &LockedCounterStyleRule,
3642 read_locked_arc(rule, |rule: &CounterStyleRule| rule.generation())
3645 fn symbol_to_string(s: &counter_style::Symbol) -> nsString {
3647 counter_style::Symbol::String(ref s) => nsString::from(&**s),
3648 counter_style::Symbol::Ident(ref i) => nsString::from(i.0.as_slice()),
3652 // TODO(emilio): Cbindgen could be used to simplify a bunch of code here.
3654 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPad(
3655 rule: &LockedCounterStyleRule,
3657 symbol: &mut nsString,
3659 read_locked_arc(rule, |rule: &CounterStyleRule| {
3660 let pad = match rule.pad() {
3662 None => return false,
3664 *width = pad.0.value();
3665 *symbol = symbol_to_string(&pad.1);
3670 fn get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool {
3673 None => return false,
3675 *out = symbol_to_string(s);
3680 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPrefix(
3681 rule: &LockedCounterStyleRule,
3684 read_locked_arc(rule, |rule: &CounterStyleRule| {
3685 get_symbol(rule.prefix(), out)
3690 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSuffix(
3691 rule: &LockedCounterStyleRule,
3694 read_locked_arc(rule, |rule: &CounterStyleRule| {
3695 get_symbol(rule.suffix(), out)
3700 pub unsafe extern "C" fn Servo_CounterStyleRule_GetNegative(
3701 rule: &LockedCounterStyleRule,
3702 prefix: &mut nsString,
3703 suffix: &mut nsString,
3705 read_locked_arc(rule, |rule: &CounterStyleRule| {
3706 let negative = match rule.negative() {
3708 None => return false,
3710 *prefix = symbol_to_string(&negative.0);
3711 *suffix = match negative.1 {
3712 Some(ref s) => symbol_to_string(s),
3713 None => nsString::new(),
3720 pub enum IsOrdinalInRange {
3728 pub unsafe extern "C" fn Servo_CounterStyleRule_IsInRange(
3729 rule: &LockedCounterStyleRule,
3731 ) -> IsOrdinalInRange {
3732 use style::counter_style::CounterBound;
3733 read_locked_arc(rule, |rule: &CounterStyleRule| {
3734 let range = match rule.range() {
3736 None => return IsOrdinalInRange::NoOrdinalSpecified,
3739 if range.0.is_empty() {
3740 return IsOrdinalInRange::Auto;
3743 let in_range = range.0.iter().any(|r| {
3744 if let CounterBound::Integer(start) = r.start {
3745 if start.value() > ordinal {
3750 if let CounterBound::Integer(end) = r.end {
3751 if end.value() < ordinal {
3760 IsOrdinalInRange::InRange
3762 IsOrdinalInRange::NotInRange
3768 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols(
3769 rule: &LockedCounterStyleRule,
3770 symbols: &mut style::OwnedSlice<nsString>,
3772 read_locked_arc(rule, |rule: &CounterStyleRule| {
3773 *symbols = match rule.symbols() {
3774 Some(s) => s.0.iter().map(symbol_to_string).collect(),
3775 None => style::OwnedSlice::default(),
3781 pub struct AdditiveSymbol {
3783 pub symbol: nsString,
3787 pub unsafe extern "C" fn Servo_CounterStyleRule_GetAdditiveSymbols(
3788 rule: &LockedCounterStyleRule,
3789 symbols: &mut style::OwnedSlice<AdditiveSymbol>,
3791 read_locked_arc(rule, |rule: &CounterStyleRule| {
3792 *symbols = match rule.additive_symbols() {
3795 .map(|s| AdditiveSymbol {
3796 weight: s.weight.value(),
3797 symbol: symbol_to_string(&s.symbol),
3801 None => style::OwnedSlice::default(),
3807 pub enum CounterSpeakAs {
3817 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSpeakAs(
3818 rule: &LockedCounterStyleRule,
3819 out: &mut CounterSpeakAs,
3821 use style::counter_style::SpeakAs;
3822 *out = read_locked_arc(rule, |rule: &CounterStyleRule| {
3823 let speak_as = match rule.speak_as() {
3825 None => return CounterSpeakAs::None,
3828 SpeakAs::Auto => CounterSpeakAs::Auto,
3829 SpeakAs::Bullets => CounterSpeakAs::Bullets,
3830 SpeakAs::Numbers => CounterSpeakAs::Numbers,
3831 SpeakAs::Words => CounterSpeakAs::Words,
3832 SpeakAs::Other(ref other) => CounterSpeakAs::Ident(other.0.as_ptr()),
3838 pub enum CounterSystem {
3849 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSystem(
3850 rule: &LockedCounterStyleRule,
3851 ) -> CounterSystem {
3852 use style::counter_style::System;
3853 read_locked_arc(rule, |rule: &CounterStyleRule| {
3854 match *rule.resolved_system() {
3855 System::Cyclic => CounterSystem::Cyclic,
3856 System::Numeric => CounterSystem::Numeric,
3857 System::Alphabetic => CounterSystem::Alphabetic,
3858 System::Symbolic => CounterSystem::Symbolic,
3859 System::Additive => CounterSystem::Additive,
3860 System::Fixed { .. } => CounterSystem::Fixed,
3861 System::Extends(_) => CounterSystem::Extends,
3867 pub unsafe extern "C" fn Servo_CounterStyleRule_GetExtended(
3868 rule: &LockedCounterStyleRule,
3870 read_locked_arc(rule, |rule: &CounterStyleRule| {
3871 match *rule.resolved_system() {
3872 counter_style::System::Extends(ref name) => name.0.as_ptr(),
3874 debug_assert!(false, "Not extends system");
3882 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFixedFirstValue(
3883 rule: &LockedCounterStyleRule,
3885 read_locked_arc(rule, |rule: &CounterStyleRule| {
3886 match *rule.resolved_system() {
3887 counter_style::System::Fixed { first_symbol_value } => {
3888 first_symbol_value.map_or(1, |v| v.value())
3891 debug_assert!(false, "Not fixed system");
3899 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFallback(
3900 rule: &LockedCounterStyleRule,
3902 read_locked_arc(rule, |rule: &CounterStyleRule| {
3903 rule.fallback().map_or(ptr::null_mut(), |i| i.0 .0.as_ptr())
3907 macro_rules! counter_style_descriptors {
3910 $($desc:ident => $getter:ident / $setter:ident,)+
3917 pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptorCssText(
3918 rule: &LockedCounterStyleRule,
3919 desc: nsCSSCounterDesc,
3920 result: &mut nsACString,
3922 let mut writer = CssWriter::new(result);
3923 read_locked_arc(rule, |rule: &CounterStyleRule| {
3925 $(nsCSSCounterDesc::$desc => {
3926 if let Some(value) = rule.$getter() {
3927 value.to_css(&mut writer).unwrap();
3930 $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3936 pub unsafe extern "C" fn Servo_CounterStyleRule_SetDescriptor(
3937 rule: &LockedCounterStyleRule,
3938 desc: nsCSSCounterDesc,
3941 let value = value.as_str_unchecked();
3942 let mut input = ParserInput::new(&value);
3943 let mut parser = Parser::new(&mut input);
3944 let url_data = dummy_url_data();
3945 let context = ParserContext::new(
3948 Some(CssRuleType::CounterStyle),
3949 ParsingMode::DEFAULT,
3950 QuirksMode::NoQuirks,
3951 /* namespaces = */ Default::default(),
3956 write_locked_arc(rule, |rule: &mut CounterStyleRule| {
3958 $(nsCSSCounterDesc::$desc => {
3959 match parser.parse_entirely(|i| Parse::parse(&context, i)) {
3960 Ok(value) => rule.$setter(value),
3964 $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3971 counter_style_descriptors! {
3973 eCSSCounterDesc_System => system / set_system,
3974 eCSSCounterDesc_Symbols => symbols / set_symbols,
3975 eCSSCounterDesc_AdditiveSymbols => additive_symbols / set_additive_symbols,
3976 eCSSCounterDesc_Negative => negative / set_negative,
3977 eCSSCounterDesc_Prefix => prefix / set_prefix,
3978 eCSSCounterDesc_Suffix => suffix / set_suffix,
3979 eCSSCounterDesc_Range => range / set_range,
3980 eCSSCounterDesc_Pad => pad / set_pad,
3981 eCSSCounterDesc_Fallback => fallback / set_fallback,
3982 eCSSCounterDesc_SpeakAs => speak_as / set_speak_as,
3985 eCSSCounterDesc_UNKNOWN,
3986 eCSSCounterDesc_COUNT,
3991 pub unsafe extern "C" fn Servo_ComputedValues_GetForPageContent(
3992 raw_data: &PerDocumentStyleData,
3993 page_name: *const nsAtom,
3994 pseudos: PagePseudoClassFlags,
3995 ) -> Strong<ComputedValues> {
3996 let global_style_data = &*GLOBAL_STYLE_DATA;
3997 let guard = global_style_data.shared_lock.read();
3998 let guards = StylesheetGuards::same(&guard);
3999 let data = raw_data.borrow_mut();
4000 let cascade_data = data.stylist.cascade_data();
4002 let mut extra_declarations = vec![];
4003 let iter = data.stylist.iter_extra_data_origins_rev();
4004 let name = if !page_name.is_null() {
4005 Some(Atom::from_raw(page_name as *mut nsAtom))
4009 for (data, origin) in iter {
4010 data.pages.match_and_append_rules(
4011 &mut extra_declarations,
4020 let rule_node = data.stylist.rule_node_for_precomputed_pseudo(
4022 &PseudoElement::PageContent,
4027 .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
4029 &PseudoElement::PageContent,
4037 pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox(
4038 parent_style_or_null: Option<&ComputedValues>,
4039 pseudo: PseudoStyleType,
4040 raw_data: &PerDocumentStyleData,
4041 ) -> Strong<ComputedValues> {
4042 let pseudo = PseudoElement::from_pseudo_type(pseudo, None).unwrap();
4043 debug_assert!(pseudo.is_anon_box());
4044 debug_assert_ne!(pseudo, PseudoElement::PageContent);
4045 let global_style_data = &*GLOBAL_STYLE_DATA;
4046 let guard = global_style_data.shared_lock.read();
4047 let guards = StylesheetGuards::same(&guard);
4048 let data = raw_data.borrow_mut();
4049 let rule_node = data
4051 .rule_node_for_precomputed_pseudo(&guards, &pseudo, vec![]);
4054 .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
4057 parent_style_or_null.map(|x| &*x),
4063 fn get_functional_pseudo_parameter_atom(
4064 functional_pseudo_parameter: *mut nsAtom,
4065 ) -> Option<AtomIdent> {
4066 if functional_pseudo_parameter.is_null() {
4069 Some(AtomIdent::new(unsafe {
4070 Atom::from_raw(functional_pseudo_parameter)
4076 pub extern "C" fn Servo_ResolvePseudoStyle(
4077 element: &RawGeckoElement,
4078 pseudo_type: PseudoStyleType,
4079 functional_pseudo_parameter: *mut nsAtom,
4081 inherited_style: Option<&ComputedValues>,
4082 raw_data: &PerDocumentStyleData,
4083 ) -> Strong<ComputedValues> {
4084 let element = GeckoElement(element);
4085 let doc_data = raw_data.borrow();
4088 "Servo_ResolvePseudoStyle: {:?} {:?}, is_probe: {}",
4090 PseudoElement::from_pseudo_type(
4092 get_functional_pseudo_parameter_atom(functional_pseudo_parameter)
4097 let data = element.borrow_data();
4099 let data = match data.as_ref() {
4100 Some(data) if data.has_styles() => data,
4102 // FIXME(bholley, emilio): Assert against this.
4104 // Known offender is nsMathMLmoFrame::MarkIntrinsicISizesDirty,
4105 // which goes and does a bunch of work involving style resolution.
4107 // Bug 1403865 tracks fixing it, and potentially adding an assert
4109 warn!("Calling Servo_ResolvePseudoStyle on unstyled element");
4110 return if is_probe {
4113 doc_data.default_computed_values().clone().into()
4118 let pseudo_element = PseudoElement::from_pseudo_type(
4120 get_functional_pseudo_parameter_atom(functional_pseudo_parameter),
4122 .expect("ResolvePseudoStyle with a non-pseudo?");
4124 let matching_fn = |pseudo: &PseudoElement| *pseudo == pseudo_element;
4126 let global_style_data = &*GLOBAL_STYLE_DATA;
4127 let guard = global_style_data.shared_lock.read();
4128 let style = get_pseudo_style(
4137 /* matching_func = */
4138 if pseudo_element.is_highlight() {
4146 Some(s) => s.into(),
4148 debug_assert!(is_probe);
4154 fn debug_atom_array(atoms: &nsTArray<structs::RefPtr<nsAtom>>) -> String {
4155 let mut result = String::from("[");
4156 for atom in atoms.iter() {
4157 if atom.mRawPtr.is_null() {
4158 result += "(null), ";
4160 let atom = unsafe { WeakAtom::new(atom.mRawPtr) };
4161 write!(result, "{}, ", atom).unwrap();
4169 pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle(
4170 element: &RawGeckoElement,
4171 pseudo_tag: *mut nsAtom,
4172 inherited_style: &ComputedValues,
4173 input_word: &nsTArray<structs::RefPtr<nsAtom>>,
4174 raw_data: &PerDocumentStyleData,
4175 ) -> Strong<ComputedValues> {
4176 let element = GeckoElement(element);
4179 .expect("Calling ResolveXULTreePseudoStyle on unstyled element?");
4181 let pseudo = unsafe {
4182 Atom::with(pseudo_tag, |atom| {
4183 PseudoElement::from_tree_pseudo_atom(atom, Box::new([]))
4185 .expect("ResolveXULTreePseudoStyle with a non-tree pseudo?")
4187 let doc_data = raw_data.borrow();
4190 "ResolveXULTreePseudoStyle: {:?} {:?} {}",
4193 debug_atom_array(input_word)
4196 let matching_fn = |pseudo: &PseudoElement| {
4199 .expect("Not a tree pseudo-element?");
4201 .all(|atom| input_word.iter().any(|item| atom.as_ptr() == item.mRawPtr))
4204 let global_style_data = &*GLOBAL_STYLE_DATA;
4205 let guard = global_style_data.shared_lock.read();
4212 Some(inherited_style),
4214 /* is_probe = */ false,
4222 pub extern "C" fn Servo_SetExplicitStyle(element: &RawGeckoElement, style: &ComputedValues) {
4223 let element = GeckoElement(element);
4224 debug!("Servo_SetExplicitStyle: {:?}", element);
4225 // We only support this API for initial styling. There's no reason it couldn't
4226 // work for other things, we just haven't had a reason to do so.
4227 debug_assert!(!element.has_data());
4228 let mut data = unsafe { element.ensure_data() };
4229 data.styles.primary = Some(unsafe { Arc::from_raw_addrefed(style) });
4232 fn get_pseudo_style(
4233 guard: &SharedRwLockReadGuard,
4234 element: GeckoElement,
4235 pseudo: &PseudoElement,
4236 rule_inclusion: RuleInclusion,
4237 styles: &ElementStyles,
4238 inherited_styles: Option<&ComputedValues>,
4241 matching_func: Option<&dyn Fn(&PseudoElement) -> bool>,
4242 ) -> Option<Arc<ComputedValues>> {
4243 let style = match pseudo.cascade_type() {
4244 PseudoElementCascadeType::Eager => {
4246 PseudoElement::FirstLetter => {
4247 styles.pseudos.get(&pseudo).map(|pseudo_styles| {
4248 // inherited_styles can be None when doing lazy resolution
4249 // (e.g. for computed style) or when probing. In that case
4250 // we just inherit from our element, which is what Gecko
4251 // does in that situation. What should actually happen in
4252 // the computed style case is a bit unclear.
4253 let inherited_styles = inherited_styles.unwrap_or(styles.primary());
4254 let guards = StylesheetGuards::same(guard);
4255 let inputs = CascadeInputs::new_from_style(pseudo_styles);
4256 stylist.compute_pseudo_element_style_with_inputs(
4260 Some(inherited_styles),
4266 // Unfortunately, we can't assert that inherited_styles, if
4267 // present, is pointer-equal to styles.primary(), or even
4268 // equal in any meaningful way. The way it can fail is as
4269 // follows. Say we append an element with a ::before,
4270 // ::after, or ::first-line to a parent with a ::first-line,
4271 // such that the element ends up on the first line of the
4272 // parent (e.g. it's an inline-block in the case it has a
4273 // ::first-line, or any container in the ::before/::after
4274 // cases). Then gecko will update its frame's style to
4275 // inherit from the parent's ::first-line. The next time we
4276 // try to get the ::before/::after/::first-line style for
4277 // the kid, we'll likely pass in the frame's style as
4278 // inherited_styles, but that's not pointer-identical to
4279 // styles.primary(), because it got reparented.
4281 // Now in practice this turns out to be OK, because all the
4282 // cases in which there's a mismatch go ahead and reparent
4283 // styles again as needed to make sure the ::first-line
4284 // affects all the things it should affect. But it makes it
4285 // impossible to assert anything about the two styles
4286 // matching here, unfortunately.
4287 styles.pseudos.get(&pseudo).cloned()
4291 PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
4292 PseudoElementCascadeType::Lazy => {
4294 inherited_styles.is_none() ||
4295 ptr::eq(inherited_styles.unwrap(), &**styles.primary())
4297 let originating_element_style = styles.primary();
4298 let guards = StylesheetGuards::same(guard);
4299 stylist.lazily_compute_pseudo_element_style(
4304 originating_element_style,
4315 Some(style.unwrap_or_else(|| {
4316 StyleBuilder::for_inheritance(
4319 Some(styles.primary()),
4327 pub unsafe extern "C" fn Servo_ComputedValues_Inherit(
4328 raw_data: &PerDocumentStyleData,
4329 pseudo: PseudoStyleType,
4330 parent_style_context: Option<&ComputedValues>,
4331 target: structs::InheritTarget,
4332 ) -> Strong<ComputedValues> {
4333 let data = raw_data.borrow();
4335 let for_text = target == structs::InheritTarget::Text;
4336 let pseudo = PseudoElement::from_pseudo_type(pseudo, None).unwrap();
4337 debug_assert!(pseudo.is_anon_box());
4339 let mut style = StyleBuilder::for_inheritance(
4340 data.stylist.device(),
4341 Some(&data.stylist),
4342 parent_style_context,
4347 StyleAdjuster::new(&mut style).adjust_for_text();
4350 style.build().into()
4354 pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions(
4355 values: &ComputedValues,
4357 let ui = values.get_ui();
4358 ui.specifies_animations() || ui.specifies_transitions()
4362 pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
4363 values: &ComputedValues,
4364 rules: &mut ThinVec<*const LockedStyleRule>,
4366 let rule_node = match values.rules {
4371 for node in rule_node.self_and_ancestors() {
4372 let style_rule = match node.style_source().and_then(|x| x.as_rule()) {
4377 // For the rules with any important declaration, we insert them into
4378 // rule tree twice, one for normal level and another for important
4379 // level. So, we skip the important one to keep the specificity order of
4381 if node.importance().important() {
4385 rules.push(&*style_rule);
4389 /// println_stderr!() calls Gecko's printf_stderr(), which, unlike eprintln!(),
4390 /// will funnel output to Android logcat.
4391 #[cfg(feature = "gecko_debug")]
4392 macro_rules! println_stderr {
4395 let mut s = nsCString::new();
4396 write!(s, $($e),+).unwrap();
4397 s.write_char('\n').unwrap();
4398 unsafe { bindings::Gecko_PrintfStderr(&s); }
4403 #[cfg(feature = "gecko_debug")]
4404 fn dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet) {
4405 println_stderr!(" Properties:");
4406 for p in properties.iter() {
4407 let mut v = nsCString::new();
4408 cv.computed_or_resolved_value(p, None, &mut v).unwrap();
4409 println_stderr!(" {:?}: {}", p, v);
4414 #[cfg(feature = "gecko_debug")]
4415 fn dump_rules(cv: &ComputedValues) {
4416 println_stderr!(" Rules({:?}):", cv.pseudo());
4417 let global_style_data = &*GLOBAL_STYLE_DATA;
4418 let guard = global_style_data.shared_lock.read();
4419 if let Some(rules) = cv.rules.as_ref() {
4420 for rn in rules.self_and_ancestors() {
4421 if rn.importance().important() {
4424 if let Some(d) = rn.style_source().and_then(|s| s.as_declarations()) {
4425 println_stderr!(" [DeclarationBlock: {:?}]", d);
4427 if let Some(r) = rn.style_source().and_then(|s| s.as_rule()) {
4428 let mut s = nsCString::new();
4429 r.read_with(&guard).to_css(&guard, &mut s).unwrap();
4430 println_stderr!(" {}", s);
4436 #[cfg(feature = "gecko_debug")]
4438 pub extern "C" fn Servo_ComputedValues_EqualForCachedAnonymousContentStyle(
4442 let mut differing_properties = a.differing_properties(b);
4444 // Ignore any difference in -x-lang, which we can't override in the rules in scrollbars.css,
4445 // but which makes no difference for the anonymous content subtrees we cache style for.
4446 differing_properties.remove(LonghandId::XLang);
4447 // Similarly, -x-lang can influence the font-family fallback we have for the initial
4448 // font-family so remove it as well.
4449 differing_properties.remove(LonghandId::FontFamily);
4450 // We reset font-size to an explicit pixel value, and thus it can get affected by our inherited
4451 // effective zoom. But we don't care about it for the same reason as above.
4452 differing_properties.remove(LonghandId::FontSize);
4454 // Ignore any difference in pref-controlled, inherited properties. These properties may or may
4455 // not be set by the 'all' declaration in scrollbars.css, depending on whether the pref was
4456 // enabled at the time the UA sheets were parsed.
4458 // If you add a new pref-controlled, inherited property, it must be defined with
4459 // `has_effect_on_gecko_scrollbars=False` to declare that different values of this property on
4460 // a <scrollbar> element or its descendant scrollbar part elements should have no effect on
4461 // their rendering and behavior.
4463 // If you do need a pref-controlled, inherited property to have an effect on these elements,
4464 // then you will need to add some checks to the
4465 // nsIAnonymousContentCreator::CreateAnonymousContent implementations of nsHTMLScrollFrame and
4466 // nsScrollbarFrame to clear the AnonymousContentKey if a non-initial value is used.
4467 differing_properties.remove_all(&LonghandIdSet::has_no_effect_on_gecko_scrollbars());
4469 if !differing_properties.is_empty() {
4470 println_stderr!("Actual style:");
4471 dump_properties_and_rules(a, &differing_properties);
4472 println_stderr!("Expected style:");
4473 dump_properties_and_rules(b, &differing_properties);
4476 differing_properties.is_empty()
4479 #[cfg(feature = "gecko_debug")]
4481 pub extern "C" fn Servo_ComputedValues_DumpMatchedRules(s: &ComputedValues) {
4486 pub extern "C" fn Servo_ComputedValues_BlockifiedDisplay(
4487 style: &ComputedValues,
4488 is_root_element: bool,
4490 let display = style.get_box().clone_display();
4491 let blockified_display = display.equivalent_block_display(is_root_element);
4492 blockified_display.to_u16()
4496 pub extern "C" fn Servo_StyleSet_Init(doc: &structs::Document) -> *mut PerDocumentStyleData {
4497 let data = Box::new(PerDocumentStyleData::new(doc));
4499 // Do this here rather than in Servo_Initialize since we need a document to
4500 // get the default computed values from.
4501 style::properties::generated::gecko::assert_initial_values_match(&data);
4503 Box::into_raw(data) as *mut PerDocumentStyleData
4507 pub unsafe extern "C" fn Servo_StyleSet_Drop(data: *mut PerDocumentStyleData) {
4508 let _ = Box::from_raw(data);
4512 pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: &PerDocumentStyleData) {
4513 let mut data = raw_data.borrow_mut();
4514 data.stylist.device_mut().rebuild_cached_data();
4515 data.undisplayed_style_cache.clear();
4519 pub unsafe extern "C" fn Servo_StyleSet_CompatModeChanged(raw_data: &PerDocumentStyleData) {
4520 let mut data = raw_data.borrow_mut();
4521 let quirks_mode = data.stylist.device().document().mCompatMode;
4522 data.stylist.set_quirks_mode(quirks_mode.into());
4525 fn parse_property_into(
4526 declarations: &mut SourcePropertyDeclaration,
4527 property_id: PropertyId,
4530 url_data: &UrlExtraData,
4531 parsing_mode: ParsingMode,
4532 quirks_mode: QuirksMode,
4533 rule_type: CssRuleType,
4534 reporter: Option<&dyn ParseErrorReporter>,
4535 ) -> Result<(), ()> {
4536 let value = unsafe { value.as_str_unchecked() };
4538 if let Some(non_custom) = property_id.non_custom_id() {
4539 if !non_custom.allowed_in_rule(rule_type.into()) {
4544 parse_one_declaration_into(
4558 pub unsafe extern "C" fn Servo_ParseProperty(
4559 property: &structs::AnimatedPropertyID,
4561 data: *mut URLExtraData,
4562 parsing_mode: ParsingMode,
4563 quirks_mode: nsCompatibility,
4564 loader: *mut Loader,
4565 rule_type: CssRuleType,
4566 ) -> Strong<LockedDeclarationBlock> {
4567 let id = get_property_id_from_animatedpropertyid!(property, Strong::null());
4568 let mut declarations = SourcePropertyDeclaration::default();
4569 let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
4570 let data = UrlExtraData::from_ptr_ref(&data);
4571 let result = parse_property_into(
4580 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4585 let global_style_data = &*GLOBAL_STYLE_DATA;
4586 let mut block = PropertyDeclarationBlock::new();
4587 block.extend(declarations.drain(), Importance::Normal);
4588 Arc::new(global_style_data.shared_lock.wrap(block)).into()
4590 Err(_) => Strong::null(),
4595 pub extern "C" fn Servo_ParseEasing(
4596 easing: &nsACString,
4597 output: &mut ComputedTimingFunction,
4599 use style::properties::longhands::transition_timing_function;
4601 let context = ParserContext::new(
4603 unsafe { dummy_url_data() },
4604 Some(CssRuleType::Style),
4605 ParsingMode::DEFAULT,
4606 QuirksMode::NoQuirks,
4607 /* namespaces = */ Default::default(),
4611 let easing = easing.to_string();
4612 let mut input = ParserInput::new(&easing);
4613 let mut parser = Parser::new(&mut input);
4615 parser.parse_entirely(|p| transition_timing_function::single_value::parse(&context, p));
4617 Ok(parsed_easing) => {
4618 *output = parsed_easing.to_computed_value_without_context();
4626 pub extern "C" fn Servo_SerializeEasing(easing: &ComputedTimingFunction, output: &mut nsACString) {
4627 easing.to_css(&mut CssWriter::new(output)).unwrap();
4631 pub extern "C" fn Servo_GetProperties_Overriding_Animation(
4632 element: &RawGeckoElement,
4633 list: &nsTArray<nsCSSPropertyID>,
4634 set: &mut structs::nsCSSPropertyIDSet,
4636 let element = GeckoElement(element);
4637 let element_data = match element.borrow_data() {
4641 let global_style_data = &*GLOBAL_STYLE_DATA;
4642 let guard = global_style_data.shared_lock.read();
4643 let guards = StylesheetGuards::same(&guard);
4644 let (overridden, custom) = element_data
4648 .get_properties_overriding_animations(&guards);
4649 for p in list.iter() {
4650 match NonCustomPropertyId::from_nscsspropertyid(*p) {
4652 if let Some(id) = property.as_longhand() {
4653 if overridden.contains(id) {
4654 unsafe { Gecko_AddPropertyToSet(set, *p) };
4659 if *p == nsCSSPropertyID::eCSSPropertyExtra_variable && custom {
4660 unsafe { Gecko_AddPropertyToSet(set, *p) };
4668 pub extern "C" fn Servo_MatrixTransform_Operate(
4669 matrix_operator: MatrixTransformOperator,
4670 from: *const structs::Matrix4x4Components,
4671 to: *const structs::Matrix4x4Components,
4673 output: *mut structs::Matrix4x4Components,
4675 use self::MatrixTransformOperator::{Accumulate, Interpolate};
4676 use style::values::computed::transform::Matrix3D;
4678 let from = Matrix3D::from(unsafe { from.as_ref() }.expect("not a valid 'from' matrix"));
4679 let to = Matrix3D::from(unsafe { to.as_ref() }.expect("not a valid 'to' matrix"));
4680 let result = match matrix_operator {
4681 Interpolate => from.animate(&to, Procedure::Interpolate { progress }),
4682 Accumulate => from.animate(
4684 Procedure::Accumulate {
4685 count: progress as u64,
4690 let output = unsafe { output.as_mut() }.expect("not a valid 'output' matrix");
4691 if let Ok(result) = result {
4692 *output = result.into();
4693 } else if progress < 0.5 {
4694 *output = from.clone().into();
4696 *output = to.clone().into();
4701 pub unsafe extern "C" fn Servo_ParseStyleAttribute(
4703 raw_extra_data: *mut URLExtraData,
4704 quirks_mode: nsCompatibility,
4705 loader: *mut Loader,
4706 rule_type: CssRuleType,
4707 ) -> Strong<LockedDeclarationBlock> {
4708 let global_style_data = &*GLOBAL_STYLE_DATA;
4709 let value = data.as_str_unchecked();
4710 let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data);
4711 let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
4712 Arc::new(global_style_data.shared_lock.wrap(parse_style_attribute(
4715 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4723 pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> Strong<LockedDeclarationBlock> {
4724 let global_style_data = &*GLOBAL_STYLE_DATA;
4728 .wrap(PropertyDeclarationBlock::new()),
4734 pub extern "C" fn Servo_DeclarationBlock_Clear(declarations: &LockedDeclarationBlock) {
4735 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4741 pub extern "C" fn Servo_DeclarationBlock_Clone(
4742 declarations: &LockedDeclarationBlock,
4743 ) -> Strong<LockedDeclarationBlock> {
4744 let global_style_data = &*GLOBAL_STYLE_DATA;
4745 let guard = global_style_data.shared_lock.read();
4749 .wrap(declarations.read_with(&guard).clone()),
4755 pub extern "C" fn Servo_DeclarationBlock_Equals(
4756 a: &LockedDeclarationBlock,
4757 b: &LockedDeclarationBlock,
4759 let global_style_data = &*GLOBAL_STYLE_DATA;
4760 let guard = global_style_data.shared_lock.read();
4761 a.read_with(&guard).declarations() == b.read_with(&guard).declarations()
4765 pub extern "C" fn Servo_DeclarationBlock_GetCssText(
4766 declarations: &LockedDeclarationBlock,
4767 result: &mut nsACString,
4769 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4770 decls.to_css(result).unwrap()
4775 pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
4776 decls: &LockedDeclarationBlock,
4777 property_id: &structs::AnimatedPropertyID,
4778 buffer: &mut nsACString,
4779 computed_values: Option<&ComputedValues>,
4780 data: &PerDocumentStyleData,
4782 let property_id = get_property_id_from_animatedpropertyid!(property_id, ());
4784 let global_style_data = &*GLOBAL_STYLE_DATA;
4785 let guard = global_style_data.shared_lock.read();
4786 let data = data.borrow();
4787 let rv = decls.read_with(&guard).single_value_to_css(
4793 debug_assert!(rv.is_ok());
4797 pub unsafe extern "C" fn Servo_SerializeFontValueForCanvas(
4798 declarations: &LockedDeclarationBlock,
4799 buffer: &mut nsACString,
4801 use style::properties::shorthands::font;
4802 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4803 let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) {
4806 warn!("Unexpected property!");
4811 let rv = longhands.to_css(&mut CssWriter::new(buffer));
4812 debug_assert!(rv.is_ok());
4817 pub extern "C" fn Servo_DeclarationBlock_Count(declarations: &LockedDeclarationBlock) -> u32 {
4818 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4819 decls.declarations().len() as u32
4824 pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(
4825 declarations: &LockedDeclarationBlock,
4827 result: &mut nsACString,
4829 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4830 if let Some(decl) = decls.declarations().get(index as usize) {
4831 result.assign(&decl.id().name());
4839 macro_rules! get_property_id_from_property {
4840 ($property: ident, $ret: expr) => {{
4841 let property = $property.as_str_unchecked();
4842 match PropertyId::parse_enabled_for_all_content(property) {
4843 Ok(property_id) => property_id,
4844 Err(_) => return $ret,
4849 unsafe fn get_property_value(
4850 declarations: &LockedDeclarationBlock,
4851 property_id: PropertyId,
4852 value: &mut nsACString,
4854 // This callsite is hot enough that the lock acquisition shows up in profiles.
4855 // Using an unchecked read here improves our performance by ~10% on the
4856 // microbenchmark in bug 1355599.
4857 read_locked_arc_unchecked(declarations, |decls: &PropertyDeclarationBlock| {
4858 decls.property_value_to_css(&property_id, value).unwrap();
4863 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValue(
4864 declarations: &LockedDeclarationBlock,
4865 property: &nsACString,
4866 value: &mut nsACString,
4870 get_property_id_from_property!(property, ()),
4876 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(
4877 declarations: &LockedDeclarationBlock,
4878 property: nsCSSPropertyID,
4879 value: &mut nsACString,
4883 get_property_id_from_nscsspropertyid!(property, ()),
4889 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(
4890 declarations: &LockedDeclarationBlock,
4891 property: &nsACString,
4893 let property_id = get_property_id_from_property!(property, false);
4894 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4895 decls.property_priority(&property_id).important()
4900 fn set_property_to_declarations(
4901 non_custom_property_id: Option<NonCustomPropertyId>,
4902 block: &LockedDeclarationBlock,
4903 parsed_declarations: &mut SourcePropertyDeclaration,
4904 before_change_closure: DeclarationBlockMutationClosure,
4905 importance: Importance,
4907 let mut updates = Default::default();
4908 let will_change = read_locked_arc(block, |decls: &PropertyDeclarationBlock| {
4909 decls.prepare_for_update(&parsed_declarations, importance, &mut updates)
4915 before_change_closure.invoke(non_custom_property_id);
4916 write_locked_arc(block, |decls: &mut PropertyDeclarationBlock| {
4917 decls.update(parsed_declarations.drain(), importance, &mut updates)
4923 declarations: &LockedDeclarationBlock,
4924 property_id: PropertyId,
4927 data: &UrlExtraData,
4928 parsing_mode: ParsingMode,
4929 quirks_mode: QuirksMode,
4930 loader: *mut Loader,
4931 rule_type: CssRuleType,
4932 before_change_closure: DeclarationBlockMutationClosure,
4934 let mut source_declarations = SourcePropertyDeclaration::default();
4935 let reporter = ErrorReporter::new(ptr::null_mut(), loader, data.ptr());
4936 let non_custom_property_id = property_id.non_custom_id();
4937 let result = parse_property_into(
4938 &mut source_declarations,
4946 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4949 if result.is_err() {
4953 let importance = if is_important {
4954 Importance::Important
4959 set_property_to_declarations(
4960 non_custom_property_id,
4962 &mut source_declarations,
4963 before_change_closure,
4969 pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
4970 declarations: &LockedDeclarationBlock,
4971 property: &nsACString,
4974 data: *mut URLExtraData,
4975 parsing_mode: ParsingMode,
4976 quirks_mode: nsCompatibility,
4977 loader: *mut Loader,
4978 rule_type: CssRuleType,
4979 before_change_closure: DeclarationBlockMutationClosure,
4983 get_property_id_from_property!(property, false),
4986 UrlExtraData::from_ptr_ref(&data),
4991 before_change_closure,
4996 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
4997 declarations: &LockedDeclarationBlock,
4998 animation_value: &AnimationValue,
4999 before_change_closure: DeclarationBlockMutationClosure,
5001 let non_custom_property_id = match animation_value.id() {
5002 PropertyDeclarationId::Longhand(id) => Some(id.into()),
5003 PropertyDeclarationId::Custom(_) => None,
5005 let mut source_declarations = SourcePropertyDeclaration::with_one(animation_value.uncompute());
5007 set_property_to_declarations(
5008 non_custom_property_id,
5010 &mut source_declarations,
5011 before_change_closure,
5017 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
5018 declarations: &LockedDeclarationBlock,
5019 property: nsCSSPropertyID,
5022 data: *mut URLExtraData,
5023 parsing_mode: ParsingMode,
5024 quirks_mode: nsCompatibility,
5025 loader: *mut Loader,
5026 rule_type: CssRuleType,
5027 before_change_closure: DeclarationBlockMutationClosure,
5031 get_property_id_from_nscsspropertyid!(property, false),
5034 UrlExtraData::from_ptr_ref(&data),
5039 before_change_closure,
5044 declarations: &LockedDeclarationBlock,
5045 property_id: PropertyId,
5046 before_change_closure: DeclarationBlockMutationClosure,
5048 let first_declaration = read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
5049 decls.first_declaration_to_remove(&property_id)
5052 let first_declaration = match first_declaration {
5054 None => return false,
5057 before_change_closure.invoke(property_id.non_custom_id());
5058 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5059 decls.remove_property(&property_id, first_declaration)
5066 pub unsafe extern "C" fn Servo_DeclarationBlock_RemoveProperty(
5067 declarations: &LockedDeclarationBlock,
5068 property: &nsACString,
5069 before_change_closure: DeclarationBlockMutationClosure,
5073 get_property_id_from_property!(property, false),
5074 before_change_closure,
5079 pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(
5080 declarations: &LockedDeclarationBlock,
5081 property: nsCSSPropertyID,
5082 before_change_closure: DeclarationBlockMutationClosure,
5086 get_property_id_from_nscsspropertyid!(property, false),
5087 before_change_closure,
5092 pub extern "C" fn Servo_MediaList_Create() -> Strong<LockedMediaList> {
5093 let global_style_data = &*GLOBAL_STYLE_DATA;
5094 Arc::new(global_style_data.shared_lock.wrap(MediaList::empty())).into()
5098 pub extern "C" fn Servo_MediaList_DeepClone(list: &LockedMediaList) -> Strong<LockedMediaList> {
5099 let global_style_data = &*GLOBAL_STYLE_DATA;
5100 read_locked_arc(list, |list: &MediaList| {
5101 Arc::new(global_style_data.shared_lock.wrap(list.clone())).into()
5106 pub extern "C" fn Servo_MediaList_Matches(
5107 list: &LockedMediaList,
5108 raw_data: &PerDocumentStyleData,
5110 let per_doc_data = raw_data.borrow();
5111 read_locked_arc(list, |list: &MediaList| {
5113 per_doc_data.stylist.device(),
5114 per_doc_data.stylist.quirks_mode(),
5120 pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword(
5121 declarations: &LockedDeclarationBlock,
5122 property: nsCSSPropertyID,
5124 let property_id = get_property_id_from_nscsspropertyid!(property, false);
5125 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
5126 decls.has_css_wide_keyword(&property_id)
5131 pub extern "C" fn Servo_MediaList_GetText(list: &LockedMediaList, result: &mut nsACString) {
5132 read_locked_arc(list, |list: &MediaList| {
5133 list.to_css(&mut CssWriter::new(result)).unwrap();
5138 pub unsafe extern "C" fn Servo_MediaList_SetText(
5139 list: &LockedMediaList,
5141 caller_type: CallerType,
5143 let text = text.as_str_unchecked();
5145 let mut input = ParserInput::new(&text);
5146 let mut parser = Parser::new(&mut input);
5147 let url_data = dummy_url_data();
5149 // TODO(emilio): If the need for `CallerType` appears in more places,
5150 // consider adding an explicit member in `ParserContext` instead of doing
5151 // this (or adding a dummy "chrome://" url data).
5153 // For media query parsing it's effectively the same, so for now...
5154 let origin = match caller_type {
5155 CallerType::System => Origin::UserAgent,
5156 CallerType::NonSystem => Origin::Author,
5159 let context = ParserContext::new(
5162 Some(CssRuleType::Media),
5163 ParsingMode::DEFAULT,
5164 QuirksMode::NoQuirks,
5165 /* namespaces = */ Default::default(),
5166 // TODO(emilio): Looks like error reporting could be useful here?
5171 write_locked_arc(list, |list: &mut MediaList| {
5172 *list = MediaList::parse(&context, &mut parser);
5177 pub extern "C" fn Servo_MediaList_IsViewportDependent(list: &LockedMediaList) -> bool {
5178 read_locked_arc(list, |list: &MediaList| list.is_viewport_dependent())
5182 pub extern "C" fn Servo_MediaList_GetLength(list: &LockedMediaList) -> u32 {
5183 read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32)
5187 pub extern "C" fn Servo_MediaList_GetMediumAt(
5188 list: &LockedMediaList,
5190 result: &mut nsACString,
5192 read_locked_arc(list, |list: &MediaList| {
5193 let media_query = match list.media_queries.get(index as usize) {
5195 None => return false,
5197 media_query.to_css(&mut CssWriter::new(result)).unwrap();
5203 pub extern "C" fn Servo_MediaList_AppendMedium(list: &LockedMediaList, new_medium: &nsACString) {
5204 let new_medium = unsafe { new_medium.as_str_unchecked() };
5205 let url_data = unsafe { dummy_url_data() };
5206 let context = ParserContext::new(
5209 Some(CssRuleType::Media),
5210 ParsingMode::DEFAULT,
5211 QuirksMode::NoQuirks,
5212 /* namespaces = */ Default::default(),
5216 write_locked_arc(list, |list: &mut MediaList| {
5217 list.append_medium(&context, new_medium);
5222 pub extern "C" fn Servo_MediaList_DeleteMedium(
5223 list: &LockedMediaList,
5224 old_medium: &nsACString,
5226 let old_medium = unsafe { old_medium.as_str_unchecked() };
5227 let url_data = unsafe { dummy_url_data() };
5228 let context = ParserContext::new(
5231 Some(CssRuleType::Media),
5232 ParsingMode::DEFAULT,
5233 QuirksMode::NoQuirks,
5234 /* namespaces = */ Default::default(),
5238 write_locked_arc(list, |list: &mut MediaList| {
5239 list.delete_medium(&context, old_medium)
5244 pub extern "C" fn Servo_MediaList_SizeOfIncludingThis(
5245 malloc_size_of: GeckoMallocSizeOf,
5246 malloc_enclosing_size_of: GeckoMallocSizeOf,
5247 list: &LockedMediaList,
5249 use malloc_size_of::MallocSizeOf;
5250 use malloc_size_of::MallocUnconditionalShallowSizeOf;
5252 let global_style_data = &*GLOBAL_STYLE_DATA;
5253 let guard = global_style_data.shared_lock.read();
5255 let mut ops = MallocSizeOfOps::new(
5256 malloc_size_of.unwrap(),
5257 Some(malloc_enclosing_size_of.unwrap()),
5261 unsafe { ArcBorrow::from_ref(list) }.with_arc(|list| {
5263 n += list.unconditional_shallow_size_of(&mut ops);
5264 n += list.read_with(&guard).size_of(&mut ops);
5269 macro_rules! get_longhand_from_id {
5271 match LonghandId::from_nscsspropertyid($id) {
5273 _ => panic!("stylo: unknown presentation property with id"),
5278 macro_rules! match_wrap_declared {
5279 ($longhand:ident, $($property:ident => $inner:expr,)*) => (
5282 LonghandId::$property => PropertyDeclaration::$property($inner),
5285 panic!("stylo: Don't know how to handle presentation property");
5292 pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(
5293 declarations: &LockedDeclarationBlock,
5294 property: nsCSSPropertyID,
5296 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
5297 decls.contains(PropertyDeclarationId::Longhand(get_longhand_from_id!(
5304 pub unsafe extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(
5305 declarations: &LockedDeclarationBlock,
5306 property: nsCSSPropertyID,
5309 use style::properties::longhands::_x_lang::computed_value::T as Lang;
5310 use style::properties::PropertyDeclaration;
5312 let long = get_longhand_from_id!(property);
5313 let prop = match_wrap_declared! { long,
5314 XLang => Lang(Atom::from_raw(value)),
5316 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5317 decls.push(prop, Importance::Normal);
5322 #[allow(unreachable_code)]
5323 pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
5324 declarations: &LockedDeclarationBlock,
5325 property: nsCSSPropertyID,
5328 use num_traits::FromPrimitive;
5329 use style::properties::longhands;
5330 use style::properties::PropertyDeclaration;
5331 use style::values::generics::box_::{VerticalAlign, VerticalAlignKeyword};
5332 use style::values::generics::font::FontStyle;
5333 use style::values::specified::{
5334 table::CaptionSide, BorderStyle, Clear, Display, Float, TextAlign, TextEmphasisPosition,
5338 fn get_from_computed<T>(value: u32) -> T
5341 T::ComputedValue: FromPrimitive,
5343 T::from_computed_value(&T::ComputedValue::from_u32(value).unwrap())
5346 let long = get_longhand_from_id!(property);
5347 let value = value as u32;
5349 let prop = match_wrap_declared! { long,
5350 MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value),
5351 Direction => get_from_computed::<longhands::direction::SpecifiedValue>(value),
5352 Display => get_from_computed::<Display>(value),
5353 Float => get_from_computed::<Float>(value),
5354 Clear => get_from_computed::<Clear>(value),
5355 VerticalAlign => VerticalAlign::Keyword(VerticalAlignKeyword::from_u32(value).unwrap()),
5356 TextAlign => get_from_computed::<TextAlign>(value),
5357 TextEmphasisPosition => TextEmphasisPosition::from_bits_retain(value as u8),
5359 // We rely on Gecko passing in font-size values (0...7) here.
5360 longhands::font_size::SpecifiedValue::from_html_size(value as u8)
5363 style::values::specified::FontStyle::Specified(if value == structs::NS_FONT_STYLE_ITALIC {
5366 debug_assert_eq!(value, structs::NS_FONT_STYLE_NORMAL);
5370 FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value),
5371 ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
5372 MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value),
5373 MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
5374 WhiteSpaceCollapse => get_from_computed::<longhands::white_space_collapse::SpecifiedValue>(value),
5375 TextWrapMode => get_from_computed::<longhands::text_wrap_mode::SpecifiedValue>(value),
5376 CaptionSide => get_from_computed::<CaptionSide>(value),
5377 BorderTopStyle => get_from_computed::<BorderStyle>(value),
5378 BorderRightStyle => get_from_computed::<BorderStyle>(value),
5379 BorderBottomStyle => get_from_computed::<BorderStyle>(value),
5380 BorderLeftStyle => get_from_computed::<BorderStyle>(value),
5382 debug_assert_eq!(value, structs::StyleTextTransformCase_None as u32);
5383 TextTransform::none()
5386 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5387 decls.push(prop, Importance::Normal);
5392 pub extern "C" fn Servo_DeclarationBlock_SetIntValue(
5393 declarations: &LockedDeclarationBlock,
5394 property: nsCSSPropertyID,
5397 use style::properties::PropertyDeclaration;
5398 use style::values::specified::Integer;
5400 let long = get_longhand_from_id!(property);
5401 let prop = match_wrap_declared! { long,
5402 XSpan => Integer::new(value),
5404 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5405 decls.push(prop, Importance::Normal);
5410 pub extern "C" fn Servo_DeclarationBlock_SetMathDepthValue(
5411 declarations: &LockedDeclarationBlock,
5415 use style::properties::longhands::math_depth::SpecifiedValue as MathDepth;
5416 use style::properties::PropertyDeclaration;
5418 let integer_value = style::values::specified::Integer::new(value);
5419 let prop = PropertyDeclaration::MathDepth(if is_relative {
5420 MathDepth::Add(integer_value)
5422 MathDepth::Absolute(integer_value)
5424 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5425 decls.push(prop, Importance::Normal);
5430 pub extern "C" fn Servo_DeclarationBlock_SetCounterResetListItem(
5431 declarations: &LockedDeclarationBlock,
5435 use style::properties::PropertyDeclaration;
5436 use style::values::generics::counters::{CounterPair, CounterReset};
5438 let prop = PropertyDeclaration::CounterReset(CounterReset::new(vec![CounterPair {
5439 name: CustomIdent(atom!("list-item")),
5440 value: style::values::specified::Integer::new(counter_value),
5443 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5444 decls.push(prop, Importance::Normal);
5449 pub extern "C" fn Servo_DeclarationBlock_SetCounterSetListItem(
5450 declarations: &LockedDeclarationBlock,
5453 use style::properties::PropertyDeclaration;
5454 use style::values::generics::counters::{CounterPair, CounterSet};
5456 let prop = PropertyDeclaration::CounterSet(CounterSet::new(vec![CounterPair {
5457 name: CustomIdent(atom!("list-item")),
5458 value: style::values::specified::Integer::new(counter_value),
5461 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5462 decls.push(prop, Importance::Normal);
5467 pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
5468 declarations: &LockedDeclarationBlock,
5469 property: nsCSSPropertyID,
5472 use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
5473 use style::properties::PropertyDeclaration;
5474 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5475 use style::values::generics::NonNegative;
5476 use style::values::specified::length::{
5477 LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage,
5479 use style::values::specified::{BorderCornerRadius, BorderSideWidth};
5481 let long = get_longhand_from_id!(property);
5482 let nocalc = NoCalcLength::from_px(value);
5483 let lp = LengthPercentage::Length(nocalc);
5484 let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
5485 let prop = match_wrap_declared! { long,
5486 Height => Size::LengthPercentage(NonNegative(lp)),
5487 Width => Size::LengthPercentage(NonNegative(lp)),
5488 BorderTopWidth => BorderSideWidth::from_px(value),
5489 BorderRightWidth => BorderSideWidth::from_px(value),
5490 BorderBottomWidth => BorderSideWidth::from_px(value),
5491 BorderLeftWidth => BorderSideWidth::from_px(value),
5492 MarginTop => lp_or_auto,
5493 MarginRight => lp_or_auto,
5494 MarginBottom => lp_or_auto,
5495 MarginLeft => lp_or_auto,
5496 PaddingTop => NonNegative(lp),
5497 PaddingRight => NonNegative(lp),
5498 PaddingBottom => NonNegative(lp),
5499 PaddingLeft => NonNegative(lp),
5501 let v = NonNegativeLength::from(nocalc);
5502 Box::new(BorderSpacing::new(v.clone(), v))
5504 BorderTopLeftRadius => {
5505 let length = NonNegativeLengthPercentage::from(nocalc);
5506 Box::new(BorderCornerRadius::new(length.clone(), length))
5508 BorderTopRightRadius => {
5509 let length = NonNegativeLengthPercentage::from(nocalc);
5510 Box::new(BorderCornerRadius::new(length.clone(), length))
5512 BorderBottomLeftRadius => {
5513 let length = NonNegativeLengthPercentage::from(nocalc);
5514 Box::new(BorderCornerRadius::new(length.clone(), length))
5516 BorderBottomRightRadius => {
5517 let length = NonNegativeLengthPercentage::from(nocalc);
5518 Box::new(BorderCornerRadius::new(length.clone(), length))
5521 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5522 decls.push(prop, Importance::Normal);
5527 pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
5528 declarations: &LockedDeclarationBlock,
5529 property: nsCSSPropertyID,
5531 unit: structs::nsCSSUnit,
5533 use style::properties::PropertyDeclaration;
5534 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5535 use style::values::generics::NonNegative;
5536 use style::values::specified::length::{
5537 FontRelativeLength, LengthPercentage, ViewportPercentageLength,
5539 use style::values::specified::FontSize;
5541 let long = get_longhand_from_id!(property);
5542 let nocalc = match unit {
5543 structs::nsCSSUnit::eCSSUnit_EM => {
5544 NoCalcLength::FontRelative(FontRelativeLength::Em(value))
5546 structs::nsCSSUnit::eCSSUnit_XHeight => {
5547 NoCalcLength::FontRelative(FontRelativeLength::Ex(value))
5549 structs::nsCSSUnit::eCSSUnit_RootEM => {
5550 NoCalcLength::FontRelative(FontRelativeLength::Rem(value))
5552 structs::nsCSSUnit::eCSSUnit_Char => {
5553 NoCalcLength::FontRelative(FontRelativeLength::Ch(value))
5555 structs::nsCSSUnit::eCSSUnit_Ideographic => {
5556 NoCalcLength::FontRelative(FontRelativeLength::Ic(value))
5558 structs::nsCSSUnit::eCSSUnit_CapHeight => {
5559 NoCalcLength::FontRelative(FontRelativeLength::Cap(value))
5561 structs::nsCSSUnit::eCSSUnit_Pixel => NoCalcLength::Absolute(AbsoluteLength::Px(value)),
5562 structs::nsCSSUnit::eCSSUnit_Inch => NoCalcLength::Absolute(AbsoluteLength::In(value)),
5563 structs::nsCSSUnit::eCSSUnit_Centimeter => {
5564 NoCalcLength::Absolute(AbsoluteLength::Cm(value))
5566 structs::nsCSSUnit::eCSSUnit_Millimeter => {
5567 NoCalcLength::Absolute(AbsoluteLength::Mm(value))
5569 structs::nsCSSUnit::eCSSUnit_Point => NoCalcLength::Absolute(AbsoluteLength::Pt(value)),
5570 structs::nsCSSUnit::eCSSUnit_Pica => NoCalcLength::Absolute(AbsoluteLength::Pc(value)),
5571 structs::nsCSSUnit::eCSSUnit_Quarter => NoCalcLength::Absolute(AbsoluteLength::Q(value)),
5572 structs::nsCSSUnit::eCSSUnit_VW => {
5573 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(value))
5575 structs::nsCSSUnit::eCSSUnit_VH => {
5576 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vh(value))
5578 structs::nsCSSUnit::eCSSUnit_VMin => {
5579 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmin(value))
5581 structs::nsCSSUnit::eCSSUnit_VMax => {
5582 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmax(value))
5584 _ => unreachable!("Unknown unit passed to SetLengthValue"),
5587 let prop = match_wrap_declared! { long,
5588 Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5589 Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5590 X => LengthPercentage::Length(nocalc),
5591 Y => LengthPercentage::Length(nocalc),
5592 Cx => LengthPercentage::Length(nocalc),
5593 Cy => LengthPercentage::Length(nocalc),
5594 R => NonNegative(LengthPercentage::Length(nocalc)),
5595 Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5596 Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5597 FontSize => FontSize::Length(LengthPercentage::Length(nocalc)),
5599 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5600 decls.push(prop, Importance::Normal);
5605 pub extern "C" fn Servo_DeclarationBlock_SetPathValue(
5606 declarations: &LockedDeclarationBlock,
5607 property: nsCSSPropertyID,
5608 path: &nsTArray<f32>,
5610 use style::properties::PropertyDeclaration;
5611 use style::values::specified::DProperty;
5613 // 1. Decode the path data from SVG.
5614 let path = match specified::SVGPathData::decode_from_f32_array(path) {
5619 // 2. Set decoded path into style.
5620 let long = get_longhand_from_id!(property);
5621 let prop = match_wrap_declared! { long,
5622 D => if path.0.is_empty() { DProperty::None } else { DProperty::Path(path) },
5624 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5625 decls.push(prop, Importance::Normal);
5630 pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
5631 declarations: &LockedDeclarationBlock,
5632 property: nsCSSPropertyID,
5635 use style::properties::PropertyDeclaration;
5636 use style::values::computed::Percentage;
5637 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5638 use style::values::generics::NonNegative;
5639 use style::values::specified::length::LengthPercentage;
5640 use style::values::specified::FontSize;
5642 let long = get_longhand_from_id!(property);
5643 let pc = Percentage(value);
5644 let lp = LengthPercentage::Percentage(pc);
5645 let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
5647 let prop = match_wrap_declared! { long,
5648 Height => Size::LengthPercentage(NonNegative(lp)),
5649 Width => Size::LengthPercentage(NonNegative(lp)),
5654 R => NonNegative(lp),
5655 Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5656 Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5657 MarginTop => lp_or_auto,
5658 MarginRight => lp_or_auto,
5659 MarginBottom => lp_or_auto,
5660 MarginLeft => lp_or_auto,
5661 FontSize => FontSize::Length(LengthPercentage::Percentage(pc)),
5663 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5664 decls.push(prop, Importance::Normal);
5669 pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(
5670 declarations: &LockedDeclarationBlock,
5671 property: nsCSSPropertyID,
5673 use style::properties::PropertyDeclaration;
5674 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5676 let long = get_longhand_from_id!(property);
5677 let auto = LengthPercentageOrAuto::Auto;
5679 let prop = match_wrap_declared! { long,
5680 Height => Size::auto(),
5681 Width => Size::auto(),
5683 MarginRight => auto,
5684 MarginBottom => auto,
5686 AspectRatio => specified::AspectRatio::auto(),
5688 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5689 decls.push(prop, Importance::Normal);
5694 pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(
5695 declarations: &LockedDeclarationBlock,
5696 property: nsCSSPropertyID,
5698 use style::properties::PropertyDeclaration;
5699 use style::values::specified::Color;
5701 let long = get_longhand_from_id!(property);
5702 let cc = Color::currentcolor();
5704 let prop = match_wrap_declared! { long,
5705 BorderTopColor => cc,
5706 BorderRightColor => cc,
5707 BorderBottomColor => cc,
5708 BorderLeftColor => cc,
5710 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5711 decls.push(prop, Importance::Normal);
5716 pub extern "C" fn Servo_DeclarationBlock_SetColorValue(
5717 declarations: &LockedDeclarationBlock,
5718 property: nsCSSPropertyID,
5719 value: structs::nscolor,
5721 use style::gecko::values::convert_nscolor_to_absolute_color;
5722 use style::properties::longhands;
5723 use style::properties::PropertyDeclaration;
5724 use style::values::specified::Color;
5726 let long = get_longhand_from_id!(property);
5727 let rgba = convert_nscolor_to_absolute_color(value);
5728 let color = Color::from_absolute_color(rgba);
5730 let prop = match_wrap_declared! { long,
5731 BorderTopColor => color,
5732 BorderRightColor => color,
5733 BorderBottomColor => color,
5734 BorderLeftColor => color,
5735 Color => longhands::color::SpecifiedValue(color),
5736 BackgroundColor => color,
5738 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5739 decls.push(prop, Importance::Normal);
5744 pub unsafe extern "C" fn Servo_DeclarationBlock_SetFontFamily(
5745 declarations: &LockedDeclarationBlock,
5748 use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
5749 use style::properties::PropertyDeclaration;
5751 let string = value.as_str_unchecked();
5752 let mut input = ParserInput::new(&string);
5753 let mut parser = Parser::new(&mut input);
5754 let context = ParserContext::new(
5757 Some(CssRuleType::Style),
5758 ParsingMode::DEFAULT,
5759 QuirksMode::NoQuirks,
5760 /* namespaces = */ Default::default(),
5764 let result = FontFamily::parse(&context, &mut parser);
5765 if let Ok(family) = result {
5766 if parser.is_exhausted() {
5767 let decl = PropertyDeclaration::FontFamily(family);
5768 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5769 decls.push(decl, Importance::Normal);
5776 pub unsafe extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(
5777 declarations: &LockedDeclarationBlock,
5779 raw_extra_data: *mut URLExtraData,
5781 use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
5782 use style::properties::PropertyDeclaration;
5783 use style::stylesheets::CorsMode;
5784 use style::values::generics::image::Image;
5785 use style::values::specified::url::SpecifiedImageUrl;
5787 let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
5788 let string = value.as_str_unchecked();
5789 let context = ParserContext::new(
5792 Some(CssRuleType::Style),
5793 ParsingMode::DEFAULT,
5794 QuirksMode::NoQuirks,
5795 /* namespaces = */ Default::default(),
5799 let url = SpecifiedImageUrl::parse_from_string(string.into(), &context, CorsMode::None);
5800 let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(vec![Image::Url(url)].into()));
5801 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5802 decls.push(decl, Importance::Normal);
5807 pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(
5808 declarations: &LockedDeclarationBlock,
5810 use style::properties::PropertyDeclaration;
5811 use style::values::specified::text::TextDecorationLine;
5813 let decoration = TextDecorationLine::COLOR_OVERRIDE;
5814 let decl = PropertyDeclaration::TextDecorationLine(decoration);
5815 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5816 decls.push(decl, Importance::Normal);
5821 pub extern "C" fn Servo_DeclarationBlock_SetAspectRatio(
5822 declarations: &LockedDeclarationBlock,
5826 use style::properties::PropertyDeclaration;
5827 use style::values::generics::position::AspectRatio;
5829 let decl = PropertyDeclaration::AspectRatio(AspectRatio::from_mapped_ratio(width, height));
5830 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5831 decls.push(decl, Importance::Normal);
5836 pub extern "C" fn Servo_CSSSupports2(property: &nsACString, value: &nsACString) -> bool {
5837 let id = unsafe { get_property_id_from_property!(property, false) };
5839 let mut declarations = SourcePropertyDeclaration::default();
5840 parse_property_into(
5845 unsafe { dummy_url_data() },
5846 ParsingMode::DEFAULT,
5847 QuirksMode::NoQuirks,
5855 pub extern "C" fn Servo_CSSSupports(
5861 let condition = unsafe { cond.as_str_unchecked() };
5862 let mut input = ParserInput::new(&condition);
5863 let mut input = Parser::new(&mut input);
5864 let cond = match input.parse_entirely(parse_condition_or_declaration) {
5866 Err(..) => return false,
5869 let origin = if ua_origin {
5874 let url_data = unsafe {
5876 dummy_chrome_url_data()
5881 let quirks_mode = if quirks {
5884 QuirksMode::NoQuirks
5887 // NOTE(emilio): The supports API is not associated to any stylesheet,
5888 // so the fact that there is no namespace map here is fine.
5889 let context = ParserContext::new(
5892 Some(CssRuleType::Style),
5893 ParsingMode::DEFAULT,
5895 /* namespaces = */ Default::default(),
5904 pub extern "C" fn Servo_CSSSupportsForImport(after_rule: &nsACString) -> bool {
5905 let condition = unsafe { after_rule.as_str_unchecked() };
5906 let mut input = ParserInput::new(&condition);
5907 let mut input = Parser::new(&mut input);
5909 // NOTE(emilio): The supports API is not associated to any stylesheet,
5910 // so the fact that there is no namespace map here is fine.
5911 let mut context = ParserContext::new(
5913 unsafe { dummy_url_data() },
5914 Some(CssRuleType::Style),
5915 ParsingMode::DEFAULT,
5916 QuirksMode::NoQuirks,
5917 /* namespaces = */ Default::default(),
5922 let (_layer, supports) = ImportRule::parse_layer_and_supports(&mut input, &mut context);
5924 supports.map_or(true, |s| s.enabled)
5928 pub unsafe extern "C" fn Servo_NoteExplicitHints(
5929 element: &RawGeckoElement,
5930 restyle_hint: RestyleHint,
5931 change_hint: nsChangeHint,
5933 GeckoElement(element).note_explicit_hints(restyle_hint, change_hint);
5937 pub extern "C" fn Servo_TakeChangeHint(element: &RawGeckoElement, was_restyled: &mut bool) -> u32 {
5938 let element = GeckoElement(element);
5940 let damage = match element.mutate_data() {
5942 *was_restyled = data.is_restyle();
5944 let damage = data.damage;
5945 data.clear_restyle_state();
5949 warn!("Trying to get change hint from unstyled element");
5950 *was_restyled = false;
5951 GeckoRestyleDamage::empty()
5955 debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
5956 // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
5957 // work as return values with the Linux 32-bit ABI at the moment because
5958 // they wrap the value in a struct, so for now just unwrap it.
5959 damage.as_change_hint().0
5963 pub extern "C" fn Servo_ResolveStyle(element: &RawGeckoElement) -> Strong<ComputedValues> {
5964 let element = GeckoElement(element);
5965 debug!("Servo_ResolveStyle: {:?}", element);
5968 .expect("Resolving style on unstyled element");
5971 element.has_current_styles(&*data),
5972 "Resolving style on {:?} without current styles: {:?}",
5976 data.styles.primary().clone().into()
5980 pub extern "C" fn Servo_ResolveStyleLazily(
5981 element: &RawGeckoElement,
5982 pseudo_type: PseudoStyleType,
5983 functional_pseudo_parameter: *mut nsAtom,
5984 rule_inclusion: StyleRuleInclusion,
5985 snapshots: *const ServoElementSnapshotTable,
5986 cache_generation: u64,
5987 can_use_cache: bool,
5988 raw_data: &PerDocumentStyleData,
5989 ) -> Strong<ComputedValues> {
5990 debug_assert!(!snapshots.is_null());
5991 let global_style_data = &*GLOBAL_STYLE_DATA;
5992 let guard = global_style_data.shared_lock.read();
5993 let element = GeckoElement(element);
5994 let mut data = raw_data.borrow_mut();
5995 let data = &mut *data;
5996 let rule_inclusion = RuleInclusion::from(rule_inclusion);
5997 let pseudo_element = PseudoElement::from_pseudo_type(
5999 get_functional_pseudo_parameter_atom(functional_pseudo_parameter),
6002 let matching_fn = |pseudo: &PseudoElement| match pseudo_element {
6003 Some(ref p) => *pseudo == *p,
6007 if cache_generation != data.undisplayed_style_cache_generation {
6008 data.undisplayed_style_cache.clear();
6009 data.undisplayed_style_cache_generation = cache_generation;
6012 let stylist = &data.stylist;
6013 let finish = |styles: &ElementStyles, is_probe: bool| -> Option<Arc<ComputedValues>> {
6014 match pseudo_element {
6015 Some(ref pseudo) => {
6022 /* inherited_styles = */ None,
6025 if pseudo.is_highlight() {
6032 None => Some(styles.primary().clone()),
6036 let is_before_or_after = pseudo_element
6038 .map_or(false, |p| p.is_before_or_after());
6040 // In the common case we already have the style. Check that before setting
6041 // up all the computation machinery.
6043 // Also, only probe in the ::before or ::after case, since their styles may
6044 // not be in the `ElementData`, given they may exist but not be applicable
6045 // to generate an actual pseudo-element (like, having a `content: none`).
6046 if rule_inclusion == RuleInclusion::All {
6047 let styles = element.borrow_data().and_then(|d| {
6049 finish(&d.styles, is_before_or_after)
6054 if let Some(result) = styles {
6055 return result.into();
6057 if pseudo_element.is_none() && can_use_cache {
6058 if let Some(style) = data.undisplayed_style_cache.get(&element.opaque()) {
6059 return style.clone().into();
6064 // We don't have the style ready. Go ahead and compute it as necessary.
6065 let shared = create_shared_context(
6069 TraversalFlags::empty(),
6070 unsafe { &*snapshots },
6072 let mut tlc = ThreadLocalStyleContext::new();
6073 let mut context = StyleContext {
6075 thread_local: &mut tlc,
6078 let styles = resolve_style(
6082 pseudo_element.as_ref(),
6084 Some(&mut data.undisplayed_style_cache)
6090 finish(&styles, /* is_probe = */ false)
6091 .expect("We're not probing, so we should always get a style back")
6096 pub extern "C" fn Servo_ReparentStyle(
6097 style_to_reparent: &ComputedValues,
6098 parent_style: &ComputedValues,
6099 layout_parent_style: &ComputedValues,
6100 element: Option<&RawGeckoElement>,
6101 raw_data: &PerDocumentStyleData,
6102 ) -> Strong<ComputedValues> {
6103 use style::properties::FirstLineReparenting;
6105 let global_style_data = &*GLOBAL_STYLE_DATA;
6106 let guard = global_style_data.shared_lock.read();
6107 let doc_data = raw_data.borrow();
6108 let inputs = CascadeInputs::new_from_style(style_to_reparent);
6109 let pseudo = style_to_reparent.pseudo();
6110 let element = element.map(GeckoElement);
6114 .cascade_style_and_visited(
6118 &StylesheetGuards::same(&guard),
6120 Some(layout_parent_style),
6121 FirstLineReparenting::Yes { style_to_reparent },
6122 /* rule_cache = */ None,
6123 &mut RuleCacheConditions::default(),
6128 #[cfg(feature = "gecko_debug")]
6129 fn simulate_compute_values_failure(property: &PropertyValuePair) -> bool {
6130 let p = &property.mProperty;
6131 let id = get_property_id_from_animatedpropertyid!(p, false);
6132 id.as_shorthand().is_ok() && property.mSimulateComputeValuesFailure
6135 #[cfg(not(feature = "gecko_debug"))]
6136 fn simulate_compute_values_failure(_: &PropertyValuePair) -> bool {
6140 fn create_context_for_animation<'a>(
6141 per_doc_data: &'a PerDocumentStyleDataImpl,
6142 style: &'a ComputedValues,
6143 parent_style: Option<&'a ComputedValues>,
6144 for_smil_animation: bool,
6145 rule_cache_conditions: &'a mut RuleCacheConditions,
6146 container_size_query: ContainerSizeQuery<'a>,
6148 Context::new_for_animation(
6149 StyleBuilder::for_animation(
6150 per_doc_data.stylist.device(),
6151 Some(&per_doc_data.stylist),
6156 per_doc_data.stylist.quirks_mode(),
6157 rule_cache_conditions,
6158 container_size_query,
6162 struct PropertyAndIndex {
6163 property: PropertyId,
6167 struct PrioritizedPropertyIter<'a> {
6168 properties: &'a [PropertyValuePair],
6169 sorted_property_indices: Vec<PropertyAndIndex>,
6173 impl<'a> PrioritizedPropertyIter<'a> {
6174 fn new(properties: &'a [PropertyValuePair]) -> PrioritizedPropertyIter {
6175 use style::values::animated::compare_property_priority;
6177 // If we fail to convert a nsCSSPropertyID into a PropertyId we
6178 // shouldn't fail outright but instead by treating that property as the
6179 // 'all' property we make it sort last.
6180 let mut sorted_property_indices: Vec<PropertyAndIndex> = properties
6183 .map(|(index, pair)| {
6184 let property = PropertyId::from_gecko_animated_property_id(&pair.mProperty)
6185 .unwrap_or(PropertyId::NonCustom(ShorthandId::All.into()));
6186 PropertyAndIndex { property, index }
6189 sorted_property_indices.sort_by(|a, b| compare_property_priority(&a.property, &b.property));
6191 PrioritizedPropertyIter {
6193 sorted_property_indices,
6198 fn reset(&mut self) {
6203 impl<'a> Iterator for PrioritizedPropertyIter<'a> {
6204 type Item = &'a PropertyValuePair;
6206 fn next(&mut self) -> Option<&'a PropertyValuePair> {
6207 if self.curr >= self.sorted_property_indices.len() {
6211 Some(&self.properties[self.sorted_property_indices[self.curr - 1].index])
6216 pub extern "C" fn Servo_GetComputedKeyframeValues(
6217 keyframes: &nsTArray<structs::Keyframe>,
6218 element: &RawGeckoElement,
6219 pseudo_type: PseudoStyleType,
6220 style: &ComputedValues,
6221 raw_data: &PerDocumentStyleData,
6222 computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>,
6224 use style::applicable_declarations::CascadePriority;
6225 use style::custom_properties::CustomPropertiesBuilder;
6226 use style::properties::PropertyDeclaration;
6227 let data = raw_data.borrow();
6228 let element = GeckoElement(element);
6229 let pseudo = PseudoElement::from_pseudo_type(pseudo_type, None);
6230 let parent_element = if pseudo.is_none() {
6231 element.inheritance_parent()
6235 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6236 let parent_style = parent_data
6238 .map(|d| d.styles.primary())
6241 let container_size_query =
6242 ContainerSizeQuery::for_element(element, parent_style, pseudo.is_some());
6243 let mut conditions = Default::default();
6244 let mut context = create_context_for_animation(
6248 /* for_smil_animation = */ false,
6250 container_size_query,
6253 let restriction = pseudo.and_then(|p| p.property_restriction());
6255 let global_style_data = &*GLOBAL_STYLE_DATA;
6256 let guard = global_style_data.shared_lock.read();
6257 let default_values = data.default_computed_values();
6259 for (index, keyframe) in keyframes.iter().enumerate() {
6260 let ref mut animation_values = computed_keyframes[index];
6262 let mut seen = PropertyDeclarationIdSet::default();
6263 let mut iter = PrioritizedPropertyIter::new(&keyframe.mPropertyValues);
6265 // FIXME (bug 1883255): This is pretty much a hack. Instead, the AnimatedValue should be
6266 // better integrated in the cascade.
6268 let mut builder = CustomPropertiesBuilder::new_with_properties(
6270 style.custom_properties().clone(),
6273 let priority = CascadePriority::same_tree_author_normal_at_root_layer();
6274 for property in &mut iter {
6276 match PropertyId::from_gecko_animated_property_id(&property.mProperty) {
6277 Some(PropertyId::Custom(..)) => true,
6281 break; // Custom props are guaranteed to sort earlier.
6283 if property.mServoDeclarationBlock.mRawPtr.is_null() {
6286 let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr };
6287 let guard = declarations.read_with(&guard);
6288 for decl in guard.normal_declaration_iter() {
6289 if let PropertyDeclaration::Custom(ref declaration) = *decl {
6290 builder.cascade(declaration, priority);
6295 let _deferred = builder.build(DeferFontRelativeCustomPropertyResolution::No);
6297 _deferred.is_none(),
6298 "Custom property processing deferred despite specifying otherwise?"
6302 let mut property_index = 0;
6303 for property in iter {
6304 if simulate_compute_values_failure(property) {
6308 let mut maybe_append_animation_value =
6309 |property: PropertyDeclarationId, value: Option<AnimationValue>| {
6310 debug_assert!(!property.is_logical());
6311 debug_assert!(property.is_animatable());
6313 // 'display' is only animatable from SMIL
6314 if property == PropertyDeclarationId::Longhand(LonghandId::Display) {
6318 // Skip restricted properties
6319 if restriction.map_or(false, |r| !property.flags().contains(r)) {
6323 if seen.contains(property) {
6326 seen.insert(property);
6328 // This is safe since we immediately write to the uninitialized values.
6330 animation_values.set_len((property_index + 1) as u32);
6332 &mut animation_values[property_index],
6333 structs::PropertyStyleAnimationValuePair {
6335 .to_gecko_animated_property_id(/* owned = */ true),
6336 mValue: structs::AnimationValue {
6337 mServo: value.map_or(structs::RefPtr::null(), |v| {
6338 structs::RefPtr::from_arc(Arc::new(v))
6344 property_index += 1;
6347 if property.mServoDeclarationBlock.mRawPtr.is_null() {
6349 OwnedPropertyDeclarationId::from_gecko_animated_property_id(&property.mProperty)
6351 maybe_append_animation_value(prop.as_borrowed(), None);
6356 let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr };
6357 let guard = declarations.read_with(&guard);
6358 let iter = guard.to_animation_value_iter(&mut context, &default_values);
6361 maybe_append_animation_value(value.id(), Some(value.clone()));
6368 pub extern "C" fn Servo_GetAnimationValues(
6369 declarations: &LockedDeclarationBlock,
6370 element: &RawGeckoElement,
6371 style: &ComputedValues,
6372 raw_data: &PerDocumentStyleData,
6373 animation_values: &mut ThinVec<structs::RefPtr<AnimationValue>>,
6375 let data = raw_data.borrow();
6376 let element = GeckoElement(element);
6377 let parent_element = element.inheritance_parent();
6378 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6379 let parent_style = parent_data
6381 .map(|d| d.styles.primary())
6384 let container_size_query =
6385 ContainerSizeQuery::for_element(element, None, /* is_pseudo = */ false);
6386 let mut conditions = Default::default();
6387 let mut context = create_context_for_animation(
6391 /* for_smil_animation = */ true,
6393 container_size_query,
6396 let default_values = data.default_computed_values();
6397 let global_style_data = &*GLOBAL_STYLE_DATA;
6398 let guard = global_style_data.shared_lock.read();
6400 let guard = declarations.read_with(&guard);
6401 let iter = guard.to_animation_value_iter(&mut context, &default_values);
6402 animation_values.extend(iter.map(|v| structs::RefPtr::from_arc(Arc::new(v))));
6406 pub extern "C" fn Servo_AnimationValue_GetPropertyId(
6407 value: &AnimationValue,
6408 property_id: &mut structs::AnimatedPropertyID,
6410 *property_id = value.id().to_gecko_animated_property_id(/* owned = */ true);
6414 pub extern "C" fn Servo_AnimationValue_Compute(
6415 element: &RawGeckoElement,
6416 declarations: &LockedDeclarationBlock,
6417 style: &ComputedValues,
6418 raw_data: &PerDocumentStyleData,
6419 ) -> Strong<AnimationValue> {
6420 let data = raw_data.borrow();
6422 let element = GeckoElement(element);
6423 let parent_element = element.inheritance_parent();
6424 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6425 let parent_style = parent_data
6427 .map(|d| d.styles.primary())
6430 let container_size_query =
6431 ContainerSizeQuery::for_element(element, None, /* is_pseudo = */ false);
6432 let mut conditions = Default::default();
6433 let mut context = create_context_for_animation(
6437 /* for_smil_animation = */ false,
6439 container_size_query,
6442 let default_values = data.default_computed_values();
6443 let global_style_data = &*GLOBAL_STYLE_DATA;
6444 let guard = global_style_data.shared_lock.read();
6445 // We only compute the first element in declarations.
6448 .declaration_importance_iter()
6451 Some((decl, imp)) if imp == Importance::Normal => {
6452 let animation = AnimationValue::from_declaration(decl, &mut context, default_values);
6453 animation.map_or(Strong::null(), |value| Arc::new(value).into())
6455 _ => Strong::null(),
6460 pub extern "C" fn Servo_AssertTreeIsClean(root: &RawGeckoElement) {
6461 if !cfg!(feature = "gecko_debug") {
6462 panic!("Calling Servo_AssertTreeIsClean in release build");
6465 let root = GeckoElement(root);
6466 debug!("Servo_AssertTreeIsClean: ");
6467 debug!("{:?}", ShowSubtreeData(root.as_node()));
6469 fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) {
6471 !el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants(),
6472 "{:?} has still dirty bit {:?} or animation-only dirty bit {:?}",
6474 el.has_dirty_descendants(),
6475 el.has_animation_only_dirty_descendants()
6477 for child in el.traversal_children() {
6478 if let Some(child) = child.as_element() {
6479 assert_subtree_is_clean(child);
6484 assert_subtree_is_clean(root);
6488 pub extern "C" fn Servo_IsWorkerThread() -> bool {
6489 thread_state::get().is_worker()
6497 fn fill_in_missing_keyframe_values(
6498 all_properties: &PropertyDeclarationIdSet,
6499 timing_function: &ComputedTimingFunction,
6500 properties_at_offset: &PropertyDeclarationIdSet,
6502 keyframes: &mut nsTArray<structs::Keyframe>,
6504 // Return early if all animated properties are already set.
6505 if properties_at_offset.contains_all(all_properties) {
6509 // Use auto for missing keyframes.
6510 // FIXME: This may be a spec issue in css-animations-2 because the spec says the default
6511 // keyframe-specific composite is replace, but web-animations-1 uses auto. Use auto now so we
6512 // use the value of animation-composition of the element, for missing keyframes.
6513 // https://github.com/w3c/csswg-drafts/issues/7476
6514 let composition = structs::CompositeOperationOrAuto::Auto;
6515 let keyframe = match offset {
6516 Offset::Zero => unsafe {
6517 Gecko_GetOrCreateInitialKeyframe(keyframes, timing_function, composition)
6519 Offset::One => unsafe {
6520 Gecko_GetOrCreateFinalKeyframe(keyframes, timing_function, composition)
6524 // Append properties that have not been set at this offset.
6525 for property in all_properties.iter() {
6526 if !properties_at_offset.contains(property) {
6528 Gecko_AppendPropertyValuePair(
6529 &mut *(*keyframe).mPropertyValues,
6530 &property.to_gecko_animated_property_id(/* owned = */ false),
6538 pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
6539 raw_data: &PerDocumentStyleData,
6540 element: &RawGeckoElement,
6541 style: &ComputedValues,
6543 inherited_timing_function: &ComputedTimingFunction,
6544 keyframes: &mut nsTArray<structs::Keyframe>,
6546 use style::gecko_bindings::structs::CompositeOperationOrAuto;
6547 use style::values::computed::AnimationComposition;
6549 debug_assert!(keyframes.len() == 0, "keyframes should be initially empty");
6551 let element = GeckoElement(element);
6552 let data = raw_data.borrow();
6553 let name = Atom::from_raw(name);
6555 let animation = match data.stylist.get_animation(&name, element) {
6556 Some(animation) => animation,
6557 None => return false,
6560 let global_style_data = &*GLOBAL_STYLE_DATA;
6561 let guard = global_style_data.shared_lock.read();
6563 let mut properties_set_at_current_offset = PropertyDeclarationIdSet::default();
6564 let mut properties_set_at_start = PropertyDeclarationIdSet::default();
6565 let mut properties_set_at_end = PropertyDeclarationIdSet::default();
6566 let mut has_complete_initial_keyframe = false;
6567 let mut has_complete_final_keyframe = false;
6568 let mut current_offset = -1.;
6570 let writing_mode = style.writing_mode;
6572 // Iterate over the keyframe rules backwards so we can drop overridden
6573 // properties (since declarations in later rules override those in earlier
6575 for step in animation.steps.iter().rev() {
6576 if step.start_percentage.0 != current_offset {
6577 properties_set_at_current_offset.clear();
6578 current_offset = step.start_percentage.0;
6581 // Override timing_function if the keyframe has an animation-timing-function.
6582 let timing_function = match step.get_animation_timing_function(&guard) {
6583 Some(val) => val.to_computed_value_without_context(),
6584 None => (*inherited_timing_function).clone(),
6587 // Override composite operation if the keyframe has an animation-composition.
6589 step.get_animation_composition(&guard)
6590 .map_or(CompositeOperationOrAuto::Auto, |val| match val {
6591 AnimationComposition::Replace => CompositeOperationOrAuto::Replace,
6592 AnimationComposition::Add => CompositeOperationOrAuto::Add,
6593 AnimationComposition::Accumulate => CompositeOperationOrAuto::Accumulate,
6596 // Look for an existing keyframe with the same offset, timing function, and compsition, or
6597 // else add a new keyframe at the beginning of the keyframe array.
6598 let keyframe = Gecko_GetOrCreateKeyframeAtStart(
6600 step.start_percentage.0 as f32,
6606 KeyframesStepValue::ComputedValues => {
6607 // In KeyframesAnimation::from_keyframes if there is no 0% or
6608 // 100% keyframe at all, we will create a 'ComputedValues' step
6609 // to represent that all properties animated by the keyframes
6610 // animation should be set to the underlying computed value for
6612 let mut seen = PropertyDeclarationIdSet::default();
6613 for property in animation.properties_changed.iter() {
6614 let property = property.to_physical(writing_mode);
6615 if seen.contains(property) {
6618 seen.insert(property);
6620 Gecko_AppendPropertyValuePair(
6621 &mut *(*keyframe).mPropertyValues,
6622 &property.to_gecko_animated_property_id(/* owned = */ false),
6625 if current_offset == 0.0 {
6626 has_complete_initial_keyframe = true;
6627 } else if current_offset == 1.0 {
6628 has_complete_final_keyframe = true;
6631 KeyframesStepValue::Declarations { ref block } => {
6632 let guard = block.read_with(&guard);
6634 // Filter out non-animatable properties and properties with
6637 // Also, iterate in reverse to respect the source order in case
6638 // there are logical and physical longhands in the same block.
6639 for declaration in guard.normal_declaration_iter().rev() {
6640 let id = declaration.id().to_physical(writing_mode);
6642 // Skip non-animatable properties, including the 'display' property because
6643 // although it is animatable from SMIL, it should not be animatable from CSS
6645 if !id.is_animatable() ||
6646 id == PropertyDeclarationId::Longhand(LonghandId::Display)
6651 if properties_set_at_current_offset.contains(id) {
6655 let pair = Gecko_AppendPropertyValuePair(
6656 &mut *(*keyframe).mPropertyValues,
6657 &id.to_gecko_animated_property_id(/* owned = */ false),
6660 (*pair).mServoDeclarationBlock.set_arc(Arc::new(
6663 .wrap(PropertyDeclarationBlock::with_one(
6664 declaration.to_physical(writing_mode),
6669 if current_offset == 0.0 {
6670 properties_set_at_start.insert(id);
6671 } else if current_offset == 1.0 {
6672 properties_set_at_end.insert(id);
6674 properties_set_at_current_offset.insert(id);
6680 let mut properties_changed = PropertyDeclarationIdSet::default();
6681 for property in animation.properties_changed.iter() {
6682 properties_changed.insert(property.to_physical(writing_mode));
6685 // Append property values that are missing in the initial or the final keyframes.
6686 if !has_complete_initial_keyframe {
6687 fill_in_missing_keyframe_values(
6688 &properties_changed,
6689 inherited_timing_function,
6690 &properties_set_at_start,
6695 if !has_complete_final_keyframe {
6696 fill_in_missing_keyframe_values(
6697 &properties_changed,
6698 inherited_timing_function,
6699 &properties_set_at_end,
6708 pub extern "C" fn Servo_StyleSet_GetFontFaceRules(
6709 raw_data: &PerDocumentStyleData,
6710 rules: &mut ThinVec<structs::nsFontFaceRuleContainer>,
6712 let data = raw_data.borrow();
6713 debug_assert_eq!(rules.len(), 0);
6715 // Reversed iterator because Gecko expects rules to appear sorted
6716 // UserAgent first, Author last.
6717 let font_face_iter = data
6719 .iter_extra_data_origins_rev()
6720 .flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o)));
6722 rules.extend(font_face_iter.map(|(&(ref rule, _layer_id), origin)| {
6723 structs::nsFontFaceRuleContainer {
6724 mRule: structs::RefPtr::from_arc(rule.clone()),
6730 // XXX Ideally this should return a Option<&LockedCounterStyleRule>,
6731 // but we cannot, because the value from AtomicRefCell::borrow() can only
6732 // live in this function, and thus anything derived from it cannot get the
6733 // same lifetime as raw_data in parameter. See bug 1451543.
6735 pub unsafe extern "C" fn Servo_StyleSet_GetCounterStyleRule(
6736 raw_data: &PerDocumentStyleData,
6738 ) -> *const LockedCounterStyleRule {
6739 let data = raw_data.borrow();
6740 Atom::with(name, |name| {
6742 .iter_extra_data_origins()
6743 .find_map(|(d, _)| d.counter_styles.get(name))
6744 .map_or(ptr::null(), |rule| &**rule as *const _)
6749 pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet(
6750 raw_data: &PerDocumentStyleData,
6751 ) -> *mut gfxFontFeatureValueSet {
6752 let data = raw_data.borrow();
6756 .iter_extra_data_origins()
6757 .any(|(d, _)| !d.font_feature_values.is_empty());
6760 return ptr::null_mut();
6763 let font_feature_values_iter = data
6765 .iter_extra_data_origins_rev()
6766 .flat_map(|(d, _)| d.font_feature_values.iter());
6768 let set = unsafe { Gecko_ConstructFontFeatureValueSet() };
6769 for &(ref rule, _) in font_feature_values_iter {
6770 rule.set_at_rules(set);
6776 pub extern "C" fn Servo_StyleSet_BuildFontPaletteValueSet(
6777 raw_data: &PerDocumentStyleData,
6778 ) -> *mut FontPaletteValueSet {
6779 let data = raw_data.borrow();
6783 .iter_extra_data_origins()
6784 .any(|(d, _)| !d.font_palette_values.is_empty());
6787 return ptr::null_mut();
6790 let font_palette_values_iter = data
6792 .iter_extra_data_origins_rev()
6793 .flat_map(|(d, _)| d.font_palette_values.iter());
6795 let set = unsafe { Gecko_ConstructFontPaletteValueSet() };
6796 for &(ref rule, _) in font_palette_values_iter {
6797 rule.to_gecko_palette_value_set(set);
6803 pub extern "C" fn Servo_StyleSet_ResolveForDeclarations(
6804 raw_data: &PerDocumentStyleData,
6805 parent_style_context: Option<&ComputedValues>,
6806 declarations: &LockedDeclarationBlock,
6807 ) -> Strong<ComputedValues> {
6808 let doc_data = raw_data.borrow();
6809 let global_style_data = &*GLOBAL_STYLE_DATA;
6810 let guard = global_style_data.shared_lock.read();
6811 let guards = StylesheetGuards::same(&guard);
6813 let parent_style = match parent_style_context {
6814 Some(parent) => &*parent,
6815 None => doc_data.default_computed_values(),
6820 .compute_for_declarations::<GeckoElement>(&guards, parent_style, unsafe {
6821 Arc::from_raw_addrefed(declarations)
6827 pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis(
6828 malloc_size_of: GeckoMallocSizeOf,
6829 malloc_enclosing_size_of: GeckoMallocSizeOf,
6830 sizes: *mut ServoStyleSetSizes,
6831 raw_data: &PerDocumentStyleData,
6833 let data = raw_data.borrow_mut();
6834 let mut ops = MallocSizeOfOps::new(
6835 malloc_size_of.unwrap(),
6836 Some(malloc_enclosing_size_of.unwrap()),
6839 let sizes = unsafe { sizes.as_mut() }.unwrap();
6840 data.add_size_of(&mut ops, sizes);
6844 pub extern "C" fn Servo_UACache_AddSizeOf(
6845 malloc_size_of: GeckoMallocSizeOf,
6846 malloc_enclosing_size_of: GeckoMallocSizeOf,
6847 sizes: *mut ServoStyleSetSizes,
6849 let mut ops = MallocSizeOfOps::new(
6850 malloc_size_of.unwrap(),
6851 Some(malloc_enclosing_size_of.unwrap()),
6854 let sizes = unsafe { sizes.as_mut() }.unwrap();
6855 add_size_of_ua_cache(&mut ops, sizes);
6859 pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
6860 raw_data: &PerDocumentStyleData,
6861 element: &RawGeckoElement,
6862 local_name: *mut nsAtom,
6864 let data = raw_data.borrow();
6865 let element = GeckoElement(element);
6868 AtomIdent::with(local_name, |atom| {
6869 data.stylist.any_applicable_rule_data(element, |data| {
6870 data.might_have_attribute_dependency(atom)
6877 pub extern "C" fn Servo_StyleSet_MightHaveNthOfIDDependency(
6878 raw_data: &PerDocumentStyleData,
6879 element: &RawGeckoElement,
6880 old_id: *mut nsAtom,
6881 new_id: *mut nsAtom,
6883 let data = raw_data.borrow();
6884 let element = GeckoElement(element);
6886 data.stylist.any_applicable_rule_data(element, |data| {
6889 .filter(|id| !id.is_null())
6891 AtomIdent::with(*id, |atom| data.might_have_nth_of_id_dependency(atom))
6893 data.might_have_nth_of_attribute_dependency(&AtomIdent(atom!("id")))
6898 pub extern "C" fn Servo_StyleSet_MightHaveNthOfClassDependency(
6899 raw_data: &PerDocumentStyleData,
6900 element: &RawGeckoElement,
6901 snapshots: &ServoElementSnapshotTable,
6903 let data = raw_data.borrow();
6904 let element = GeckoElement(element);
6906 data.stylist.any_applicable_rule_data(element, |data| {
6907 classes_changed(&element, snapshots)
6909 .any(|atom| data.might_have_nth_of_class_dependency(atom)) ||
6910 data.might_have_nth_of_attribute_dependency(&AtomIdent(atom!("class")))
6915 pub extern "C" fn Servo_StyleSet_MightHaveNthOfAttributeDependency(
6916 raw_data: &PerDocumentStyleData,
6917 element: &RawGeckoElement,
6918 local_name: *mut nsAtom,
6920 let data = raw_data.borrow();
6921 let element = GeckoElement(element);
6924 AtomIdent::with(local_name, |atom| {
6925 data.stylist.any_applicable_rule_data(element, |data| {
6926 data.might_have_nth_of_attribute_dependency(atom)
6932 fn on_siblings_invalidated(element: GeckoElement) {
6933 let parent = element
6935 .expect("How could we invalidate siblings without a common parent?");
6937 parent.set_dirty_descendants();
6938 bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0);
6942 fn restyle_for_nth_of(element: GeckoElement, flags: ElementSelectorFlags) {
6945 "Calling restyle for nth but no relevant flag is set."
6947 fn invalidate_siblings_of(
6948 element: GeckoElement,
6949 get_sibling: fn(GeckoElement) -> Option<GeckoElement>,
6951 let mut sibling = get_sibling(element);
6952 while let Some(sib) = sibling {
6953 if let Some(mut data) = sib.mutate_data() {
6954 data.hint.insert(RestyleHint::restyle_subtree());
6956 sibling = get_sibling(sib);
6960 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
6961 invalidate_siblings_of(element, |e| e.prev_sibling_element());
6963 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
6964 invalidate_siblings_of(element, |e| e.next_sibling_element());
6966 on_siblings_invalidated(element);
6969 fn relative_selector_invalidated_at(element: GeckoElement, result: &InvalidationResult) {
6970 if result.has_invalidated_siblings() {
6971 on_siblings_invalidated(element);
6972 } else if result.has_invalidated_descendants() {
6973 unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) };
6974 } else if result.has_invalidated_self() {
6975 unsafe { bindings::Gecko_NoteDirtyElement(element.0) };
6978 .map_or(ElementSelectorFlags::empty(), |e| e.slow_selector_flags());
6979 // We invalidated up to the anchor, and it has a flag for nth-of invalidation.
6980 if !flags.is_empty() {
6981 restyle_for_nth_of(element, flags);
6986 fn add_relative_selector_attribute_dependency<'a>(
6987 element: &GeckoElement<'a>,
6988 scope: &Option<OpaqueElement>,
6989 invalidation_map: &'a RelativeSelectorInvalidationMap,
6990 attribute: &AtomIdent,
6991 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>,
6993 match invalidation_map
6995 .other_attribute_affecting_selectors
6999 for dependency in v {
7000 collector.add_dependency(dependency, *element, *scope);
7007 fn inherit_relative_selector_search_direction(
7008 parent: Option<GeckoElement>,
7009 prev_sibling: Option<GeckoElement>,
7010 ) -> ElementSelectorFlags {
7011 let mut inherited = ElementSelectorFlags::empty();
7012 if let Some(parent) = parent {
7014 .relative_selector_search_direction()
7015 .intersection(ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR);
7017 if let Some(sibling) = prev_sibling {
7018 // Inherit both, for e.g. a sibling with `:has(~.sibling .descendant)`
7019 inherited |= sibling.relative_selector_search_direction().intersection(
7020 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING,
7027 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorIDDependency(
7028 raw_data: &PerDocumentStyleData,
7029 element: &RawGeckoElement,
7030 old_id: *mut nsAtom,
7031 new_id: *mut nsAtom,
7032 snapshots: &ServoElementSnapshotTable,
7034 let data = raw_data.borrow();
7035 let element = GeckoElement(element);
7037 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7038 let invalidator = RelativeSelectorInvalidator {
7041 snapshot_table: Some(snapshots),
7042 invalidated: relative_selector_invalidated_at,
7043 sibling_traversal_map: SiblingTraversalMap::default(),
7044 _marker: std::marker::PhantomData,
7047 invalidator.invalidate_relative_selectors_for_this(
7049 |element, scope, data, quirks_mode, collector| {
7050 let invalidation_map = data.relative_selector_invalidation_map();
7051 relative_selector_dependencies_for_id(
7060 add_relative_selector_attribute_dependency(
7064 &AtomIdent(atom!("id")),
7072 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorClassDependency(
7073 raw_data: &PerDocumentStyleData,
7074 element: &RawGeckoElement,
7075 snapshots: &ServoElementSnapshotTable,
7077 let data = raw_data.borrow();
7078 let element = GeckoElement(element);
7079 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7080 let invalidator = RelativeSelectorInvalidator {
7083 snapshot_table: Some(snapshots),
7084 invalidated: relative_selector_invalidated_at,
7085 sibling_traversal_map: SiblingTraversalMap::default(),
7086 _marker: std::marker::PhantomData,
7089 invalidator.invalidate_relative_selectors_for_this(
7091 |element, scope, data, quirks_mode, mut collector| {
7092 let invalidation_map = data.relative_selector_invalidation_map();
7094 relative_selector_dependencies_for_class(
7095 &classes_changed(element, snapshots),
7102 add_relative_selector_attribute_dependency(
7106 &AtomIdent(atom!("class")),
7114 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorAttributeDependency(
7115 raw_data: &PerDocumentStyleData,
7116 element: &RawGeckoElement,
7117 local_name: *mut nsAtom,
7118 snapshots: &ServoElementSnapshotTable,
7120 let data = raw_data.borrow();
7121 let element = GeckoElement(element);
7123 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7125 AtomIdent::with(local_name, |atom| {
7126 let invalidator = RelativeSelectorInvalidator {
7129 snapshot_table: Some(snapshots),
7130 invalidated: relative_selector_invalidated_at,
7131 sibling_traversal_map: SiblingTraversalMap::default(),
7132 _marker: std::marker::PhantomData,
7135 invalidator.invalidate_relative_selectors_for_this(
7137 |element, scope, data, _quirks_mode, mut collector| {
7138 add_relative_selector_attribute_dependency(
7141 data.relative_selector_invalidation_map(),
7152 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorStateDependency(
7153 raw_data: &PerDocumentStyleData,
7154 element: &RawGeckoElement,
7156 snapshots: &ServoElementSnapshotTable,
7158 let element = GeckoElement(element);
7160 let state = match ElementState::from_bits(state) {
7161 Some(state) => state,
7164 let data = raw_data.borrow();
7165 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7167 let invalidator = RelativeSelectorInvalidator {
7170 snapshot_table: Some(snapshots),
7171 invalidated: relative_selector_invalidated_at,
7172 sibling_traversal_map: SiblingTraversalMap::default(),
7173 _marker: std::marker::PhantomData,
7176 invalidator.invalidate_relative_selectors_for_this(
7178 |element, scope, data, quirks_mode, collector| {
7179 let invalidation_map = data.relative_selector_invalidation_map();
7182 .state_affecting_selectors
7183 .lookup_with_additional(*element, quirks_mode, None, &[], state, |dependency| {
7184 if !dependency.state.intersects(state) {
7187 collector.add_dependency(&dependency.dep, *element, scope);
7195 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorCustomStateDependency(
7196 raw_data: &PerDocumentStyleData,
7197 element: &RawGeckoElement,
7199 snapshots: &ServoElementSnapshotTable,
7201 let data = raw_data.borrow();
7202 let element = GeckoElement(element);
7204 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7205 let invalidator = RelativeSelectorInvalidator {
7208 snapshot_table: Some(snapshots),
7209 invalidated: relative_selector_invalidated_at,
7210 sibling_traversal_map: SiblingTraversalMap::default(),
7211 _marker: std::marker::PhantomData,
7214 invalidator.invalidate_relative_selectors_for_this(
7216 |element, scope, data, _quirks_mode, collector| {
7217 let invalidation_map = data.relative_selector_invalidation_map();
7218 relative_selector_dependencies_for_custom_state(
7229 fn invalidate_relative_selector_prev_sibling_side_effect(
7230 prev_sibling: GeckoElement,
7231 quirks_mode: QuirksMode,
7232 sibling_traversal_map: SiblingTraversalMap<GeckoElement>,
7235 let invalidator = RelativeSelectorInvalidator {
7236 element: prev_sibling,
7238 snapshot_table: None,
7239 invalidated: relative_selector_invalidated_at,
7240 sibling_traversal_map,
7241 _marker: std::marker::PhantomData,
7243 invalidator.invalidate_relative_selectors_for_dom_mutation(
7246 ElementSelectorFlags::empty(),
7247 DomMutationOperation::SideEffectPrevSibling,
7251 fn invalidate_relative_selector_next_sibling_side_effect(
7252 next_sibling: GeckoElement,
7253 quirks_mode: QuirksMode,
7254 sibling_traversal_map: SiblingTraversalMap<GeckoElement>,
7257 let invalidator = RelativeSelectorInvalidator {
7258 element: next_sibling,
7260 snapshot_table: None,
7261 invalidated: relative_selector_invalidated_at,
7262 sibling_traversal_map,
7263 _marker: std::marker::PhantomData,
7265 invalidator.invalidate_relative_selectors_for_dom_mutation(
7268 ElementSelectorFlags::empty(),
7269 DomMutationOperation::SideEffectNextSibling,
7273 fn invalidate_relative_selector_ts_dependency(
7274 raw_data: &PerDocumentStyleData,
7275 element: GeckoElement,
7276 state: TSStateForInvalidation,
7278 let data = raw_data.borrow();
7279 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7281 let invalidator = RelativeSelectorInvalidator {
7284 snapshot_table: None,
7285 invalidated: relative_selector_invalidated_at,
7286 sibling_traversal_map: SiblingTraversalMap::default(),
7287 _marker: std::marker::PhantomData,
7290 invalidator.invalidate_relative_selectors_for_this(
7292 |element, scope, data, quirks_mode, collector| {
7293 let invalidation_map = data.relative_selector_invalidation_map();
7295 .ts_state_to_selector
7296 .lookup_with_additional(
7301 ElementState::empty(),
7303 if !dependency.state.intersects(state) {
7306 collector.add_dependency(&dependency.dep, *element, scope);
7315 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorEmptyDependency(
7316 raw_data: &PerDocumentStyleData,
7317 element: &RawGeckoElement,
7319 invalidate_relative_selector_ts_dependency(
7321 GeckoElement(element),
7322 TSStateForInvalidation::EMPTY,
7327 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorNthEdgeDependency(
7328 raw_data: &PerDocumentStyleData,
7329 element: &RawGeckoElement,
7331 invalidate_relative_selector_ts_dependency(
7333 GeckoElement(element),
7334 TSStateForInvalidation::NTH_EDGE,
7339 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorNthDependencyFromSibling(
7340 raw_data: &PerDocumentStyleData,
7341 element: &RawGeckoElement,
7343 let mut element = Some(GeckoElement(element));
7345 // Short of doing the actual matching, any of the siblings can match the selector, so we
7346 // have to try invalidating against all of them.
7347 while let Some(sibling) = element {
7348 invalidate_relative_selector_ts_dependency(raw_data, sibling, TSStateForInvalidation::NTH);
7349 element = sibling.next_sibling_element();
7354 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForInsertion(
7355 raw_data: &PerDocumentStyleData,
7356 element: &RawGeckoElement,
7358 let element = GeckoElement(element);
7359 let data = raw_data.borrow();
7360 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7362 let inherited = inherit_relative_selector_search_direction(
7363 element.parent_element(),
7364 element.prev_sibling_element(),
7366 // Technically, we're not handling breakouts, where the anchor is a (later-sibling) descendant.
7367 // For descendant case, we're ok since it's a descendant of an element yet to be styled.
7368 // For later-sibling descendant, `HAS_SLOW_SELECTOR_LATER_SIBLINGS` is set anyway.
7369 if inherited.is_empty() {
7373 // Ok, we could've been inserted between two sibling elements that were connected
7374 // through next sibling. This can happen in two ways:
7376 // * `:has(.. .a + .b ..)`
7377 // Note that the previous sibling may be the anchor, and not part of the invalidation chain.
7378 // Either way, there must be siblings to both sides of the element being inserted
7381 element.prev_sibling_element(),
7382 element.next_sibling_element(),
7384 (Some(prev_sibling), Some(next_sibling)) => 'sibling: {
7385 // If the prev sibling is not on the sibling search path, skip.
7387 .relative_selector_search_direction()
7388 .intersects(ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING)
7392 element.apply_selector_flags(
7393 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
7395 invalidate_relative_selector_prev_sibling_side_effect(
7398 SiblingTraversalMap::new(
7400 prev_sibling.prev_sibling_element(),
7401 element.next_sibling_element(),
7402 ), // Pretend this inserted element isn't here.
7405 invalidate_relative_selector_next_sibling_side_effect(
7408 SiblingTraversalMap::new(
7411 next_sibling.next_sibling_element(),
7419 let invalidator = RelativeSelectorInvalidator {
7422 snapshot_table: None,
7423 invalidated: relative_selector_invalidated_at,
7424 sibling_traversal_map: SiblingTraversalMap::default(),
7425 _marker: std::marker::PhantomData,
7428 invalidator.invalidate_relative_selectors_for_dom_mutation(
7432 DomMutationOperation::Insert,
7437 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForAppend(
7438 raw_data: &PerDocumentStyleData,
7439 first_node: &RawGeckoNode,
7441 let first_node = GeckoNode(first_node);
7442 let inherited = inherit_relative_selector_search_direction(
7443 first_node.parent_element(),
7444 first_node.prev_sibling_element(),
7446 if inherited.is_empty() {
7449 let first_element = if let Some(e) = first_node.as_element() {
7451 } else if let Some(e) = first_node.next_sibling_element() {
7456 let data = raw_data.borrow();
7457 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7459 let mut element = Some(first_element);
7460 while let Some(e) = element {
7461 let invalidator = RelativeSelectorInvalidator {
7464 snapshot_table: None,
7465 sibling_traversal_map: SiblingTraversalMap::default(),
7466 invalidated: relative_selector_invalidated_at,
7467 _marker: std::marker::PhantomData,
7469 invalidator.invalidate_relative_selectors_for_dom_mutation(
7473 DomMutationOperation::Append,
7475 element = e.next_sibling_element();
7479 fn get_siblings_of_element<'e>(
7480 element: GeckoElement<'e>,
7481 following_node: &'e Option<GeckoNode<'e>>,
7482 ) -> (Option<GeckoElement<'e>>, Option<GeckoElement<'e>>) {
7483 let node = match following_node {
7486 return match element.as_node().parent_node() {
7487 Some(p) => (p.last_child_element(), None),
7488 None => (None, None),
7493 (node.prev_sibling_element(), node.next_sibling_element())
7497 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForRemoval(
7498 raw_data: &PerDocumentStyleData,
7499 element: &RawGeckoElement,
7500 following_node: Option<&RawGeckoNode>,
7502 let element = GeckoElement(element);
7504 // This element was in-tree, so we can safely say that if it was not on
7505 // the relative selector search path, its removal will not invalidate any
7506 // relative selector.
7507 if element.relative_selector_search_direction().is_empty() {
7510 let following_node = following_node.map(GeckoNode);
7511 let (prev_sibling, next_sibling) = get_siblings_of_element(element, &following_node);
7512 let data = raw_data.borrow();
7513 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7516 inherit_relative_selector_search_direction(element.parent_element(), prev_sibling);
7517 if inherited.is_empty() {
7521 // Same comment as insertion applies.
7522 match (prev_sibling, next_sibling) {
7523 (Some(prev_sibling), Some(next_sibling)) => {
7524 invalidate_relative_selector_prev_sibling_side_effect(
7527 SiblingTraversalMap::default(),
7530 invalidate_relative_selector_next_sibling_side_effect(
7533 SiblingTraversalMap::default(),
7539 let invalidator = RelativeSelectorInvalidator {
7542 snapshot_table: None,
7543 sibling_traversal_map: SiblingTraversalMap::new(element, prev_sibling, next_sibling),
7544 invalidated: relative_selector_invalidated_at,
7545 _marker: std::marker::PhantomData,
7547 invalidator.invalidate_relative_selectors_for_dom_mutation(
7551 DomMutationOperation::Remove,
7556 pub extern "C" fn Servo_StyleSet_HasStateDependency(
7557 raw_data: &PerDocumentStyleData,
7558 element: &RawGeckoElement,
7561 let element = GeckoElement(element);
7563 let state = ElementState::from_bits_retain(state);
7564 let data = raw_data.borrow();
7567 .any_applicable_rule_data(element, |data| data.has_state_dependency(state))
7571 pub extern "C" fn Servo_StyleSet_HasNthOfCustomStateDependency(
7572 raw_data: &PerDocumentStyleData,
7573 element: &RawGeckoElement,
7576 let element = GeckoElement(element);
7577 let data = raw_data.borrow();
7579 .any_applicable_rule_data(element, |data| unsafe {
7580 AtomIdent::with(state, |atom| data.has_nth_of_custom_state_dependency(atom))
7586 pub extern "C" fn Servo_StyleSet_HasNthOfStateDependency(
7587 raw_data: &PerDocumentStyleData,
7588 element: &RawGeckoElement,
7591 let element = GeckoElement(element);
7593 let state = ElementState::from_bits_retain(state);
7594 let data = raw_data.borrow();
7597 .any_applicable_rule_data(element, |data| data.has_nth_of_state_dependency(state))
7601 pub extern "C" fn Servo_StyleSet_RestyleSiblingsForNthOf(element: &RawGeckoElement, flags: u32) {
7602 let flags = slow_selector_flags_from_node_selector_flags(flags);
7603 let element = GeckoElement(element);
7604 restyle_for_nth_of(element, flags);
7608 pub extern "C" fn Servo_StyleSet_HasDocumentStateDependency(
7609 raw_data: &PerDocumentStyleData,
7612 let state = DocumentState::from_bits_retain(state);
7613 let data = raw_data.borrow();
7615 data.stylist.has_document_state_dependency(state)
7618 fn computed_or_resolved_value(
7619 style: &ComputedValues,
7620 prop: nsCSSPropertyID,
7621 context: Option<&style::values::resolved::Context>,
7622 value: &mut nsACString,
7624 if let Some(longhand) = LonghandId::from_nscsspropertyid(prop) {
7626 .computed_or_resolved_value(longhand, context, value)
7631 ShorthandId::from_nscsspropertyid(prop).expect("Not a shorthand nor a longhand?");
7632 let mut block = PropertyDeclarationBlock::new();
7633 for longhand in shorthand.longhands() {
7635 style.computed_or_resolved_declaration(longhand, context),
7639 block.shorthand_to_css(shorthand, value).unwrap();
7643 pub unsafe extern "C" fn Servo_GetComputedValue(
7644 style: &ComputedValues,
7645 prop: nsCSSPropertyID,
7646 value: &mut nsACString,
7648 computed_or_resolved_value(style, prop, None, value)
7652 pub unsafe extern "C" fn Servo_GetResolvedValue(
7653 style: &ComputedValues,
7654 prop: nsCSSPropertyID,
7655 raw_data: &PerDocumentStyleData,
7656 element: &RawGeckoElement,
7657 value: &mut nsACString,
7659 use style::values::resolved;
7661 let data = raw_data.borrow();
7662 let device = data.stylist.device();
7663 let context = resolved::Context {
7666 element_info: resolved::ResolvedElementInfo {
7667 element: GeckoElement(element),
7671 computed_or_resolved_value(style, prop, Some(&context), value)
7675 pub unsafe extern "C" fn Servo_GetCustomPropertyValue(
7676 computed_values: &ComputedValues,
7677 raw_style_set: &PerDocumentStyleData,
7679 value: &mut nsACString,
7681 let doc_data = raw_style_set.borrow();
7682 let name = Atom::from(name.as_str_unchecked());
7683 let custom_registration = doc_data.stylist.get_custom_property_registration(&name);
7684 let computed_value = if custom_registration.inherits() {
7685 computed_values.custom_properties.inherited.get(&name)
7687 computed_values.custom_properties.non_inherited.get(&name)
7690 if let Some(v) = computed_value {
7691 v.to_css(&mut CssWriter::new(value)).unwrap();
7699 pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u32 {
7700 // Just expose the custom property items from custom_properties.inherited
7701 // and custom_properties.non_inherited.
7702 let properties = computed_values.custom_properties();
7703 properties.inherited.len() as u32 + properties.non_inherited.len() as u32
7707 pub extern "C" fn Servo_GetCustomPropertyNameAt(
7708 computed_values: &ComputedValues,
7711 match &computed_values
7713 .property_at(index as usize)
7715 Some((name, _value)) => name.as_ptr(),
7716 None => ptr::null_mut(),
7721 pub extern "C" fn Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool {
7725 fn relative_selector_dependencies_for_id<'a>(
7726 old_id: *const nsAtom,
7727 new_id: *const nsAtom,
7728 element: &GeckoElement<'a>,
7729 scope: Option<OpaqueElement>,
7730 quirks_mode: QuirksMode,
7731 invalidation_map: &'a RelativeSelectorInvalidationMap,
7732 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>,
7736 .filter(|id| !id.is_null())
7737 .for_each(|id| unsafe {
7738 AtomIdent::with(*id, |atom| {
7739 match invalidation_map.map.id_to_selector.get(atom, quirks_mode) {
7741 for dependency in v {
7742 collector.add_dependency(dependency, *element, scope);
7751 fn relative_selector_dependencies_for_class<'a>(
7752 classes_changed: &SmallVec<[Atom; 8]>,
7753 element: &GeckoElement<'a>,
7754 scope: Option<OpaqueElement>,
7755 quirks_mode: QuirksMode,
7756 invalidation_map: &'a RelativeSelectorInvalidationMap,
7757 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>,
7759 classes_changed.iter().for_each(|atom| {
7760 match invalidation_map
7763 .get(atom, quirks_mode)
7766 for dependency in v {
7767 collector.add_dependency(dependency, *element, scope);
7775 fn relative_selector_dependencies_for_custom_state<'a>(
7776 state: *const nsAtom,
7777 element: GeckoElement<'a>,
7778 scope: Option<OpaqueElement>,
7779 invalidation_map: &'a RelativeSelectorInvalidationMap,
7780 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>,
7783 AtomIdent::with(state, |atom| {
7784 match invalidation_map
7786 .custom_state_affecting_selectors
7790 for dependency in v {
7791 collector.add_dependency(dependency, element, scope);
7800 fn process_relative_selector_invalidations(
7801 element: &GeckoElement,
7802 snapshot_table: &ServoElementSnapshotTable,
7803 data: &PerDocumentStyleDataImpl,
7805 let snapshot = match snapshot_table.get(element) {
7809 let mut states = None;
7810 let mut classes = None;
7812 let quirks_mode: QuirksMode = data.stylist.quirks_mode();
7813 let invalidator = RelativeSelectorInvalidator {
7816 invalidated: relative_selector_invalidated_at,
7817 sibling_traversal_map: SiblingTraversalMap::default(),
7818 snapshot_table: Some(snapshot_table),
7819 _marker: std::marker::PhantomData,
7822 invalidator.invalidate_relative_selectors_for_this(
7824 |element, scope, data, quirks_mode, collector| {
7825 let invalidation_map = data.relative_selector_invalidation_map();
7826 let states = *states.get_or_insert_with(|| {
7827 ElementWrapper::new(*element, snapshot_table).state_changes()
7829 let classes = classes.get_or_insert_with(|| classes_changed(element, snapshot_table));
7830 if snapshot.id_changed() {
7831 relative_selector_dependencies_for_id(
7834 .map(|id| id.as_ptr().cast_const())
7835 .unwrap_or(ptr::null()),
7838 .map(|id| id.as_ptr().cast_const())
7839 .unwrap_or(ptr::null()),
7847 relative_selector_dependencies_for_class(
7855 snapshot.each_attr_changed(|attr| {
7856 add_relative_selector_attribute_dependency(
7866 .state_affecting_selectors
7867 .lookup_with_additional(*element, quirks_mode, None, &[], states, |dependency| {
7868 if !dependency.state.intersects(states) {
7871 collector.add_dependency(&dependency.dep, *element, scope);
7879 pub extern "C" fn Servo_ProcessInvalidations(
7880 set: &PerDocumentStyleData,
7881 element: &RawGeckoElement,
7882 snapshots: *const ServoElementSnapshotTable,
7884 debug_assert!(!snapshots.is_null());
7886 let element = GeckoElement(element);
7887 debug_assert!(element.has_snapshot());
7888 debug_assert!(!element.handled_snapshot());
7890 let snapshot_table = unsafe { &*snapshots };
7891 let per_doc_data = set.borrow();
7892 process_relative_selector_invalidations(&element, snapshot_table, &per_doc_data);
7894 let mut data = element.mutate_data();
7896 // Snapshot for unstyled element is really only meant for relative selector
7897 // invalidation, so this is fine.
7901 let global_style_data = &*GLOBAL_STYLE_DATA;
7902 let guard = global_style_data.shared_lock.read();
7903 let per_doc_data = set.borrow();
7904 let shared_style_context = create_shared_context(
7907 &per_doc_data.stylist,
7908 TraversalFlags::empty(),
7911 let mut data = data.as_mut().map(|d| &mut **d);
7913 let mut selector_caches = SelectorCaches::default();
7914 if let Some(ref mut data) = data {
7915 // FIXME(emilio): Ideally we could share the nth-index-cache across all
7917 let result = data.invalidate_style_if_needed(
7919 &shared_style_context,
7921 &mut selector_caches,
7924 if result.has_invalidated_siblings() {
7925 let parent = element
7927 .expect("How could we invalidate siblings without a common parent?");
7929 parent.set_dirty_descendants();
7930 bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0);
7932 } else if result.has_invalidated_descendants() {
7933 unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) };
7934 } else if result.has_invalidated_self() {
7935 unsafe { bindings::Gecko_NoteDirtyElement(element.0) };
7941 pub extern "C" fn Servo_HasPendingRestyleAncestor(
7942 element: &RawGeckoElement,
7943 may_need_to_flush_layout: bool,
7945 let mut has_yet_to_be_styled = false;
7946 let mut element = Some(GeckoElement(element));
7947 while let Some(e) = element {
7948 if e.has_any_animation() {
7952 // If the element needs a frame, it means that we haven't styled it yet
7953 // after it got inserted in the document, and thus we may need to do
7954 // that for transitions and animations to trigger.
7956 // This is a fast path in the common case, but `has_yet_to_be_styled` is
7957 // the real check for this.
7958 if e.needs_frame() {
7962 let data = e.borrow_data();
7963 if let Some(ref data) = data {
7964 if !data.hint.is_empty() {
7967 if has_yet_to_be_styled && !data.styles.is_display_none() {
7970 // Ideally, DOM mutations wouldn't affect layout trees of siblings.
7972 // In practice, this can happen because Gecko deals pretty badly
7973 // with some kinds of content insertion and removals.
7975 // If we may need to flush layout, we need frames to accurately
7976 // determine whether we'll actually flush, so if we have to
7977 // reconstruct we need to flush style, which is what will take care
7978 // of ensuring that frames are constructed, even if the style itself
7980 if may_need_to_flush_layout && data.damage.contains(GeckoRestyleDamage::reconstruct()) {
7984 has_yet_to_be_styled = data.is_none();
7986 element = e.traversal_parent();
7992 pub unsafe extern "C" fn Servo_SelectorList_Parse(
7993 selector_list: &nsACString,
7995 ) -> *mut SelectorList {
7996 use style::selector_parser::SelectorParser;
7998 let url_data = if is_chrome {
7999 dummy_chrome_url_data()
8004 let input = selector_list.as_str_unchecked();
8005 let selector_list = match SelectorParser::parse_author_origin_no_namespace(&input, url_data) {
8006 Ok(selector_list) => selector_list,
8007 Err(..) => return ptr::null_mut(),
8010 Box::into_raw(Box::new(selector_list))
8014 pub unsafe extern "C" fn Servo_SelectorList_Drop(list: *mut SelectorList) {
8015 let _ = Box::from_raw(list);
8019 pub unsafe extern "C" fn Servo_IsValidCSSColor(value: &nsACString) -> bool {
8020 let mut input = ParserInput::new(value.as_str_unchecked());
8021 let mut input = Parser::new(&mut input);
8022 let context = ParserContext::new(
8025 Some(CssRuleType::Style),
8026 ParsingMode::DEFAULT,
8027 QuirksMode::NoQuirks,
8028 /* namespaces = */ Default::default(),
8032 specified::Color::is_valid(&context, &mut input)
8036 pub unsafe extern "C" fn Servo_ComputeColor(
8037 raw_data: Option<&PerDocumentStyleData>,
8038 current_color: structs::nscolor,
8040 result_color: &mut structs::nscolor,
8041 was_current_color: *mut bool,
8042 loader: *mut Loader,
8044 let mut input = ParserInput::new(value.as_str_unchecked());
8045 let mut input = Parser::new(&mut input);
8046 let reporter = loader.as_mut().and_then(|loader| {
8047 // Make an ErrorReporter that will report errors as being "from DOM".
8048 ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut())
8051 let context = ParserContext::new(
8054 Some(CssRuleType::Style),
8055 ParsingMode::DEFAULT,
8056 QuirksMode::NoQuirks,
8057 /* namespaces = */ Default::default(),
8058 reporter.as_ref().map(|e| e as &dyn ParseErrorReporter),
8063 let device = match raw_data {
8066 Some(data.stylist.device())
8071 let computed = match specified::Color::parse_and_compute(&context, &mut input, device) {
8073 None => return false,
8076 let current_color = style::gecko::values::convert_nscolor_to_absolute_color(current_color);
8077 if !was_current_color.is_null() {
8078 *was_current_color = computed.is_currentcolor();
8081 let rgba = computed.resolve_to_absolute(¤t_color);
8082 *result_color = style::gecko::values::convert_absolute_color_to_nscolor(&rgba);
8087 pub unsafe extern "C" fn Servo_ColorTo(
8088 from_color: &nsACString,
8089 to_color_space: &nsACString,
8090 result_color: &mut nsACString,
8091 result_components: &mut nsTArray<f32>,
8092 result_adjusted: &mut bool,
8093 loader: *mut Loader,
8095 // Figure out the color space.
8096 let mut input = ParserInput::new(to_color_space.as_str_unchecked());
8097 let mut input = Parser::new(&mut input);
8098 let to_color_space = match ColorSpace::parse(&mut input) {
8099 Ok(color_space) => color_space,
8101 // Can't parse the color space? Fail the conversion.
8106 let mut input = ParserInput::new(from_color.as_str_unchecked());
8107 let mut input = Parser::new(&mut input);
8109 let reporter = loader.as_mut().and_then(|loader| {
8110 // Make an ErrorReporter that will report errors as being "from DOM".
8111 ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut())
8114 let context = ParserContext::new(
8117 Some(CssRuleType::Style),
8118 ParsingMode::DEFAULT,
8119 QuirksMode::NoQuirks,
8120 /* namespaces = */ Default::default(),
8121 reporter.as_ref().map(|e| e as &dyn ParseErrorReporter),
8125 let specified = match specified::Color::parse(&context, &mut input) {
8127 Err(_) => return false,
8130 let color = match specified {
8131 specified::Color::Absolute(ref absolute) => &absolute.color,
8133 // Can't do anything with a non-absolute color from here, so we
8134 // fail the conversion.
8139 let color = color.to_color_space(to_color_space);
8140 let mut s = String::new();
8142 .write_author_preferred_value(&mut CssWriter::new(&mut s))
8144 result_color.assign(&s);
8146 result_components.assign_from_iter_pod(color.raw_components().iter().copied());
8148 // For now we don't do gamut mapping, so always false.
8149 *result_adjusted = false;
8155 pub extern "C" fn Servo_ResolveColor(
8156 color: &computed::Color,
8157 foreground: &style::color::AbsoluteColor,
8158 ) -> style::color::AbsoluteColor {
8159 color.resolve_to_absolute(foreground)
8163 pub extern "C" fn Servo_ResolveCalcLengthPercentage(
8164 calc: &computed::length_percentage::CalcLengthPercentage,
8167 calc.resolve(computed::Length::new(basis)).px()
8171 pub extern "C" fn Servo_ConvertColorSpace(
8172 color: &AbsoluteColor,
8173 color_space: ColorSpace,
8174 ) -> AbsoluteColor {
8175 color.to_color_space(color_space)
8179 pub unsafe extern "C" fn Servo_IntersectionObserverRootMargin_Parse(
8181 result: *mut IntersectionObserverRootMargin,
8183 let value = value.as_str_unchecked();
8184 let result = result.as_mut().unwrap();
8186 let mut input = ParserInput::new(&value);
8187 let mut parser = Parser::new(&mut input);
8189 let url_data = dummy_url_data();
8190 let context = ParserContext::new(
8193 Some(CssRuleType::Style),
8194 ParsingMode::DEFAULT,
8195 QuirksMode::NoQuirks,
8196 /* namespaces = */ Default::default(),
8201 let margin = parser.parse_entirely(|p| IntersectionObserverRootMargin::parse(&context, p));
8212 pub extern "C" fn Servo_IntersectionObserverRootMargin_ToString(
8213 root_margin: &IntersectionObserverRootMargin,
8214 result: &mut nsACString,
8216 let mut writer = CssWriter::new(result);
8217 root_margin.to_css(&mut writer).unwrap();
8221 pub extern "C" fn Servo_ParseTransformIntoMatrix(
8223 contain_3d: &mut bool,
8224 result: &mut structs::Matrix4x4Components,
8226 use style::properties::longhands::transform;
8228 let string = unsafe { value.as_str_unchecked() };
8229 let mut input = ParserInput::new(&string);
8230 let mut parser = Parser::new(&mut input);
8231 let context = ParserContext::new(
8233 unsafe { dummy_url_data() },
8234 Some(CssRuleType::Style),
8235 ParsingMode::DEFAULT,
8236 QuirksMode::NoQuirks,
8237 /* namespaces = */ Default::default(),
8242 let transform = match parser.parse_entirely(|t| transform::parse(&context, t)) {
8244 Err(..) => return false,
8247 let (m, is_3d) = match transform.to_transform_3d_matrix(None) {
8248 Ok(result) => result,
8249 Err(..) => return false,
8252 *result = m.to_array();
8253 *contain_3d = is_3d;
8258 pub extern "C" fn Servo_ParseFilters(
8261 data: *mut URLExtraData,
8262 out: &mut style::OwnedSlice<Filter>,
8264 use style::values::specified::effects::SpecifiedFilter;
8266 let string = unsafe { value.as_str_unchecked() };
8267 let mut input = ParserInput::new(&string);
8268 let mut parser = Parser::new(&mut input);
8269 let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
8270 let context = ParserContext::new(
8274 ParsingMode::DEFAULT,
8275 QuirksMode::NoQuirks,
8276 /* namespaces = */ Default::default(),
8281 let mut filters = vec![];
8284 .try_parse(|i| i.expect_ident_matching("none"))
8287 return parser.expect_exhausted().is_ok();
8290 if parser.is_exhausted() {
8294 while !parser.is_exhausted() {
8295 let specified_filter = match SpecifiedFilter::parse(&context, &mut parser) {
8297 Err(..) => return false,
8300 let filter = match specified_filter.to_computed_value_without_context() {
8302 Err(..) => return false,
8305 if ignore_urls && matches!(filter, Filter::Url(_)) {
8309 filters.push(filter);
8312 *out = style::OwnedSlice::from(filters);
8317 pub unsafe extern "C" fn Servo_ParseFontShorthandForMatching(
8319 data: *mut URLExtraData,
8320 family: &mut FontFamilyList,
8321 style: &mut FontStyle,
8322 stretch: &mut FontStretch,
8323 weight: &mut FontWeight,
8324 size: Option<&mut f32>,
8325 small_caps: Option<&mut bool>,
8327 use style::properties::shorthands::font;
8328 use style::values::generics::font::FontStyle as GenericFontStyle;
8329 use style::values::specified::font as specified;
8331 let string = value.as_str_unchecked();
8332 let mut input = ParserInput::new(&string);
8333 let mut parser = Parser::new(&mut input);
8334 let url_data = UrlExtraData::from_ptr_ref(&data);
8335 let context = ParserContext::new(
8338 Some(CssRuleType::FontFace),
8339 ParsingMode::DEFAULT,
8340 QuirksMode::NoQuirks,
8341 /* namespaces = */ Default::default(),
8346 let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) {
8348 Err(..) => return false,
8351 // The system font is not acceptable, so we return false.
8352 match font.font_family {
8353 specified::FontFamily::Values(list) => *family = list,
8354 specified::FontFamily::System(_) => return false,
8357 let specified_font_style = match font.font_style {
8358 specified::FontStyle::Specified(ref s) => s,
8359 specified::FontStyle::System(_) => return false,
8362 *style = match *specified_font_style {
8363 GenericFontStyle::Normal => FontStyle::NORMAL,
8364 GenericFontStyle::Italic => FontStyle::ITALIC,
8365 GenericFontStyle::Oblique(ref angle) => FontStyle::oblique(angle.degrees()),
8368 *stretch = match font.font_stretch {
8369 specified::FontStretch::Keyword(ref k) => k.compute(),
8370 specified::FontStretch::Stretch(ref p) => FontStretch::from_percentage(p.0.get()),
8371 specified::FontStretch::System(_) => return false,
8374 *weight = match font.font_weight {
8375 specified::FontWeight::Absolute(w) => w.compute(),
8376 // Resolve relative font weights against the initial of font-weight
8377 // (normal, which is equivalent to 400).
8378 specified::FontWeight::Bolder => FontWeight::normal().bolder(),
8379 specified::FontWeight::Lighter => FontWeight::normal().lighter(),
8380 specified::FontWeight::System(_) => return false,
8383 // XXX This is unfinished; see values::specified::FontSize::ToComputedValue
8384 // for a more complete implementation (but we can't use it as-is).
8385 if let Some(size) = size {
8386 *size = match font.font_size {
8387 specified::FontSize::Length(lp) => {
8388 use style::values::generics::transform::ToAbsoluteLength;
8389 match lp.to_pixel_length(None) {
8391 Err(..) => return false,
8394 specified::FontSize::Keyword(info) => {
8395 let keyword = if info.kw != specified::FontSizeKeyword::Math {
8398 specified::FontSizeKeyword::Medium
8400 // Map absolute-size keywords to sizes.
8401 // TODO: Maybe get a meaningful quirks / base size from the caller?
8402 let quirks_mode = QuirksMode::NoQuirks;
8404 .to_length_without_context(
8406 computed::Length::new(specified::FONT_MEDIUM_PX),
8411 // smaller, larger not currently supported
8412 specified::FontSize::Smaller |
8413 specified::FontSize::Larger |
8414 specified::FontSize::System(_) => {
8420 if let Some(small_caps) = small_caps {
8421 use style::computed_values::font_variant_caps::T::SmallCaps;
8422 *small_caps = font.font_variant_caps == SmallCaps;
8429 pub unsafe extern "C" fn Servo_SourceSizeList_Parse(value: &nsACString) -> *mut SourceSizeList {
8430 let value = value.as_str_unchecked();
8431 let mut input = ParserInput::new(value);
8432 let mut parser = Parser::new(&mut input);
8434 let context = ParserContext::new(
8437 Some(CssRuleType::Style),
8438 ParsingMode::DEFAULT,
8439 QuirksMode::NoQuirks,
8440 /* namespaces = */ Default::default(),
8445 // NB: Intentionally not calling parse_entirely.
8446 let list = SourceSizeList::parse(&context, &mut parser);
8447 Box::into_raw(Box::new(list))
8451 pub unsafe extern "C" fn Servo_SourceSizeList_Evaluate(
8452 raw_data: &PerDocumentStyleData,
8453 list: Option<&SourceSizeList>,
8455 let doc_data = raw_data.borrow();
8456 let device = doc_data.stylist.device();
8457 let quirks_mode = doc_data.stylist.quirks_mode();
8459 let result = match list {
8460 Some(list) => list.evaluate(device, quirks_mode),
8461 None => SourceSizeList::empty().evaluate(device, quirks_mode),
8468 pub unsafe extern "C" fn Servo_SourceSizeList_Drop(list: *mut SourceSizeList) {
8469 let _ = Box::from_raw(list);
8473 pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges(
8474 root: &RawGeckoElement,
8475 document_style: &PerDocumentStyleData,
8476 non_document_styles: &nsTArray<&AuthorStyles>,
8477 states_changed: u64,
8479 use style::invalidation::element::document_state::DocumentStateInvalidationProcessor;
8480 use style::invalidation::element::invalidator::TreeStyleInvalidator;
8482 let document_data = document_style.borrow();
8484 let iter = document_data
8487 .map(|(data, _origin)| data)
8491 .map(|author_styles| &*author_styles.data),
8494 let mut selector_caches = SelectorCaches::default();
8495 let root = GeckoElement(root);
8496 let mut processor = DocumentStateInvalidationProcessor::new(
8498 DocumentState::from_bits_retain(states_changed),
8499 &mut selector_caches,
8500 root.as_node().owner_doc().quirks_mode(),
8504 TreeStyleInvalidator::new(root, /* stack_limit_checker = */ None, &mut processor)
8507 debug_assert!(!result.has_invalidated_siblings(), "How in the world?");
8508 if result.has_invalidated_descendants() {
8509 bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0);
8510 } else if result.has_invalidated_self() {
8511 bindings::Gecko_NoteDirtyElement(root.0);
8516 pub unsafe extern "C" fn Servo_PseudoClass_GetStates(name: &nsACString) -> u64 {
8517 let name = name.as_str_unchecked();
8518 match NonTSPseudoClass::parse_non_functional(name) {
8520 // Ignore :any-link since it contains both visited and unvisited state.
8521 Some(NonTSPseudoClass::AnyLink) => 0,
8522 Some(pseudo_class) => pseudo_class.state_flag().bits(),
8527 pub unsafe extern "C" fn Servo_UseCounters_Create() -> *mut UseCounters {
8528 Box::into_raw(Box::<UseCounters>::default())
8532 pub unsafe extern "C" fn Servo_UseCounters_Drop(c: *mut UseCounters) {
8533 let _ = Box::from_raw(c);
8537 pub unsafe extern "C" fn Servo_UseCounters_Merge(
8538 doc_counters: &UseCounters,
8539 sheet_counters: &UseCounters,
8541 doc_counters.merge(sheet_counters)
8545 pub unsafe extern "C" fn Servo_IsPropertyIdRecordedInUseCounter(
8546 use_counters: &UseCounters,
8547 id: nsCSSPropertyID,
8549 let id = NonCustomPropertyId::from_nscsspropertyid(id).unwrap();
8550 use_counters.non_custom_properties.recorded(id)
8554 pub unsafe extern "C" fn Servo_IsUnknownPropertyRecordedInUseCounter(
8555 use_counters: &UseCounters,
8556 p: CountedUnknownProperty,
8558 use_counters.counted_unknown_properties.recorded(p)
8562 pub unsafe extern "C" fn Servo_IsCssPropertyRecordedInUseCounter(
8563 use_counters: &UseCounters,
8564 property: &nsACString,
8565 known_prop: *mut bool,
8567 *known_prop = false;
8569 let prop_name = property.as_str_unchecked();
8570 if let Ok(p) = PropertyId::parse_unchecked_for_testing(prop_name) {
8571 if let Some(id) = p.non_custom_id() {
8573 return use_counters.non_custom_properties.recorded(id);
8577 if let Some(p) = CountedUnknownProperty::parse_for_testing(prop_name) {
8579 return use_counters.counted_unknown_properties.recorded(p);
8586 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Create(
8589 ) -> *mut SharedMemoryBuilder {
8590 Box::into_raw(Box::new(SharedMemoryBuilder::new(buffer, len)))
8594 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_AddStylesheet(
8595 builder: &mut SharedMemoryBuilder,
8596 contents: &StylesheetContents,
8597 error_message: &mut nsACString,
8598 ) -> *const LockedCssRules {
8599 // Assert some things we assume when we create a style sheet from shared
8601 debug_assert_eq!(contents.origin, Origin::UserAgent);
8602 debug_assert_eq!(contents.quirks_mode, QuirksMode::NoQuirks);
8603 debug_assert!(contents.source_map_url.read().is_none());
8604 debug_assert!(contents.source_url.read().is_none());
8606 match builder.write(&contents.rules) {
8607 Ok(rules_ptr) => &**rules_ptr,
8609 error_message.assign(&message);
8616 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_GetLength(
8617 builder: &SharedMemoryBuilder,
8623 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Drop(builder: *mut SharedMemoryBuilder) {
8624 let _ = Box::from_raw(builder);
8628 pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void {
8629 style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr()
8633 pub unsafe extern "C" fn Servo_LoadData_GetLazy(
8634 source: &url::LoadDataSource,
8635 ) -> *const url::LoadData {
8640 pub extern "C" fn Servo_LengthPercentage_ToCss(
8641 lp: &computed::LengthPercentage,
8642 result: &mut nsACString,
8644 lp.to_css(&mut CssWriter::new(result)).unwrap();
8648 pub extern "C" fn Servo_FontStyle_ToCss(s: &FontStyle, result: &mut nsACString) {
8649 s.to_css(&mut CssWriter::new(result)).unwrap()
8653 pub extern "C" fn Servo_FontWeight_ToCss(w: &FontWeight, result: &mut nsACString) {
8654 w.to_css(&mut CssWriter::new(result)).unwrap()
8658 pub extern "C" fn Servo_FontStretch_ToCss(s: &FontStretch, result: &mut nsACString) {
8659 s.to_css(&mut CssWriter::new(result)).unwrap()
8663 pub extern "C" fn Servo_FontStretch_SerializeKeyword(
8665 result: &mut nsACString,
8667 let kw = match s.as_keyword() {
8669 None => return false,
8671 kw.to_css(&mut CssWriter::new(result)).unwrap();
8676 pub unsafe extern "C" fn Servo_CursorKind_Parse(
8677 cursor: &nsACString,
8678 result: &mut computed::ui::CursorKind,
8680 match computed::ui::CursorKind::from_ident(cursor.as_str_unchecked()) {
8690 pub extern "C" fn Servo_FontFamily_Generic(generic: GenericFontFamily) -> &'static FontFamily {
8691 FontFamily::generic(generic)
8695 pub extern "C" fn Servo_FontFamily_ForSystemFont(name: &nsACString, out: &mut FontFamily) {
8696 *out = FontFamily::for_system_font(&name.to_utf8());
8700 pub extern "C" fn Servo_FontFamilyList_WithNames(
8701 names: &nsTArray<computed::font::SingleFontFamily>,
8702 out: &mut FontFamilyList,
8704 *out = FontFamilyList {
8705 list: style_traits::arc_slice::ArcSlice::from_iter(names.iter().cloned()),
8710 pub extern "C" fn Servo_FamilyName_Serialize(name: &FamilyName, result: &mut nsACString) {
8711 name.to_css(&mut CssWriter::new(result)).unwrap()
8715 pub extern "C" fn Servo_GenericFontFamily_Parse(input: &nsACString) -> GenericFontFamily {
8716 let context = ParserContext::new(
8718 unsafe { dummy_url_data() },
8719 Some(CssRuleType::Style),
8720 ParsingMode::DEFAULT,
8721 QuirksMode::NoQuirks,
8722 /* namespaces = */ Default::default(),
8726 let value = input.to_utf8();
8727 let mut input = ParserInput::new(&value);
8728 let mut input = Parser::new(&mut input);
8729 GenericFontFamily::parse(&context, &mut input).unwrap_or(GenericFontFamily::None)
8733 pub extern "C" fn Servo_ColorScheme_Parse(input: &nsACString, out: &mut u8) -> bool {
8734 use style::values::specified::ColorScheme;
8736 let context = ParserContext::new(
8738 unsafe { dummy_url_data() },
8739 Some(CssRuleType::Style),
8740 ParsingMode::DEFAULT,
8741 QuirksMode::NoQuirks,
8742 /* namespaces = */ Default::default(),
8746 let input = unsafe { input.as_str_unchecked() };
8747 let mut input = ParserInput::new(&input);
8748 let mut input = Parser::new(&mut input);
8749 let scheme = match input.parse_entirely(|i| ColorScheme::parse(&context, i)) {
8750 Ok(scheme) => scheme,
8751 Err(..) => return false,
8753 *out = scheme.raw_bits();
8758 pub extern "C" fn Servo_LayerBlockRule_GetName(rule: &LayerBlockRule, result: &mut nsACString) {
8759 if let Some(ref name) = rule.name {
8760 name.to_css(&mut CssWriter::new(result)).unwrap()
8765 pub extern "C" fn Servo_ScopeRule_GetStart(rule: &ScopeRule, result: &mut nsACString) {
8766 if let Some(v) = rule.bounds.start.as_ref() {
8767 v.to_css(&mut CssWriter::new(result)).unwrap();
8769 result.set_is_void(true);
8774 pub extern "C" fn Servo_ScopeRule_GetEnd(rule: &ScopeRule, result: &mut nsACString) {
8775 if let Some(v) = rule.bounds.end.as_ref() {
8776 v.to_css(&mut CssWriter::new(result)).unwrap();
8778 result.set_is_void(true);
8783 pub extern "C" fn Servo_LayerStatementRule_GetNameCount(rule: &LayerStatementRule) -> usize {
8788 pub extern "C" fn Servo_LayerStatementRule_GetNameAt(
8789 rule: &LayerStatementRule,
8791 result: &mut nsACString,
8793 if let Some(ref name) = rule.names.get(index) {
8794 name.to_css(&mut CssWriter::new(result)).unwrap()
8799 pub unsafe extern "C" fn Servo_InvalidateForViewportUnits(
8800 document_style: &PerDocumentStyleData,
8801 root: &RawGeckoElement,
8804 let mut document_data = document_style.borrow_mut();
8805 let ref mut stylist = document_data.stylist;
8806 let device = stylist.device();
8808 if !device.used_viewport_size() {
8812 if dynamic_only && !device.used_dynamic_viewport_size() {
8816 // If the viewport changed, then initial values containing viewport units need to be recomputed.
8818 .get_custom_property_initial_values_flags()
8819 .intersects(ComputedValueFlags::USES_VIEWPORT_UNITS)
8821 stylist.rebuild_initial_values_for_custom_properties();
8824 if style::invalidation::viewport_units::invalidate(GeckoElement(root)) {
8825 // The invalidation machinery propagates the bits up, but we still need
8826 // to tell the Gecko restyle root machinery about it.
8827 bindings::Gecko_NoteDirtySubtreeForInvalidation(root);
8832 pub extern "C" fn Servo_InterpolateColor(
8833 interpolation: ColorInterpolationMethod,
8834 left: &AbsoluteColor,
8835 right: &AbsoluteColor,
8837 ) -> AbsoluteColor {
8838 style::color::mix::mix(
8844 ColorMixFlags::empty(),
8849 pub extern "C" fn Servo_EasingFunctionAt(
8850 easing_function: &ComputedTimingFunction,
8852 before_flag: BeforeFlag,
8854 easing_function.calculate_output(progress, before_flag, 1e-7)
8857 fn parse_no_context<'i, F, R>(string: &'i str, parse: F) -> Result<R, ()>
8859 F: FnOnce(&ParserContext, &mut Parser<'i, '_>) -> Result<R, ParseError<'i>>,
8861 let context = ParserContext::new(
8863 unsafe { dummy_url_data() },
8865 ParsingMode::DEFAULT,
8866 QuirksMode::NoQuirks,
8867 /* namespaces = */ Default::default(),
8871 let mut input = ParserInput::new(string);
8872 Parser::new(&mut input)
8873 .parse_entirely(|i| parse(&context, i))
8878 // Parse a length without style context (for canvas2d letterSpacing/wordSpacing attributes).
8879 // This accepts absolute lengths, and if a font-metrics-getter function is passed, also
8880 // font-relative ones, but not other units (such as percentages, viewport-relative, etc)
8881 // that would require a full style context to resolve.
8882 pub extern "C" fn Servo_ParseLengthWithoutStyleContext(
8885 get_font_metrics: Option<unsafe extern "C" fn(*mut c_void) -> GeckoFontMetrics>,
8886 getter_context: *mut c_void,
8888 let metrics_getter = if let Some(getter) = get_font_metrics {
8889 Some(move || -> GeckoFontMetrics { unsafe { getter(getter_context) } })
8893 let value = parse_no_context(unsafe { len.as_str_unchecked() }, specified::Length::parse)
8894 .and_then(|p| p.to_computed_pixel_length_with_font_metrics(metrics_getter));
8905 pub extern "C" fn Servo_SlowRgbToColorName(r: u8, g: u8, b: u8, result: &mut nsACString) -> bool {
8906 let mut candidates = SmallVec::<[&'static str; 5]>::new();
8907 for (name, color) in cssparser::color::all_named_colors() {
8908 if color == (r, g, b) {
8909 candidates.push(name);
8912 if candidates.is_empty() {
8915 // DevTools expect the first alphabetically.
8917 result.assign(candidates[0]);
8922 pub extern "C" fn Servo_ColorNameToRgb(name: &nsACString, out: &mut structs::nscolor) -> bool {
8923 match cssparser::color::parse_named_color(unsafe { name.as_str_unchecked() }) {
8925 *out = style::gecko::values::convert_absolute_color_to_nscolor(&AbsoluteColor::new(
8939 pub enum RegisterCustomPropertyResult {
8940 SuccessfullyRegistered,
8945 InvalidInitialValue,
8946 InitialValueNotComputationallyIndependent,
8949 /// https://drafts.css-houdini.org/css-properties-values-api-1/#the-registerproperty-function
8951 pub extern "C" fn Servo_RegisterCustomProperty(
8952 per_doc_data: &PerDocumentStyleData,
8953 extra_data: *mut URLExtraData,
8955 syntax: &nsACString,
8957 initial_value: Option<&nsACString>,
8958 ) -> RegisterCustomPropertyResult {
8959 use self::RegisterCustomPropertyResult::*;
8960 use style::custom_properties::SpecifiedValue;
8961 use style::properties_and_values::rule::{PropertyRegistrationError, PropertyRuleName};
8962 use style::properties_and_values::syntax::Descriptor;
8964 let mut per_doc_data = per_doc_data.borrow_mut();
8965 let url_data = unsafe { UrlExtraData::from_ptr_ref(&extra_data) };
8966 let name = unsafe { name.as_str_unchecked() };
8967 let syntax = unsafe { syntax.as_str_unchecked() };
8968 let initial_value = initial_value.map(|v| unsafe { v.as_str_unchecked() });
8970 // If name is not a custom property name string, throw a SyntaxError and exit this algorithm.
8971 let name = match style::custom_properties::parse_name(name) {
8972 Ok(n) => Atom::from(n),
8973 Err(()) => return InvalidName,
8976 // If property set already contains an entry with name as its property name (compared
8977 // codepoint-wise), throw an InvalidModificationError and exit this algorithm.
8980 .custom_property_script_registry()
8984 return AlreadyRegistered;
8986 // Attempt to consume a syntax definition from syntax. If it returns failure, throw a
8987 // SyntaxError. Otherwise, let syntax definition be the returned syntax definition.
8988 let Ok(syntax) = Descriptor::from_str(syntax, /* preserve_specified = */ false) else {
8989 return InvalidSyntax;
8992 let initial_value = match initial_value {
8994 let mut input = ParserInput::new(v);
8995 let parsed = Parser::new(&mut input)
8996 .parse_entirely(|input| {
8997 input.skip_whitespace();
8998 SpecifiedValue::parse(input, url_data).map(Arc::new)
9001 if parsed.is_none() {
9002 return InvalidInitialValue;
9010 PropertyRegistration::validate_initial_value(&syntax, initial_value.as_deref())
9012 return match error {
9013 PropertyRegistrationError::InitialValueNotComputationallyIndependent => {
9014 InitialValueNotComputationallyIndependent
9016 PropertyRegistrationError::InvalidInitialValue => InvalidInitialValue,
9017 PropertyRegistrationError::NoInitialValue => NoInitialValue,
9023 .custom_property_script_registry_mut()
9024 .register(PropertyRegistration {
9025 name: PropertyRuleName(name),
9026 data: PropertyRegistrationData {
9028 inherits: if inherits {
9029 PropertyInherits::True
9031 PropertyInherits::False
9035 url_data: url_data.clone(),
9036 source_location: SourceLocation { line: 0, column: 0 },
9041 .rebuild_initial_values_for_custom_properties();
9043 SuccessfullyRegistered
9047 pub struct PropDef {
9048 // The name of the property.
9050 // The syntax of the property.
9051 pub syntax: nsCString,
9052 // Whether the property inherits.
9054 pub has_initial_value: bool,
9055 pub initial_value: nsCString,
9056 // True if the property was set with CSS.registerProperty
9061 /// Creates a PropDef from a name and a PropertyRegistration.
9062 pub fn new(name: Atom, property_registration: &PropertyRegistration, from_js: bool) -> Self {
9063 let mut syntax = nsCString::new();
9064 if let Some(spec) = property_registration.data.syntax.specified_string() {
9065 syntax.assign(spec);
9067 // FIXME: Descriptor::to_css should behave consistently (probably this shouldn't use
9068 // the ToCss trait).
9069 property_registration
9072 .to_css(&mut CssWriter::new(&mut syntax))
9075 let initial_value = property_registration.data.initial_value.to_css_nscstring();
9079 inherits: property_registration.data.inherits(),
9080 has_initial_value: property_registration.data.initial_value.is_some(),
9088 pub extern "C" fn Servo_GetRegisteredCustomProperties(
9089 per_doc_data: &PerDocumentStyleData,
9090 custom_properties: &mut ThinVec<PropDef>,
9092 let stylist = &per_doc_data.borrow().stylist;
9094 custom_properties.extend(
9096 .custom_property_script_registry()
9099 .map(|(name, property_registration)| {
9100 PropDef::new(name.clone(), property_registration, /* from_js */ true)
9104 for (cascade_data, _origin) in stylist.iter_origins() {
9105 custom_properties.extend(cascade_data.custom_property_registrations().iter().map(
9107 let property_registration = &value.last().unwrap().0;
9110 property_registration,
9120 pub struct SelectorWarningData {
9121 /// Index to the selector generating the warning.
9123 /// Kind of the warning.
9124 pub kind: SelectorWarningKind,
9128 pub extern "C" fn Servo_GetSelectorWarnings(
9129 rule: &LockedStyleRule,
9130 warnings: &mut ThinVec<SelectorWarningData>,
9132 read_locked_arc(rule, |r| {
9133 for (i, selector) in r.selectors.slice().iter().enumerate() {
9134 for k in SelectorWarningKind::from_selector(selector) {
9135 warnings.push(SelectorWarningData { index: i, kind: k });
9142 pub extern "C" fn Servo_GetRuleBodyText(
9143 initial_text: &nsACString,
9144 ret_val: &mut nsACString,
9146 let css_text = unsafe { initial_text.as_str_unchecked() };
9147 let mut input = ParserInput::new(&css_text);
9148 let mut input = Parser::new(&mut input);
9150 let mut found_start = false;
9152 // Search forward for the opening brace.
9153 while let Ok(token) = input.next() {
9155 Token::CurlyBracketBlock => {
9162 if token.is_parse_error() {
9169 ret_val.set_is_void(true);
9173 let token_start = input.position();
9174 // Parse the nested block to move the parser to the end of the block
9175 let _ = input.parse_nested_block(
9176 |_i| -> Result<(), CssParseError<'_, BasicParseError>> {
9181 // We're not guaranteed to have a closing bracket, but when we do, we need to move
9182 // the end offset before it.
9183 let mut token_slice = input.slice_from(token_start);
9184 if token_slice.ends_with("}") {
9185 token_slice = token_slice.strip_suffix("}").unwrap();
9187 ret_val.assign(token_slice);
9191 pub extern "C" fn Servo_ReplaceBlockRuleBodyTextInStylesheetText(
9192 stylesheet_text: &nsACString,
9195 new_body_text: &nsACString,
9196 ret_val: &mut nsACString,
9198 let css_text = unsafe { stylesheet_text.as_str_unchecked() };
9200 let Some(rule_start_index) = get_byte_index_from_line_and_column(css_text, line, column) else {
9201 ret_val.set_is_void(true);
9205 let mut input = ParserInput::new(&css_text[rule_start_index..]);
9206 let mut input = Parser::new(&mut input);
9207 let mut found_start = false;
9209 // Search forward for the opening brace.
9210 while let Ok(token) = input.next() {
9211 if matches!(*token, Token::CurlyBracketBlock) {
9216 if token.is_parse_error() {
9222 ret_val.set_is_void(true);
9226 let token_start = input.position();
9227 let rule_body_start = rule_start_index + token_start.byte_index();
9228 // Parse the nested block to move the parser to the end of the block
9229 let _ = input.parse_nested_block(
9230 |_i| -> Result<(), CssParseError<'_, BasicParseError>> {
9234 let mut rule_body_end = rule_start_index + input.position().byte_index();
9236 // We're not guaranteed to have a closing bracket, but when we do, we need to move
9237 // the end offset before it.
9238 let token_slice = input.slice_from(token_start);
9239 if token_slice.ends_with("}") {
9243 ret_val.append(&css_text[..rule_body_start]);
9244 ret_val.append(new_body_text);
9245 ret_val.append(&css_text[rule_body_end..]);
9248 /// Find css_text byte position corresponding to the passed line and column
9249 fn get_byte_index_from_line_and_column(
9253 ) -> Option<usize> {
9254 // Find the byte index of the start of the passed line within css_text
9255 let mut line_byte_index = Some(0);
9257 let mut current_line = 1;
9258 let mut last_byte = None;
9259 let mut bytes_iter = css_text.bytes();
9260 line_byte_index = bytes_iter.position(|byte| {
9261 // We want to get the position _after_ the EOF sequence
9262 let on_expected_line = current_line == line;
9263 let is_previous_byte_carriage_return = last_byte == Some(b'\r');
9264 last_byte = Some(byte);
9268 } else if byte == b'\n' {
9269 if !is_previous_byte_carriage_return {
9279 if line_byte_index.is_none() {
9284 return line_byte_index;
9287 let line_byte_index = line_byte_index.unwrap();
9288 let mut current_column = 1;
9289 for (byte_index, _char) in css_text[line_byte_index..].char_indices() {
9290 if current_column == column {
9291 return Some(line_byte_index + byte_index);
9293 current_column += 1;
9300 pub struct CSSToken {
9301 pub text: nsCString,
9302 pub token_type: nsCString,
9304 pub unit: nsCString,
9305 pub has_number: bool,
9307 pub has_value: bool,
9308 pub value: nsCString,
9309 // line and column at which the token starts
9315 pub unsafe extern "C" fn Servo_CSSParser_create(
9317 ) -> *mut ParserState {
9318 let css_text = unsafe { text.as_str_unchecked() };
9319 let mut parser_input = ParserInput::new(&css_text);
9320 let input = Parser::new(&mut parser_input);
9321 Box::into_raw(Box::new(input.state()))
9325 pub unsafe extern "C" fn Servo_CSSParser_destroy(
9326 state: *mut ParserState,
9328 drop(Box::from_raw(state));
9332 pub unsafe extern "C" fn Servo_CSSParser_GetCurrentLine(
9333 state: &ParserState,
9335 return state.source_location().line;
9339 pub unsafe extern "C" fn Servo_CSSParser_GetCurrentColumn(
9340 state: &ParserState,
9342 return state.source_location().column;
9346 pub unsafe extern "C" fn Servo_CSSParser_NextToken(
9348 state: &mut ParserState,
9349 css_token: &mut CSSToken,
9351 let css_text = unsafe { text.as_str_unchecked() };
9352 let mut parser_input = ParserInput::new(&css_text);
9353 let mut input = Parser::new(&mut parser_input);
9356 let token_start = input.position();
9357 let location_start = state.source_location();
9358 let Ok(token) = &input.next_including_whitespace_and_comments() else {
9362 let token_type = match *token {
9363 Token::Ident(_) => "Ident",
9364 Token::AtKeyword(_) => "AtKeyword",
9365 Token::Hash(_) => "Hash",
9366 Token::IDHash(_) => "IDHash",
9367 Token::QuotedString(_) => "QuotedString",
9368 Token::UnquotedUrl(_) => "UnquotedUrl",
9369 Token::Delim(_) => "Delim",
9370 Token::Number{..} => "Number",
9371 Token::Percentage{..} => "Percentage",
9372 Token::Dimension{..} => "Dimension",
9373 Token::WhiteSpace(_) => "WhiteSpace",
9374 Token::Comment(_) => "Comment",
9375 Token::Colon => "Colon",
9376 Token::Semicolon => "Semicolon",
9377 Token::Comma => "Comma",
9378 Token::IncludeMatch => "IncludeMatch",
9379 Token::DashMatch => "DashMatch",
9380 Token::PrefixMatch => "PrefixMatch",
9381 Token::SuffixMatch => "SuffixMatch",
9382 Token::SubstringMatch => "SubstringMatch",
9383 Token::CDO => "CDO",
9384 Token::CDC => "CDC",
9385 Token::Function(_) => "Function",
9386 Token::ParenthesisBlock => "ParenthesisBlock",
9387 Token::SquareBracketBlock => "SquareBracketBlock",
9388 Token::CurlyBracketBlock => "CurlyBracketBlock",
9389 Token::BadUrl(_) => "BadUrl",
9390 Token::BadString(_) => "BadString",
9391 Token::CloseParenthesis => "CloseParenthesis",
9392 Token::CloseSquareBracket => "CloseSquareBracket",
9393 Token::CloseCurlyBracket => "CloseCurlyBracket",
9396 let token_value = match *token {
9397 Token::Ident(value) |
9398 Token::AtKeyword(value) |
9399 Token::Hash(value) |
9400 Token::IDHash(value) |
9401 Token::QuotedString(value) |
9402 Token::UnquotedUrl(value) |
9403 Token::Function(value) |
9404 Token::BadUrl(value) |
9405 Token::BadString(value) => {
9406 let mut text = nsCString::new();
9407 text.assign(value.as_bytes());
9410 // value is a str here, we need a different branch to handle it
9411 Token::Comment(value) => {
9412 let mut text = nsCString::new();
9413 text.assign(value.as_bytes());
9416 // Delim and WhiteSpace also have value, but they will be similar to text, so don't
9419 Token::WhiteSpace(_) |
9420 // Number, Percentage and Dimension expose numeric values that will be exposed in `number`
9422 Token::Percentage{..} |
9423 Token::Dimension{..} |
9424 // The rest of the tokens don't expose a string value
9428 Token::IncludeMatch |
9430 Token::PrefixMatch |
9431 Token::SuffixMatch |
9432 Token::SubstringMatch |
9435 Token::ParenthesisBlock |
9436 Token::SquareBracketBlock |
9437 Token::CurlyBracketBlock |
9438 Token::CloseParenthesis |
9439 Token::CloseSquareBracket |
9440 Token::CloseCurlyBracket => None
9443 let token_unit = match *token {
9447 let mut unit_text = nsCString::new();
9448 unit_text.assign(unit.as_bytes());
9454 let token_number = match *token {
9463 } => Some(unit_value),
9466 css_token.has_number = token_number.is_some();
9467 if css_token.has_number {
9468 css_token.number = *token_number.unwrap();
9471 let need_to_parse_nested_block = match *token {
9472 Token::Function(_) |
9473 Token::ParenthesisBlock |
9474 Token::CurlyBracketBlock |
9475 Token::SquareBracketBlock => true,
9479 let mut text = nsCString::new();
9480 text.assign(&input.slice_from(token_start));
9482 css_token.text = text;
9483 css_token.token_type = token_type.into();
9484 css_token.has_value = token_value.is_some();
9485 if css_token.has_value {
9486 css_token.value = token_value.unwrap();
9488 css_token.has_unit = token_unit.is_some();
9489 if css_token.has_unit {
9490 css_token.unit = token_unit.unwrap();
9493 css_token.line = location_start.line;
9494 css_token.column = location_start.column;
9496 if need_to_parse_nested_block {
9497 let _ = input.parse_nested_block(
9498 |i| -> Result<(), CssParseError<'_, BasicParseError>> {
9504 *state = input.state();