1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
5 use super::error_reporter::ErrorReporter;
6 use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader};
7 use bincode::{deserialize, serialize};
8 use cssparser::ToCss as ParserToCss;
9 use cssparser::{Parser, ParserInput, SourceLocation, UnicodeRange};
10 use dom::{DocumentState, ElementState};
11 use malloc_size_of::MallocSizeOfOps;
12 use nsstring::{nsCString, nsString};
13 use selectors::matching::{MatchingForInvalidation, SelectorCaches};
14 use servo_arc::{Arc, ArcBorrow};
15 use smallvec::SmallVec;
16 use style::values::generics::color::ColorMixFlags;
17 use std::collections::BTreeSet;
20 use std::os::raw::c_void;
22 use style::color::mix::ColorInterpolationMethod;
23 use style::color::{AbsoluteColor, ColorSpace};
24 use style::context::ThreadLocalStyleContext;
25 use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
26 use style::counter_style;
27 use style::data::{self, ElementStyles};
28 use style::dom::{ShowSubtreeData, TDocument, TElement, TNode};
30 use style::error_reporting::ParseErrorReporter;
31 use style::font_face::{self, FontFaceSourceFormat, FontFaceSourceListComponent, Source};
32 use style::gecko::arc_types::{
33 LockedCounterStyleRule, LockedCssRules, LockedDeclarationBlock, LockedFontFaceRule,
34 LockedImportRule, LockedKeyframe, LockedKeyframesRule, LockedMediaList, LockedPageRule,
37 use style::gecko::data::{
38 AuthorStyles, GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl,
40 use style::gecko::restyle_damage::GeckoRestyleDamage;
41 use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement};
42 use style::gecko::snapshot_helpers::classes_changed;
43 use style::gecko::traversal::RecalcStyleOnly;
44 use style::gecko::url;
45 use style::gecko::wrapper::{GeckoElement, GeckoNode};
46 use style::gecko_bindings::bindings;
47 use style::gecko_bindings::bindings::nsACString;
48 use style::gecko_bindings::bindings::nsAString;
49 use style::gecko_bindings::bindings::Gecko_AddPropertyToSet;
50 use style::gecko_bindings::bindings::Gecko_AppendPropertyValuePair;
51 use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet;
52 use style::gecko_bindings::bindings::Gecko_ConstructFontPaletteValueSet;
53 use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
54 use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
55 use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
56 use style::gecko_bindings::bindings::Gecko_HaveSeenPtr;
57 use style::gecko_bindings::structs;
58 use style::gecko_bindings::structs::GeckoFontMetrics;
59 use style::gecko_bindings::structs::gfx::FontPaletteValueSet;
60 use style::gecko_bindings::structs::gfxFontFeatureValueSet;
61 use style::gecko_bindings::structs::ipc::ByteBuf;
62 use style::gecko_bindings::structs::nsAtom;
63 use style::gecko_bindings::structs::nsCSSCounterDesc;
64 use style::gecko_bindings::structs::nsCSSFontDesc;
65 use style::gecko_bindings::structs::nsCSSPropertyID;
66 use style::gecko_bindings::structs::nsChangeHint;
67 use style::gecko_bindings::structs::nsCompatibility;
68 use style::gecko_bindings::structs::nsStyleTransformMatrix::MatrixTransformOperator;
69 use style::gecko_bindings::structs::nsTArray;
70 use style::gecko_bindings::structs::nsresult;
71 use style::gecko_bindings::structs::CallerType;
72 use style::gecko_bindings::structs::CompositeOperation;
73 use style::gecko_bindings::structs::DeclarationBlockMutationClosure;
74 use style::gecko_bindings::structs::IterationCompositeOperation;
75 use style::gecko_bindings::structs::Loader;
76 use style::gecko_bindings::structs::LoaderReusableStyleSheets;
77 use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf;
78 use style::gecko_bindings::structs::OriginFlags;
79 use style::gecko_bindings::structs::PropertyValuePair;
80 use style::gecko_bindings::structs::PseudoStyleType;
81 use style::gecko_bindings::structs::SeenPtrs;
82 use style::gecko_bindings::structs::ServoElementSnapshotTable;
83 use style::gecko_bindings::structs::ServoStyleSetSizes;
84 use style::gecko_bindings::structs::ServoTraversalFlags;
85 use style::gecko_bindings::structs::SheetLoadData;
86 use style::gecko_bindings::structs::SheetLoadDataHolder;
87 use style::gecko_bindings::structs::SheetParsingMode;
88 use style::gecko_bindings::structs::StyleRuleInclusion;
89 use style::gecko_bindings::structs::StyleSheet as DomStyleSheet;
90 use style::gecko_bindings::structs::URLExtraData;
91 use style::gecko_bindings::structs::{nsINode as RawGeckoNode, Element as RawGeckoElement};
92 use style::gecko_bindings::sugar::ownership::Strong;
93 use style::gecko_bindings::sugar::refptr::RefPtr;
94 use style::global_style_data::{
95 GlobalStyleData, PlatformThreadHandle, StyleThreadPool, GLOBAL_STYLE_DATA, STYLE_THREAD_POOL,
97 use style::invalidation::element::restyle_hints::RestyleHint;
98 use style::invalidation::stylesheets::RuleChangeKind;
99 use style::media_queries::MediaList;
100 use style::parser::{Parse, ParserContext};
101 use style::properties::animated_properties::{AnimationValue, AnimationValueMap};
102 use style::properties::{parse_one_declaration_into, parse_style_attribute};
103 use style::properties::{ComputedValues, CountedUnknownProperty, Importance, NonCustomPropertyId};
104 use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId};
105 use style::properties::{PropertyDeclarationId, ShorthandId};
106 use style::properties::{SourcePropertyDeclaration, StyleBuilder};
107 use style::properties_and_values::rule::Inherits as PropertyInherits;
108 use style::rule_cache::RuleCacheConditions;
109 use style::rule_tree::StrongRuleNode;
110 use style::selector_parser::PseudoElementCascadeType;
111 use style::shared_lock::{
112 Locked, SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard,
114 use style::string_cache::{Atom, WeakAtom};
115 use style::style_adjuster::StyleAdjuster;
116 use style::stylesheets::container_rule::ContainerSizeQuery;
117 use style::stylesheets::import_rule::{ImportLayer, ImportSheet};
118 use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
119 use style::stylesheets::supports_rule::parse_condition_or_declaration;
120 use style::stylesheets::{
121 AllowImportRules, ContainerRule, CounterStyleRule, CssRule, CssRuleType, CssRuleTypes,
122 CssRules, CssRulesHelpers, DocumentRule, FontFaceRule, FontFeatureValuesRule,
123 FontPaletteValuesRule, ImportRule, KeyframesRule, LayerBlockRule, LayerStatementRule,
124 MediaRule, NamespaceRule, Origin, OriginSet, PagePseudoClassFlags, PageRule, PropertyRule,
125 SanitizationData, SanitizationKind, StyleRule, StylesheetContents, StylesheetLoader as
126 StyleStylesheetLoader, SupportsRule, UrlExtraData,
128 use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
129 use style::thread_state;
130 use style::traversal::resolve_style;
131 use style::traversal::DomTraversal;
132 use style::traversal_flags::{self, TraversalFlags};
133 use style::use_counters::UseCounters;
134 use style::values::animated::{Animate, Procedure, ToAnimatedZero};
135 use style::values::computed::easing::ComputedTimingFunction;
136 use style::values::computed::effects::Filter;
137 use style::values::computed::font::{
138 FamilyName, FontFamily, FontFamilyList, FontStretch, FontStyle, FontWeight, GenericFontFamily,
140 use style::values::computed::{self, Context, ToComputedValue};
141 use style::values::distance::ComputeSquaredDistance;
142 use style::values::generics::easing::BeforeFlag;
143 use style::values::specified::gecko::IntersectionObserverRootMargin;
144 use style::values::specified::source_size_list::SourceSizeList;
145 use style::values::specified::{AbsoluteLength, NoCalcLength};
146 use style::values::{specified, AtomIdent, CustomIdent, KeyframesName};
147 use style_traits::{CssWriter, ParseError, ParsingMode, ToCss};
148 use thin_vec::ThinVec;
149 use to_shmem::SharedMemoryBuilder;
151 trait ClosureHelper {
152 fn invoke(&self, property_id: Option<NonCustomPropertyId>);
155 impl ClosureHelper for DeclarationBlockMutationClosure {
157 fn invoke(&self, property_id: Option<NonCustomPropertyId>) {
158 if let Some(function) = self.function.as_ref() {
159 let gecko_prop_id = match property_id {
160 Some(p) => p.to_nscsspropertyid(),
161 None => nsCSSPropertyID::eCSSPropertyExtra_variable,
163 unsafe { function(self.data, gecko_prop_id) }
169 * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
170 * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
171 * those signatures as well, giving us a second declaration of all the Servo_* functions in this
172 * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
173 * depend on but good enough for our purposes.
176 // A dummy url data for where we don't pass url data in.
177 static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut _;
178 static mut DUMMY_CHROME_URL_DATA: *mut URLExtraData = 0 as *mut _;
181 pub unsafe extern "C" fn Servo_Initialize(
182 dummy_url_data: *mut URLExtraData,
183 dummy_chrome_url_data: *mut URLExtraData,
185 use style::gecko_bindings::sugar::origin_flags;
187 // Pretend that we're a Servo Layout thread, to make some assertions happy.
188 thread_state::initialize(thread_state::ThreadState::LAYOUT);
190 // Perform some debug-only runtime assertions.
191 origin_flags::assert_flags_match();
192 traversal_flags::assert_traversal_flags_match();
193 specified::font::assert_variant_east_asian_matches();
194 specified::font::assert_variant_ligatures_matches();
196 DUMMY_URL_DATA = dummy_url_data;
197 DUMMY_CHROME_URL_DATA = dummy_chrome_url_data;
201 pub unsafe extern "C" fn Servo_Shutdown() {
202 DUMMY_URL_DATA = ptr::null_mut();
203 DUMMY_CHROME_URL_DATA = ptr::null_mut();
209 unsafe fn dummy_url_data() -> &'static UrlExtraData {
210 UrlExtraData::from_ptr_ref(&DUMMY_URL_DATA)
214 fn is_main_thread() -> bool {
215 unsafe { bindings::Gecko_IsMainThread() }
219 fn is_dom_worker_thread() -> bool {
220 unsafe { bindings::Gecko_IsDOMWorkerThread() }
224 /// Thread-local style data for DOM workers
225 static DOM_WORKER_RWLOCK: SharedRwLock = SharedRwLock::new();
229 fn is_in_servo_traversal() -> bool {
230 unsafe { bindings::Gecko_IsInServoTraversal() }
233 fn create_shared_context<'a>(
234 global_style_data: &GlobalStyleData,
235 guard: &'a SharedRwLockReadGuard,
236 stylist: &'a Stylist,
237 traversal_flags: TraversalFlags,
238 snapshot_map: &'a ServoElementSnapshotTable,
239 ) -> SharedStyleContext<'a> {
242 visited_styles_enabled: stylist.device().visited_styles_enabled(),
243 options: global_style_data.options.clone(),
244 guards: StylesheetGuards::same(guard),
245 current_time_for_animations: 0.0, // Unused for Gecko, at least for now.
252 element: GeckoElement,
253 global_style_data: &GlobalStyleData,
254 per_doc_data: &PerDocumentStyleDataImpl,
255 guard: &SharedRwLockReadGuard,
256 traversal_flags: TraversalFlags,
257 snapshots: &ServoElementSnapshotTable,
259 let shared_style_context = create_shared_context(
262 &per_doc_data.stylist,
267 let token = RecalcStyleOnly::pre_traverse(element, &shared_style_context);
269 if !token.should_traverse() {
273 debug!("Traversing subtree from {:?}", element);
275 let thread_pool_holder = &*STYLE_THREAD_POOL;
277 let thread_pool = if traversal_flags.contains(TraversalFlags::ParallelTraversal) {
278 pool = thread_pool_holder.pool();
284 let traversal = RecalcStyleOnly::new(shared_style_context);
285 driver::traverse_dom(&traversal, token, thread_pool);
288 /// Traverses the subtree rooted at `root` for restyling.
290 /// Returns whether the root was restyled. Whether anything else was restyled or
291 /// not can be inferred from the dirty bits in the rest of the tree.
293 pub extern "C" fn Servo_TraverseSubtree(
294 root: &RawGeckoElement,
295 raw_data: &PerDocumentStyleData,
296 snapshots: *const ServoElementSnapshotTable,
297 raw_flags: ServoTraversalFlags,
299 let traversal_flags = TraversalFlags::from_bits_truncate(raw_flags);
300 debug_assert!(!snapshots.is_null());
302 let element = GeckoElement(root);
304 debug!("Servo_TraverseSubtree (flags={:?})", traversal_flags);
305 debug!("{:?}", ShowSubtreeData(element.as_node()));
307 if cfg!(debug_assertions) {
308 if let Some(parent) = element.traversal_parent() {
311 .expect("Styling element with unstyled parent");
313 !data.styles.is_display_none(),
314 "Styling element with display: none parent"
319 let needs_animation_only_restyle =
320 element.has_animation_only_dirty_descendants() || element.has_animation_restyle_hints();
322 let per_doc_data = raw_data.borrow();
323 debug_assert!(!per_doc_data.stylist.stylesheets_have_changed());
325 let global_style_data = &*GLOBAL_STYLE_DATA;
326 let guard = global_style_data.shared_lock.read();
328 let was_initial_style = !element.has_data();
330 if needs_animation_only_restyle {
332 "Servo_TraverseSubtree doing animation-only restyle (aodd={})",
333 element.has_animation_only_dirty_descendants()
340 traversal_flags | TraversalFlags::AnimationOnly,
341 unsafe { &*snapshots },
351 unsafe { &*snapshots },
355 "Servo_TraverseSubtree complete (dd={}, aodd={}, lfcd={}, lfc={}, data={:?})",
356 element.has_dirty_descendants(),
357 element.has_animation_only_dirty_descendants(),
358 element.descendants_need_frames(),
359 element.needs_frame(),
360 element.borrow_data().unwrap()
363 if was_initial_style {
364 debug_assert!(!element.borrow_data().unwrap().contains_restyle_data());
367 let element_was_restyled = element.borrow_data().unwrap().contains_restyle_data();
372 /// Checks whether the rule tree has crossed its threshold for unused nodes, and
373 /// if so, frees them.
375 pub extern "C" fn Servo_MaybeGCRuleTree(raw_data: &PerDocumentStyleData) {
376 let per_doc_data = raw_data.borrow_mut();
377 per_doc_data.stylist.rule_tree().maybe_gc();
381 pub extern "C" fn Servo_AnimationValues_Interpolate(
382 from: &AnimationValue,
385 ) -> Strong<AnimationValue> {
386 if let Ok(value) = from.animate(to, Procedure::Interpolate { progress }) {
387 Arc::new(value).into()
394 pub extern "C" fn Servo_AnimationValues_IsInterpolable(
395 from: &AnimationValue,
398 from.animate(to, Procedure::Interpolate { progress: 0.5 })
403 pub extern "C" fn Servo_AnimationValues_Add(
406 ) -> Strong<AnimationValue> {
407 if let Ok(value) = a.animate(b, Procedure::Add) {
408 Arc::new(value).into()
415 pub extern "C" fn Servo_AnimationValues_Accumulate(
419 ) -> Strong<AnimationValue> {
420 if let Ok(value) = a.animate(b, Procedure::Accumulate { count }) {
421 Arc::new(value).into()
428 pub extern "C" fn Servo_AnimationValues_GetZeroValue(
429 value_to_match: &AnimationValue,
430 ) -> Strong<AnimationValue> {
431 if let Ok(zero_value) = value_to_match.to_animated_zero() {
432 Arc::new(zero_value).into()
439 pub extern "C" fn Servo_AnimationValues_ComputeDistance(
440 from: &AnimationValue,
443 // If compute_squared_distance() failed, this function will return negative value
444 // in order to check whether we support the specified paced animation values.
445 from.compute_squared_distance(to).map_or(-1.0, |d| d.sqrt())
448 /// Compute one of the endpoints for the interpolation interval, compositing it with the
449 /// underlying value if needed.
450 /// An None returned value means, "Just use endpoint_value as-is."
451 /// It is the responsibility of the caller to ensure that |underlying_value| is provided
452 /// when it will be used.
453 fn composite_endpoint(
454 endpoint_value: Option<&AnimationValue>,
455 composite: CompositeOperation,
456 underlying_value: Option<&AnimationValue>,
457 ) -> Option<AnimationValue> {
458 match endpoint_value {
459 Some(endpoint_value) => match composite {
460 CompositeOperation::Add => underlying_value
461 .expect("We should have an underlying_value")
462 .animate(endpoint_value, Procedure::Add)
464 CompositeOperation::Accumulate => underlying_value
465 .expect("We should have an underlying value")
466 .animate(endpoint_value, Procedure::Accumulate { count: 1 })
470 None => underlying_value.map(|v| v.clone()),
474 /// Accumulate one of the endpoints of the animation interval.
475 /// A returned value of None means, "Just use endpoint_value as-is."
476 fn accumulate_endpoint(
477 endpoint_value: Option<&AnimationValue>,
478 composited_value: Option<AnimationValue>,
479 last_value: &AnimationValue,
480 current_iteration: u64,
481 ) -> Option<AnimationValue> {
483 endpoint_value.is_some() || composited_value.is_some(),
484 "Should have a suitable value to use"
487 let count = current_iteration;
488 match composited_value {
489 Some(endpoint) => last_value
490 .animate(&endpoint, Procedure::Accumulate { count })
494 .animate(endpoint_value.unwrap(), Procedure::Accumulate { count })
499 /// Compose the animation segment. We composite it with the underlying_value and last_value if
501 /// The caller is responsible for providing an underlying value and last value
502 /// in all situations where there are needed.
503 fn compose_animation_segment(
504 segment: &structs::AnimationPropertySegment,
505 underlying_value: Option<&AnimationValue>,
506 last_value: Option<&AnimationValue>,
507 iteration_composite: IterationCompositeOperation,
508 current_iteration: u64,
510 segment_progress: f64,
511 ) -> AnimationValue {
512 // Extract keyframe values.
513 let keyframe_from_value = unsafe { segment.mFromValue.mServo.mRawPtr.as_ref() };
514 let keyframe_to_value = unsafe { segment.mToValue.mServo.mRawPtr.as_ref() };
515 let mut composited_from_value = composite_endpoint(
517 segment.mFromComposite,
520 let mut composited_to_value =
521 composite_endpoint(keyframe_to_value, segment.mToComposite, underlying_value);
524 keyframe_from_value.is_some() || composited_from_value.is_some(),
525 "Should have a suitable from value to use"
528 keyframe_to_value.is_some() || composited_to_value.is_some(),
529 "Should have a suitable to value to use"
532 // Apply iteration composite behavior.
533 if iteration_composite == IterationCompositeOperation::Accumulate && current_iteration > 0 {
534 let last_value = last_value
535 .unwrap_or_else(|| underlying_value.expect("Should have a valid underlying value"));
537 composited_from_value = accumulate_endpoint(
539 composited_from_value,
543 composited_to_value = accumulate_endpoint(
551 // Use the composited value if there is one, otherwise, use the original keyframe value.
552 let from = composited_from_value
554 .unwrap_or_else(|| keyframe_from_value.unwrap());
555 let to = composited_to_value
557 .unwrap_or_else(|| keyframe_to_value.unwrap());
559 if segment.mToKey == segment.mFromKey {
560 return if total_progress < 0. {
569 Procedure::Interpolate {
570 progress: segment_progress,
575 if segment_progress < 0.5 {
585 pub extern "C" fn Servo_ComposeAnimationSegment(
586 segment: &structs::AnimationPropertySegment,
587 underlying_value: Option<&AnimationValue>,
588 last_value: Option<&AnimationValue>,
589 iteration_composite: IterationCompositeOperation,
591 current_iteration: u64,
592 ) -> Strong<AnimationValue> {
593 let result = compose_animation_segment(
602 Arc::new(result).into()
606 pub extern "C" fn Servo_AnimationCompose(
607 value_map: &mut AnimationValueMap,
608 base_values: &structs::RawServoAnimationValueTable,
609 css_property: nsCSSPropertyID,
610 segment: &structs::AnimationPropertySegment,
611 last_segment: &structs::AnimationPropertySegment,
612 computed_timing: &structs::ComputedTiming,
613 iteration_composite: IterationCompositeOperation,
615 use style::gecko_bindings::bindings::Gecko_AnimationGetBaseStyle;
616 use style::gecko_bindings::bindings::Gecko_GetPositionInSegment;
617 use style::gecko_bindings::bindings::Gecko_GetProgressFromComputedTiming;
619 let property = match LonghandId::from_nscsspropertyid(css_property) {
620 Ok(longhand) if longhand.is_animatable() => longhand,
624 // We will need an underlying value if either of the endpoints is null...
625 let need_underlying_value = segment.mFromValue.mServo.mRawPtr.is_null() ||
626 segment.mToValue.mServo.mRawPtr.is_null() ||
627 // ... or if they have a non-replace composite mode ...
628 segment.mFromComposite != CompositeOperation::Replace ||
629 segment.mToComposite != CompositeOperation::Replace ||
630 // ... or if we accumulate onto the last value and it is null.
631 (iteration_composite == IterationCompositeOperation::Accumulate &&
632 computed_timing.mCurrentIteration > 0 &&
633 last_segment.mToValue.mServo.mRawPtr.is_null());
635 // If either of the segment endpoints are null, get the underlying value to
636 // use from the current value in the values map (set by a lower-priority
637 // effect), or, if there is no current value, look up the cached base value
638 // for this property.
639 let underlying_value = if need_underlying_value {
640 let previous_composed_value = value_map.get(&property).map(|v| &*v);
641 previous_composed_value
642 .or_else(|| unsafe { Gecko_AnimationGetBaseStyle(base_values, css_property).as_ref() })
647 if need_underlying_value && underlying_value.is_none() {
648 warn!("Underlying value should be valid when we expect to use it");
652 let last_value = unsafe { last_segment.mToValue.mServo.mRawPtr.as_ref() };
653 let progress = unsafe { Gecko_GetProgressFromComputedTiming(computed_timing) };
654 let position = if segment.mToKey == segment.mFromKey {
655 // Note: compose_animation_segment doesn't use this value
656 // if segment.mFromKey == segment.mToKey, so assigning |progress| directly is fine.
659 unsafe { Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag) }
662 let result = compose_animation_segment(
667 computed_timing.mCurrentIteration,
671 value_map.insert(property, result);
674 macro_rules! get_property_id_from_nscsspropertyid {
675 ($property_id: ident, $ret: expr) => {{
676 match PropertyId::from_nscsspropertyid($property_id) {
677 Ok(property_id) => property_id,
686 pub extern "C" fn Servo_AnimationValue_Serialize(
687 value: &AnimationValue,
688 property: nsCSSPropertyID,
689 raw_data: &PerDocumentStyleData,
690 buffer: &mut nsACString,
692 let uncomputed_value = value.uncompute();
693 let data = raw_data.borrow();
694 let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
695 .single_value_to_css(
696 &get_property_id_from_nscsspropertyid!(property, ()),
699 None, /* No extra custom properties */
702 debug_assert!(rv.is_ok());
705 /// Debug: MOZ_DBG for AnimationValue.
707 pub extern "C" fn Servo_AnimationValue_Dump(value: &AnimationValue, result: &mut nsACString) {
708 write!(result, "{:?}", value).unwrap();
712 pub extern "C" fn Servo_AnimationValue_GetColor(
713 value: &AnimationValue,
714 foreground_color: structs::nscolor,
715 ) -> structs::nscolor {
716 use style::gecko::values::{
717 convert_absolute_color_to_nscolor, convert_nscolor_to_absolute_color,
719 use style::values::computed::color::Color as ComputedColor;
721 AnimationValue::BackgroundColor(ref color) => {
722 let computed: ComputedColor = color.clone();
723 let foreground_color = convert_nscolor_to_absolute_color(foreground_color);
724 convert_absolute_color_to_nscolor(&computed.resolve_to_absolute(&foreground_color))
726 _ => panic!("Other color properties are not supported yet"),
731 pub extern "C" fn Servo_AnimationValue_IsCurrentColor(value: &AnimationValue) -> bool {
733 AnimationValue::BackgroundColor(ref color) => color.is_currentcolor(),
735 debug_assert!(false, "Other color properties are not supported yet");
742 pub extern "C" fn Servo_AnimationValue_GetOpacity(value: &AnimationValue) -> f32 {
743 if let AnimationValue::Opacity(opacity) = *value {
746 panic!("The AnimationValue should be Opacity");
751 pub extern "C" fn Servo_AnimationValue_Opacity(opacity: f32) -> Strong<AnimationValue> {
752 Arc::new(AnimationValue::Opacity(opacity)).into()
756 pub extern "C" fn Servo_AnimationValue_Color(
757 color_property: nsCSSPropertyID,
758 color: structs::nscolor,
759 ) -> Strong<AnimationValue> {
760 use style::gecko::values::convert_nscolor_to_absolute_color;
761 use style::values::animated::color::Color;
763 let property = LonghandId::from_nscsspropertyid(color_property)
764 .expect("We don't have shorthand property animation value");
766 let animated = convert_nscolor_to_absolute_color(color);
769 LonghandId::BackgroundColor => {
770 Arc::new(AnimationValue::BackgroundColor(Color::Absolute(animated))).into()
772 _ => panic!("Should be background-color property"),
777 pub unsafe extern "C" fn Servo_AnimationValue_GetScale(
778 value: &AnimationValue,
779 ) -> *const computed::Scale {
781 AnimationValue::Scale(ref value) => value,
782 _ => unreachable!("Expected scale"),
787 pub unsafe extern "C" fn Servo_AnimationValue_GetTranslate(
788 value: &AnimationValue,
789 ) -> *const computed::Translate {
791 AnimationValue::Translate(ref value) => value,
792 _ => unreachable!("Expected translate"),
797 pub unsafe extern "C" fn Servo_AnimationValue_GetRotate(
798 value: &AnimationValue,
799 ) -> *const computed::Rotate {
801 AnimationValue::Rotate(ref value) => value,
802 _ => unreachable!("Expected rotate"),
807 pub unsafe extern "C" fn Servo_AnimationValue_GetTransform(
808 value: &AnimationValue,
809 ) -> *const computed::Transform {
811 AnimationValue::Transform(ref value) => value,
812 _ => unreachable!("Unsupported transform animation value"),
817 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPath(
818 value: &AnimationValue,
819 output: &mut computed::motion::OffsetPath,
821 use style::values::animated::ToAnimatedValue;
823 AnimationValue::OffsetPath(ref value) => {
824 *output = ToAnimatedValue::from_animated_value(value.clone())
826 _ => unreachable!("Expected offset-path"),
831 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetDistance(
832 value: &AnimationValue,
833 ) -> *const computed::LengthPercentage {
835 AnimationValue::OffsetDistance(ref value) => value,
836 _ => unreachable!("Expected offset-distance"),
841 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetRotate(
842 value: &AnimationValue,
843 ) -> *const computed::motion::OffsetRotate {
845 AnimationValue::OffsetRotate(ref value) => value,
846 _ => unreachable!("Expected offset-rotate"),
851 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetAnchor(
852 value: &AnimationValue,
853 ) -> *const computed::position::PositionOrAuto {
855 AnimationValue::OffsetAnchor(ref value) => value,
856 _ => unreachable!("Expected offset-anchor"),
861 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPosition(
862 value: &AnimationValue,
863 ) -> *const computed::motion::OffsetPosition {
865 AnimationValue::OffsetPosition(ref value) => value,
866 _ => unreachable!("Expected offset-position"),
871 pub unsafe extern "C" fn Servo_AnimationValue_IsOffsetPathUrl(
872 value: &AnimationValue,
874 use style::values::generics::motion::{GenericOffsetPath, GenericOffsetPathFunction};
875 if let AnimationValue::OffsetPath(ref op) = value {
876 if let GenericOffsetPath::OffsetPath { path, coord_box: _ } = op {
877 return matches!(**path, GenericOffsetPathFunction::Url(_));
884 pub unsafe extern "C" fn Servo_AnimationValue_Rotate(
885 r: &computed::Rotate,
886 ) -> Strong<AnimationValue> {
887 Arc::new(AnimationValue::Rotate(r.clone())).into()
891 pub unsafe extern "C" fn Servo_AnimationValue_Translate(
892 t: &computed::Translate,
893 ) -> Strong<AnimationValue> {
894 Arc::new(AnimationValue::Translate(t.clone())).into()
898 pub unsafe extern "C" fn Servo_AnimationValue_Scale(s: &computed::Scale) -> Strong<AnimationValue> {
899 Arc::new(AnimationValue::Scale(s.clone())).into()
903 pub unsafe extern "C" fn Servo_AnimationValue_Transform(
904 transform: &computed::Transform,
905 ) -> Strong<AnimationValue> {
906 Arc::new(AnimationValue::Transform(transform.clone())).into()
910 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPath(
911 p: &computed::motion::OffsetPath,
912 ) -> Strong<AnimationValue> {
913 use style::values::animated::ToAnimatedValue;
914 Arc::new(AnimationValue::OffsetPath(p.clone().to_animated_value())).into()
918 pub unsafe extern "C" fn Servo_AnimationValue_OffsetDistance(
919 d: &computed::LengthPercentage,
920 ) -> Strong<AnimationValue> {
921 Arc::new(AnimationValue::OffsetDistance(d.clone())).into()
925 pub unsafe extern "C" fn Servo_AnimationValue_OffsetRotate(
926 r: &computed::motion::OffsetRotate,
927 ) -> Strong<AnimationValue> {
928 Arc::new(AnimationValue::OffsetRotate(*r)).into()
932 pub unsafe extern "C" fn Servo_AnimationValue_OffsetAnchor(
933 p: &computed::position::PositionOrAuto,
934 ) -> Strong<AnimationValue> {
935 Arc::new(AnimationValue::OffsetAnchor(p.clone())).into()
939 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPosition(
940 p: &computed::motion::OffsetPosition,
941 ) -> Strong<AnimationValue> {
942 Arc::new(AnimationValue::OffsetPosition(p.clone())).into()
946 pub extern "C" fn Servo_AnimationValue_DeepEqual(
947 this: &AnimationValue,
948 other: &AnimationValue,
954 pub extern "C" fn Servo_AnimationValue_Uncompute(
955 value: &AnimationValue,
956 ) -> Strong<LockedDeclarationBlock> {
957 let global_style_data = &*GLOBAL_STYLE_DATA;
961 .wrap(PropertyDeclarationBlock::with_one(
970 fn create_byte_buf_from_vec(mut v: Vec<u8>) -> ByteBuf {
972 mData: v.as_mut_ptr(),
974 mCapacity: v.capacity(),
981 fn view_byte_buf(b: &ByteBuf) -> &[u8] {
982 if b.mData.is_null() {
983 debug_assert_eq!(b.mCapacity, 0);
986 unsafe { std::slice::from_raw_parts(b.mData, b.mLen) }
989 macro_rules! impl_basic_serde_funcs {
990 ($ser_name:ident, $de_name:ident, $computed_type:ty) => {
992 pub extern "C" fn $ser_name(v: &$computed_type, output: &mut ByteBuf) -> bool {
993 let buf = match serialize(v) {
995 Err(..) => return false,
998 *output = create_byte_buf_from_vec(buf);
1003 pub unsafe extern "C" fn $de_name(input: &ByteBuf, v: *mut $computed_type) -> bool {
1004 let buf = match deserialize(view_byte_buf(input)) {
1006 Err(..) => return false,
1009 std::ptr::write(v, buf);
1015 impl_basic_serde_funcs!(
1016 Servo_LengthPercentage_Serialize,
1017 Servo_LengthPercentage_Deserialize,
1018 computed::LengthPercentage
1021 impl_basic_serde_funcs!(
1022 Servo_StyleRotate_Serialize,
1023 Servo_StyleRotate_Deserialize,
1024 computed::transform::Rotate
1027 impl_basic_serde_funcs!(
1028 Servo_StyleScale_Serialize,
1029 Servo_StyleScale_Deserialize,
1030 computed::transform::Scale
1033 impl_basic_serde_funcs!(
1034 Servo_StyleTranslate_Serialize,
1035 Servo_StyleTranslate_Deserialize,
1036 computed::transform::Translate
1039 impl_basic_serde_funcs!(
1040 Servo_StyleTransform_Serialize,
1041 Servo_StyleTransform_Deserialize,
1042 computed::transform::Transform
1045 impl_basic_serde_funcs!(
1046 Servo_StyleOffsetPath_Serialize,
1047 Servo_StyleOffsetPath_Deserialize,
1048 computed::motion::OffsetPath
1051 impl_basic_serde_funcs!(
1052 Servo_StyleOffsetRotate_Serialize,
1053 Servo_StyleOffsetRotate_Deserialize,
1054 computed::motion::OffsetRotate
1057 impl_basic_serde_funcs!(
1058 Servo_StylePositionOrAuto_Serialize,
1059 Servo_StylePositionOrAuto_Deserialize,
1060 computed::position::PositionOrAuto
1063 impl_basic_serde_funcs!(
1064 Servo_StyleOffsetPosition_Serialize,
1065 Servo_StyleOffsetPosition_Deserialize,
1066 computed::motion::OffsetPosition
1069 impl_basic_serde_funcs!(
1070 Servo_StyleComputedTimingFunction_Serialize,
1071 Servo_StyleComputedTimingFunction_Deserialize,
1072 ComputedTimingFunction
1075 // Return the ComputedValues by a base ComputedValues and the rules.
1076 fn resolve_rules_for_element_with_context<'a>(
1077 element: GeckoElement<'a>,
1078 mut context: StyleContext<GeckoElement<'a>>,
1079 rules: StrongRuleNode,
1080 original_computed_values: &ComputedValues,
1081 ) -> Arc<ComputedValues> {
1082 use style::style_resolver::{PseudoElementResolution, StyleResolverForElement};
1084 // This currently ignores visited styles, which seems acceptable, as
1085 // existing browsers don't appear to animate visited styles.
1086 let inputs = CascadeInputs {
1088 visited_rules: None,
1089 flags: original_computed_values.flags.for_cascade_inputs(),
1092 // Actually `PseudoElementResolution` doesn't matter.
1093 let mut resolver = StyleResolverForElement::new(
1097 PseudoElementResolution::IfApplicable,
1100 .cascade_style_and_visited_with_default_parents(inputs)
1105 pub extern "C" fn Servo_AnimationValueMap_Create() -> *mut AnimationValueMap {
1106 Box::into_raw(Box::default())
1110 pub unsafe extern "C" fn Servo_AnimationValueMap_Drop(value_map: *mut AnimationValueMap) {
1111 let _ = Box::from_raw(value_map);
1115 pub extern "C" fn Servo_AnimationValueMap_GetValue(
1116 value_map: &AnimationValueMap,
1117 property_id: nsCSSPropertyID,
1118 ) -> Strong<AnimationValue> {
1119 let property = match LonghandId::from_nscsspropertyid(property_id) {
1120 Ok(longhand) => longhand,
1121 Err(()) => return Strong::null(),
1125 .map_or(Strong::null(), |value| Arc::new(value.clone()).into())
1129 pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(
1130 raw_style_set: &PerDocumentStyleData,
1131 element: &RawGeckoElement,
1132 computed_values: &ComputedValues,
1133 snapshots: *const ServoElementSnapshotTable,
1134 ) -> Strong<ComputedValues> {
1135 debug_assert!(!snapshots.is_null());
1136 let computed_values = unsafe { ArcBorrow::from_ref(computed_values) };
1138 let rules = match computed_values.rules {
1139 None => return computed_values.clone_arc().into(),
1140 Some(ref rules) => rules,
1143 let doc_data = raw_style_set.borrow();
1144 let without_animations_rules = doc_data.stylist.rule_tree().remove_animation_rules(rules);
1145 if without_animations_rules == *rules {
1146 return computed_values.clone_arc().into();
1149 let element = GeckoElement(element);
1151 let global_style_data = &*GLOBAL_STYLE_DATA;
1152 let guard = global_style_data.shared_lock.read();
1153 let shared = create_shared_context(
1157 TraversalFlags::empty(),
1158 unsafe { &*snapshots },
1160 let mut tlc = ThreadLocalStyleContext::new();
1161 let context = StyleContext {
1163 thread_local: &mut tlc,
1166 resolve_rules_for_element_with_context(
1169 without_animations_rules,
1176 pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue(
1177 computed_values: &ComputedValues,
1178 property_id: nsCSSPropertyID,
1179 ) -> Strong<AnimationValue> {
1180 let property = match LonghandId::from_nscsspropertyid(property_id) {
1181 Ok(longhand) => longhand,
1182 Err(()) => return Strong::null(),
1184 match AnimationValue::from_computed_values(property, &computed_values) {
1185 Some(v) => Arc::new(v).into(),
1186 None => Strong::null(),
1191 pub extern "C" fn Servo_ResolveLogicalProperty(
1192 property_id: nsCSSPropertyID,
1193 style: &ComputedValues,
1194 ) -> nsCSSPropertyID {
1195 let longhand = LonghandId::from_nscsspropertyid(property_id)
1196 .expect("We shouldn't need to care about shorthands");
1199 .to_physical(style.writing_mode)
1200 .to_nscsspropertyid()
1204 pub unsafe extern "C" fn Servo_Property_LookupEnabledForAllContent(
1206 ) -> nsCSSPropertyID {
1207 match PropertyId::parse_enabled_for_all_content(prop.as_str_unchecked()) {
1208 Ok(p) => p.to_nscsspropertyid_resolving_aliases(),
1209 Err(..) => nsCSSPropertyID::eCSSProperty_UNKNOWN,
1214 pub unsafe extern "C" fn Servo_Property_GetName(
1215 prop: nsCSSPropertyID,
1216 out_length: *mut u32,
1218 let (ptr, len) = match NonCustomPropertyId::from_nscsspropertyid(prop) {
1220 let name = p.name();
1221 (name.as_bytes().as_ptr(), name.len())
1223 Err(..) => (ptr::null(), 0),
1226 *out_length = len as u32;
1230 macro_rules! parse_enabled_property_name {
1231 ($prop_name:ident, $found:ident, $default:expr) => {{
1232 let prop_name = $prop_name.as_str_unchecked();
1233 match PropertyId::parse_enabled_for_all_content(prop_name) {
1247 pub unsafe extern "C" fn Servo_Property_IsShorthand(
1248 prop_name: &nsACString,
1251 let prop_id = parse_enabled_property_name!(prop_name, found, false);
1252 prop_id.is_shorthand()
1256 pub unsafe extern "C" fn Servo_Property_IsInherited(prop_name: &nsACString) -> bool {
1257 let prop_name = prop_name.as_str_unchecked();
1258 let prop_id = match PropertyId::parse_enabled_for_all_content(prop_name) {
1260 Err(_) => return false,
1262 let longhand_id = match prop_id {
1263 PropertyId::Custom(_) => return true,
1264 PropertyId::Longhand(id) | PropertyId::LonghandAlias(id, _) => id,
1265 PropertyId::Shorthand(id) | PropertyId::ShorthandAlias(id, _) => {
1266 id.longhands().next().unwrap()
1269 longhand_id.inherited()
1273 pub unsafe extern "C" fn Servo_Property_SupportsType(
1274 prop_name: &nsACString,
1278 let prop_id = parse_enabled_property_name!(prop_name, found, false);
1279 prop_id.supports_type(ty)
1282 // TODO(emilio): We could use ThinVec instead of nsTArray.
1284 pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty(
1285 prop_name: &nsACString,
1287 result: &mut nsTArray<nsString>,
1289 let prop_id = parse_enabled_property_name!(prop_name, found, ());
1290 // Use B-tree set for unique and sorted result.
1291 let mut values = BTreeSet::<&'static str>::new();
1292 prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter()));
1294 let mut extras = vec![];
1295 if values.contains("transparent") {
1296 // This is a special value devtools use to avoid inserting the
1297 // long list of color keywords. We need to prepend it to values.
1298 extras.push("COLOR");
1301 let len = extras.len() + values.len();
1302 bindings::Gecko_ResizeTArrayForStrings(result, len as u32);
1304 for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) {
1305 dest.write_str(src).unwrap();
1310 pub extern "C" fn Servo_Property_IsAnimatable(prop: nsCSSPropertyID) -> bool {
1311 NonCustomPropertyId::from_nscsspropertyid(prop)
1313 .map_or(false, |p| p.is_animatable())
1317 pub extern "C" fn Servo_Property_IsTransitionable(prop: nsCSSPropertyID) -> bool {
1318 NonCustomPropertyId::from_nscsspropertyid(prop)
1320 .map_or(false, |p| p.is_transitionable())
1324 pub extern "C" fn Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID) -> bool {
1325 match LonghandId::from_nscsspropertyid(property) {
1326 Ok(longhand) => longhand.is_discrete_animatable(),
1327 Err(()) => return false,
1332 pub extern "C" fn Servo_Element_ClearData(element: &RawGeckoElement) {
1333 unsafe { GeckoElement(element).clear_data() };
1337 pub extern "C" fn Servo_Element_SizeOfExcludingThisAndCVs(
1338 malloc_size_of: GeckoMallocSizeOf,
1339 malloc_enclosing_size_of: GeckoMallocSizeOf,
1340 seen_ptrs: *mut SeenPtrs,
1341 element: &RawGeckoElement,
1343 let element = GeckoElement(element);
1344 let borrow = element.borrow_data();
1345 if let Some(data) = borrow {
1346 let have_seen_ptr = move |ptr| unsafe { Gecko_HaveSeenPtr(seen_ptrs, ptr) };
1347 let mut ops = MallocSizeOfOps::new(
1348 malloc_size_of.unwrap(),
1349 Some(malloc_enclosing_size_of.unwrap()),
1350 Some(Box::new(have_seen_ptr)),
1352 (*data).size_of_excluding_cvs(&mut ops)
1359 pub extern "C" fn Servo_Element_GetMaybeOutOfDateStyle(
1360 element: &RawGeckoElement,
1361 ) -> *const ComputedValues {
1362 let element = GeckoElement(element);
1363 let data = match element.borrow_data() {
1365 None => return ptr::null(),
1367 &**data.styles.primary() as *const _
1371 pub extern "C" fn Servo_Element_GetMaybeOutOfDatePseudoStyle(
1372 element: &RawGeckoElement,
1374 ) -> *const ComputedValues {
1375 let element = GeckoElement(element);
1376 let data = match element.borrow_data() {
1378 None => return ptr::null(),
1380 match data.styles.pseudos.as_array()[index].as_ref() {
1381 Some(style) => &**style as *const _,
1382 None => ptr::null(),
1387 pub extern "C" fn Servo_Element_IsDisplayNone(element: &RawGeckoElement) -> bool {
1388 let element = GeckoElement(element);
1391 .expect("Invoking Servo_Element_IsDisplayNone on unstyled element");
1393 // This function is hot, so we bypass the AtomicRefCell.
1395 // It would be nice to also assert that we're not in the servo traversal,
1396 // but this function is called at various intermediate checkpoints when
1397 // managing the traversal on the Gecko side.
1398 debug_assert!(is_main_thread());
1399 unsafe { &*data.as_ptr() }.styles.is_display_none()
1403 pub extern "C" fn Servo_Element_IsDisplayContents(element: &RawGeckoElement) -> bool {
1404 let element = GeckoElement(element);
1407 .expect("Invoking Servo_Element_IsDisplayContents on unstyled element");
1409 debug_assert!(is_main_thread());
1410 unsafe { &*data.as_ptr() }
1419 pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGeckoElement) -> bool {
1420 let element = GeckoElement(element);
1423 .expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element");
1425 .contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
1428 fn mode_to_origin(mode: SheetParsingMode) -> Origin {
1430 SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
1431 SheetParsingMode::eUserSheetFeatures => Origin::User,
1432 SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
1437 pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> Strong<StylesheetContents> {
1438 let global_style_data = &*GLOBAL_STYLE_DATA;
1439 let origin = mode_to_origin(mode);
1440 let shared_lock = &global_style_data.shared_lock;
1441 StylesheetContents::from_str(
1443 unsafe { dummy_url_data() }.clone(),
1446 /* loader = */ None,
1448 QuirksMode::NoQuirks,
1449 /* use_counters = */ None,
1450 AllowImportRules::Yes,
1451 /* sanitization_data = */ None,
1456 /// Note: The load_data corresponds to this sheet, and is passed as the parent
1457 /// load data for child sheet loads. It may be null for certain cases where we
1458 /// know we won't have child loads.
1460 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8Bytes(
1461 loader: *mut Loader,
1462 stylesheet: *mut DomStyleSheet,
1463 load_data: *mut SheetLoadData,
1465 mode: SheetParsingMode,
1466 extra_data: *mut URLExtraData,
1467 quirks_mode: nsCompatibility,
1468 reusable_sheets: *mut LoaderReusableStyleSheets,
1469 use_counters: Option<&UseCounters>,
1470 allow_import_rules: AllowImportRules,
1471 sanitization_kind: SanitizationKind,
1472 sanitized_output: Option<&mut nsAString>,
1473 ) -> Strong<StylesheetContents> {
1474 let global_style_data = &*GLOBAL_STYLE_DATA;
1475 let input = bytes.as_str_unchecked();
1477 let reporter = ErrorReporter::new(stylesheet, loader, extra_data);
1478 let url_data = UrlExtraData::from_ptr_ref(&extra_data);
1479 let loader = if loader.is_null() {
1483 sanitized_output.is_none(),
1484 "Shouldn't trigger @import loads for sanitization",
1486 Some(StylesheetLoader::new(
1494 // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
1495 let loader: Option<&dyn StyleStylesheetLoader> = match loader {
1497 Some(ref s) => Some(s),
1500 let mut sanitization_data = SanitizationData::new(sanitization_kind);
1502 let contents = StylesheetContents::from_str(
1505 mode_to_origin(mode),
1506 &global_style_data.shared_lock,
1508 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
1512 sanitization_data.as_mut(),
1515 if let Some(data) = sanitization_data {
1518 .assign_utf8(data.take().as_bytes());
1525 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
1526 load_data: *mut SheetLoadDataHolder,
1527 extra_data: *mut URLExtraData,
1529 mode: SheetParsingMode,
1530 quirks_mode: nsCompatibility,
1531 should_record_use_counters: bool,
1532 allow_import_rules: AllowImportRules,
1534 let load_data = RefPtr::new(load_data);
1535 let extra_data = UrlExtraData::new(extra_data);
1537 let mut sheet_bytes = nsCString::new();
1538 sheet_bytes.assign(bytes);
1540 let async_parser = AsyncStylesheetParser::new(
1544 mode_to_origin(mode),
1546 should_record_use_counters,
1550 if let Some(thread_pool) = STYLE_THREAD_POOL.pool().as_ref() {
1551 thread_pool.spawn(|| {
1552 gecko_profiler_label!(Layout, CSSParsing);
1553 async_parser.parse();
1556 async_parser.parse();
1561 pub unsafe extern "C" fn Servo_ShutdownThreadPool() {
1562 debug_assert!(is_main_thread() && !is_in_servo_traversal());
1563 StyleThreadPool::shutdown();
1567 pub unsafe extern "C" fn Servo_ThreadPool_GetThreadHandles(handles: &mut ThinVec<PlatformThreadHandle>) {
1568 StyleThreadPool::get_thread_handles(handles);
1572 pub unsafe extern "C" fn Servo_StyleSheet_FromSharedData(
1573 extra_data: *mut URLExtraData,
1574 shared_rules: &LockedCssRules,
1575 ) -> Strong<StylesheetContents> {
1576 StylesheetContents::from_shared_data(
1577 Arc::from_raw_addrefed(shared_rules),
1579 UrlExtraData::new(extra_data),
1580 QuirksMode::NoQuirks,
1586 pub extern "C" fn Servo_StyleSet_AppendStyleSheet(
1587 raw_data: &PerDocumentStyleData,
1588 sheet: *const DomStyleSheet,
1590 let global_style_data = &*GLOBAL_STYLE_DATA;
1591 let mut data = raw_data.borrow_mut();
1592 let data = &mut *data;
1593 let guard = global_style_data.shared_lock.read();
1594 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1595 data.stylist.append_stylesheet(sheet, &guard);
1599 pub extern "C" fn Servo_AuthorStyles_Create() -> *mut AuthorStyles {
1600 Box::into_raw(Box::new(AuthorStyles::new()))
1604 pub unsafe extern "C" fn Servo_AuthorStyles_Drop(styles: *mut AuthorStyles) {
1605 let _ = Box::from_raw(styles);
1609 pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet(
1610 styles: &mut AuthorStyles,
1611 sheet: *const DomStyleSheet,
1613 let global_style_data = &*GLOBAL_STYLE_DATA;
1614 let guard = global_style_data.shared_lock.read();
1615 let sheet = GeckoStyleSheet::new(sheet);
1616 styles.stylesheets.append_stylesheet(None, sheet, &guard);
1620 pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore(
1621 styles: &mut AuthorStyles,
1622 sheet: *const DomStyleSheet,
1623 before_sheet: *const DomStyleSheet,
1625 let global_style_data = &*GLOBAL_STYLE_DATA;
1626 let guard = global_style_data.shared_lock.read();
1627 styles.stylesheets.insert_stylesheet_before(
1629 GeckoStyleSheet::new(sheet),
1630 GeckoStyleSheet::new(before_sheet),
1636 pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet(
1637 styles: &mut AuthorStyles,
1638 sheet: *const DomStyleSheet,
1640 let global_style_data = &*GLOBAL_STYLE_DATA;
1641 let guard = global_style_data.shared_lock.read();
1644 .remove_stylesheet(None, GeckoStyleSheet::new(sheet), &guard);
1648 pub extern "C" fn Servo_AuthorStyles_ForceDirty(styles: &mut AuthorStyles) {
1649 styles.stylesheets.force_dirty();
1653 pub extern "C" fn Servo_AuthorStyles_IsDirty(styles: &AuthorStyles) -> bool {
1654 styles.stylesheets.dirty()
1658 pub extern "C" fn Servo_AuthorStyles_Flush(
1659 styles: &mut AuthorStyles,
1660 document_set: &PerDocumentStyleData,
1662 // Try to avoid the atomic borrow below if possible.
1663 if !styles.stylesheets.dirty() {
1667 let global_style_data = &*GLOBAL_STYLE_DATA;
1668 let guard = global_style_data.shared_lock.read();
1670 let mut document_data = document_set.borrow_mut();
1672 // TODO(emilio): This is going to need an element or something to do proper
1673 // invalidation in Shadow roots.
1674 styles.flush::<GeckoElement>(&mut document_data.stylist, &guard);
1678 pub extern "C" fn Servo_StyleSet_RemoveUniqueEntriesFromAuthorStylesCache(
1679 document_set: &PerDocumentStyleData,
1681 let mut document_data = document_set.borrow_mut();
1684 .remove_unique_author_data_cache_entries();
1688 pub unsafe extern "C" fn Servo_DeclarationBlock_SizeOfIncludingThis(
1689 malloc_size_of: GeckoMallocSizeOf,
1690 malloc_enclosing_size_of: GeckoMallocSizeOf,
1691 declarations: &LockedDeclarationBlock,
1693 use malloc_size_of::MallocSizeOf;
1694 use malloc_size_of::MallocUnconditionalShallowSizeOf;
1696 let global_style_data = &*GLOBAL_STYLE_DATA;
1697 let guard = global_style_data.shared_lock.read();
1699 let mut ops = MallocSizeOfOps::new(
1700 malloc_size_of.unwrap(),
1701 Some(malloc_enclosing_size_of.unwrap()),
1705 ArcBorrow::from_ref(declarations).with_arc(|declarations| {
1707 n += declarations.unconditional_shallow_size_of(&mut ops);
1708 n += declarations.read_with(&guard).size_of(&mut ops);
1714 pub unsafe extern "C" fn Servo_AuthorStyles_SizeOfIncludingThis(
1715 malloc_size_of: GeckoMallocSizeOf,
1716 malloc_enclosing_size_of: GeckoMallocSizeOf,
1717 styles: &AuthorStyles,
1719 // We cannot `use` MallocSizeOf at the top level, otherwise the compiler
1720 // would complain in `Servo_StyleSheet_SizeOfIncludingThis` for `size_of`
1722 use malloc_size_of::MallocSizeOf;
1723 let malloc_size_of = malloc_size_of.unwrap();
1724 let malloc_size_of_this = malloc_size_of(styles as *const AuthorStyles as *const c_void);
1726 let mut ops = MallocSizeOfOps::new(
1728 Some(malloc_enclosing_size_of.unwrap()),
1731 malloc_size_of_this + styles.size_of(&mut ops)
1735 pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged(
1736 document_set: &PerDocumentStyleData,
1737 non_document_styles: &mut nsTArray<&mut AuthorStyles>,
1738 may_affect_default_style: bool,
1739 ) -> structs::MediumFeaturesChangedResult {
1740 let global_style_data = &*GLOBAL_STYLE_DATA;
1741 let guard = global_style_data.shared_lock.read();
1743 // NOTE(emilio): We don't actually need to flush the stylist here and ensure
1746 // In case it isn't we would trigger a rebuild + restyle as needed too.
1748 // We need to ensure the default computed values are up to date though,
1749 // because those can influence the result of media query evaluation.
1750 let mut document_data = document_set.borrow_mut();
1752 if may_affect_default_style {
1753 document_data.stylist.device_mut().reset_computed_values();
1755 let guards = StylesheetGuards::same(&guard);
1757 let origins_in_which_rules_changed = document_data
1759 .media_features_change_changed_style(&guards, document_data.stylist.device());
1761 let affects_document_rules = !origins_in_which_rules_changed.is_empty();
1762 if affects_document_rules {
1765 .force_stylesheet_origins_dirty(origins_in_which_rules_changed);
1768 let mut affects_non_document_rules = false;
1769 for author_styles in &mut **non_document_styles {
1770 let affected_style = author_styles.stylesheets.iter().any(|sheet| {
1771 !author_styles.data.media_feature_affected_matches(
1774 document_data.stylist.device(),
1775 document_data.stylist.quirks_mode(),
1779 affects_non_document_rules = true;
1780 author_styles.stylesheets.force_dirty();
1784 structs::MediumFeaturesChangedResult {
1785 mAffectsDocumentRules: affects_document_rules,
1786 mAffectsNonDocumentRules: affects_non_document_rules,
1791 pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(
1792 raw_data: &PerDocumentStyleData,
1793 sheet: *const DomStyleSheet,
1794 before_sheet: *const DomStyleSheet,
1796 let global_style_data = &*GLOBAL_STYLE_DATA;
1797 let mut data = raw_data.borrow_mut();
1798 let data = &mut *data;
1799 let guard = global_style_data.shared_lock.read();
1800 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1801 data.stylist.insert_stylesheet_before(
1803 unsafe { GeckoStyleSheet::new(before_sheet) },
1809 pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(
1810 raw_data: &PerDocumentStyleData,
1811 sheet: *const DomStyleSheet,
1813 let global_style_data = &*GLOBAL_STYLE_DATA;
1814 let mut data = raw_data.borrow_mut();
1815 let data = &mut *data;
1816 let guard = global_style_data.shared_lock.read();
1817 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1818 data.stylist.remove_stylesheet(sheet, &guard);
1822 pub unsafe extern "C" fn Servo_StyleSet_GetSheetAt(
1823 raw_data: &PerDocumentStyleData,
1826 ) -> *const DomStyleSheet {
1827 let data = raw_data.borrow();
1829 .sheet_at(origin, index)
1830 .map_or(ptr::null(), |s| s.raw())
1834 pub unsafe extern "C" fn Servo_StyleSet_GetSheetCount(
1835 raw_data: &PerDocumentStyleData,
1838 let data = raw_data.borrow();
1839 data.stylist.sheet_count(origin)
1843 pub unsafe extern "C" fn Servo_StyleSet_FlushStyleSheets(
1844 raw_data: &PerDocumentStyleData,
1845 doc_element: Option<&RawGeckoElement>,
1846 snapshots: *const ServoElementSnapshotTable,
1848 let global_style_data = &*GLOBAL_STYLE_DATA;
1849 let guard = global_style_data.shared_lock.read();
1850 let mut data = raw_data.borrow_mut();
1851 let doc_element = doc_element.map(GeckoElement);
1853 let have_invalidations = data.flush_stylesheets(&guard, doc_element, snapshots.as_ref());
1855 if have_invalidations && doc_element.is_some() {
1856 // The invalidation machinery propagates the bits up, but we still need
1857 // to tell the Gecko restyle root machinery about it.
1858 bindings::Gecko_NoteDirtySubtreeForInvalidation(doc_element.unwrap().0);
1863 pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(
1864 raw_data: &PerDocumentStyleData,
1865 changed_origins: OriginFlags,
1867 let mut data = raw_data.borrow_mut();
1869 .force_stylesheet_origins_dirty(OriginSet::from(changed_origins));
1873 pub extern "C" fn Servo_StyleSet_SetAuthorStyleDisabled(
1874 raw_data: &PerDocumentStyleData,
1875 author_style_disabled: bool,
1877 let mut data = raw_data.borrow_mut();
1878 let enabled = if author_style_disabled {
1879 AuthorStylesEnabled::No
1881 AuthorStylesEnabled::Yes
1883 data.stylist.set_author_styles_enabled(enabled);
1887 pub extern "C" fn Servo_StyleSet_UsesFontMetrics(raw_data: &PerDocumentStyleData) -> bool {
1888 let doc_data = raw_data;
1889 doc_data.borrow().stylist.device().used_font_metrics()
1893 pub extern "C" fn Servo_StyleSheet_HasRules(raw_contents: &StylesheetContents) -> bool {
1894 let global_style_data = &*GLOBAL_STYLE_DATA;
1895 let guard = global_style_data.shared_lock.read();
1896 !raw_contents.rules.read_with(&guard).0.is_empty()
1900 pub extern "C" fn Servo_StyleSheet_GetRules(sheet: &StylesheetContents) -> Strong<LockedCssRules> {
1901 sheet.rules.clone().into()
1905 pub extern "C" fn Servo_StyleSheet_Clone(
1906 contents: &StylesheetContents,
1907 reference_sheet: *const DomStyleSheet,
1908 ) -> Strong<StylesheetContents> {
1909 use style::shared_lock::{DeepCloneParams, DeepCloneWithLock};
1910 let global_style_data = &*GLOBAL_STYLE_DATA;
1911 let guard = global_style_data.shared_lock.read();
1912 let params = DeepCloneParams { reference_sheet };
1914 Arc::new(contents.deep_clone_with_lock(&global_style_data.shared_lock, &guard, ¶ms)).into()
1918 pub extern "C" fn Servo_StyleSheet_SizeOfIncludingThis(
1919 malloc_size_of: GeckoMallocSizeOf,
1920 malloc_enclosing_size_of: GeckoMallocSizeOf,
1921 sheet: &StylesheetContents,
1923 let global_style_data = &*GLOBAL_STYLE_DATA;
1924 let guard = global_style_data.shared_lock.read();
1925 let mut ops = MallocSizeOfOps::new(
1926 malloc_size_of.unwrap(),
1927 Some(malloc_enclosing_size_of.unwrap()),
1930 // TODO(emilio): We're not measuring the size of the Arc<StylesheetContents>
1931 // allocation itself here.
1932 sheet.size_of(&guard, &mut ops)
1936 pub extern "C" fn Servo_StyleSheet_GetOrigin(sheet: &StylesheetContents) -> Origin {
1941 pub extern "C" fn Servo_StyleSheet_GetSourceMapURL(
1942 contents: &StylesheetContents,
1943 result: &mut nsACString,
1945 let url_opt = contents.source_map_url.read();
1946 if let Some(ref url) = *url_opt {
1952 pub extern "C" fn Servo_StyleSheet_GetSourceURL(
1953 contents: &StylesheetContents,
1954 result: &mut nsACString,
1956 let url_opt = contents.source_url.read();
1957 if let Some(ref url) = *url_opt {
1962 fn with_maybe_worker_shared_lock<R>(func: impl FnOnce(&SharedRwLock) -> R) -> R {
1963 if is_dom_worker_thread() {
1964 DOM_WORKER_RWLOCK.with(func)
1966 func(&GLOBAL_STYLE_DATA.shared_lock)
1970 fn read_locked_arc<T, R, F>(raw: &Locked<T>, func: F) -> R
1974 debug_assert!(!is_dom_worker_thread());
1975 let global_style_data = &*GLOBAL_STYLE_DATA;
1976 let guard = global_style_data.shared_lock.read();
1977 func(raw.read_with(&guard))
1980 fn read_locked_arc_worker<T, R, F>(raw: &Locked<T>, func: F) -> R
1984 with_maybe_worker_shared_lock(|lock| {
1985 let guard = lock.read();
1986 func(raw.read_with(&guard))
1990 #[cfg(debug_assertions)]
1991 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &Locked<T>, func: F) -> R
1995 debug_assert!(is_main_thread() && !is_in_servo_traversal());
1996 read_locked_arc(raw, func)
1999 #[cfg(not(debug_assertions))]
2000 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &Locked<T>, func: F) -> R
2004 debug_assert!(!is_dom_worker_thread());
2005 func(raw.read_unchecked())
2008 fn write_locked_arc<T, R, F>(raw: &Locked<T>, func: F) -> R
2010 F: FnOnce(&mut T) -> R,
2012 debug_assert!(!is_dom_worker_thread());
2013 let global_style_data = &*GLOBAL_STYLE_DATA;
2014 let mut guard = global_style_data.shared_lock.write();
2015 func(raw.write_with(&mut guard))
2018 fn write_locked_arc_worker<T, R, F>(raw: &Locked<T>, func: F) -> R
2020 F: FnOnce(&mut T) -> R,
2022 with_maybe_worker_shared_lock(|lock| {
2023 let mut guard = lock.write();
2024 func(raw.write_with(&mut guard))
2029 pub extern "C" fn Servo_CssRules_ListTypes(rules: &LockedCssRules, result: &mut nsTArray<usize>) {
2030 read_locked_arc(rules, |rules: &CssRules| {
2031 result.assign_from_iter_pod(rules.0.iter().map(|rule| rule.rule_type() as usize));
2036 pub extern "C" fn Servo_CssRules_InsertRule(
2037 rules: &LockedCssRules,
2038 contents: &StylesheetContents,
2041 containing_rule_types: u32,
2042 loader: *mut Loader,
2043 allow_import_rules: AllowImportRules,
2044 gecko_stylesheet: *mut DomStyleSheet,
2045 rule_type: &mut CssRuleType,
2047 let loader = if loader.is_null() {
2050 Some(StylesheetLoader::new(
2059 .map(|loader| loader as &dyn StyleStylesheetLoader);
2060 let rule = unsafe { rule.as_str_unchecked() };
2062 let global_style_data = &*GLOBAL_STYLE_DATA;
2063 let result = rules.insert_rule(
2064 &global_style_data.shared_lock,
2068 CssRuleTypes::from_bits(containing_rule_types),
2075 *rule_type = new_rule.rule_type();
2078 Err(err) => err.into(),
2083 pub extern "C" fn Servo_CssRules_DeleteRule(rules: &LockedCssRules, index: u32) -> nsresult {
2084 write_locked_arc(rules, |rules: &mut CssRules| {
2085 match rules.remove_rule(index as usize) {
2086 Ok(_) => nsresult::NS_OK,
2087 Err(err) => err.into(),
2092 trait MaybeLocked<Target> {
2093 fn maybe_locked_read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a Target;
2096 impl<T> MaybeLocked<T> for T {
2097 fn maybe_locked_read<'a>(&'a self, _: &'a SharedRwLockReadGuard) -> &'a T {
2102 impl<T> MaybeLocked<T> for Locked<T> {
2103 fn maybe_locked_read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
2104 self.read_with(guard)
2108 macro_rules! impl_basic_rule_funcs_without_getter {
2110 ($rule_type:ty, $maybe_locked_rule_type:ty),
2111 debug: $debug:ident,
2112 to_css: $to_css:ident,
2114 #[cfg(debug_assertions)]
2116 pub extern "C" fn $debug(rule: &$maybe_locked_rule_type, result: &mut nsACString) {
2117 let global_style_data = &*GLOBAL_STYLE_DATA;
2118 let guard = global_style_data.shared_lock.read();
2119 let rule: &$rule_type = rule.maybe_locked_read(&guard);
2120 write!(result, "{:?}", *rule).unwrap();
2123 #[cfg(not(debug_assertions))]
2125 pub extern "C" fn $debug(_: &$maybe_locked_rule_type, _: &mut nsACString) {
2130 pub extern "C" fn $to_css(rule: &$maybe_locked_rule_type, result: &mut nsACString) {
2131 let global_style_data = &*GLOBAL_STYLE_DATA;
2132 let guard = global_style_data.shared_lock.read();
2133 let rule: &$rule_type = rule.maybe_locked_read(&guard);
2134 rule.to_css(&guard, result).unwrap();
2139 macro_rules! impl_basic_rule_funcs {
2140 { ($name:ident, $rule_type:ty, $maybe_locked_rule_type:ty),
2141 getter: $getter:ident,
2142 debug: $debug:ident,
2143 to_css: $to_css:ident,
2144 changed: $changed:ident,
2147 pub extern "C" fn $getter(
2148 rules: &LockedCssRules,
2152 ) -> Strong<$maybe_locked_rule_type> {
2153 let global_style_data = &*GLOBAL_STYLE_DATA;
2154 let guard = global_style_data.shared_lock.read();
2155 let rules = rules.read_with(&guard);
2156 let index = index as usize;
2158 if index >= rules.0.len() {
2159 return Strong::null();
2162 match rules.0[index] {
2163 CssRule::$name(ref arc) => {
2164 let rule: &$rule_type = (&**arc).maybe_locked_read(&guard);
2165 let location = rule.source_location;
2166 *line = location.line as u32;
2167 *column = location.column as u32;
2177 pub extern "C" fn $changed(
2178 styleset: &PerDocumentStyleData,
2179 rule: &$maybe_locked_rule_type,
2180 sheet: &DomStyleSheet,
2181 change_kind: RuleChangeKind,
2183 let mut data = styleset.borrow_mut();
2184 let data = &mut *data;
2185 let global_style_data = &*GLOBAL_STYLE_DATA;
2186 let guard = global_style_data.shared_lock.read();
2187 // TODO(emilio): Would be nice not to deal with refcount bumps here,
2188 // but it's probably not a huge deal.
2189 let rule = unsafe { CssRule::$name(Arc::from_raw_addrefed(rule)) };
2190 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
2191 data.stylist.rule_changed(&sheet, &rule, &guard, change_kind);
2194 impl_basic_rule_funcs_without_getter! {
2195 ($rule_type, $maybe_locked_rule_type),
2202 macro_rules! impl_group_rule_funcs {
2203 { ($name:ident, $rule_type:ty, $maybe_locked_rule_type:ty),
2204 get_rules: $get_rules:ident,
2207 impl_basic_rule_funcs! { ($name, $rule_type, $maybe_locked_rule_type), $($basic)+ }
2210 pub extern "C" fn $get_rules(rule: &$maybe_locked_rule_type) -> Strong<LockedCssRules> {
2211 let global_style_data = &*GLOBAL_STYLE_DATA;
2212 let guard = global_style_data.shared_lock.read();
2213 let rule: &$rule_type = rule.maybe_locked_read(&guard);
2214 rule.rules.clone().into()
2219 impl_basic_rule_funcs! { (Style, StyleRule, Locked<StyleRule>),
2220 getter: Servo_CssRules_GetStyleRuleAt,
2221 debug: Servo_StyleRule_Debug,
2222 to_css: Servo_StyleRule_GetCssText,
2223 changed: Servo_StyleSet_StyleRuleChanged,
2227 pub extern "C" fn Servo_StyleRule_EnsureRules(rule: &LockedStyleRule, read_only: bool) -> Strong<LockedCssRules> {
2228 let global_style_data = &*GLOBAL_STYLE_DATA;
2229 let lock = &global_style_data.shared_lock;
2231 let guard = lock.read();
2232 if let Some(ref rules) = rule.read_with(&guard).rules {
2233 return rules.clone().into();
2235 return CssRules::new(vec![], lock).into();
2237 let mut guard = lock.write();
2238 rule.write_with(&mut guard)
2240 .get_or_insert_with(|| CssRules::new(vec![], lock))
2245 impl_basic_rule_funcs! { (Import, ImportRule, Locked<ImportRule>),
2246 getter: Servo_CssRules_GetImportRuleAt,
2247 debug: Servo_ImportRule_Debug,
2248 to_css: Servo_ImportRule_GetCssText,
2249 changed: Servo_StyleSet_ImportRuleChanged,
2252 impl_basic_rule_funcs_without_getter! { (Keyframe, Locked<Keyframe>),
2253 debug: Servo_Keyframe_Debug,
2254 to_css: Servo_Keyframe_GetCssText,
2257 impl_basic_rule_funcs! { (Keyframes, KeyframesRule, Locked<KeyframesRule>),
2258 getter: Servo_CssRules_GetKeyframesRuleAt,
2259 debug: Servo_KeyframesRule_Debug,
2260 to_css: Servo_KeyframesRule_GetCssText,
2261 changed: Servo_StyleSet_KeyframesRuleChanged,
2264 impl_group_rule_funcs! { (Media, MediaRule, MediaRule),
2265 get_rules: Servo_MediaRule_GetRules,
2266 getter: Servo_CssRules_GetMediaRuleAt,
2267 debug: Servo_MediaRule_Debug,
2268 to_css: Servo_MediaRule_GetCssText,
2269 changed: Servo_StyleSet_MediaRuleChanged,
2272 impl_basic_rule_funcs! { (Namespace, NamespaceRule, NamespaceRule),
2273 getter: Servo_CssRules_GetNamespaceRuleAt,
2274 debug: Servo_NamespaceRule_Debug,
2275 to_css: Servo_NamespaceRule_GetCssText,
2276 changed: Servo_StyleSet_NamespaceRuleChanged,
2279 impl_basic_rule_funcs! { (Page, PageRule, Locked<PageRule>),
2280 getter: Servo_CssRules_GetPageRuleAt,
2281 debug: Servo_PageRule_Debug,
2282 to_css: Servo_PageRule_GetCssText,
2283 changed: Servo_StyleSet_PageRuleChanged,
2286 impl_basic_rule_funcs! { (Property, PropertyRule, PropertyRule),
2287 getter: Servo_CssRules_GetPropertyRuleAt,
2288 debug: Servo_PropertyRule_Debug,
2289 to_css: Servo_PropertyRule_GetCssText,
2290 changed: Servo_StyleSet_PropertyRuleChanged,
2293 impl_group_rule_funcs! { (Supports, SupportsRule, SupportsRule),
2294 get_rules: Servo_SupportsRule_GetRules,
2295 getter: Servo_CssRules_GetSupportsRuleAt,
2296 debug: Servo_SupportsRule_Debug,
2297 to_css: Servo_SupportsRule_GetCssText,
2298 changed: Servo_StyleSet_SupportsRuleChanged,
2301 impl_group_rule_funcs! { (Container, ContainerRule, ContainerRule),
2302 get_rules: Servo_ContainerRule_GetRules,
2303 getter: Servo_CssRules_GetContainerRuleAt,
2304 debug: Servo_ContainerRule_Debug,
2305 to_css: Servo_ContainerRule_GetCssText,
2306 changed: Servo_StyleSet_ContainerRuleChanged,
2309 impl_group_rule_funcs! { (LayerBlock, LayerBlockRule, LayerBlockRule),
2310 get_rules: Servo_LayerBlockRule_GetRules,
2311 getter: Servo_CssRules_GetLayerBlockRuleAt,
2312 debug: Servo_LayerBlockRule_Debug,
2313 to_css: Servo_LayerBlockRule_GetCssText,
2314 changed: Servo_StyleSet_LayerBlockRuleChanged,
2317 impl_basic_rule_funcs! { (LayerStatement, LayerStatementRule, LayerStatementRule),
2318 getter: Servo_CssRules_GetLayerStatementRuleAt,
2319 debug: Servo_LayerStatementRule_Debug,
2320 to_css: Servo_LayerStatementRule_GetCssText,
2321 changed: Servo_StyleSet_LayerStatementRuleChanged,
2324 impl_group_rule_funcs! { (Document, DocumentRule, DocumentRule),
2325 get_rules: Servo_DocumentRule_GetRules,
2326 getter: Servo_CssRules_GetDocumentRuleAt,
2327 debug: Servo_DocumentRule_Debug,
2328 to_css: Servo_DocumentRule_GetCssText,
2329 changed: Servo_StyleSet_DocumentRuleChanged,
2332 impl_basic_rule_funcs! { (FontFeatureValues, FontFeatureValuesRule, FontFeatureValuesRule),
2333 getter: Servo_CssRules_GetFontFeatureValuesRuleAt,
2334 debug: Servo_FontFeatureValuesRule_Debug,
2335 to_css: Servo_FontFeatureValuesRule_GetCssText,
2336 changed: Servo_StyleSet_FontFeatureValuesRuleChanged,
2339 impl_basic_rule_funcs! { (FontPaletteValues, FontPaletteValuesRule, FontPaletteValuesRule),
2340 getter: Servo_CssRules_GetFontPaletteValuesRuleAt,
2341 debug: Servo_FontPaletteValuesRule_Debug,
2342 to_css: Servo_FontPaletteValuesRule_GetCssText,
2343 changed: Servo_StyleSet_FontPaletteValuesRuleChanged,
2346 impl_basic_rule_funcs! { (FontFace, FontFaceRule, Locked<FontFaceRule>),
2347 getter: Servo_CssRules_GetFontFaceRuleAt,
2348 debug: Servo_FontFaceRule_Debug,
2349 to_css: Servo_FontFaceRule_GetCssText,
2350 changed: Servo_StyleSet_FontFaceRuleChanged,
2353 impl_basic_rule_funcs! { (CounterStyle, CounterStyleRule, Locked<CounterStyleRule>),
2354 getter: Servo_CssRules_GetCounterStyleRuleAt,
2355 debug: Servo_CounterStyleRule_Debug,
2356 to_css: Servo_CounterStyleRule_GetCssText,
2357 changed: Servo_StyleSet_CounterStyleRuleChanged,
2361 pub extern "C" fn Servo_StyleRule_GetStyle(
2362 rule: &LockedStyleRule,
2363 ) -> Strong<LockedDeclarationBlock> {
2364 read_locked_arc(rule, |rule: &StyleRule| rule.block.clone().into())
2368 pub extern "C" fn Servo_StyleRule_SetStyle(
2369 rule: &LockedStyleRule,
2370 declarations: &LockedDeclarationBlock,
2372 write_locked_arc(rule, |rule: &mut StyleRule| {
2373 rule.block = unsafe { Arc::from_raw_addrefed(declarations) };
2378 pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: &LockedStyleRule, result: &mut nsACString) {
2379 read_locked_arc(rule, |rule| rule.selectors.to_css(result).unwrap());
2382 fn desugared_selector_list(rules: &ThinVec<&LockedStyleRule>) -> SelectorList {
2383 let mut selectors: Option<SelectorList> = None;
2384 for rule in rules.iter().rev() {
2385 selectors = Some(read_locked_arc(rule, |rule| match selectors {
2386 Some(s) => rule.selectors.replace_parent_selector(&s.to_shared()),
2387 None => rule.selectors.clone(),
2390 selectors.expect("Empty rule chain?")
2394 pub extern "C" fn Servo_StyleRule_GetSelectorDataAtIndex(
2395 rules: &ThinVec<&LockedStyleRule>,
2397 text: Option<&mut nsACString>,
2398 specificity: Option<&mut u64>,
2400 let selectors = desugared_selector_list(rules);
2401 let Some(selector) = selectors.0.get(index as usize) else { return };
2402 if let Some(text) = text {
2403 selector.to_css(text).unwrap();
2405 if let Some(specificity) = specificity {
2406 *specificity = selector.specificity() as u64;
2411 pub extern "C" fn Servo_StyleRule_GetSelectorCount(rule: &LockedStyleRule) -> u32 {
2412 read_locked_arc(rule, |rule| rule.selectors.0.len() as u32)
2416 pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(
2417 rules: &ThinVec<&LockedStyleRule>,
2418 element: &RawGeckoElement,
2420 host: Option<&RawGeckoElement>,
2421 pseudo_type: PseudoStyleType,
2422 relevant_link_visited: bool,
2424 use selectors::matching::{
2425 matches_selector, MatchingContext, MatchingMode, NeedsSelectorFlags, VisitedHandlingMode,
2427 let selectors = desugared_selector_list(rules);
2428 let Some(selector) = selectors.0.get(index as usize) else { return false };
2429 let mut matching_mode = MatchingMode::Normal;
2430 match PseudoElement::from_pseudo_type(pseudo_type, None) {
2432 // We need to make sure that the requested pseudo element type
2433 // matches the selector pseudo element type before proceeding.
2434 match selector.pseudo_element() {
2435 Some(selector_pseudo) if *selector_pseudo == pseudo => {
2436 matching_mode = MatchingMode::ForStatelessPseudoElement
2442 // Do not attempt to match if a pseudo element is requested and
2443 // this is not a pseudo element selector, or vice versa.
2444 if selector.has_pseudo_element() {
2450 let element = GeckoElement(element);
2451 let host = host.map(GeckoElement);
2452 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2453 let mut selector_caches = SelectorCaches::default();
2454 let visited_mode = if relevant_link_visited {
2455 VisitedHandlingMode::RelevantLinkVisited
2457 VisitedHandlingMode::AllLinksUnvisited
2459 let mut ctx = MatchingContext::new_for_visited(
2461 /* bloom_filter = */ None,
2462 &mut selector_caches,
2465 NeedsSelectorFlags::No,
2466 MatchingForInvalidation::No,
2468 ctx.with_shadow_host(host, |ctx| {
2469 matches_selector(selector, 0, None, &element, ctx)
2473 pub type SelectorList = selectors::SelectorList<style::gecko::selector_parser::SelectorImpl>;
2476 pub extern "C" fn Servo_StyleRule_SetSelectorText(
2477 contents: &StylesheetContents,
2478 rule: &LockedStyleRule,
2481 let value_str = unsafe { text.as_str_unchecked() };
2483 write_locked_arc(rule, |rule: &mut StyleRule| {
2484 use style::selector_parser::SelectorParser;
2485 use selectors::parser::ParseRelative;
2487 let namespaces = contents.namespaces.read();
2488 let url_data = contents.url_data.read();
2489 let parser = SelectorParser {
2490 stylesheet_origin: contents.origin,
2491 namespaces: &namespaces,
2492 url_data: &url_data,
2493 for_supports_rule: false,
2496 // TODO: Maybe allow setting relative selectors from the OM, if we're in a nested style
2498 let mut parser_input = ParserInput::new(&value_str);
2499 match SelectorList::parse(&parser, &mut Parser::new(&mut parser_input), ParseRelative::No) {
2501 rule.selectors = selectors;
2510 pub unsafe extern "C" fn Servo_SelectorList_Closest(
2511 element: &RawGeckoElement,
2512 selectors: &SelectorList,
2513 ) -> *const RawGeckoElement {
2514 use style::dom_apis;
2516 let element = GeckoElement(element);
2517 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2518 dom_apis::element_closest(element, &selectors, quirks_mode).map_or(ptr::null(), |e| e.0)
2522 pub unsafe extern "C" fn Servo_SelectorList_Matches(
2523 element: &RawGeckoElement,
2524 selectors: &SelectorList,
2526 use style::dom_apis;
2528 let element = GeckoElement(element);
2529 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2530 dom_apis::element_matches(&element, &selectors, quirks_mode)
2534 pub unsafe extern "C" fn Servo_SelectorList_QueryFirst(
2535 node: &RawGeckoNode,
2536 selectors: &SelectorList,
2537 may_use_invalidation: bool,
2538 ) -> *const RawGeckoElement {
2539 use style::dom_apis::{self, MayUseInvalidation, QueryFirst};
2541 let node = GeckoNode(node);
2542 let mut result = None;
2544 let may_use_invalidation = if may_use_invalidation {
2545 MayUseInvalidation::Yes
2547 MayUseInvalidation::No
2550 dom_apis::query_selector::<GeckoElement, QueryFirst>(
2554 may_use_invalidation,
2557 result.map_or(ptr::null(), |e| e.0)
2561 pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
2562 node: &RawGeckoNode,
2563 selectors: &SelectorList,
2564 content_list: *mut structs::nsSimpleContentList,
2565 may_use_invalidation: bool,
2567 use style::dom_apis::{self, MayUseInvalidation, QueryAll};
2569 let node = GeckoNode(node);
2570 let mut result = SmallVec::new();
2572 let may_use_invalidation = if may_use_invalidation {
2573 MayUseInvalidation::Yes
2575 MayUseInvalidation::No
2578 dom_apis::query_selector::<GeckoElement, QueryAll>(
2582 may_use_invalidation,
2585 if !result.is_empty() {
2586 // NOTE(emilio): This relies on a slice of GeckoElement having the same
2587 // memory representation than a slice of element pointers.
2588 bindings::Gecko_ContentList_AppendAll(
2590 result.as_ptr() as *mut *const _,
2597 pub extern "C" fn Servo_ImportRule_GetHref(rule: &LockedImportRule, result: &mut nsAString) {
2598 read_locked_arc(rule, |rule: &ImportRule| {
2599 write!(result, "{}", rule.url.as_str()).unwrap();
2604 pub extern "C" fn Servo_ImportRule_GetLayerName(rule: &LockedImportRule, result: &mut nsACString) {
2605 // https://w3c.github.io/csswg-drafts/cssom/#dom-cssimportrule-layername
2606 read_locked_arc(rule, |rule: &ImportRule| match rule.layer {
2607 ImportLayer::Named(ref name) => name.to_css(&mut CssWriter::new(result)).unwrap(), // "return the layer name declared in the at-rule itself"
2608 ImportLayer::Anonymous => {}, // "or an empty string if the layer is anonymous"
2609 ImportLayer::None => result.set_is_void(true), // "or null if the at-rule does not declare a layer"
2614 pub extern "C" fn Servo_ImportRule_GetSupportsText(
2615 rule: &LockedImportRule,
2616 result: &mut nsACString,
2618 read_locked_arc(rule, |rule: &ImportRule| match rule.supports {
2619 Some(ref supports) => supports
2621 .to_css(&mut CssWriter::new(result))
2623 None => result.set_is_void(true),
2628 pub extern "C" fn Servo_ImportRule_GetSheet(rule: &LockedImportRule) -> *const DomStyleSheet {
2629 read_locked_arc(rule, |rule: &ImportRule| {
2632 .map_or(ptr::null(), |s| s.raw() as *const DomStyleSheet)
2637 pub unsafe extern "C" fn Servo_ImportRule_SetSheet(
2638 rule: &LockedImportRule,
2639 sheet: *mut DomStyleSheet,
2641 write_locked_arc(rule, |rule: &mut ImportRule| {
2642 rule.stylesheet = ImportSheet::new(GeckoStyleSheet::new(sheet));
2647 pub extern "C" fn Servo_Keyframe_GetKeyText(keyframe: &LockedKeyframe, result: &mut nsACString) {
2648 read_locked_arc(keyframe, |keyframe: &Keyframe| {
2651 .to_css(&mut CssWriter::new(result))
2657 pub extern "C" fn Servo_Keyframe_SetKeyText(keyframe: &LockedKeyframe, text: &nsACString) -> bool {
2658 let text = unsafe { text.as_str_unchecked() };
2659 let mut input = ParserInput::new(&text);
2660 if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
2661 write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2662 keyframe.selector = selector;
2671 pub extern "C" fn Servo_Keyframe_GetStyle(
2672 keyframe: &LockedKeyframe,
2673 ) -> Strong<LockedDeclarationBlock> {
2674 read_locked_arc(keyframe, |keyframe: &Keyframe| {
2675 keyframe.block.clone().into()
2680 pub extern "C" fn Servo_Keyframe_SetStyle(
2681 keyframe: &LockedKeyframe,
2682 declarations: &LockedDeclarationBlock,
2684 write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2685 keyframe.block = unsafe { Arc::from_raw_addrefed(declarations) };
2690 pub extern "C" fn Servo_KeyframesRule_GetName(rule: &LockedKeyframesRule) -> *mut nsAtom {
2691 read_locked_arc(rule, |rule: &KeyframesRule| rule.name.as_atom().as_ptr())
2695 pub unsafe extern "C" fn Servo_KeyframesRule_SetName(
2696 rule: &LockedKeyframesRule,
2699 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2700 rule.name = KeyframesName::from_atom(Atom::from_addrefed(name));
2705 pub extern "C" fn Servo_KeyframesRule_GetCount(rule: &LockedKeyframesRule) -> u32 {
2706 read_locked_arc(rule, |rule: &KeyframesRule| rule.keyframes.len() as u32)
2710 pub extern "C" fn Servo_KeyframesRule_GetKeyframeAt(
2711 rule: &LockedKeyframesRule,
2715 ) -> Strong<LockedKeyframe> {
2716 let global_style_data = &*GLOBAL_STYLE_DATA;
2717 let guard = global_style_data.shared_lock.read();
2718 let key = rule.read_with(&guard).keyframes[index as usize].clone();
2719 let location = key.read_with(&guard).source_location;
2720 *line = location.line as u32;
2721 *column = location.column as u32;
2726 pub extern "C" fn Servo_KeyframesRule_FindRule(
2727 rule: &LockedKeyframesRule,
2730 let key = unsafe { key.as_str_unchecked() };
2731 let global_style_data = &*GLOBAL_STYLE_DATA;
2732 let guard = global_style_data.shared_lock.read();
2733 rule.read_with(&guard)
2734 .find_rule(&guard, key)
2735 .map(|index| index as u32)
2736 .unwrap_or(u32::max_value())
2740 pub extern "C" fn Servo_KeyframesRule_AppendRule(
2741 rule: &LockedKeyframesRule,
2742 contents: &StylesheetContents,
2745 let css = unsafe { css.as_str_unchecked() };
2746 let global_style_data = &*GLOBAL_STYLE_DATA;
2748 match Keyframe::parse(css, &contents, &global_style_data.shared_lock) {
2750 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2751 rule.keyframes.push(keyframe);
2760 pub extern "C" fn Servo_KeyframesRule_DeleteRule(rule: &LockedKeyframesRule, index: u32) {
2761 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2762 rule.keyframes.remove(index as usize);
2767 pub extern "C" fn Servo_MediaRule_GetMedia(rule: &MediaRule) -> Strong<LockedMediaList> {
2768 rule.media_queries.clone().into()
2772 pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: &NamespaceRule) -> *mut nsAtom {
2775 .map_or(atom!("").as_ptr(), |a| a.as_ptr())
2779 pub extern "C" fn Servo_NamespaceRule_GetURI(rule: &NamespaceRule) -> *mut nsAtom {
2784 pub extern "C" fn Servo_PageRule_GetStyle(rule: &LockedPageRule) -> Strong<LockedDeclarationBlock> {
2785 read_locked_arc(rule, |rule: &PageRule| rule.block.clone().into())
2789 pub extern "C" fn Servo_PageRule_SetStyle(
2790 rule: &LockedPageRule,
2791 declarations: &LockedDeclarationBlock,
2793 write_locked_arc(rule, |rule: &mut PageRule| {
2794 rule.block = unsafe { Arc::from_raw_addrefed(declarations) };
2799 pub extern "C" fn Servo_PageRule_GetSelectorText(rule: &LockedPageRule, result: &mut nsACString) {
2800 read_locked_arc(rule, |rule: &PageRule| {
2801 rule.selectors.to_css(&mut CssWriter::new(result)).unwrap();
2806 pub extern "C" fn Servo_PageRule_SetSelectorText(
2807 contents: &StylesheetContents,
2808 rule: &LockedPageRule,
2811 let value_str = unsafe { text.as_str_unchecked() };
2813 write_locked_arc(rule, |rule: &mut PageRule| {
2814 use style::stylesheets::PageSelectors;
2816 let mut parser_input = ParserInput::new(&value_str);
2817 let mut parser = Parser::new(&mut parser_input);
2819 // Ensure that a blank input results in empty page selectors
2820 if parser.is_exhausted() {
2821 rule.selectors = PageSelectors::default();
2825 let url_data = contents.url_data.read();
2826 let context = ParserContext::new(
2830 ParsingMode::DEFAULT,
2831 QuirksMode::NoQuirks,
2832 /* namespaces = */ Default::default(),
2837 match parser.parse_entirely(|i| PageSelectors::parse(&context, i)) {
2839 rule.selectors = selectors;
2848 pub extern "C" fn Servo_PropertyRule_GetName(rule: &PropertyRule, result: &mut nsACString) {
2849 rule.name.to_css(&mut CssWriter::new(result)).unwrap()
2853 pub extern "C" fn Servo_PropertyRule_GetSyntax(rule: &PropertyRule, result: &mut nsACString) {
2854 if let Some(ref syntax) = rule.syntax {
2855 CssWriter::new(result).write_str(syntax.as_str()).unwrap()
2860 pub extern "C" fn Servo_PropertyRule_GetInherits(rule: &PropertyRule) -> bool {
2861 matches!(rule.inherits, Some(PropertyInherits::True))
2865 pub extern "C" fn Servo_PropertyRule_GetInitialValue(
2866 rule: &PropertyRule,
2867 result: &mut nsACString,
2870 .to_css(&mut CssWriter::new(result))
2872 rule.initial_value.is_some()
2876 pub extern "C" fn Servo_SupportsRule_GetConditionText(
2877 rule: &SupportsRule,
2878 result: &mut nsACString,
2880 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
2884 pub extern "C" fn Servo_ContainerRule_GetConditionText(
2885 rule: &ContainerRule,
2886 result: &mut nsACString,
2888 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
2892 pub extern "C" fn Servo_ContainerRule_GetContainerQuery(
2893 rule: &ContainerRule,
2894 result: &mut nsACString,
2896 rule.query_condition()
2897 .to_css(&mut CssWriter::new(result))
2902 pub extern "C" fn Servo_ContainerRule_QueryContainerFor(
2903 rule: &ContainerRule,
2904 element: &RawGeckoElement,
2905 ) -> *const RawGeckoElement {
2907 .find_container(GeckoElement(element), None)
2908 .map_or(ptr::null(), |result| result.element.0)
2912 pub extern "C" fn Servo_ContainerRule_GetContainerName(
2913 rule: &ContainerRule,
2914 result: &mut nsACString,
2916 let name = rule.container_name();
2917 if !name.is_none() {
2918 name.to_css(&mut CssWriter::new(result)).unwrap();
2923 pub extern "C" fn Servo_DocumentRule_GetConditionText(
2924 rule: &DocumentRule,
2925 result: &mut nsACString,
2927 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
2931 pub extern "C" fn Servo_FontFeatureValuesRule_GetFontFamily(
2932 rule: &FontFeatureValuesRule,
2933 result: &mut nsACString,
2936 .to_css(&mut CssWriter::new(result))
2941 pub extern "C" fn Servo_FontFeatureValuesRule_GetValueText(
2942 rule: &FontFeatureValuesRule,
2943 result: &mut nsACString,
2945 rule.value_to_css(&mut CssWriter::new(result)).unwrap();
2949 pub extern "C" fn Servo_FontPaletteValuesRule_GetName(
2950 rule: &FontPaletteValuesRule,
2951 result: &mut nsACString,
2953 rule.name.to_css(&mut CssWriter::new(result)).unwrap()
2957 pub extern "C" fn Servo_FontPaletteValuesRule_GetFontFamily(
2958 rule: &FontPaletteValuesRule,
2959 result: &mut nsACString,
2961 if !rule.family_names.is_empty() {
2963 .to_css(&mut CssWriter::new(result))
2969 pub extern "C" fn Servo_FontPaletteValuesRule_GetBasePalette(
2970 rule: &FontPaletteValuesRule,
2971 result: &mut nsACString,
2974 .to_css(&mut CssWriter::new(result))
2979 pub extern "C" fn Servo_FontPaletteValuesRule_GetOverrideColors(
2980 rule: &FontPaletteValuesRule,
2981 result: &mut nsACString,
2983 if !rule.override_colors.is_empty() {
2984 rule.override_colors
2985 .to_css(&mut CssWriter::new(result))
2991 pub extern "C" fn Servo_FontFaceRule_CreateEmpty() -> Strong<LockedFontFaceRule> {
2992 // XXX This is not great. We should split FontFace descriptor data
2993 // from the rule, so that we don't need to create the rule like this
2994 // and the descriptor data itself can be hold in UniquePtr from the
2995 // Gecko side. See bug 1450904.
2996 with_maybe_worker_shared_lock(|lock| {
2997 Arc::new(lock.wrap(FontFaceRule::empty(SourceLocation { line: 0, column: 0 }))).into()
3002 pub unsafe extern "C" fn Servo_FontFaceRule_Clone(
3003 rule: &LockedFontFaceRule,
3004 ) -> Strong<LockedFontFaceRule> {
3005 let clone = read_locked_arc_worker(rule, |rule: &FontFaceRule| rule.clone());
3006 with_maybe_worker_shared_lock(|lock| Arc::new(lock.wrap(clone)).into())
3010 pub unsafe extern "C" fn Servo_FontFaceRule_GetSourceLocation(
3011 rule: &LockedFontFaceRule,
3015 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3016 let location = rule.source_location;
3017 *line.as_mut().unwrap() = location.line as u32;
3018 *column.as_mut().unwrap() = location.column as u32;
3022 macro_rules! apply_font_desc_list {
3023 ($apply_macro:ident) => {
3026 eCSSFontDesc_Family => family,
3027 eCSSFontDesc_Style => style,
3028 eCSSFontDesc_Weight => weight,
3029 eCSSFontDesc_Stretch => stretch,
3030 eCSSFontDesc_Src => sources,
3031 eCSSFontDesc_UnicodeRange => unicode_range,
3032 eCSSFontDesc_FontFeatureSettings => feature_settings,
3033 eCSSFontDesc_FontVariationSettings => variation_settings,
3034 eCSSFontDesc_FontLanguageOverride => language_override,
3035 eCSSFontDesc_Display => display,
3036 eCSSFontDesc_AscentOverride => ascent_override,
3037 eCSSFontDesc_DescentOverride => descent_override,
3038 eCSSFontDesc_LineGapOverride => line_gap_override,
3039 eCSSFontDesc_SizeAdjust => size_adjust,
3042 eCSSFontDesc_UNKNOWN,
3050 pub unsafe extern "C" fn Servo_FontFaceRule_Length(rule: &LockedFontFaceRule) -> u32 {
3051 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3053 macro_rules! count_values {
3055 valid: [$($v_enum_name:ident => $field:ident,)*]
3056 invalid: [$($i_enum_name:ident,)*]
3058 $(if rule.$field.is_some() {
3063 apply_font_desc_list!(count_values);
3069 pub unsafe extern "C" fn Servo_FontFaceRule_IndexGetter(
3070 rule: &LockedFontFaceRule,
3072 ) -> nsCSSFontDesc {
3073 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3075 macro_rules! lookup_index {
3077 valid: [$($v_enum_name:ident => $field:ident,)*]
3078 invalid: [$($i_enum_name:ident,)*]
3080 $(if rule.$field.is_some() {
3082 if count - 1 == index {
3083 return nsCSSFontDesc::$v_enum_name;
3088 apply_font_desc_list!(lookup_index);
3089 return nsCSSFontDesc::eCSSFontDesc_UNKNOWN;
3094 pub unsafe extern "C" fn Servo_FontFaceRule_GetDeclCssText(
3095 rule: &LockedFontFaceRule,
3096 result: &mut nsACString,
3098 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3099 rule.decl_to_css(result).unwrap();
3103 macro_rules! simple_font_descriptor_getter_impl {
3104 ($rule:ident, $out:ident, $field:ident, $compute:ident) => {
3105 read_locked_arc_worker($rule, |rule: &FontFaceRule| {
3107 None => return false,
3108 Some(ref f) => *$out = f.$compute(),
3116 pub extern "C" fn Servo_FontFaceRule_GetFontWeight(
3117 rule: &LockedFontFaceRule,
3118 out: &mut font_face::ComputedFontWeightRange,
3120 simple_font_descriptor_getter_impl!(rule, out, weight, compute)
3124 pub extern "C" fn Servo_FontFaceRule_GetFontStretch(
3125 rule: &LockedFontFaceRule,
3126 out: &mut font_face::ComputedFontStretchRange,
3128 simple_font_descriptor_getter_impl!(rule, out, stretch, compute)
3132 pub extern "C" fn Servo_FontFaceRule_GetFontStyle(
3133 rule: &LockedFontFaceRule,
3134 out: &mut font_face::ComputedFontStyleDescriptor,
3136 simple_font_descriptor_getter_impl!(rule, out, style, compute)
3140 pub extern "C" fn Servo_FontFaceRule_GetFontDisplay(
3141 rule: &LockedFontFaceRule,
3142 out: &mut font_face::FontDisplay,
3144 simple_font_descriptor_getter_impl!(rule, out, display, clone)
3148 pub extern "C" fn Servo_FontFaceRule_GetFontLanguageOverride(
3149 rule: &LockedFontFaceRule,
3150 out: &mut computed::FontLanguageOverride,
3152 simple_font_descriptor_getter_impl!(rule, out, language_override, clone)
3155 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3156 // rather than an actual percentage value.
3158 pub extern "C" fn Servo_FontFaceRule_GetAscentOverride(
3159 rule: &LockedFontFaceRule,
3160 out: &mut computed::Percentage,
3162 simple_font_descriptor_getter_impl!(rule, out, ascent_override, compute)
3165 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3166 // rather than an actual percentage value.
3168 pub extern "C" fn Servo_FontFaceRule_GetDescentOverride(
3169 rule: &LockedFontFaceRule,
3170 out: &mut computed::Percentage,
3172 simple_font_descriptor_getter_impl!(rule, out, descent_override, compute)
3175 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal'
3176 // rather than an actual percentage value.
3178 pub extern "C" fn Servo_FontFaceRule_GetLineGapOverride(
3179 rule: &LockedFontFaceRule,
3180 out: &mut computed::Percentage,
3182 simple_font_descriptor_getter_impl!(rule, out, line_gap_override, compute)
3186 pub extern "C" fn Servo_FontFaceRule_GetSizeAdjust(
3187 rule: &LockedFontFaceRule,
3188 out: &mut computed::Percentage,
3190 simple_font_descriptor_getter_impl!(rule, out, size_adjust, compute)
3194 pub unsafe extern "C" fn Servo_FontFaceRule_GetFamilyName(
3195 rule: &LockedFontFaceRule,
3197 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3198 // TODO(emilio): font-family is a mandatory descriptor, can't we unwrap
3199 // here, and remove the null-checks in Gecko?
3202 .map_or(ptr::null_mut(), |f| f.name.as_ptr())
3207 pub unsafe extern "C" fn Servo_FontFaceRule_GetUnicodeRanges(
3208 rule: &LockedFontFaceRule,
3209 out_len: *mut usize,
3210 ) -> *const UnicodeRange {
3212 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3213 let ranges = match rule.unicode_range {
3214 Some(ref ranges) => ranges,
3215 None => return ptr::null(),
3217 *out_len = ranges.len();
3218 ranges.as_ptr() as *const _
3223 pub unsafe extern "C" fn Servo_FontFaceRule_GetSources(
3224 rule: &LockedFontFaceRule,
3225 out: *mut nsTArray<FontFaceSourceListComponent>,
3227 let out = &mut *out;
3228 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3229 let sources = match rule.sources {
3233 let len = sources.0.iter().fold(0, |acc, src| {
3235 Source::Url(ref url) => {
3236 (if url.format_hint.is_some() { 2 } else { 1 }) +
3237 (if url.tech_flags.is_empty() { 0 } else { 1 })
3239 Source::Local(_) => 1,
3243 out.set_len(len as u32);
3245 let mut iter = out.iter_mut();
3248 let mut set_next = |component: FontFaceSourceListComponent| {
3249 *iter.next().expect("miscalculated length") = component;
3252 for source in sources.0.iter() {
3254 Source::Url(ref url) => {
3255 set_next(FontFaceSourceListComponent::Url(&url.url));
3256 if let Some(hint) = &url.format_hint {
3258 FontFaceSourceFormat::Keyword(kw) => {
3259 set_next(FontFaceSourceListComponent::FormatHintKeyword(*kw))
3261 FontFaceSourceFormat::String(s) => {
3262 set_next(FontFaceSourceListComponent::FormatHintString {
3264 utf8_bytes: s.as_ptr(),
3269 if !url.tech_flags.is_empty() {
3270 set_next(FontFaceSourceListComponent::TechFlags(url.tech_flags));
3273 Source::Local(ref name) => {
3274 set_next(FontFaceSourceListComponent::Local(name.name.as_ptr()));
3280 assert!(iter.next().is_none(), "miscalculated");
3285 pub unsafe extern "C" fn Servo_FontFaceRule_GetVariationSettings(
3286 rule: &LockedFontFaceRule,
3287 variations: *mut nsTArray<structs::gfxFontVariation>,
3289 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3290 let source_variations = match rule.variation_settings {
3295 (*variations).set_len(source_variations.0.len() as u32);
3296 for (target, source) in (*variations).iter_mut().zip(source_variations.0.iter()) {
3297 *target = structs::gfxFontVariation {
3299 mValue: source.value.get(),
3306 pub unsafe extern "C" fn Servo_FontFaceRule_GetFeatureSettings(
3307 rule: &LockedFontFaceRule,
3308 features: *mut nsTArray<structs::gfxFontFeature>,
3310 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3311 let source_features = match rule.feature_settings {
3316 (*features).set_len(source_features.0.len() as u32);
3317 for (target, source) in (*features).iter_mut().zip(source_features.0.iter()) {
3318 *target = structs::gfxFontFeature {
3320 mValue: source.value.value() as u32,
3327 pub extern "C" fn Servo_FontFaceRule_GetDescriptorCssText(
3328 rule: &LockedFontFaceRule,
3329 desc: nsCSSFontDesc,
3330 result: &mut nsACString,
3332 read_locked_arc_worker(rule, |rule: &FontFaceRule| {
3333 let mut writer = CssWriter::new(result);
3334 macro_rules! to_css_text {
3336 valid: [$($v_enum_name:ident => $field:ident,)*]
3337 invalid: [$($i_enum_name:ident,)*]
3341 nsCSSFontDesc::$v_enum_name => {
3342 if let Some(ref value) = rule.$field {
3343 value.to_css(&mut writer).unwrap();
3348 nsCSSFontDesc::$i_enum_name => {
3349 debug_assert!(false, "not a valid font descriptor");
3355 apply_font_desc_list!(to_css_text)
3360 pub unsafe extern "C" fn Servo_FontFaceRule_SetDescriptor(
3361 rule: &LockedFontFaceRule,
3362 desc: nsCSSFontDesc,
3364 data: *mut URLExtraData,
3365 out_changed: *mut bool,
3367 let value = value.as_str_unchecked();
3368 let mut input = ParserInput::new(&value);
3369 let mut parser = Parser::new(&mut input);
3370 let url_data = UrlExtraData::from_ptr_ref(&data);
3371 let context = ParserContext::new(
3374 Some(CssRuleType::FontFace),
3375 ParsingMode::DEFAULT,
3376 QuirksMode::NoQuirks,
3377 /* namespaces = */ Default::default(),
3382 write_locked_arc_worker(rule, |rule: &mut FontFaceRule| {
3383 macro_rules! to_css_text {
3385 valid: [$($v_enum_name:ident => $field:ident,)*]
3386 invalid: [$($i_enum_name:ident,)*]
3390 nsCSSFontDesc::$v_enum_name => {
3391 if let Ok(value) = parser.parse_entirely(|i| Parse::parse(&context, i)) {
3392 let result = Some(value);
3393 *out_changed = result != rule.$field;
3394 rule.$field = result;
3402 nsCSSFontDesc::$i_enum_name => {
3403 debug_assert!(false, "not a valid font descriptor");
3410 apply_font_desc_list!(to_css_text)
3415 pub unsafe extern "C" fn Servo_FontFaceRule_ResetDescriptor(
3416 rule: &LockedFontFaceRule,
3417 desc: nsCSSFontDesc,
3419 write_locked_arc_worker(rule, |rule: &mut FontFaceRule| {
3420 macro_rules! reset_desc {
3422 valid: [$($v_enum_name:ident => $field:ident,)*]
3423 invalid: [$($i_enum_name:ident,)*]
3426 $(nsCSSFontDesc::$v_enum_name => rule.$field = None,)*
3427 $(nsCSSFontDesc::$i_enum_name => debug_assert!(false, "not a valid font descriptor"),)*
3431 apply_font_desc_list!(reset_desc)
3436 pub unsafe extern "C" fn Servo_CounterStyleRule_GetName(
3437 rule: &LockedCounterStyleRule,
3439 read_locked_arc(rule, |rule: &CounterStyleRule| rule.name().0.as_ptr())
3443 pub unsafe extern "C" fn Servo_CounterStyleRule_SetName(
3444 rule: &LockedCounterStyleRule,
3447 let value = value.as_str_unchecked();
3448 let mut input = ParserInput::new(&value);
3449 let mut parser = Parser::new(&mut input);
3450 match parser.parse_entirely(counter_style::parse_counter_style_name_definition) {
3452 write_locked_arc(rule, |rule: &mut CounterStyleRule| rule.set_name(name));
3460 pub unsafe extern "C" fn Servo_CounterStyleRule_GetGeneration(
3461 rule: &LockedCounterStyleRule,
3463 read_locked_arc(rule, |rule: &CounterStyleRule| rule.generation())
3466 fn symbol_to_string(s: &counter_style::Symbol) -> nsString {
3468 counter_style::Symbol::String(ref s) => nsString::from(&**s),
3469 counter_style::Symbol::Ident(ref i) => nsString::from(i.0.as_slice()),
3473 // TODO(emilio): Cbindgen could be used to simplify a bunch of code here.
3475 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPad(
3476 rule: &LockedCounterStyleRule,
3478 symbol: &mut nsString,
3480 read_locked_arc(rule, |rule: &CounterStyleRule| {
3481 let pad = match rule.pad() {
3483 None => return false,
3485 *width = pad.0.value();
3486 *symbol = symbol_to_string(&pad.1);
3491 fn get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool {
3494 None => return false,
3496 *out = symbol_to_string(s);
3501 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPrefix(
3502 rule: &LockedCounterStyleRule,
3505 read_locked_arc(rule, |rule: &CounterStyleRule| {
3506 get_symbol(rule.prefix(), out)
3511 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSuffix(
3512 rule: &LockedCounterStyleRule,
3515 read_locked_arc(rule, |rule: &CounterStyleRule| {
3516 get_symbol(rule.suffix(), out)
3521 pub unsafe extern "C" fn Servo_CounterStyleRule_GetNegative(
3522 rule: &LockedCounterStyleRule,
3523 prefix: &mut nsString,
3524 suffix: &mut nsString,
3526 read_locked_arc(rule, |rule: &CounterStyleRule| {
3527 let negative = match rule.negative() {
3529 None => return false,
3531 *prefix = symbol_to_string(&negative.0);
3532 *suffix = match negative.1 {
3533 Some(ref s) => symbol_to_string(s),
3534 None => nsString::new(),
3541 pub enum IsOrdinalInRange {
3549 pub unsafe extern "C" fn Servo_CounterStyleRule_IsInRange(
3550 rule: &LockedCounterStyleRule,
3552 ) -> IsOrdinalInRange {
3553 use style::counter_style::CounterBound;
3554 read_locked_arc(rule, |rule: &CounterStyleRule| {
3555 let range = match rule.range() {
3557 None => return IsOrdinalInRange::NoOrdinalSpecified,
3560 if range.0.is_empty() {
3561 return IsOrdinalInRange::Auto;
3564 let in_range = range.0.iter().any(|r| {
3565 if let CounterBound::Integer(start) = r.start {
3566 if start.value() > ordinal {
3571 if let CounterBound::Integer(end) = r.end {
3572 if end.value() < ordinal {
3581 IsOrdinalInRange::InRange
3583 IsOrdinalInRange::NotInRange
3589 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols(
3590 rule: &LockedCounterStyleRule,
3591 symbols: &mut style::OwnedSlice<nsString>,
3593 read_locked_arc(rule, |rule: &CounterStyleRule| {
3594 *symbols = match rule.symbols() {
3595 Some(s) => s.0.iter().map(symbol_to_string).collect(),
3596 None => style::OwnedSlice::default(),
3602 pub struct AdditiveSymbol {
3604 pub symbol: nsString,
3608 pub unsafe extern "C" fn Servo_CounterStyleRule_GetAdditiveSymbols(
3609 rule: &LockedCounterStyleRule,
3610 symbols: &mut style::OwnedSlice<AdditiveSymbol>,
3612 read_locked_arc(rule, |rule: &CounterStyleRule| {
3613 *symbols = match rule.additive_symbols() {
3616 .map(|s| AdditiveSymbol {
3617 weight: s.weight.value(),
3618 symbol: symbol_to_string(&s.symbol),
3622 None => style::OwnedSlice::default(),
3628 pub enum CounterSpeakAs {
3638 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSpeakAs(
3639 rule: &LockedCounterStyleRule,
3640 out: &mut CounterSpeakAs,
3642 use style::counter_style::SpeakAs;
3643 *out = read_locked_arc(rule, |rule: &CounterStyleRule| {
3644 let speak_as = match rule.speak_as() {
3646 None => return CounterSpeakAs::None,
3649 SpeakAs::Auto => CounterSpeakAs::Auto,
3650 SpeakAs::Bullets => CounterSpeakAs::Bullets,
3651 SpeakAs::Numbers => CounterSpeakAs::Numbers,
3652 SpeakAs::Words => CounterSpeakAs::Words,
3653 SpeakAs::Other(ref other) => CounterSpeakAs::Ident(other.0.as_ptr()),
3659 pub enum CounterSystem {
3670 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSystem(
3671 rule: &LockedCounterStyleRule,
3672 ) -> CounterSystem {
3673 use style::counter_style::System;
3674 read_locked_arc(rule, |rule: &CounterStyleRule| {
3675 match *rule.resolved_system() {
3676 System::Cyclic => CounterSystem::Cyclic,
3677 System::Numeric => CounterSystem::Numeric,
3678 System::Alphabetic => CounterSystem::Alphabetic,
3679 System::Symbolic => CounterSystem::Symbolic,
3680 System::Additive => CounterSystem::Additive,
3681 System::Fixed { .. } => CounterSystem::Fixed,
3682 System::Extends(_) => CounterSystem::Extends,
3688 pub unsafe extern "C" fn Servo_CounterStyleRule_GetExtended(
3689 rule: &LockedCounterStyleRule,
3691 read_locked_arc(rule, |rule: &CounterStyleRule| {
3692 match *rule.resolved_system() {
3693 counter_style::System::Extends(ref name) => name.0.as_ptr(),
3695 debug_assert!(false, "Not extends system");
3703 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFixedFirstValue(
3704 rule: &LockedCounterStyleRule,
3706 read_locked_arc(rule, |rule: &CounterStyleRule| {
3707 match *rule.resolved_system() {
3708 counter_style::System::Fixed { first_symbol_value } => {
3709 first_symbol_value.map_or(1, |v| v.value())
3712 debug_assert!(false, "Not fixed system");
3720 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFallback(
3721 rule: &LockedCounterStyleRule,
3723 read_locked_arc(rule, |rule: &CounterStyleRule| {
3724 rule.fallback().map_or(ptr::null_mut(), |i| i.0 .0.as_ptr())
3728 macro_rules! counter_style_descriptors {
3731 $($desc:ident => $getter:ident / $setter:ident,)+
3738 pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptorCssText(
3739 rule: &LockedCounterStyleRule,
3740 desc: nsCSSCounterDesc,
3741 result: &mut nsACString,
3743 let mut writer = CssWriter::new(result);
3744 read_locked_arc(rule, |rule: &CounterStyleRule| {
3746 $(nsCSSCounterDesc::$desc => {
3747 if let Some(value) = rule.$getter() {
3748 value.to_css(&mut writer).unwrap();
3751 $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3757 pub unsafe extern "C" fn Servo_CounterStyleRule_SetDescriptor(
3758 rule: &LockedCounterStyleRule,
3759 desc: nsCSSCounterDesc,
3762 let value = value.as_str_unchecked();
3763 let mut input = ParserInput::new(&value);
3764 let mut parser = Parser::new(&mut input);
3765 let url_data = dummy_url_data();
3766 let context = ParserContext::new(
3769 Some(CssRuleType::CounterStyle),
3770 ParsingMode::DEFAULT,
3771 QuirksMode::NoQuirks,
3772 /* namespaces = */ Default::default(),
3777 write_locked_arc(rule, |rule: &mut CounterStyleRule| {
3779 $(nsCSSCounterDesc::$desc => {
3780 match parser.parse_entirely(|i| Parse::parse(&context, i)) {
3781 Ok(value) => rule.$setter(value),
3785 $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3792 counter_style_descriptors! {
3794 eCSSCounterDesc_System => system / set_system,
3795 eCSSCounterDesc_Symbols => symbols / set_symbols,
3796 eCSSCounterDesc_AdditiveSymbols => additive_symbols / set_additive_symbols,
3797 eCSSCounterDesc_Negative => negative / set_negative,
3798 eCSSCounterDesc_Prefix => prefix / set_prefix,
3799 eCSSCounterDesc_Suffix => suffix / set_suffix,
3800 eCSSCounterDesc_Range => range / set_range,
3801 eCSSCounterDesc_Pad => pad / set_pad,
3802 eCSSCounterDesc_Fallback => fallback / set_fallback,
3803 eCSSCounterDesc_SpeakAs => speak_as / set_speak_as,
3806 eCSSCounterDesc_UNKNOWN,
3807 eCSSCounterDesc_COUNT,
3812 pub unsafe extern "C" fn Servo_ComputedValues_GetForPageContent(
3813 raw_data: &PerDocumentStyleData,
3814 page_name: *const nsAtom,
3815 pseudos: PagePseudoClassFlags,
3816 ) -> Strong<ComputedValues> {
3817 let global_style_data = &*GLOBAL_STYLE_DATA;
3818 let guard = global_style_data.shared_lock.read();
3819 let guards = StylesheetGuards::same(&guard);
3820 let data = raw_data.borrow_mut();
3821 let cascade_data = data.stylist.cascade_data();
3823 let mut extra_declarations = vec![];
3824 let iter = data.stylist.iter_extra_data_origins_rev();
3825 let name = if !page_name.is_null() {
3826 Some(Atom::from_raw(page_name as *mut nsAtom))
3830 for (data, origin) in iter {
3831 data.pages.match_and_append_rules(
3832 &mut extra_declarations,
3841 let rule_node = data.stylist.rule_node_for_precomputed_pseudo(
3843 &PseudoElement::PageContent,
3848 .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
3850 &PseudoElement::PageContent,
3858 pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox(
3859 parent_style_or_null: Option<&ComputedValues>,
3860 pseudo: PseudoStyleType,
3861 raw_data: &PerDocumentStyleData,
3862 ) -> Strong<ComputedValues> {
3863 let pseudo = PseudoElement::from_pseudo_type(pseudo, None).unwrap();
3864 debug_assert!(pseudo.is_anon_box());
3865 debug_assert_ne!(pseudo, PseudoElement::PageContent);
3866 let global_style_data = &*GLOBAL_STYLE_DATA;
3867 let guard = global_style_data.shared_lock.read();
3868 let guards = StylesheetGuards::same(&guard);
3869 let data = raw_data.borrow_mut();
3870 let rule_node = data
3872 .rule_node_for_precomputed_pseudo(&guards, &pseudo, vec![]);
3875 .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
3878 parent_style_or_null.map(|x| &*x),
3884 fn get_functional_pseudo_parameter_atom(
3885 functional_pseudo_parameter: *mut nsAtom,
3886 ) -> Option<AtomIdent> {
3887 if functional_pseudo_parameter.is_null() {
3890 Some(AtomIdent::new(unsafe {
3891 Atom::from_raw(functional_pseudo_parameter)
3897 pub extern "C" fn Servo_ResolvePseudoStyle(
3898 element: &RawGeckoElement,
3899 pseudo_type: PseudoStyleType,
3900 functional_pseudo_parameter: *mut nsAtom,
3902 inherited_style: Option<&ComputedValues>,
3903 raw_data: &PerDocumentStyleData,
3904 ) -> Strong<ComputedValues> {
3905 let element = GeckoElement(element);
3906 let doc_data = raw_data.borrow();
3909 "Servo_ResolvePseudoStyle: {:?} {:?}, is_probe: {}",
3911 PseudoElement::from_pseudo_type(
3913 get_functional_pseudo_parameter_atom(functional_pseudo_parameter)
3918 let data = element.borrow_data();
3920 let data = match data.as_ref() {
3921 Some(data) if data.has_styles() => data,
3923 // FIXME(bholley, emilio): Assert against this.
3925 // Known offender is nsMathMLmoFrame::MarkIntrinsicISizesDirty,
3926 // which goes and does a bunch of work involving style resolution.
3928 // Bug 1403865 tracks fixing it, and potentially adding an assert
3930 warn!("Calling Servo_ResolvePseudoStyle on unstyled element");
3931 return if is_probe {
3934 doc_data.default_computed_values().clone().into()
3939 let pseudo_element = PseudoElement::from_pseudo_type(
3941 get_functional_pseudo_parameter_atom(functional_pseudo_parameter),
3943 .expect("ResolvePseudoStyle with a non-pseudo?");
3945 let matching_fn = |pseudo: &PseudoElement| *pseudo == pseudo_element;
3947 let global_style_data = &*GLOBAL_STYLE_DATA;
3948 let guard = global_style_data.shared_lock.read();
3949 let style = get_pseudo_style(
3958 /* matching_func = */ if pseudo_element.is_highlight() {Some(&matching_fn)} else {None},
3962 Some(s) => s.into(),
3964 debug_assert!(is_probe);
3970 fn debug_atom_array(atoms: &nsTArray<structs::RefPtr<nsAtom>>) -> String {
3971 let mut result = String::from("[");
3972 for atom in atoms.iter() {
3973 if atom.mRawPtr.is_null() {
3974 result += "(null), ";
3976 let atom = unsafe { WeakAtom::new(atom.mRawPtr) };
3977 write!(result, "{}, ", atom).unwrap();
3985 pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle(
3986 element: &RawGeckoElement,
3987 pseudo_tag: *mut nsAtom,
3988 inherited_style: &ComputedValues,
3989 input_word: &nsTArray<structs::RefPtr<nsAtom>>,
3990 raw_data: &PerDocumentStyleData,
3991 ) -> Strong<ComputedValues> {
3992 let element = GeckoElement(element);
3995 .expect("Calling ResolveXULTreePseudoStyle on unstyled element?");
3997 let pseudo = unsafe {
3998 Atom::with(pseudo_tag, |atom| {
3999 PseudoElement::from_tree_pseudo_atom(atom, Box::new([]))
4001 .expect("ResolveXULTreePseudoStyle with a non-tree pseudo?")
4003 let doc_data = raw_data.borrow();
4006 "ResolveXULTreePseudoStyle: {:?} {:?} {}",
4009 debug_atom_array(input_word)
4012 let matching_fn = |pseudo: &PseudoElement| {
4015 .expect("Not a tree pseudo-element?");
4017 .all(|atom| input_word.iter().any(|item| atom.as_ptr() == item.mRawPtr))
4020 let global_style_data = &*GLOBAL_STYLE_DATA;
4021 let guard = global_style_data.shared_lock.read();
4028 Some(inherited_style),
4030 /* is_probe = */ false,
4038 pub extern "C" fn Servo_SetExplicitStyle(element: &RawGeckoElement, style: &ComputedValues) {
4039 let element = GeckoElement(element);
4040 debug!("Servo_SetExplicitStyle: {:?}", element);
4041 // We only support this API for initial styling. There's no reason it couldn't
4042 // work for other things, we just haven't had a reason to do so.
4043 debug_assert!(!element.has_data());
4044 let mut data = unsafe { element.ensure_data() };
4045 data.styles.primary = Some(unsafe { Arc::from_raw_addrefed(style) });
4048 fn get_pseudo_style(
4049 guard: &SharedRwLockReadGuard,
4050 element: GeckoElement,
4051 pseudo: &PseudoElement,
4052 rule_inclusion: RuleInclusion,
4053 styles: &ElementStyles,
4054 inherited_styles: Option<&ComputedValues>,
4057 matching_func: Option<&dyn Fn(&PseudoElement) -> bool>,
4058 ) -> Option<Arc<ComputedValues>> {
4059 let style = match pseudo.cascade_type() {
4060 PseudoElementCascadeType::Eager => {
4062 PseudoElement::FirstLetter => {
4063 styles.pseudos.get(&pseudo).map(|pseudo_styles| {
4064 // inherited_styles can be None when doing lazy resolution
4065 // (e.g. for computed style) or when probing. In that case
4066 // we just inherit from our element, which is what Gecko
4067 // does in that situation. What should actually happen in
4068 // the computed style case is a bit unclear.
4069 let inherited_styles = inherited_styles.unwrap_or(styles.primary());
4070 let guards = StylesheetGuards::same(guard);
4071 let inputs = CascadeInputs::new_from_style(pseudo_styles);
4072 stylist.compute_pseudo_element_style_with_inputs(
4076 Some(styles.primary()),
4077 Some(inherited_styles),
4083 // Unfortunately, we can't assert that inherited_styles, if
4084 // present, is pointer-equal to styles.primary(), or even
4085 // equal in any meaningful way. The way it can fail is as
4086 // follows. Say we append an element with a ::before,
4087 // ::after, or ::first-line to a parent with a ::first-line,
4088 // such that the element ends up on the first line of the
4089 // parent (e.g. it's an inline-block in the case it has a
4090 // ::first-line, or any container in the ::before/::after
4091 // cases). Then gecko will update its frame's style to
4092 // inherit from the parent's ::first-line. The next time we
4093 // try to get the ::before/::after/::first-line style for
4094 // the kid, we'll likely pass in the frame's style as
4095 // inherited_styles, but that's not pointer-identical to
4096 // styles.primary(), because it got reparented.
4098 // Now in practice this turns out to be OK, because all the
4099 // cases in which there's a mismatch go ahead and reparent
4100 // styles again as needed to make sure the ::first-line
4101 // affects all the things it should affect. But it makes it
4102 // impossible to assert anything about the two styles
4103 // matching here, unfortunately.
4104 styles.pseudos.get(&pseudo).cloned()
4108 PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
4109 PseudoElementCascadeType::Lazy => {
4111 inherited_styles.is_none() ||
4112 ptr::eq(inherited_styles.unwrap(), &**styles.primary())
4114 let base = if pseudo.inherits_from_default_values() {
4115 stylist.device().default_computed_values_arc()
4119 let guards = StylesheetGuards::same(guard);
4120 stylist.lazily_compute_pseudo_element_style(
4137 Some(style.unwrap_or_else(|| {
4138 StyleBuilder::for_inheritance(stylist.device(), Some(stylist), Some(styles.primary()), Some(pseudo))
4144 pub unsafe extern "C" fn Servo_ComputedValues_Inherit(
4145 raw_data: &PerDocumentStyleData,
4146 pseudo: PseudoStyleType,
4147 parent_style_context: Option<&ComputedValues>,
4148 target: structs::InheritTarget,
4149 ) -> Strong<ComputedValues> {
4150 let data = raw_data.borrow();
4152 let for_text = target == structs::InheritTarget::Text;
4153 let pseudo = PseudoElement::from_pseudo_type(pseudo, None).unwrap();
4154 debug_assert!(pseudo.is_anon_box());
4157 StyleBuilder::for_inheritance(data.stylist.device(), Some(&data.stylist), parent_style_context, Some(&pseudo));
4160 StyleAdjuster::new(&mut style).adjust_for_text();
4163 style.build().into()
4167 pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions(
4168 values: &ComputedValues,
4170 let ui = values.get_ui();
4171 ui.specifies_animations() || ui.specifies_transitions()
4175 pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
4176 values: &ComputedValues,
4177 rules: &mut ThinVec<*const LockedStyleRule>,
4179 let rule_node = match values.rules {
4184 for node in rule_node.self_and_ancestors() {
4185 let style_rule = match node.style_source().and_then(|x| x.as_rule()) {
4190 // For the rules with any important declaration, we insert them into
4191 // rule tree twice, one for normal level and another for important
4192 // level. So, we skip the important one to keep the specificity order of
4194 if node.importance().important() {
4198 rules.push(&*style_rule);
4202 /// println_stderr!() calls Gecko's printf_stderr(), which, unlike eprintln!(),
4203 /// will funnel output to Android logcat.
4204 #[cfg(feature = "gecko_debug")]
4205 macro_rules! println_stderr {
4208 let mut s = nsCString::new();
4209 write!(s, $($e),+).unwrap();
4210 s.write_char('\n').unwrap();
4211 unsafe { bindings::Gecko_PrintfStderr(&s); }
4216 #[cfg(feature = "gecko_debug")]
4217 fn dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet) {
4218 println_stderr!(" Properties:");
4219 for p in properties.iter() {
4220 let mut v = nsCString::new();
4221 cv.computed_or_resolved_value(p, None, &mut v).unwrap();
4222 println_stderr!(" {:?}: {}", p, v);
4227 #[cfg(feature = "gecko_debug")]
4228 fn dump_rules(cv: &ComputedValues) {
4229 println_stderr!(" Rules({:?}):", cv.pseudo());
4230 let global_style_data = &*GLOBAL_STYLE_DATA;
4231 let guard = global_style_data.shared_lock.read();
4232 if let Some(rules) = cv.rules.as_ref() {
4233 for rn in rules.self_and_ancestors() {
4234 if rn.importance().important() {
4237 if let Some(d) = rn.style_source().and_then(|s| s.as_declarations()) {
4238 println_stderr!(" [DeclarationBlock: {:?}]", d);
4240 if let Some(r) = rn.style_source().and_then(|s| s.as_rule()) {
4241 let mut s = nsCString::new();
4242 r.read_with(&guard).to_css(&guard, &mut s).unwrap();
4243 println_stderr!(" {}", s);
4249 #[cfg(feature = "gecko_debug")]
4251 pub extern "C" fn Servo_ComputedValues_EqualForCachedAnonymousContentStyle(
4255 let mut differing_properties = a.differing_properties(b);
4257 // Ignore any difference in -x-lang, which we can't override in the rules in scrollbars.css,
4258 // but which makes no difference for the anonymous content subtrees we cache style for.
4259 differing_properties.remove(LonghandId::XLang);
4260 // Similarly, -x-lang can influence the font-family fallback we have for the initial
4261 // font-family so remove it as well.
4262 differing_properties.remove(LonghandId::FontFamily);
4264 // Ignore any difference in pref-controlled, inherited properties. These properties may or may
4265 // not be set by the 'all' declaration in scrollbars.css, depending on whether the pref was
4266 // enabled at the time the UA sheets were parsed.
4268 // If you add a new pref-controlled, inherited property, it must be defined with
4269 // `has_effect_on_gecko_scrollbars=False` to declare that different values of this property on
4270 // a <scrollbar> element or its descendant scrollbar part elements should have no effect on
4271 // their rendering and behavior.
4273 // If you do need a pref-controlled, inherited property to have an effect on these elements,
4274 // then you will need to add some checks to the
4275 // nsIAnonymousContentCreator::CreateAnonymousContent implementations of nsHTMLScrollFrame and
4276 // nsScrollbarFrame to clear the AnonymousContentKey if a non-initial value is used.
4277 differing_properties.remove_all(&LonghandIdSet::has_no_effect_on_gecko_scrollbars());
4279 if !differing_properties.is_empty() {
4280 println_stderr!("Actual style:");
4281 dump_properties_and_rules(a, &differing_properties);
4282 println_stderr!("Expected style:");
4283 dump_properties_and_rules(b, &differing_properties);
4286 differing_properties.is_empty()
4289 #[cfg(feature = "gecko_debug")]
4291 pub extern "C" fn Servo_ComputedValues_DumpMatchedRules(s: &ComputedValues) {
4296 pub extern "C" fn Servo_ComputedValues_BlockifiedDisplay(
4297 style: &ComputedValues,
4298 is_root_element: bool,
4300 let display = style.get_box().clone_display();
4301 let blockified_display = display.equivalent_block_display(is_root_element);
4302 blockified_display.to_u16()
4306 pub extern "C" fn Servo_StyleSet_Init(doc: &structs::Document) -> *mut PerDocumentStyleData {
4307 let data = Box::new(PerDocumentStyleData::new(doc));
4309 // Do this here rather than in Servo_Initialize since we need a document to
4310 // get the default computed values from.
4311 style::properties::generated::gecko::assert_initial_values_match(&data);
4313 Box::into_raw(data) as *mut PerDocumentStyleData
4317 pub unsafe extern "C" fn Servo_StyleSet_Drop(data: *mut PerDocumentStyleData) {
4318 let _ = Box::from_raw(data);
4322 pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: &PerDocumentStyleData) {
4323 let mut data = raw_data.borrow_mut();
4324 data.stylist.device_mut().rebuild_cached_data();
4325 data.undisplayed_style_cache.clear();
4329 pub unsafe extern "C" fn Servo_StyleSet_CompatModeChanged(raw_data: &PerDocumentStyleData) {
4330 let mut data = raw_data.borrow_mut();
4331 let quirks_mode = data.stylist.device().document().mCompatMode;
4332 data.stylist.set_quirks_mode(quirks_mode.into());
4335 fn parse_property_into(
4336 declarations: &mut SourcePropertyDeclaration,
4337 property_id: PropertyId,
4340 url_data: &UrlExtraData,
4341 parsing_mode: ParsingMode,
4342 quirks_mode: QuirksMode,
4343 rule_type: CssRuleType,
4344 reporter: Option<&dyn ParseErrorReporter>,
4345 ) -> Result<(), ()> {
4346 let value = unsafe { value.as_str_unchecked() };
4348 if let Some(non_custom) = property_id.non_custom_id() {
4349 if !non_custom.allowed_in_rule(rule_type.into()) {
4354 parse_one_declaration_into(
4368 pub unsafe extern "C" fn Servo_ParseProperty(
4369 property: nsCSSPropertyID,
4371 data: *mut URLExtraData,
4372 parsing_mode: ParsingMode,
4373 quirks_mode: nsCompatibility,
4374 loader: *mut Loader,
4375 rule_type: CssRuleType,
4376 ) -> Strong<LockedDeclarationBlock> {
4377 let id = get_property_id_from_nscsspropertyid!(property, Strong::null());
4378 let mut declarations = SourcePropertyDeclaration::default();
4379 let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
4380 let data = UrlExtraData::from_ptr_ref(&data);
4381 let result = parse_property_into(
4390 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4395 let global_style_data = &*GLOBAL_STYLE_DATA;
4396 let mut block = PropertyDeclarationBlock::new();
4397 block.extend(declarations.drain(), Importance::Normal);
4398 Arc::new(global_style_data.shared_lock.wrap(block)).into()
4400 Err(_) => Strong::null(),
4405 pub extern "C" fn Servo_ParseEasing(
4406 easing: &nsACString,
4407 output: &mut ComputedTimingFunction,
4409 use style::properties::longhands::transition_timing_function;
4411 let context = ParserContext::new(
4413 unsafe { dummy_url_data() },
4414 Some(CssRuleType::Style),
4415 ParsingMode::DEFAULT,
4416 QuirksMode::NoQuirks,
4417 /* namespaces = */ Default::default(),
4421 let easing = easing.to_string();
4422 let mut input = ParserInput::new(&easing);
4423 let mut parser = Parser::new(&mut input);
4425 parser.parse_entirely(|p| transition_timing_function::single_value::parse(&context, p));
4427 Ok(parsed_easing) => {
4428 *output = parsed_easing.to_computed_value_without_context();
4436 pub extern "C" fn Servo_SerializeEasing(easing: &ComputedTimingFunction, output: &mut nsACString) {
4437 easing.to_css(&mut CssWriter::new(output)).unwrap();
4441 pub extern "C" fn Servo_GetProperties_Overriding_Animation(
4442 element: &RawGeckoElement,
4443 list: &nsTArray<nsCSSPropertyID>,
4444 set: &mut structs::nsCSSPropertyIDSet,
4446 let element = GeckoElement(element);
4447 let element_data = match element.borrow_data() {
4451 let global_style_data = &*GLOBAL_STYLE_DATA;
4452 let guard = global_style_data.shared_lock.read();
4453 let guards = StylesheetGuards::same(&guard);
4454 let (overridden, custom) = element_data
4458 .get_properties_overriding_animations(&guards);
4459 for p in list.iter() {
4460 match PropertyId::from_nscsspropertyid(*p) {
4462 if let PropertyId::Longhand(id) = property {
4463 if overridden.contains(id) {
4464 unsafe { Gecko_AddPropertyToSet(set, *p) };
4469 if *p == nsCSSPropertyID::eCSSPropertyExtra_variable && custom {
4470 unsafe { Gecko_AddPropertyToSet(set, *p) };
4478 pub extern "C" fn Servo_MatrixTransform_Operate(
4479 matrix_operator: MatrixTransformOperator,
4480 from: *const structs::Matrix4x4Components,
4481 to: *const structs::Matrix4x4Components,
4483 output: *mut structs::Matrix4x4Components,
4485 use self::MatrixTransformOperator::{Accumulate, Interpolate};
4486 use style::values::computed::transform::Matrix3D;
4488 let from = Matrix3D::from(unsafe { from.as_ref() }.expect("not a valid 'from' matrix"));
4489 let to = Matrix3D::from(unsafe { to.as_ref() }.expect("not a valid 'to' matrix"));
4490 let result = match matrix_operator {
4491 Interpolate => from.animate(&to, Procedure::Interpolate { progress }),
4492 Accumulate => from.animate(
4494 Procedure::Accumulate {
4495 count: progress as u64,
4500 let output = unsafe { output.as_mut() }.expect("not a valid 'output' matrix");
4501 if let Ok(result) = result {
4502 *output = result.into();
4503 } else if progress < 0.5 {
4504 *output = from.clone().into();
4506 *output = to.clone().into();
4511 pub unsafe extern "C" fn Servo_ParseStyleAttribute(
4513 raw_extra_data: *mut URLExtraData,
4514 quirks_mode: nsCompatibility,
4515 loader: *mut Loader,
4516 rule_type: CssRuleType,
4517 ) -> Strong<LockedDeclarationBlock> {
4518 let global_style_data = &*GLOBAL_STYLE_DATA;
4519 let value = data.as_str_unchecked();
4520 let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data);
4521 let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
4522 Arc::new(global_style_data.shared_lock.wrap(parse_style_attribute(
4525 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4533 pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> Strong<LockedDeclarationBlock> {
4534 let global_style_data = &*GLOBAL_STYLE_DATA;
4538 .wrap(PropertyDeclarationBlock::new()),
4544 pub extern "C" fn Servo_DeclarationBlock_Clear(declarations: &LockedDeclarationBlock) {
4545 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4551 pub extern "C" fn Servo_DeclarationBlock_Clone(
4552 declarations: &LockedDeclarationBlock,
4553 ) -> Strong<LockedDeclarationBlock> {
4554 let global_style_data = &*GLOBAL_STYLE_DATA;
4555 let guard = global_style_data.shared_lock.read();
4559 .wrap(declarations.read_with(&guard).clone()),
4565 pub extern "C" fn Servo_DeclarationBlock_Equals(
4566 a: &LockedDeclarationBlock,
4567 b: &LockedDeclarationBlock,
4569 let global_style_data = &*GLOBAL_STYLE_DATA;
4570 let guard = global_style_data.shared_lock.read();
4571 a.read_with(&guard).declarations() == b.read_with(&guard).declarations()
4575 pub extern "C" fn Servo_DeclarationBlock_GetCssText(
4576 declarations: &LockedDeclarationBlock,
4577 result: &mut nsACString,
4579 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4580 decls.to_css(result).unwrap()
4585 pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
4586 decls: &LockedDeclarationBlock,
4587 property_id: nsCSSPropertyID,
4588 buffer: &mut nsACString,
4589 computed_values: Option<&ComputedValues>,
4590 custom_properties: Option<&LockedDeclarationBlock>,
4591 data: &PerDocumentStyleData,
4593 let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
4595 let global_style_data = &*GLOBAL_STYLE_DATA;
4596 let guard = global_style_data.shared_lock.read();
4597 let custom_properties = custom_properties.map(|block| block.read_with(&guard));
4598 let data = data.borrow();
4599 let rv = decls.read_with(&guard).single_value_to_css(
4606 debug_assert!(rv.is_ok());
4610 pub unsafe extern "C" fn Servo_SerializeFontValueForCanvas(
4611 declarations: &LockedDeclarationBlock,
4612 buffer: &mut nsACString,
4614 use style::properties::shorthands::font;
4615 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4616 let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) {
4619 warn!("Unexpected property!");
4624 let rv = longhands.to_css(&mut CssWriter::new(buffer));
4625 debug_assert!(rv.is_ok());
4630 pub extern "C" fn Servo_DeclarationBlock_Count(declarations: &LockedDeclarationBlock) -> u32 {
4631 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4632 decls.declarations().len() as u32
4637 pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(
4638 declarations: &LockedDeclarationBlock,
4640 result: &mut nsACString,
4642 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4643 if let Some(decl) = decls.declarations().get(index as usize) {
4644 result.assign(&decl.id().name());
4652 macro_rules! get_property_id_from_property {
4653 ($property: ident, $ret: expr) => {{
4654 let property = $property.as_str_unchecked();
4655 match PropertyId::parse_enabled_for_all_content(property) {
4656 Ok(property_id) => property_id,
4657 Err(_) => return $ret,
4662 unsafe fn get_property_value(
4663 declarations: &LockedDeclarationBlock,
4664 property_id: PropertyId,
4665 value: &mut nsACString,
4667 // This callsite is hot enough that the lock acquisition shows up in profiles.
4668 // Using an unchecked read here improves our performance by ~10% on the
4669 // microbenchmark in bug 1355599.
4670 read_locked_arc_unchecked(declarations, |decls: &PropertyDeclarationBlock| {
4671 decls.property_value_to_css(&property_id, value).unwrap();
4676 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValue(
4677 declarations: &LockedDeclarationBlock,
4678 property: &nsACString,
4679 value: &mut nsACString,
4683 get_property_id_from_property!(property, ()),
4689 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(
4690 declarations: &LockedDeclarationBlock,
4691 property: nsCSSPropertyID,
4692 value: &mut nsACString,
4696 get_property_id_from_nscsspropertyid!(property, ()),
4702 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(
4703 declarations: &LockedDeclarationBlock,
4704 property: &nsACString,
4706 let property_id = get_property_id_from_property!(property, false);
4707 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4708 decls.property_priority(&property_id).important()
4713 fn set_property_to_declarations(
4714 non_custom_property_id: Option<NonCustomPropertyId>,
4715 block: &LockedDeclarationBlock,
4716 parsed_declarations: &mut SourcePropertyDeclaration,
4717 before_change_closure: DeclarationBlockMutationClosure,
4718 importance: Importance,
4720 let mut updates = Default::default();
4721 let will_change = read_locked_arc(block, |decls: &PropertyDeclarationBlock| {
4722 decls.prepare_for_update(&parsed_declarations, importance, &mut updates)
4728 before_change_closure.invoke(non_custom_property_id);
4729 write_locked_arc(block, |decls: &mut PropertyDeclarationBlock| {
4730 decls.update(parsed_declarations.drain(), importance, &mut updates)
4736 declarations: &LockedDeclarationBlock,
4737 property_id: PropertyId,
4740 data: &UrlExtraData,
4741 parsing_mode: ParsingMode,
4742 quirks_mode: QuirksMode,
4743 loader: *mut Loader,
4744 rule_type: CssRuleType,
4745 before_change_closure: DeclarationBlockMutationClosure,
4747 let mut source_declarations = SourcePropertyDeclaration::default();
4748 let reporter = ErrorReporter::new(ptr::null_mut(), loader, data.ptr());
4749 let non_custom_property_id = property_id.non_custom_id();
4750 let result = parse_property_into(
4751 &mut source_declarations,
4759 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4762 if result.is_err() {
4766 let importance = if is_important {
4767 Importance::Important
4772 set_property_to_declarations(
4773 non_custom_property_id,
4775 &mut source_declarations,
4776 before_change_closure,
4782 pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
4783 declarations: &LockedDeclarationBlock,
4784 property: &nsACString,
4787 data: *mut URLExtraData,
4788 parsing_mode: ParsingMode,
4789 quirks_mode: nsCompatibility,
4790 loader: *mut Loader,
4791 rule_type: CssRuleType,
4792 before_change_closure: DeclarationBlockMutationClosure,
4796 get_property_id_from_property!(property, false),
4799 UrlExtraData::from_ptr_ref(&data),
4804 before_change_closure,
4809 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
4810 declarations: &LockedDeclarationBlock,
4811 animation_value: &AnimationValue,
4812 before_change_closure: DeclarationBlockMutationClosure,
4814 let non_custom_property_id = animation_value.id().into();
4815 let mut source_declarations = SourcePropertyDeclaration::with_one(animation_value.uncompute());
4817 set_property_to_declarations(
4818 Some(non_custom_property_id),
4820 &mut source_declarations,
4821 before_change_closure,
4827 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
4828 declarations: &LockedDeclarationBlock,
4829 property: nsCSSPropertyID,
4832 data: *mut URLExtraData,
4833 parsing_mode: ParsingMode,
4834 quirks_mode: nsCompatibility,
4835 loader: *mut Loader,
4836 rule_type: CssRuleType,
4837 before_change_closure: DeclarationBlockMutationClosure,
4841 get_property_id_from_nscsspropertyid!(property, false),
4844 UrlExtraData::from_ptr_ref(&data),
4849 before_change_closure,
4854 declarations: &LockedDeclarationBlock,
4855 property_id: PropertyId,
4856 before_change_closure: DeclarationBlockMutationClosure,
4858 let first_declaration = read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4859 decls.first_declaration_to_remove(&property_id)
4862 let first_declaration = match first_declaration {
4864 None => return false,
4867 before_change_closure.invoke(property_id.non_custom_id());
4868 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4869 decls.remove_property(&property_id, first_declaration)
4876 pub unsafe extern "C" fn Servo_DeclarationBlock_RemoveProperty(
4877 declarations: &LockedDeclarationBlock,
4878 property: &nsACString,
4879 before_change_closure: DeclarationBlockMutationClosure,
4883 get_property_id_from_property!(property, false),
4884 before_change_closure,
4889 pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(
4890 declarations: &LockedDeclarationBlock,
4891 property: nsCSSPropertyID,
4892 before_change_closure: DeclarationBlockMutationClosure,
4896 get_property_id_from_nscsspropertyid!(property, false),
4897 before_change_closure,
4902 pub extern "C" fn Servo_MediaList_Create() -> Strong<LockedMediaList> {
4903 let global_style_data = &*GLOBAL_STYLE_DATA;
4904 Arc::new(global_style_data.shared_lock.wrap(MediaList::empty())).into()
4908 pub extern "C" fn Servo_MediaList_DeepClone(list: &LockedMediaList) -> Strong<LockedMediaList> {
4909 let global_style_data = &*GLOBAL_STYLE_DATA;
4910 read_locked_arc(list, |list: &MediaList| {
4911 Arc::new(global_style_data.shared_lock.wrap(list.clone())).into()
4916 pub extern "C" fn Servo_MediaList_Matches(
4917 list: &LockedMediaList,
4918 raw_data: &PerDocumentStyleData,
4920 let per_doc_data = raw_data.borrow();
4921 read_locked_arc(list, |list: &MediaList| {
4923 per_doc_data.stylist.device(),
4924 per_doc_data.stylist.quirks_mode(),
4930 pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword(
4931 declarations: &LockedDeclarationBlock,
4932 property: nsCSSPropertyID,
4934 let property_id = get_property_id_from_nscsspropertyid!(property, false);
4935 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4936 decls.has_css_wide_keyword(&property_id)
4941 pub extern "C" fn Servo_MediaList_GetText(list: &LockedMediaList, result: &mut nsACString) {
4942 read_locked_arc(list, |list: &MediaList| {
4943 list.to_css(&mut CssWriter::new(result)).unwrap();
4948 pub unsafe extern "C" fn Servo_MediaList_SetText(
4949 list: &LockedMediaList,
4951 caller_type: CallerType,
4953 let text = text.as_str_unchecked();
4955 let mut input = ParserInput::new(&text);
4956 let mut parser = Parser::new(&mut input);
4957 let url_data = dummy_url_data();
4959 // TODO(emilio): If the need for `CallerType` appears in more places,
4960 // consider adding an explicit member in `ParserContext` instead of doing
4961 // this (or adding a dummy "chrome://" url data).
4963 // For media query parsing it's effectively the same, so for now...
4964 let origin = match caller_type {
4965 CallerType::System => Origin::UserAgent,
4966 CallerType::NonSystem => Origin::Author,
4969 let context = ParserContext::new(
4972 Some(CssRuleType::Media),
4973 ParsingMode::DEFAULT,
4974 QuirksMode::NoQuirks,
4975 /* namespaces = */ Default::default(),
4976 // TODO(emilio): Looks like error reporting could be useful here?
4981 write_locked_arc(list, |list: &mut MediaList| {
4982 *list = MediaList::parse(&context, &mut parser);
4987 pub extern "C" fn Servo_MediaList_IsViewportDependent(list: &LockedMediaList) -> bool {
4988 read_locked_arc(list, |list: &MediaList| list.is_viewport_dependent())
4992 pub extern "C" fn Servo_MediaList_GetLength(list: &LockedMediaList) -> u32 {
4993 read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32)
4997 pub extern "C" fn Servo_MediaList_GetMediumAt(
4998 list: &LockedMediaList,
5000 result: &mut nsACString,
5002 read_locked_arc(list, |list: &MediaList| {
5003 let media_query = match list.media_queries.get(index as usize) {
5005 None => return false,
5007 media_query.to_css(&mut CssWriter::new(result)).unwrap();
5013 pub extern "C" fn Servo_MediaList_AppendMedium(list: &LockedMediaList, new_medium: &nsACString) {
5014 let new_medium = unsafe { new_medium.as_str_unchecked() };
5015 let url_data = unsafe { dummy_url_data() };
5016 let context = ParserContext::new(
5019 Some(CssRuleType::Media),
5020 ParsingMode::DEFAULT,
5021 QuirksMode::NoQuirks,
5022 /* namespaces = */ Default::default(),
5026 write_locked_arc(list, |list: &mut MediaList| {
5027 list.append_medium(&context, new_medium);
5032 pub extern "C" fn Servo_MediaList_DeleteMedium(
5033 list: &LockedMediaList,
5034 old_medium: &nsACString,
5036 let old_medium = unsafe { old_medium.as_str_unchecked() };
5037 let url_data = unsafe { dummy_url_data() };
5038 let context = ParserContext::new(
5041 Some(CssRuleType::Media),
5042 ParsingMode::DEFAULT,
5043 QuirksMode::NoQuirks,
5044 /* namespaces = */ Default::default(),
5048 write_locked_arc(list, |list: &mut MediaList| {
5049 list.delete_medium(&context, old_medium)
5054 pub extern "C" fn Servo_MediaList_SizeOfIncludingThis(
5055 malloc_size_of: GeckoMallocSizeOf,
5056 malloc_enclosing_size_of: GeckoMallocSizeOf,
5057 list: &LockedMediaList,
5059 use malloc_size_of::MallocSizeOf;
5060 use malloc_size_of::MallocUnconditionalShallowSizeOf;
5062 let global_style_data = &*GLOBAL_STYLE_DATA;
5063 let guard = global_style_data.shared_lock.read();
5065 let mut ops = MallocSizeOfOps::new(
5066 malloc_size_of.unwrap(),
5067 Some(malloc_enclosing_size_of.unwrap()),
5071 unsafe { ArcBorrow::from_ref(list) }.with_arc(|list| {
5073 n += list.unconditional_shallow_size_of(&mut ops);
5074 n += list.read_with(&guard).size_of(&mut ops);
5079 macro_rules! get_longhand_from_id {
5081 match PropertyId::from_nscsspropertyid($id) {
5082 Ok(PropertyId::Longhand(long)) => long,
5083 _ => panic!("stylo: unknown presentation property with id"),
5088 macro_rules! match_wrap_declared {
5089 ($longhand:ident, $($property:ident => $inner:expr,)*) => (
5092 LonghandId::$property => PropertyDeclaration::$property($inner),
5095 panic!("stylo: Don't know how to handle presentation property");
5102 pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(
5103 declarations: &LockedDeclarationBlock,
5104 property: nsCSSPropertyID,
5106 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
5107 decls.contains(PropertyDeclarationId::Longhand(get_longhand_from_id!(
5114 pub unsafe extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(
5115 declarations: &LockedDeclarationBlock,
5116 property: nsCSSPropertyID,
5119 use style::properties::longhands::_x_lang::computed_value::T as Lang;
5120 use style::properties::PropertyDeclaration;
5122 let long = get_longhand_from_id!(property);
5123 let prop = match_wrap_declared! { long,
5124 XLang => Lang(Atom::from_raw(value)),
5126 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5127 decls.push(prop, Importance::Normal);
5132 #[allow(unreachable_code)]
5133 pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
5134 declarations: &LockedDeclarationBlock,
5135 property: nsCSSPropertyID,
5138 use num_traits::FromPrimitive;
5139 use style::properties::longhands;
5140 use style::properties::PropertyDeclaration;
5141 use style::values::generics::box_::{VerticalAlign, VerticalAlignKeyword};
5142 use style::values::generics::font::FontStyle;
5143 use style::values::specified::{
5144 table::CaptionSide, BorderStyle, Clear, Display, Float, TextAlign, TextEmphasisPosition, TextTransform
5147 fn get_from_computed<T>(value: u32) -> T
5150 T::ComputedValue: FromPrimitive,
5152 T::from_computed_value(&T::ComputedValue::from_u32(value).unwrap())
5155 let long = get_longhand_from_id!(property);
5156 let value = value as u32;
5158 let prop = match_wrap_declared! { long,
5159 MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value),
5160 Direction => get_from_computed::<longhands::direction::SpecifiedValue>(value),
5161 Display => get_from_computed::<Display>(value),
5162 Float => get_from_computed::<Float>(value),
5163 Clear => get_from_computed::<Clear>(value),
5164 VerticalAlign => VerticalAlign::Keyword(VerticalAlignKeyword::from_u32(value).unwrap()),
5165 TextAlign => get_from_computed::<TextAlign>(value),
5166 TextEmphasisPosition => TextEmphasisPosition::from_bits_truncate(value as u8),
5168 // We rely on Gecko passing in font-size values (0...7) here.
5169 longhands::font_size::SpecifiedValue::from_html_size(value as u8)
5172 style::values::specified::FontStyle::Specified(if value == structs::NS_FONT_STYLE_ITALIC {
5175 debug_assert_eq!(value, structs::NS_FONT_STYLE_NORMAL);
5179 FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value),
5180 ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
5181 MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value),
5182 MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
5183 WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value),
5184 CaptionSide => get_from_computed::<CaptionSide>(value),
5185 BorderTopStyle => get_from_computed::<BorderStyle>(value),
5186 BorderRightStyle => get_from_computed::<BorderStyle>(value),
5187 BorderBottomStyle => get_from_computed::<BorderStyle>(value),
5188 BorderLeftStyle => get_from_computed::<BorderStyle>(value),
5190 debug_assert_eq!(value, structs::StyleTextTransformCase_None as u32);
5191 TextTransform::none()
5194 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5195 decls.push(prop, Importance::Normal);
5200 pub extern "C" fn Servo_DeclarationBlock_SetIntValue(
5201 declarations: &LockedDeclarationBlock,
5202 property: nsCSSPropertyID,
5205 use style::properties::PropertyDeclaration;
5206 use style::values::specified::Integer;
5208 let long = get_longhand_from_id!(property);
5209 let prop = match_wrap_declared! { long,
5210 XSpan => Integer::new(value),
5212 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5213 decls.push(prop, Importance::Normal);
5218 pub extern "C" fn Servo_DeclarationBlock_SetMathDepthValue(
5219 declarations: &LockedDeclarationBlock,
5223 use style::properties::longhands::math_depth::SpecifiedValue as MathDepth;
5224 use style::properties::PropertyDeclaration;
5226 let integer_value = style::values::specified::Integer::new(value);
5227 let prop = PropertyDeclaration::MathDepth(if is_relative {
5228 MathDepth::Add(integer_value)
5230 MathDepth::Absolute(integer_value)
5232 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5233 decls.push(prop, Importance::Normal);
5238 pub extern "C" fn Servo_DeclarationBlock_SetCounterResetListItem(
5239 declarations: &LockedDeclarationBlock,
5243 use style::properties::PropertyDeclaration;
5244 use style::values::generics::counters::{CounterPair, CounterReset};
5246 let prop = PropertyDeclaration::CounterReset(CounterReset::new(vec![CounterPair {
5247 name: CustomIdent(atom!("list-item")),
5248 value: style::values::specified::Integer::new(counter_value),
5251 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5252 decls.push(prop, Importance::Normal);
5257 pub extern "C" fn Servo_DeclarationBlock_SetCounterSetListItem(
5258 declarations: &LockedDeclarationBlock,
5261 use style::properties::PropertyDeclaration;
5262 use style::values::generics::counters::{CounterPair, CounterSet};
5264 let prop = PropertyDeclaration::CounterSet(CounterSet::new(vec![CounterPair {
5265 name: CustomIdent(atom!("list-item")),
5266 value: style::values::specified::Integer::new(counter_value),
5269 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5270 decls.push(prop, Importance::Normal);
5275 pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
5276 declarations: &LockedDeclarationBlock,
5277 property: nsCSSPropertyID,
5280 use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
5281 use style::properties::PropertyDeclaration;
5282 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5283 use style::values::generics::NonNegative;
5284 use style::values::specified::length::{
5285 LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage,
5287 use style::values::specified::{BorderCornerRadius, BorderSideWidth};
5289 let long = get_longhand_from_id!(property);
5290 let nocalc = NoCalcLength::from_px(value);
5291 let lp = LengthPercentage::Length(nocalc);
5292 let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
5293 let prop = match_wrap_declared! { long,
5294 Height => Size::LengthPercentage(NonNegative(lp)),
5295 Width => Size::LengthPercentage(NonNegative(lp)),
5296 BorderTopWidth => BorderSideWidth::from_px(value),
5297 BorderRightWidth => BorderSideWidth::from_px(value),
5298 BorderBottomWidth => BorderSideWidth::from_px(value),
5299 BorderLeftWidth => BorderSideWidth::from_px(value),
5300 MarginTop => lp_or_auto,
5301 MarginRight => lp_or_auto,
5302 MarginBottom => lp_or_auto,
5303 MarginLeft => lp_or_auto,
5304 PaddingTop => NonNegative(lp),
5305 PaddingRight => NonNegative(lp),
5306 PaddingBottom => NonNegative(lp),
5307 PaddingLeft => NonNegative(lp),
5309 let v = NonNegativeLength::from(nocalc);
5310 Box::new(BorderSpacing::new(v.clone(), v))
5312 BorderTopLeftRadius => {
5313 let length = NonNegativeLengthPercentage::from(nocalc);
5314 Box::new(BorderCornerRadius::new(length.clone(), length))
5316 BorderTopRightRadius => {
5317 let length = NonNegativeLengthPercentage::from(nocalc);
5318 Box::new(BorderCornerRadius::new(length.clone(), length))
5320 BorderBottomLeftRadius => {
5321 let length = NonNegativeLengthPercentage::from(nocalc);
5322 Box::new(BorderCornerRadius::new(length.clone(), length))
5324 BorderBottomRightRadius => {
5325 let length = NonNegativeLengthPercentage::from(nocalc);
5326 Box::new(BorderCornerRadius::new(length.clone(), length))
5329 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5330 decls.push(prop, Importance::Normal);
5335 pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
5336 declarations: &LockedDeclarationBlock,
5337 property: nsCSSPropertyID,
5339 unit: structs::nsCSSUnit,
5341 use style::properties::PropertyDeclaration;
5342 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5343 use style::values::generics::NonNegative;
5344 use style::values::specified::length::{FontRelativeLength, LengthPercentage};
5345 use style::values::specified::FontSize;
5347 let long = get_longhand_from_id!(property);
5348 let nocalc = match unit {
5349 structs::nsCSSUnit::eCSSUnit_EM => {
5350 NoCalcLength::FontRelative(FontRelativeLength::Em(value))
5352 structs::nsCSSUnit::eCSSUnit_XHeight => {
5353 NoCalcLength::FontRelative(FontRelativeLength::Ex(value))
5355 structs::nsCSSUnit::eCSSUnit_Pixel => NoCalcLength::Absolute(AbsoluteLength::Px(value)),
5356 structs::nsCSSUnit::eCSSUnit_Inch => NoCalcLength::Absolute(AbsoluteLength::In(value)),
5357 structs::nsCSSUnit::eCSSUnit_Centimeter => {
5358 NoCalcLength::Absolute(AbsoluteLength::Cm(value))
5360 structs::nsCSSUnit::eCSSUnit_Millimeter => {
5361 NoCalcLength::Absolute(AbsoluteLength::Mm(value))
5363 structs::nsCSSUnit::eCSSUnit_Point => NoCalcLength::Absolute(AbsoluteLength::Pt(value)),
5364 structs::nsCSSUnit::eCSSUnit_Pica => NoCalcLength::Absolute(AbsoluteLength::Pc(value)),
5365 structs::nsCSSUnit::eCSSUnit_Quarter => NoCalcLength::Absolute(AbsoluteLength::Q(value)),
5366 _ => unreachable!("Unknown unit passed to SetLengthValue"),
5369 let prop = match_wrap_declared! { long,
5370 Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5371 Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5372 X => LengthPercentage::Length(nocalc),
5373 Y => LengthPercentage::Length(nocalc),
5374 Cx => LengthPercentage::Length(nocalc),
5375 Cy => LengthPercentage::Length(nocalc),
5376 R => NonNegative(LengthPercentage::Length(nocalc)),
5377 Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5378 Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5379 FontSize => FontSize::Length(LengthPercentage::Length(nocalc)),
5381 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5382 decls.push(prop, Importance::Normal);
5387 pub extern "C" fn Servo_DeclarationBlock_SetPathValue(
5388 declarations: &LockedDeclarationBlock,
5389 property: nsCSSPropertyID,
5390 path: &nsTArray<f32>,
5392 use style::properties::PropertyDeclaration;
5393 use style::values::specified::DProperty;
5395 // 1. Decode the path data from SVG.
5396 let path = match specified::SVGPathData::decode_from_f32_array(path) {
5401 // 2. Set decoded path into style.
5402 let long = get_longhand_from_id!(property);
5403 let prop = match_wrap_declared! { long,
5404 D => if path.0.is_empty() { DProperty::None } else { DProperty::Path(path) },
5406 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5407 decls.push(prop, Importance::Normal);
5412 pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
5413 declarations: &LockedDeclarationBlock,
5414 property: nsCSSPropertyID,
5417 use style::properties::PropertyDeclaration;
5418 use style::values::computed::Percentage;
5419 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5420 use style::values::generics::NonNegative;
5421 use style::values::specified::length::LengthPercentage;
5422 use style::values::specified::FontSize;
5424 let long = get_longhand_from_id!(property);
5425 let pc = Percentage(value);
5426 let lp = LengthPercentage::Percentage(pc);
5427 let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
5429 let prop = match_wrap_declared! { long,
5430 Height => Size::LengthPercentage(NonNegative(lp)),
5431 Width => Size::LengthPercentage(NonNegative(lp)),
5436 R => NonNegative(lp),
5437 Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5438 Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5439 MarginTop => lp_or_auto,
5440 MarginRight => lp_or_auto,
5441 MarginBottom => lp_or_auto,
5442 MarginLeft => lp_or_auto,
5443 FontSize => FontSize::Length(LengthPercentage::Percentage(pc)),
5445 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5446 decls.push(prop, Importance::Normal);
5451 pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(
5452 declarations: &LockedDeclarationBlock,
5453 property: nsCSSPropertyID,
5455 use style::properties::PropertyDeclaration;
5456 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5458 let long = get_longhand_from_id!(property);
5459 let auto = LengthPercentageOrAuto::Auto;
5461 let prop = match_wrap_declared! { long,
5462 Height => Size::auto(),
5463 Width => Size::auto(),
5465 MarginRight => auto,
5466 MarginBottom => auto,
5468 AspectRatio => specified::AspectRatio::auto(),
5470 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5471 decls.push(prop, Importance::Normal);
5476 pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(
5477 declarations: &LockedDeclarationBlock,
5478 property: nsCSSPropertyID,
5480 use style::properties::PropertyDeclaration;
5481 use style::values::specified::Color;
5483 let long = get_longhand_from_id!(property);
5484 let cc = Color::currentcolor();
5486 let prop = match_wrap_declared! { long,
5487 BorderTopColor => cc,
5488 BorderRightColor => cc,
5489 BorderBottomColor => cc,
5490 BorderLeftColor => cc,
5492 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5493 decls.push(prop, Importance::Normal);
5498 pub extern "C" fn Servo_DeclarationBlock_SetColorValue(
5499 declarations: &LockedDeclarationBlock,
5500 property: nsCSSPropertyID,
5501 value: structs::nscolor,
5503 use style::gecko::values::convert_nscolor_to_absolute_color;
5504 use style::properties::longhands;
5505 use style::properties::PropertyDeclaration;
5506 use style::values::specified::Color;
5508 let long = get_longhand_from_id!(property);
5509 let rgba = convert_nscolor_to_absolute_color(value);
5510 let color = Color::from_absolute_color(rgba);
5512 let prop = match_wrap_declared! { long,
5513 BorderTopColor => color,
5514 BorderRightColor => color,
5515 BorderBottomColor => color,
5516 BorderLeftColor => color,
5517 Color => longhands::color::SpecifiedValue(color),
5518 BackgroundColor => color,
5520 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5521 decls.push(prop, Importance::Normal);
5526 pub unsafe extern "C" fn Servo_DeclarationBlock_SetFontFamily(
5527 declarations: &LockedDeclarationBlock,
5530 use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
5531 use style::properties::PropertyDeclaration;
5533 let string = value.as_str_unchecked();
5534 let mut input = ParserInput::new(&string);
5535 let mut parser = Parser::new(&mut input);
5536 let context = ParserContext::new(
5539 Some(CssRuleType::Style),
5540 ParsingMode::DEFAULT,
5541 QuirksMode::NoQuirks,
5542 /* namespaces = */ Default::default(),
5546 let result = FontFamily::parse(&context, &mut parser);
5547 if let Ok(family) = result {
5548 if parser.is_exhausted() {
5549 let decl = PropertyDeclaration::FontFamily(family);
5550 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5551 decls.push(decl, Importance::Normal);
5558 pub unsafe extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(
5559 declarations: &LockedDeclarationBlock,
5561 raw_extra_data: *mut URLExtraData,
5563 use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
5564 use style::properties::PropertyDeclaration;
5565 use style::stylesheets::CorsMode;
5566 use style::values::generics::image::Image;
5567 use style::values::specified::url::SpecifiedImageUrl;
5569 let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
5570 let string = value.as_str_unchecked();
5571 let context = ParserContext::new(
5574 Some(CssRuleType::Style),
5575 ParsingMode::DEFAULT,
5576 QuirksMode::NoQuirks,
5577 /* namespaces = */ Default::default(),
5581 let url = SpecifiedImageUrl::parse_from_string(string.into(), &context, CorsMode::None);
5582 let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(vec![Image::Url(url)].into()));
5583 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5584 decls.push(decl, Importance::Normal);
5589 pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(
5590 declarations: &LockedDeclarationBlock,
5592 use style::properties::PropertyDeclaration;
5593 use style::values::specified::text::TextDecorationLine;
5595 let decoration = TextDecorationLine::COLOR_OVERRIDE;
5596 let decl = PropertyDeclaration::TextDecorationLine(decoration);
5597 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5598 decls.push(decl, Importance::Normal);
5603 pub extern "C" fn Servo_DeclarationBlock_SetAspectRatio(
5604 declarations: &LockedDeclarationBlock,
5608 use style::properties::PropertyDeclaration;
5609 use style::values::generics::position::AspectRatio;
5611 let decl = PropertyDeclaration::AspectRatio(AspectRatio::from_mapped_ratio(width, height));
5612 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5613 decls.push(decl, Importance::Normal);
5618 pub extern "C" fn Servo_CSSSupports2(property: &nsACString, value: &nsACString) -> bool {
5619 let id = unsafe { get_property_id_from_property!(property, false) };
5621 let mut declarations = SourcePropertyDeclaration::default();
5622 parse_property_into(
5627 unsafe { dummy_url_data() },
5628 ParsingMode::DEFAULT,
5629 QuirksMode::NoQuirks,
5637 pub extern "C" fn Servo_CSSSupports(
5643 let condition = unsafe { cond.as_str_unchecked() };
5644 let mut input = ParserInput::new(&condition);
5645 let mut input = Parser::new(&mut input);
5646 let cond = match input.parse_entirely(parse_condition_or_declaration) {
5648 Err(..) => return false,
5651 let origin = if ua_origin {
5656 let url_data = unsafe {
5657 UrlExtraData::from_ptr_ref(if chrome_sheet {
5658 &DUMMY_CHROME_URL_DATA
5663 let quirks_mode = if quirks {
5666 QuirksMode::NoQuirks
5669 // NOTE(emilio): The supports API is not associated to any stylesheet,
5670 // so the fact that there is no namespace map here is fine.
5671 let context = ParserContext::new(
5674 Some(CssRuleType::Style),
5675 ParsingMode::DEFAULT,
5677 /* namespaces = */ Default::default(),
5686 pub extern "C" fn Servo_CSSSupportsForImport(after_rule: &nsACString) -> bool {
5687 let condition = unsafe { after_rule.as_str_unchecked() };
5688 let mut input = ParserInput::new(&condition);
5689 let mut input = Parser::new(&mut input);
5691 // NOTE(emilio): The supports API is not associated to any stylesheet,
5692 // so the fact that there is no namespace map here is fine.
5693 let mut context = ParserContext::new(
5695 unsafe { dummy_url_data() },
5696 Some(CssRuleType::Style),
5697 ParsingMode::DEFAULT,
5698 QuirksMode::NoQuirks,
5699 /* namespaces = */ Default::default(),
5704 let (_layer, supports) = ImportRule::parse_layer_and_supports(&mut input, &mut context);
5706 supports.map_or(true, |s| s.enabled)
5710 pub unsafe extern "C" fn Servo_NoteExplicitHints(
5711 element: &RawGeckoElement,
5712 restyle_hint: RestyleHint,
5713 change_hint: nsChangeHint,
5715 GeckoElement(element).note_explicit_hints(restyle_hint, change_hint);
5719 pub extern "C" fn Servo_TakeChangeHint(element: &RawGeckoElement, was_restyled: &mut bool) -> u32 {
5720 let element = GeckoElement(element);
5722 let damage = match element.mutate_data() {
5724 *was_restyled = data.is_restyle();
5726 let damage = data.damage;
5727 data.clear_restyle_state();
5731 warn!("Trying to get change hint from unstyled element");
5732 *was_restyled = false;
5733 GeckoRestyleDamage::empty()
5737 debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
5738 // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
5739 // work as return values with the Linux 32-bit ABI at the moment because
5740 // they wrap the value in a struct, so for now just unwrap it.
5741 damage.as_change_hint().0
5745 pub extern "C" fn Servo_ResolveStyle(element: &RawGeckoElement) -> Strong<ComputedValues> {
5746 let element = GeckoElement(element);
5747 debug!("Servo_ResolveStyle: {:?}", element);
5750 .expect("Resolving style on unstyled element");
5753 element.has_current_styles(&*data),
5754 "Resolving style on {:?} without current styles: {:?}",
5758 data.styles.primary().clone().into()
5762 pub extern "C" fn Servo_ResolveStyleLazily(
5763 element: &RawGeckoElement,
5764 pseudo_type: PseudoStyleType,
5765 functional_pseudo_parameter: *mut nsAtom,
5766 rule_inclusion: StyleRuleInclusion,
5767 snapshots: *const ServoElementSnapshotTable,
5768 cache_generation: u64,
5769 can_use_cache: bool,
5770 raw_data: &PerDocumentStyleData,
5771 ) -> Strong<ComputedValues> {
5772 use selectors::Element;
5773 debug_assert!(!snapshots.is_null());
5774 let global_style_data = &*GLOBAL_STYLE_DATA;
5775 let guard = global_style_data.shared_lock.read();
5776 let element = GeckoElement(element);
5777 let mut data = raw_data.borrow_mut();
5778 let data = &mut *data;
5779 let rule_inclusion = RuleInclusion::from(rule_inclusion);
5780 let pseudo_element = PseudoElement::from_pseudo_type(
5782 get_functional_pseudo_parameter_atom(functional_pseudo_parameter),
5785 let matching_fn = |pseudo: &PseudoElement| match pseudo_element {
5786 Some(ref p) => *pseudo == *p,
5790 if cache_generation != data.undisplayed_style_cache_generation {
5791 data.undisplayed_style_cache.clear();
5792 data.undisplayed_style_cache_generation = cache_generation;
5795 let stylist = &data.stylist;
5796 let finish = |styles: &ElementStyles, is_probe: bool| -> Option<Arc<ComputedValues>> {
5797 match pseudo_element {
5798 Some(ref pseudo) => {
5805 /* inherited_styles = */ None,
5808 if pseudo.is_highlight() {
5815 None => Some(styles.primary().clone()),
5819 let is_before_or_after = pseudo_element
5821 .map_or(false, |p| p.is_before_or_after());
5823 // In the common case we already have the style. Check that before setting
5824 // up all the computation machinery.
5826 // Also, only probe in the ::before or ::after case, since their styles may
5827 // not be in the `ElementData`, given they may exist but not be applicable
5828 // to generate an actual pseudo-element (like, having a `content: none`).
5829 if rule_inclusion == RuleInclusion::All {
5830 let styles = element.borrow_data().and_then(|d| {
5832 finish(&d.styles, is_before_or_after)
5837 if let Some(result) = styles {
5838 return result.into();
5840 if pseudo_element.is_none() && can_use_cache {
5841 if let Some(style) = data.undisplayed_style_cache.get(&element.opaque()) {
5842 return style.clone().into();
5847 // We don't have the style ready. Go ahead and compute it as necessary.
5848 let shared = create_shared_context(
5852 TraversalFlags::empty(),
5853 unsafe { &*snapshots },
5855 let mut tlc = ThreadLocalStyleContext::new();
5856 let mut context = StyleContext {
5858 thread_local: &mut tlc,
5861 let styles = resolve_style(
5865 pseudo_element.as_ref(),
5867 Some(&mut data.undisplayed_style_cache)
5873 finish(&styles, /* is_probe = */ false)
5874 .expect("We're not probing, so we should always get a style back")
5879 pub extern "C" fn Servo_ReparentStyle(
5880 style_to_reparent: &ComputedValues,
5881 parent_style: &ComputedValues,
5882 layout_parent_style: &ComputedValues,
5883 element: Option<&RawGeckoElement>,
5884 raw_data: &PerDocumentStyleData,
5885 ) -> Strong<ComputedValues> {
5886 use style::properties::FirstLineReparenting;
5888 let global_style_data = &*GLOBAL_STYLE_DATA;
5889 let guard = global_style_data.shared_lock.read();
5890 let doc_data = raw_data.borrow();
5891 let inputs = CascadeInputs::new_from_style(style_to_reparent);
5892 let pseudo = style_to_reparent.pseudo();
5893 let element = element.map(GeckoElement);
5895 let is_pseudo_element = element.is_some() && pseudo.is_some();
5896 let originating_element_style = if is_pseudo_element {
5904 .cascade_style_and_visited(
5908 &StylesheetGuards::same(&guard),
5909 originating_element_style,
5911 Some(layout_parent_style),
5912 FirstLineReparenting::Yes { style_to_reparent },
5913 /* rule_cache = */ None,
5914 &mut RuleCacheConditions::default(),
5919 #[cfg(feature = "gecko_debug")]
5920 fn simulate_compute_values_failure(property: &PropertyValuePair) -> bool {
5921 let p = property.mProperty;
5922 let id = get_property_id_from_nscsspropertyid!(p, false);
5923 id.as_shorthand().is_ok() && property.mSimulateComputeValuesFailure
5926 #[cfg(not(feature = "gecko_debug"))]
5927 fn simulate_compute_values_failure(_: &PropertyValuePair) -> bool {
5931 fn create_context_for_animation<'a>(
5932 per_doc_data: &'a PerDocumentStyleDataImpl,
5933 style: &'a ComputedValues,
5934 parent_style: Option<&'a ComputedValues>,
5935 for_smil_animation: bool,
5936 rule_cache_conditions: &'a mut RuleCacheConditions,
5937 container_size_query: ContainerSizeQuery<'a>,
5939 Context::new_for_animation(
5940 StyleBuilder::for_animation(per_doc_data.stylist.device(), Some(&per_doc_data.stylist), style, parent_style),
5942 per_doc_data.stylist.quirks_mode(),
5943 rule_cache_conditions,
5944 container_size_query,
5948 struct PropertyAndIndex {
5949 property: PropertyId,
5953 struct PrioritizedPropertyIter<'a> {
5954 properties: &'a [PropertyValuePair],
5955 sorted_property_indices: Vec<PropertyAndIndex>,
5959 impl<'a> PrioritizedPropertyIter<'a> {
5960 fn new(properties: &'a [PropertyValuePair]) -> PrioritizedPropertyIter {
5961 use style::values::animated::compare_property_priority;
5963 // If we fail to convert a nsCSSPropertyID into a PropertyId we
5964 // shouldn't fail outright but instead by treating that property as the
5965 // 'all' property we make it sort last.
5966 let mut sorted_property_indices: Vec<PropertyAndIndex> = properties
5969 .map(|(index, pair)| {
5970 let property = PropertyId::from_nscsspropertyid(pair.mProperty)
5971 .unwrap_or(PropertyId::Shorthand(ShorthandId::All));
5973 PropertyAndIndex { property, index }
5976 sorted_property_indices.sort_by(|a, b| compare_property_priority(&a.property, &b.property));
5978 PrioritizedPropertyIter {
5980 sorted_property_indices,
5986 impl<'a> Iterator for PrioritizedPropertyIter<'a> {
5987 type Item = &'a PropertyValuePair;
5989 fn next(&mut self) -> Option<&'a PropertyValuePair> {
5990 if self.curr >= self.sorted_property_indices.len() {
5994 Some(&self.properties[self.sorted_property_indices[self.curr - 1].index])
5999 pub extern "C" fn Servo_GetComputedKeyframeValues(
6000 keyframes: &nsTArray<structs::Keyframe>,
6001 element: &RawGeckoElement,
6002 pseudo_type: PseudoStyleType,
6003 style: &ComputedValues,
6004 raw_data: &PerDocumentStyleData,
6005 computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>,
6007 let data = raw_data.borrow();
6008 let element = GeckoElement(element);
6009 let pseudo = PseudoElement::from_pseudo_type(pseudo_type, None);
6010 let parent_element = if pseudo.is_none() {
6011 element.inheritance_parent()
6015 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6016 let parent_style = parent_data
6018 .map(|d| d.styles.primary())
6021 let container_size_query =
6022 ContainerSizeQuery::for_element(element, pseudo.as_ref().and(parent_style));
6023 let mut conditions = Default::default();
6024 let mut context = create_context_for_animation(
6028 /* for_smil_animation = */ false,
6030 container_size_query,
6033 let restriction = pseudo.and_then(|p| p.property_restriction());
6035 let global_style_data = &*GLOBAL_STYLE_DATA;
6036 let guard = global_style_data.shared_lock.read();
6037 let default_values = data.default_computed_values();
6039 let mut raw_custom_properties_block; // To make the raw block alive in the scope.
6040 for (index, keyframe) in keyframes.iter().enumerate() {
6041 let mut custom_properties = None;
6042 for property in keyframe.mPropertyValues.iter() {
6043 // Find the block for custom properties first.
6044 if property.mProperty == nsCSSPropertyID::eCSSPropertyExtra_variable {
6045 raw_custom_properties_block = unsafe { &*property.mServoDeclarationBlock.mRawPtr };
6046 let guard = raw_custom_properties_block.read_with(&guard);
6047 custom_properties = guard.cascade_custom_properties_with_context(&context);
6048 // There should be one PropertyDeclarationBlock for custom properties.
6053 let ref mut animation_values = computed_keyframes[index];
6055 let mut seen = LonghandIdSet::new();
6057 let mut property_index = 0;
6058 for property in PrioritizedPropertyIter::new(&keyframe.mPropertyValues) {
6059 if simulate_compute_values_failure(property) {
6063 let mut maybe_append_animation_value =
6064 |property: LonghandId, value: Option<AnimationValue>| {
6065 debug_assert!(!property.is_logical());
6066 debug_assert!(property.is_animatable());
6068 // 'display' is only animatable from SMIL
6069 if property == LonghandId::Display {
6073 // Skip restricted properties
6074 if restriction.map_or(false, |r| !property.flags().contains(r)) {
6078 if seen.contains(property) {
6081 seen.insert(property);
6083 // This is safe since we immediately write to the uninitialized values.
6085 animation_values.set_len((property_index + 1) as u32);
6087 &mut animation_values[property_index],
6088 structs::PropertyStyleAnimationValuePair {
6089 mProperty: property.to_nscsspropertyid(),
6090 mValue: structs::AnimationValue {
6091 mServo: value.map_or(structs::RefPtr::null(), |v| {
6092 structs::RefPtr::from_arc(Arc::new(v))
6098 property_index += 1;
6101 if property.mServoDeclarationBlock.mRawPtr.is_null() {
6102 let property = LonghandId::from_nscsspropertyid(property.mProperty);
6103 if let Ok(prop) = property {
6104 maybe_append_animation_value(prop, None);
6109 let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr };
6110 let guard = declarations.read_with(&guard);
6111 let iter = guard.to_animation_value_iter(
6114 custom_properties.as_ref(),
6118 let id = value.id();
6119 maybe_append_animation_value(id, Some(value));
6126 pub extern "C" fn Servo_GetAnimationValues(
6127 declarations: &LockedDeclarationBlock,
6128 element: &RawGeckoElement,
6129 style: &ComputedValues,
6130 raw_data: &PerDocumentStyleData,
6131 animation_values: &mut ThinVec<structs::RefPtr<AnimationValue>>,
6133 let data = raw_data.borrow();
6134 let element = GeckoElement(element);
6135 let parent_element = element.inheritance_parent();
6136 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6137 let parent_style = parent_data
6139 .map(|d| d.styles.primary())
6142 let container_size_query = ContainerSizeQuery::for_element(element, None);
6143 let mut conditions = Default::default();
6144 let mut context = create_context_for_animation(
6148 /* for_smil_animation = */ true,
6150 container_size_query,
6153 let default_values = data.default_computed_values();
6154 let global_style_data = &*GLOBAL_STYLE_DATA;
6155 let guard = global_style_data.shared_lock.read();
6157 let guard = declarations.read_with(&guard);
6158 let iter = guard.to_animation_value_iter(
6161 None, // SMIL has no extra custom properties.
6163 animation_values.extend(iter.map(|v| structs::RefPtr::from_arc(Arc::new(v))));
6167 pub extern "C" fn Servo_AnimationValue_GetPropertyId(value: &AnimationValue) -> nsCSSPropertyID {
6168 value.id().to_nscsspropertyid()
6172 pub extern "C" fn Servo_AnimationValue_Compute(
6173 element: &RawGeckoElement,
6174 declarations: &LockedDeclarationBlock,
6175 style: &ComputedValues,
6176 raw_data: &PerDocumentStyleData,
6177 ) -> Strong<AnimationValue> {
6178 let data = raw_data.borrow();
6180 let element = GeckoElement(element);
6181 let parent_element = element.inheritance_parent();
6182 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
6183 let parent_style = parent_data
6185 .map(|d| d.styles.primary())
6188 let container_size_query = ContainerSizeQuery::for_element(element, None);
6189 let mut conditions = Default::default();
6190 let mut context = create_context_for_animation(
6194 /* for_smil_animation = */ false,
6196 container_size_query,
6199 let default_values = data.default_computed_values();
6200 let global_style_data = &*GLOBAL_STYLE_DATA;
6201 let guard = global_style_data.shared_lock.read();
6202 // We only compute the first element in declarations.
6205 .declaration_importance_iter()
6208 Some((decl, imp)) if imp == Importance::Normal => {
6209 let animation = AnimationValue::from_declaration(
6212 None, // No extra custom properties for devtools.
6215 animation.map_or(Strong::null(), |value| Arc::new(value).into())
6217 _ => Strong::null(),
6222 pub extern "C" fn Servo_AssertTreeIsClean(root: &RawGeckoElement) {
6223 if !cfg!(feature = "gecko_debug") {
6224 panic!("Calling Servo_AssertTreeIsClean in release build");
6227 let root = GeckoElement(root);
6228 debug!("Servo_AssertTreeIsClean: ");
6229 debug!("{:?}", ShowSubtreeData(root.as_node()));
6231 fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) {
6233 !el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants(),
6234 "{:?} has still dirty bit {:?} or animation-only dirty bit {:?}",
6236 el.has_dirty_descendants(),
6237 el.has_animation_only_dirty_descendants()
6239 for child in el.traversal_children() {
6240 if let Some(child) = child.as_element() {
6241 assert_subtree_is_clean(child);
6246 assert_subtree_is_clean(root);
6250 pub extern "C" fn Servo_IsWorkerThread() -> bool {
6251 thread_state::get().is_worker()
6259 fn fill_in_missing_keyframe_values(
6260 all_properties: &LonghandIdSet,
6261 timing_function: &ComputedTimingFunction,
6262 longhands_at_offset: &LonghandIdSet,
6264 keyframes: &mut nsTArray<structs::Keyframe>,
6266 // Return early if all animated properties are already set.
6267 if longhands_at_offset.contains_all(all_properties) {
6271 // Use auto for missing keyframes.
6272 // FIXME: This may be a spec issue in css-animations-2 because the spec says the default
6273 // keyframe-specific composite is replace, but web-animations-1 uses auto. Use auto now so we
6274 // use the value of animation-composition of the element, for missing keyframes.
6275 // https://github.com/w3c/csswg-drafts/issues/7476
6276 let composition = structs::CompositeOperationOrAuto::Auto;
6277 let keyframe = match offset {
6278 Offset::Zero => unsafe {
6279 Gecko_GetOrCreateInitialKeyframe(keyframes, timing_function, composition)
6281 Offset::One => unsafe {
6282 Gecko_GetOrCreateFinalKeyframe(keyframes, timing_function, composition)
6286 // Append properties that have not been set at this offset.
6287 for property in all_properties.iter() {
6288 if !longhands_at_offset.contains(property) {
6290 Gecko_AppendPropertyValuePair(
6291 &mut *(*keyframe).mPropertyValues,
6292 property.to_nscsspropertyid(),
6300 pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
6301 raw_data: &PerDocumentStyleData,
6302 element: &RawGeckoElement,
6303 style: &ComputedValues,
6305 inherited_timing_function: &ComputedTimingFunction,
6306 keyframes: &mut nsTArray<structs::Keyframe>,
6308 use style::gecko_bindings::structs::CompositeOperationOrAuto;
6309 use style::properties::longhands::animation_composition::single_value::computed_value::T as Composition;
6311 debug_assert!(keyframes.len() == 0, "keyframes should be initially empty");
6313 let element = GeckoElement(element);
6314 let data = raw_data.borrow();
6315 let name = Atom::from_raw(name);
6317 let animation = match data.stylist.get_animation(&name, element) {
6318 Some(animation) => animation,
6319 None => return false,
6322 let global_style_data = &*GLOBAL_STYLE_DATA;
6323 let guard = global_style_data.shared_lock.read();
6325 let mut properties_set_at_current_offset = LonghandIdSet::new();
6326 let mut properties_set_at_start = LonghandIdSet::new();
6327 let mut properties_set_at_end = LonghandIdSet::new();
6328 let mut has_complete_initial_keyframe = false;
6329 let mut has_complete_final_keyframe = false;
6330 let mut current_offset = -1.;
6332 let writing_mode = style.writing_mode;
6334 // Iterate over the keyframe rules backwards so we can drop overridden
6335 // properties (since declarations in later rules override those in earlier
6337 for step in animation.steps.iter().rev() {
6338 if step.start_percentage.0 != current_offset {
6339 properties_set_at_current_offset.clear();
6340 current_offset = step.start_percentage.0;
6343 // Override timing_function if the keyframe has an animation-timing-function.
6344 let timing_function = match step.get_animation_timing_function(&guard) {
6345 Some(val) => val.to_computed_value_without_context(),
6346 None => (*inherited_timing_function).clone(),
6349 // Override composite operation if the keyframe has an animation-composition.
6351 step.get_animation_composition(&guard)
6352 .map_or(CompositeOperationOrAuto::Auto, |val| match val {
6353 Composition::Replace => CompositeOperationOrAuto::Replace,
6354 Composition::Add => CompositeOperationOrAuto::Add,
6355 Composition::Accumulate => CompositeOperationOrAuto::Accumulate,
6358 // Look for an existing keyframe with the same offset, timing function, and compsition, or
6359 // else add a new keyframe at the beginning of the keyframe array.
6360 let keyframe = Gecko_GetOrCreateKeyframeAtStart(
6362 step.start_percentage.0 as f32,
6368 KeyframesStepValue::ComputedValues => {
6369 // In KeyframesAnimation::from_keyframes if there is no 0% or
6370 // 100% keyframe at all, we will create a 'ComputedValues' step
6371 // to represent that all properties animated by the keyframes
6372 // animation should be set to the underlying computed value for
6374 let mut seen = LonghandIdSet::new();
6375 for property in animation.properties_changed.iter() {
6376 let property = property.to_physical(writing_mode);
6377 if seen.contains(property) {
6380 seen.insert(property);
6382 Gecko_AppendPropertyValuePair(
6383 &mut *(*keyframe).mPropertyValues,
6384 property.to_nscsspropertyid(),
6387 if current_offset == 0.0 {
6388 has_complete_initial_keyframe = true;
6389 } else if current_offset == 1.0 {
6390 has_complete_final_keyframe = true;
6393 KeyframesStepValue::Declarations { ref block } => {
6394 let guard = block.read_with(&guard);
6396 let mut custom_properties = PropertyDeclarationBlock::new();
6398 // Filter out non-animatable properties and properties with
6401 // Also, iterate in reverse to respect the source order in case
6402 // there are logical and physical longhands in the same block.
6403 for declaration in guard.normal_declaration_iter().rev() {
6404 let id = declaration.id();
6407 PropertyDeclarationId::Longhand(id) => {
6408 // Skip the 'display' property because although it
6409 // is animatable from SMIL, it should not be
6410 // animatable from CSS Animations.
6411 if id == LonghandId::Display {
6415 if !id.is_animatable() {
6419 id.to_physical(writing_mode)
6421 PropertyDeclarationId::Custom(..) => {
6422 custom_properties.push(declaration.clone(), Importance::Normal);
6427 if properties_set_at_current_offset.contains(id) {
6431 let pair = Gecko_AppendPropertyValuePair(
6432 &mut *(*keyframe).mPropertyValues,
6433 id.to_nscsspropertyid(),
6436 (*pair).mServoDeclarationBlock.set_arc(Arc::new(
6439 .wrap(PropertyDeclarationBlock::with_one(
6440 declaration.to_physical(writing_mode),
6445 if current_offset == 0.0 {
6446 properties_set_at_start.insert(id);
6447 } else if current_offset == 1.0 {
6448 properties_set_at_end.insert(id);
6450 properties_set_at_current_offset.insert(id);
6453 if custom_properties.any_normal() {
6454 let pair = Gecko_AppendPropertyValuePair(
6455 &mut *(*keyframe).mPropertyValues,
6456 nsCSSPropertyID::eCSSPropertyExtra_variable,
6459 (*pair).mServoDeclarationBlock.set_arc(Arc::new(
6460 global_style_data.shared_lock.wrap(custom_properties),
6467 let mut properties_changed = LonghandIdSet::new();
6468 for property in animation.properties_changed.iter() {
6469 properties_changed.insert(property.to_physical(writing_mode));
6472 // Append property values that are missing in the initial or the final keyframes.
6473 if !has_complete_initial_keyframe {
6474 fill_in_missing_keyframe_values(
6475 &properties_changed,
6476 inherited_timing_function,
6477 &properties_set_at_start,
6482 if !has_complete_final_keyframe {
6483 fill_in_missing_keyframe_values(
6484 &properties_changed,
6485 inherited_timing_function,
6486 &properties_set_at_end,
6495 pub extern "C" fn Servo_StyleSet_GetFontFaceRules(
6496 raw_data: &PerDocumentStyleData,
6497 rules: &mut ThinVec<structs::nsFontFaceRuleContainer>,
6499 let data = raw_data.borrow();
6500 debug_assert_eq!(rules.len(), 0);
6502 // Reversed iterator because Gecko expects rules to appear sorted
6503 // UserAgent first, Author last.
6504 let font_face_iter = data
6506 .iter_extra_data_origins_rev()
6507 .flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o)));
6509 rules.extend(font_face_iter.map(|(&(ref rule, _layer_id), origin)| {
6510 structs::nsFontFaceRuleContainer {
6511 mRule: structs::RefPtr::from_arc(rule.clone()),
6517 // XXX Ideally this should return a Option<&LockedCounterStyleRule>,
6518 // but we cannot, because the value from AtomicRefCell::borrow() can only
6519 // live in this function, and thus anything derived from it cannot get the
6520 // same lifetime as raw_data in parameter. See bug 1451543.
6522 pub unsafe extern "C" fn Servo_StyleSet_GetCounterStyleRule(
6523 raw_data: &PerDocumentStyleData,
6525 ) -> *const LockedCounterStyleRule {
6526 let data = raw_data.borrow();
6527 Atom::with(name, |name| {
6529 .iter_extra_data_origins()
6530 .find_map(|(d, _)| d.counter_styles.get(name))
6531 .map_or(ptr::null(), |rule| &**rule as *const _)
6536 pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet(
6537 raw_data: &PerDocumentStyleData,
6538 ) -> *mut gfxFontFeatureValueSet {
6539 let data = raw_data.borrow();
6543 .iter_extra_data_origins()
6544 .any(|(d, _)| !d.font_feature_values.is_empty());
6547 return ptr::null_mut();
6550 let font_feature_values_iter = data
6552 .iter_extra_data_origins_rev()
6553 .flat_map(|(d, _)| d.font_feature_values.iter());
6555 let set = unsafe { Gecko_ConstructFontFeatureValueSet() };
6556 for &(ref rule, _) in font_feature_values_iter {
6557 rule.set_at_rules(set);
6563 pub extern "C" fn Servo_StyleSet_BuildFontPaletteValueSet(
6564 raw_data: &PerDocumentStyleData,
6565 ) -> *mut FontPaletteValueSet {
6566 let data = raw_data.borrow();
6570 .iter_extra_data_origins()
6571 .any(|(d, _)| !d.font_palette_values.is_empty());
6574 return ptr::null_mut();
6577 let font_palette_values_iter = data
6579 .iter_extra_data_origins_rev()
6580 .flat_map(|(d, _)| d.font_palette_values.iter());
6582 let set = unsafe { Gecko_ConstructFontPaletteValueSet() };
6583 for &(ref rule, _) in font_palette_values_iter {
6584 rule.to_gecko_palette_value_set(set);
6590 pub extern "C" fn Servo_StyleSet_ResolveForDeclarations(
6591 raw_data: &PerDocumentStyleData,
6592 parent_style_context: Option<&ComputedValues>,
6593 declarations: &LockedDeclarationBlock,
6594 ) -> Strong<ComputedValues> {
6595 let doc_data = raw_data.borrow();
6596 let global_style_data = &*GLOBAL_STYLE_DATA;
6597 let guard = global_style_data.shared_lock.read();
6598 let guards = StylesheetGuards::same(&guard);
6600 let parent_style = match parent_style_context {
6601 Some(parent) => &*parent,
6602 None => doc_data.default_computed_values(),
6607 .compute_for_declarations::<GeckoElement>(&guards, parent_style, unsafe {
6608 Arc::from_raw_addrefed(declarations)
6614 pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis(
6615 malloc_size_of: GeckoMallocSizeOf,
6616 malloc_enclosing_size_of: GeckoMallocSizeOf,
6617 sizes: *mut ServoStyleSetSizes,
6618 raw_data: &PerDocumentStyleData,
6620 let data = raw_data.borrow_mut();
6621 let mut ops = MallocSizeOfOps::new(
6622 malloc_size_of.unwrap(),
6623 Some(malloc_enclosing_size_of.unwrap()),
6626 let sizes = unsafe { sizes.as_mut() }.unwrap();
6627 data.add_size_of(&mut ops, sizes);
6631 pub extern "C" fn Servo_UACache_AddSizeOf(
6632 malloc_size_of: GeckoMallocSizeOf,
6633 malloc_enclosing_size_of: GeckoMallocSizeOf,
6634 sizes: *mut ServoStyleSetSizes,
6636 let mut ops = MallocSizeOfOps::new(
6637 malloc_size_of.unwrap(),
6638 Some(malloc_enclosing_size_of.unwrap()),
6641 let sizes = unsafe { sizes.as_mut() }.unwrap();
6642 add_size_of_ua_cache(&mut ops, sizes);
6646 pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
6647 raw_data: &PerDocumentStyleData,
6648 element: &RawGeckoElement,
6649 local_name: *mut nsAtom,
6651 let data = raw_data.borrow();
6652 let element = GeckoElement(element);
6655 AtomIdent::with(local_name, |atom| {
6656 data.stylist.any_applicable_rule_data(element, |data| {
6657 data.might_have_attribute_dependency(atom)
6664 pub extern "C" fn Servo_StyleSet_MightHaveNthOfIDDependency(
6665 raw_data: &PerDocumentStyleData,
6666 element: &RawGeckoElement,
6667 old_id: *mut nsAtom,
6668 new_id: *mut nsAtom,
6670 let data = raw_data.borrow();
6671 let element = GeckoElement(element);
6673 data.stylist.any_applicable_rule_data(element, |data| {
6676 .filter(|id| !id.is_null())
6678 AtomIdent::with(*id, |atom| data.might_have_nth_of_id_dependency(atom))
6680 data.might_have_nth_of_attribute_dependency(&AtomIdent(atom!("id")))
6685 pub extern "C" fn Servo_StyleSet_MightHaveNthOfClassDependency(
6686 raw_data: &PerDocumentStyleData,
6687 element: &RawGeckoElement,
6688 snapshots: &ServoElementSnapshotTable,
6690 let data = raw_data.borrow();
6691 let element = GeckoElement(element);
6693 data.stylist.any_applicable_rule_data(element, |data| {
6694 classes_changed(&element, snapshots)
6696 .any(|atom| data.might_have_nth_of_class_dependency(atom)) ||
6697 data.might_have_nth_of_attribute_dependency(&AtomIdent(atom!("class")))
6702 pub extern "C" fn Servo_StyleSet_MightHaveNthOfAttributeDependency(
6703 raw_data: &PerDocumentStyleData,
6704 element: &RawGeckoElement,
6705 local_name: *mut nsAtom,
6707 let data = raw_data.borrow();
6708 let element = GeckoElement(element);
6711 AtomIdent::with(local_name, |atom| {
6712 data.stylist.any_applicable_rule_data(element, |data| {
6713 data.might_have_nth_of_attribute_dependency(atom)
6720 pub extern "C" fn Servo_StyleSet_HasStateDependency(
6721 raw_data: &PerDocumentStyleData,
6722 element: &RawGeckoElement,
6725 let element = GeckoElement(element);
6727 let state = ElementState::from_bits_truncate(state);
6728 let data = raw_data.borrow();
6731 .any_applicable_rule_data(element, |data| data.has_state_dependency(state))
6735 pub extern "C" fn Servo_StyleSet_HasNthOfStateDependency(
6736 raw_data: &PerDocumentStyleData,
6737 element: &RawGeckoElement,
6740 let element = GeckoElement(element);
6742 let state = ElementState::from_bits_truncate(state);
6743 let data = raw_data.borrow();
6746 .any_applicable_rule_data(element, |data| data.has_nth_of_state_dependency(state))
6750 pub extern "C" fn Servo_StyleSet_HasDocumentStateDependency(
6751 raw_data: &PerDocumentStyleData,
6754 let state = DocumentState::from_bits_truncate(state);
6755 let data = raw_data.borrow();
6757 data.stylist.has_document_state_dependency(state)
6760 fn computed_or_resolved_value(
6761 style: &ComputedValues,
6762 prop: nsCSSPropertyID,
6763 context: Option<&style::values::resolved::Context>,
6764 value: &mut nsACString,
6766 if let Ok(longhand) = LonghandId::from_nscsspropertyid(prop) {
6768 .computed_or_resolved_value(longhand, context, value)
6773 ShorthandId::from_nscsspropertyid(prop).expect("Not a shorthand nor a longhand?");
6774 let mut block = PropertyDeclarationBlock::new();
6775 for longhand in shorthand.longhands() {
6777 style.computed_or_resolved_declaration(longhand, context),
6781 block.shorthand_to_css(shorthand, value).unwrap();
6785 pub unsafe extern "C" fn Servo_GetComputedValue(
6786 style: &ComputedValues,
6787 prop: nsCSSPropertyID,
6788 value: &mut nsACString,
6790 computed_or_resolved_value(style, prop, None, value)
6794 pub unsafe extern "C" fn Servo_GetResolvedValue(
6795 style: &ComputedValues,
6796 prop: nsCSSPropertyID,
6797 raw_data: &PerDocumentStyleData,
6798 element: &RawGeckoElement,
6799 value: &mut nsACString,
6801 use style::values::resolved;
6803 let data = raw_data.borrow();
6804 let device = data.stylist.device();
6805 let context = resolved::Context {
6808 element_info: resolved::ResolvedElementInfo {
6809 element: GeckoElement(element),
6813 computed_or_resolved_value(style, prop, Some(&context), value)
6817 pub unsafe extern "C" fn Servo_GetCustomPropertyValue(
6818 computed_values: &ComputedValues,
6820 value: &mut nsACString,
6822 let custom_properties = match computed_values.custom_properties() {
6824 None => return false,
6827 let name = Atom::from(name.as_str_unchecked());
6828 let computed_value = match custom_properties.get(&name) {
6830 None => return false,
6833 computed_value.to_css(&mut CssWriter::new(value)).unwrap();
6838 pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u32 {
6839 match computed_values.custom_properties() {
6840 Some(p) => p.len() as u32,
6846 pub extern "C" fn Servo_GetCustomPropertyNameAt(
6847 computed_values: &ComputedValues,
6850 let custom_properties = match computed_values.custom_properties() {
6852 None => return ptr::null_mut(),
6855 let property_name = match custom_properties.get_index(index as usize) {
6856 Some((key, _value)) => key,
6857 None => return ptr::null_mut(),
6860 property_name.as_ptr()
6864 pub extern "C" fn Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool {
6869 pub extern "C" fn Servo_ProcessInvalidations(
6870 set: &PerDocumentStyleData,
6871 element: &RawGeckoElement,
6872 snapshots: *const ServoElementSnapshotTable,
6874 debug_assert!(!snapshots.is_null());
6876 let element = GeckoElement(element);
6877 debug_assert!(element.has_snapshot());
6878 debug_assert!(!element.handled_snapshot());
6880 let mut data = element.mutate_data();
6881 debug_assert!(data.is_some());
6883 let global_style_data = &*GLOBAL_STYLE_DATA;
6884 let guard = global_style_data.shared_lock.read();
6885 let per_doc_data = set.borrow();
6886 let shared_style_context = create_shared_context(
6889 &per_doc_data.stylist,
6890 TraversalFlags::empty(),
6891 unsafe { &*snapshots },
6893 let mut data = data.as_mut().map(|d| &mut **d);
6895 let mut selector_caches = SelectorCaches::default();
6896 if let Some(ref mut data) = data {
6897 // FIXME(emilio): Ideally we could share the nth-index-cache across all
6899 let result = data.invalidate_style_if_needed(
6901 &shared_style_context,
6903 &mut selector_caches,
6906 if result.has_invalidated_siblings() {
6907 let parent = element
6909 .expect("How could we invalidate siblings without a common parent?");
6911 parent.set_dirty_descendants();
6912 bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0);
6914 } else if result.has_invalidated_descendants() {
6915 unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) };
6916 } else if result.has_invalidated_self() {
6917 unsafe { bindings::Gecko_NoteDirtyElement(element.0) };
6923 pub extern "C" fn Servo_HasPendingRestyleAncestor(
6924 element: &RawGeckoElement,
6925 may_need_to_flush_layout: bool,
6927 let mut has_yet_to_be_styled = false;
6928 let mut element = Some(GeckoElement(element));
6929 while let Some(e) = element {
6930 if e.has_any_animation() {
6934 // If the element needs a frame, it means that we haven't styled it yet
6935 // after it got inserted in the document, and thus we may need to do
6936 // that for transitions and animations to trigger.
6938 // This is a fast path in the common case, but `has_yet_to_be_styled` is
6939 // the real check for this.
6940 if e.needs_frame() {
6944 let data = e.borrow_data();
6945 if let Some(ref data) = data {
6946 if !data.hint.is_empty() {
6949 if has_yet_to_be_styled && !data.styles.is_display_none() {
6952 // Ideally, DOM mutations wouldn't affect layout trees of siblings.
6954 // In practice, this can happen because Gecko deals pretty badly
6955 // with some kinds of content insertion and removals.
6957 // If we may need to flush layout, we need frames to accurately
6958 // determine whether we'll actually flush, so if we have to
6959 // reconstruct we need to flush style, which is what will take care
6960 // of ensuring that frames are constructed, even if the style itself
6962 if may_need_to_flush_layout && data.damage.contains(GeckoRestyleDamage::reconstruct()) {
6966 has_yet_to_be_styled = data.is_none();
6968 element = e.traversal_parent();
6974 pub unsafe extern "C" fn Servo_SelectorList_Parse(
6975 selector_list: &nsACString,
6977 ) -> *mut SelectorList {
6978 use style::selector_parser::SelectorParser;
6980 let url_data = UrlExtraData::from_ptr_ref(if is_chrome {
6981 &DUMMY_CHROME_URL_DATA
6986 let input = selector_list.as_str_unchecked();
6987 let selector_list = match SelectorParser::parse_author_origin_no_namespace(&input, url_data) {
6988 Ok(selector_list) => selector_list,
6989 Err(..) => return ptr::null_mut(),
6992 Box::into_raw(Box::new(selector_list))
6996 pub unsafe extern "C" fn Servo_SelectorList_Drop(list: *mut SelectorList) {
6997 let _ = Box::from_raw(list);
7001 pub unsafe extern "C" fn Servo_IsValidCSSColor(value: &nsACString) -> bool {
7002 let mut input = ParserInput::new(value.as_str_unchecked());
7003 let mut input = Parser::new(&mut input);
7004 let context = ParserContext::new(
7007 Some(CssRuleType::Style),
7008 ParsingMode::DEFAULT,
7009 QuirksMode::NoQuirks,
7010 /* namespaces = */ Default::default(),
7014 specified::Color::is_valid(&context, &mut input)
7018 pub unsafe extern "C" fn Servo_ComputeColor(
7019 raw_data: Option<&PerDocumentStyleData>,
7020 current_color: structs::nscolor,
7022 result_color: &mut structs::nscolor,
7023 was_current_color: *mut bool,
7024 loader: *mut Loader,
7026 let mut input = ParserInput::new(value.as_str_unchecked());
7027 let mut input = Parser::new(&mut input);
7028 let reporter = loader.as_mut().and_then(|loader| {
7029 // Make an ErrorReporter that will report errors as being "from DOM".
7030 ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut())
7033 let context = ParserContext::new(
7036 Some(CssRuleType::Style),
7037 ParsingMode::DEFAULT,
7038 QuirksMode::NoQuirks,
7039 /* namespaces = */ Default::default(),
7040 reporter.as_ref().map(|e| e as &dyn ParseErrorReporter),
7045 let device = match raw_data {
7048 Some(data.stylist.device())
7053 let computed = match specified::Color::parse_and_compute(&context, &mut input, device) {
7055 None => return false,
7058 let current_color = style::gecko::values::convert_nscolor_to_absolute_color(current_color);
7059 if !was_current_color.is_null() {
7060 *was_current_color = computed.is_currentcolor();
7063 let rgba = computed.resolve_to_absolute(¤t_color);
7064 *result_color = style::gecko::values::convert_absolute_color_to_nscolor(&rgba);
7069 pub extern "C" fn Servo_ResolveColor(
7070 color: &computed::Color,
7071 foreground: &style::color::AbsoluteColor,
7072 ) -> style::color::AbsoluteColor {
7073 color.resolve_to_absolute(foreground)
7077 pub extern "C" fn Servo_ResolveCalcLengthPercentage(
7078 calc: &computed::length_percentage::CalcLengthPercentage,
7081 calc.resolve(computed::Length::new(basis)).px()
7085 pub extern "C" fn Servo_ConvertColorSpace(
7086 color: &AbsoluteColor,
7087 color_space: ColorSpace,
7088 ) -> AbsoluteColor {
7089 color.to_color_space(color_space)
7093 pub unsafe extern "C" fn Servo_IntersectionObserverRootMargin_Parse(
7095 result: *mut IntersectionObserverRootMargin,
7097 let value = value.as_str_unchecked();
7098 let result = result.as_mut().unwrap();
7100 let mut input = ParserInput::new(&value);
7101 let mut parser = Parser::new(&mut input);
7103 let url_data = dummy_url_data();
7104 let context = ParserContext::new(
7107 Some(CssRuleType::Style),
7108 ParsingMode::DEFAULT,
7109 QuirksMode::NoQuirks,
7110 /* namespaces = */ Default::default(),
7115 let margin = parser.parse_entirely(|p| IntersectionObserverRootMargin::parse(&context, p));
7126 pub extern "C" fn Servo_IntersectionObserverRootMargin_ToString(
7127 root_margin: &IntersectionObserverRootMargin,
7128 result: &mut nsACString,
7130 let mut writer = CssWriter::new(result);
7131 root_margin.to_css(&mut writer).unwrap();
7135 pub extern "C" fn Servo_ParseTransformIntoMatrix(
7137 contain_3d: &mut bool,
7138 result: &mut structs::Matrix4x4Components,
7140 use style::properties::longhands::transform;
7142 let string = unsafe { value.as_str_unchecked() };
7143 let mut input = ParserInput::new(&string);
7144 let mut parser = Parser::new(&mut input);
7145 let context = ParserContext::new(
7147 unsafe { dummy_url_data() },
7148 Some(CssRuleType::Style),
7149 ParsingMode::DEFAULT,
7150 QuirksMode::NoQuirks,
7151 /* namespaces = */ Default::default(),
7156 let transform = match parser.parse_entirely(|t| transform::parse(&context, t)) {
7158 Err(..) => return false,
7161 let (m, is_3d) = match transform.to_transform_3d_matrix(None) {
7162 Ok(result) => result,
7163 Err(..) => return false,
7166 *result = m.to_array();
7167 *contain_3d = is_3d;
7172 pub extern "C" fn Servo_ParseFilters(
7175 data: *mut URLExtraData,
7176 out: &mut style::OwnedSlice<Filter>,
7178 use style::values::specified::effects::SpecifiedFilter;
7180 let string = unsafe { value.as_str_unchecked() };
7181 let mut input = ParserInput::new(&string);
7182 let mut parser = Parser::new(&mut input);
7183 let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
7184 let context = ParserContext::new(
7188 ParsingMode::DEFAULT,
7189 QuirksMode::NoQuirks,
7190 /* namespaces = */ Default::default(),
7195 let mut filters = vec![];
7197 if parser.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
7198 return parser.expect_exhausted().is_ok();
7201 if parser.is_exhausted() {
7205 while !parser.is_exhausted() {
7206 let specified_filter = match SpecifiedFilter::parse(&context, &mut parser) {
7208 Err(..) => return false,
7211 let filter = match specified_filter.to_computed_value_without_context() {
7213 Err(..) => return false,
7216 if ignore_urls && matches!(filter, Filter::Url(_)) {
7220 filters.push(filter);
7223 *out = style::OwnedSlice::from(filters);
7228 pub unsafe extern "C" fn Servo_ParseFontShorthandForMatching(
7230 data: *mut URLExtraData,
7231 family: &mut FontFamilyList,
7232 style: &mut FontStyle,
7233 stretch: &mut FontStretch,
7234 weight: &mut FontWeight,
7235 size: Option<&mut f32>,
7236 small_caps: Option<&mut bool>,
7238 use style::properties::shorthands::font;
7239 use style::values::generics::font::FontStyle as GenericFontStyle;
7240 use style::values::specified::font as specified;
7242 let string = value.as_str_unchecked();
7243 let mut input = ParserInput::new(&string);
7244 let mut parser = Parser::new(&mut input);
7245 let url_data = UrlExtraData::from_ptr_ref(&data);
7246 let context = ParserContext::new(
7249 Some(CssRuleType::FontFace),
7250 ParsingMode::DEFAULT,
7251 QuirksMode::NoQuirks,
7252 /* namespaces = */ Default::default(),
7257 let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) {
7259 Err(..) => return false,
7262 // The system font is not acceptable, so we return false.
7263 match font.font_family {
7264 specified::FontFamily::Values(list) => *family = list,
7265 specified::FontFamily::System(_) => return false,
7268 let specified_font_style = match font.font_style {
7269 specified::FontStyle::Specified(ref s) => s,
7270 specified::FontStyle::System(_) => return false,
7273 *style = match *specified_font_style {
7274 GenericFontStyle::Normal => FontStyle::NORMAL,
7275 GenericFontStyle::Italic => FontStyle::ITALIC,
7276 GenericFontStyle::Oblique(ref angle) => FontStyle::oblique(angle.degrees()),
7279 *stretch = match font.font_stretch {
7280 specified::FontStretch::Keyword(ref k) => k.compute(),
7281 specified::FontStretch::Stretch(ref p) => FontStretch::from_percentage(p.0.get()),
7282 specified::FontStretch::System(_) => return false,
7285 *weight = match font.font_weight {
7286 specified::FontWeight::Absolute(w) => w.compute(),
7287 // Resolve relative font weights against the initial of font-weight
7288 // (normal, which is equivalent to 400).
7289 specified::FontWeight::Bolder => FontWeight::normal().bolder(),
7290 specified::FontWeight::Lighter => FontWeight::normal().lighter(),
7291 specified::FontWeight::System(_) => return false,
7294 // XXX This is unfinished; see values::specified::FontSize::ToComputedValue
7295 // for a more complete implementation (but we can't use it as-is).
7296 if let Some(size) = size {
7297 *size = match font.font_size {
7298 specified::FontSize::Length(lp) => {
7299 use style::values::generics::transform::ToAbsoluteLength;
7300 match lp.to_pixel_length(None) {
7302 Err(..) => return false,
7305 specified::FontSize::Keyword(info) => {
7306 let keyword = if info.kw != specified::FontSizeKeyword::Math {
7309 specified::FontSizeKeyword::Medium
7311 // Map absolute-size keywords to sizes.
7312 // TODO: Maybe get a meaningful quirks / base size from the caller?
7313 let quirks_mode = QuirksMode::NoQuirks;
7315 .to_length_without_context(
7317 computed::Length::new(specified::FONT_MEDIUM_PX),
7322 // smaller, larger not currently supported
7323 specified::FontSize::Smaller |
7324 specified::FontSize::Larger |
7325 specified::FontSize::System(_) => {
7331 if let Some(small_caps) = small_caps {
7332 use style::computed_values::font_variant_caps::T::SmallCaps;
7333 *small_caps = font.font_variant_caps == SmallCaps;
7340 pub unsafe extern "C" fn Servo_SourceSizeList_Parse(value: &nsACString) -> *mut SourceSizeList {
7341 let value = value.as_str_unchecked();
7342 let mut input = ParserInput::new(value);
7343 let mut parser = Parser::new(&mut input);
7345 let context = ParserContext::new(
7348 Some(CssRuleType::Style),
7349 ParsingMode::DEFAULT,
7350 QuirksMode::NoQuirks,
7351 /* namespaces = */ Default::default(),
7356 // NB: Intentionally not calling parse_entirely.
7357 let list = SourceSizeList::parse(&context, &mut parser);
7358 Box::into_raw(Box::new(list))
7362 pub unsafe extern "C" fn Servo_SourceSizeList_Evaluate(
7363 raw_data: &PerDocumentStyleData,
7364 list: Option<&SourceSizeList>,
7366 let doc_data = raw_data.borrow();
7367 let device = doc_data.stylist.device();
7368 let quirks_mode = doc_data.stylist.quirks_mode();
7370 let result = match list {
7371 Some(list) => list.evaluate(device, quirks_mode),
7372 None => SourceSizeList::empty().evaluate(device, quirks_mode),
7379 pub unsafe extern "C" fn Servo_SourceSizeList_Drop(list: *mut SourceSizeList) {
7380 let _ = Box::from_raw(list);
7384 pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges(
7385 root: &RawGeckoElement,
7386 document_style: &PerDocumentStyleData,
7387 non_document_styles: &nsTArray<&AuthorStyles>,
7388 states_changed: u64,
7390 use style::invalidation::element::document_state::DocumentStateInvalidationProcessor;
7391 use style::invalidation::element::invalidator::TreeStyleInvalidator;
7393 let document_data = document_style.borrow();
7395 let iter = document_data
7398 .map(|(data, _origin)| data)
7402 .map(|author_styles| &*author_styles.data),
7405 let mut selector_caches = SelectorCaches::default();
7406 let root = GeckoElement(root);
7407 let mut processor = DocumentStateInvalidationProcessor::new(
7409 DocumentState::from_bits_truncate(states_changed),
7410 &mut selector_caches,
7411 root.as_node().owner_doc().quirks_mode(),
7415 TreeStyleInvalidator::new(root, /* stack_limit_checker = */ None, &mut processor)
7418 debug_assert!(!result.has_invalidated_siblings(), "How in the world?");
7419 if result.has_invalidated_descendants() {
7420 bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0);
7421 } else if result.has_invalidated_self() {
7422 bindings::Gecko_NoteDirtyElement(root.0);
7427 pub unsafe extern "C" fn Servo_PseudoClass_GetStates(name: &nsACString) -> u64 {
7428 let name = name.as_str_unchecked();
7429 match NonTSPseudoClass::parse_non_functional(name) {
7431 // Ignore :any-link since it contains both visited and unvisited state.
7432 Some(NonTSPseudoClass::AnyLink) => 0,
7433 Some(pseudo_class) => pseudo_class.state_flag().bits(),
7438 pub unsafe extern "C" fn Servo_UseCounters_Create() -> *mut UseCounters {
7439 Box::into_raw(Box::<UseCounters>::default())
7443 pub unsafe extern "C" fn Servo_UseCounters_Drop(c: *mut UseCounters) {
7444 let _ = Box::from_raw(c);
7448 pub unsafe extern "C" fn Servo_UseCounters_Merge(
7449 doc_counters: &UseCounters,
7450 sheet_counters: &UseCounters,
7452 doc_counters.merge(sheet_counters)
7456 pub unsafe extern "C" fn Servo_IsPropertyIdRecordedInUseCounter(
7457 use_counters: &UseCounters,
7458 id: nsCSSPropertyID,
7460 let id = NonCustomPropertyId::from_nscsspropertyid(id).unwrap();
7461 use_counters.non_custom_properties.recorded(id)
7465 pub unsafe extern "C" fn Servo_IsUnknownPropertyRecordedInUseCounter(
7466 use_counters: &UseCounters,
7467 p: CountedUnknownProperty,
7469 use_counters.counted_unknown_properties.recorded(p)
7473 pub unsafe extern "C" fn Servo_IsCssPropertyRecordedInUseCounter(
7474 use_counters: &UseCounters,
7475 property: &nsACString,
7476 known_prop: *mut bool,
7478 *known_prop = false;
7480 let prop_name = property.as_str_unchecked();
7481 if let Ok(p) = PropertyId::parse_unchecked_for_testing(prop_name) {
7482 if let Some(id) = p.non_custom_id() {
7484 return use_counters.non_custom_properties.recorded(id);
7488 if let Some(p) = CountedUnknownProperty::parse_for_testing(prop_name) {
7490 return use_counters.counted_unknown_properties.recorded(p);
7497 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Create(
7500 ) -> *mut SharedMemoryBuilder {
7501 Box::into_raw(Box::new(SharedMemoryBuilder::new(buffer, len)))
7505 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_AddStylesheet(
7506 builder: &mut SharedMemoryBuilder,
7507 contents: &StylesheetContents,
7508 error_message: &mut nsACString,
7509 ) -> *const LockedCssRules {
7510 // Assert some things we assume when we create a style sheet from shared
7512 debug_assert_eq!(contents.origin, Origin::UserAgent);
7513 debug_assert_eq!(contents.quirks_mode, QuirksMode::NoQuirks);
7514 debug_assert!(contents.source_map_url.read().is_none());
7515 debug_assert!(contents.source_url.read().is_none());
7517 match builder.write(&contents.rules) {
7518 Ok(rules_ptr) => &**rules_ptr,
7520 error_message.assign(&message);
7527 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_GetLength(
7528 builder: &SharedMemoryBuilder,
7534 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Drop(builder: *mut SharedMemoryBuilder) {
7535 let _ = Box::from_raw(builder);
7539 pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void {
7540 style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr()
7544 pub unsafe extern "C" fn Servo_LoadData_GetLazy(
7545 source: &url::LoadDataSource,
7546 ) -> *const url::LoadData {
7551 pub extern "C" fn Servo_LengthPercentage_ToCss(
7552 lp: &computed::LengthPercentage,
7553 result: &mut nsACString,
7555 lp.to_css(&mut CssWriter::new(result)).unwrap();
7559 pub extern "C" fn Servo_FontStyle_ToCss(s: &FontStyle, result: &mut nsACString) {
7560 s.to_css(&mut CssWriter::new(result)).unwrap()
7564 pub extern "C" fn Servo_FontWeight_ToCss(w: &FontWeight, result: &mut nsACString) {
7565 w.to_css(&mut CssWriter::new(result)).unwrap()
7569 pub extern "C" fn Servo_FontStretch_ToCss(s: &FontStretch, result: &mut nsACString) {
7570 s.to_css(&mut CssWriter::new(result)).unwrap()
7574 pub extern "C" fn Servo_FontStretch_SerializeKeyword(
7576 result: &mut nsACString,
7578 let kw = match s.as_keyword() {
7580 None => return false,
7582 kw.to_css(&mut CssWriter::new(result)).unwrap();
7587 pub unsafe extern "C" fn Servo_CursorKind_Parse(
7588 cursor: &nsACString,
7589 result: &mut computed::ui::CursorKind,
7591 match computed::ui::CursorKind::from_ident(cursor.as_str_unchecked()) {
7601 pub extern "C" fn Servo_FontFamily_Generic(generic: GenericFontFamily) -> &'static FontFamily {
7602 FontFamily::generic(generic)
7606 pub extern "C" fn Servo_FontFamily_ForSystemFont(name: &nsACString, out: &mut FontFamily) {
7607 *out = FontFamily::for_system_font(&name.to_utf8());
7611 pub extern "C" fn Servo_FontFamilyList_WithNames(
7612 names: &nsTArray<computed::font::SingleFontFamily>,
7613 out: &mut FontFamilyList,
7615 *out = FontFamilyList {
7616 list: style_traits::arc_slice::ArcSlice::from_iter(names.iter().cloned()),
7621 pub extern "C" fn Servo_FamilyName_Serialize(name: &FamilyName, result: &mut nsACString) {
7622 name.to_css(&mut CssWriter::new(result)).unwrap()
7626 pub extern "C" fn Servo_GenericFontFamily_Parse(input: &nsACString) -> GenericFontFamily {
7627 let context = ParserContext::new(
7629 unsafe { dummy_url_data() },
7630 Some(CssRuleType::Style),
7631 ParsingMode::DEFAULT,
7632 QuirksMode::NoQuirks,
7633 /* namespaces = */ Default::default(),
7637 let value = input.to_utf8();
7638 let mut input = ParserInput::new(&value);
7639 let mut input = Parser::new(&mut input);
7640 GenericFontFamily::parse(&context, &mut input).unwrap_or(GenericFontFamily::None)
7644 pub extern "C" fn Servo_ColorScheme_Parse(input: &nsACString, out: &mut u8) -> bool {
7645 use style::values::specified::ColorScheme;
7647 let context = ParserContext::new(
7649 unsafe { dummy_url_data() },
7650 Some(CssRuleType::Style),
7651 ParsingMode::DEFAULT,
7652 QuirksMode::NoQuirks,
7653 /* namespaces = */ Default::default(),
7657 let input = unsafe { input.as_str_unchecked() };
7658 let mut input = ParserInput::new(&input);
7659 let mut input = Parser::new(&mut input);
7660 let scheme = match input.parse_entirely(|i| ColorScheme::parse(&context, i)) {
7661 Ok(scheme) => scheme,
7662 Err(..) => return false,
7664 *out = scheme.raw_bits();
7669 pub extern "C" fn Servo_LayerBlockRule_GetName(rule: &LayerBlockRule, result: &mut nsACString) {
7670 if let Some(ref name) = rule.name {
7671 name.to_css(&mut CssWriter::new(result)).unwrap()
7676 pub extern "C" fn Servo_LayerStatementRule_GetNameCount(rule: &LayerStatementRule) -> usize {
7681 pub extern "C" fn Servo_LayerStatementRule_GetNameAt(
7682 rule: &LayerStatementRule,
7684 result: &mut nsACString,
7686 if let Some(ref name) = rule.names.get(index) {
7687 name.to_css(&mut CssWriter::new(result)).unwrap()
7692 pub unsafe extern "C" fn Servo_InvalidateForViewportUnits(
7693 document_style: &PerDocumentStyleData,
7694 root: &RawGeckoElement,
7697 let document_data = document_style.borrow();
7698 let device = document_data.stylist.device();
7700 if !device.used_viewport_size() {
7704 if dynamic_only && !device.used_dynamic_viewport_size() {
7708 if style::invalidation::viewport_units::invalidate(GeckoElement(root)) {
7709 // The invalidation machinery propagates the bits up, but we still need
7710 // to tell the Gecko restyle root machinery about it.
7711 bindings::Gecko_NoteDirtySubtreeForInvalidation(root);
7716 pub extern "C" fn Servo_InterpolateColor(
7717 interpolation: ColorInterpolationMethod,
7718 left: &AbsoluteColor,
7719 right: &AbsoluteColor,
7721 ) -> AbsoluteColor {
7722 style::color::mix::mix(
7728 ColorMixFlags::empty(),
7733 pub extern "C" fn Servo_EasingFunctionAt(
7734 easing_function: &ComputedTimingFunction,
7736 before_flag: BeforeFlag,
7738 easing_function.calculate_output(progress, before_flag, 1e-7)
7741 fn parse_no_context<'i, F, R>(string: &'i str, parse: F) -> Result<R, ()>
7743 F: FnOnce(&ParserContext, &mut Parser<'i, '_>) -> Result<R, ParseError<'i>>,
7745 let context = ParserContext::new(
7747 unsafe { dummy_url_data() },
7749 ParsingMode::DEFAULT,
7750 QuirksMode::NoQuirks,
7751 /* namespaces = */ Default::default(),
7755 let mut input = ParserInput::new(string);
7756 Parser::new(&mut input)
7757 .parse_entirely(|i| parse(&context, i))
7762 // Parse a length without style context (for canvas2d letterSpacing/wordSpacing attributes).
7763 // This accepts absolute lengths, and if a font-metrics-getter function is passed, also
7764 // font-relative ones, but not other units (such as percentages, viewport-relative, etc)
7765 // that would require a full style context to resolve.
7766 pub extern "C" fn Servo_ParseLengthWithoutStyleContext(
7769 get_font_metrics: Option<unsafe extern "C" fn(*mut c_void) -> GeckoFontMetrics>,
7770 getter_context: *mut c_void
7772 let metrics_getter = if let Some(getter) = get_font_metrics {
7773 Some(move || -> GeckoFontMetrics {
7774 unsafe { getter(getter_context) }
7779 let value = parse_no_context(unsafe { len.as_str_unchecked() }, specified::Length::parse)
7780 .and_then(|p| p.to_computed_pixel_length_with_font_metrics(metrics_getter));
7791 pub extern "C" fn Servo_SlowRgbToColorName(r: u8, g: u8, b: u8, result: &mut nsACString) -> bool {
7792 let mut candidates = SmallVec::<[&'static str; 5]>::new();
7793 for (name, color) in cssparser::all_named_colors() {
7794 if color == (r, g, b) {
7795 candidates.push(name);
7798 if candidates.is_empty() {
7801 // DevTools expect the first alphabetically.
7803 result.assign(candidates[0]);
7808 pub extern "C" fn Servo_ColorNameToRgb(name: &nsACString, out: &mut structs::nscolor) -> bool {
7809 match cssparser::parse_named_color::<specified::Color>(unsafe { name.as_str_unchecked() }) {
7810 Ok(specified::Color::Absolute(ref color)) => {
7811 *out = style::gecko::values::convert_absolute_color_to_nscolor(&color.color);
7819 pub enum RegisterCustomPropertyResult {
7820 SuccessfullyRegistered,
7825 InvalidInitialValue,
7826 InitialValueNotComputationallyIndependent,
7829 /// https://drafts.css-houdini.org/css-properties-values-api-1/#the-registerproperty-function
7831 pub extern "C" fn Servo_RegisterCustomProperty(
7832 per_doc_data: &PerDocumentStyleData,
7833 extra_data: *mut URLExtraData,
7835 syntax: &nsACString,
7837 initial_value: Option<&nsACString>,
7838 ) -> RegisterCustomPropertyResult {
7839 use self::RegisterCustomPropertyResult::*;
7840 use style::custom_properties::SpecifiedValue;
7841 use style::properties_and_values::registry::PropertyRegistration;
7842 use style::properties_and_values::rule::{PropertyRuleData, ToRegistrationError};
7843 use style::properties_and_values::syntax::Descriptor;
7845 let mut per_doc_data = per_doc_data.borrow_mut();
7846 let url_data = unsafe { UrlExtraData::from_ptr_ref(&extra_data) };
7847 let name = unsafe { name.as_str_unchecked() };
7848 let syntax = unsafe { syntax.as_str_unchecked() };
7849 let initial_value = initial_value.map(|v| unsafe { v.as_str_unchecked() });
7851 // If name is not a custom property name string, throw a SyntaxError and exit this algorithm.
7852 let name = match style::custom_properties::parse_name(name) {
7853 Ok(n) => Atom::from(n),
7854 Err(()) => return InvalidName,
7857 // If property set already contains an entry with name as its property name (compared
7858 // codepoint-wise), throw an InvalidModificationError and exit this algorithm.
7859 if per_doc_data.stylist.custom_property_script_registry().get(&name).is_some() {
7860 return AlreadyRegistered
7862 // Attempt to consume a syntax definition from syntax. If it returns failure, throw a
7863 // SyntaxError. Otherwise, let syntax definition be the returned syntax definition.
7864 let Ok(syntax) = Descriptor::from_str(syntax) else { return InvalidSyntax };
7866 let initial_value = match initial_value {
7868 let mut input = ParserInput::new(v);
7869 let parsed = Parser::new(&mut input).parse_entirely(|input| {
7870 input.skip_whitespace();
7871 SpecifiedValue::parse(input)
7873 if parsed.is_none() {
7874 return InvalidInitialValue
7882 PropertyRuleData::validate_initial_value(&syntax, initial_value.as_ref(), url_data)
7884 return match error {
7885 ToRegistrationError::MissingInherits |
7886 ToRegistrationError::MissingSyntax => unreachable!(),
7887 ToRegistrationError::InitialValueNotComputationallyIndependent => InitialValueNotComputationallyIndependent,
7888 ToRegistrationError::InvalidInitialValue => InvalidInitialValue,
7889 ToRegistrationError::NoInitialValue=> NoInitialValue,
7895 .custom_property_script_registry_mut()
7898 PropertyRegistration {
7902 url_data: url_data.clone(),
7906 SuccessfullyRegistered