glue.rs (357305B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 use super::error_reporter::ErrorReporter; 6 use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader}; 7 use cssparser::ToCss as ParserToCss; 8 use cssparser::{ 9 BasicParseError, ParseError as CssParseError, Parser, ParserInput, ParserState, SourceLocation, 10 Token, UnicodeRange, 11 }; 12 use dom::{DocumentState, ElementState}; 13 use malloc_size_of::MallocSizeOfOps; 14 use nsstring::{nsCString, nsString}; 15 use selectors::context::{MatchingContext, MatchingMode, NeedsSelectorFlags}; 16 use selectors::matching::{ 17 matches_selector_list, ElementSelectorFlags, MatchingForInvalidation, SelectorCaches, 18 }; 19 use selectors::parser::PseudoElement as PseudoElementTrait; 20 use selectors::{Element, OpaqueElement}; 21 use servo_arc::{Arc, ArcBorrow}; 22 use smallvec::SmallVec; 23 use std::collections::BTreeSet; 24 use std::fmt::Write; 25 use std::iter; 26 use std::os::raw::c_void; 27 use std::ptr; 28 use std::sync::LazyLock; 29 use style::color::mix::ColorInterpolationMethod; 30 use style::color::{AbsoluteColor, ColorComponents, ColorSpace}; 31 use style::computed_value_flags::ComputedValueFlags; 32 use style::context::ThreadLocalStyleContext; 33 use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext}; 34 use style::counter_style; 35 use style::custom_properties::DeferFontRelativeCustomPropertyResolution; 36 use style::data::{self, ElementStyles}; 37 use style::dom::{ShowSubtreeData, TDocument, TElement, TNode, TShadowRoot}; 38 use style::driver; 39 use style::error_reporting::{ParseErrorReporter, SelectorWarningKind}; 40 use style::font_face::{self, FontFaceSourceFormat, FontFaceSourceListComponent, Source}; 41 use style::gecko::arc_types::{ 42 LockedCounterStyleRule, LockedCssRules, LockedDeclarationBlock, LockedFontFaceRule, 43 LockedImportRule, LockedKeyframe, LockedKeyframesRule, LockedMediaList, 44 LockedNestedDeclarationsRule, LockedPageRule, LockedPositionTryRule, LockedStyleRule, 45 }; 46 use style::gecko::data::{ 47 AuthorStyles, GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl, 48 }; 49 use style::gecko::restyle_damage::GeckoRestyleDamage; 50 use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement}; 51 use style::gecko::snapshot_helpers::classes_changed; 52 use style::gecko::traversal::RecalcStyleOnly; 53 use style::gecko::url; 54 use style::gecko::wrapper::{ 55 slow_selector_flags_from_node_selector_flags, GeckoElement, GeckoNode, 56 }; 57 use style::gecko_bindings::bindings; 58 use style::gecko_bindings::bindings::nsACString; 59 use style::gecko_bindings::bindings::nsAString; 60 use style::gecko_bindings::bindings::Gecko_AddPropertyToSet; 61 use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet; 62 use style::gecko_bindings::bindings::Gecko_ConstructFontPaletteValueSet; 63 use style::gecko_bindings::bindings::Gecko_HaveSeenPtr; 64 use style::gecko_bindings::structs; 65 use style::gecko_bindings::structs::gfx::FontPaletteValueSet; 66 use style::gecko_bindings::structs::gfxFontFeatureValueSet; 67 use style::gecko_bindings::structs::nsAtom; 68 use style::gecko_bindings::structs::nsCSSCounterDesc; 69 use style::gecko_bindings::structs::nsCSSFontDesc; 70 use style::gecko_bindings::structs::nsChangeHint; 71 use style::gecko_bindings::structs::nsCompatibility; 72 use style::gecko_bindings::structs::nsresult; 73 use style::gecko_bindings::structs::CallerType; 74 use style::gecko_bindings::structs::CompositeOperation; 75 use style::gecko_bindings::structs::DeclarationBlockMutationClosure; 76 use style::gecko_bindings::structs::GeckoFontMetrics; 77 use style::gecko_bindings::structs::IterationCompositeOperation; 78 use style::gecko_bindings::structs::Loader; 79 use style::gecko_bindings::structs::LoaderReusableStyleSheets; 80 use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf; 81 use style::gecko_bindings::structs::NonCustomCSSPropertyId; 82 use style::gecko_bindings::structs::OriginFlags; 83 use style::gecko_bindings::structs::PropertyValuePair; 84 use style::gecko_bindings::structs::PseudoStyleType; 85 use style::gecko_bindings::structs::SeenPtrs; 86 use style::gecko_bindings::structs::ServoElementSnapshotTable; 87 use style::gecko_bindings::structs::ServoStyleSetSizes; 88 use style::gecko_bindings::structs::ServoTraversalFlags; 89 use style::gecko_bindings::structs::SheetLoadData; 90 use style::gecko_bindings::structs::SheetLoadDataHolder; 91 use style::gecko_bindings::structs::SheetParsingMode; 92 use style::gecko_bindings::structs::StyleRuleInclusion; 93 use style::gecko_bindings::structs::StyleSheet as DomStyleSheet; 94 use style::gecko_bindings::structs::URLExtraData; 95 use style::gecko_bindings::structs::{nsINode as RawGeckoNode, Element as RawGeckoElement}; 96 use style::gecko_bindings::structs::{AnchorPosOffsetResolutionParams, AnchorPosResolutionParams}; 97 use style::gecko_bindings::sugar::ownership::Strong; 98 use style::gecko_bindings::sugar::refptr::RefPtr; 99 use style::global_style_data::{ 100 GlobalStyleData, PlatformThreadHandle, StyleThreadPool, GLOBAL_STYLE_DATA, STYLE_THREAD_POOL, 101 }; 102 use style::invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper}; 103 use style::invalidation::element::invalidation_map::{InvalidationMap, TSStateForInvalidation}; 104 use style::invalidation::element::invalidator::{InvalidationResult, SiblingTraversalMap}; 105 use style::invalidation::element::relative_selector::{ 106 DomMutationOperation, RelativeSelectorDependencyCollector, RelativeSelectorInvalidator, 107 }; 108 use style::invalidation::element::restyle_hints::RestyleHint; 109 use style::invalidation::stylesheets::RuleChangeKind; 110 use style::logical_geometry::{LogicalAxis, PhysicalAxis, PhysicalSide, WritingMode}; 111 use style::media_queries::MediaList; 112 use style::parser::{Parse, ParserContext}; 113 use style::properties::declaration_block::PropertyTypedValue; 114 #[cfg(feature = "gecko_debug")] 115 use style::properties::LonghandIdSet; 116 use style::properties::{ 117 animated_properties::{AnimationValue, AnimationValueMap}, 118 parse_one_declaration_into, parse_style_attribute, ComputedValues, CountedUnknownProperty, 119 Importance, LonghandId, NonCustomPropertyId, OwnedPropertyDeclarationId, 120 PropertyDeclarationBlock, PropertyDeclarationId, PropertyDeclarationIdSet, PropertyId, 121 ShorthandId, SourcePropertyDeclaration, StyleBuilder, 122 }; 123 use style::properties_and_values::registry::{PropertyRegistration, PropertyRegistrationData}; 124 use style::properties_and_values::rule::Inherits as PropertyInherits; 125 use style::rule_cache::RuleCacheConditions; 126 use style::rule_tree::StrongRuleNode; 127 use style::selector_parser::PseudoElementCascadeType; 128 use style::shared_lock::{ 129 Locked, SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, 130 }; 131 use style::string_cache::{Atom, WeakAtom}; 132 use style::style_adjuster::StyleAdjuster; 133 use style::stylesheets::container_rule::ContainerSizeQuery; 134 use style::stylesheets::import_rule::{ImportLayer, ImportSheet}; 135 use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue}; 136 use style::stylesheets::scope_rule::{ImplicitScopeRoot, ScopeRootCandidate, ScopeSubjectMap}; 137 use style::stylesheets::supports_rule::parse_condition_or_declaration; 138 use style::stylesheets::{ 139 AllowImportRules, ContainerRule, CounterStyleRule, CssRule, CssRuleRef, CssRuleType, 140 CssRuleTypes, CssRules, CustomMediaCondition, CustomMediaEvaluator, CustomMediaRule, 141 DocumentRule, FontFaceRule, FontFeatureValuesRule, FontPaletteValuesRule, ImportRule, 142 KeyframesRule, LayerBlockRule, LayerStatementRule, MarginRule, MediaRule, NamespaceRule, 143 NestedDeclarationsRule, Origin, OriginSet, PagePseudoClassFlags, PageRule, PositionTryRule, 144 PropertyRule, SanitizationData, SanitizationKind, ScopeRule, StartingStyleRule, StyleRule, 145 StylesheetContents, StylesheetInDocument, StylesheetLoader as StyleStylesheetLoader, 146 SupportsRule, UrlExtraData, 147 }; 148 use style::stylist::{ 149 add_size_of_ua_cache, replace_parent_selector_with_implicit_scope, scope_root_candidates, 150 AuthorStylesEnabled, RuleInclusion, ScopeBoundsWithHashes, ScopeConditionId, 151 ScopeConditionReference, Stylist, 152 }; 153 use style::thread_state; 154 use style::traversal::resolve_style; 155 use style::traversal::DomTraversal; 156 use style::traversal_flags::{self, TraversalFlags}; 157 use style::use_counters::{CustomUseCounter, UseCounters}; 158 use style::values::animated::{Animate, Procedure, ToAnimatedZero}; 159 use style::values::computed::easing::ComputedTimingFunction; 160 use style::values::computed::effects::Filter; 161 use style::values::computed::font::{ 162 FamilyName, FontFamily, FontFamilyList, FontStretch, FontStyle, FontWeight, GenericFontFamily, 163 }; 164 use style::values::computed::length_percentage::{ 165 AllowAnchorPosResolutionInCalcPercentage, Unpacked, 166 }; 167 use style::values::computed::position::{AnchorFunction, PositionArea}; 168 use style::values::computed::{self, ContentVisibility, Context, ToComputedValue}; 169 use style::values::distance::{ComputeSquaredDistance, SquaredDistance}; 170 use style::values::generics::color::ColorMixFlags; 171 use style::values::generics::easing::BeforeFlag; 172 use style::values::generics::length::GenericAnchorSizeFunction; 173 use style::values::resolved; 174 use style::values::specified::align::AlignFlags; 175 use style::values::specified::intersection_observer::IntersectionObserverMargin; 176 use style::values::specified::position::PositionTryFallbacksItem; 177 use style::values::specified::source_size_list::SourceSizeList; 178 use style::values::specified::svg_path::PathCommand; 179 use style::values::specified::{AbsoluteLength, NoCalcLength}; 180 use style::values::{specified, AtomIdent, CustomIdent, KeyframesName}; 181 use style_traits::{CssWriter, ParseError, ParsingMode, ToCss, TypedValue}; 182 use thin_vec::ThinVec as nsTArray; 183 use to_shmem::SharedMemoryBuilder; 184 185 trait ClosureHelper { 186 fn invoke(&self, property_id: Option<NonCustomPropertyId>); 187 } 188 189 const NO_MUTATION_CLOSURE: DeclarationBlockMutationClosure = DeclarationBlockMutationClosure { 190 data: std::ptr::null_mut(), 191 function: None, 192 }; 193 194 impl ClosureHelper for DeclarationBlockMutationClosure { 195 #[inline] 196 fn invoke(&self, property_id: Option<NonCustomPropertyId>) { 197 if let Some(function) = self.function.as_ref() { 198 let gecko_prop_id = match property_id { 199 Some(p) => p.to_noncustomcsspropertyid(), 200 None => NonCustomCSSPropertyId::eCSSPropertyExtra_variable, 201 }; 202 unsafe { function(self.data, gecko_prop_id) } 203 } 204 } 205 } 206 207 /* 208 * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in 209 * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against 210 * those signatures as well, giving us a second declaration of all the Servo_* functions in this 211 * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to 212 * depend on but good enough for our purposes. 213 */ 214 215 // A dummy url data for where we don't pass url data in. 216 static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut _; 217 static mut DUMMY_CHROME_URL_DATA: *mut URLExtraData = 0 as *mut _; 218 219 #[no_mangle] 220 pub unsafe extern "C" fn Servo_Initialize( 221 dummy_url_data: *mut URLExtraData, 222 dummy_chrome_url_data: *mut URLExtraData, 223 ) { 224 use style::gecko_bindings::sugar::origin_flags; 225 226 // Pretend that we're a Servo Layout thread, to make some assertions happy. 227 thread_state::initialize(thread_state::ThreadState::LAYOUT); 228 229 debug_assert!(is_main_thread()); 230 LazyLock::force(&STYLE_THREAD_POOL); 231 232 // Perform some debug-only runtime assertions. 233 origin_flags::assert_flags_match(); 234 traversal_flags::assert_traversal_flags_match(); 235 236 DUMMY_URL_DATA = dummy_url_data; 237 DUMMY_CHROME_URL_DATA = dummy_chrome_url_data; 238 } 239 240 #[no_mangle] 241 pub unsafe extern "C" fn Servo_Shutdown() { 242 DUMMY_URL_DATA = ptr::null_mut(); 243 DUMMY_CHROME_URL_DATA = ptr::null_mut(); 244 Stylist::shutdown(); 245 url::shutdown(); 246 } 247 248 #[inline(always)] 249 unsafe fn dummy_url_data() -> &'static UrlExtraData { 250 UrlExtraData::from_ptr_ref(std::ptr::addr_of!(DUMMY_URL_DATA).as_ref().unwrap()) 251 } 252 253 #[inline(always)] 254 unsafe fn dummy_chrome_url_data() -> &'static UrlExtraData { 255 UrlExtraData::from_ptr_ref(std::ptr::addr_of!(DUMMY_CHROME_URL_DATA).as_ref().unwrap()) 256 } 257 258 #[allow(dead_code)] 259 fn is_main_thread() -> bool { 260 unsafe { bindings::Gecko_IsMainThread() } 261 } 262 263 #[allow(dead_code)] 264 fn is_dom_worker_thread() -> bool { 265 unsafe { bindings::Gecko_IsDOMWorkerThread() } 266 } 267 268 thread_local! { 269 /// Thread-local style data for DOM workers 270 static DOM_WORKER_RWLOCK: SharedRwLock = SharedRwLock::new(); 271 } 272 273 #[allow(dead_code)] 274 fn is_in_servo_traversal() -> bool { 275 unsafe { bindings::Gecko_IsInServoTraversal() } 276 } 277 278 fn create_shared_context<'a>( 279 global_style_data: &GlobalStyleData, 280 guard: &'a SharedRwLockReadGuard, 281 stylist: &'a Stylist, 282 traversal_flags: TraversalFlags, 283 snapshot_map: &'a ServoElementSnapshotTable, 284 ) -> SharedStyleContext<'a> { 285 SharedStyleContext { 286 stylist: &stylist, 287 visited_styles_enabled: stylist.device().visited_styles_enabled(), 288 options: global_style_data.options.clone(), 289 guards: StylesheetGuards::same(guard), 290 current_time_for_animations: 0.0, // Unused for Gecko, at least for now. 291 traversal_flags, 292 snapshot_map, 293 } 294 } 295 296 fn traverse_subtree( 297 element: GeckoElement, 298 global_style_data: &GlobalStyleData, 299 per_doc_data: &PerDocumentStyleDataImpl, 300 guard: &SharedRwLockReadGuard, 301 traversal_flags: TraversalFlags, 302 snapshots: &ServoElementSnapshotTable, 303 ) { 304 let shared_style_context = create_shared_context( 305 &global_style_data, 306 &guard, 307 &per_doc_data.stylist, 308 traversal_flags, 309 snapshots, 310 ); 311 312 let token = RecalcStyleOnly::pre_traverse(element, &shared_style_context); 313 314 if !token.should_traverse() { 315 return; 316 } 317 318 debug!("Traversing subtree from {:?}", element); 319 320 let thread_pool_holder = &*STYLE_THREAD_POOL; 321 let pool; 322 let thread_pool = if traversal_flags.contains(TraversalFlags::ParallelTraversal) { 323 pool = thread_pool_holder.pool(); 324 pool.as_ref() 325 } else { 326 None 327 }; 328 329 let traversal = RecalcStyleOnly::new(shared_style_context); 330 driver::traverse_dom(&traversal, token, thread_pool); 331 } 332 333 /// Traverses the subtree rooted at `root` for restyling. 334 /// 335 /// Returns whether the root was restyled. Whether anything else was restyled or 336 /// not can be inferred from the dirty bits in the rest of the tree. 337 #[no_mangle] 338 pub extern "C" fn Servo_TraverseSubtree( 339 root: &RawGeckoElement, 340 raw_data: &PerDocumentStyleData, 341 snapshots: *const ServoElementSnapshotTable, 342 raw_flags: ServoTraversalFlags, 343 ) -> bool { 344 let traversal_flags = TraversalFlags::from_bits_retain(raw_flags); 345 debug_assert!(!snapshots.is_null()); 346 347 let element = GeckoElement(root); 348 349 debug!("Servo_TraverseSubtree (flags={:?})", traversal_flags); 350 debug!("{:?}", ShowSubtreeData(element.as_node())); 351 352 if cfg!(debug_assertions) { 353 if let Some(parent) = element.traversal_parent() { 354 let data = parent 355 .borrow_data() 356 .expect("Styling element with unstyled parent"); 357 assert!( 358 !data.styles.is_display_none(), 359 "Styling element with display: none parent" 360 ); 361 } 362 } 363 364 let needs_animation_only_restyle = 365 element.has_animation_only_dirty_descendants() || element.has_animation_restyle_hints(); 366 367 let per_doc_data = raw_data.borrow(); 368 debug_assert!(!per_doc_data.stylist.stylesheets_have_changed()); 369 370 let global_style_data = &*GLOBAL_STYLE_DATA; 371 let guard = global_style_data.shared_lock.read(); 372 373 let was_initial_style = !element.has_data(); 374 375 if needs_animation_only_restyle { 376 debug!( 377 "Servo_TraverseSubtree doing animation-only restyle (aodd={})", 378 element.has_animation_only_dirty_descendants() 379 ); 380 traverse_subtree( 381 element, 382 &global_style_data, 383 &per_doc_data, 384 &guard, 385 traversal_flags | TraversalFlags::AnimationOnly, 386 unsafe { &*snapshots }, 387 ); 388 } 389 390 traverse_subtree( 391 element, 392 &global_style_data, 393 &per_doc_data, 394 &guard, 395 traversal_flags, 396 unsafe { &*snapshots }, 397 ); 398 399 debug!( 400 "Servo_TraverseSubtree complete (dd={}, aodd={}, lfcd={}, lfc={}, data={:?})", 401 element.has_dirty_descendants(), 402 element.has_animation_only_dirty_descendants(), 403 element.descendants_need_frames(), 404 element.needs_frame(), 405 element.borrow_data().unwrap() 406 ); 407 408 if was_initial_style { 409 debug_assert!(!element.borrow_data().unwrap().contains_restyle_data()); 410 false 411 } else { 412 let element_was_restyled = element.borrow_data().unwrap().contains_restyle_data(); 413 element_was_restyled 414 } 415 } 416 417 /// Checks whether the rule tree has crossed its threshold for unused nodes, and 418 /// if so, frees them. 419 #[no_mangle] 420 pub extern "C" fn Servo_MaybeGCRuleTree(raw_data: &PerDocumentStyleData) { 421 let per_doc_data = raw_data.borrow_mut(); 422 per_doc_data.stylist.rule_tree().maybe_gc(); 423 } 424 425 #[no_mangle] 426 pub extern "C" fn Servo_AnimationValues_Interpolate( 427 from: &AnimationValue, 428 to: &AnimationValue, 429 progress: f64, 430 ) -> Strong<AnimationValue> { 431 if let Ok(value) = from.animate(to, Procedure::Interpolate { progress }) { 432 Arc::new(value).into() 433 } else { 434 Strong::null() 435 } 436 } 437 438 #[no_mangle] 439 pub extern "C" fn Servo_AnimationValues_IsInterpolable( 440 from: &AnimationValue, 441 to: &AnimationValue, 442 ) -> bool { 443 from.interpolable_with(to) 444 } 445 446 #[no_mangle] 447 pub extern "C" fn Servo_AnimationValues_Add( 448 a: &AnimationValue, 449 b: &AnimationValue, 450 ) -> Strong<AnimationValue> { 451 if let Ok(value) = a.animate(b, Procedure::Add) { 452 Arc::new(value).into() 453 } else { 454 Strong::null() 455 } 456 } 457 458 #[no_mangle] 459 pub extern "C" fn Servo_AnimationValues_Accumulate( 460 a: &AnimationValue, 461 b: &AnimationValue, 462 count: u64, 463 ) -> Strong<AnimationValue> { 464 if let Ok(value) = a.animate(b, Procedure::Accumulate { count }) { 465 Arc::new(value).into() 466 } else { 467 Strong::null() 468 } 469 } 470 471 #[no_mangle] 472 pub extern "C" fn Servo_AnimationValues_GetZeroValue( 473 value_to_match: &AnimationValue, 474 ) -> Strong<AnimationValue> { 475 if let Ok(zero_value) = value_to_match.to_animated_zero() { 476 Arc::new(zero_value).into() 477 } else { 478 Strong::null() 479 } 480 } 481 482 #[no_mangle] 483 pub extern "C" fn Servo_AnimationValues_ComputeDistance( 484 from: &AnimationValue, 485 to: &AnimationValue, 486 ) -> f64 { 487 // If compute_squared_distance() failed, this function will return negative value 488 // in order to check whether we support the specified paced animation values. 489 from.compute_squared_distance(to).map_or(-1.0, |d| d.sqrt()) 490 } 491 492 /// Compute one of the endpoints for the interpolation interval, compositing it with the 493 /// underlying value if needed. 494 /// An None returned value means, "Just use endpoint_value as-is." 495 /// It is the responsibility of the caller to ensure that |underlying_value| is provided 496 /// when it will be used. 497 fn composite_endpoint( 498 endpoint_value: Option<&AnimationValue>, 499 composite: CompositeOperation, 500 underlying_value: Option<&AnimationValue>, 501 ) -> Option<AnimationValue> { 502 match endpoint_value { 503 Some(endpoint_value) => match composite { 504 CompositeOperation::Add => underlying_value 505 .expect("We should have an underlying_value") 506 .animate(endpoint_value, Procedure::Add) 507 .ok(), 508 CompositeOperation::Accumulate => underlying_value 509 .expect("We should have an underlying value") 510 .animate(endpoint_value, Procedure::Accumulate { count: 1 }) 511 .ok(), 512 _ => None, 513 }, 514 None => underlying_value.map(|v| v.clone()), 515 } 516 } 517 518 /// Accumulate one of the endpoints of the animation interval. 519 /// A returned value of None means, "Just use endpoint_value as-is." 520 fn accumulate_endpoint( 521 endpoint_value: Option<&AnimationValue>, 522 composited_value: Option<AnimationValue>, 523 last_value: &AnimationValue, 524 current_iteration: u64, 525 ) -> Option<AnimationValue> { 526 debug_assert!( 527 endpoint_value.is_some() || composited_value.is_some(), 528 "Should have a suitable value to use" 529 ); 530 531 let count = current_iteration; 532 match composited_value { 533 Some(endpoint) => last_value 534 .animate(&endpoint, Procedure::Accumulate { count }) 535 .ok() 536 .or(Some(endpoint)), 537 None => last_value 538 .animate(endpoint_value.unwrap(), Procedure::Accumulate { count }) 539 .ok(), 540 } 541 } 542 543 /// Compose the animation segment. We composite it with the underlying_value and last_value if 544 /// needed. 545 /// The caller is responsible for providing an underlying value and last value 546 /// in all situations where there are needed. 547 fn compose_animation_segment( 548 segment: &structs::AnimationPropertySegment, 549 underlying_value: Option<&AnimationValue>, 550 last_value: Option<&AnimationValue>, 551 iteration_composite: IterationCompositeOperation, 552 current_iteration: u64, 553 total_progress: f64, 554 segment_progress: f64, 555 ) -> AnimationValue { 556 // Extract keyframe values. 557 let keyframe_from_value = unsafe { segment.mFromValue.mServo.mRawPtr.as_ref() }; 558 let keyframe_to_value = unsafe { segment.mToValue.mServo.mRawPtr.as_ref() }; 559 let mut composited_from_value = composite_endpoint( 560 keyframe_from_value, 561 segment.mFromComposite, 562 underlying_value, 563 ); 564 let mut composited_to_value = 565 composite_endpoint(keyframe_to_value, segment.mToComposite, underlying_value); 566 567 debug_assert!( 568 keyframe_from_value.is_some() || composited_from_value.is_some(), 569 "Should have a suitable from value to use" 570 ); 571 debug_assert!( 572 keyframe_to_value.is_some() || composited_to_value.is_some(), 573 "Should have a suitable to value to use" 574 ); 575 576 // Apply iteration composite behavior. 577 if iteration_composite == IterationCompositeOperation::Accumulate && current_iteration > 0 { 578 let last_value = last_value 579 .unwrap_or_else(|| underlying_value.expect("Should have a valid underlying value")); 580 581 composited_from_value = accumulate_endpoint( 582 keyframe_from_value, 583 composited_from_value, 584 last_value, 585 current_iteration, 586 ); 587 composited_to_value = accumulate_endpoint( 588 keyframe_to_value, 589 composited_to_value, 590 last_value, 591 current_iteration, 592 ); 593 } 594 595 // Use the composited value if there is one, otherwise, use the original keyframe value. 596 let from = composited_from_value 597 .as_ref() 598 .unwrap_or_else(|| keyframe_from_value.unwrap()); 599 let to = composited_to_value 600 .as_ref() 601 .unwrap_or_else(|| keyframe_to_value.unwrap()); 602 603 if segment.mToKey == segment.mFromKey { 604 return if total_progress < 0. { 605 from.clone() 606 } else { 607 to.clone() 608 }; 609 } 610 611 match from.animate( 612 to, 613 Procedure::Interpolate { 614 progress: segment_progress, 615 }, 616 ) { 617 Ok(value) => value, 618 _ => { 619 if segment_progress < 0.5 { 620 from.clone() 621 } else { 622 to.clone() 623 } 624 }, 625 } 626 } 627 628 #[no_mangle] 629 pub extern "C" fn Servo_ComposeAnimationSegment( 630 segment: &structs::AnimationPropertySegment, 631 underlying_value: Option<&AnimationValue>, 632 last_value: Option<&AnimationValue>, 633 iteration_composite: IterationCompositeOperation, 634 progress: f64, 635 current_iteration: u64, 636 ) -> Strong<AnimationValue> { 637 let result = compose_animation_segment( 638 segment, 639 underlying_value, 640 last_value, 641 iteration_composite, 642 current_iteration, 643 progress, 644 progress, 645 ); 646 Arc::new(result).into() 647 } 648 649 #[no_mangle] 650 pub extern "C" fn Servo_AnimationCompose( 651 value_map: &mut AnimationValueMap, 652 base_values: &structs::RawServoAnimationValueTable, 653 css_property: &structs::CSSPropertyId, 654 segment: &structs::AnimationPropertySegment, 655 last_segment: &structs::AnimationPropertySegment, 656 computed_timing: &structs::ComputedTiming, 657 iteration_composite: IterationCompositeOperation, 658 ) { 659 use style::gecko_bindings::bindings::Gecko_AnimationGetBaseStyle; 660 use style::gecko_bindings::bindings::Gecko_GetPositionInSegment; 661 use style::gecko_bindings::bindings::Gecko_GetProgressFromComputedTiming; 662 663 let property = match OwnedPropertyDeclarationId::from_gecko_css_property_id(css_property) { 664 Some(property) if property.as_borrowed().is_animatable() => property, 665 _ => return, 666 }; 667 668 // We will need an underlying value if either of the endpoints is null... 669 let need_underlying_value = segment.mFromValue.mServo.mRawPtr.is_null() || 670 segment.mToValue.mServo.mRawPtr.is_null() || 671 // ... or if they have a non-replace composite mode ... 672 segment.mFromComposite != CompositeOperation::Replace || 673 segment.mToComposite != CompositeOperation::Replace || 674 // ... or if we accumulate onto the last value and it is null. 675 (iteration_composite == IterationCompositeOperation::Accumulate && 676 computed_timing.mCurrentIteration > 0 && 677 last_segment.mToValue.mServo.mRawPtr.is_null()); 678 679 // If either of the segment endpoints are null, get the underlying value to 680 // use from the current value in the values map (set by a lower-priority 681 // effect), or, if there is no current value, look up the cached base value 682 // for this property. 683 let underlying_value = if need_underlying_value { 684 let previous_composed_value = value_map.get(&property).map(|v| &*v); 685 previous_composed_value 686 .or_else(|| unsafe { Gecko_AnimationGetBaseStyle(base_values, css_property).as_ref() }) 687 } else { 688 None 689 }; 690 691 if need_underlying_value && underlying_value.is_none() { 692 warn!("Underlying value should be valid when we expect to use it"); 693 return; 694 } 695 696 let last_value = unsafe { last_segment.mToValue.mServo.mRawPtr.as_ref() }; 697 let progress = unsafe { Gecko_GetProgressFromComputedTiming(computed_timing) }; 698 let position = if segment.mToKey == segment.mFromKey { 699 // Note: compose_animation_segment doesn't use this value 700 // if segment.mFromKey == segment.mToKey, so assigning |progress| directly is fine. 701 progress 702 } else { 703 unsafe { Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag) } 704 }; 705 706 let result = compose_animation_segment( 707 segment, 708 underlying_value, 709 last_value, 710 iteration_composite, 711 computed_timing.mCurrentIteration, 712 progress, 713 position, 714 ); 715 value_map.insert(property, result); 716 } 717 718 macro_rules! get_property_id_from_noncustomcsspropertyid { 719 ($property_id: ident, $ret: expr) => {{ 720 match PropertyId::from_noncustomcsspropertyid($property_id) { 721 Some(property_id) => property_id, 722 None => { 723 return $ret; 724 }, 725 } 726 }}; 727 } 728 729 macro_rules! get_property_id_from_csspropertyid { 730 ($property_id: ident, $ret: expr) => {{ 731 match PropertyId::from_gecko_css_property_id($property_id) { 732 Some(property_id) => property_id, 733 None => { 734 return $ret; 735 }, 736 } 737 }}; 738 } 739 740 #[no_mangle] 741 pub extern "C" fn Servo_AnimationValue_Serialize( 742 value: &AnimationValue, 743 property: &structs::CSSPropertyId, 744 raw_data: &PerDocumentStyleData, 745 buffer: &mut nsACString, 746 ) { 747 let uncomputed_value = value.uncompute(); 748 let data = raw_data.borrow(); 749 let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal) 750 .single_value_to_css( 751 &get_property_id_from_csspropertyid!(property, ()), 752 buffer, 753 None, 754 &data.stylist, 755 ); 756 debug_assert!(rv.is_ok()); 757 } 758 759 /// Debug: MOZ_DBG for AnimationValue. 760 #[no_mangle] 761 pub extern "C" fn Servo_AnimationValue_Dump(value: &AnimationValue, result: &mut nsACString) { 762 write!(result, "{:?}", value).unwrap(); 763 } 764 765 #[no_mangle] 766 pub extern "C" fn Servo_AnimationValue_GetColor( 767 value: &AnimationValue, 768 foreground_color: structs::nscolor, 769 ) -> structs::nscolor { 770 use style::gecko::values::{ 771 convert_absolute_color_to_nscolor, convert_nscolor_to_absolute_color, 772 }; 773 use style::values::computed::color::Color as ComputedColor; 774 match *value { 775 AnimationValue::BackgroundColor(ref color) => { 776 let computed: ComputedColor = color.clone(); 777 let foreground_color = convert_nscolor_to_absolute_color(foreground_color); 778 convert_absolute_color_to_nscolor(&computed.resolve_to_absolute(&foreground_color)) 779 }, 780 _ => panic!("Other color properties are not supported yet"), 781 } 782 } 783 784 #[no_mangle] 785 pub extern "C" fn Servo_AnimationValue_IsCurrentColor(value: &AnimationValue) -> bool { 786 match *value { 787 AnimationValue::BackgroundColor(ref color) => color.is_currentcolor(), 788 _ => { 789 debug_assert!(false, "Other color properties are not supported yet"); 790 false 791 }, 792 } 793 } 794 795 #[no_mangle] 796 pub extern "C" fn Servo_AnimationValue_GetOpacity(value: &AnimationValue) -> f32 { 797 if let AnimationValue::Opacity(opacity) = *value { 798 opacity 799 } else { 800 panic!("The AnimationValue should be Opacity"); 801 } 802 } 803 804 #[no_mangle] 805 pub extern "C" fn Servo_AnimationValue_Opacity(opacity: f32) -> Strong<AnimationValue> { 806 Arc::new(AnimationValue::Opacity(opacity)).into() 807 } 808 809 #[no_mangle] 810 pub extern "C" fn Servo_AnimationValue_Color( 811 color_property: NonCustomCSSPropertyId, 812 color: structs::nscolor, 813 ) -> Strong<AnimationValue> { 814 use style::gecko::values::convert_nscolor_to_absolute_color; 815 use style::values::animated::color::Color; 816 817 let property = LonghandId::from_noncustomcsspropertyid(color_property) 818 .expect("We don't have shorthand property animation value"); 819 820 let animated = convert_nscolor_to_absolute_color(color); 821 822 match property { 823 LonghandId::BackgroundColor => { 824 Arc::new(AnimationValue::BackgroundColor(Color::Absolute(animated))).into() 825 }, 826 _ => panic!("Should be background-color property"), 827 } 828 } 829 830 #[no_mangle] 831 pub unsafe extern "C" fn Servo_AnimationValue_GetScale( 832 value: &AnimationValue, 833 ) -> *const computed::Scale { 834 match *value { 835 AnimationValue::Scale(ref value) => value, 836 _ => unreachable!("Expected scale"), 837 } 838 } 839 840 #[no_mangle] 841 pub unsafe extern "C" fn Servo_AnimationValue_GetTranslate( 842 value: &AnimationValue, 843 ) -> *const computed::Translate { 844 match *value { 845 AnimationValue::Translate(ref value) => value, 846 _ => unreachable!("Expected translate"), 847 } 848 } 849 850 #[no_mangle] 851 pub unsafe extern "C" fn Servo_AnimationValue_GetRotate( 852 value: &AnimationValue, 853 ) -> *const computed::Rotate { 854 match *value { 855 AnimationValue::Rotate(ref value) => value, 856 _ => unreachable!("Expected rotate"), 857 } 858 } 859 860 #[no_mangle] 861 pub unsafe extern "C" fn Servo_AnimationValue_GetTransform( 862 value: &AnimationValue, 863 ) -> *const computed::Transform { 864 match *value { 865 AnimationValue::Transform(ref value) => value, 866 _ => unreachable!("Unsupported transform animation value"), 867 } 868 } 869 870 #[no_mangle] 871 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPath( 872 value: &AnimationValue, 873 output: &mut computed::motion::OffsetPath, 874 ) { 875 use style::values::animated::ToAnimatedValue; 876 match *value { 877 AnimationValue::OffsetPath(ref value) => { 878 *output = ToAnimatedValue::from_animated_value(value.clone()) 879 }, 880 _ => unreachable!("Expected offset-path"), 881 } 882 } 883 884 #[no_mangle] 885 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetDistance( 886 value: &AnimationValue, 887 ) -> *const computed::LengthPercentage { 888 match *value { 889 AnimationValue::OffsetDistance(ref value) => value, 890 _ => unreachable!("Expected offset-distance"), 891 } 892 } 893 894 #[no_mangle] 895 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetRotate( 896 value: &AnimationValue, 897 ) -> *const computed::motion::OffsetRotate { 898 match *value { 899 AnimationValue::OffsetRotate(ref value) => value, 900 _ => unreachable!("Expected offset-rotate"), 901 } 902 } 903 904 #[no_mangle] 905 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetAnchor( 906 value: &AnimationValue, 907 ) -> *const computed::position::PositionOrAuto { 908 match *value { 909 AnimationValue::OffsetAnchor(ref value) => value, 910 _ => unreachable!("Expected offset-anchor"), 911 } 912 } 913 914 #[no_mangle] 915 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPosition( 916 value: &AnimationValue, 917 ) -> *const computed::motion::OffsetPosition { 918 match *value { 919 AnimationValue::OffsetPosition(ref value) => value, 920 _ => unreachable!("Expected offset-position"), 921 } 922 } 923 924 #[no_mangle] 925 pub unsafe extern "C" fn Servo_AnimationValue_IsOffsetPathUrl(value: &AnimationValue) -> bool { 926 use style::values::generics::motion::{GenericOffsetPath, GenericOffsetPathFunction}; 927 if let AnimationValue::OffsetPath(ref op) = value { 928 if let GenericOffsetPath::OffsetPath { path, coord_box: _ } = op { 929 return matches!(**path, GenericOffsetPathFunction::Url(_)); 930 } 931 } 932 false 933 } 934 935 #[no_mangle] 936 pub unsafe extern "C" fn Servo_AnimationValue_Rotate( 937 r: &computed::Rotate, 938 ) -> Strong<AnimationValue> { 939 Arc::new(AnimationValue::Rotate(r.clone())).into() 940 } 941 942 #[no_mangle] 943 pub unsafe extern "C" fn Servo_AnimationValue_Translate( 944 t: &computed::Translate, 945 ) -> Strong<AnimationValue> { 946 Arc::new(AnimationValue::Translate(t.clone())).into() 947 } 948 949 #[no_mangle] 950 pub unsafe extern "C" fn Servo_AnimationValue_Scale(s: &computed::Scale) -> Strong<AnimationValue> { 951 Arc::new(AnimationValue::Scale(s.clone())).into() 952 } 953 954 #[no_mangle] 955 pub unsafe extern "C" fn Servo_AnimationValue_Transform( 956 transform: &computed::Transform, 957 ) -> Strong<AnimationValue> { 958 Arc::new(AnimationValue::Transform(transform.clone())).into() 959 } 960 961 #[no_mangle] 962 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPath( 963 p: &computed::OffsetPath, 964 ) -> Strong<AnimationValue> { 965 Arc::new(AnimationValue::OffsetPath(std::mem::transmute(p.clone()))).into() 966 } 967 968 #[no_mangle] 969 pub unsafe extern "C" fn Servo_AnimationValue_OffsetDistance( 970 d: &computed::LengthPercentage, 971 ) -> Strong<AnimationValue> { 972 Arc::new(AnimationValue::OffsetDistance(d.clone())).into() 973 } 974 975 #[no_mangle] 976 pub unsafe extern "C" fn Servo_AnimationValue_OffsetRotate( 977 r: &computed::motion::OffsetRotate, 978 ) -> Strong<AnimationValue> { 979 Arc::new(AnimationValue::OffsetRotate(*r)).into() 980 } 981 982 #[no_mangle] 983 pub unsafe extern "C" fn Servo_AnimationValue_OffsetAnchor( 984 p: &computed::position::PositionOrAuto, 985 ) -> Strong<AnimationValue> { 986 Arc::new(AnimationValue::OffsetAnchor(p.clone())).into() 987 } 988 989 #[no_mangle] 990 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPosition( 991 p: &computed::motion::OffsetPosition, 992 ) -> Strong<AnimationValue> { 993 Arc::new(AnimationValue::OffsetPosition(p.clone())).into() 994 } 995 996 #[no_mangle] 997 pub extern "C" fn Servo_AnimationValue_DeepEqual( 998 this: &AnimationValue, 999 other: &AnimationValue, 1000 ) -> bool { 1001 this == other 1002 } 1003 1004 #[no_mangle] 1005 pub extern "C" fn Servo_AnimationValue_Uncompute( 1006 value: &AnimationValue, 1007 ) -> Strong<LockedDeclarationBlock> { 1008 let global_style_data = &*GLOBAL_STYLE_DATA; 1009 Arc::new( 1010 global_style_data 1011 .shared_lock 1012 .wrap(PropertyDeclarationBlock::with_one( 1013 value.uncompute(), 1014 Importance::Normal, 1015 )), 1016 ) 1017 .into() 1018 } 1019 1020 ipdl_utils::define_ffi_serializer!( 1021 computed::LengthPercentage, 1022 Servo_LengthPercentage_Serialize, 1023 Servo_LengthPercentage_Deserialize 1024 ); 1025 1026 ipdl_utils::define_ffi_serializer!( 1027 computed::transform::Rotate, 1028 Servo_StyleRotate_Serialize, 1029 Servo_StyleRotate_Deserialize 1030 ); 1031 1032 ipdl_utils::define_ffi_serializer!( 1033 computed::transform::Scale, 1034 Servo_StyleScale_Serialize, 1035 Servo_StyleScale_Deserialize 1036 ); 1037 1038 ipdl_utils::define_ffi_serializer!( 1039 computed::transform::Translate, 1040 Servo_StyleTranslate_Serialize, 1041 Servo_StyleTranslate_Deserialize 1042 ); 1043 1044 ipdl_utils::define_ffi_serializer!( 1045 computed::transform::Transform, 1046 Servo_StyleTransform_Serialize, 1047 Servo_StyleTransform_Deserialize 1048 ); 1049 1050 ipdl_utils::define_ffi_serializer!( 1051 computed::motion::OffsetPath, 1052 Servo_StyleOffsetPath_Serialize, 1053 Servo_StyleOffsetPath_Deserialize 1054 ); 1055 1056 ipdl_utils::define_ffi_serializer!( 1057 computed::motion::OffsetRotate, 1058 Servo_StyleOffsetRotate_Serialize, 1059 Servo_StyleOffsetRotate_Deserialize 1060 ); 1061 1062 ipdl_utils::define_ffi_serializer!( 1063 computed::position::PositionOrAuto, 1064 Servo_StylePositionOrAuto_Serialize, 1065 Servo_StylePositionOrAuto_Deserialize 1066 ); 1067 1068 ipdl_utils::define_ffi_serializer!( 1069 computed::motion::OffsetPosition, 1070 Servo_StyleOffsetPosition_Serialize, 1071 Servo_StyleOffsetPosition_Deserialize 1072 ); 1073 1074 ipdl_utils::define_ffi_serializer!( 1075 ComputedTimingFunction, 1076 Servo_StyleComputedTimingFunction_Serialize, 1077 Servo_StyleComputedTimingFunction_Deserialize 1078 ); 1079 1080 // Return the ComputedValues by a base ComputedValues and the rules. 1081 fn resolve_rules_for_element_with_context<'a>( 1082 element: GeckoElement<'a>, 1083 mut context: StyleContext<GeckoElement<'a>>, 1084 rules: StrongRuleNode, 1085 original_computed_values: &ComputedValues, 1086 ) -> Arc<ComputedValues> { 1087 use style::style_resolver::{PseudoElementResolution, StyleResolverForElement}; 1088 1089 // This currently ignores visited styles, which seems acceptable, as 1090 // existing browsers don't appear to animate visited styles. 1091 let inputs = CascadeInputs { 1092 rules: Some(rules), 1093 visited_rules: None, 1094 flags: original_computed_values.flags.for_cascade_inputs(), 1095 }; 1096 1097 // Actually `PseudoElementResolution` doesn't matter. 1098 let mut resolver = StyleResolverForElement::new( 1099 element, 1100 &mut context, 1101 RuleInclusion::All, 1102 PseudoElementResolution::IfApplicable, 1103 ); 1104 resolver 1105 .cascade_style_and_visited_with_default_parents(inputs) 1106 .0 1107 } 1108 1109 #[no_mangle] 1110 pub extern "C" fn Servo_AnimationValueMap_Create() -> *mut AnimationValueMap { 1111 Box::into_raw(Box::default()) 1112 } 1113 1114 #[no_mangle] 1115 pub unsafe extern "C" fn Servo_AnimationValueMap_Drop(value_map: *mut AnimationValueMap) { 1116 let _ = Box::from_raw(value_map); 1117 } 1118 1119 #[no_mangle] 1120 pub extern "C" fn Servo_AnimationValueMap_GetValue( 1121 value_map: &AnimationValueMap, 1122 property_id: &structs::CSSPropertyId, 1123 ) -> Strong<AnimationValue> { 1124 let property = match OwnedPropertyDeclarationId::from_gecko_css_property_id(property_id) { 1125 Some(property) => property, 1126 None => return Strong::null(), 1127 }; 1128 value_map 1129 .get(&property) 1130 .map_or(Strong::null(), |value| Arc::new(value.clone()).into()) 1131 } 1132 1133 #[no_mangle] 1134 pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement( 1135 raw_style_set: &PerDocumentStyleData, 1136 element: &RawGeckoElement, 1137 computed_values: &ComputedValues, 1138 snapshots: *const ServoElementSnapshotTable, 1139 ) -> Strong<ComputedValues> { 1140 debug_assert!(!snapshots.is_null()); 1141 let computed_values = unsafe { ArcBorrow::from_ref(computed_values) }; 1142 1143 let rules = match computed_values.rules { 1144 None => return computed_values.clone_arc().into(), 1145 Some(ref rules) => rules, 1146 }; 1147 1148 let doc_data = raw_style_set.borrow(); 1149 let without_animations_rules = doc_data.stylist.rule_tree().remove_animation_rules(rules); 1150 if without_animations_rules == *rules { 1151 return computed_values.clone_arc().into(); 1152 } 1153 1154 let element = GeckoElement(element); 1155 1156 let global_style_data = &*GLOBAL_STYLE_DATA; 1157 let guard = global_style_data.shared_lock.read(); 1158 let shared = create_shared_context( 1159 &global_style_data, 1160 &guard, 1161 &doc_data.stylist, 1162 TraversalFlags::empty(), 1163 unsafe { &*snapshots }, 1164 ); 1165 let mut tlc = ThreadLocalStyleContext::new(); 1166 let context = StyleContext { 1167 shared: &shared, 1168 thread_local: &mut tlc, 1169 }; 1170 1171 resolve_rules_for_element_with_context( 1172 element, 1173 context, 1174 without_animations_rules, 1175 &computed_values, 1176 ) 1177 .into() 1178 } 1179 1180 #[repr(C)] 1181 #[derive(Default)] 1182 pub struct ShouldTransitionResult { 1183 should_animate: bool, 1184 old_transition_value_matches: bool, 1185 } 1186 1187 #[inline] 1188 fn is_transitionable(prop: PropertyDeclarationId, behavior: computed::TransitionBehavior) -> bool { 1189 if !prop.is_animatable() { 1190 return false; 1191 } 1192 // TODO(bug 1885995): Return `false` in is_discrete_animatable for interpolatable custom 1193 // property types. 1194 if matches!(prop, PropertyDeclarationId::Custom(..)) { 1195 return true; 1196 } 1197 1198 match behavior { 1199 computed::TransitionBehavior::Normal => !prop.is_discrete_animatable(), 1200 // If transition-behavior is allow-discrete, transitionable is the same as animatable. 1201 computed::TransitionBehavior::AllowDiscrete => true, 1202 } 1203 } 1204 1205 // Note: |new| is the after-change style; however, |old| is the computed values as of the previous 1206 // style change event, and it includes the running transitions and animations. 1207 #[no_mangle] 1208 pub extern "C" fn Servo_ComputedValues_ShouldTransition( 1209 old: &ComputedValues, 1210 new: &ComputedValues, 1211 prop: &structs::CSSPropertyId, 1212 behavior: computed::TransitionBehavior, 1213 old_transition_end_value: Option<&AnimationValue>, 1214 current_start_value: Option<&AnimationValue>, 1215 current_end_value: Option<&AnimationValue>, 1216 progress: Option<&f64>, 1217 start: &mut structs::RefPtr<AnimationValue>, 1218 end: &mut structs::RefPtr<AnimationValue>, 1219 ) -> ShouldTransitionResult { 1220 let Some(prop) = OwnedPropertyDeclarationId::from_gecko_css_property_id(prop) else { 1221 return Default::default(); 1222 }; 1223 let prop = prop.as_borrowed(); 1224 if !is_transitionable(prop, behavior) { 1225 return Default::default(); 1226 } 1227 1228 let Some(new_value) = AnimationValue::from_computed_values(prop, new) else { 1229 return Default::default(); 1230 }; 1231 1232 // If the element has a running transition for the property, there is a matching 1233 // transition-property value, and the end value of the running transition is not equal to the 1234 // value of the property in the after-change style. 1235 if let Some(old_transition_end_value) = old_transition_end_value { 1236 if *old_transition_end_value == new_value { 1237 return ShouldTransitionResult { 1238 should_animate: false, 1239 old_transition_value_matches: true, 1240 }; 1241 } 1242 } 1243 1244 let Some(old_value) = AnimationValue::from_computed_values(prop, old) else { 1245 return Default::default(); 1246 }; 1247 1248 // For main thread animations, it's fine to use |old_value| because it represents the value in 1249 // before-change style [1] if not transitions and animations, or the current value [2] if it 1250 // has a running transition. 1251 // 1252 // If this property is replacing a running or pending transition, we might want to compute a 1253 // more accurate current value, to make sure the check of `current_or_old_value == new_value` 1254 // below makes sense. |old_value| might be stale, even being the initial value of the 1255 // transition (if we've throttled the animation on the main thread, due to it being off-screen, 1256 // or a compositor animation). This prevents us from creating a reversing transition 1257 // incorrectly. 1258 // 1259 // [1] https://drafts.csswg.org/css-transitions-1/#before-change-style 1260 // [2] https://drafts.csswg.org/css-transitions-1/#current-value 1261 let current_value = match (current_start_value, current_end_value, progress) { 1262 (Some(from), Some(to), Some(p)) => { 1263 // Compute the current value for the compositor animations. 1264 from.animate(to, Procedure::Interpolate { progress: *p }) 1265 .ok() 1266 }, 1267 _ => None, 1268 }; 1269 1270 // Per spec (https://drafts.csswg.org/css-transitions-1/#starting): 1271 // 1. If the element does not have a running transition for the property, we have to check if 1272 // the before-change style is different from the after-change style for that property, and 1273 // if the values for the property are transitionable. 1274 // ... 1275 // 4. If the element has a running transition for the property, there is a matching 1276 // transition-property value, and the end value is not equal to the value of the property 1277 // in the after-change style. Also, if the **current value** of the property in the 1278 // running transition is equal to the value of the property in the after-change style, or 1279 // if these two values are not transitionable. In this case, we don't create new transition 1280 // and we will cancel the running transition. 1281 let current_or_old_value = current_value.unwrap_or(old_value); 1282 if current_or_old_value == new_value 1283 || matches!(behavior, computed::TransitionBehavior::Normal if !current_or_old_value.interpolable_with(&new_value)) 1284 { 1285 return Default::default(); 1286 } 1287 1288 start.set_arc(Arc::new(current_or_old_value)); 1289 end.set_arc(Arc::new(new_value)); 1290 1291 ShouldTransitionResult { 1292 should_animate: true, 1293 old_transition_value_matches: false, 1294 } 1295 } 1296 1297 #[no_mangle] 1298 pub extern "C" fn Servo_ComputedValues_TransitionValueMatches( 1299 style: &ComputedValues, 1300 prop: &structs::CSSPropertyId, 1301 transition_value: &AnimationValue, 1302 ) -> bool { 1303 let Some(prop) = OwnedPropertyDeclarationId::from_gecko_css_property_id(prop) else { 1304 return false; 1305 }; 1306 // Note: the running transitions should be transitionable, so it is always allow-discrete. 1307 let prop = prop.as_borrowed(); 1308 if !is_transitionable(prop, computed::TransitionBehavior::AllowDiscrete) { 1309 return false; 1310 } 1311 let Some(value) = AnimationValue::from_computed_values(prop, style) else { 1312 return false; 1313 }; 1314 value == *transition_value 1315 } 1316 1317 #[no_mangle] 1318 pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue( 1319 computed_values: &ComputedValues, 1320 property_id: &structs::CSSPropertyId, 1321 ) -> Strong<AnimationValue> { 1322 let property = match OwnedPropertyDeclarationId::from_gecko_css_property_id(property_id) { 1323 Some(property) => property, 1324 None => return Strong::null(), 1325 }; 1326 match AnimationValue::from_computed_values(property.as_borrowed(), &computed_values) { 1327 Some(v) => Arc::new(v).into(), 1328 None => Strong::null(), 1329 } 1330 } 1331 1332 #[no_mangle] 1333 pub extern "C" fn Servo_ResolveLogicalProperty( 1334 property_id: NonCustomCSSPropertyId, 1335 style: &ComputedValues, 1336 ) -> NonCustomCSSPropertyId { 1337 let longhand = LonghandId::from_noncustomcsspropertyid(property_id) 1338 .expect("We shouldn't need to care about shorthands"); 1339 1340 longhand 1341 .to_physical(style.writing_mode) 1342 .to_noncustomcsspropertyid() 1343 } 1344 1345 #[no_mangle] 1346 pub unsafe extern "C" fn Servo_Property_LookupEnabledForAllContent( 1347 prop: &nsACString, 1348 ) -> NonCustomCSSPropertyId { 1349 match PropertyId::parse_enabled_for_all_content(prop.as_str_unchecked()) { 1350 Ok(p) => p.to_noncustomcsspropertyid_resolving_aliases(), 1351 Err(..) => NonCustomCSSPropertyId::eCSSProperty_UNKNOWN, 1352 } 1353 } 1354 1355 #[no_mangle] 1356 pub unsafe extern "C" fn Servo_Property_GetName( 1357 prop: NonCustomCSSPropertyId, 1358 out_length: *mut u32, 1359 ) -> *const u8 { 1360 let (ptr, len) = match NonCustomPropertyId::from_noncustomcsspropertyid(prop) { 1361 Some(p) => { 1362 let name = p.name(); 1363 (name.as_bytes().as_ptr(), name.len()) 1364 }, 1365 None => (ptr::null(), 0), 1366 }; 1367 1368 *out_length = len as u32; 1369 ptr 1370 } 1371 1372 macro_rules! parse_enabled_property_name { 1373 ($prop_name:ident, $found:ident, $default:expr) => {{ 1374 let prop_name = $prop_name.as_str_unchecked(); 1375 match PropertyId::parse_enabled_for_all_content(prop_name) { 1376 Ok(p) => { 1377 *$found = true; 1378 p 1379 }, 1380 Err(..) => { 1381 *$found = false; 1382 return $default; 1383 }, 1384 } 1385 }}; 1386 } 1387 1388 #[no_mangle] 1389 pub unsafe extern "C" fn Servo_Property_IsShorthand( 1390 prop_name: &nsACString, 1391 found: *mut bool, 1392 ) -> bool { 1393 let prop_id = parse_enabled_property_name!(prop_name, found, false); 1394 prop_id.is_shorthand() 1395 } 1396 1397 #[no_mangle] 1398 pub unsafe extern "C" fn Servo_Property_IsInherited( 1399 per_doc_data: &PerDocumentStyleData, 1400 prop_name: &nsACString, 1401 ) -> bool { 1402 let prop_name = prop_name.as_str_unchecked(); 1403 let prop_id = match PropertyId::parse_enabled_for_all_content(prop_name) { 1404 Ok(id) => id, 1405 Err(_) => return false, 1406 }; 1407 let longhand_id = match prop_id { 1408 PropertyId::Custom(property_name) => { 1409 let stylist = &per_doc_data.borrow().stylist; 1410 return stylist 1411 .get_custom_property_registration(&property_name) 1412 .inherits(); 1413 }, 1414 PropertyId::NonCustom(id) => match id.longhand_or_shorthand() { 1415 Ok(lh) => lh, 1416 Err(sh) => sh.longhands().next().unwrap(), 1417 }, 1418 }; 1419 longhand_id.inherited() 1420 } 1421 1422 #[no_mangle] 1423 pub unsafe extern "C" fn Servo_Property_SupportsType( 1424 prop_name: &nsACString, 1425 ty: u8, 1426 found: *mut bool, 1427 ) -> bool { 1428 let prop_id = parse_enabled_property_name!(prop_name, found, false); 1429 prop_id.supports_type(ty) 1430 } 1431 1432 #[no_mangle] 1433 pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty( 1434 prop_name: &nsACString, 1435 found: *mut bool, 1436 result: &mut nsTArray<nsString>, 1437 ) { 1438 let prop_id = parse_enabled_property_name!(prop_name, found, ()); 1439 // Use B-tree set for unique and sorted result. 1440 let mut values = BTreeSet::<&'static str>::new(); 1441 prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter())); 1442 1443 if values.contains("transparent") { 1444 // This is a special value devtools use to avoid inserting the 1445 // long list of color keywords. We need to prepend it to values. 1446 result.push("COLOR".into()); 1447 } 1448 1449 for value in values { 1450 result.push(value.into()); 1451 } 1452 } 1453 1454 #[no_mangle] 1455 pub extern "C" fn Servo_Property_IsAnimatable(prop: &structs::CSSPropertyId) -> bool { 1456 PropertyId::from_gecko_css_property_id(prop).map_or(false, |p| p.is_animatable()) 1457 } 1458 1459 #[no_mangle] 1460 pub extern "C" fn Servo_Property_IsDiscreteAnimatable(property: NonCustomCSSPropertyId) -> bool { 1461 match LonghandId::from_noncustomcsspropertyid(property) { 1462 Some(longhand) => longhand.is_discrete_animatable(), 1463 None => return false, 1464 } 1465 } 1466 1467 #[no_mangle] 1468 pub extern "C" fn Servo_Element_ClearData(element: &RawGeckoElement) { 1469 unsafe { GeckoElement(element).clear_data() }; 1470 } 1471 1472 #[no_mangle] 1473 pub extern "C" fn Servo_Element_SizeOfExcludingThisAndCVs( 1474 malloc_size_of: GeckoMallocSizeOf, 1475 malloc_enclosing_size_of: GeckoMallocSizeOf, 1476 seen_ptrs: *mut SeenPtrs, 1477 element: &RawGeckoElement, 1478 ) -> usize { 1479 let element = GeckoElement(element); 1480 let borrow = element.borrow_data(); 1481 if let Some(data) = borrow { 1482 let have_seen_ptr = move |ptr| unsafe { Gecko_HaveSeenPtr(seen_ptrs, ptr) }; 1483 let mut ops = MallocSizeOfOps::new( 1484 malloc_size_of.unwrap(), 1485 Some(malloc_enclosing_size_of.unwrap()), 1486 Some(Box::new(have_seen_ptr)), 1487 ); 1488 (*data).size_of_excluding_cvs(&mut ops) 1489 } else { 1490 0 1491 } 1492 } 1493 1494 #[no_mangle] 1495 pub extern "C" fn Servo_Element_GetMaybeOutOfDateStyle( 1496 element: &RawGeckoElement, 1497 ) -> *const ComputedValues { 1498 let element = GeckoElement(element); 1499 let data = match element.borrow_data() { 1500 Some(d) => d, 1501 None => return ptr::null(), 1502 }; 1503 &**data.styles.primary() as *const _ 1504 } 1505 1506 #[no_mangle] 1507 pub extern "C" fn Servo_Element_GetMaybeOutOfDatePseudoStyle( 1508 element: &RawGeckoElement, 1509 index: usize, 1510 ) -> *const ComputedValues { 1511 let element = GeckoElement(element); 1512 let data = match element.borrow_data() { 1513 Some(d) => d, 1514 None => return ptr::null(), 1515 }; 1516 match data.styles.pseudos.as_array()[index].as_ref() { 1517 Some(style) => &**style as *const _, 1518 None => ptr::null(), 1519 } 1520 } 1521 1522 // Some functions are so hot and main-thread-only that we have to bypass the AtomicRefCell. 1523 // 1524 // It would be nice to also assert that we're not in the servo traversal, but this function is 1525 // called at various intermediate checkpoints when managing the traversal on the Gecko side. 1526 #[cfg(debug_assertions)] 1527 unsafe fn borrow_assert_main_thread<T>( 1528 cell: &atomic_refcell::AtomicRefCell<T>, 1529 ) -> atomic_refcell::AtomicRef<'_, T> { 1530 debug_assert!(is_main_thread()); 1531 cell.borrow() 1532 } 1533 1534 #[cfg(not(debug_assertions))] 1535 unsafe fn borrow_assert_main_thread<T>(cell: &atomic_refcell::AtomicRefCell<T>) -> &T { 1536 unsafe { &*cell.as_ptr() } 1537 } 1538 1539 #[no_mangle] 1540 pub extern "C" fn Servo_Element_IsDisplayNone(element: &RawGeckoElement) -> bool { 1541 let element = GeckoElement(element); 1542 let data = element 1543 .get_data() 1544 .expect("Invoking Servo_Element_IsDisplayNone on unstyled element"); 1545 1546 let is_display_none = unsafe { borrow_assert_main_thread(data) } 1547 .styles 1548 .is_display_none(); 1549 is_display_none 1550 } 1551 1552 #[no_mangle] 1553 pub extern "C" fn Servo_Element_IsDisplayContents(element: &RawGeckoElement) -> bool { 1554 let element = GeckoElement(element); 1555 let data = element 1556 .get_data() 1557 .expect("Invoking Servo_Element_IsDisplayContents on unstyled element"); 1558 1559 let is_display_contents = unsafe { borrow_assert_main_thread(data) } 1560 .styles 1561 .primary() 1562 .get_box() 1563 .clone_display() 1564 .is_contents(); 1565 is_display_contents 1566 } 1567 1568 #[no_mangle] 1569 pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGeckoElement) -> bool { 1570 let element = GeckoElement(element); 1571 let data = element 1572 .borrow_data() 1573 .expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element"); 1574 data.flags 1575 .contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE) 1576 } 1577 1578 #[no_mangle] 1579 pub extern "C" fn Servo_Element_MayHaveStartingStyle(element: &RawGeckoElement) -> bool { 1580 let element = GeckoElement(element); 1581 let data = match element.borrow_data() { 1582 Some(d) => d, 1583 None => return false, 1584 }; 1585 data.flags 1586 .contains(data::ElementDataFlags::MAY_HAVE_STARTING_STYLE) 1587 } 1588 1589 fn mode_to_origin(mode: SheetParsingMode) -> Origin { 1590 match mode { 1591 SheetParsingMode::eAuthorSheetFeatures => Origin::Author, 1592 SheetParsingMode::eUserSheetFeatures => Origin::User, 1593 SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent, 1594 } 1595 } 1596 1597 #[no_mangle] 1598 pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> Strong<StylesheetContents> { 1599 let global_style_data = &*GLOBAL_STYLE_DATA; 1600 let origin = mode_to_origin(mode); 1601 let shared_lock = &global_style_data.shared_lock; 1602 StylesheetContents::from_str( 1603 "", 1604 unsafe { dummy_url_data() }.clone(), 1605 origin, 1606 shared_lock, 1607 /* loader = */ None, 1608 None, 1609 QuirksMode::NoQuirks, 1610 AllowImportRules::Yes, 1611 /* sanitization_data = */ None, 1612 ) 1613 .into() 1614 } 1615 1616 /// Note: The load_data corresponds to this sheet, and is passed as the parent 1617 /// load data for child sheet loads. It may be null for certain cases where we 1618 /// know we won't have child loads. 1619 #[no_mangle] 1620 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8Bytes( 1621 loader: *mut Loader, 1622 stylesheet: *mut DomStyleSheet, 1623 load_data: *mut SheetLoadData, 1624 bytes: &nsACString, 1625 mode: SheetParsingMode, 1626 extra_data: *mut URLExtraData, 1627 quirks_mode: nsCompatibility, 1628 reusable_sheets: *mut LoaderReusableStyleSheets, 1629 allow_import_rules: AllowImportRules, 1630 sanitization_kind: SanitizationKind, 1631 sanitized_output: Option<&mut nsAString>, 1632 ) -> Strong<StylesheetContents> { 1633 let global_style_data = &*GLOBAL_STYLE_DATA; 1634 let input = bytes.as_str_unchecked(); 1635 1636 let reporter = ErrorReporter::new(stylesheet, loader, extra_data); 1637 let url_data = UrlExtraData::from_ptr_ref(&extra_data); 1638 let loader = if loader.is_null() { 1639 None 1640 } else { 1641 debug_assert!( 1642 sanitized_output.is_none(), 1643 "Shouldn't trigger @import loads for sanitization", 1644 ); 1645 Some(StylesheetLoader::new( 1646 loader, 1647 stylesheet, 1648 load_data, 1649 reusable_sheets, 1650 )) 1651 }; 1652 1653 // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason? 1654 let loader: Option<&dyn StyleStylesheetLoader> = match loader { 1655 None => None, 1656 Some(ref s) => Some(s), 1657 }; 1658 1659 let mut sanitization_data = SanitizationData::new(sanitization_kind); 1660 1661 let contents = StylesheetContents::from_str( 1662 input, 1663 url_data.clone(), 1664 mode_to_origin(mode), 1665 &global_style_data.shared_lock, 1666 loader, 1667 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter), 1668 quirks_mode.into(), 1669 allow_import_rules, 1670 sanitization_data.as_mut(), 1671 ); 1672 1673 if let Some(data) = sanitization_data { 1674 sanitized_output 1675 .unwrap() 1676 .assign_utf8(data.take().as_bytes()); 1677 } 1678 1679 contents.into() 1680 } 1681 1682 #[no_mangle] 1683 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync( 1684 load_data: *mut SheetLoadDataHolder, 1685 extra_data: *mut URLExtraData, 1686 bytes: &nsACString, 1687 mode: SheetParsingMode, 1688 quirks_mode: nsCompatibility, 1689 allow_import_rules: AllowImportRules, 1690 ) { 1691 let load_data = RefPtr::new(load_data); 1692 let extra_data = UrlExtraData::new(extra_data); 1693 1694 let mut sheet_bytes = nsCString::new(); 1695 sheet_bytes.assign(bytes); 1696 1697 let async_parser = AsyncStylesheetParser::new( 1698 load_data, 1699 extra_data, 1700 sheet_bytes, 1701 mode_to_origin(mode), 1702 quirks_mode.into(), 1703 allow_import_rules, 1704 ); 1705 1706 if let Some(thread_pool) = STYLE_THREAD_POOL.pool().as_ref() { 1707 thread_pool.spawn(|| { 1708 gecko_profiler_label!(Layout, CSSParsing); 1709 async_parser.parse(); 1710 }); 1711 } else { 1712 async_parser.parse(); 1713 } 1714 } 1715 1716 #[no_mangle] 1717 pub unsafe extern "C" fn Servo_ShutdownThreadPool() { 1718 debug_assert!(is_main_thread() && !is_in_servo_traversal()); 1719 StyleThreadPool::shutdown(); 1720 } 1721 1722 #[no_mangle] 1723 pub unsafe extern "C" fn Servo_ThreadPool_GetThreadHandles( 1724 handles: &mut nsTArray<PlatformThreadHandle>, 1725 ) { 1726 StyleThreadPool::get_thread_handles(handles); 1727 } 1728 1729 #[no_mangle] 1730 pub unsafe extern "C" fn Servo_StyleSheet_FromSharedData( 1731 extra_data: *mut URLExtraData, 1732 shared_rules: &LockedCssRules, 1733 ) -> Strong<StylesheetContents> { 1734 StylesheetContents::from_shared_data( 1735 Arc::from_raw_addrefed(shared_rules), 1736 Origin::UserAgent, 1737 UrlExtraData::new(extra_data), 1738 QuirksMode::NoQuirks, 1739 ) 1740 .into() 1741 } 1742 1743 #[no_mangle] 1744 pub extern "C" fn Servo_StyleSet_AppendStyleSheet( 1745 raw_data: &PerDocumentStyleData, 1746 sheet: *const DomStyleSheet, 1747 ) { 1748 let global_style_data = &*GLOBAL_STYLE_DATA; 1749 let mut data = raw_data.borrow_mut(); 1750 let data = &mut *data; 1751 let guard = global_style_data.shared_lock.read(); 1752 let sheet = unsafe { GeckoStyleSheet::new(sheet) }; 1753 data.stylist.append_stylesheet(sheet, &guard); 1754 } 1755 1756 #[no_mangle] 1757 pub extern "C" fn Servo_AuthorStyles_Create() -> *mut AuthorStyles { 1758 Box::into_raw(Box::new(AuthorStyles::new())) 1759 } 1760 1761 #[no_mangle] 1762 pub unsafe extern "C" fn Servo_AuthorStyles_Drop(styles: *mut AuthorStyles) { 1763 let _ = Box::from_raw(styles); 1764 } 1765 1766 #[no_mangle] 1767 pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet( 1768 styles: &mut AuthorStyles, 1769 sheet: *const DomStyleSheet, 1770 ) { 1771 let global_style_data = &*GLOBAL_STYLE_DATA; 1772 let guard = global_style_data.shared_lock.read(); 1773 let sheet = GeckoStyleSheet::new(sheet); 1774 styles 1775 .stylesheets 1776 .append_stylesheet(None, styles.data.custom_media_map(), sheet, &guard); 1777 } 1778 1779 #[no_mangle] 1780 pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore( 1781 styles: &mut AuthorStyles, 1782 sheet: *const DomStyleSheet, 1783 before_sheet: *const DomStyleSheet, 1784 ) { 1785 let global_style_data = &*GLOBAL_STYLE_DATA; 1786 let guard = global_style_data.shared_lock.read(); 1787 styles.stylesheets.insert_stylesheet_before( 1788 None, 1789 styles.data.custom_media_map(), 1790 GeckoStyleSheet::new(sheet), 1791 GeckoStyleSheet::new(before_sheet), 1792 &guard, 1793 ); 1794 } 1795 1796 #[no_mangle] 1797 pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet( 1798 styles: &mut AuthorStyles, 1799 sheet: *const DomStyleSheet, 1800 ) { 1801 let global_style_data = &*GLOBAL_STYLE_DATA; 1802 let guard = global_style_data.shared_lock.read(); 1803 styles.stylesheets.remove_stylesheet( 1804 None, 1805 styles.data.custom_media_map(), 1806 GeckoStyleSheet::new(sheet), 1807 &guard, 1808 ); 1809 } 1810 1811 #[no_mangle] 1812 pub extern "C" fn Servo_AuthorStyles_ForceDirty(styles: &mut AuthorStyles) { 1813 styles.stylesheets.force_dirty(); 1814 } 1815 1816 #[no_mangle] 1817 pub extern "C" fn Servo_AuthorStyles_IsDirty(styles: &AuthorStyles) -> bool { 1818 styles.stylesheets.dirty() 1819 } 1820 1821 #[no_mangle] 1822 pub unsafe extern "C" fn Servo_DeclarationBlock_SizeOfIncludingThis( 1823 malloc_size_of: GeckoMallocSizeOf, 1824 malloc_enclosing_size_of: GeckoMallocSizeOf, 1825 declarations: &LockedDeclarationBlock, 1826 ) -> usize { 1827 use malloc_size_of::MallocSizeOf; 1828 use malloc_size_of::MallocUnconditionalShallowSizeOf; 1829 1830 let global_style_data = &*GLOBAL_STYLE_DATA; 1831 let guard = global_style_data.shared_lock.read(); 1832 1833 let mut ops = MallocSizeOfOps::new( 1834 malloc_size_of.unwrap(), 1835 Some(malloc_enclosing_size_of.unwrap()), 1836 None, 1837 ); 1838 1839 ArcBorrow::from_ref(declarations).with_arc(|declarations| { 1840 let mut n = 0; 1841 n += declarations.unconditional_shallow_size_of(&mut ops); 1842 n += declarations.read_with(&guard).size_of(&mut ops); 1843 n 1844 }) 1845 } 1846 1847 #[no_mangle] 1848 pub unsafe extern "C" fn Servo_AuthorStyles_SizeOfIncludingThis( 1849 malloc_size_of: GeckoMallocSizeOf, 1850 malloc_enclosing_size_of: GeckoMallocSizeOf, 1851 styles: &AuthorStyles, 1852 ) -> usize { 1853 // We cannot `use` MallocSizeOf at the top level, otherwise the compiler 1854 // would complain in `Servo_StyleSheet_SizeOfIncludingThis` for `size_of` 1855 // there. 1856 use malloc_size_of::MallocSizeOf; 1857 let malloc_size_of = malloc_size_of.unwrap(); 1858 let malloc_size_of_this = malloc_size_of(styles as *const AuthorStyles as *const c_void); 1859 1860 let mut ops = MallocSizeOfOps::new( 1861 malloc_size_of, 1862 Some(malloc_enclosing_size_of.unwrap()), 1863 None, 1864 ); 1865 malloc_size_of_this + styles.size_of(&mut ops) 1866 } 1867 1868 #[no_mangle] 1869 pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged( 1870 document_set: &PerDocumentStyleData, 1871 non_document_styles: &mut nsTArray<&mut AuthorStyles>, 1872 may_affect_default_style: bool, 1873 ) -> structs::MediumFeaturesChangedResult { 1874 let global_style_data = &*GLOBAL_STYLE_DATA; 1875 let guard = global_style_data.shared_lock.read(); 1876 1877 // NOTE(emilio): We don't actually need to flush the stylist here and ensure 1878 // it's up to date. 1879 // 1880 // In case it isn't we would trigger a rebuild + restyle as needed too. 1881 // 1882 // We need to ensure the default computed values are up to date though, 1883 // because those can influence the result of media query evaluation. 1884 let mut document_data = document_set.borrow_mut(); 1885 1886 if may_affect_default_style { 1887 document_data.stylist.device_mut().reset_computed_values(); 1888 } 1889 let guards = StylesheetGuards::same(&guard); 1890 1891 let origins_in_which_rules_changed = document_data 1892 .stylist 1893 .media_features_change_changed_style(&guards, document_data.stylist.device()); 1894 1895 let affects_document_rules = !origins_in_which_rules_changed.is_empty(); 1896 if affects_document_rules { 1897 document_data 1898 .stylist 1899 .force_stylesheet_origins_dirty(origins_in_which_rules_changed); 1900 } 1901 1902 let mut affects_non_document_rules = false; 1903 for author_styles in &mut **non_document_styles { 1904 let affected_style = author_styles.stylesheets.iter().any(|sheet| { 1905 !author_styles.data.media_feature_affected_matches( 1906 sheet, 1907 &guards.author, 1908 document_data.stylist.device(), 1909 document_data.stylist.quirks_mode(), 1910 ) 1911 }); 1912 if affected_style { 1913 affects_non_document_rules = true; 1914 author_styles.stylesheets.force_dirty(); 1915 } 1916 } 1917 1918 structs::MediumFeaturesChangedResult { 1919 mAffectsDocumentRules: affects_document_rules, 1920 mAffectsNonDocumentRules: affects_non_document_rules, 1921 } 1922 } 1923 1924 #[no_mangle] 1925 pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore( 1926 raw_data: &PerDocumentStyleData, 1927 sheet: *const DomStyleSheet, 1928 before_sheet: *const DomStyleSheet, 1929 ) { 1930 let global_style_data = &*GLOBAL_STYLE_DATA; 1931 let mut data = raw_data.borrow_mut(); 1932 let data = &mut *data; 1933 let guard = global_style_data.shared_lock.read(); 1934 let sheet = unsafe { GeckoStyleSheet::new(sheet) }; 1935 data.stylist.insert_stylesheet_before( 1936 sheet, 1937 unsafe { GeckoStyleSheet::new(before_sheet) }, 1938 &guard, 1939 ); 1940 } 1941 1942 #[no_mangle] 1943 pub extern "C" fn Servo_StyleSet_RemoveStyleSheet( 1944 raw_data: &PerDocumentStyleData, 1945 sheet: *const DomStyleSheet, 1946 ) { 1947 let global_style_data = &*GLOBAL_STYLE_DATA; 1948 let mut data = raw_data.borrow_mut(); 1949 let data = &mut *data; 1950 let guard = global_style_data.shared_lock.read(); 1951 let sheet = unsafe { GeckoStyleSheet::new(sheet) }; 1952 data.stylist.remove_stylesheet(sheet, &guard); 1953 } 1954 1955 #[no_mangle] 1956 pub unsafe extern "C" fn Servo_StyleSet_GetSheetAt( 1957 raw_data: &PerDocumentStyleData, 1958 origin: Origin, 1959 index: usize, 1960 ) -> *const DomStyleSheet { 1961 let data = raw_data.borrow(); 1962 data.stylist 1963 .sheet_at(origin, index) 1964 .map_or(ptr::null(), |s| s.raw()) 1965 } 1966 1967 #[no_mangle] 1968 pub unsafe extern "C" fn Servo_StyleSet_GetSheetCount( 1969 raw_data: &PerDocumentStyleData, 1970 origin: Origin, 1971 ) -> usize { 1972 let data = raw_data.borrow(); 1973 data.stylist.sheet_count(origin) 1974 } 1975 1976 #[no_mangle] 1977 pub unsafe extern "C" fn Servo_StyleSet_FlushStyleSheets( 1978 raw_data: &PerDocumentStyleData, 1979 doc_element: Option<&RawGeckoElement>, 1980 snapshots: *const ServoElementSnapshotTable, 1981 non_document_styles: &mut nsTArray<&mut AuthorStyles>, 1982 ) { 1983 let global_style_data = &*GLOBAL_STYLE_DATA; 1984 let guard = global_style_data.shared_lock.read(); 1985 let mut data = raw_data.borrow_mut(); 1986 let doc_element = doc_element.map(GeckoElement); 1987 1988 let mut invalidations = data.flush_stylesheets(&guard); 1989 if !non_document_styles.is_empty() { 1990 for author_styles in non_document_styles { 1991 let shadow_invalidations = author_styles.flush(&mut data.stylist, &guard); 1992 // TODO(emilio): For now we drop the style invalidations on the floor, relying on 1993 // explicit invalidation from C++. 1994 // TODO(emilio): Consider doing scoped cascade data invalidation, specially once we 1995 // have tree-scoped names. 1996 invalidations 1997 .cascade_data_difference 1998 .merge_with(shadow_invalidations.cascade_data_difference); 1999 } 2000 data.stylist.remove_unique_author_data_cache_entries(); 2001 } 2002 2003 // TODO(emilio): consider merging the existing stylesheet invalidation machinery into the 2004 // `CascadeDataDifference`. 2005 let Some(doc_element) = doc_element else { 2006 return; 2007 }; 2008 if invalidations.process_style(doc_element, snapshots.as_ref()) { 2009 // The style invalidation machinery propagates the bits up, but we still need to tell the 2010 // Gecko restyle root machinery about it. 2011 bindings::Gecko_NoteDirtySubtreeForInvalidation(doc_element.0); 2012 } 2013 let changed_position_try_names = &invalidations 2014 .cascade_data_difference 2015 .changed_position_try_names; 2016 if !changed_position_try_names.is_empty() { 2017 style::invalidation::stylesheets::invalidate_position_try( 2018 doc_element, 2019 &changed_position_try_names, 2020 &mut |e, _data| unsafe { 2021 bindings::Gecko_InvalidatePositionTry(e.0); 2022 }, 2023 &mut |_| {}, 2024 ); 2025 } 2026 } 2027 2028 #[no_mangle] 2029 pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged( 2030 raw_data: &PerDocumentStyleData, 2031 changed_origins: OriginFlags, 2032 ) { 2033 let mut data = raw_data.borrow_mut(); 2034 data.stylist 2035 .force_stylesheet_origins_dirty(OriginSet::from(changed_origins)); 2036 } 2037 2038 #[no_mangle] 2039 pub extern "C" fn Servo_StyleSet_SetAuthorStyleDisabled( 2040 raw_data: &PerDocumentStyleData, 2041 author_style_disabled: bool, 2042 ) { 2043 let mut data = raw_data.borrow_mut(); 2044 let enabled = if author_style_disabled { 2045 AuthorStylesEnabled::No 2046 } else { 2047 AuthorStylesEnabled::Yes 2048 }; 2049 data.stylist.set_author_styles_enabled(enabled); 2050 } 2051 2052 #[no_mangle] 2053 pub extern "C" fn Servo_StyleSet_UsesFontMetrics(raw_data: &PerDocumentStyleData) -> bool { 2054 let doc_data = raw_data; 2055 doc_data.borrow().stylist.device().used_font_metrics() 2056 } 2057 2058 #[no_mangle] 2059 pub extern "C" fn Servo_StyleSet_UsesRootFontMetrics(raw_data: &PerDocumentStyleData) -> bool { 2060 let doc_data = raw_data; 2061 doc_data.borrow().stylist.device().used_root_font_metrics() 2062 } 2063 2064 #[no_mangle] 2065 pub extern "C" fn Servo_StyleSheet_HasRules(raw_contents: &StylesheetContents) -> bool { 2066 let global_style_data = &*GLOBAL_STYLE_DATA; 2067 let guard = global_style_data.shared_lock.read(); 2068 !raw_contents.rules.read_with(&guard).0.is_empty() 2069 } 2070 2071 #[no_mangle] 2072 pub extern "C" fn Servo_StyleSheet_UseCounters(raw_contents: &StylesheetContents) -> &UseCounters { 2073 &raw_contents.use_counters 2074 } 2075 2076 #[no_mangle] 2077 pub extern "C" fn Servo_StyleSheet_GetRules(sheet: &StylesheetContents) -> Strong<LockedCssRules> { 2078 sheet.rules.clone().into() 2079 } 2080 2081 #[no_mangle] 2082 pub extern "C" fn Servo_StyleSheet_Clone( 2083 contents: &StylesheetContents, 2084 data: *mut URLExtraData, 2085 ) -> Strong<StylesheetContents> { 2086 let global_style_data = &*GLOBAL_STYLE_DATA; 2087 let guard = global_style_data.shared_lock.read(); 2088 let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) }; 2089 contents 2090 .deep_clone(&global_style_data.shared_lock, Some(url_data), &guard) 2091 .into() 2092 } 2093 2094 #[no_mangle] 2095 pub extern "C" fn Servo_StyleSheet_SizeOfIncludingThis( 2096 malloc_size_of: GeckoMallocSizeOf, 2097 malloc_enclosing_size_of: GeckoMallocSizeOf, 2098 sheet: &StylesheetContents, 2099 ) -> usize { 2100 let global_style_data = &*GLOBAL_STYLE_DATA; 2101 let guard = global_style_data.shared_lock.read(); 2102 let mut ops = MallocSizeOfOps::new( 2103 malloc_size_of.unwrap(), 2104 Some(malloc_enclosing_size_of.unwrap()), 2105 None, 2106 ); 2107 // TODO(emilio): We're not measuring the size of the Arc<StylesheetContents> 2108 // allocation itself here. 2109 sheet.size_of(&guard, &mut ops) 2110 } 2111 2112 #[no_mangle] 2113 pub extern "C" fn Servo_StyleSheet_GetOrigin(sheet: &StylesheetContents) -> Origin { 2114 sheet.origin 2115 } 2116 2117 #[no_mangle] 2118 pub extern "C" fn Servo_StyleSheet_GetSourceMapURL( 2119 contents: &StylesheetContents, 2120 result: &mut nsACString, 2121 ) { 2122 if let Some(ref url) = contents.source_map_url { 2123 result.assign(url); 2124 } 2125 } 2126 2127 #[no_mangle] 2128 pub extern "C" fn Servo_StyleSheet_GetSourceURL( 2129 contents: &StylesheetContents, 2130 result: &mut nsACString, 2131 ) { 2132 if let Some(ref url) = contents.source_url { 2133 result.assign(url); 2134 } 2135 } 2136 2137 fn with_maybe_worker_shared_lock<R>(func: impl FnOnce(&SharedRwLock) -> R) -> R { 2138 if is_dom_worker_thread() { 2139 DOM_WORKER_RWLOCK.with(func) 2140 } else { 2141 func(&GLOBAL_STYLE_DATA.shared_lock) 2142 } 2143 } 2144 2145 fn read_locked_arc<T, R, F>(raw: &Locked<T>, func: F) -> R 2146 where 2147 F: FnOnce(&T) -> R, 2148 { 2149 debug_assert!(!is_dom_worker_thread()); 2150 let global_style_data = &*GLOBAL_STYLE_DATA; 2151 let guard = global_style_data.shared_lock.read(); 2152 func(raw.read_with(&guard)) 2153 } 2154 2155 fn read_locked_arc_worker<T, R, F>(raw: &Locked<T>, func: F) -> R 2156 where 2157 F: FnOnce(&T) -> R, 2158 { 2159 with_maybe_worker_shared_lock(|lock| { 2160 let guard = lock.read(); 2161 func(raw.read_with(&guard)) 2162 }) 2163 } 2164 2165 #[cfg(debug_assertions)] 2166 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &Locked<T>, func: F) -> R 2167 where 2168 F: FnOnce(&T) -> R, 2169 { 2170 debug_assert!(is_main_thread() && !is_in_servo_traversal()); 2171 read_locked_arc(raw, func) 2172 } 2173 2174 #[cfg(not(debug_assertions))] 2175 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &Locked<T>, func: F) -> R 2176 where 2177 F: FnOnce(&T) -> R, 2178 { 2179 debug_assert!(!is_dom_worker_thread()); 2180 func(raw.read_unchecked()) 2181 } 2182 2183 fn write_locked_arc<T, R, F>(raw: &Locked<T>, func: F) -> R 2184 where 2185 F: FnOnce(&mut T) -> R, 2186 { 2187 debug_assert!(!is_dom_worker_thread()); 2188 let global_style_data = &*GLOBAL_STYLE_DATA; 2189 let mut guard = global_style_data.shared_lock.write(); 2190 func(raw.write_with(&mut guard)) 2191 } 2192 2193 fn write_locked_arc_worker<T, R, F>(raw: &Locked<T>, func: F) -> R 2194 where 2195 F: FnOnce(&mut T) -> R, 2196 { 2197 with_maybe_worker_shared_lock(|lock| { 2198 let mut guard = lock.write(); 2199 func(raw.write_with(&mut guard)) 2200 }) 2201 } 2202 2203 #[no_mangle] 2204 pub extern "C" fn Servo_CssRules_GetRuleCount(rules: &LockedCssRules) -> usize { 2205 read_locked_arc(rules, |rules| rules.0.len()) 2206 } 2207 2208 #[no_mangle] 2209 pub extern "C" fn Servo_CssRules_GetRuleTypeAt( 2210 rules: &LockedCssRules, 2211 index: usize, 2212 ) -> CssRuleType { 2213 read_locked_arc(rules, |rules| rules.0[index].rule_type()) 2214 } 2215 2216 #[no_mangle] 2217 pub extern "C" fn Servo_CssRules_ListTypes(rules: &LockedCssRules, result: &mut nsTArray<usize>) { 2218 read_locked_arc(rules, |rules: &CssRules| { 2219 result.extend(rules.0.iter().map(|rule| rule.rule_type() as usize)); 2220 }) 2221 } 2222 2223 #[no_mangle] 2224 pub extern "C" fn Servo_CssRules_InsertRule( 2225 rules: &LockedCssRules, 2226 contents: &StylesheetContents, 2227 rule: &nsACString, 2228 index: u32, 2229 containing_rule_types: u32, 2230 parse_relative_rule_type: Option<&CssRuleType>, 2231 loader: *mut Loader, 2232 allow_import_rules: AllowImportRules, 2233 gecko_stylesheet: *mut DomStyleSheet, 2234 rule_type: &mut CssRuleType, 2235 ) -> nsresult { 2236 let loader = if loader.is_null() { 2237 None 2238 } else { 2239 Some(StylesheetLoader::new( 2240 loader, 2241 gecko_stylesheet, 2242 ptr::null_mut(), 2243 ptr::null_mut(), 2244 )) 2245 }; 2246 let loader = loader 2247 .as_ref() 2248 .map(|loader| loader as &dyn StyleStylesheetLoader); 2249 let rule = unsafe { rule.as_str_unchecked() }; 2250 2251 let global_style_data = &*GLOBAL_STYLE_DATA; 2252 let index = index as usize; 2253 let new_rule = { 2254 let guard = global_style_data.shared_lock.read(); 2255 match rules.read_with(&guard).parse_rule_for_insert( 2256 &global_style_data.shared_lock, 2257 rule, 2258 contents, 2259 index, 2260 CssRuleTypes::from_bits(containing_rule_types), 2261 parse_relative_rule_type.cloned(), 2262 loader, 2263 allow_import_rules, 2264 ) { 2265 Ok(r) => r, 2266 Err(e) => return e.into(), 2267 } 2268 }; 2269 2270 let mut write_guard = global_style_data.shared_lock.write(); 2271 *rule_type = new_rule.rule_type(); 2272 rules.write_with(&mut write_guard).0.insert(index, new_rule); 2273 nsresult::NS_OK 2274 } 2275 2276 #[no_mangle] 2277 pub extern "C" fn Servo_CssRules_DeleteRule(rules: &LockedCssRules, index: u32) -> nsresult { 2278 write_locked_arc(rules, |rules: &mut CssRules| { 2279 match rules.remove_rule(index as usize) { 2280 Ok(_) => nsresult::NS_OK, 2281 Err(err) => err.into(), 2282 } 2283 }) 2284 } 2285 2286 trait MaybeLocked<Target> { 2287 fn maybe_locked_read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a Target; 2288 } 2289 2290 impl<T> MaybeLocked<T> for T { 2291 fn maybe_locked_read<'a>(&'a self, _: &'a SharedRwLockReadGuard) -> &'a T { 2292 self 2293 } 2294 } 2295 2296 impl<T> MaybeLocked<T> for Locked<T> { 2297 fn maybe_locked_read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T { 2298 self.read_with(guard) 2299 } 2300 } 2301 2302 macro_rules! impl_basic_rule_funcs_without_getter { 2303 { 2304 ($rule_type:ty, $maybe_locked_rule_type:ty), 2305 debug: $debug:ident, 2306 to_css: $to_css:ident, 2307 } => { 2308 #[cfg(debug_assertions)] 2309 #[no_mangle] 2310 pub extern "C" fn $debug(rule: &$maybe_locked_rule_type, result: &mut nsACString) { 2311 let global_style_data = &*GLOBAL_STYLE_DATA; 2312 let guard = global_style_data.shared_lock.read(); 2313 let rule: &$rule_type = rule.maybe_locked_read(&guard); 2314 write!(result, "{:?}", *rule).unwrap(); 2315 } 2316 2317 #[cfg(not(debug_assertions))] 2318 #[no_mangle] 2319 pub extern "C" fn $debug(_: &$maybe_locked_rule_type, _: &mut nsACString) { 2320 unreachable!() 2321 } 2322 2323 #[no_mangle] 2324 pub extern "C" fn $to_css(rule: &$maybe_locked_rule_type, result: &mut nsACString) { 2325 let global_style_data = &*GLOBAL_STYLE_DATA; 2326 let guard = global_style_data.shared_lock.read(); 2327 let rule: &$rule_type = rule.maybe_locked_read(&guard); 2328 rule.to_css(&guard, result).unwrap(); 2329 } 2330 } 2331 } 2332 2333 macro_rules! impl_basic_rule_funcs { 2334 { ($name:ident, $rule_type:ty, $maybe_locked_rule_type:ty), 2335 getter: $getter:ident, 2336 debug: $debug:ident, 2337 to_css: $to_css:ident, 2338 changed: $changed:ident, 2339 } => { 2340 #[no_mangle] 2341 pub extern "C" fn $getter( 2342 rules: &LockedCssRules, 2343 index: u32, 2344 line: &mut u32, 2345 column: &mut u32, 2346 ) -> Strong<$maybe_locked_rule_type> { 2347 let global_style_data = &*GLOBAL_STYLE_DATA; 2348 let guard = global_style_data.shared_lock.read(); 2349 let rules = rules.read_with(&guard); 2350 let index = index as usize; 2351 2352 if index >= rules.0.len() { 2353 return Strong::null(); 2354 } 2355 2356 match rules.0[index] { 2357 CssRule::$name(ref arc) => { 2358 let rule: &$rule_type = (&**arc).maybe_locked_read(&guard); 2359 let location = rule.source_location; 2360 *line = location.line as u32; 2361 *column = location.column as u32; 2362 arc.clone().into() 2363 }, 2364 _ => { 2365 Strong::null() 2366 } 2367 } 2368 } 2369 2370 #[no_mangle] 2371 pub extern "C" fn $changed( 2372 styleset: &PerDocumentStyleData, 2373 rule: &$maybe_locked_rule_type, 2374 sheet: &DomStyleSheet, 2375 change_kind: RuleChangeKind, 2376 ancestors: &nsTArray<CssRuleRef>, 2377 ) { 2378 let mut data = styleset.borrow_mut(); 2379 let data = &mut *data; 2380 let global_style_data = &*GLOBAL_STYLE_DATA; 2381 let guard = global_style_data.shared_lock.read(); 2382 // TODO(emilio): Would be nice not to deal with refcount bumps here, 2383 // but it's probably not a huge deal. 2384 let rule = unsafe { CssRule::$name(Arc::from_raw_addrefed(rule)) }; 2385 let sheet = unsafe { GeckoStyleSheet::new(sheet) }; 2386 data.stylist.rule_changed(&sheet, &rule, &guard, change_kind, ancestors.as_slice()); 2387 } 2388 2389 impl_basic_rule_funcs_without_getter! { 2390 ($rule_type, $maybe_locked_rule_type), 2391 debug: $debug, 2392 to_css: $to_css, 2393 } 2394 } 2395 } 2396 2397 macro_rules! impl_group_rule_funcs { 2398 { ($name:ident, $rule_type:ty, $maybe_locked_rule_type:ty), 2399 get_rules: $get_rules:ident, 2400 $($basic:tt)+ 2401 } => { 2402 impl_basic_rule_funcs! { ($name, $rule_type, $maybe_locked_rule_type), $($basic)+ } 2403 2404 #[no_mangle] 2405 pub extern "C" fn $get_rules(rule: &$maybe_locked_rule_type) -> Strong<LockedCssRules> { 2406 let global_style_data = &*GLOBAL_STYLE_DATA; 2407 let guard = global_style_data.shared_lock.read(); 2408 let rule: &$rule_type = rule.maybe_locked_read(&guard); 2409 rule.rules.clone().into() 2410 } 2411 } 2412 } 2413 2414 impl_basic_rule_funcs! { (Style, StyleRule, Locked<StyleRule>), 2415 getter: Servo_CssRules_GetStyleRuleAt, 2416 debug: Servo_StyleRule_Debug, 2417 to_css: Servo_StyleRule_GetCssText, 2418 changed: Servo_StyleSet_StyleRuleChanged, 2419 } 2420 2421 #[no_mangle] 2422 pub extern "C" fn Servo_StyleRule_EnsureRules( 2423 rule: &LockedStyleRule, 2424 read_only: bool, 2425 ) -> Strong<LockedCssRules> { 2426 let global_style_data = &*GLOBAL_STYLE_DATA; 2427 let lock = &global_style_data.shared_lock; 2428 if read_only { 2429 let guard = lock.read(); 2430 if let Some(ref rules) = rule.read_with(&guard).rules { 2431 return rules.clone().into(); 2432 } 2433 return CssRules::new(vec![], lock).into(); 2434 } 2435 let mut guard = lock.write(); 2436 rule.write_with(&mut guard) 2437 .rules 2438 .get_or_insert_with(|| CssRules::new(vec![], lock)) 2439 .clone() 2440 .into() 2441 } 2442 2443 impl_basic_rule_funcs! { (Import, ImportRule, Locked<ImportRule>), 2444 getter: Servo_CssRules_GetImportRuleAt, 2445 debug: Servo_ImportRule_Debug, 2446 to_css: Servo_ImportRule_GetCssText, 2447 changed: Servo_StyleSet_ImportRuleChanged, 2448 } 2449 2450 impl_basic_rule_funcs_without_getter! { (Keyframe, Locked<Keyframe>), 2451 debug: Servo_Keyframe_Debug, 2452 to_css: Servo_Keyframe_GetCssText, 2453 } 2454 2455 impl_basic_rule_funcs! { (Keyframes, KeyframesRule, Locked<KeyframesRule>), 2456 getter: Servo_CssRules_GetKeyframesRuleAt, 2457 debug: Servo_KeyframesRule_Debug, 2458 to_css: Servo_KeyframesRule_GetCssText, 2459 changed: Servo_StyleSet_KeyframesRuleChanged, 2460 } 2461 2462 impl_group_rule_funcs! { (Media, MediaRule, MediaRule), 2463 get_rules: Servo_MediaRule_GetRules, 2464 getter: Servo_CssRules_GetMediaRuleAt, 2465 debug: Servo_MediaRule_Debug, 2466 to_css: Servo_MediaRule_GetCssText, 2467 changed: Servo_StyleSet_MediaRuleChanged, 2468 } 2469 2470 impl_basic_rule_funcs! { (Margin, MarginRule, MarginRule), 2471 getter: Servo_CssRules_GetMarginRuleAt, 2472 debug: Servo_MarginRule_Debug, 2473 to_css: Servo_MarginRule_GetCssText, 2474 changed: Servo_StyleSet_MarginRuleChanged, 2475 } 2476 2477 impl_basic_rule_funcs! { (CustomMedia, CustomMediaRule, CustomMediaRule), 2478 getter: Servo_CssRules_GetCustomMediaRuleAt, 2479 debug: Servo_CustomMediaRule_Debug, 2480 to_css: Servo_CustomMediaRule_GetCssText, 2481 changed: Servo_StyleSet_CustomMediaRuleChanged, 2482 } 2483 2484 impl_basic_rule_funcs! { (Namespace, NamespaceRule, NamespaceRule), 2485 getter: Servo_CssRules_GetNamespaceRuleAt, 2486 debug: Servo_NamespaceRule_Debug, 2487 to_css: Servo_NamespaceRule_GetCssText, 2488 changed: Servo_StyleSet_NamespaceRuleChanged, 2489 } 2490 2491 impl_group_rule_funcs! { (Page, PageRule, Locked<PageRule>), 2492 get_rules: Servo_PageRule_GetRules, 2493 getter: Servo_CssRules_GetPageRuleAt, 2494 debug: Servo_PageRule_Debug, 2495 to_css: Servo_PageRule_GetCssText, 2496 changed: Servo_StyleSet_PageRuleChanged, 2497 } 2498 2499 impl_basic_rule_funcs! { (Property, PropertyRule, PropertyRule), 2500 getter: Servo_CssRules_GetPropertyRuleAt, 2501 debug: Servo_PropertyRule_Debug, 2502 to_css: Servo_PropertyRule_GetCssText, 2503 changed: Servo_StyleSet_PropertyRuleChanged, 2504 } 2505 2506 impl_group_rule_funcs! { (Supports, SupportsRule, SupportsRule), 2507 get_rules: Servo_SupportsRule_GetRules, 2508 getter: Servo_CssRules_GetSupportsRuleAt, 2509 debug: Servo_SupportsRule_Debug, 2510 to_css: Servo_SupportsRule_GetCssText, 2511 changed: Servo_StyleSet_SupportsRuleChanged, 2512 } 2513 2514 impl_group_rule_funcs! { (Container, ContainerRule, ContainerRule), 2515 get_rules: Servo_ContainerRule_GetRules, 2516 getter: Servo_CssRules_GetContainerRuleAt, 2517 debug: Servo_ContainerRule_Debug, 2518 to_css: Servo_ContainerRule_GetCssText, 2519 changed: Servo_StyleSet_ContainerRuleChanged, 2520 } 2521 2522 impl_group_rule_funcs! { (LayerBlock, LayerBlockRule, LayerBlockRule), 2523 get_rules: Servo_LayerBlockRule_GetRules, 2524 getter: Servo_CssRules_GetLayerBlockRuleAt, 2525 debug: Servo_LayerBlockRule_Debug, 2526 to_css: Servo_LayerBlockRule_GetCssText, 2527 changed: Servo_StyleSet_LayerBlockRuleChanged, 2528 } 2529 2530 impl_basic_rule_funcs! { (LayerStatement, LayerStatementRule, LayerStatementRule), 2531 getter: Servo_CssRules_GetLayerStatementRuleAt, 2532 debug: Servo_LayerStatementRule_Debug, 2533 to_css: Servo_LayerStatementRule_GetCssText, 2534 changed: Servo_StyleSet_LayerStatementRuleChanged, 2535 } 2536 2537 impl_group_rule_funcs! { (Document, DocumentRule, DocumentRule), 2538 get_rules: Servo_DocumentRule_GetRules, 2539 getter: Servo_CssRules_GetDocumentRuleAt, 2540 debug: Servo_DocumentRule_Debug, 2541 to_css: Servo_DocumentRule_GetCssText, 2542 changed: Servo_StyleSet_DocumentRuleChanged, 2543 } 2544 2545 impl_basic_rule_funcs! { (FontFeatureValues, FontFeatureValuesRule, FontFeatureValuesRule), 2546 getter: Servo_CssRules_GetFontFeatureValuesRuleAt, 2547 debug: Servo_FontFeatureValuesRule_Debug, 2548 to_css: Servo_FontFeatureValuesRule_GetCssText, 2549 changed: Servo_StyleSet_FontFeatureValuesRuleChanged, 2550 } 2551 2552 impl_basic_rule_funcs! { (FontPaletteValues, FontPaletteValuesRule, FontPaletteValuesRule), 2553 getter: Servo_CssRules_GetFontPaletteValuesRuleAt, 2554 debug: Servo_FontPaletteValuesRule_Debug, 2555 to_css: Servo_FontPaletteValuesRule_GetCssText, 2556 changed: Servo_StyleSet_FontPaletteValuesRuleChanged, 2557 } 2558 2559 impl_basic_rule_funcs! { (FontFace, FontFaceRule, Locked<FontFaceRule>), 2560 getter: Servo_CssRules_GetFontFaceRuleAt, 2561 debug: Servo_FontFaceRule_Debug, 2562 to_css: Servo_FontFaceRule_GetCssText, 2563 changed: Servo_StyleSet_FontFaceRuleChanged, 2564 } 2565 2566 impl_basic_rule_funcs! { (CounterStyle, CounterStyleRule, Locked<CounterStyleRule>), 2567 getter: Servo_CssRules_GetCounterStyleRuleAt, 2568 debug: Servo_CounterStyleRule_Debug, 2569 to_css: Servo_CounterStyleRule_GetCssText, 2570 changed: Servo_StyleSet_CounterStyleRuleChanged, 2571 } 2572 2573 impl_group_rule_funcs! { (Scope, ScopeRule, ScopeRule), 2574 get_rules: Servo_ScopeRule_GetRules, 2575 getter: Servo_CssRules_GetScopeRuleAt, 2576 debug: Servo_ScopeRule_Debug, 2577 to_css: Servo_ScopeRule_GetCssText, 2578 changed: Servo_StyleSet_ScopeRuleChanged, 2579 } 2580 2581 impl_group_rule_funcs! { (StartingStyle, StartingStyleRule, StartingStyleRule), 2582 get_rules: Servo_StartingStyleRule_GetRules, 2583 getter: Servo_CssRules_GetStartingStyleRuleAt, 2584 debug: Servo_StartingStyleRule_Debug, 2585 to_css: Servo_StartingStyleRule_GetCssText, 2586 changed: Servo_StyleSet_StartingStyleRuleChanged, 2587 } 2588 2589 impl_basic_rule_funcs! { (PositionTry, PositionTryRule, Locked<PositionTryRule>), 2590 getter: Servo_CssRules_GetPositionTryRuleAt, 2591 debug: Servo_PositionTryRule_Debug, 2592 to_css: Servo_PositionTryRule_GetCssText, 2593 changed: Servo_StyleSet_PositionTryRuleChanged, 2594 } 2595 2596 impl_basic_rule_funcs! { (NestedDeclarations, NestedDeclarationsRule, Locked<NestedDeclarationsRule>), 2597 getter: Servo_CssRules_GetNestedDeclarationsRuleAt, 2598 debug: Servo_NestedDeclarationsRule_Debug, 2599 to_css: Servo_NestedDeclarationsRule_GetCssText, 2600 changed: Servo_StyleSet_NestedDeclarationsRuleChanged, 2601 } 2602 2603 #[no_mangle] 2604 pub extern "C" fn Servo_NestedDeclarationsRule_GetStyle( 2605 rule: &LockedNestedDeclarationsRule, 2606 ) -> Strong<LockedDeclarationBlock> { 2607 read_locked_arc(rule, |rule: &NestedDeclarationsRule| { 2608 rule.block.clone().into() 2609 }) 2610 } 2611 2612 #[no_mangle] 2613 pub extern "C" fn Servo_NestedDeclarationsRule_SetStyle( 2614 rule: &LockedNestedDeclarationsRule, 2615 declarations: &LockedDeclarationBlock, 2616 ) { 2617 write_locked_arc(rule, |rule: &mut NestedDeclarationsRule| { 2618 rule.block = unsafe { Arc::from_raw_addrefed(declarations) }; 2619 }) 2620 } 2621 2622 #[no_mangle] 2623 pub extern "C" fn Servo_StyleRule_GetStyle( 2624 rule: &LockedStyleRule, 2625 ) -> Strong<LockedDeclarationBlock> { 2626 read_locked_arc(rule, |rule: &StyleRule| rule.block.clone().into()) 2627 } 2628 2629 #[no_mangle] 2630 pub extern "C" fn Servo_StyleRule_SetStyle( 2631 rule: &LockedStyleRule, 2632 declarations: &LockedDeclarationBlock, 2633 ) { 2634 write_locked_arc(rule, |rule: &mut StyleRule| { 2635 rule.block = unsafe { Arc::from_raw_addrefed(declarations) }; 2636 }) 2637 } 2638 2639 #[no_mangle] 2640 pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: &LockedStyleRule, result: &mut nsACString) { 2641 read_locked_arc(rule, |rule| rule.selectors.to_css(result).unwrap()); 2642 } 2643 2644 fn desugared_selector_list(rules: &[&LockedStyleRule]) -> SelectorList { 2645 let mut selectors: Option<SelectorList> = None; 2646 for rule in rules.iter().rev() { 2647 selectors = Some(read_locked_arc(rule, |rule| match selectors { 2648 Some(ref s) => rule.selectors.replace_parent_selector(s), 2649 None => rule.selectors.clone(), 2650 })); 2651 } 2652 selectors.expect("Empty rule chain?") 2653 } 2654 2655 #[no_mangle] 2656 pub extern "C" fn Servo_StyleRule_GetSelectorList( 2657 rules: &nsTArray<&LockedStyleRule>, 2658 ) -> *mut SelectorList { 2659 Box::into_raw(Box::new(desugared_selector_list(rules))) 2660 } 2661 2662 #[no_mangle] 2663 pub extern "C" fn Servo_StyleRule_GetSelectorDataAtIndex( 2664 rules: &nsTArray<&LockedStyleRule>, 2665 index: u32, 2666 text: Option<&mut nsACString>, 2667 specificity: Option<&mut u64>, 2668 ) { 2669 let selectors = desugared_selector_list(rules); 2670 let Some(selector) = selectors.slice().get(index as usize) else { 2671 return; 2672 }; 2673 if let Some(text) = text { 2674 selector.to_css(text).unwrap(); 2675 } 2676 if let Some(specificity) = specificity { 2677 *specificity = selector.specificity() as u64; 2678 } 2679 } 2680 2681 #[no_mangle] 2682 pub extern "C" fn Servo_StyleRule_GetSelectorCount(rule: &LockedStyleRule) -> u32 { 2683 read_locked_arc(rule, |rule| rule.selectors.len() as u32) 2684 } 2685 2686 struct DesugaredScopeData { 2687 conditions: SmallVec<[ScopeConditionReference; 2]>, 2688 subject_map: ScopeSubjectMap, 2689 } 2690 2691 fn desugared_selector_list_with_scope( 2692 quirks_mode: QuirksMode, 2693 rules: &[&LockedStyleRule], 2694 scope_data: &nsTArray<ScopeRuleData>, 2695 ) -> (SelectorList, Option<DesugaredScopeData>) { 2696 if scope_data.is_empty() { 2697 return (desugared_selector_list(rules), None); 2698 } 2699 2700 fn desugared_scope_rule( 2701 quirks_mode: QuirksMode, 2702 id: u16, 2703 scope_data: &ScopeRuleData, 2704 selectors: &[&LockedStyleRule], 2705 subject_map: &mut ScopeSubjectMap, 2706 ) -> ScopeConditionReference { 2707 debug_assert!(id > 0, "ID corresponds to none?"); 2708 let (start, end) = unsafe { 2709 let rule = scope_data 2710 .scope_rule 2711 .as_ref() 2712 .expect("Ill-formed scope data?"); 2713 ( 2714 if selectors.is_empty() { 2715 rule.bounds.start.clone() 2716 } else { 2717 let desugared = desugared_selector_list(selectors); 2718 rule.bounds 2719 .start 2720 .as_ref() 2721 .map(|s| s.replace_parent_selector(&desugared)) 2722 }, 2723 rule.bounds 2724 .end 2725 .as_ref() 2726 .map(|s| replace_parent_selector_with_implicit_scope(s)), 2727 ) 2728 }; 2729 // Building the subject map is likey worth it, because we traverse up as much as possible to gather all possible candidates. 2730 start 2731 .as_ref() 2732 .map(|s| subject_map.add_bound_start(s, quirks_mode)); 2733 ScopeConditionReference::new( 2734 ScopeConditionId::new(id - 1), 2735 // Don't bother with hashing - we don't compute ancestor hashes anyway. 2736 Some(ScopeBoundsWithHashes::new_no_hash(start, end)), 2737 unsafe { GeckoStyleSheet::new(scope_data.sheet).implicit_scope_root() } 2738 .unwrap_or(ImplicitScopeRoot::DocumentElement), 2739 false, 2740 ) 2741 } 2742 2743 let innermost_scope_valid_til = scope_data[0].valid_til; 2744 // Take style rules up to the innermost scope rule, and desugar it. 2745 let desugared_style = desugared_selector_list(if innermost_scope_valid_til > rules.len() - 1 { 2746 &rules[0..] 2747 } else { 2748 &rules[0..=innermost_scope_valid_til] 2749 }); 2750 2751 // Now, desugar the scope rule(s) with any intervening nested style rule(s). 2752 let mut conditions = SmallVec::with_capacity(scope_data.len()); 2753 let mut subject_map = ScopeSubjectMap::default(); 2754 conditions.push(ScopeConditionReference::none()); 2755 let mut end_at = rules.len() - 1; 2756 for data in scope_data.iter().rev() { 2757 conditions.push(desugared_scope_rule( 2758 quirks_mode, 2759 conditions.len() as u16, 2760 data, 2761 &rules[data.valid_til + 1..=end_at], 2762 &mut subject_map, 2763 )); 2764 end_at = data.valid_til; 2765 } 2766 2767 ( 2768 desugared_style, 2769 Some(DesugaredScopeData { 2770 conditions, 2771 subject_map, 2772 }), 2773 ) 2774 } 2775 2776 /// Additional scope rule data for matching a style rule. 2777 #[repr(C)] 2778 pub struct ScopeRuleData { 2779 /// Scope rule applicable at this nesting level. 2780 pub scope_rule: *const ScopeRule, 2781 /// Stylesheet this scope rule comes from. 2782 pub sheet: *const DomStyleSheet, 2783 /// Index to the last style rule in an array this scope applies to. 2784 pub valid_til: usize, 2785 } 2786 2787 fn selector_matches_element<F, R>( 2788 rules: &nsTArray<&LockedStyleRule>, 2789 scope_rules: &nsTArray<ScopeRuleData>, 2790 element: GeckoElement, 2791 index: u32, 2792 host: Option<&RawGeckoElement>, 2793 pseudo_type: PseudoStyleType, 2794 pseudo_id: *const nsAtom, 2795 relevant_link_visited: bool, 2796 on_match: F, 2797 ) -> Option<R> 2798 where 2799 F: FnOnce(Option<&ScopeRootCandidate>) -> R, 2800 { 2801 use selectors::matching::{ 2802 matches_selector, IncludeStartingStyle, MatchingContext, MatchingMode, NeedsSelectorFlags, 2803 VisitedHandlingMode, 2804 }; 2805 2806 let quirks_mode = element.as_node().owner_doc().quirks_mode(); 2807 let (selectors, scopes) = desugared_selector_list_with_scope(quirks_mode, rules, scope_rules); 2808 let Some(selector) = selectors.slice().get(index as usize) else { 2809 return None; 2810 }; 2811 let mut matching_mode = MatchingMode::Normal; 2812 let pseudo_id = if pseudo_id.is_null() { 2813 None 2814 } else { 2815 Some(AtomIdent::new(unsafe { 2816 Atom::from_raw(pseudo_id as *mut nsAtom) 2817 })) 2818 }; 2819 match PseudoElement::from_pseudo_type(pseudo_type, pseudo_id) { 2820 Some(pseudo) => { 2821 // We need to make sure that the requested pseudo element type 2822 // matches the selector pseudo element type before proceeding. 2823 let selector_pseudo = selector.pseudo_element()?; 2824 // The element here is used to get the active view transition (for 2825 // view-transition-class), so passing the originating element is fine here. 2826 if !pseudo.matches(selector_pseudo, &element) { 2827 return None; 2828 } 2829 matching_mode = MatchingMode::ForStatelessPseudoElement; 2830 }, 2831 None => { 2832 // Do not attempt to match if a pseudo element is requested and 2833 // this is not a pseudo element selector, or vice versa. 2834 if selector.has_pseudo_element() { 2835 return None; 2836 } 2837 }, 2838 }; 2839 2840 let host = host.map(GeckoElement); 2841 let mut selector_caches = SelectorCaches::default(); 2842 let visited_mode = if relevant_link_visited { 2843 VisitedHandlingMode::RelevantLinkVisited 2844 } else { 2845 VisitedHandlingMode::AllLinksUnvisited 2846 }; 2847 let mut ctx = MatchingContext::new_for_visited( 2848 matching_mode, 2849 /* bloom_filter = */ None, 2850 &mut selector_caches, 2851 visited_mode, 2852 IncludeStartingStyle::No, 2853 quirks_mode, 2854 NeedsSelectorFlags::No, 2855 MatchingForInvalidation::No, 2856 ); 2857 ctx.with_shadow_host(host, |ctx| match scopes.as_ref() { 2858 None => matches_selector(selector, 0, None, &element, ctx).then(|| on_match(None)), 2859 Some(s) => { 2860 let id = ScopeConditionId::new((s.conditions.len() - 1) as u16); 2861 let candidates = scope_root_candidates( 2862 &s.conditions, 2863 id, 2864 &element, 2865 selector.is_part(), 2866 &s.subject_map, 2867 ctx, 2868 ); 2869 let scope_root = candidates.candidates.iter().find_map(|candidate| { 2870 ctx.nest_for_scope(Some(candidate.root), |ctx| { 2871 matches_selector(selector, 0, None, &element, ctx).then(|| candidate) 2872 }) 2873 }); 2874 scope_root.map(|root| on_match(Some(root))) 2875 }, 2876 }) 2877 } 2878 2879 #[no_mangle] 2880 pub extern "C" fn Servo_StyleRule_SelectorMatchesElement( 2881 rules: &nsTArray<&LockedStyleRule>, 2882 scope_rules: &nsTArray<ScopeRuleData>, 2883 element: &RawGeckoElement, 2884 index: u32, 2885 host: Option<&RawGeckoElement>, 2886 pseudo_type: PseudoStyleType, 2887 pseudo_id: *const nsAtom, 2888 relevant_link_visited: bool, 2889 ) -> bool { 2890 selector_matches_element( 2891 rules, 2892 scope_rules, 2893 GeckoElement(element), 2894 index, 2895 host, 2896 pseudo_type, 2897 pseudo_id, 2898 relevant_link_visited, 2899 |_| true, 2900 ) 2901 .unwrap_or(false) 2902 } 2903 2904 #[no_mangle] 2905 pub extern "C" fn Servo_StyleRule_GetScopeRootFor( 2906 rules: &nsTArray<&LockedStyleRule>, 2907 scope_rules: &nsTArray<ScopeRuleData>, 2908 element: &RawGeckoElement, 2909 index: u32, 2910 host: Option<&RawGeckoElement>, 2911 pseudo_type: PseudoStyleType, 2912 pseudo_id: *const nsAtom, 2913 relevant_link_visited: bool, 2914 ) -> *const RawGeckoElement { 2915 let element = GeckoElement(element); 2916 selector_matches_element( 2917 rules, 2918 scope_rules, 2919 element, 2920 index, 2921 host, 2922 pseudo_type, 2923 pseudo_id, 2924 relevant_link_visited, 2925 |candidate| { 2926 candidate 2927 .map(|c| c.get_scope_root_element(element)) 2928 .flatten() 2929 }, 2930 ) 2931 .flatten() 2932 .map_or(ptr::null(), |e| e.0) 2933 } 2934 2935 pub type SelectorList = selectors::SelectorList<style::gecko::selector_parser::SelectorImpl>; 2936 2937 #[no_mangle] 2938 pub extern "C" fn Servo_StyleRule_SetSelectorText( 2939 contents: &StylesheetContents, 2940 rule: &LockedStyleRule, 2941 text: &nsACString, 2942 parse_relative_rule_type: Option<&CssRuleType>, 2943 ) -> bool { 2944 let value_str = unsafe { text.as_str_unchecked() }; 2945 2946 write_locked_arc(rule, |rule: &mut StyleRule| { 2947 use selectors::parser::ParseRelative; 2948 use style::selector_parser::SelectorParser; 2949 2950 let namespaces = &contents.namespaces; 2951 let url_data = &contents.url_data; 2952 let parser = SelectorParser { 2953 stylesheet_origin: contents.origin, 2954 namespaces: &namespaces, 2955 url_data: &url_data, 2956 for_supports_rule: false, 2957 }; 2958 2959 let parse_relative = match parse_relative_rule_type { 2960 Some(CssRuleType::Style) => ParseRelative::ForNesting, 2961 Some(CssRuleType::Scope) => ParseRelative::ForScope, 2962 _ => ParseRelative::No, 2963 }; 2964 let mut parser_input = ParserInput::new(&value_str); 2965 match SelectorList::parse(&parser, &mut Parser::new(&mut parser_input), parse_relative) { 2966 Ok(selectors) => { 2967 rule.selectors = selectors; 2968 true 2969 }, 2970 Err(_) => false, 2971 } 2972 }) 2973 } 2974 2975 #[no_mangle] 2976 pub unsafe extern "C" fn Servo_SelectorList_Closest( 2977 element: &RawGeckoElement, 2978 selectors: &SelectorList, 2979 ) -> *const RawGeckoElement { 2980 use style::dom_apis; 2981 2982 let element = GeckoElement(element); 2983 let quirks_mode = element.as_node().owner_doc().quirks_mode(); 2984 dom_apis::element_closest(element, &selectors, quirks_mode).map_or(ptr::null(), |e| e.0) 2985 } 2986 2987 #[no_mangle] 2988 pub unsafe extern "C" fn Servo_SelectorList_Matches( 2989 element: &RawGeckoElement, 2990 selectors: &SelectorList, 2991 ) -> bool { 2992 use style::dom_apis; 2993 2994 let element = GeckoElement(element); 2995 let quirks_mode = element.as_node().owner_doc().quirks_mode(); 2996 dom_apis::element_matches(&element, &selectors, quirks_mode) 2997 } 2998 2999 #[no_mangle] 3000 pub unsafe extern "C" fn Servo_SelectorList_QueryFirst( 3001 node: &RawGeckoNode, 3002 selectors: &SelectorList, 3003 may_use_invalidation: bool, 3004 ) -> *const RawGeckoElement { 3005 use style::dom_apis::{self, MayUseInvalidation, QueryFirst}; 3006 3007 let node = GeckoNode(node); 3008 let mut result = None; 3009 3010 let may_use_invalidation = if may_use_invalidation { 3011 MayUseInvalidation::Yes 3012 } else { 3013 MayUseInvalidation::No 3014 }; 3015 3016 dom_apis::query_selector::<GeckoElement, QueryFirst>( 3017 node, 3018 &selectors, 3019 &mut result, 3020 may_use_invalidation, 3021 ); 3022 3023 result.map_or(ptr::null(), |e| e.0) 3024 } 3025 3026 #[no_mangle] 3027 pub unsafe extern "C" fn Servo_SelectorList_QueryAll( 3028 node: &RawGeckoNode, 3029 selectors: &SelectorList, 3030 content_list: *mut structs::nsSimpleContentList, 3031 may_use_invalidation: bool, 3032 ) { 3033 use style::dom_apis::{self, MayUseInvalidation, QueryAll}; 3034 3035 let node = GeckoNode(node); 3036 let mut result = SmallVec::new(); 3037 3038 let may_use_invalidation = if may_use_invalidation { 3039 MayUseInvalidation::Yes 3040 } else { 3041 MayUseInvalidation::No 3042 }; 3043 3044 dom_apis::query_selector::<GeckoElement, QueryAll>( 3045 node, 3046 &selectors, 3047 &mut result, 3048 may_use_invalidation, 3049 ); 3050 3051 if !result.is_empty() { 3052 // NOTE(emilio): This relies on a slice of GeckoElement having the same 3053 // memory representation than a slice of element pointers. 3054 bindings::Gecko_ContentList_AppendAll( 3055 content_list, 3056 result.as_ptr() as *mut *const _, 3057 result.len(), 3058 ) 3059 } 3060 } 3061 3062 #[no_mangle] 3063 pub unsafe extern "C" fn Servo_SelectorList_QueryAllWithScope( 3064 node: &RawGeckoNode, 3065 rules: &nsTArray<&LockedStyleRule>, 3066 scope_rules: &nsTArray<ScopeRuleData>, 3067 content_list: *mut structs::nsSimpleContentList, 3068 ) { 3069 let root = GeckoNode(node); 3070 let quirks_mode = root.owner_doc().quirks_mode(); 3071 let (selectors, scopes) = desugared_selector_list_with_scope(quirks_mode, rules, scope_rules); 3072 // This replicates the slow path of `querySelectorAll`. 3073 // TODO(dshin): A tigher integration could be nicer - but it'd be for 3074 // a very specific (DevTools-only) use case, since normal `querySelectorAll` 3075 // JS calls can't use @scope. 3076 let mut selector_caches = SelectorCaches::default(); 3077 let mut ctx = MatchingContext::new( 3078 MatchingMode::Normal, 3079 /* bloom_filter = */ None, 3080 &mut selector_caches, 3081 quirks_mode, 3082 NeedsSelectorFlags::No, 3083 MatchingForInvalidation::No, 3084 ); 3085 let root_element = root.as_element(); 3086 ctx.current_host = match root_element { 3087 Some(root) => root.containing_shadow_host().map(|host| host.opaque()), 3088 None => root.as_shadow_root().map(|root| root.host().opaque()), 3089 }; 3090 let mut result: SmallVec<[GeckoElement; 128]> = Default::default(); 3091 let may_match_shadow_host_for_part = selectors.slice().iter().any(|s| s.is_part()); 3092 for node in root.dom_descendants() { 3093 let Some(element) = node.as_element() else { 3094 continue; 3095 }; 3096 let matches = match scopes.as_ref() { 3097 None => matches_selector_list(&selectors, &element, &mut ctx), 3098 Some(s) => { 3099 let id = ScopeConditionId::new((s.conditions.len() - 1) as u16); 3100 let candidates = scope_root_candidates( 3101 &s.conditions, 3102 id, 3103 &element, 3104 may_match_shadow_host_for_part, 3105 &s.subject_map, 3106 &mut ctx, 3107 ); 3108 candidates.candidates.iter().any(|candidate| { 3109 ctx.nest_for_scope(Some(candidate.root), |ctx| { 3110 matches_selector_list(&selectors, &element, ctx) 3111 }) 3112 }) 3113 }, 3114 }; 3115 if matches { 3116 result.push(element); 3117 } 3118 } 3119 3120 if !result.is_empty() { 3121 // NOTE(emilio): This relies on a slice of GeckoElement having the same 3122 // memory representation than a slice of element pointers. 3123 bindings::Gecko_ContentList_AppendAll( 3124 content_list, 3125 result.as_ptr() as *mut *const _, 3126 result.len(), 3127 ) 3128 } 3129 } 3130 3131 #[no_mangle] 3132 pub extern "C" fn Servo_ImportRule_GetHref(rule: &LockedImportRule, result: &mut nsAString) { 3133 read_locked_arc(rule, |rule: &ImportRule| { 3134 write!(result, "{}", rule.url.as_str()).unwrap(); 3135 }) 3136 } 3137 3138 #[no_mangle] 3139 pub extern "C" fn Servo_ImportRule_GetLayerName(rule: &LockedImportRule, result: &mut nsACString) { 3140 // https://w3c.github.io/csswg-drafts/cssom/#dom-cssimportrule-layername 3141 read_locked_arc(rule, |rule: &ImportRule| match rule.layer { 3142 ImportLayer::Named(ref name) => name.to_css(&mut CssWriter::new(result)).unwrap(), // "return the layer name declared in the at-rule itself" 3143 ImportLayer::Anonymous => {}, // "or an empty string if the layer is anonymous" 3144 ImportLayer::None => result.set_is_void(true), // "or null if the at-rule does not declare a layer" 3145 }) 3146 } 3147 3148 #[no_mangle] 3149 pub extern "C" fn Servo_ImportRule_GetSupportsText( 3150 rule: &LockedImportRule, 3151 result: &mut nsACString, 3152 ) { 3153 read_locked_arc(rule, |rule: &ImportRule| match rule.supports { 3154 Some(ref supports) => supports 3155 .condition 3156 .to_css(&mut CssWriter::new(result)) 3157 .unwrap(), 3158 None => result.set_is_void(true), 3159 }) 3160 } 3161 3162 #[no_mangle] 3163 pub extern "C" fn Servo_ImportRule_GetSheet(rule: &LockedImportRule) -> *const DomStyleSheet { 3164 read_locked_arc(rule, |rule: &ImportRule| { 3165 rule.stylesheet 3166 .as_sheet() 3167 .map_or(ptr::null(), |s| s.raw() as *const DomStyleSheet) 3168 }) 3169 } 3170 3171 #[no_mangle] 3172 pub unsafe extern "C" fn Servo_ImportRule_SetSheet( 3173 rule: &LockedImportRule, 3174 sheet: *mut DomStyleSheet, 3175 ) { 3176 write_locked_arc(rule, |rule: &mut ImportRule| { 3177 rule.stylesheet = ImportSheet::new(GeckoStyleSheet::new(sheet)); 3178 }) 3179 } 3180 3181 #[no_mangle] 3182 pub extern "C" fn Servo_Keyframe_GetKeyText(keyframe: &LockedKeyframe, result: &mut nsACString) { 3183 read_locked_arc(keyframe, |keyframe: &Keyframe| { 3184 keyframe 3185 .selector 3186 .to_css(&mut CssWriter::new(result)) 3187 .unwrap() 3188 }) 3189 } 3190 3191 #[no_mangle] 3192 pub extern "C" fn Servo_Keyframe_SetKeyText(keyframe: &LockedKeyframe, text: &nsACString) -> bool { 3193 let text = unsafe { text.as_str_unchecked() }; 3194 let mut input = ParserInput::new(&text); 3195 if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) { 3196 write_locked_arc(keyframe, |keyframe: &mut Keyframe| { 3197 keyframe.selector = selector; 3198 }); 3199 true 3200 } else { 3201 false 3202 } 3203 } 3204 3205 #[no_mangle] 3206 pub extern "C" fn Servo_Keyframe_GetStyle( 3207 keyframe: &LockedKeyframe, 3208 ) -> Strong<LockedDeclarationBlock> { 3209 read_locked_arc(keyframe, |keyframe: &Keyframe| { 3210 keyframe.block.clone().into() 3211 }) 3212 } 3213 3214 #[no_mangle] 3215 pub extern "C" fn Servo_Keyframe_SetStyle( 3216 keyframe: &LockedKeyframe, 3217 declarations: &LockedDeclarationBlock, 3218 ) { 3219 write_locked_arc(keyframe, |keyframe: &mut Keyframe| { 3220 keyframe.block = unsafe { Arc::from_raw_addrefed(declarations) }; 3221 }) 3222 } 3223 3224 #[no_mangle] 3225 pub extern "C" fn Servo_KeyframesRule_GetName(rule: &LockedKeyframesRule) -> *mut nsAtom { 3226 read_locked_arc(rule, |rule: &KeyframesRule| rule.name.as_atom().as_ptr()) 3227 } 3228 3229 #[no_mangle] 3230 pub unsafe extern "C" fn Servo_KeyframesRule_SetName( 3231 rule: &LockedKeyframesRule, 3232 name: *mut nsAtom, 3233 ) { 3234 write_locked_arc(rule, |rule: &mut KeyframesRule| { 3235 rule.name = KeyframesName::from_atom(Atom::from_addrefed(name)); 3236 }) 3237 } 3238 3239 #[no_mangle] 3240 pub extern "C" fn Servo_KeyframesRule_GetCount(rule: &LockedKeyframesRule) -> u32 { 3241 read_locked_arc(rule, |rule: &KeyframesRule| rule.keyframes.len() as u32) 3242 } 3243 3244 #[no_mangle] 3245 pub extern "C" fn Servo_KeyframesRule_GetKeyframeAt( 3246 rule: &LockedKeyframesRule, 3247 index: u32, 3248 line: &mut u32, 3249 column: &mut u32, 3250 ) -> Strong<LockedKeyframe> { 3251 let global_style_data = &*GLOBAL_STYLE_DATA; 3252 let guard = global_style_data.shared_lock.read(); 3253 let key = rule.read_with(&guard).keyframes[index as usize].clone(); 3254 let location = key.read_with(&guard).source_location; 3255 *line = location.line as u32; 3256 *column = location.column as u32; 3257 key.into() 3258 } 3259 3260 #[no_mangle] 3261 pub extern "C" fn Servo_KeyframesRule_FindRule( 3262 rule: &LockedKeyframesRule, 3263 key: &nsACString, 3264 ) -> u32 { 3265 let key = unsafe { key.as_str_unchecked() }; 3266 let global_style_data = &*GLOBAL_STYLE_DATA; 3267 let guard = global_style_data.shared_lock.read(); 3268 rule.read_with(&guard) 3269 .find_rule(&guard, key) 3270 .map(|index| index as u32) 3271 .unwrap_or(u32::max_value()) 3272 } 3273 3274 #[no_mangle] 3275 pub extern "C" fn Servo_KeyframesRule_AppendRule( 3276 rule: &LockedKeyframesRule, 3277 contents: &StylesheetContents, 3278 css: &nsACString, 3279 ) -> bool { 3280 let css = unsafe { css.as_str_unchecked() }; 3281 let global_style_data = &*GLOBAL_STYLE_DATA; 3282 3283 match Keyframe::parse(css, &contents, &global_style_data.shared_lock) { 3284 Ok(keyframe) => { 3285 write_locked_arc(rule, |rule: &mut KeyframesRule| { 3286 rule.keyframes.push(keyframe); 3287 }); 3288 true 3289 }, 3290 Err(..) => false, 3291 } 3292 } 3293 3294 #[no_mangle] 3295 pub extern "C" fn Servo_KeyframesRule_DeleteRule(rule: &LockedKeyframesRule, index: u32) { 3296 write_locked_arc(rule, |rule: &mut KeyframesRule| { 3297 rule.keyframes.remove(index as usize); 3298 }) 3299 } 3300 3301 #[no_mangle] 3302 pub extern "C" fn Servo_MediaRule_GetMedia(rule: &MediaRule) -> Strong<LockedMediaList> { 3303 rule.media_queries.clone().into() 3304 } 3305 3306 /// If the condition is null, the true/false gets communicated via the out-param 3307 #[no_mangle] 3308 pub extern "C" fn Servo_CustomMediaRule_GetCondition( 3309 rule: &CustomMediaRule, 3310 value: Option<&mut bool>, 3311 ) -> Strong<LockedMediaList> { 3312 let fixed_value = match rule.condition { 3313 CustomMediaCondition::True => true, 3314 CustomMediaCondition::False => false, 3315 CustomMediaCondition::MediaList(ref list) => return list.clone().into(), 3316 }; 3317 if let Some(value) = value { 3318 *value = fixed_value; 3319 } 3320 Strong::null() 3321 } 3322 3323 #[no_mangle] 3324 pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: &NamespaceRule) -> *mut nsAtom { 3325 rule.prefix 3326 .as_ref() 3327 .map_or(atom!("").as_ptr(), |a| a.as_ptr()) 3328 } 3329 3330 #[no_mangle] 3331 pub extern "C" fn Servo_NamespaceRule_GetURI(rule: &NamespaceRule) -> *mut nsAtom { 3332 rule.url.0.as_ptr() 3333 } 3334 3335 #[no_mangle] 3336 pub extern "C" fn Servo_MarginRule_GetStyle(rule: &MarginRule) -> Strong<LockedDeclarationBlock> { 3337 rule.block.clone().into() 3338 } 3339 3340 #[no_mangle] 3341 pub extern "C" fn Servo_MarginRule_GetName(rule: &MarginRule, out: &mut nsACString) { 3342 out.assign(rule.name()); 3343 } 3344 3345 #[no_mangle] 3346 pub extern "C" fn Servo_CustomMediaRule_GetName(rule: &CustomMediaRule) -> *mut nsAtom { 3347 rule.name.0.as_ptr() 3348 } 3349 3350 #[no_mangle] 3351 pub extern "C" fn Servo_PageRule_GetStyle(rule: &LockedPageRule) -> Strong<LockedDeclarationBlock> { 3352 read_locked_arc(rule, |rule: &PageRule| rule.block.clone().into()) 3353 } 3354 3355 #[no_mangle] 3356 pub extern "C" fn Servo_PageRule_SetStyle( 3357 rule: &LockedPageRule, 3358 declarations: &LockedDeclarationBlock, 3359 ) { 3360 write_locked_arc(rule, |rule: &mut PageRule| { 3361 rule.block = unsafe { Arc::from_raw_addrefed(declarations) }; 3362 }) 3363 } 3364 3365 #[no_mangle] 3366 pub extern "C" fn Servo_PageRule_GetSelectorText(rule: &LockedPageRule, result: &mut nsACString) { 3367 read_locked_arc(rule, |rule: &PageRule| { 3368 rule.selectors.to_css(&mut CssWriter::new(result)).unwrap(); 3369 }) 3370 } 3371 3372 #[no_mangle] 3373 pub extern "C" fn Servo_PageRule_SetSelectorText( 3374 contents: &StylesheetContents, 3375 rule: &LockedPageRule, 3376 text: &nsACString, 3377 ) -> bool { 3378 let value_str = unsafe { text.as_str_unchecked() }; 3379 3380 write_locked_arc(rule, |rule: &mut PageRule| { 3381 use style::stylesheets::PageSelectors; 3382 3383 let mut parser_input = ParserInput::new(&value_str); 3384 let mut parser = Parser::new(&mut parser_input); 3385 3386 // Ensure that a blank input results in empty page selectors 3387 if parser.is_exhausted() { 3388 rule.selectors = PageSelectors::default(); 3389 return true; 3390 } 3391 3392 let url_data = &contents.url_data; 3393 let context = ParserContext::new( 3394 Origin::Author, 3395 &url_data, 3396 None, 3397 ParsingMode::DEFAULT, 3398 QuirksMode::NoQuirks, 3399 /* namespaces = */ Default::default(), 3400 None, 3401 None, 3402 ); 3403 3404 match parser.parse_entirely(|i| PageSelectors::parse(&context, i)) { 3405 Ok(selectors) => { 3406 rule.selectors = selectors; 3407 true 3408 }, 3409 Err(_) => false, 3410 } 3411 }) 3412 } 3413 3414 #[no_mangle] 3415 pub extern "C" fn Servo_PropertyRule_GetName(rule: &PropertyRule, result: &mut nsACString) { 3416 write!(result, "--{}", rule.name.0).unwrap(); 3417 } 3418 3419 #[no_mangle] 3420 pub extern "C" fn Servo_PropertyRule_GetSyntax(rule: &PropertyRule, result: &mut nsACString) { 3421 if let Some(syntax) = rule.data.syntax.specified_string() { 3422 result.assign(syntax); 3423 } else { 3424 debug_assert!(false, "Rule without specified syntax?"); 3425 } 3426 } 3427 3428 #[no_mangle] 3429 pub extern "C" fn Servo_PropertyRule_GetInherits(rule: &PropertyRule) -> bool { 3430 rule.inherits() 3431 } 3432 3433 #[no_mangle] 3434 pub extern "C" fn Servo_PropertyRule_GetInitialValue( 3435 rule: &PropertyRule, 3436 result: &mut nsACString, 3437 ) -> bool { 3438 rule.data 3439 .initial_value 3440 .to_css(&mut CssWriter::new(result)) 3441 .unwrap(); 3442 rule.data.initial_value.is_some() 3443 } 3444 3445 #[no_mangle] 3446 pub extern "C" fn Servo_SupportsRule_GetConditionText( 3447 rule: &SupportsRule, 3448 result: &mut nsACString, 3449 ) { 3450 rule.condition.to_css(&mut CssWriter::new(result)).unwrap(); 3451 } 3452 3453 #[no_mangle] 3454 pub extern "C" fn Servo_ContainerRule_GetConditionText( 3455 rule: &ContainerRule, 3456 result: &mut nsACString, 3457 ) { 3458 rule.condition.to_css(&mut CssWriter::new(result)).unwrap(); 3459 } 3460 3461 #[no_mangle] 3462 pub extern "C" fn Servo_ContainerRule_GetContainerQuery( 3463 rule: &ContainerRule, 3464 result: &mut nsACString, 3465 ) { 3466 rule.query_condition() 3467 .to_css(&mut CssWriter::new(result)) 3468 .unwrap(); 3469 } 3470 3471 #[no_mangle] 3472 pub extern "C" fn Servo_ContainerRule_QueryContainerFor( 3473 rule: &ContainerRule, 3474 element: &RawGeckoElement, 3475 ) -> *const RawGeckoElement { 3476 rule.condition 3477 .find_container(GeckoElement(element), None) 3478 .map_or(ptr::null(), |result| result.element.0) 3479 } 3480 3481 #[no_mangle] 3482 pub extern "C" fn Servo_ContainerRule_GetContainerName( 3483 rule: &ContainerRule, 3484 result: &mut nsACString, 3485 ) { 3486 let name = rule.container_name(); 3487 if !name.is_none() { 3488 name.to_css(&mut CssWriter::new(result)).unwrap(); 3489 } 3490 } 3491 3492 #[no_mangle] 3493 pub extern "C" fn Servo_DocumentRule_GetConditionText( 3494 rule: &DocumentRule, 3495 result: &mut nsACString, 3496 ) { 3497 rule.condition.to_css(&mut CssWriter::new(result)).unwrap(); 3498 } 3499 3500 #[no_mangle] 3501 pub extern "C" fn Servo_FontFeatureValuesRule_GetFontFamily( 3502 rule: &FontFeatureValuesRule, 3503 result: &mut nsACString, 3504 ) { 3505 rule.family_names 3506 .to_css(&mut CssWriter::new(result)) 3507 .unwrap(); 3508 } 3509 3510 #[no_mangle] 3511 pub extern "C" fn Servo_FontFeatureValuesRule_GetValueText( 3512 rule: &FontFeatureValuesRule, 3513 result: &mut nsACString, 3514 ) { 3515 rule.value_to_css(&mut CssWriter::new(result)).unwrap(); 3516 } 3517 3518 #[no_mangle] 3519 pub extern "C" fn Servo_FontPaletteValuesRule_GetName( 3520 rule: &FontPaletteValuesRule, 3521 result: &mut nsACString, 3522 ) { 3523 rule.name.to_css(&mut CssWriter::new(result)).unwrap() 3524 } 3525 3526 #[no_mangle] 3527 pub extern "C" fn Servo_FontPaletteValuesRule_GetFontFamily( 3528 rule: &FontPaletteValuesRule, 3529 result: &mut nsACString, 3530 ) { 3531 if !rule.family_names.is_empty() { 3532 rule.family_names 3533 .to_css(&mut CssWriter::new(result)) 3534 .unwrap() 3535 } 3536 } 3537 3538 #[no_mangle] 3539 pub extern "C" fn Servo_FontPaletteValuesRule_GetBasePalette( 3540 rule: &FontPaletteValuesRule, 3541 result: &mut nsACString, 3542 ) { 3543 rule.base_palette 3544 .to_css(&mut CssWriter::new(result)) 3545 .unwrap() 3546 } 3547 3548 #[no_mangle] 3549 pub extern "C" fn Servo_FontPaletteValuesRule_GetOverrideColors( 3550 rule: &FontPaletteValuesRule, 3551 result: &mut nsACString, 3552 ) { 3553 if !rule.override_colors.is_empty() { 3554 rule.override_colors 3555 .to_css(&mut CssWriter::new(result)) 3556 .unwrap() 3557 } 3558 } 3559 3560 #[no_mangle] 3561 pub extern "C" fn Servo_FontFaceRule_CreateEmpty() -> Strong<LockedFontFaceRule> { 3562 // XXX This is not great. We should split FontFace descriptor data 3563 // from the rule, so that we don't need to create the rule like this 3564 // and the descriptor data itself can be hold in UniquePtr from the 3565 // Gecko side. See bug 1450904. 3566 with_maybe_worker_shared_lock(|lock| { 3567 Arc::new(lock.wrap(FontFaceRule::empty(SourceLocation { line: 0, column: 0 }))).into() 3568 }) 3569 } 3570 3571 #[no_mangle] 3572 pub unsafe extern "C" fn Servo_FontFaceRule_Clone( 3573 rule: &LockedFontFaceRule, 3574 ) -> Strong<LockedFontFaceRule> { 3575 let clone = read_locked_arc_worker(rule, |rule: &FontFaceRule| rule.clone()); 3576 with_maybe_worker_shared_lock(|lock| Arc::new(lock.wrap(clone)).into()) 3577 } 3578 3579 #[no_mangle] 3580 pub unsafe extern "C" fn Servo_FontFaceRule_Equals( 3581 a: &LockedFontFaceRule, 3582 b: &LockedFontFaceRule, 3583 ) -> bool { 3584 if a as *const _ == b as *const _ { 3585 return true; 3586 } 3587 read_locked_arc_worker(a, |a: &FontFaceRule| { 3588 read_locked_arc_worker(b, |b: &FontFaceRule| a == b) 3589 }) 3590 } 3591 3592 #[no_mangle] 3593 pub unsafe extern "C" fn Servo_FontFaceRule_GetSourceLocation( 3594 rule: &LockedFontFaceRule, 3595 line: *mut u32, 3596 column: *mut u32, 3597 ) { 3598 read_locked_arc_worker(rule, |rule: &FontFaceRule| { 3599 let location = rule.source_location; 3600 *line.as_mut().unwrap() = location.line as u32; 3601 *column.as_mut().unwrap() = location.column as u32; 3602 }); 3603 } 3604 3605 macro_rules! apply_font_desc_list { 3606 ($apply_macro:ident) => { 3607 $apply_macro! { 3608 valid: [ 3609 eCSSFontDesc_Family => family, 3610 eCSSFontDesc_Style => style, 3611 eCSSFontDesc_Weight => weight, 3612 eCSSFontDesc_Stretch => stretch, 3613 eCSSFontDesc_Src => sources, 3614 eCSSFontDesc_UnicodeRange => unicode_range, 3615 eCSSFontDesc_FontFeatureSettings => feature_settings, 3616 eCSSFontDesc_FontVariationSettings => variation_settings, 3617 eCSSFontDesc_FontLanguageOverride => language_override, 3618 eCSSFontDesc_Display => display, 3619 eCSSFontDesc_AscentOverride => ascent_override, 3620 eCSSFontDesc_DescentOverride => descent_override, 3621 eCSSFontDesc_LineGapOverride => line_gap_override, 3622 eCSSFontDesc_SizeAdjust => size_adjust, 3623 ] 3624 invalid: [ 3625 eCSSFontDesc_UNKNOWN, 3626 eCSSFontDesc_COUNT, 3627 ] 3628 } 3629 }; 3630 } 3631 3632 #[no_mangle] 3633 pub unsafe extern "C" fn Servo_FontFaceRule_Length(rule: &LockedFontFaceRule) -> u32 { 3634 read_locked_arc_worker(rule, |rule: &FontFaceRule| { 3635 let mut result = 0; 3636 macro_rules! count_values { 3637 ( 3638 valid: [$($v_enum_name:ident => $field:ident,)*] 3639 invalid: [$($i_enum_name:ident,)*] 3640 ) => { 3641 $(if rule.$field.is_some() { 3642 result += 1; 3643 })* 3644 } 3645 } 3646 apply_font_desc_list!(count_values); 3647 result 3648 }) 3649 } 3650 3651 #[no_mangle] 3652 pub unsafe extern "C" fn Servo_FontFaceRule_IndexGetter( 3653 rule: &LockedFontFaceRule, 3654 index: u32, 3655 ) -> nsCSSFontDesc { 3656 read_locked_arc_worker(rule, |rule: &FontFaceRule| { 3657 let mut count = 0; 3658 macro_rules! lookup_index { 3659 ( 3660 valid: [$($v_enum_name:ident => $field:ident,)*] 3661 invalid: [$($i_enum_name:ident,)*] 3662 ) => { 3663 $(if rule.$field.is_some() { 3664 count += 1; 3665 if count - 1 == index { 3666 return nsCSSFontDesc::$v_enum_name; 3667 } 3668 })* 3669 } 3670 } 3671 apply_font_desc_list!(lookup_index); 3672 return nsCSSFontDesc::eCSSFontDesc_UNKNOWN; 3673 }) 3674 } 3675 3676 #[no_mangle] 3677 pub unsafe extern "C" fn Servo_FontFaceRule_GetDeclCssText( 3678 rule: &LockedFontFaceRule, 3679 result: &mut nsACString, 3680 ) { 3681 read_locked_arc_worker(rule, |rule: &FontFaceRule| { 3682 rule.decl_to_css(result).unwrap(); 3683 }) 3684 } 3685 3686 macro_rules! simple_font_descriptor_getter_impl { 3687 ($rule:ident, $out:ident, $field:ident, $compute:ident) => { 3688 read_locked_arc_worker($rule, |rule: &FontFaceRule| { 3689 match rule.$field { 3690 None => return false, 3691 Some(ref f) => *$out = f.$compute(), 3692 } 3693 true 3694 }) 3695 }; 3696 } 3697 3698 #[no_mangle] 3699 pub extern "C" fn Servo_FontFaceRule_GetFontWeight( 3700 rule: &LockedFontFaceRule, 3701 out: &mut font_face::ComputedFontWeightRange, 3702 ) -> bool { 3703 simple_font_descriptor_getter_impl!(rule, out, weight, compute) 3704 } 3705 3706 #[no_mangle] 3707 pub extern "C" fn Servo_FontFaceRule_GetFontStretch( 3708 rule: &LockedFontFaceRule, 3709 out: &mut font_face::ComputedFontStretchRange, 3710 ) -> bool { 3711 simple_font_descriptor_getter_impl!(rule, out, stretch, compute) 3712 } 3713 3714 #[no_mangle] 3715 pub extern "C" fn Servo_FontFaceRule_GetFontStyle( 3716 rule: &LockedFontFaceRule, 3717 out: &mut font_face::ComputedFontStyleDescriptor, 3718 ) -> bool { 3719 simple_font_descriptor_getter_impl!(rule, out, style, compute) 3720 } 3721 3722 #[no_mangle] 3723 pub extern "C" fn Servo_FontFaceRule_GetFontDisplay( 3724 rule: &LockedFontFaceRule, 3725 out: &mut font_face::FontDisplay, 3726 ) -> bool { 3727 simple_font_descriptor_getter_impl!(rule, out, display, clone) 3728 } 3729 3730 #[no_mangle] 3731 pub extern "C" fn Servo_FontFaceRule_GetFontLanguageOverride( 3732 rule: &LockedFontFaceRule, 3733 out: &mut computed::FontLanguageOverride, 3734 ) -> bool { 3735 simple_font_descriptor_getter_impl!(rule, out, language_override, clone) 3736 } 3737 3738 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal' 3739 // rather than an actual percentage value. 3740 #[no_mangle] 3741 pub extern "C" fn Servo_FontFaceRule_GetAscentOverride( 3742 rule: &LockedFontFaceRule, 3743 out: &mut computed::Percentage, 3744 ) -> bool { 3745 simple_font_descriptor_getter_impl!(rule, out, ascent_override, compute) 3746 } 3747 3748 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal' 3749 // rather than an actual percentage value. 3750 #[no_mangle] 3751 pub extern "C" fn Servo_FontFaceRule_GetDescentOverride( 3752 rule: &LockedFontFaceRule, 3753 out: &mut computed::Percentage, 3754 ) -> bool { 3755 simple_font_descriptor_getter_impl!(rule, out, descent_override, compute) 3756 } 3757 3758 // Returns a Percentage of -1.0 if the override descriptor is present but 'normal' 3759 // rather than an actual percentage value. 3760 #[no_mangle] 3761 pub extern "C" fn Servo_FontFaceRule_GetLineGapOverride( 3762 rule: &LockedFontFaceRule, 3763 out: &mut computed::Percentage, 3764 ) -> bool { 3765 simple_font_descriptor_getter_impl!(rule, out, line_gap_override, compute) 3766 } 3767 3768 #[no_mangle] 3769 pub extern "C" fn Servo_FontFaceRule_GetSizeAdjust( 3770 rule: &LockedFontFaceRule, 3771 out: &mut computed::Percentage, 3772 ) -> bool { 3773 simple_font_descriptor_getter_impl!(rule, out, size_adjust, compute) 3774 } 3775 3776 #[no_mangle] 3777 pub unsafe extern "C" fn Servo_FontFaceRule_GetFamilyName( 3778 rule: &LockedFontFaceRule, 3779 ) -> *mut nsAtom { 3780 read_locked_arc_worker(rule, |rule: &FontFaceRule| { 3781 // TODO(emilio): font-family is a mandatory descriptor, can't we unwrap 3782 // here, and remove the null-checks in Gecko? 3783 rule.family 3784 .as_ref() 3785 .map_or(ptr::null_mut(), |f| f.name.as_ptr()) 3786 }) 3787 } 3788 3789 #[no_mangle] 3790 pub unsafe extern "C" fn Servo_FontFaceRule_GetUnicodeRanges( 3791 rule: &LockedFontFaceRule, 3792 out_len: *mut usize, 3793 ) -> *const UnicodeRange { 3794 *out_len = 0; 3795 read_locked_arc_worker(rule, |rule: &FontFaceRule| { 3796 let ranges = match rule.unicode_range { 3797 Some(ref ranges) => ranges, 3798 None => return ptr::null(), 3799 }; 3800 *out_len = ranges.len(); 3801 ranges.as_ptr() as *const _ 3802 }) 3803 } 3804 3805 #[no_mangle] 3806 pub unsafe extern "C" fn Servo_FontFaceRule_GetSources( 3807 rule: &LockedFontFaceRule, 3808 out: &mut nsTArray<FontFaceSourceListComponent>, 3809 ) { 3810 read_locked_arc_worker(rule, |rule: &FontFaceRule| { 3811 let sources = match rule.sources { 3812 Some(ref s) => s, 3813 None => return, 3814 }; 3815 3816 for source in sources.0.iter() { 3817 match *source { 3818 Source::Url(ref url) => { 3819 out.push(FontFaceSourceListComponent::Url(&url.url)); 3820 if let Some(hint) = &url.format_hint { 3821 match hint { 3822 FontFaceSourceFormat::Keyword(kw) => { 3823 out.push(FontFaceSourceListComponent::FormatHintKeyword(*kw)) 3824 }, 3825 FontFaceSourceFormat::String(s) => { 3826 out.push(FontFaceSourceListComponent::FormatHintString { 3827 length: s.len(), 3828 utf8_bytes: s.as_ptr(), 3829 }) 3830 }, 3831 } 3832 } 3833 if !url.tech_flags.is_empty() { 3834 out.push(FontFaceSourceListComponent::TechFlags(url.tech_flags)); 3835 } 3836 }, 3837 Source::Local(ref name) => { 3838 out.push(FontFaceSourceListComponent::Local(name.name.as_ptr())); 3839 }, 3840 } 3841 } 3842 }) 3843 } 3844 3845 #[no_mangle] 3846 pub unsafe extern "C" fn Servo_FontFaceRule_GetVariationSettings( 3847 rule: &LockedFontFaceRule, 3848 variations: &mut nsTArray<structs::gfxFontVariation>, 3849 ) { 3850 read_locked_arc_worker(rule, |rule: &FontFaceRule| { 3851 let source_variations = match rule.variation_settings { 3852 Some(ref v) => v, 3853 None => return, 3854 }; 3855 3856 variations.extend( 3857 source_variations 3858 .0 3859 .iter() 3860 .map(|source| structs::gfxFontVariation { 3861 mTag: source.tag.0, 3862 mValue: source.value.get(), 3863 }), 3864 ); 3865 }); 3866 } 3867 3868 #[no_mangle] 3869 pub unsafe extern "C" fn Servo_FontFaceRule_GetFeatureSettings( 3870 rule: &LockedFontFaceRule, 3871 features: &mut nsTArray<structs::gfxFontFeature>, 3872 ) { 3873 read_locked_arc_worker(rule, |rule: &FontFaceRule| { 3874 let source_features = match rule.feature_settings { 3875 Some(ref v) => v, 3876 None => return, 3877 }; 3878 3879 features.extend( 3880 source_features 3881 .0 3882 .iter() 3883 .map(|source| structs::gfxFontFeature { 3884 mTag: source.tag.0, 3885 mValue: source.value.value() as u32, 3886 }), 3887 ); 3888 }); 3889 } 3890 3891 #[no_mangle] 3892 pub extern "C" fn Servo_FontFaceRule_GetDescriptorCssText( 3893 rule: &LockedFontFaceRule, 3894 desc: nsCSSFontDesc, 3895 result: &mut nsACString, 3896 ) { 3897 read_locked_arc_worker(rule, |rule: &FontFaceRule| { 3898 let mut writer = CssWriter::new(result); 3899 macro_rules! to_css_text { 3900 ( 3901 valid: [$($v_enum_name:ident => $field:ident,)*] 3902 invalid: [$($i_enum_name:ident,)*] 3903 ) => { 3904 match desc { 3905 $( 3906 nsCSSFontDesc::$v_enum_name => { 3907 if let Some(ref value) = rule.$field { 3908 value.to_css(&mut writer).unwrap(); 3909 } 3910 } 3911 )* 3912 $( 3913 nsCSSFontDesc::$i_enum_name => { 3914 debug_assert!(false, "not a valid font descriptor"); 3915 } 3916 )* 3917 } 3918 } 3919 } 3920 apply_font_desc_list!(to_css_text) 3921 }) 3922 } 3923 3924 #[no_mangle] 3925 pub unsafe extern "C" fn Servo_FontFaceRule_SetDescriptor( 3926 rule: &LockedFontFaceRule, 3927 desc: nsCSSFontDesc, 3928 value: &nsACString, 3929 data: *mut URLExtraData, 3930 out_changed: *mut bool, 3931 ) -> bool { 3932 let value = value.as_str_unchecked(); 3933 let mut input = ParserInput::new(&value); 3934 let mut parser = Parser::new(&mut input); 3935 let url_data = UrlExtraData::from_ptr_ref(&data); 3936 let context = ParserContext::new( 3937 Origin::Author, 3938 url_data, 3939 Some(CssRuleType::FontFace), 3940 ParsingMode::DEFAULT, 3941 QuirksMode::NoQuirks, 3942 /* namespaces = */ Default::default(), 3943 None, 3944 None, 3945 ); 3946 3947 write_locked_arc_worker(rule, |rule: &mut FontFaceRule| { 3948 macro_rules! to_css_text { 3949 ( 3950 valid: [$($v_enum_name:ident => $field:ident,)*] 3951 invalid: [$($i_enum_name:ident,)*] 3952 ) => { 3953 match desc { 3954 $( 3955 nsCSSFontDesc::$v_enum_name => { 3956 if let Ok(value) = parser.parse_entirely(|i| Parse::parse(&context, i)) { 3957 let result = Some(value); 3958 *out_changed = result != rule.$field; 3959 rule.$field = result; 3960 true 3961 } else { 3962 false 3963 } 3964 } 3965 )* 3966 $( 3967 nsCSSFontDesc::$i_enum_name => { 3968 debug_assert!(false, "not a valid font descriptor"); 3969 false 3970 } 3971 )* 3972 } 3973 } 3974 } 3975 apply_font_desc_list!(to_css_text) 3976 }) 3977 } 3978 3979 #[no_mangle] 3980 pub unsafe extern "C" fn Servo_FontFaceRule_ResetDescriptor( 3981 rule: &LockedFontFaceRule, 3982 desc: nsCSSFontDesc, 3983 ) { 3984 write_locked_arc_worker(rule, |rule: &mut FontFaceRule| { 3985 macro_rules! reset_desc { 3986 ( 3987 valid: [$($v_enum_name:ident => $field:ident,)*] 3988 invalid: [$($i_enum_name:ident,)*] 3989 ) => { 3990 match desc { 3991 $(nsCSSFontDesc::$v_enum_name => rule.$field = None,)* 3992 $(nsCSSFontDesc::$i_enum_name => debug_assert!(false, "not a valid font descriptor"),)* 3993 } 3994 } 3995 } 3996 apply_font_desc_list!(reset_desc) 3997 }) 3998 } 3999 4000 #[no_mangle] 4001 pub unsafe extern "C" fn Servo_CounterStyleRule_GetName( 4002 rule: &LockedCounterStyleRule, 4003 ) -> *mut nsAtom { 4004 read_locked_arc(rule, |rule: &CounterStyleRule| rule.name().0.as_ptr()) 4005 } 4006 4007 #[no_mangle] 4008 pub unsafe extern "C" fn Servo_CounterStyleRule_SetName( 4009 rule: &LockedCounterStyleRule, 4010 value: &nsACString, 4011 ) -> bool { 4012 let value = value.as_str_unchecked(); 4013 let mut input = ParserInput::new(&value); 4014 let mut parser = Parser::new(&mut input); 4015 match parser.parse_entirely(counter_style::parse_counter_style_name_definition) { 4016 Ok(name) => { 4017 write_locked_arc(rule, |rule: &mut CounterStyleRule| rule.set_name(name)); 4018 true 4019 }, 4020 Err(_) => false, 4021 } 4022 } 4023 4024 #[no_mangle] 4025 pub unsafe extern "C" fn Servo_CounterStyleRule_GetGeneration( 4026 rule: &LockedCounterStyleRule, 4027 ) -> u32 { 4028 read_locked_arc(rule, |rule: &CounterStyleRule| rule.generation()) 4029 } 4030 4031 fn symbol_to_string(s: &counter_style::Symbol) -> nsString { 4032 match *s { 4033 counter_style::Symbol::String(ref s) => nsString::from(&**s), 4034 counter_style::Symbol::Ident(ref i) => nsString::from(i.0.as_slice()), 4035 } 4036 } 4037 4038 // TODO(emilio): Cbindgen could be used to simplify a bunch of code here. 4039 #[no_mangle] 4040 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPad( 4041 rule: &LockedCounterStyleRule, 4042 width: &mut i32, 4043 symbol: &mut nsString, 4044 ) -> bool { 4045 read_locked_arc(rule, |rule: &CounterStyleRule| { 4046 let pad = match rule.pad() { 4047 Some(pad) => pad, 4048 None => return false, 4049 }; 4050 *width = pad.0.value(); 4051 *symbol = symbol_to_string(&pad.1); 4052 true 4053 }) 4054 } 4055 4056 fn get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool { 4057 let s = match s { 4058 Some(s) => s, 4059 None => return false, 4060 }; 4061 *out = symbol_to_string(s); 4062 true 4063 } 4064 4065 #[no_mangle] 4066 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPrefix( 4067 rule: &LockedCounterStyleRule, 4068 out: &mut nsString, 4069 ) -> bool { 4070 read_locked_arc(rule, |rule: &CounterStyleRule| { 4071 get_symbol(rule.prefix(), out) 4072 }) 4073 } 4074 4075 #[no_mangle] 4076 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSuffix( 4077 rule: &LockedCounterStyleRule, 4078 out: &mut nsString, 4079 ) -> bool { 4080 read_locked_arc(rule, |rule: &CounterStyleRule| { 4081 get_symbol(rule.suffix(), out) 4082 }) 4083 } 4084 4085 #[no_mangle] 4086 pub unsafe extern "C" fn Servo_CounterStyleRule_GetNegative( 4087 rule: &LockedCounterStyleRule, 4088 prefix: &mut nsString, 4089 suffix: &mut nsString, 4090 ) -> bool { 4091 read_locked_arc(rule, |rule: &CounterStyleRule| { 4092 let negative = match rule.negative() { 4093 Some(n) => n, 4094 None => return false, 4095 }; 4096 *prefix = symbol_to_string(&negative.0); 4097 *suffix = match negative.1 { 4098 Some(ref s) => symbol_to_string(s), 4099 None => nsString::new(), 4100 }; 4101 true 4102 }) 4103 } 4104 4105 #[repr(u8)] 4106 pub enum IsOrdinalInRange { 4107 Auto, 4108 InRange, 4109 NotInRange, 4110 NoOrdinalSpecified, 4111 } 4112 4113 #[no_mangle] 4114 pub unsafe extern "C" fn Servo_CounterStyleRule_IsInRange( 4115 rule: &LockedCounterStyleRule, 4116 ordinal: i32, 4117 ) -> IsOrdinalInRange { 4118 use style::counter_style::CounterBound; 4119 read_locked_arc(rule, |rule: &CounterStyleRule| { 4120 let range = match rule.range() { 4121 Some(r) => r, 4122 None => return IsOrdinalInRange::NoOrdinalSpecified, 4123 }; 4124 4125 if range.0.is_empty() { 4126 return IsOrdinalInRange::Auto; 4127 } 4128 4129 let in_range = range.0.iter().any(|r| { 4130 if let CounterBound::Integer(start) = r.start { 4131 if start.value() > ordinal { 4132 return false; 4133 } 4134 } 4135 4136 if let CounterBound::Integer(end) = r.end { 4137 if end.value() < ordinal { 4138 return false; 4139 } 4140 } 4141 4142 true 4143 }); 4144 4145 if in_range { 4146 IsOrdinalInRange::InRange 4147 } else { 4148 IsOrdinalInRange::NotInRange 4149 } 4150 }) 4151 } 4152 4153 #[no_mangle] 4154 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols( 4155 rule: &LockedCounterStyleRule, 4156 count: &mut usize, 4157 ) -> *const counter_style::Symbol { 4158 read_locked_arc(rule, |rule: &CounterStyleRule| { 4159 let symbols = match rule.symbols() { 4160 Some(s) => &*s.0, 4161 None => &[], 4162 }; 4163 *count = symbols.len(); 4164 symbols.as_ptr() 4165 }) 4166 } 4167 4168 #[repr(C)] 4169 pub struct AdditiveSymbol { 4170 pub weight: i32, 4171 pub symbol: nsString, 4172 } 4173 4174 #[no_mangle] 4175 pub unsafe extern "C" fn Servo_CounterStyleRule_GetAdditiveSymbols( 4176 rule: &LockedCounterStyleRule, 4177 symbols: &mut style::OwnedSlice<AdditiveSymbol>, 4178 ) { 4179 read_locked_arc(rule, |rule: &CounterStyleRule| { 4180 *symbols = match rule.additive_symbols() { 4181 Some(s) => { 4182 s.0.iter() 4183 .map(|s| AdditiveSymbol { 4184 weight: s.weight.value(), 4185 symbol: symbol_to_string(&s.symbol), 4186 }) 4187 .collect() 4188 }, 4189 None => style::OwnedSlice::default(), 4190 }; 4191 }) 4192 } 4193 4194 #[repr(C, u8)] 4195 pub enum CounterSpeakAs { 4196 None, 4197 Auto, 4198 Bullets, 4199 Numbers, 4200 Words, 4201 Ident(*mut nsAtom), 4202 } 4203 4204 #[no_mangle] 4205 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSpeakAs( 4206 rule: &LockedCounterStyleRule, 4207 out: &mut CounterSpeakAs, 4208 ) { 4209 use style::counter_style::SpeakAs; 4210 *out = read_locked_arc(rule, |rule: &CounterStyleRule| { 4211 let speak_as = match rule.speak_as() { 4212 Some(s) => s, 4213 None => return CounterSpeakAs::None, 4214 }; 4215 match *speak_as { 4216 SpeakAs::Auto => CounterSpeakAs::Auto, 4217 SpeakAs::Bullets => CounterSpeakAs::Bullets, 4218 SpeakAs::Numbers => CounterSpeakAs::Numbers, 4219 SpeakAs::Words => CounterSpeakAs::Words, 4220 SpeakAs::Other(ref other) => CounterSpeakAs::Ident(other.0.as_ptr()), 4221 } 4222 }); 4223 } 4224 4225 #[repr(u8)] 4226 pub enum CounterSystem { 4227 Cyclic = 0, 4228 Numeric, 4229 Alphabetic, 4230 Symbolic, 4231 Additive, 4232 Fixed, 4233 Extends, 4234 } 4235 4236 #[no_mangle] 4237 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSystem( 4238 rule: &LockedCounterStyleRule, 4239 ) -> CounterSystem { 4240 use style::counter_style::System; 4241 read_locked_arc(rule, |rule: &CounterStyleRule| { 4242 match *rule.resolved_system() { 4243 System::Cyclic => CounterSystem::Cyclic, 4244 System::Numeric => CounterSystem::Numeric, 4245 System::Alphabetic => CounterSystem::Alphabetic, 4246 System::Symbolic => CounterSystem::Symbolic, 4247 System::Additive => CounterSystem::Additive, 4248 System::Fixed { .. } => CounterSystem::Fixed, 4249 System::Extends(_) => CounterSystem::Extends, 4250 } 4251 }) 4252 } 4253 4254 #[no_mangle] 4255 pub unsafe extern "C" fn Servo_CounterStyleRule_GetExtended( 4256 rule: &LockedCounterStyleRule, 4257 ) -> *mut nsAtom { 4258 read_locked_arc(rule, |rule: &CounterStyleRule| { 4259 match *rule.resolved_system() { 4260 counter_style::System::Extends(ref name) => name.0.as_ptr(), 4261 _ => { 4262 debug_assert!(false, "Not extends system"); 4263 ptr::null_mut() 4264 }, 4265 } 4266 }) 4267 } 4268 4269 #[no_mangle] 4270 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFixedFirstValue( 4271 rule: &LockedCounterStyleRule, 4272 ) -> i32 { 4273 read_locked_arc(rule, |rule: &CounterStyleRule| { 4274 match *rule.resolved_system() { 4275 counter_style::System::Fixed { first_symbol_value } => { 4276 first_symbol_value.map_or(1, |v| v.value()) 4277 }, 4278 _ => { 4279 debug_assert!(false, "Not fixed system"); 4280 0 4281 }, 4282 } 4283 }) 4284 } 4285 4286 #[no_mangle] 4287 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFallback( 4288 rule: &LockedCounterStyleRule, 4289 ) -> *mut nsAtom { 4290 read_locked_arc(rule, |rule: &CounterStyleRule| { 4291 rule.fallback().map_or(ptr::null_mut(), |i| i.0 .0.as_ptr()) 4292 }) 4293 } 4294 4295 macro_rules! counter_style_descriptors { 4296 { 4297 valid: [ 4298 $($desc:ident => $getter:ident / $setter:ident,)+ 4299 ] 4300 invalid: [ 4301 $($i_desc:ident,)+ 4302 ] 4303 } => { 4304 #[no_mangle] 4305 pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptorCssText( 4306 rule: &LockedCounterStyleRule, 4307 desc: nsCSSCounterDesc, 4308 result: &mut nsACString, 4309 ) { 4310 let mut writer = CssWriter::new(result); 4311 read_locked_arc(rule, |rule: &CounterStyleRule| { 4312 match desc { 4313 $(nsCSSCounterDesc::$desc => { 4314 if let Some(value) = rule.$getter() { 4315 value.to_css(&mut writer).unwrap(); 4316 } 4317 })+ 4318 $(nsCSSCounterDesc::$i_desc => unreachable!(),)+ 4319 } 4320 }); 4321 } 4322 4323 #[no_mangle] 4324 pub unsafe extern "C" fn Servo_CounterStyleRule_SetDescriptor( 4325 rule: &LockedCounterStyleRule, 4326 desc: nsCSSCounterDesc, 4327 value: &nsACString, 4328 ) -> bool { 4329 let value = value.as_str_unchecked(); 4330 let mut input = ParserInput::new(&value); 4331 let mut parser = Parser::new(&mut input); 4332 let url_data = dummy_url_data(); 4333 let context = ParserContext::new( 4334 Origin::Author, 4335 url_data, 4336 Some(CssRuleType::CounterStyle), 4337 ParsingMode::DEFAULT, 4338 QuirksMode::NoQuirks, 4339 /* namespaces = */ Default::default(), 4340 None, 4341 None, 4342 ); 4343 4344 write_locked_arc(rule, |rule: &mut CounterStyleRule| { 4345 match desc { 4346 $(nsCSSCounterDesc::$desc => { 4347 match parser.parse_entirely(|i| Parse::parse(&context, i)) { 4348 Ok(value) => rule.$setter(value), 4349 Err(_) => false, 4350 } 4351 })+ 4352 $(nsCSSCounterDesc::$i_desc => unreachable!(),)+ 4353 } 4354 }) 4355 } 4356 } 4357 } 4358 4359 counter_style_descriptors! { 4360 valid: [ 4361 eCSSCounterDesc_System => system / set_system, 4362 eCSSCounterDesc_Symbols => symbols / set_symbols, 4363 eCSSCounterDesc_AdditiveSymbols => additive_symbols / set_additive_symbols, 4364 eCSSCounterDesc_Negative => negative / set_negative, 4365 eCSSCounterDesc_Prefix => prefix / set_prefix, 4366 eCSSCounterDesc_Suffix => suffix / set_suffix, 4367 eCSSCounterDesc_Range => range / set_range, 4368 eCSSCounterDesc_Pad => pad / set_pad, 4369 eCSSCounterDesc_Fallback => fallback / set_fallback, 4370 eCSSCounterDesc_SpeakAs => speak_as / set_speak_as, 4371 ] 4372 invalid: [ 4373 eCSSCounterDesc_UNKNOWN, 4374 eCSSCounterDesc_COUNT, 4375 ] 4376 } 4377 4378 #[no_mangle] 4379 pub unsafe extern "C" fn Servo_PositionTryRule_GetName( 4380 rule: &LockedPositionTryRule, 4381 result: &mut nsACString, 4382 ) { 4383 read_locked_arc(rule, |rule: &PositionTryRule| { 4384 rule.name.to_css(&mut CssWriter::new(result)).unwrap() 4385 }); 4386 } 4387 4388 #[no_mangle] 4389 pub extern "C" fn Servo_PositionTryRule_GetStyle( 4390 rule: &LockedPositionTryRule, 4391 ) -> Strong<LockedDeclarationBlock> { 4392 read_locked_arc(rule, |rule: &PositionTryRule| rule.block.clone().into()) 4393 } 4394 4395 #[no_mangle] 4396 pub extern "C" fn Servo_PositionTryRule_SetStyle( 4397 rule: &LockedPositionTryRule, 4398 declarations: &LockedDeclarationBlock, 4399 ) { 4400 write_locked_arc(rule, |rule: &mut PositionTryRule| { 4401 rule.block = unsafe { Arc::from_raw_addrefed(declarations) }; 4402 }) 4403 } 4404 4405 #[no_mangle] 4406 pub unsafe extern "C" fn Servo_ComputedValues_GetForPageContent( 4407 raw_data: &PerDocumentStyleData, 4408 page_name: *const nsAtom, 4409 pseudos: PagePseudoClassFlags, 4410 ) -> Strong<ComputedValues> { 4411 let global_style_data = &*GLOBAL_STYLE_DATA; 4412 let guard = global_style_data.shared_lock.read(); 4413 let guards = StylesheetGuards::same(&guard); 4414 let data = raw_data.borrow_mut(); 4415 let cascade_data = data.stylist.cascade_data(); 4416 4417 let mut extra_declarations = vec![]; 4418 let iter = data.stylist.iter_extra_data_origins_rev(); 4419 let name = if !page_name.is_null() { 4420 Some(Atom::from_raw(page_name as *mut nsAtom)) 4421 } else { 4422 None 4423 }; 4424 for (data, origin) in iter { 4425 data.pages.match_and_append_rules( 4426 &mut extra_declarations, 4427 origin, 4428 &guards, 4429 cascade_data, 4430 &name, 4431 pseudos, 4432 ); 4433 } 4434 4435 let rule_node = data.stylist.rule_node_for_precomputed_pseudo( 4436 &guards, 4437 &PseudoElement::PageContent, 4438 extra_declarations, 4439 ); 4440 4441 data.stylist 4442 .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>( 4443 &guards, 4444 &PseudoElement::PageContent, 4445 None, 4446 rule_node, 4447 ) 4448 .into() 4449 } 4450 4451 #[no_mangle] 4452 pub unsafe extern "C" fn Servo_ComputedValues_GetForPositionTry( 4453 raw_data: &PerDocumentStyleData, 4454 style: &ComputedValues, 4455 element: &RawGeckoElement, 4456 fallback_item: &PositionTryFallbacksItem, 4457 ) -> Strong<ComputedValues> { 4458 let global_style_data = &*GLOBAL_STYLE_DATA; 4459 let guard = global_style_data.shared_lock.read(); 4460 let guards = StylesheetGuards::same(&guard); 4461 let element = GeckoElement(element); 4462 let data = raw_data.borrow(); 4463 data.stylist 4464 .resolve_position_try(style, &guards, element, fallback_item) 4465 .into() 4466 } 4467 4468 #[no_mangle] 4469 pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox( 4470 parent_style_or_null: Option<&ComputedValues>, 4471 pseudo: PseudoStyleType, 4472 raw_data: &PerDocumentStyleData, 4473 ) -> Strong<ComputedValues> { 4474 let pseudo = PseudoElement::from_pseudo_type(pseudo, None).unwrap(); 4475 debug_assert!(pseudo.is_anon_box()); 4476 debug_assert_ne!(pseudo, PseudoElement::PageContent); 4477 let global_style_data = &*GLOBAL_STYLE_DATA; 4478 let guard = global_style_data.shared_lock.read(); 4479 let guards = StylesheetGuards::same(&guard); 4480 let data = raw_data.borrow_mut(); 4481 let rule_node = data 4482 .stylist 4483 .rule_node_for_precomputed_pseudo(&guards, &pseudo, vec![]); 4484 4485 data.stylist 4486 .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>( 4487 &guards, 4488 &pseudo, 4489 parent_style_or_null.map(|x| &*x), 4490 rule_node, 4491 ) 4492 .into() 4493 } 4494 4495 fn get_functional_pseudo_parameter_atom( 4496 functional_pseudo_parameter: *mut nsAtom, 4497 ) -> Option<AtomIdent> { 4498 if functional_pseudo_parameter.is_null() { 4499 None 4500 } else { 4501 Some(AtomIdent::new(unsafe { 4502 Atom::from_raw(functional_pseudo_parameter) 4503 })) 4504 } 4505 } 4506 4507 #[no_mangle] 4508 pub extern "C" fn Servo_ResolvePseudoStyle( 4509 element: &RawGeckoElement, 4510 pseudo_type: PseudoStyleType, 4511 functional_pseudo_parameter: *mut nsAtom, 4512 is_probe: bool, 4513 inherited_style: Option<&ComputedValues>, 4514 raw_data: &PerDocumentStyleData, 4515 ) -> Strong<ComputedValues> { 4516 let element = GeckoElement(element); 4517 let doc_data = raw_data.borrow(); 4518 4519 debug!( 4520 "Servo_ResolvePseudoStyle: {:?} {:?}, is_probe: {}", 4521 element, 4522 PseudoElement::from_pseudo_type( 4523 pseudo_type, 4524 get_functional_pseudo_parameter_atom(functional_pseudo_parameter) 4525 ), 4526 is_probe 4527 ); 4528 4529 let data = element.borrow_data(); 4530 4531 let data = match data.as_ref() { 4532 Some(data) if data.has_styles() => data, 4533 _ => { 4534 // FIXME(bholley, emilio): Assert against this. 4535 // 4536 // Known offender is nsMathMLmoFrame::MarkIntrinsicISizesDirty, 4537 // which goes and does a bunch of work involving style resolution. 4538 // 4539 // Bug 1403865 tracks fixing it, and potentially adding an assert 4540 // here instead. 4541 warn!("Calling Servo_ResolvePseudoStyle on unstyled element"); 4542 return if is_probe { 4543 Strong::null() 4544 } else { 4545 doc_data.default_computed_values().clone().into() 4546 }; 4547 }, 4548 }; 4549 4550 let pseudo_element = PseudoElement::from_pseudo_type( 4551 pseudo_type, 4552 get_functional_pseudo_parameter_atom(functional_pseudo_parameter), 4553 ) 4554 .expect("ResolvePseudoStyle with a non-pseudo?"); 4555 4556 let matching_fn = |pseudo: &PseudoElement| *pseudo == pseudo_element; 4557 4558 let global_style_data = &*GLOBAL_STYLE_DATA; 4559 let guard = global_style_data.shared_lock.read(); 4560 let style = get_pseudo_style( 4561 &guard, 4562 element, 4563 &pseudo_element, 4564 RuleInclusion::All, 4565 &data.styles, 4566 inherited_style, 4567 &doc_data.stylist, 4568 is_probe, 4569 /* matching_func = */ 4570 if pseudo_element.is_highlight() { 4571 Some(&matching_fn) 4572 } else { 4573 None 4574 }, 4575 ); 4576 4577 match style { 4578 Some(s) => s.into(), 4579 None => { 4580 debug_assert!(is_probe); 4581 Strong::null() 4582 }, 4583 } 4584 } 4585 4586 fn debug_atom_array(atoms: &nsTArray<structs::RefPtr<nsAtom>>) -> String { 4587 let mut result = String::from("["); 4588 for atom in atoms.iter() { 4589 if atom.mRawPtr.is_null() { 4590 result += "(null), "; 4591 } else { 4592 let atom = unsafe { WeakAtom::new(atom.mRawPtr) }; 4593 write!(result, "{}, ", atom).unwrap(); 4594 } 4595 } 4596 result.push(']'); 4597 result 4598 } 4599 4600 #[no_mangle] 4601 pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle( 4602 element: &RawGeckoElement, 4603 pseudo_tag: *mut nsAtom, 4604 inherited_style: &ComputedValues, 4605 input_word: &nsTArray<structs::RefPtr<nsAtom>>, 4606 raw_data: &PerDocumentStyleData, 4607 ) -> Strong<ComputedValues> { 4608 let element = GeckoElement(element); 4609 let data = element 4610 .borrow_data() 4611 .expect("Calling ResolveXULTreePseudoStyle on unstyled element?"); 4612 4613 let pseudo = unsafe { 4614 Atom::with(pseudo_tag, |atom| { 4615 PseudoElement::from_tree_pseudo_atom(atom, Box::new([])) 4616 }) 4617 .expect("ResolveXULTreePseudoStyle with a non-tree pseudo?") 4618 }; 4619 let doc_data = raw_data.borrow(); 4620 4621 debug!( 4622 "ResolveXULTreePseudoStyle: {:?} {:?} {}", 4623 element, 4624 pseudo, 4625 debug_atom_array(input_word) 4626 ); 4627 4628 let matching_fn = |pseudo: &PseudoElement| { 4629 let args = pseudo 4630 .tree_pseudo_args() 4631 .expect("Not a tree pseudo-element?"); 4632 args.iter() 4633 .all(|atom| input_word.iter().any(|item| atom.as_ptr() == item.mRawPtr)) 4634 }; 4635 4636 let global_style_data = &*GLOBAL_STYLE_DATA; 4637 let guard = global_style_data.shared_lock.read(); 4638 get_pseudo_style( 4639 &guard, 4640 element, 4641 &pseudo, 4642 RuleInclusion::All, 4643 &data.styles, 4644 Some(inherited_style), 4645 &doc_data.stylist, 4646 /* is_probe = */ false, 4647 Some(&matching_fn), 4648 ) 4649 .unwrap() 4650 .into() 4651 } 4652 4653 #[no_mangle] 4654 pub extern "C" fn Servo_SetExplicitStyle(element: &RawGeckoElement, style: &ComputedValues) { 4655 let element = GeckoElement(element); 4656 debug!("Servo_SetExplicitStyle: {:?}", element); 4657 // We only support this API for initial styling. There's no reason it couldn't 4658 // work for other things, we just haven't had a reason to do so. 4659 debug_assert!(!element.has_data()); 4660 let mut data = unsafe { element.ensure_data() }; 4661 data.styles.primary = Some(unsafe { Arc::from_raw_addrefed(style) }); 4662 } 4663 4664 fn get_pseudo_style( 4665 guard: &SharedRwLockReadGuard, 4666 element: GeckoElement, 4667 pseudo: &PseudoElement, 4668 rule_inclusion: RuleInclusion, 4669 styles: &ElementStyles, 4670 inherited_styles: Option<&ComputedValues>, 4671 stylist: &Stylist, 4672 is_probe: bool, 4673 matching_func: Option<&dyn Fn(&PseudoElement) -> bool>, 4674 ) -> Option<Arc<ComputedValues>> { 4675 let style = match pseudo.cascade_type() { 4676 PseudoElementCascadeType::Eager => { 4677 match *pseudo { 4678 PseudoElement::FirstLetter => { 4679 styles.pseudos.get(&pseudo).map(|pseudo_styles| { 4680 // inherited_styles can be None when doing lazy resolution 4681 // (e.g. for computed style) or when probing. In that case 4682 // we just inherit from our element, which is what Gecko 4683 // does in that situation. What should actually happen in 4684 // the computed style case is a bit unclear. 4685 let inherited_styles = inherited_styles.unwrap_or(styles.primary()); 4686 let guards = StylesheetGuards::same(guard); 4687 let inputs = CascadeInputs::new_from_style(pseudo_styles); 4688 stylist.compute_pseudo_element_style_with_inputs( 4689 inputs, 4690 pseudo, 4691 &guards, 4692 Some(inherited_styles), 4693 Some(element), 4694 ) 4695 }) 4696 }, 4697 _ => { 4698 // Unfortunately, we can't assert that inherited_styles, if 4699 // present, is pointer-equal to styles.primary(), or even 4700 // equal in any meaningful way. The way it can fail is as 4701 // follows. Say we append an element with a ::before, 4702 // ::after, or ::first-line to a parent with a ::first-line, 4703 // such that the element ends up on the first line of the 4704 // parent (e.g. it's an inline-block in the case it has a 4705 // ::first-line, or any container in the ::before/::after 4706 // cases). Then gecko will update its frame's style to 4707 // inherit from the parent's ::first-line. The next time we 4708 // try to get the ::before/::after/::first-line style for 4709 // the kid, we'll likely pass in the frame's style as 4710 // inherited_styles, but that's not pointer-identical to 4711 // styles.primary(), because it got reparented. 4712 // 4713 // Now in practice this turns out to be OK, because all the 4714 // cases in which there's a mismatch go ahead and reparent 4715 // styles again as needed to make sure the ::first-line 4716 // affects all the things it should affect. But it makes it 4717 // impossible to assert anything about the two styles 4718 // matching here, unfortunately. 4719 styles.pseudos.get(&pseudo).cloned() 4720 }, 4721 } 4722 }, 4723 PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"), 4724 PseudoElementCascadeType::Lazy => { 4725 debug_assert!( 4726 inherited_styles.is_none() 4727 || ptr::eq(inherited_styles.unwrap(), &**styles.primary()) 4728 ); 4729 let originating_element_style = styles.primary(); 4730 let guards = StylesheetGuards::same(guard); 4731 stylist.lazily_compute_pseudo_element_style( 4732 &guards, 4733 element, 4734 &pseudo, 4735 rule_inclusion, 4736 originating_element_style, 4737 is_probe, 4738 matching_func, 4739 ) 4740 }, 4741 }; 4742 4743 if is_probe { 4744 return style; 4745 } 4746 4747 Some(style.unwrap_or_else(|| { 4748 StyleBuilder::for_inheritance( 4749 stylist.device(), 4750 Some(stylist), 4751 Some(styles.primary()), 4752 Some(pseudo), 4753 ) 4754 .build() 4755 })) 4756 } 4757 4758 #[no_mangle] 4759 pub unsafe extern "C" fn Servo_ComputedValues_Inherit( 4760 raw_data: &PerDocumentStyleData, 4761 pseudo: PseudoStyleType, 4762 parent_style_context: Option<&ComputedValues>, 4763 target: structs::InheritTarget, 4764 ) -> Strong<ComputedValues> { 4765 let data = raw_data.borrow(); 4766 4767 let for_text = target == structs::InheritTarget::Text; 4768 let pseudo = PseudoElement::from_pseudo_type(pseudo, None).unwrap(); 4769 debug_assert!(pseudo.is_anon_box()); 4770 4771 let mut style = StyleBuilder::for_inheritance( 4772 data.stylist.device(), 4773 Some(&data.stylist), 4774 parent_style_context, 4775 Some(&pseudo), 4776 ); 4777 4778 if for_text { 4779 StyleAdjuster::new(&mut style).adjust_for_text(); 4780 } 4781 4782 style.build().into() 4783 } 4784 4785 #[no_mangle] 4786 pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions( 4787 values: &ComputedValues, 4788 ) -> bool { 4789 let ui = values.get_ui(); 4790 ui.specifies_animations() || ui.specifies_transitions() 4791 } 4792 4793 #[repr(u8)] 4794 pub enum MatchingDeclarationBlockOrigin { 4795 UserAgent, 4796 User, 4797 Author, 4798 PresHints, 4799 PositionFallback, 4800 Animations, 4801 Transitions, 4802 SMIL, 4803 } 4804 4805 #[repr(C)] 4806 pub struct MatchingDeclarationBlock { 4807 block: *const LockedDeclarationBlock, 4808 origin: MatchingDeclarationBlockOrigin, 4809 } 4810 4811 #[no_mangle] 4812 pub extern "C" fn Servo_ComputedValues_GetMatchingDeclarations( 4813 values: &ComputedValues, 4814 rules: &mut nsTArray<MatchingDeclarationBlock>, 4815 ) { 4816 use style::rule_tree::CascadeLevel; 4817 let rule_node = match values.rules { 4818 Some(ref r) => r, 4819 None => return, 4820 }; 4821 4822 for node in rule_node.self_and_ancestors() { 4823 // For the rules with any important declaration, we insert them into 4824 // rule tree twice, one for normal level and another for important 4825 // level. So, we skip the important one to keep the specificity order of 4826 // rules. 4827 if node.importance().important() { 4828 continue; 4829 } 4830 4831 let Some(source) = node.style_source() else { 4832 continue; 4833 }; 4834 4835 let origin = match node.cascade_level() { 4836 CascadeLevel::UANormal | CascadeLevel::UAImportant => { 4837 MatchingDeclarationBlockOrigin::UserAgent 4838 }, 4839 CascadeLevel::UserNormal | CascadeLevel::UserImportant => { 4840 MatchingDeclarationBlockOrigin::User 4841 }, 4842 CascadeLevel::AuthorNormal { .. } | CascadeLevel::AuthorImportant { .. } => { 4843 MatchingDeclarationBlockOrigin::Author 4844 }, 4845 CascadeLevel::PositionFallback => MatchingDeclarationBlockOrigin::PositionFallback, 4846 CascadeLevel::PresHints => MatchingDeclarationBlockOrigin::PresHints, 4847 CascadeLevel::Animations => MatchingDeclarationBlockOrigin::Animations, 4848 CascadeLevel::Transitions => MatchingDeclarationBlockOrigin::Transitions, 4849 CascadeLevel::SMILOverride => MatchingDeclarationBlockOrigin::SMIL, 4850 }; 4851 4852 rules.push(MatchingDeclarationBlock { 4853 block: &**source.get(), 4854 origin, 4855 }); 4856 } 4857 } 4858 4859 /// println_stderr!() calls Gecko's printf_stderr(), which, unlike eprintln!(), 4860 /// will funnel output to Android logcat. 4861 #[cfg(feature = "gecko_debug")] 4862 macro_rules! println_stderr { 4863 ($($e:expr),+) => { 4864 { 4865 let mut s = nsCString::new(); 4866 write!(s, $($e),+).unwrap(); 4867 s.write_char('\n').unwrap(); 4868 unsafe { bindings::Gecko_PrintfStderr(&s); } 4869 } 4870 } 4871 } 4872 4873 #[cfg(feature = "gecko_debug")] 4874 fn dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet) { 4875 println_stderr!(" Properties:"); 4876 for p in properties.iter() { 4877 let mut v = nsCString::new(); 4878 cv.computed_or_resolved_value(p, None, &mut v).unwrap(); 4879 println_stderr!(" {:?}: {}", p, v); 4880 } 4881 dump_rules(cv); 4882 } 4883 4884 #[cfg(feature = "gecko_debug")] 4885 fn dump_rules(cv: &ComputedValues) { 4886 println_stderr!(" Rules({:?}):", cv.pseudo()); 4887 if let Some(rules) = cv.rules.as_ref() { 4888 for rn in rules.self_and_ancestors() { 4889 if rn.importance().important() { 4890 continue; 4891 } 4892 if let Some(d) = rn.style_source() { 4893 println_stderr!(" {:?}", d.get()); 4894 } 4895 } 4896 } 4897 } 4898 4899 #[cfg(feature = "gecko_debug")] 4900 #[no_mangle] 4901 pub extern "C" fn Servo_ComputedValues_EqualForCachedAnonymousContentStyle( 4902 a: &ComputedValues, 4903 b: &ComputedValues, 4904 ) -> bool { 4905 let mut differing_properties = a.differing_properties(b); 4906 4907 // Ignore any difference in -x-lang, which we can't override in the rules in scrollbars.css, 4908 // but which makes no difference for the anonymous content subtrees we cache style for. 4909 differing_properties.remove(LonghandId::XLang); 4910 // Similarly, -x-lang can influence the font-family fallback we have for the initial 4911 // font-family so remove it as well. 4912 differing_properties.remove(LonghandId::FontFamily); 4913 // We reset font-size to an explicit pixel value, and thus it can get affected by our inherited 4914 // effective zoom. But we don't care about it for the same reason as above. 4915 differing_properties.remove(LonghandId::FontSize); 4916 4917 // Ignore any difference in pref-controlled, inherited properties. These properties may or may 4918 // not be set by the 'all' declaration in scrollbars.css, depending on whether the pref was 4919 // enabled at the time the UA sheets were parsed. 4920 // 4921 // If you add a new pref-controlled, inherited property, it must be defined with 4922 // `has_effect_on_gecko_scrollbars=False` to declare that different values of this property on 4923 // a <scrollbar> element or its descendant scrollbar part elements should have no effect on 4924 // their rendering and behavior. 4925 // 4926 // If you do need a pref-controlled, inherited property to have an effect on these elements, 4927 // then you will need to add some checks to the 4928 // nsIAnonymousContentCreator::CreateAnonymousContent implementations of ScrollContainerFrame 4929 // and nsScrollbarFrame to clear the AnonymousContentKey if a non-initial value is used. 4930 differing_properties.remove_all(&LonghandIdSet::has_no_effect_on_gecko_scrollbars()); 4931 4932 if !differing_properties.is_empty() { 4933 println_stderr!("Actual style:"); 4934 dump_properties_and_rules(a, &differing_properties); 4935 println_stderr!("Expected style:"); 4936 dump_properties_and_rules(b, &differing_properties); 4937 } 4938 4939 differing_properties.is_empty() 4940 } 4941 4942 #[cfg(feature = "gecko_debug")] 4943 #[no_mangle] 4944 pub extern "C" fn Servo_ComputedValues_DumpMatchedRules(s: &ComputedValues) { 4945 dump_rules(s); 4946 } 4947 4948 #[no_mangle] 4949 pub extern "C" fn Servo_ComputedValues_BlockifiedDisplay( 4950 style: &ComputedValues, 4951 is_root_element: bool, 4952 ) -> u16 { 4953 let display = style.get_box().clone_display(); 4954 let blockified_display = display.equivalent_block_display(is_root_element); 4955 blockified_display.to_u16() 4956 } 4957 4958 #[no_mangle] 4959 pub extern "C" fn Servo_StyleSet_Init(doc: &structs::Document) -> *mut PerDocumentStyleData { 4960 let data = Box::new(PerDocumentStyleData::new(doc)); 4961 4962 // Do this here rather than in Servo_Initialize since we need a document to 4963 // get the default computed values from. 4964 style::properties::generated::gecko::assert_initial_values_match(&data); 4965 4966 Box::into_raw(data) as *mut PerDocumentStyleData 4967 } 4968 4969 #[no_mangle] 4970 pub unsafe extern "C" fn Servo_StyleSet_Drop(data: *mut PerDocumentStyleData) { 4971 let _ = Box::from_raw(data); 4972 } 4973 4974 #[no_mangle] 4975 pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: &PerDocumentStyleData) { 4976 let mut data = raw_data.borrow_mut(); 4977 data.stylist.device_mut().rebuild_cached_data(); 4978 data.undisplayed_style_cache.clear(); 4979 } 4980 4981 #[no_mangle] 4982 pub unsafe extern "C" fn Servo_StyleSet_CompatModeChanged(raw_data: &PerDocumentStyleData) { 4983 let mut data = raw_data.borrow_mut(); 4984 let quirks_mode = data.stylist.device().document().mCompatMode; 4985 data.stylist.set_quirks_mode(quirks_mode.into()); 4986 } 4987 4988 fn parse_property_into( 4989 declarations: &mut SourcePropertyDeclaration, 4990 property_id: PropertyId, 4991 value: &nsACString, 4992 origin: Origin, 4993 url_data: &UrlExtraData, 4994 parsing_mode: ParsingMode, 4995 quirks_mode: QuirksMode, 4996 rule_type: CssRuleType, 4997 reporter: Option<&dyn ParseErrorReporter>, 4998 ) -> Result<(), ()> { 4999 let value = unsafe { value.as_str_unchecked() }; 5000 5001 if let Some(non_custom) = property_id.non_custom_id() { 5002 if !non_custom.allowed_in_rule(rule_type.into()) { 5003 return Err(()); 5004 } 5005 } 5006 5007 parse_one_declaration_into( 5008 declarations, 5009 property_id, 5010 value, 5011 origin, 5012 url_data, 5013 reporter, 5014 parsing_mode, 5015 quirks_mode, 5016 rule_type, 5017 ) 5018 } 5019 5020 #[no_mangle] 5021 pub unsafe extern "C" fn Servo_ParseProperty( 5022 property: &structs::CSSPropertyId, 5023 value: &nsACString, 5024 data: *mut URLExtraData, 5025 parsing_mode: ParsingMode, 5026 quirks_mode: nsCompatibility, 5027 loader: *mut Loader, 5028 rule_type: CssRuleType, 5029 ) -> Strong<LockedDeclarationBlock> { 5030 let id = get_property_id_from_csspropertyid!(property, Strong::null()); 5031 let mut declarations = SourcePropertyDeclaration::default(); 5032 let reporter = ErrorReporter::new(ptr::null_mut(), loader, data); 5033 let data = UrlExtraData::from_ptr_ref(&data); 5034 let result = parse_property_into( 5035 &mut declarations, 5036 id, 5037 value, 5038 Origin::Author, 5039 data, 5040 parsing_mode, 5041 quirks_mode.into(), 5042 rule_type, 5043 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter), 5044 ); 5045 5046 match result { 5047 Ok(()) => { 5048 let global_style_data = &*GLOBAL_STYLE_DATA; 5049 let mut block = PropertyDeclarationBlock::new(); 5050 block.extend(declarations.drain(), Importance::Normal); 5051 Arc::new(global_style_data.shared_lock.wrap(block)).into() 5052 }, 5053 Err(_) => Strong::null(), 5054 } 5055 } 5056 5057 #[no_mangle] 5058 pub extern "C" fn Servo_ParseEasing( 5059 easing: &nsACString, 5060 output: &mut ComputedTimingFunction, 5061 ) -> bool { 5062 use style::properties::longhands::transition_timing_function; 5063 5064 let context = ParserContext::new( 5065 Origin::Author, 5066 unsafe { dummy_url_data() }, 5067 Some(CssRuleType::Style), 5068 ParsingMode::DEFAULT, 5069 QuirksMode::NoQuirks, 5070 /* namespaces = */ Default::default(), 5071 None, 5072 None, 5073 ); 5074 let easing = easing.to_string(); 5075 let mut input = ParserInput::new(&easing); 5076 let mut parser = Parser::new(&mut input); 5077 let result = 5078 parser.parse_entirely(|p| transition_timing_function::single_value::parse(&context, p)); 5079 match result { 5080 Ok(parsed_easing) => { 5081 *output = parsed_easing.to_computed_value_without_context(); 5082 true 5083 }, 5084 Err(_) => false, 5085 } 5086 } 5087 5088 #[no_mangle] 5089 pub extern "C" fn Servo_SerializeEasing(easing: &ComputedTimingFunction, output: &mut nsACString) { 5090 easing.to_css(&mut CssWriter::new(output)).unwrap(); 5091 } 5092 5093 #[no_mangle] 5094 pub extern "C" fn Servo_GetProperties_Overriding_Animation( 5095 element: &RawGeckoElement, 5096 list: &nsTArray<NonCustomCSSPropertyId>, 5097 set: &mut structs::nsCSSPropertyIDSet, 5098 ) { 5099 let element = GeckoElement(element); 5100 let element_data = match element.borrow_data() { 5101 Some(data) => data, 5102 None => return, 5103 }; 5104 let global_style_data = &*GLOBAL_STYLE_DATA; 5105 let guard = global_style_data.shared_lock.read(); 5106 let guards = StylesheetGuards::same(&guard); 5107 let (overridden, custom) = element_data 5108 .styles 5109 .primary() 5110 .rules() 5111 .get_properties_overriding_animations(&guards); 5112 for p in list.iter() { 5113 match NonCustomPropertyId::from_noncustomcsspropertyid(*p) { 5114 Some(property) => { 5115 if let Some(id) = property.as_longhand() { 5116 if overridden.contains(id) { 5117 unsafe { Gecko_AddPropertyToSet(set, *p) }; 5118 } 5119 } 5120 }, 5121 None => { 5122 if *p == NonCustomCSSPropertyId::eCSSPropertyExtra_variable && custom { 5123 unsafe { Gecko_AddPropertyToSet(set, *p) }; 5124 } 5125 }, 5126 } 5127 } 5128 } 5129 5130 #[no_mangle] 5131 pub extern "C" fn Servo_MatrixTransform_Operate( 5132 interpolate: bool, 5133 from: &structs::Matrix4x4Components, 5134 to: &structs::Matrix4x4Components, 5135 progress: f64, 5136 output: &mut structs::Matrix4x4Components, 5137 ) { 5138 use style::values::computed::transform::Matrix3D; 5139 5140 let from = Matrix3D::from(from); 5141 let to = Matrix3D::from(to); 5142 let proc = if interpolate { 5143 Procedure::Interpolate { progress } 5144 } else { 5145 Procedure::Accumulate { 5146 count: progress as u64, 5147 } 5148 }; 5149 let result = from.animate(&to, proc); 5150 if let Ok(result) = result { 5151 *output = result.into(); 5152 } else if progress < 0.5 { 5153 *output = from.clone().into(); 5154 } else { 5155 *output = to.clone().into(); 5156 } 5157 } 5158 5159 #[no_mangle] 5160 pub unsafe extern "C" fn Servo_ParseStyleAttribute( 5161 data: &nsACString, 5162 raw_extra_data: *mut URLExtraData, 5163 quirks_mode: nsCompatibility, 5164 loader: *mut Loader, 5165 rule_type: CssRuleType, 5166 ) -> Strong<LockedDeclarationBlock> { 5167 let global_style_data = &*GLOBAL_STYLE_DATA; 5168 let value = data.as_str_unchecked(); 5169 let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data); 5170 let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data); 5171 Arc::new(global_style_data.shared_lock.wrap(parse_style_attribute( 5172 value, 5173 url_data, 5174 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter), 5175 quirks_mode.into(), 5176 rule_type, 5177 ))) 5178 .into() 5179 } 5180 5181 #[no_mangle] 5182 pub extern "C" fn Servo_ParsePseudoElement( 5183 data: &nsAString, 5184 request: &mut structs::PseudoStyleRequest, /* output */ 5185 ) -> bool { 5186 let string = data.to_string(); 5187 let mut input = ParserInput::new(&string); 5188 let mut parser = Parser::new(&mut input); 5189 // This is unspecced, but we'd like to match other browsers' behavior, so we reject the 5190 // preceding whitespaces and trailing whitespaces. 5191 // FIXME: Bug 1845712. Figure out if it is necessary to reject preceding and trailing 5192 // whitespaces. 5193 if parser.try_parse(|i| i.expect_whitespace()).is_ok() { 5194 return false; 5195 } 5196 let Ok(pseudo) = PseudoElement::parse_ignore_enabled_state(&mut parser) else { 5197 return false; 5198 }; 5199 // The trailing tokens are not allowed, including whitespaces. 5200 if parser.next_including_whitespace().is_ok() { 5201 return false; 5202 } 5203 5204 let (pseudo_type, name) = pseudo.pseudo_type_and_argument(); 5205 let name_ptr = name.map_or(std::ptr::null_mut(), |name| name.as_ptr()); 5206 request.mType = pseudo_type; 5207 request.mIdentifier = unsafe { RefPtr::new(name_ptr).forget() }; 5208 5209 true 5210 } 5211 5212 #[no_mangle] 5213 pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> Strong<LockedDeclarationBlock> { 5214 let global_style_data = &*GLOBAL_STYLE_DATA; 5215 Arc::new( 5216 global_style_data 5217 .shared_lock 5218 .wrap(PropertyDeclarationBlock::new()), 5219 ) 5220 .into() 5221 } 5222 5223 #[no_mangle] 5224 pub extern "C" fn Servo_DeclarationBlock_Clear(declarations: &LockedDeclarationBlock) { 5225 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 5226 decls.clear(); 5227 }); 5228 } 5229 5230 #[no_mangle] 5231 pub extern "C" fn Servo_DeclarationBlock_Clone( 5232 declarations: &LockedDeclarationBlock, 5233 ) -> Strong<LockedDeclarationBlock> { 5234 let global_style_data = &*GLOBAL_STYLE_DATA; 5235 let guard = global_style_data.shared_lock.read(); 5236 Arc::new( 5237 global_style_data 5238 .shared_lock 5239 .wrap(declarations.read_with(&guard).clone()), 5240 ) 5241 .into() 5242 } 5243 5244 #[no_mangle] 5245 pub extern "C" fn Servo_DeclarationBlock_Equals( 5246 a: &LockedDeclarationBlock, 5247 b: &LockedDeclarationBlock, 5248 ) -> bool { 5249 let global_style_data = &*GLOBAL_STYLE_DATA; 5250 let guard = global_style_data.shared_lock.read(); 5251 a.read_with(&guard).declarations() == b.read_with(&guard).declarations() 5252 } 5253 5254 #[no_mangle] 5255 pub extern "C" fn Servo_DeclarationBlock_GetCssText( 5256 declarations: &LockedDeclarationBlock, 5257 result: &mut nsACString, 5258 ) { 5259 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { 5260 decls.to_css(result).unwrap() 5261 }) 5262 } 5263 5264 #[no_mangle] 5265 pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue( 5266 decls: &LockedDeclarationBlock, 5267 property_id: &structs::CSSPropertyId, 5268 buffer: &mut nsACString, 5269 computed_values: Option<&ComputedValues>, 5270 data: &PerDocumentStyleData, 5271 ) { 5272 let property_id = get_property_id_from_csspropertyid!(property_id, ()); 5273 5274 let global_style_data = &*GLOBAL_STYLE_DATA; 5275 let guard = global_style_data.shared_lock.read(); 5276 let data = data.borrow(); 5277 let rv = decls.read_with(&guard).single_value_to_css( 5278 &property_id, 5279 buffer, 5280 computed_values, 5281 &data.stylist, 5282 ); 5283 debug_assert!(rv.is_ok()); 5284 } 5285 5286 #[no_mangle] 5287 pub unsafe extern "C" fn Servo_SerializeFontValueForCanvas( 5288 declarations: &LockedDeclarationBlock, 5289 buffer: &mut nsACString, 5290 ) { 5291 use style::properties::shorthands::font; 5292 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { 5293 let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) { 5294 Ok(l) => l, 5295 Err(()) => { 5296 warn!("Unexpected property!"); 5297 return; 5298 }, 5299 }; 5300 5301 let rv = longhands.to_css(&mut CssWriter::new(buffer)); 5302 debug_assert!(rv.is_ok()); 5303 }) 5304 } 5305 5306 #[no_mangle] 5307 pub extern "C" fn Servo_DeclarationBlock_Count(declarations: &LockedDeclarationBlock) -> u32 { 5308 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { 5309 decls.declarations().len() as u32 5310 }) 5311 } 5312 5313 #[no_mangle] 5314 pub extern "C" fn Servo_DeclarationBlock_GetNthProperty( 5315 declarations: &LockedDeclarationBlock, 5316 index: u32, 5317 result: &mut nsACString, 5318 ) -> bool { 5319 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { 5320 if let Some(decl) = decls.declarations().get(index as usize) { 5321 result.assign(&decl.id().name()); 5322 true 5323 } else { 5324 false 5325 } 5326 }) 5327 } 5328 5329 macro_rules! get_property_id_from_property { 5330 ($property: ident, $ret: expr) => {{ 5331 let property = $property.as_str_unchecked(); 5332 match PropertyId::parse_enabled_for_all_content(property) { 5333 Ok(property_id) => property_id, 5334 Err(_) => return $ret, 5335 } 5336 }}; 5337 } 5338 5339 unsafe fn get_property_value( 5340 declarations: &LockedDeclarationBlock, 5341 property_id: PropertyId, 5342 value: &mut nsACString, 5343 ) { 5344 // This callsite is hot enough that the lock acquisition shows up in profiles. 5345 // Using an unchecked read here improves our performance by ~10% on the 5346 // microbenchmark in bug 1355599. 5347 read_locked_arc_unchecked(declarations, |decls: &PropertyDeclarationBlock| { 5348 decls.property_value_to_css(&property_id, value).unwrap(); 5349 }) 5350 } 5351 5352 #[no_mangle] 5353 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValue( 5354 declarations: &LockedDeclarationBlock, 5355 property: &nsACString, 5356 value: &mut nsACString, 5357 ) { 5358 get_property_value( 5359 declarations, 5360 get_property_id_from_property!(property, ()), 5361 value, 5362 ) 5363 } 5364 5365 #[no_mangle] 5366 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValueByNonCustomId( 5367 declarations: &LockedDeclarationBlock, 5368 property_id: NonCustomCSSPropertyId, 5369 value: &mut nsACString, 5370 ) { 5371 get_property_value( 5372 declarations, 5373 get_property_id_from_noncustomcsspropertyid!(property_id, ()), 5374 value, 5375 ) 5376 } 5377 5378 #[no_mangle] 5379 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValueById( 5380 declarations: &LockedDeclarationBlock, 5381 property_id: &structs::CSSPropertyId, 5382 value: &mut nsACString, 5383 ) { 5384 get_property_value( 5385 declarations, 5386 get_property_id_from_csspropertyid!(property_id, ()), 5387 value, 5388 ) 5389 } 5390 5391 #[no_mangle] 5392 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant( 5393 declarations: &LockedDeclarationBlock, 5394 property: &nsACString, 5395 ) -> bool { 5396 let property_id = get_property_id_from_property!(property, false); 5397 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { 5398 decls.property_priority(&property_id).important() 5399 }) 5400 } 5401 5402 /// A FFI-friendly counterpart to [`PropertyTypedValue`]. 5403 /// 5404 /// This type is returned across the Rust <-> C++ boundary. It mirrors 5405 /// [`PropertyTypedValue`], but with one important difference: 5406 /// 5407 /// * Internally, [`PropertyTypedValue::Unsupported`] is just a marker. 5408 /// * Here, `PropertyTypedValueResult::Unsupported` carries a 5409 /// `Strong<LockedDeclarationBlock>`. 5410 /// This is mostly because `cbindgen` currently cannot generate right bindings 5411 /// for `Arc<Locked<PropertyDeclarationBlock>>` inside the Rust enum. 5412 #[repr(C)] 5413 pub enum PropertyTypedValueResult { 5414 /// The property is not present in the declaration block. 5415 None, 5416 5417 /// The property exists but cannot be expressed as a `TypedValue`. 5418 /// 5419 /// Used for shorthands and other unrepresentable cases. In this case, the 5420 /// full declaration block is returned so that a corresponding 5421 /// `CSSUnsupportedValue` object can be created and tied to the property. 5422 Unsupported(Strong<LockedDeclarationBlock>), 5423 5424 /// The property was successfully reified into a `TypedValue`. 5425 Typed(TypedValue), 5426 } 5427 5428 #[no_mangle] 5429 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyTypedValue( 5430 declarations: &LockedDeclarationBlock, 5431 property: &nsACString, 5432 result: *mut PropertyTypedValueResult, 5433 ) -> bool { 5434 let property_id = get_property_id_from_property!(property, false); 5435 5436 *result = read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { 5437 let property_typed_value = decls.property_value_to_typed(&property_id); 5438 5439 match property_typed_value { 5440 PropertyTypedValue::None => PropertyTypedValueResult::None, 5441 5442 PropertyTypedValue::Unsupported => { 5443 let global_style_data = &*GLOBAL_STYLE_DATA; 5444 PropertyTypedValueResult::Unsupported( 5445 Arc::new(global_style_data.shared_lock.wrap(decls.clone())).into(), 5446 ) 5447 }, 5448 5449 PropertyTypedValue::Typed(typed_value) => PropertyTypedValueResult::Typed(typed_value), 5450 } 5451 }); 5452 5453 true 5454 } 5455 5456 #[inline(always)] 5457 fn set_property_to_declarations( 5458 non_custom_property_id: Option<NonCustomPropertyId>, 5459 block: &LockedDeclarationBlock, 5460 parsed_declarations: &mut SourcePropertyDeclaration, 5461 before_change_closure: DeclarationBlockMutationClosure, 5462 importance: Importance, 5463 ) -> bool { 5464 let mut updates = Default::default(); 5465 let will_change = read_locked_arc(block, |decls: &PropertyDeclarationBlock| { 5466 decls.prepare_for_update(&parsed_declarations, importance, &mut updates) 5467 }); 5468 if !will_change { 5469 return false; 5470 } 5471 5472 before_change_closure.invoke(non_custom_property_id); 5473 write_locked_arc(block, |decls: &mut PropertyDeclarationBlock| { 5474 decls.update(parsed_declarations.drain(), importance, &mut updates) 5475 }); 5476 true 5477 } 5478 5479 fn set_property( 5480 declarations: &LockedDeclarationBlock, 5481 property_id: PropertyId, 5482 value: &nsACString, 5483 is_important: bool, 5484 data: &UrlExtraData, 5485 parsing_mode: ParsingMode, 5486 quirks_mode: QuirksMode, 5487 loader: *mut Loader, 5488 rule_type: CssRuleType, 5489 before_change_closure: DeclarationBlockMutationClosure, 5490 ) -> bool { 5491 let mut source_declarations = SourcePropertyDeclaration::default(); 5492 let reporter = ErrorReporter::new(ptr::null_mut(), loader, data.ptr()); 5493 let non_custom_property_id = property_id.non_custom_id(); 5494 let result = parse_property_into( 5495 &mut source_declarations, 5496 property_id, 5497 value, 5498 Origin::Author, 5499 data, 5500 parsing_mode, 5501 quirks_mode, 5502 rule_type, 5503 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter), 5504 ); 5505 5506 if result.is_err() { 5507 return false; 5508 } 5509 5510 let importance = if is_important { 5511 Importance::Important 5512 } else { 5513 Importance::Normal 5514 }; 5515 5516 set_property_to_declarations( 5517 non_custom_property_id, 5518 declarations, 5519 &mut source_declarations, 5520 before_change_closure, 5521 importance, 5522 ) 5523 } 5524 5525 #[no_mangle] 5526 pub unsafe extern "C" fn Servo_DeclarationBlock_SanitizeForCanvas( 5527 declarations: &LockedDeclarationBlock, 5528 ) { 5529 use style::properties::PropertyDeclaration; 5530 use style::values::specified::{LineHeight, XTextScale, Zoom}; 5531 // From canvas spec, force to set line-height property to 'normal' font property. 5532 // Also, for compat, disable text scaling and CSS zoom. 5533 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 5534 decls.push( 5535 PropertyDeclaration::LineHeight(LineHeight::Normal), 5536 Importance::Normal, 5537 ); 5538 decls.push( 5539 PropertyDeclaration::Zoom(Zoom::Document), 5540 Importance::Normal, 5541 ); 5542 decls.push( 5543 PropertyDeclaration::XTextScale(XTextScale::None), 5544 Importance::Normal, 5545 ); 5546 }); 5547 } 5548 5549 #[no_mangle] 5550 pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty( 5551 declarations: &LockedDeclarationBlock, 5552 property: &nsACString, 5553 value: &nsACString, 5554 is_important: bool, 5555 data: *mut URLExtraData, 5556 parsing_mode: ParsingMode, 5557 quirks_mode: nsCompatibility, 5558 loader: *mut Loader, 5559 rule_type: CssRuleType, 5560 before_change_closure: DeclarationBlockMutationClosure, 5561 ) -> bool { 5562 set_property( 5563 declarations, 5564 get_property_id_from_property!(property, false), 5565 value, 5566 is_important, 5567 UrlExtraData::from_ptr_ref(&data), 5568 parsing_mode, 5569 quirks_mode.into(), 5570 loader, 5571 rule_type, 5572 before_change_closure, 5573 ) 5574 } 5575 5576 #[no_mangle] 5577 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue( 5578 declarations: &LockedDeclarationBlock, 5579 animation_value: &AnimationValue, 5580 before_change_closure: DeclarationBlockMutationClosure, 5581 ) -> bool { 5582 let non_custom_property_id = match animation_value.id() { 5583 PropertyDeclarationId::Longhand(id) => Some(id.into()), 5584 PropertyDeclarationId::Custom(_) => None, 5585 }; 5586 let mut source_declarations = SourcePropertyDeclaration::with_one(animation_value.uncompute()); 5587 5588 set_property_to_declarations( 5589 non_custom_property_id, 5590 declarations, 5591 &mut source_declarations, 5592 before_change_closure, 5593 Importance::Normal, 5594 ) 5595 } 5596 5597 #[no_mangle] 5598 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById( 5599 declarations: &LockedDeclarationBlock, 5600 property: NonCustomCSSPropertyId, 5601 value: &nsACString, 5602 is_important: bool, 5603 data: *mut URLExtraData, 5604 parsing_mode: ParsingMode, 5605 quirks_mode: nsCompatibility, 5606 loader: *mut Loader, 5607 rule_type: CssRuleType, 5608 before_change_closure: DeclarationBlockMutationClosure, 5609 ) -> bool { 5610 set_property( 5611 declarations, 5612 get_property_id_from_noncustomcsspropertyid!(property, false), 5613 value, 5614 is_important, 5615 UrlExtraData::from_ptr_ref(&data), 5616 parsing_mode, 5617 quirks_mode.into(), 5618 loader, 5619 rule_type, 5620 before_change_closure, 5621 ) 5622 } 5623 5624 fn remove_property( 5625 declarations: &LockedDeclarationBlock, 5626 property_id: PropertyId, 5627 before_change_closure: DeclarationBlockMutationClosure, 5628 ) -> bool { 5629 let first_declaration = read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { 5630 decls.first_declaration_to_remove(&property_id) 5631 }); 5632 5633 let first_declaration = match first_declaration { 5634 Some(i) => i, 5635 None => return false, 5636 }; 5637 5638 before_change_closure.invoke(property_id.non_custom_id()); 5639 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 5640 decls.remove_property(&property_id, first_declaration) 5641 }); 5642 5643 true 5644 } 5645 5646 #[no_mangle] 5647 pub unsafe extern "C" fn Servo_DeclarationBlock_RemoveProperty( 5648 declarations: &LockedDeclarationBlock, 5649 property: &nsACString, 5650 before_change_closure: DeclarationBlockMutationClosure, 5651 ) -> bool { 5652 remove_property( 5653 declarations, 5654 get_property_id_from_property!(property, false), 5655 before_change_closure, 5656 ) 5657 } 5658 5659 #[no_mangle] 5660 pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById( 5661 declarations: &LockedDeclarationBlock, 5662 property: NonCustomCSSPropertyId, 5663 before_change_closure: DeclarationBlockMutationClosure, 5664 ) -> bool { 5665 remove_property( 5666 declarations, 5667 get_property_id_from_noncustomcsspropertyid!(property, false), 5668 before_change_closure, 5669 ) 5670 } 5671 5672 #[no_mangle] 5673 pub extern "C" fn Servo_MediaList_Create() -> Strong<LockedMediaList> { 5674 let global_style_data = &*GLOBAL_STYLE_DATA; 5675 Arc::new(global_style_data.shared_lock.wrap(MediaList::empty())).into() 5676 } 5677 5678 #[no_mangle] 5679 pub extern "C" fn Servo_MediaList_DeepClone(list: &LockedMediaList) -> Strong<LockedMediaList> { 5680 let global_style_data = &*GLOBAL_STYLE_DATA; 5681 read_locked_arc(list, |list: &MediaList| { 5682 Arc::new(global_style_data.shared_lock.wrap(list.clone())).into() 5683 }) 5684 } 5685 5686 #[no_mangle] 5687 pub extern "C" fn Servo_MediaList_Matches( 5688 list: &LockedMediaList, 5689 raw_data: &PerDocumentStyleData, 5690 ) -> bool { 5691 let per_doc_data = raw_data.borrow(); 5692 read_locked_arc(list, |list: &MediaList| { 5693 list.evaluate( 5694 per_doc_data.stylist.device(), 5695 per_doc_data.stylist.quirks_mode(), 5696 &mut CustomMediaEvaluator::none(), 5697 ) 5698 }) 5699 } 5700 5701 #[no_mangle] 5702 pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword( 5703 declarations: &LockedDeclarationBlock, 5704 property: NonCustomCSSPropertyId, 5705 ) -> bool { 5706 let property_id = get_property_id_from_noncustomcsspropertyid!(property, false); 5707 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { 5708 decls.has_css_wide_keyword(&property_id) 5709 }) 5710 } 5711 5712 #[no_mangle] 5713 pub extern "C" fn Servo_MediaList_GetText(list: &LockedMediaList, result: &mut nsACString) { 5714 read_locked_arc(list, |list: &MediaList| { 5715 list.to_css(&mut CssWriter::new(result)).unwrap(); 5716 }) 5717 } 5718 5719 #[no_mangle] 5720 pub unsafe extern "C" fn Servo_MediaList_SetText( 5721 list: &LockedMediaList, 5722 text: &nsACString, 5723 caller_type: CallerType, 5724 ) { 5725 let text = text.as_str_unchecked(); 5726 5727 let mut input = ParserInput::new(&text); 5728 let mut parser = Parser::new(&mut input); 5729 let url_data = dummy_url_data(); 5730 5731 // TODO(emilio): If the need for `CallerType` appears in more places, 5732 // consider adding an explicit member in `ParserContext` instead of doing 5733 // this (or adding a dummy "chrome://" url data). 5734 // 5735 // For media query parsing it's effectively the same, so for now... 5736 let origin = match caller_type { 5737 CallerType::System => Origin::UserAgent, 5738 CallerType::NonSystem => Origin::Author, 5739 }; 5740 5741 let context = ParserContext::new( 5742 origin, 5743 url_data, 5744 Some(CssRuleType::Media), 5745 ParsingMode::DEFAULT, 5746 QuirksMode::NoQuirks, 5747 /* namespaces = */ Default::default(), 5748 // TODO(emilio): Looks like error reporting could be useful here? 5749 None, 5750 None, 5751 ); 5752 5753 write_locked_arc(list, |list: &mut MediaList| { 5754 *list = MediaList::parse(&context, &mut parser); 5755 }) 5756 } 5757 5758 #[no_mangle] 5759 pub extern "C" fn Servo_MediaList_IsViewportDependent(list: &LockedMediaList) -> bool { 5760 read_locked_arc(list, |list: &MediaList| list.is_viewport_dependent()) 5761 } 5762 5763 #[no_mangle] 5764 pub extern "C" fn Servo_MediaList_GetLength(list: &LockedMediaList) -> u32 { 5765 read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32) 5766 } 5767 5768 #[no_mangle] 5769 pub extern "C" fn Servo_MediaList_GetMediumAt( 5770 list: &LockedMediaList, 5771 index: u32, 5772 result: &mut nsACString, 5773 ) -> bool { 5774 read_locked_arc(list, |list: &MediaList| { 5775 let media_query = match list.media_queries.get(index as usize) { 5776 Some(mq) => mq, 5777 None => return false, 5778 }; 5779 media_query.to_css(&mut CssWriter::new(result)).unwrap(); 5780 true 5781 }) 5782 } 5783 5784 #[no_mangle] 5785 pub extern "C" fn Servo_MediaList_AppendMedium(list: &LockedMediaList, new_medium: &nsACString) { 5786 let new_medium = unsafe { new_medium.as_str_unchecked() }; 5787 let url_data = unsafe { dummy_url_data() }; 5788 let context = ParserContext::new( 5789 Origin::Author, 5790 url_data, 5791 Some(CssRuleType::Media), 5792 ParsingMode::DEFAULT, 5793 QuirksMode::NoQuirks, 5794 /* namespaces = */ Default::default(), 5795 None, 5796 None, 5797 ); 5798 write_locked_arc(list, |list: &mut MediaList| { 5799 list.append_medium(&context, new_medium); 5800 }) 5801 } 5802 5803 #[no_mangle] 5804 pub extern "C" fn Servo_MediaList_DeleteMedium( 5805 list: &LockedMediaList, 5806 old_medium: &nsACString, 5807 ) -> bool { 5808 let old_medium = unsafe { old_medium.as_str_unchecked() }; 5809 let url_data = unsafe { dummy_url_data() }; 5810 let context = ParserContext::new( 5811 Origin::Author, 5812 url_data, 5813 Some(CssRuleType::Media), 5814 ParsingMode::DEFAULT, 5815 QuirksMode::NoQuirks, 5816 /* namespaces = */ Default::default(), 5817 None, 5818 None, 5819 ); 5820 write_locked_arc(list, |list: &mut MediaList| { 5821 list.delete_medium(&context, old_medium) 5822 }) 5823 } 5824 5825 #[no_mangle] 5826 pub extern "C" fn Servo_MediaList_SizeOfIncludingThis( 5827 malloc_size_of: GeckoMallocSizeOf, 5828 malloc_enclosing_size_of: GeckoMallocSizeOf, 5829 list: &LockedMediaList, 5830 ) -> usize { 5831 use malloc_size_of::MallocSizeOf; 5832 use malloc_size_of::MallocUnconditionalShallowSizeOf; 5833 5834 let global_style_data = &*GLOBAL_STYLE_DATA; 5835 let guard = global_style_data.shared_lock.read(); 5836 5837 let mut ops = MallocSizeOfOps::new( 5838 malloc_size_of.unwrap(), 5839 Some(malloc_enclosing_size_of.unwrap()), 5840 None, 5841 ); 5842 5843 unsafe { ArcBorrow::from_ref(list) }.with_arc(|list| { 5844 let mut n = 0; 5845 n += list.unconditional_shallow_size_of(&mut ops); 5846 n += list.read_with(&guard).size_of(&mut ops); 5847 n 5848 }) 5849 } 5850 5851 macro_rules! get_longhand_from_id { 5852 ($id:expr) => { 5853 match LonghandId::from_noncustomcsspropertyid($id) { 5854 Some(lh) => lh, 5855 _ => panic!("stylo: unknown presentation property with id"), 5856 } 5857 }; 5858 } 5859 5860 macro_rules! match_wrap_declared { 5861 ($longhand:ident, $($property:ident => $inner:expr,)*) => ( 5862 match $longhand { 5863 $( 5864 LonghandId::$property => PropertyDeclaration::$property($inner), 5865 )* 5866 _ => { 5867 panic!("stylo: Don't know how to handle presentation property"); 5868 } 5869 } 5870 ) 5871 } 5872 5873 #[no_mangle] 5874 pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet( 5875 declarations: &LockedDeclarationBlock, 5876 property: NonCustomCSSPropertyId, 5877 ) -> bool { 5878 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { 5879 decls.contains(PropertyDeclarationId::Longhand(get_longhand_from_id!( 5880 property 5881 ))) 5882 }) 5883 } 5884 5885 #[no_mangle] 5886 pub unsafe extern "C" fn Servo_DeclarationBlock_HasLonghandProperty( 5887 declarations: &LockedDeclarationBlock, 5888 property: &nsACString, 5889 ) -> bool { 5890 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { 5891 let prop_name = property.as_str_unchecked(); 5892 if let Ok(property_id) = PropertyId::parse_unchecked(prop_name, None) { 5893 if let Err(longhand_or_custom) = property_id.as_shorthand() { 5894 return decls.contains(longhand_or_custom); 5895 } 5896 } 5897 5898 false 5899 }) 5900 } 5901 5902 #[no_mangle] 5903 pub unsafe extern "C" fn Servo_DeclarationBlock_SetIdentStringValue( 5904 declarations: &LockedDeclarationBlock, 5905 property: NonCustomCSSPropertyId, 5906 value: *mut nsAtom, 5907 ) { 5908 use style::properties::longhands::_x_lang::computed_value::T as Lang; 5909 use style::properties::PropertyDeclaration; 5910 5911 let long = get_longhand_from_id!(property); 5912 let prop = match_wrap_declared! { long, 5913 XLang => Lang(Atom::from_raw(value)), 5914 }; 5915 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 5916 decls.push(prop, Importance::Normal); 5917 }) 5918 } 5919 5920 #[no_mangle] 5921 #[allow(unreachable_code)] 5922 pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue( 5923 declarations: &LockedDeclarationBlock, 5924 property: NonCustomCSSPropertyId, 5925 value: i32, 5926 ) -> bool { 5927 use num_traits::FromPrimitive; 5928 use style::properties::longhands; 5929 use style::properties::PropertyDeclaration; 5930 use style::values::generics::box_::{VerticalAlign, VerticalAlignKeyword}; 5931 use style::values::generics::font::FontStyle; 5932 use style::values::specified::{ 5933 table::CaptionSide, BorderStyle, Clear, Display, Float, TextAlign, TextEmphasisPosition, 5934 TextTransform, 5935 }; 5936 5937 fn get_from_computed<T>(value: u32) -> T 5938 where 5939 T: ToComputedValue, 5940 T::ComputedValue: FromPrimitive, 5941 { 5942 T::from_computed_value(&T::ComputedValue::from_u32(value).unwrap()) 5943 } 5944 5945 let long = get_longhand_from_id!(property); 5946 let value = value as u32; 5947 5948 let prop = match_wrap_declared! { long, 5949 Direction => get_from_computed::<longhands::direction::SpecifiedValue>(value), 5950 Display => get_from_computed::<Display>(value), 5951 Float => get_from_computed::<Float>(value), 5952 Clear => get_from_computed::<Clear>(value), 5953 VerticalAlign => VerticalAlign::Keyword(VerticalAlignKeyword::from_u32(value).unwrap()), 5954 TextAlign => get_from_computed::<TextAlign>(value), 5955 TextEmphasisPosition => TextEmphasisPosition::from_bits_retain(value as u8), 5956 FontSize => { 5957 // We rely on Gecko passing in font-size values (0...7) here. 5958 longhands::font_size::SpecifiedValue::from_html_size(value as u8) 5959 }, 5960 FontStyle => { 5961 specified::FontStyle::Specified(if value == structs::NS_FONT_STYLE_ITALIC { 5962 FontStyle::Italic 5963 } else { 5964 debug_assert_eq!(value, structs::NS_FONT_STYLE_NORMAL); 5965 FontStyle::normal() 5966 }) 5967 }, 5968 FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value), 5969 ListStyleType => longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value), 5970 MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value), 5971 MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value), 5972 WhiteSpaceCollapse => get_from_computed::<longhands::white_space_collapse::SpecifiedValue>(value), 5973 TextWrapMode => get_from_computed::<longhands::text_wrap_mode::SpecifiedValue>(value), 5974 CaptionSide => get_from_computed::<CaptionSide>(value), 5975 BorderTopStyle => get_from_computed::<BorderStyle>(value), 5976 BorderRightStyle => get_from_computed::<BorderStyle>(value), 5977 BorderBottomStyle => get_from_computed::<BorderStyle>(value), 5978 BorderLeftStyle => get_from_computed::<BorderStyle>(value), 5979 TextTransform => { 5980 debug_assert_eq!(value, 0); 5981 TextTransform::NONE 5982 }, 5983 WritingMode => get_from_computed::<longhands::writing_mode::SpecifiedValue>(value), 5984 ContentVisibility => get_from_computed::<ContentVisibility>(value), 5985 TextOrientation => get_from_computed::<longhands::text_orientation::SpecifiedValue>(value), 5986 MixBlendMode => get_from_computed::<longhands::mix_blend_mode::SpecifiedValue>(value), 5987 }; 5988 let mut source_declarations = SourcePropertyDeclaration::with_one(prop); 5989 set_property_to_declarations( 5990 Some(long.into()), 5991 declarations, 5992 &mut source_declarations, 5993 NO_MUTATION_CLOSURE, 5994 Importance::Normal, 5995 ) 5996 } 5997 5998 #[no_mangle] 5999 pub extern "C" fn Servo_DeclarationBlock_SetIntValue( 6000 declarations: &LockedDeclarationBlock, 6001 property: NonCustomCSSPropertyId, 6002 value: i32, 6003 ) { 6004 use style::properties::PropertyDeclaration; 6005 use style::values::specified::Integer; 6006 6007 let long = get_longhand_from_id!(property); 6008 let prop = match_wrap_declared! { long, 6009 XSpan => Integer::new(value), 6010 }; 6011 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6012 decls.push(prop, Importance::Normal); 6013 }) 6014 } 6015 6016 #[no_mangle] 6017 pub extern "C" fn Servo_DeclarationBlock_SetMathDepthValue( 6018 declarations: &LockedDeclarationBlock, 6019 value: i32, 6020 is_relative: bool, 6021 ) { 6022 use style::properties::longhands::math_depth::SpecifiedValue as MathDepth; 6023 use style::properties::PropertyDeclaration; 6024 6025 let integer_value = style::values::specified::Integer::new(value); 6026 let prop = PropertyDeclaration::MathDepth(if is_relative { 6027 MathDepth::Add(integer_value) 6028 } else { 6029 MathDepth::Absolute(integer_value) 6030 }); 6031 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6032 decls.push(prop, Importance::Normal); 6033 }) 6034 } 6035 6036 #[no_mangle] 6037 pub extern "C" fn Servo_DeclarationBlock_SetCounterResetListItem( 6038 declarations: &LockedDeclarationBlock, 6039 counter_value: i32, 6040 is_reversed: bool, 6041 ) { 6042 use style::properties::PropertyDeclaration; 6043 use style::values::generics::counters::{CounterPair, CounterReset}; 6044 6045 let prop = PropertyDeclaration::CounterReset(CounterReset::new(vec![CounterPair { 6046 name: CustomIdent(atom!("list-item")), 6047 value: style::values::specified::Integer::new(counter_value), 6048 is_reversed, 6049 }])); 6050 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6051 decls.push(prop, Importance::Normal); 6052 }) 6053 } 6054 6055 #[no_mangle] 6056 pub extern "C" fn Servo_DeclarationBlock_SetCounterSetListItem( 6057 declarations: &LockedDeclarationBlock, 6058 counter_value: i32, 6059 ) { 6060 use style::properties::PropertyDeclaration; 6061 use style::values::generics::counters::{CounterPair, CounterSet}; 6062 6063 let prop = PropertyDeclaration::CounterSet(CounterSet::new(vec![CounterPair { 6064 name: CustomIdent(atom!("list-item")), 6065 value: style::values::specified::Integer::new(counter_value), 6066 is_reversed: false, 6067 }])); 6068 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6069 decls.push(prop, Importance::Normal); 6070 }) 6071 } 6072 6073 #[no_mangle] 6074 pub extern "C" fn Servo_DeclarationBlock_SetPixelValue( 6075 declarations: &LockedDeclarationBlock, 6076 property: NonCustomCSSPropertyId, 6077 value: f32, 6078 ) { 6079 use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing; 6080 use style::properties::PropertyDeclaration; 6081 use style::values::generics::length::{GenericMargin, Size}; 6082 use style::values::generics::NonNegative; 6083 use style::values::specified::length::{ 6084 LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, 6085 }; 6086 use style::values::specified::{BorderCornerRadius, BorderSideWidth}; 6087 6088 let long = get_longhand_from_id!(property); 6089 let nocalc = NoCalcLength::from_px(value); 6090 let lp = LengthPercentage::Length(nocalc); 6091 let margin = GenericMargin::LengthPercentage(lp.clone()); 6092 let prop = match_wrap_declared! { long, 6093 Height => Size::LengthPercentage(NonNegative(lp)), 6094 Width => Size::LengthPercentage(NonNegative(lp)), 6095 BorderTopWidth => BorderSideWidth::from_px(value), 6096 BorderRightWidth => BorderSideWidth::from_px(value), 6097 BorderBottomWidth => BorderSideWidth::from_px(value), 6098 BorderLeftWidth => BorderSideWidth::from_px(value), 6099 MarginTop => margin, 6100 MarginRight => margin, 6101 MarginBottom => margin, 6102 MarginLeft => margin, 6103 PaddingTop => NonNegative(lp), 6104 PaddingRight => NonNegative(lp), 6105 PaddingBottom => NonNegative(lp), 6106 PaddingLeft => NonNegative(lp), 6107 BorderSpacing => { 6108 let v = NonNegativeLength::from(nocalc); 6109 Box::new(BorderSpacing::new(v.clone(), v)) 6110 }, 6111 BorderTopLeftRadius => { 6112 let length = NonNegativeLengthPercentage::from(nocalc); 6113 Box::new(BorderCornerRadius::new(length.clone(), length)) 6114 }, 6115 BorderTopRightRadius => { 6116 let length = NonNegativeLengthPercentage::from(nocalc); 6117 Box::new(BorderCornerRadius::new(length.clone(), length)) 6118 }, 6119 BorderBottomLeftRadius => { 6120 let length = NonNegativeLengthPercentage::from(nocalc); 6121 Box::new(BorderCornerRadius::new(length.clone(), length)) 6122 }, 6123 BorderBottomRightRadius => { 6124 let length = NonNegativeLengthPercentage::from(nocalc); 6125 Box::new(BorderCornerRadius::new(length.clone(), length)) 6126 }, 6127 }; 6128 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6129 decls.push(prop, Importance::Normal); 6130 }) 6131 } 6132 6133 #[no_mangle] 6134 pub extern "C" fn Servo_DeclarationBlock_SetLengthValue( 6135 declarations: &LockedDeclarationBlock, 6136 property: NonCustomCSSPropertyId, 6137 value: f32, 6138 unit: structs::nsCSSUnit, 6139 ) -> bool { 6140 use style::properties::PropertyDeclaration; 6141 use style::values::generics::length::{LengthPercentageOrAuto, Size}; 6142 use style::values::generics::NonNegative; 6143 use style::values::specified::length::{ 6144 FontRelativeLength, LengthPercentage, ViewportPercentageLength, 6145 }; 6146 use style::values::specified::FontSize; 6147 6148 let long = get_longhand_from_id!(property); 6149 let nocalc = match unit { 6150 structs::nsCSSUnit::eCSSUnit_EM => { 6151 NoCalcLength::FontRelative(FontRelativeLength::Em(value)) 6152 }, 6153 structs::nsCSSUnit::eCSSUnit_XHeight => { 6154 NoCalcLength::FontRelative(FontRelativeLength::Ex(value)) 6155 }, 6156 structs::nsCSSUnit::eCSSUnit_RootEM => { 6157 NoCalcLength::FontRelative(FontRelativeLength::Rem(value)) 6158 }, 6159 structs::nsCSSUnit::eCSSUnit_Char => { 6160 NoCalcLength::FontRelative(FontRelativeLength::Ch(value)) 6161 }, 6162 structs::nsCSSUnit::eCSSUnit_Ideographic => { 6163 NoCalcLength::FontRelative(FontRelativeLength::Ic(value)) 6164 }, 6165 structs::nsCSSUnit::eCSSUnit_CapHeight => { 6166 NoCalcLength::FontRelative(FontRelativeLength::Cap(value)) 6167 }, 6168 structs::nsCSSUnit::eCSSUnit_LineHeight => { 6169 NoCalcLength::FontRelative(FontRelativeLength::Lh(value)) 6170 }, 6171 structs::nsCSSUnit::eCSSUnit_RootLineHeight => { 6172 NoCalcLength::FontRelative(FontRelativeLength::Rlh(value)) 6173 }, 6174 structs::nsCSSUnit::eCSSUnit_Pixel => NoCalcLength::Absolute(AbsoluteLength::Px(value)), 6175 structs::nsCSSUnit::eCSSUnit_Inch => NoCalcLength::Absolute(AbsoluteLength::In(value)), 6176 structs::nsCSSUnit::eCSSUnit_Centimeter => { 6177 NoCalcLength::Absolute(AbsoluteLength::Cm(value)) 6178 }, 6179 structs::nsCSSUnit::eCSSUnit_Millimeter => { 6180 NoCalcLength::Absolute(AbsoluteLength::Mm(value)) 6181 }, 6182 structs::nsCSSUnit::eCSSUnit_Point => NoCalcLength::Absolute(AbsoluteLength::Pt(value)), 6183 structs::nsCSSUnit::eCSSUnit_Pica => NoCalcLength::Absolute(AbsoluteLength::Pc(value)), 6184 structs::nsCSSUnit::eCSSUnit_Quarter => NoCalcLength::Absolute(AbsoluteLength::Q(value)), 6185 structs::nsCSSUnit::eCSSUnit_VW => { 6186 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(value)) 6187 }, 6188 structs::nsCSSUnit::eCSSUnit_VH => { 6189 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vh(value)) 6190 }, 6191 structs::nsCSSUnit::eCSSUnit_VMin => { 6192 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmin(value)) 6193 }, 6194 structs::nsCSSUnit::eCSSUnit_VMax => { 6195 NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmax(value)) 6196 }, 6197 _ => unreachable!("Unknown unit passed to SetLengthValue"), 6198 }; 6199 6200 let mut source_declarations = SourcePropertyDeclaration::with_one(match_wrap_declared! { long, 6201 Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))), 6202 Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))), 6203 X => LengthPercentage::Length(nocalc), 6204 Y => LengthPercentage::Length(nocalc), 6205 Cx => LengthPercentage::Length(nocalc), 6206 Cy => LengthPercentage::Length(nocalc), 6207 R => NonNegative(LengthPercentage::Length(nocalc)), 6208 Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))), 6209 Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))), 6210 FontSize => FontSize::Length(LengthPercentage::Length(nocalc)), 6211 }); 6212 set_property_to_declarations( 6213 Some(long.into()), 6214 declarations, 6215 &mut source_declarations, 6216 NO_MUTATION_CLOSURE, 6217 Importance::Normal, 6218 ) 6219 } 6220 6221 #[no_mangle] 6222 pub extern "C" fn Servo_DeclarationBlock_SetTransform( 6223 declarations: &LockedDeclarationBlock, 6224 property: NonCustomCSSPropertyId, 6225 ops: &nsTArray<computed::TransformOperation>, 6226 ) -> bool { 6227 use style::properties::PropertyDeclaration; 6228 use style::values::generics::transform::GenericTransform; 6229 let long = get_longhand_from_id!(property); 6230 let v = GenericTransform( 6231 ops.iter() 6232 .map(ToComputedValue::from_computed_value) 6233 .collect(), 6234 ); 6235 let prop = match_wrap_declared! { long, 6236 Transform => v, 6237 }; 6238 let mut source_declarations = SourcePropertyDeclaration::with_one(prop); 6239 set_property_to_declarations( 6240 Some(long.into()), 6241 declarations, 6242 &mut source_declarations, 6243 NO_MUTATION_CLOSURE, 6244 Importance::Normal, 6245 ) 6246 } 6247 6248 #[no_mangle] 6249 pub extern "C" fn Servo_DeclarationBlock_SetBackdropFilter( 6250 declarations: &LockedDeclarationBlock, 6251 property: NonCustomCSSPropertyId, 6252 filters: &style::OwnedSlice<Filter>, 6253 ) -> bool { 6254 use style::properties::longhands::backdrop_filter::SpecifiedValue as BackdropFilters; 6255 use style::properties::PropertyDeclaration; 6256 let long = get_longhand_from_id!(property); 6257 let v = BackdropFilters( 6258 filters 6259 .iter() 6260 .map(ToComputedValue::from_computed_value) 6261 .collect(), 6262 ); 6263 let prop = match_wrap_declared! { long, 6264 BackdropFilter => v, 6265 }; 6266 let mut source_declarations = SourcePropertyDeclaration::with_one(prop); 6267 set_property_to_declarations( 6268 Some(long.into()), 6269 declarations, 6270 &mut source_declarations, 6271 NO_MUTATION_CLOSURE, 6272 Importance::Normal, 6273 ) 6274 } 6275 6276 #[no_mangle] 6277 pub extern "C" fn Servo_DeclarationBlock_SetColorScheme( 6278 declarations: &LockedDeclarationBlock, 6279 property: NonCustomCSSPropertyId, 6280 color_scheme: &style::values::computed::ColorScheme, 6281 ) -> bool { 6282 use style::properties::PropertyDeclaration; 6283 use style::values::specified::ColorScheme; 6284 let long = get_longhand_from_id!(property); 6285 let prop = match_wrap_declared! { long, 6286 ColorScheme => ColorScheme::from_computed_value(color_scheme), 6287 }; 6288 let mut source_declarations = SourcePropertyDeclaration::with_one(prop); 6289 set_property_to_declarations( 6290 Some(long.into()), 6291 declarations, 6292 &mut source_declarations, 6293 NO_MUTATION_CLOSURE, 6294 Importance::Normal, 6295 ) 6296 } 6297 6298 #[no_mangle] 6299 pub extern "C" fn Servo_DeclarationBlock_SetPathValue( 6300 declarations: &LockedDeclarationBlock, 6301 property: NonCustomCSSPropertyId, 6302 path: &specified::SVGPathData, 6303 ) { 6304 use style::properties::PropertyDeclaration; 6305 use style::values::specified::DProperty; 6306 6307 // 2. Set decoded path into style. 6308 let long = get_longhand_from_id!(property); 6309 let prop = match_wrap_declared! { long, 6310 D => if path.0.is_empty() { DProperty::None } else { DProperty::Path(path.clone()) }, 6311 }; 6312 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6313 decls.push(prop, Importance::Normal); 6314 }) 6315 } 6316 6317 #[no_mangle] 6318 pub extern "C" fn Servo_CreatePathDataFromCommands( 6319 path_commands: &mut nsTArray<PathCommand>, 6320 dest: &mut specified::SVGPathData, 6321 ) { 6322 let path = specified::SVGPathData(style_traits::arc_slice::ArcSlice::from_iter( 6323 path_commands.drain(..), 6324 )); 6325 *dest = path; 6326 } 6327 6328 #[no_mangle] 6329 pub extern "C" fn Servo_SVGPathData_Add( 6330 dest: &mut specified::SVGPathData, 6331 to_add: &specified::SVGPathData, 6332 count: u32, 6333 ) -> bool { 6334 match dest.animate( 6335 to_add, 6336 Procedure::Accumulate { 6337 count: count as u64, 6338 }, 6339 ) { 6340 Ok(r) => { 6341 *dest = r; 6342 true 6343 }, 6344 Err(..) => false, 6345 } 6346 } 6347 6348 #[no_mangle] 6349 pub extern "C" fn Servo_SVGPathData_Parse( 6350 input: &nsACString, 6351 dest: &mut specified::SVGPathData, 6352 ) -> bool { 6353 let (path, ret) = specified::SVGPathData::parse_bytes(input.as_ref()); 6354 *dest = path; 6355 ret 6356 } 6357 6358 #[no_mangle] 6359 pub extern "C" fn Servo_SVGPathData_NormalizeAndReduce( 6360 input: &specified::SVGPathData, 6361 dest: &mut specified::SVGPathData, 6362 ) { 6363 let path = input.normalize(true); 6364 *dest = path; 6365 } 6366 6367 #[no_mangle] 6368 pub extern "C" fn Servo_SVGPathData_ToString(path: &specified::SVGPathData, dest: &mut nsACString) { 6369 path.to_css(&mut CssWriter::new(dest), /* quote = */ false) 6370 .unwrap(); 6371 } 6372 6373 #[no_mangle] 6374 pub extern "C" fn Servo_SVGPathData_Interpolate( 6375 left: Option<&specified::SVGPathData>, 6376 right: &specified::SVGPathData, 6377 progress: f64, 6378 dest: &mut specified::SVGPathData, 6379 ) -> bool { 6380 let zero; 6381 let left = match left { 6382 Some(l) => l, 6383 None => { 6384 zero = match right.to_animated_zero() { 6385 Ok(z) => z, 6386 Err(..) => { 6387 debug_assert!(false, "how?"); 6388 return false; 6389 }, 6390 }; 6391 &zero 6392 }, 6393 }; 6394 6395 match left.animate(right, Procedure::Interpolate { progress }) { 6396 Ok(r) => { 6397 *dest = r; 6398 true 6399 }, 6400 Err(..) => false, 6401 } 6402 } 6403 6404 #[no_mangle] 6405 pub extern "C" fn Servo_DeclarationBlock_SetPercentValue( 6406 declarations: &LockedDeclarationBlock, 6407 property: NonCustomCSSPropertyId, 6408 value: f32, 6409 ) { 6410 use style::properties::PropertyDeclaration; 6411 use style::values::computed::Percentage; 6412 use style::values::generics::length::{GenericMargin, LengthPercentageOrAuto, Size}; 6413 use style::values::generics::NonNegative; 6414 use style::values::specified::length::LengthPercentage; 6415 use style::values::specified::FontSize; 6416 6417 let long = get_longhand_from_id!(property); 6418 let pc = Percentage(value); 6419 let lp = LengthPercentage::Percentage(pc); 6420 let margin = GenericMargin::LengthPercentage(lp.clone()); 6421 6422 let prop = match_wrap_declared! { long, 6423 Height => Size::LengthPercentage(NonNegative(lp)), 6424 Width => Size::LengthPercentage(NonNegative(lp)), 6425 X => lp, 6426 Y => lp, 6427 Cx => lp, 6428 Cy => lp, 6429 R => NonNegative(lp), 6430 Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)), 6431 Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)), 6432 MarginTop => margin, 6433 MarginRight => margin, 6434 MarginBottom => margin, 6435 MarginLeft => margin, 6436 FontSize => FontSize::Length(LengthPercentage::Percentage(pc)), 6437 }; 6438 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6439 decls.push(prop, Importance::Normal); 6440 }) 6441 } 6442 6443 #[no_mangle] 6444 pub extern "C" fn Servo_DeclarationBlock_SetAutoValue( 6445 declarations: &LockedDeclarationBlock, 6446 property: NonCustomCSSPropertyId, 6447 ) { 6448 use style::properties::PropertyDeclaration; 6449 use style::values::generics::length::{GenericMargin, Size}; 6450 6451 let long = get_longhand_from_id!(property); 6452 let auto = GenericMargin::Auto; 6453 6454 let prop = match_wrap_declared! { long, 6455 Height => Size::auto(), 6456 Width => Size::auto(), 6457 MarginTop => auto, 6458 MarginRight => auto, 6459 MarginBottom => auto, 6460 MarginLeft => auto, 6461 AspectRatio => specified::AspectRatio::auto(), 6462 }; 6463 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6464 decls.push(prop, Importance::Normal); 6465 }) 6466 } 6467 6468 #[no_mangle] 6469 pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor( 6470 declarations: &LockedDeclarationBlock, 6471 property: NonCustomCSSPropertyId, 6472 ) { 6473 use style::properties::PropertyDeclaration; 6474 use style::values::specified::Color; 6475 6476 let long = get_longhand_from_id!(property); 6477 let cc = Color::currentcolor(); 6478 6479 let prop = match_wrap_declared! { long, 6480 BorderTopColor => cc, 6481 BorderRightColor => cc, 6482 BorderBottomColor => cc, 6483 BorderLeftColor => cc, 6484 }; 6485 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6486 decls.push(prop, Importance::Normal); 6487 }) 6488 } 6489 6490 #[no_mangle] 6491 pub extern "C" fn Servo_DeclarationBlock_SetColorValue( 6492 declarations: &LockedDeclarationBlock, 6493 property: NonCustomCSSPropertyId, 6494 value: structs::nscolor, 6495 ) { 6496 use style::gecko::values::convert_nscolor_to_absolute_color; 6497 use style::properties::longhands; 6498 use style::properties::PropertyDeclaration; 6499 use style::values::specified::Color; 6500 6501 let long = get_longhand_from_id!(property); 6502 let rgba = convert_nscolor_to_absolute_color(value); 6503 let color = Color::from_absolute_color(rgba); 6504 6505 let prop = match_wrap_declared! { long, 6506 BorderTopColor => color, 6507 BorderRightColor => color, 6508 BorderBottomColor => color, 6509 BorderLeftColor => color, 6510 Color => longhands::color::SpecifiedValue(color), 6511 BackgroundColor => color, 6512 }; 6513 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6514 decls.push(prop, Importance::Normal); 6515 }) 6516 } 6517 6518 #[no_mangle] 6519 pub unsafe extern "C" fn Servo_DeclarationBlock_SetFontFamily( 6520 declarations: &LockedDeclarationBlock, 6521 value: &nsACString, 6522 ) { 6523 use style::properties::longhands::font_family::SpecifiedValue as FontFamily; 6524 use style::properties::PropertyDeclaration; 6525 6526 let string = value.as_str_unchecked(); 6527 let mut input = ParserInput::new(&string); 6528 let mut parser = Parser::new(&mut input); 6529 let context = ParserContext::new( 6530 Origin::Author, 6531 dummy_url_data(), 6532 Some(CssRuleType::Style), 6533 ParsingMode::DEFAULT, 6534 QuirksMode::NoQuirks, 6535 /* namespaces = */ Default::default(), 6536 None, 6537 None, 6538 ); 6539 let result = FontFamily::parse(&context, &mut parser); 6540 if let Ok(family) = result { 6541 if parser.is_exhausted() { 6542 let decl = PropertyDeclaration::FontFamily(family); 6543 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6544 decls.push(decl, Importance::Normal); 6545 }) 6546 } 6547 } 6548 } 6549 6550 #[no_mangle] 6551 pub unsafe extern "C" fn Servo_DeclarationBlock_SetBackgroundImage( 6552 declarations: &LockedDeclarationBlock, 6553 value: &nsACString, 6554 raw_extra_data: *mut URLExtraData, 6555 ) { 6556 use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage; 6557 use style::properties::PropertyDeclaration; 6558 use style::stylesheets::CorsMode; 6559 use style::values::generics::image::Image; 6560 use style::values::specified::url::SpecifiedUrl; 6561 6562 let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data); 6563 let string = value.as_str_unchecked(); 6564 let context = ParserContext::new( 6565 Origin::Author, 6566 url_data, 6567 Some(CssRuleType::Style), 6568 ParsingMode::DEFAULT, 6569 QuirksMode::NoQuirks, 6570 /* namespaces = */ Default::default(), 6571 None, 6572 None, 6573 ); 6574 let url = SpecifiedUrl::parse_from_string(string.into(), &context, CorsMode::None); 6575 let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(vec![Image::Url(url)].into())); 6576 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6577 decls.push(decl, Importance::Normal); 6578 }); 6579 } 6580 6581 #[no_mangle] 6582 pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride( 6583 declarations: &LockedDeclarationBlock, 6584 ) { 6585 use style::properties::PropertyDeclaration; 6586 use style::values::specified::text::TextDecorationLine; 6587 6588 let decoration = TextDecorationLine::COLOR_OVERRIDE; 6589 let decl = PropertyDeclaration::TextDecorationLine(decoration); 6590 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6591 decls.push(decl, Importance::Normal); 6592 }) 6593 } 6594 6595 #[no_mangle] 6596 pub extern "C" fn Servo_DeclarationBlock_SetAspectRatio( 6597 declarations: &LockedDeclarationBlock, 6598 width: f32, 6599 height: f32, 6600 ) { 6601 use style::properties::PropertyDeclaration; 6602 use style::values::generics::position::AspectRatio; 6603 6604 let decl = PropertyDeclaration::AspectRatio(AspectRatio::from_mapped_ratio(width, height)); 6605 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { 6606 decls.push(decl, Importance::Normal); 6607 }) 6608 } 6609 6610 #[no_mangle] 6611 pub extern "C" fn Servo_CSSSupports2(property: &nsACString, value: &nsACString) -> bool { 6612 let id = unsafe { get_property_id_from_property!(property, false) }; 6613 6614 let mut declarations = SourcePropertyDeclaration::default(); 6615 parse_property_into( 6616 &mut declarations, 6617 id, 6618 value, 6619 Origin::Author, 6620 unsafe { dummy_url_data() }, 6621 ParsingMode::DEFAULT, 6622 QuirksMode::NoQuirks, 6623 CssRuleType::Style, 6624 None, 6625 ) 6626 .is_ok() 6627 } 6628 6629 #[no_mangle] 6630 pub extern "C" fn Servo_CSSSupports( 6631 cond: &nsACString, 6632 ua_origin: bool, 6633 chrome_sheet: bool, 6634 quirks: bool, 6635 ) -> bool { 6636 let condition = unsafe { cond.as_str_unchecked() }; 6637 let mut input = ParserInput::new(&condition); 6638 let mut input = Parser::new(&mut input); 6639 let cond = match input.parse_entirely(parse_condition_or_declaration) { 6640 Ok(c) => c, 6641 Err(..) => return false, 6642 }; 6643 6644 let origin = if ua_origin { 6645 Origin::UserAgent 6646 } else { 6647 Origin::Author 6648 }; 6649 let url_data = unsafe { 6650 if chrome_sheet { 6651 dummy_chrome_url_data() 6652 } else { 6653 dummy_url_data() 6654 } 6655 }; 6656 let quirks_mode = if quirks { 6657 QuirksMode::Quirks 6658 } else { 6659 QuirksMode::NoQuirks 6660 }; 6661 6662 // NOTE(emilio): The supports API is not associated to any stylesheet, 6663 // so the fact that there is no namespace map here is fine. 6664 let context = ParserContext::new( 6665 origin, 6666 url_data, 6667 Some(CssRuleType::Style), 6668 ParsingMode::DEFAULT, 6669 quirks_mode, 6670 /* namespaces = */ Default::default(), 6671 None, 6672 None, 6673 ); 6674 6675 cond.eval(&context) 6676 } 6677 6678 #[no_mangle] 6679 pub extern "C" fn Servo_CSSSupportsForImport(after_rule: &nsACString) -> bool { 6680 let condition = unsafe { after_rule.as_str_unchecked() }; 6681 let mut input = ParserInput::new(&condition); 6682 let mut input = Parser::new(&mut input); 6683 6684 // NOTE(emilio): The supports API is not associated to any stylesheet, 6685 // so the fact that there is no namespace map here is fine. 6686 let mut context = ParserContext::new( 6687 Origin::Author, 6688 unsafe { dummy_url_data() }, 6689 Some(CssRuleType::Style), 6690 ParsingMode::DEFAULT, 6691 QuirksMode::NoQuirks, 6692 /* namespaces = */ Default::default(), 6693 None, 6694 None, 6695 ); 6696 6697 let (_layer, supports) = ImportRule::parse_layer_and_supports(&mut input, &mut context); 6698 6699 supports.map_or(true, |s| s.enabled) 6700 } 6701 6702 #[no_mangle] 6703 pub unsafe extern "C" fn Servo_NoteExplicitHints( 6704 element: &RawGeckoElement, 6705 restyle_hint: RestyleHint, 6706 change_hint: nsChangeHint, 6707 ) { 6708 GeckoElement(element).note_explicit_hints(restyle_hint, change_hint); 6709 } 6710 6711 #[no_mangle] 6712 pub extern "C" fn Servo_TakeChangeHint(element: &RawGeckoElement, was_restyled: &mut bool) -> u32 { 6713 let element = GeckoElement(element); 6714 6715 let damage = match element.mutate_data() { 6716 Some(mut data) => { 6717 *was_restyled = data.is_restyle(); 6718 6719 let damage = data.damage; 6720 data.clear_restyle_state(); 6721 damage 6722 }, 6723 None => { 6724 warn!("Trying to get change hint from unstyled element"); 6725 *was_restyled = false; 6726 GeckoRestyleDamage::empty() 6727 }, 6728 }; 6729 6730 debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage); 6731 // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't 6732 // work as return values with the Linux 32-bit ABI at the moment because 6733 // they wrap the value in a struct, so for now just unwrap it. 6734 damage.as_change_hint().0 6735 } 6736 6737 #[no_mangle] 6738 pub extern "C" fn Servo_ResolveStyle(element: &RawGeckoElement) -> Strong<ComputedValues> { 6739 let element = GeckoElement(element); 6740 debug!("Servo_ResolveStyle: {:?}", element); 6741 let data = element 6742 .borrow_data() 6743 .expect("Resolving style on unstyled element"); 6744 6745 debug_assert!( 6746 element.has_current_styles(&*data), 6747 "Resolving style on {:?} without current styles: {:?}", 6748 element, 6749 data 6750 ); 6751 data.styles.primary().clone().into() 6752 } 6753 6754 #[no_mangle] 6755 pub extern "C" fn Servo_ResolveStyleLazily( 6756 element: &RawGeckoElement, 6757 pseudo_type: PseudoStyleType, 6758 functional_pseudo_parameter: *mut nsAtom, 6759 rule_inclusion: StyleRuleInclusion, 6760 snapshots: *const ServoElementSnapshotTable, 6761 cache_generation: u64, 6762 can_use_cache: bool, 6763 raw_data: &PerDocumentStyleData, 6764 ) -> Strong<ComputedValues> { 6765 debug_assert!(!snapshots.is_null()); 6766 let global_style_data = &*GLOBAL_STYLE_DATA; 6767 let guard = global_style_data.shared_lock.read(); 6768 let element = GeckoElement(element); 6769 let mut data = raw_data.borrow_mut(); 6770 let data = &mut *data; 6771 let rule_inclusion = RuleInclusion::from(rule_inclusion); 6772 let pseudo_element = PseudoElement::from_pseudo_type( 6773 pseudo_type, 6774 get_functional_pseudo_parameter_atom(functional_pseudo_parameter), 6775 ); 6776 6777 let matching_fn = |pseudo_selector: &PseudoElement| match pseudo_element { 6778 Some(ref p) => p.matches(pseudo_selector, &element), 6779 _ => false, 6780 }; 6781 6782 if cache_generation != data.undisplayed_style_cache_generation { 6783 data.undisplayed_style_cache.clear(); 6784 data.undisplayed_style_cache_generation = cache_generation; 6785 } 6786 6787 let stylist = &data.stylist; 6788 let finish = |styles: &ElementStyles, is_probe: bool| -> Option<Arc<ComputedValues>> { 6789 match pseudo_element { 6790 Some(ref pseudo) => { 6791 get_pseudo_style( 6792 &guard, 6793 element, 6794 pseudo, 6795 rule_inclusion, 6796 styles, 6797 /* inherited_styles = */ None, 6798 &stylist, 6799 is_probe, 6800 if pseudo.is_highlight() || pseudo.is_named_view_transition() { 6801 Some(&matching_fn) 6802 } else { 6803 None 6804 }, 6805 ) 6806 }, 6807 None => Some(styles.primary().clone()), 6808 } 6809 }; 6810 6811 let is_before_or_after = pseudo_element 6812 .as_ref() 6813 .map_or(false, |p| p.is_before_or_after()); 6814 6815 // In the common case we already have the style. Check that before setting 6816 // up all the computation machinery. 6817 // 6818 // Also, only probe in the ::before or ::after case, since their styles may 6819 // not be in the `ElementData`, given they may exist but not be applicable 6820 // to generate an actual pseudo-element (like, having a `content: none`). 6821 if rule_inclusion == RuleInclusion::All { 6822 let styles = element.borrow_data().and_then(|d| { 6823 if d.has_styles() { 6824 finish(&d.styles, is_before_or_after) 6825 } else { 6826 None 6827 } 6828 }); 6829 if let Some(result) = styles { 6830 return result.into(); 6831 } 6832 if pseudo_element.is_none() && can_use_cache { 6833 if let Some(style) = data.undisplayed_style_cache.get(&element.opaque()) { 6834 return style.clone().into(); 6835 } 6836 } 6837 } 6838 6839 // We don't have the style ready. Go ahead and compute it as necessary. 6840 let shared = create_shared_context( 6841 &global_style_data, 6842 &guard, 6843 &stylist, 6844 TraversalFlags::empty(), 6845 unsafe { &*snapshots }, 6846 ); 6847 let mut tlc = ThreadLocalStyleContext::new(); 6848 let mut context = StyleContext { 6849 shared: &shared, 6850 thread_local: &mut tlc, 6851 }; 6852 6853 let styles = resolve_style( 6854 &mut context, 6855 element, 6856 rule_inclusion, 6857 pseudo_element.as_ref(), 6858 if can_use_cache { 6859 Some(&mut data.undisplayed_style_cache) 6860 } else { 6861 None 6862 }, 6863 ); 6864 6865 finish(&styles, /* is_probe = */ false) 6866 .expect("We're not probing, so we should always get a style back") 6867 .into() 6868 } 6869 6870 #[no_mangle] 6871 pub extern "C" fn Servo_ResolveStartingStyle( 6872 element: &RawGeckoElement, 6873 snapshots: *const ServoElementSnapshotTable, 6874 raw_data: &PerDocumentStyleData, 6875 ) -> Strong<ComputedValues> { 6876 use style::style_resolver::{PseudoElementResolution, StyleResolverForElement}; 6877 6878 let doc_data = raw_data.borrow(); 6879 let global_style_data = &*GLOBAL_STYLE_DATA; 6880 let guard = global_style_data.shared_lock.read(); 6881 let shared = create_shared_context( 6882 &global_style_data, 6883 &guard, 6884 &doc_data.stylist, 6885 TraversalFlags::empty(), 6886 unsafe { &*snapshots }, 6887 ); 6888 let mut tlc = ThreadLocalStyleContext::new(); 6889 let mut context = StyleContext { 6890 shared: &shared, 6891 thread_local: &mut tlc, 6892 }; 6893 6894 let element = GeckoElement(element); 6895 context.thread_local.bloom_filter.rebuild(element); 6896 6897 let mut resolver = StyleResolverForElement::new( 6898 element, 6899 &mut context, 6900 RuleInclusion::All, 6901 PseudoElementResolution::IfApplicable, 6902 ); 6903 6904 let starting_style = resolver.resolve_starting_style(); 6905 starting_style.style.0.into() 6906 } 6907 6908 #[no_mangle] 6909 pub extern "C" fn Servo_ReparentStyle( 6910 style_to_reparent: &ComputedValues, 6911 parent_style: &ComputedValues, 6912 layout_parent_style: &ComputedValues, 6913 element: Option<&RawGeckoElement>, 6914 raw_data: &PerDocumentStyleData, 6915 ) -> Strong<ComputedValues> { 6916 use style::properties::FirstLineReparenting; 6917 6918 let global_style_data = &*GLOBAL_STYLE_DATA; 6919 let guard = global_style_data.shared_lock.read(); 6920 let doc_data = raw_data.borrow(); 6921 let inputs = CascadeInputs::new_from_style(style_to_reparent); 6922 let element = element.map(GeckoElement); 6923 // We need the pseudo-type to reparent stuff like anonymous boxes, but we don't store pseudo 6924 // identifiers in the style itself, so if there's no pseudo try the element as well. 6925 let pseudo = style_to_reparent 6926 .pseudo() 6927 .or_else(|| element.and_then(|e| e.implemented_pseudo_element())); 6928 6929 doc_data 6930 .stylist 6931 .cascade_style_and_visited( 6932 element, 6933 pseudo.as_ref(), 6934 inputs, 6935 &StylesheetGuards::same(&guard), 6936 Some(parent_style), 6937 Some(layout_parent_style), 6938 FirstLineReparenting::Yes { style_to_reparent }, 6939 /* try_tactic = */ &Default::default(), 6940 /* rule_cache = */ None, 6941 &mut RuleCacheConditions::default(), 6942 ) 6943 .into() 6944 } 6945 6946 #[cfg(feature = "gecko_debug")] 6947 fn simulate_compute_values_failure(property: &PropertyValuePair) -> bool { 6948 let p = &property.mProperty; 6949 let id = get_property_id_from_csspropertyid!(p, false); 6950 id.as_shorthand().is_ok() && property.mSimulateComputeValuesFailure 6951 } 6952 6953 #[cfg(not(feature = "gecko_debug"))] 6954 fn simulate_compute_values_failure(_: &PropertyValuePair) -> bool { 6955 false 6956 } 6957 6958 fn create_context_for_animation<'a>( 6959 per_doc_data: &'a PerDocumentStyleDataImpl, 6960 style: &'a ComputedValues, 6961 parent_style: Option<&'a ComputedValues>, 6962 for_smil_animation: bool, 6963 rule_cache_conditions: &'a mut RuleCacheConditions, 6964 container_size_query: ContainerSizeQuery<'a>, 6965 ) -> Context<'a> { 6966 Context::new_for_animation( 6967 StyleBuilder::for_derived_style( 6968 per_doc_data.stylist.device(), 6969 Some(&per_doc_data.stylist), 6970 style, 6971 parent_style, 6972 ), 6973 for_smil_animation, 6974 per_doc_data.stylist.quirks_mode(), 6975 rule_cache_conditions, 6976 container_size_query, 6977 ) 6978 } 6979 6980 struct PropertyAndIndex { 6981 property: PropertyId, 6982 index: usize, 6983 } 6984 6985 struct PrioritizedPropertyIter<'a> { 6986 properties: &'a [PropertyValuePair], 6987 sorted_property_indices: Box<[PropertyAndIndex]>, 6988 curr: usize, 6989 } 6990 6991 impl<'a> PrioritizedPropertyIter<'a> { 6992 fn new(properties: &'a [PropertyValuePair]) -> Self { 6993 use style::values::animated::compare_property_priority; 6994 6995 // If we fail to convert a NonCustomCSSPropertyId into a PropertyId we 6996 // shouldn't fail outright but instead by treating that property as the 6997 // 'all' property we make it sort last. 6998 let mut sorted_property_indices: Box<[PropertyAndIndex]> = properties 6999 .iter() 7000 .enumerate() 7001 .map(|(index, pair)| { 7002 let property = PropertyId::from_gecko_css_property_id(&pair.mProperty) 7003 .unwrap_or(PropertyId::NonCustom(ShorthandId::All.into())); 7004 PropertyAndIndex { property, index } 7005 }) 7006 .collect(); 7007 sorted_property_indices.sort_by(|a, b| compare_property_priority(&a.property, &b.property)); 7008 7009 PrioritizedPropertyIter { 7010 properties, 7011 sorted_property_indices, 7012 curr: 0, 7013 } 7014 } 7015 7016 fn reset(&mut self) { 7017 self.curr = 0; 7018 } 7019 } 7020 7021 impl<'a> Iterator for PrioritizedPropertyIter<'a> { 7022 type Item = &'a PropertyValuePair; 7023 7024 fn next(&mut self) -> Option<&'a PropertyValuePair> { 7025 if self.curr >= self.sorted_property_indices.len() { 7026 return None; 7027 } 7028 self.curr += 1; 7029 Some(&self.properties[self.sorted_property_indices[self.curr - 1].index]) 7030 } 7031 } 7032 7033 #[no_mangle] 7034 pub extern "C" fn Servo_GetComputedKeyframeValues( 7035 keyframes: &nsTArray<structs::Keyframe>, 7036 element: &RawGeckoElement, 7037 pseudo_type: PseudoStyleType, 7038 style: &ComputedValues, 7039 raw_data: &PerDocumentStyleData, 7040 computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>, 7041 ) { 7042 use style::applicable_declarations::CascadePriority; 7043 use style::custom_properties::CustomPropertiesBuilder; 7044 use style::properties::PropertyDeclaration; 7045 let data = raw_data.borrow(); 7046 let element = GeckoElement(element); 7047 let pseudo = PseudoElement::from_pseudo_type(pseudo_type, None); 7048 let parent_element = if pseudo.is_none() { 7049 element.inheritance_parent() 7050 } else { 7051 Some(element) 7052 }; 7053 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data()); 7054 let parent_style = parent_data 7055 .as_ref() 7056 .map(|d| d.styles.primary()) 7057 .map(|x| &**x); 7058 7059 let container_size_query = 7060 ContainerSizeQuery::for_element(element, parent_style, pseudo.is_some()); 7061 let mut conditions = Default::default(); 7062 let mut context = create_context_for_animation( 7063 &data, 7064 &style, 7065 parent_style, 7066 /* for_smil_animation = */ false, 7067 &mut conditions, 7068 container_size_query, 7069 ); 7070 7071 let restriction = pseudo.and_then(|p| p.property_restriction()); 7072 7073 let global_style_data = &*GLOBAL_STYLE_DATA; 7074 let guard = global_style_data.shared_lock.read(); 7075 let default_values = data.default_computed_values(); 7076 7077 for (index, keyframe) in keyframes.iter().enumerate() { 7078 let ref mut animation_values = computed_keyframes[index]; 7079 7080 let mut seen = PropertyDeclarationIdSet::default(); 7081 let mut iter = PrioritizedPropertyIter::new(&keyframe.mPropertyValues); 7082 7083 // FIXME (bug 1883255): This is pretty much a hack. Instead, the AnimatedValue should be 7084 // better integrated in the cascade. 7085 { 7086 let mut builder = CustomPropertiesBuilder::new_with_properties( 7087 &data.stylist, 7088 style.custom_properties().clone(), 7089 &mut context, 7090 ); 7091 let priority = CascadePriority::same_tree_author_normal_at_root_layer(); 7092 for property in &mut iter { 7093 let is_custom = match PropertyId::from_gecko_css_property_id(&property.mProperty) { 7094 Some(PropertyId::Custom(..)) => true, 7095 _ => false, 7096 }; 7097 if !is_custom { 7098 break; // Custom props are guaranteed to sort earlier. 7099 } 7100 if property.mServoDeclarationBlock.mRawPtr.is_null() { 7101 continue; 7102 } 7103 let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr }; 7104 let guard = declarations.read_with(&guard); 7105 for decl in guard.normal_declaration_iter() { 7106 if let PropertyDeclaration::Custom(ref declaration) = *decl { 7107 builder.cascade(declaration, priority, &element); 7108 } 7109 } 7110 } 7111 iter.reset(); 7112 let _deferred = builder.build(DeferFontRelativeCustomPropertyResolution::No, &element); 7113 debug_assert!( 7114 _deferred.is_none(), 7115 "Custom property processing deferred despite specifying otherwise?" 7116 ); 7117 }; 7118 7119 let mut property_index = 0; 7120 for property in iter { 7121 if simulate_compute_values_failure(property) { 7122 continue; 7123 } 7124 7125 let mut maybe_append_animation_value = 7126 |property: PropertyDeclarationId, value: Option<AnimationValue>| { 7127 debug_assert!(!property.is_logical()); 7128 debug_assert!(property.is_animatable()); 7129 7130 // 'display' is only animatable from SMIL 7131 if property == PropertyDeclarationId::Longhand(LonghandId::Display) { 7132 return; 7133 } 7134 7135 // Skip restricted properties 7136 if restriction.map_or(false, |r| !property.flags().contains(r)) { 7137 return; 7138 } 7139 7140 if seen.contains(property) { 7141 return; 7142 } 7143 seen.insert(property); 7144 7145 animation_values.push(structs::PropertyStyleAnimationValuePair { 7146 mProperty: property.to_gecko_css_property_id(), 7147 mValue: structs::AnimationValue { 7148 mServo: value.map_or(structs::RefPtr::null(), |v| { 7149 structs::RefPtr::from_arc(Arc::new(v)) 7150 }), 7151 }, 7152 }); 7153 property_index += 1; 7154 }; 7155 7156 if property.mServoDeclarationBlock.mRawPtr.is_null() { 7157 if let Some(prop) = 7158 OwnedPropertyDeclarationId::from_gecko_css_property_id(&property.mProperty) 7159 { 7160 maybe_append_animation_value(prop.as_borrowed(), None); 7161 } 7162 continue; 7163 } 7164 7165 let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr }; 7166 let guard = declarations.read_with(&guard); 7167 let iter = guard.to_animation_value_iter(&mut context, style, &default_values); 7168 7169 for value in iter { 7170 maybe_append_animation_value(value.id(), Some(value.clone())); 7171 } 7172 } 7173 } 7174 } 7175 7176 #[no_mangle] 7177 pub extern "C" fn Servo_GetAnimationValues( 7178 declarations: &LockedDeclarationBlock, 7179 element: &RawGeckoElement, 7180 style: &ComputedValues, 7181 raw_data: &PerDocumentStyleData, 7182 animation_values: &mut nsTArray<structs::RefPtr<AnimationValue>>, 7183 ) { 7184 let data = raw_data.borrow(); 7185 let element = GeckoElement(element); 7186 let parent_element = element.inheritance_parent(); 7187 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data()); 7188 let parent_style = parent_data 7189 .as_ref() 7190 .map(|d| d.styles.primary()) 7191 .map(|x| &**x); 7192 7193 let container_size_query = 7194 ContainerSizeQuery::for_element(element, None, /* is_pseudo = */ false); 7195 let mut conditions = Default::default(); 7196 let mut context = create_context_for_animation( 7197 &data, 7198 &style, 7199 parent_style, 7200 /* for_smil_animation = */ true, 7201 &mut conditions, 7202 container_size_query, 7203 ); 7204 7205 let default_values = data.default_computed_values(); 7206 let global_style_data = &*GLOBAL_STYLE_DATA; 7207 let guard = global_style_data.shared_lock.read(); 7208 7209 let guard = declarations.read_with(&guard); 7210 let iter = guard.to_animation_value_iter(&mut context, style, &default_values); 7211 animation_values.extend(iter.map(|v| structs::RefPtr::from_arc(Arc::new(v)))); 7212 } 7213 7214 #[no_mangle] 7215 pub extern "C" fn Servo_AnimationValue_GetPropertyId( 7216 value: &AnimationValue, 7217 property_id: &mut structs::CSSPropertyId, 7218 ) { 7219 *property_id = value.id().to_gecko_css_property_id(); 7220 } 7221 7222 #[no_mangle] 7223 pub extern "C" fn Servo_AnimationValue_Compute( 7224 element: &RawGeckoElement, 7225 declarations: &LockedDeclarationBlock, 7226 style: &ComputedValues, 7227 raw_data: &PerDocumentStyleData, 7228 ) -> Strong<AnimationValue> { 7229 let data = raw_data.borrow(); 7230 7231 let element = GeckoElement(element); 7232 let parent_element = element.inheritance_parent(); 7233 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data()); 7234 let parent_style = parent_data 7235 .as_ref() 7236 .map(|d| d.styles.primary()) 7237 .map(|x| &**x); 7238 7239 let container_size_query = 7240 ContainerSizeQuery::for_element(element, None, /* is_pseudo = */ false); 7241 let mut conditions = Default::default(); 7242 let mut context = create_context_for_animation( 7243 &data, 7244 style, 7245 parent_style, 7246 /* for_smil_animation = */ false, 7247 &mut conditions, 7248 container_size_query, 7249 ); 7250 7251 let default_values = data.default_computed_values(); 7252 let global_style_data = &*GLOBAL_STYLE_DATA; 7253 let guard = global_style_data.shared_lock.read(); 7254 // We only compute the first element in declarations. 7255 match declarations 7256 .read_with(&guard) 7257 .declaration_importance_iter() 7258 .next() 7259 { 7260 Some((decl, imp)) if imp == Importance::Normal => { 7261 let animation = AnimationValue::from_declaration( 7262 decl, 7263 &mut context, 7264 style, 7265 default_values, 7266 &element, 7267 ); 7268 animation.map_or(Strong::null(), |value| Arc::new(value).into()) 7269 }, 7270 _ => Strong::null(), 7271 } 7272 } 7273 7274 #[no_mangle] 7275 pub extern "C" fn Servo_AssertTreeIsClean(root: &RawGeckoElement) { 7276 if !cfg!(feature = "gecko_debug") { 7277 panic!("Calling Servo_AssertTreeIsClean in release build"); 7278 } 7279 7280 let root = GeckoElement(root); 7281 debug!("Servo_AssertTreeIsClean: "); 7282 debug!("{:?}", ShowSubtreeData(root.as_node())); 7283 7284 fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) { 7285 debug_assert!( 7286 !el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants(), 7287 "{:?} has still dirty bit {:?} or animation-only dirty bit {:?}", 7288 el, 7289 el.has_dirty_descendants(), 7290 el.has_animation_only_dirty_descendants() 7291 ); 7292 for child in el.traversal_children() { 7293 if let Some(child) = child.as_element() { 7294 assert_subtree_is_clean(child); 7295 } 7296 } 7297 } 7298 7299 assert_subtree_is_clean(root); 7300 } 7301 7302 #[no_mangle] 7303 pub extern "C" fn Servo_IsWorkerThread() -> bool { 7304 thread_state::get().is_worker() 7305 } 7306 7307 enum Offset { 7308 Zero, 7309 One, 7310 } 7311 7312 fn property_value_pair_for(id: &PropertyDeclarationId) -> structs::PropertyValuePair { 7313 structs::PropertyValuePair { 7314 mProperty: id.to_gecko_css_property_id(), 7315 mServoDeclarationBlock: structs::RefPtr::null(), 7316 #[cfg(feature = "gecko_debug")] 7317 mSimulateComputeValuesFailure: false, 7318 } 7319 } 7320 7321 fn fill_in_missing_keyframe_values( 7322 all_properties: &PropertyDeclarationIdSet, 7323 timing_function: &ComputedTimingFunction, 7324 properties_at_offset: &PropertyDeclarationIdSet, 7325 offset: Offset, 7326 keyframes: &mut nsTArray<structs::Keyframe>, 7327 ) { 7328 // Return early if all animated properties are already set. 7329 if properties_at_offset.contains_all(all_properties) { 7330 return; 7331 } 7332 7333 // Use auto for missing keyframes. 7334 // FIXME: This may be a spec issue in css-animations-2 because the spec says the default 7335 // keyframe-specific composite is replace, but web-animations-1 uses auto. Use auto now so we 7336 // use the value of animation-composition of the element, for missing keyframes. 7337 // https://github.com/w3c/csswg-drafts/issues/7476 7338 let composition = structs::CompositeOperationOrAuto::Auto; 7339 let keyframe = match offset { 7340 Offset::Zero => unsafe { 7341 &mut *bindings::Gecko_GetOrCreateInitialKeyframe( 7342 keyframes, 7343 timing_function, 7344 composition, 7345 ) 7346 }, 7347 Offset::One => unsafe { 7348 &mut *bindings::Gecko_GetOrCreateFinalKeyframe(keyframes, timing_function, composition) 7349 }, 7350 }; 7351 7352 // Append properties that have not been set at this offset. 7353 for property in all_properties.iter() { 7354 if !properties_at_offset.contains(property) { 7355 keyframe 7356 .mPropertyValues 7357 .push(property_value_pair_for(&property)); 7358 } 7359 } 7360 } 7361 7362 #[no_mangle] 7363 pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName( 7364 raw_data: &PerDocumentStyleData, 7365 element: &RawGeckoElement, 7366 style: &ComputedValues, 7367 name: *mut nsAtom, 7368 inherited_timing_function: &ComputedTimingFunction, 7369 keyframes: &mut nsTArray<structs::Keyframe>, 7370 ) -> bool { 7371 use style::gecko_bindings::structs::CompositeOperationOrAuto; 7372 use style::values::computed::AnimationComposition; 7373 7374 debug_assert!(keyframes.len() == 0, "keyframes should be initially empty"); 7375 7376 let element = GeckoElement(element); 7377 let data = raw_data.borrow(); 7378 let name = Atom::from_raw(name); 7379 7380 let animation = match data.stylist.lookup_keyframes(&name, element) { 7381 Some(animation) => animation, 7382 None => return false, 7383 }; 7384 7385 let global_style_data = &*GLOBAL_STYLE_DATA; 7386 let guard = global_style_data.shared_lock.read(); 7387 7388 let mut properties_set_at_current_offset = PropertyDeclarationIdSet::default(); 7389 let mut properties_set_at_start = PropertyDeclarationIdSet::default(); 7390 let mut properties_set_at_end = PropertyDeclarationIdSet::default(); 7391 let mut has_complete_initial_keyframe = false; 7392 let mut has_complete_final_keyframe = false; 7393 let mut current_offset = -1.; 7394 7395 let writing_mode = style.writing_mode; 7396 7397 // Iterate over the keyframe rules backwards so we can drop overridden 7398 // properties (since declarations in later rules override those in earlier 7399 // ones). 7400 for step in animation.steps.iter().rev() { 7401 if step.start_percentage.0 != current_offset { 7402 properties_set_at_current_offset.clear(); 7403 current_offset = step.start_percentage.0; 7404 } 7405 7406 // Override timing_function if the keyframe has an animation-timing-function. 7407 let timing_function = match step.get_animation_timing_function(&guard) { 7408 Some(val) => val.to_computed_value_without_context(), 7409 None => (*inherited_timing_function).clone(), 7410 }; 7411 7412 // Override composite operation if the keyframe has an animation-composition. 7413 let composition = 7414 step.get_animation_composition(&guard) 7415 .map_or(CompositeOperationOrAuto::Auto, |val| match val { 7416 AnimationComposition::Replace => CompositeOperationOrAuto::Replace, 7417 AnimationComposition::Add => CompositeOperationOrAuto::Add, 7418 AnimationComposition::Accumulate => CompositeOperationOrAuto::Accumulate, 7419 }); 7420 7421 // Look for an existing keyframe with the same offset, timing function, and compsition, or 7422 // else add a new keyframe at the beginning of the keyframe array. 7423 let keyframe = &mut *bindings::Gecko_GetOrCreateKeyframeAtStart( 7424 keyframes, 7425 step.start_percentage.0 as f32, 7426 &timing_function, 7427 composition, 7428 ); 7429 7430 match step.value { 7431 KeyframesStepValue::ComputedValues => { 7432 // In KeyframesAnimation::from_keyframes if there is no 0% or 7433 // 100% keyframe at all, we will create a 'ComputedValues' step 7434 // to represent that all properties animated by the keyframes 7435 // animation should be set to the underlying computed value for 7436 // that keyframe. 7437 let mut seen = PropertyDeclarationIdSet::default(); 7438 for property in animation.properties_changed.iter() { 7439 let property = property.to_physical(writing_mode); 7440 if seen.contains(property) { 7441 continue; 7442 } 7443 seen.insert(property); 7444 keyframe 7445 .mPropertyValues 7446 .push(property_value_pair_for(&property)); 7447 } 7448 if current_offset == 0.0 { 7449 has_complete_initial_keyframe = true; 7450 } else if current_offset == 1.0 { 7451 has_complete_final_keyframe = true; 7452 } 7453 }, 7454 KeyframesStepValue::Declarations { ref block } => { 7455 let guard = block.read_with(&guard); 7456 7457 // Filter out non-animatable properties and properties with 7458 // !important. 7459 // 7460 // Also, iterate in reverse to respect the source order in case 7461 // there are logical and physical longhands in the same block. 7462 for declaration in guard.normal_declaration_iter().rev() { 7463 let id = declaration.id().to_physical(writing_mode); 7464 7465 // Skip non-animatable properties, including the 'display' property because 7466 // although it is animatable from SMIL, it should not be animatable from CSS 7467 // Animations. 7468 if !id.is_animatable() 7469 || id == PropertyDeclarationId::Longhand(LonghandId::Display) 7470 { 7471 continue; 7472 } 7473 7474 if properties_set_at_current_offset.contains(id) { 7475 continue; 7476 } 7477 7478 let mut pair = property_value_pair_for(&id); 7479 pair.mServoDeclarationBlock.set_arc(Arc::new( 7480 global_style_data 7481 .shared_lock 7482 .wrap(PropertyDeclarationBlock::with_one( 7483 declaration.to_physical(writing_mode), 7484 Importance::Normal, 7485 )), 7486 )); 7487 keyframe.mPropertyValues.push(pair); 7488 7489 if current_offset == 0.0 { 7490 properties_set_at_start.insert(id); 7491 } else if current_offset == 1.0 { 7492 properties_set_at_end.insert(id); 7493 } 7494 properties_set_at_current_offset.insert(id); 7495 } 7496 }, 7497 } 7498 } 7499 7500 let mut properties_changed = PropertyDeclarationIdSet::default(); 7501 for property in animation.properties_changed.iter() { 7502 properties_changed.insert(property.to_physical(writing_mode)); 7503 } 7504 7505 // Append property values that are missing in the initial or the final keyframes. 7506 if !has_complete_initial_keyframe { 7507 fill_in_missing_keyframe_values( 7508 &properties_changed, 7509 inherited_timing_function, 7510 &properties_set_at_start, 7511 Offset::Zero, 7512 keyframes, 7513 ); 7514 } 7515 if !has_complete_final_keyframe { 7516 fill_in_missing_keyframe_values( 7517 &properties_changed, 7518 inherited_timing_function, 7519 &properties_set_at_end, 7520 Offset::One, 7521 keyframes, 7522 ); 7523 } 7524 true 7525 } 7526 7527 #[no_mangle] 7528 pub extern "C" fn Servo_StyleSet_GetFontFaceRules( 7529 raw_data: &PerDocumentStyleData, 7530 rules: &mut nsTArray<structs::nsFontFaceRuleContainer>, 7531 ) { 7532 let data = raw_data.borrow(); 7533 debug_assert_eq!(rules.len(), 0); 7534 7535 // Reversed iterator because Gecko expects rules to appear sorted 7536 // UserAgent first, Author last. 7537 let font_face_iter = data 7538 .stylist 7539 .iter_extra_data_origins_rev() 7540 .flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o))); 7541 7542 rules.extend(font_face_iter.map(|(&(ref rule, _layer_id), origin)| { 7543 structs::nsFontFaceRuleContainer { 7544 mRule: structs::RefPtr::from_arc(rule.clone()), 7545 mOrigin: origin, 7546 } 7547 })) 7548 } 7549 7550 // XXX Ideally this should return a Option<&LockedCounterStyleRule>, 7551 // but we cannot, because the value from AtomicRefCell::borrow() can only 7552 // live in this function, and thus anything derived from it cannot get the 7553 // same lifetime as raw_data in parameter. See bug 1451543. 7554 #[no_mangle] 7555 pub unsafe extern "C" fn Servo_StyleSet_GetCounterStyleRule( 7556 raw_data: &PerDocumentStyleData, 7557 name: *mut nsAtom, 7558 ) -> *const LockedCounterStyleRule { 7559 let data = raw_data.borrow(); 7560 Atom::with(name, |name| { 7561 data.stylist 7562 .iter_extra_data_origins() 7563 .find_map(|(d, _)| d.counter_styles.get(name)) 7564 .map_or(ptr::null(), |rule| &**rule as *const _) 7565 }) 7566 } 7567 7568 #[no_mangle] 7569 pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet( 7570 raw_data: &PerDocumentStyleData, 7571 ) -> *mut gfxFontFeatureValueSet { 7572 let data = raw_data.borrow(); 7573 7574 let has_rule = data 7575 .stylist 7576 .iter_extra_data_origins() 7577 .any(|(d, _)| !d.font_feature_values.is_empty()); 7578 7579 if !has_rule { 7580 return ptr::null_mut(); 7581 } 7582 7583 let font_feature_values_iter = data 7584 .stylist 7585 .iter_extra_data_origins_rev() 7586 .flat_map(|(d, _)| d.font_feature_values.iter()); 7587 7588 let set = unsafe { Gecko_ConstructFontFeatureValueSet() }; 7589 for &(ref rule, _) in font_feature_values_iter { 7590 rule.set_at_rules(set); 7591 } 7592 set 7593 } 7594 7595 #[no_mangle] 7596 pub extern "C" fn Servo_StyleSet_BuildFontPaletteValueSet( 7597 raw_data: &PerDocumentStyleData, 7598 ) -> *mut FontPaletteValueSet { 7599 let data = raw_data.borrow(); 7600 7601 let has_rule = data 7602 .stylist 7603 .iter_extra_data_origins() 7604 .any(|(d, _)| !d.font_palette_values.is_empty()); 7605 7606 if !has_rule { 7607 return ptr::null_mut(); 7608 } 7609 7610 let font_palette_values_iter = data 7611 .stylist 7612 .iter_extra_data_origins_rev() 7613 .flat_map(|(d, _)| d.font_palette_values.iter()); 7614 7615 let set = unsafe { Gecko_ConstructFontPaletteValueSet() }; 7616 for &(ref rule, _) in font_palette_values_iter { 7617 rule.to_gecko_palette_value_set(set); 7618 } 7619 set 7620 } 7621 7622 #[no_mangle] 7623 pub extern "C" fn Servo_StyleSet_ResolveForDeclarations( 7624 raw_data: &PerDocumentStyleData, 7625 parent_style_context: Option<&ComputedValues>, 7626 declarations: &LockedDeclarationBlock, 7627 ) -> Strong<ComputedValues> { 7628 let doc_data = raw_data.borrow(); 7629 let global_style_data = &*GLOBAL_STYLE_DATA; 7630 let guard = global_style_data.shared_lock.read(); 7631 let guards = StylesheetGuards::same(&guard); 7632 7633 let parent_style = match parent_style_context { 7634 Some(parent) => &*parent, 7635 None => doc_data.default_computed_values(), 7636 }; 7637 7638 doc_data 7639 .stylist 7640 .compute_for_declarations::<GeckoElement>(&guards, parent_style, unsafe { 7641 Arc::from_raw_addrefed(declarations) 7642 }) 7643 .into() 7644 } 7645 7646 #[no_mangle] 7647 pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis( 7648 malloc_size_of: GeckoMallocSizeOf, 7649 malloc_enclosing_size_of: GeckoMallocSizeOf, 7650 sizes: *mut ServoStyleSetSizes, 7651 raw_data: &PerDocumentStyleData, 7652 ) { 7653 let data = raw_data.borrow_mut(); 7654 let mut ops = MallocSizeOfOps::new( 7655 malloc_size_of.unwrap(), 7656 Some(malloc_enclosing_size_of.unwrap()), 7657 None, 7658 ); 7659 let sizes = unsafe { sizes.as_mut() }.unwrap(); 7660 data.add_size_of(&mut ops, sizes); 7661 } 7662 7663 #[no_mangle] 7664 pub extern "C" fn Servo_UACache_AddSizeOf( 7665 malloc_size_of: GeckoMallocSizeOf, 7666 malloc_enclosing_size_of: GeckoMallocSizeOf, 7667 sizes: *mut ServoStyleSetSizes, 7668 ) { 7669 let mut ops = MallocSizeOfOps::new( 7670 malloc_size_of.unwrap(), 7671 Some(malloc_enclosing_size_of.unwrap()), 7672 None, 7673 ); 7674 let sizes = unsafe { sizes.as_mut() }.unwrap(); 7675 add_size_of_ua_cache(&mut ops, sizes); 7676 } 7677 7678 #[no_mangle] 7679 pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency( 7680 raw_data: &PerDocumentStyleData, 7681 element: &RawGeckoElement, 7682 local_name: *mut nsAtom, 7683 ) -> bool { 7684 let data = raw_data.borrow(); 7685 let element = GeckoElement(element); 7686 7687 unsafe { 7688 AtomIdent::with(local_name, |atom| { 7689 data.stylist.any_applicable_rule_data(element, |data| { 7690 data.might_have_attribute_dependency(atom) 7691 }) 7692 }) 7693 } 7694 } 7695 7696 #[no_mangle] 7697 pub extern "C" fn Servo_StyleSet_MightHaveNthOfIDDependency( 7698 raw_data: &PerDocumentStyleData, 7699 element: &RawGeckoElement, 7700 old_id: *mut nsAtom, 7701 new_id: *mut nsAtom, 7702 ) -> bool { 7703 let data = raw_data.borrow(); 7704 let element = GeckoElement(element); 7705 7706 data.stylist.any_applicable_rule_data(element, |data| { 7707 [old_id, new_id] 7708 .iter() 7709 .filter(|id| !id.is_null()) 7710 .any(|id| unsafe { 7711 AtomIdent::with(*id, |atom| data.might_have_nth_of_id_dependency(atom)) 7712 }) 7713 || data.might_have_nth_of_attribute_dependency(&AtomIdent(atom!("id"))) 7714 }) 7715 } 7716 7717 #[no_mangle] 7718 pub extern "C" fn Servo_StyleSet_MightHaveNthOfClassDependency( 7719 raw_data: &PerDocumentStyleData, 7720 element: &RawGeckoElement, 7721 snapshots: &ServoElementSnapshotTable, 7722 ) -> bool { 7723 let data = raw_data.borrow(); 7724 let element = GeckoElement(element); 7725 7726 data.stylist.any_applicable_rule_data(element, |data| { 7727 classes_changed(&element, snapshots) 7728 .iter() 7729 .any(|atom| data.might_have_nth_of_class_dependency(atom)) 7730 || data.might_have_nth_of_attribute_dependency(&AtomIdent(atom!("class"))) 7731 }) 7732 } 7733 7734 #[no_mangle] 7735 pub extern "C" fn Servo_StyleSet_MightHaveNthOfAttributeDependency( 7736 raw_data: &PerDocumentStyleData, 7737 element: &RawGeckoElement, 7738 local_name: *mut nsAtom, 7739 ) -> bool { 7740 let data = raw_data.borrow(); 7741 let element = GeckoElement(element); 7742 7743 unsafe { 7744 AtomIdent::with(local_name, |atom| { 7745 data.stylist.any_applicable_rule_data(element, |data| { 7746 data.might_have_nth_of_attribute_dependency(atom) 7747 }) 7748 }) 7749 } 7750 } 7751 7752 fn on_siblings_invalidated(element: GeckoElement) { 7753 let parent = element 7754 .traversal_parent() 7755 .expect("How could we invalidate siblings without a common parent?"); 7756 unsafe { 7757 parent.set_dirty_descendants(); 7758 bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0); 7759 } 7760 } 7761 7762 fn restyle_for_nth_of(element: GeckoElement, flags: ElementSelectorFlags) { 7763 debug_assert!( 7764 !flags.is_empty(), 7765 "Calling restyle for nth but no relevant flag is set." 7766 ); 7767 fn invalidate_siblings_of( 7768 element: GeckoElement, 7769 get_sibling: fn(GeckoElement) -> Option<GeckoElement>, 7770 ) { 7771 let mut sibling = get_sibling(element); 7772 while let Some(sib) = sibling { 7773 if let Some(mut data) = sib.mutate_data() { 7774 data.hint.insert(RestyleHint::restyle_subtree()); 7775 } 7776 sibling = get_sibling(sib); 7777 } 7778 } 7779 7780 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR) { 7781 invalidate_siblings_of(element, |e| e.prev_sibling_element()); 7782 } 7783 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) { 7784 invalidate_siblings_of(element, |e| e.next_sibling_element()); 7785 } 7786 on_siblings_invalidated(element); 7787 } 7788 7789 fn relative_selector_invalidated_at(element: GeckoElement, result: &InvalidationResult) { 7790 if result.has_invalidated_siblings() { 7791 on_siblings_invalidated(element); 7792 } else if result.has_invalidated_descendants() { 7793 unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) }; 7794 } else if result.has_invalidated_self() { 7795 unsafe { bindings::Gecko_NoteDirtyElement(element.0) }; 7796 let flags = element 7797 .parent_element() 7798 .map_or(ElementSelectorFlags::empty(), |e| e.slow_selector_flags()); 7799 // We invalidated up to the anchor, and it has a flag for nth-of invalidation. 7800 if !flags.is_empty() { 7801 restyle_for_nth_of(element, flags); 7802 } 7803 } 7804 } 7805 7806 fn add_relative_selector_attribute_dependency<'a>( 7807 element: &GeckoElement<'a>, 7808 scope: &Option<OpaqueElement>, 7809 invalidation_map: &'a InvalidationMap, 7810 attribute: &AtomIdent, 7811 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>, 7812 ) { 7813 match invalidation_map 7814 .other_attribute_affecting_selectors 7815 .get(attribute) 7816 { 7817 Some(v) => { 7818 for dependency in v { 7819 collector.add_dependency(dependency, *element, *scope); 7820 } 7821 }, 7822 None => (), 7823 }; 7824 } 7825 7826 fn inherit_relative_selector_search_direction( 7827 parent: Option<GeckoElement>, 7828 prev_sibling: Option<GeckoElement>, 7829 ) -> ElementSelectorFlags { 7830 let mut inherited = ElementSelectorFlags::empty(); 7831 if let Some(parent) = parent { 7832 inherited |= parent 7833 .relative_selector_search_direction() 7834 .intersection(ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR); 7835 } 7836 if let Some(sibling) = prev_sibling { 7837 // Inherit both, for e.g. a sibling with `:has(~.sibling .descendant)` 7838 inherited |= sibling.relative_selector_search_direction().intersection( 7839 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING, 7840 ); 7841 } 7842 inherited 7843 } 7844 7845 #[no_mangle] 7846 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorIDDependency( 7847 raw_data: &PerDocumentStyleData, 7848 element: &RawGeckoElement, 7849 old_id: *mut nsAtom, 7850 new_id: *mut nsAtom, 7851 snapshots: &ServoElementSnapshotTable, 7852 ) { 7853 let data = raw_data.borrow(); 7854 let element = GeckoElement(element); 7855 7856 let quirks_mode: QuirksMode = data.stylist.quirks_mode(); 7857 let invalidator = RelativeSelectorInvalidator { 7858 element, 7859 quirks_mode, 7860 snapshot_table: Some(snapshots), 7861 invalidated: relative_selector_invalidated_at, 7862 sibling_traversal_map: SiblingTraversalMap::default(), 7863 _marker: std::marker::PhantomData, 7864 }; 7865 7866 invalidator.invalidate_relative_selectors_for_this( 7867 &data.stylist, 7868 |element, scope, data, quirks_mode, collector| { 7869 let invalidation_map = data.relative_selector_invalidation_map(); 7870 relative_selector_dependencies_for_id( 7871 old_id, 7872 new_id, 7873 element, 7874 scope, 7875 quirks_mode, 7876 &invalidation_map, 7877 collector, 7878 ); 7879 add_relative_selector_attribute_dependency( 7880 element, 7881 &scope, 7882 invalidation_map, 7883 &AtomIdent(atom!("id")), 7884 collector, 7885 ); 7886 }, 7887 ); 7888 } 7889 7890 #[no_mangle] 7891 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorClassDependency( 7892 raw_data: &PerDocumentStyleData, 7893 element: &RawGeckoElement, 7894 snapshots: &ServoElementSnapshotTable, 7895 ) { 7896 let data = raw_data.borrow(); 7897 let element = GeckoElement(element); 7898 let quirks_mode: QuirksMode = data.stylist.quirks_mode(); 7899 let invalidator = RelativeSelectorInvalidator { 7900 element, 7901 quirks_mode, 7902 snapshot_table: Some(snapshots), 7903 invalidated: relative_selector_invalidated_at, 7904 sibling_traversal_map: SiblingTraversalMap::default(), 7905 _marker: std::marker::PhantomData, 7906 }; 7907 7908 invalidator.invalidate_relative_selectors_for_this( 7909 &data.stylist, 7910 |element, scope, data, quirks_mode, mut collector| { 7911 let invalidation_map = data.relative_selector_invalidation_map(); 7912 7913 relative_selector_dependencies_for_class( 7914 &classes_changed(element, snapshots), 7915 &element, 7916 scope, 7917 quirks_mode, 7918 invalidation_map, 7919 collector, 7920 ); 7921 add_relative_selector_attribute_dependency( 7922 element, 7923 &scope, 7924 invalidation_map, 7925 &AtomIdent(atom!("class")), 7926 &mut collector, 7927 ); 7928 }, 7929 ); 7930 } 7931 7932 #[no_mangle] 7933 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorAttributeDependency( 7934 raw_data: &PerDocumentStyleData, 7935 element: &RawGeckoElement, 7936 local_name: *mut nsAtom, 7937 snapshots: &ServoElementSnapshotTable, 7938 ) { 7939 let data = raw_data.borrow(); 7940 let element = GeckoElement(element); 7941 7942 let quirks_mode: QuirksMode = data.stylist.quirks_mode(); 7943 unsafe { 7944 AtomIdent::with(local_name, |atom| { 7945 let invalidator = RelativeSelectorInvalidator { 7946 element, 7947 quirks_mode, 7948 snapshot_table: Some(snapshots), 7949 invalidated: relative_selector_invalidated_at, 7950 sibling_traversal_map: SiblingTraversalMap::default(), 7951 _marker: std::marker::PhantomData, 7952 }; 7953 7954 invalidator.invalidate_relative_selectors_for_this( 7955 &data.stylist, 7956 |element, scope, data, _quirks_mode, mut collector| { 7957 add_relative_selector_attribute_dependency( 7958 element, 7959 &scope, 7960 data.relative_selector_invalidation_map(), 7961 atom, 7962 &mut collector, 7963 ); 7964 }, 7965 ); 7966 }) 7967 } 7968 } 7969 7970 #[no_mangle] 7971 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorStateDependency( 7972 raw_data: &PerDocumentStyleData, 7973 element: &RawGeckoElement, 7974 state: u64, 7975 snapshots: &ServoElementSnapshotTable, 7976 ) { 7977 let element = GeckoElement(element); 7978 7979 let state = match ElementState::from_bits(state) { 7980 Some(state) => state, 7981 None => return, 7982 }; 7983 let data = raw_data.borrow(); 7984 let quirks_mode: QuirksMode = data.stylist.quirks_mode(); 7985 7986 let invalidator = RelativeSelectorInvalidator { 7987 element, 7988 quirks_mode, 7989 snapshot_table: Some(snapshots), 7990 invalidated: relative_selector_invalidated_at, 7991 sibling_traversal_map: SiblingTraversalMap::default(), 7992 _marker: std::marker::PhantomData, 7993 }; 7994 7995 invalidator.invalidate_relative_selectors_for_this( 7996 &data.stylist, 7997 |element, scope, data, quirks_mode, collector| { 7998 let invalidation_map = data.relative_selector_invalidation_map(); 7999 invalidation_map 8000 .state_affecting_selectors 8001 .lookup_with_additional(*element, quirks_mode, None, &[], state, |dependency| { 8002 if !dependency.state.intersects(state) { 8003 return true; 8004 } 8005 collector.add_dependency(&dependency.dep, *element, scope); 8006 true 8007 }); 8008 }, 8009 ); 8010 } 8011 8012 #[no_mangle] 8013 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorCustomStateDependency( 8014 raw_data: &PerDocumentStyleData, 8015 element: &RawGeckoElement, 8016 state: *mut nsAtom, 8017 snapshots: &ServoElementSnapshotTable, 8018 ) { 8019 let data = raw_data.borrow(); 8020 let element = GeckoElement(element); 8021 8022 let quirks_mode: QuirksMode = data.stylist.quirks_mode(); 8023 let invalidator = RelativeSelectorInvalidator { 8024 element, 8025 quirks_mode, 8026 snapshot_table: Some(snapshots), 8027 invalidated: relative_selector_invalidated_at, 8028 sibling_traversal_map: SiblingTraversalMap::default(), 8029 _marker: std::marker::PhantomData, 8030 }; 8031 8032 invalidator.invalidate_relative_selectors_for_this( 8033 &data.stylist, 8034 |element, scope, data, _quirks_mode, collector| { 8035 let invalidation_map = data.relative_selector_invalidation_map(); 8036 relative_selector_dependencies_for_custom_state( 8037 state, 8038 *element, 8039 scope, 8040 &invalidation_map, 8041 collector, 8042 ); 8043 }, 8044 ); 8045 } 8046 8047 fn invalidate_relative_selector_prev_sibling_side_effect( 8048 prev_sibling: GeckoElement, 8049 quirks_mode: QuirksMode, 8050 sibling_traversal_map: SiblingTraversalMap<GeckoElement>, 8051 stylist: &Stylist, 8052 ) { 8053 let invalidator = RelativeSelectorInvalidator { 8054 element: prev_sibling, 8055 quirks_mode, 8056 snapshot_table: None, 8057 invalidated: relative_selector_invalidated_at, 8058 sibling_traversal_map, 8059 _marker: std::marker::PhantomData, 8060 }; 8061 invalidator.invalidate_relative_selectors_for_dom_mutation( 8062 false, 8063 &stylist, 8064 ElementSelectorFlags::empty(), 8065 DomMutationOperation::SideEffectPrevSibling, 8066 ); 8067 } 8068 8069 fn invalidate_relative_selector_next_sibling_side_effect( 8070 next_sibling: GeckoElement, 8071 quirks_mode: QuirksMode, 8072 sibling_traversal_map: SiblingTraversalMap<GeckoElement>, 8073 stylist: &Stylist, 8074 ) { 8075 let invalidator = RelativeSelectorInvalidator { 8076 element: next_sibling, 8077 quirks_mode, 8078 snapshot_table: None, 8079 invalidated: relative_selector_invalidated_at, 8080 sibling_traversal_map, 8081 _marker: std::marker::PhantomData, 8082 }; 8083 invalidator.invalidate_relative_selectors_for_dom_mutation( 8084 false, 8085 &stylist, 8086 ElementSelectorFlags::empty(), 8087 DomMutationOperation::SideEffectNextSibling, 8088 ); 8089 } 8090 8091 fn invalidate_relative_selector_ts_dependency( 8092 stylist: &Stylist, 8093 element: GeckoElement, 8094 state: TSStateForInvalidation, 8095 ) { 8096 let quirks_mode = stylist.quirks_mode(); 8097 8098 let invalidator = RelativeSelectorInvalidator { 8099 element, 8100 quirks_mode, 8101 snapshot_table: None, 8102 invalidated: relative_selector_invalidated_at, 8103 sibling_traversal_map: SiblingTraversalMap::default(), 8104 _marker: std::marker::PhantomData, 8105 }; 8106 8107 invalidator.invalidate_relative_selectors_for_this( 8108 stylist, 8109 |element, scope, data, quirks_mode, collector| { 8110 let invalidation_map_attributes = data.relative_invalidation_map_attributes(); 8111 invalidation_map_attributes 8112 .ts_state_to_selector 8113 .lookup_with_additional( 8114 *element, 8115 quirks_mode, 8116 None, 8117 &[], 8118 ElementState::empty(), 8119 |dependency| { 8120 if !dependency.state.intersects(state) { 8121 return true; 8122 } 8123 collector.add_dependency(&dependency.dep, *element, scope); 8124 true 8125 }, 8126 ); 8127 }, 8128 ); 8129 } 8130 8131 #[no_mangle] 8132 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorEmptyDependency( 8133 raw_data: &PerDocumentStyleData, 8134 element: &RawGeckoElement, 8135 ) { 8136 invalidate_relative_selector_ts_dependency( 8137 &raw_data.borrow().stylist, 8138 GeckoElement(element), 8139 TSStateForInvalidation::EMPTY, 8140 ); 8141 } 8142 8143 /// Which edge side should the invalidation run for? 8144 #[repr(u8)] 8145 pub enum RelativeSelectorNthEdgeInvalidateFor { 8146 First, 8147 Last, 8148 } 8149 8150 #[no_mangle] 8151 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorNthEdgeDependency( 8152 raw_data: &PerDocumentStyleData, 8153 element: &RawGeckoElement, 8154 invalidate_for: RelativeSelectorNthEdgeInvalidateFor, 8155 ) { 8156 invalidate_relative_selector_ts_dependency( 8157 &raw_data.borrow().stylist, 8158 GeckoElement(element), 8159 match invalidate_for { 8160 RelativeSelectorNthEdgeInvalidateFor::First => TSStateForInvalidation::NTH_EDGE_FIRST, 8161 RelativeSelectorNthEdgeInvalidateFor::Last => TSStateForInvalidation::NTH_EDGE_LAST, 8162 }, 8163 ); 8164 } 8165 8166 #[no_mangle] 8167 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorNthDependencyFromSibling( 8168 raw_data: &PerDocumentStyleData, 8169 element: &RawGeckoElement, 8170 force: bool, 8171 ) { 8172 let mut element = Some(GeckoElement(element)); 8173 let data = unsafe { borrow_assert_main_thread(raw_data) }; 8174 8175 // Short of doing the actual matching, any of the siblings can match the selector, so we 8176 // have to try invalidating against all of them. 8177 while let Some(sibling) = element { 8178 if force { 8179 unsafe { sibling.note_explicit_hints(RestyleHint::restyle_subtree(), nsChangeHint(0)) }; 8180 } 8181 invalidate_relative_selector_ts_dependency( 8182 &data.stylist, 8183 sibling, 8184 TSStateForInvalidation::NTH, 8185 ); 8186 element = sibling.next_sibling_element(); 8187 } 8188 } 8189 8190 #[no_mangle] 8191 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForInsertion( 8192 raw_data: &PerDocumentStyleData, 8193 element: &RawGeckoElement, 8194 ) { 8195 let element = GeckoElement(element); 8196 let data = raw_data.borrow(); 8197 let quirks_mode: QuirksMode = data.stylist.quirks_mode(); 8198 8199 let inherited = inherit_relative_selector_search_direction( 8200 element.parent_element(), 8201 element.prev_sibling_element(), 8202 ); 8203 // Technically, we're not handling breakouts, where the anchor is a (later-sibling) descendant. 8204 // For descendant case, we're ok since it's a descendant of an element yet to be styled. 8205 // For later-sibling descendant, `HAS_SLOW_SELECTOR_LATER_SIBLINGS` is set anyway. 8206 if inherited.is_empty() { 8207 return; 8208 } 8209 8210 // Ok, we could've been inserted between two sibling elements that were connected 8211 // through next sibling. This can happen in two ways: 8212 // * `.a:has(+ .b)` 8213 // * `:has(.. .a + .b ..)` 8214 // Note that the previous sibling may be the anchor, and not part of the invalidation chain. 8215 // Either way, there must be siblings to both sides of the element being inserted 8216 // to consider it. 8217 match ( 8218 element.prev_sibling_element(), 8219 element.next_sibling_element(), 8220 ) { 8221 (Some(prev_sibling), Some(next_sibling)) => 'sibling: { 8222 // If the prev sibling is not on the sibling search path, skip. 8223 if !prev_sibling 8224 .relative_selector_search_direction() 8225 .intersects(ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING) 8226 { 8227 break 'sibling; 8228 } 8229 element.apply_selector_flags( 8230 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING, 8231 ); 8232 invalidate_relative_selector_prev_sibling_side_effect( 8233 prev_sibling, 8234 quirks_mode, 8235 SiblingTraversalMap::new( 8236 prev_sibling, 8237 prev_sibling.prev_sibling_element(), 8238 element.next_sibling_element(), 8239 ), // Pretend this inserted element isn't here. 8240 &data.stylist, 8241 ); 8242 invalidate_relative_selector_next_sibling_side_effect( 8243 next_sibling, 8244 quirks_mode, 8245 SiblingTraversalMap::new( 8246 next_sibling, 8247 Some(prev_sibling), 8248 next_sibling.next_sibling_element(), 8249 ), 8250 &data.stylist, 8251 ); 8252 }, 8253 _ => (), 8254 }; 8255 8256 let invalidator = RelativeSelectorInvalidator { 8257 element, 8258 quirks_mode, 8259 snapshot_table: None, 8260 invalidated: relative_selector_invalidated_at, 8261 sibling_traversal_map: SiblingTraversalMap::default(), 8262 _marker: std::marker::PhantomData, 8263 }; 8264 8265 invalidator.invalidate_relative_selectors_for_dom_mutation( 8266 true, 8267 &data.stylist, 8268 inherited, 8269 DomMutationOperation::Insert, 8270 ); 8271 } 8272 8273 #[no_mangle] 8274 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForAppend( 8275 raw_data: &PerDocumentStyleData, 8276 first_node: &RawGeckoNode, 8277 ) { 8278 let first_node = GeckoNode(first_node); 8279 let inherited = inherit_relative_selector_search_direction( 8280 first_node.parent_element(), 8281 first_node.prev_sibling_element(), 8282 ); 8283 if inherited.is_empty() { 8284 return; 8285 } 8286 let first_element = if let Some(e) = first_node.as_element() { 8287 e 8288 } else if let Some(e) = first_node.next_sibling_element() { 8289 e 8290 } else { 8291 return; 8292 }; 8293 let data = raw_data.borrow(); 8294 let quirks_mode: QuirksMode = data.stylist.quirks_mode(); 8295 8296 let mut element = Some(first_element); 8297 while let Some(e) = element { 8298 let invalidator = RelativeSelectorInvalidator { 8299 element: e, 8300 quirks_mode, 8301 snapshot_table: None, 8302 sibling_traversal_map: SiblingTraversalMap::default(), 8303 invalidated: relative_selector_invalidated_at, 8304 _marker: std::marker::PhantomData, 8305 }; 8306 invalidator.invalidate_relative_selectors_for_dom_mutation( 8307 true, 8308 &data.stylist, 8309 inherited, 8310 DomMutationOperation::Append, 8311 ); 8312 element = e.next_sibling_element(); 8313 } 8314 } 8315 8316 #[no_mangle] 8317 pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForRemoval( 8318 raw_data: &PerDocumentStyleData, 8319 element: &RawGeckoElement, 8320 ) { 8321 let element = GeckoElement(element); 8322 8323 // This element was in-tree, so we can safely say that if it was not on 8324 // the relative selector search path, its removal will not invalidate any 8325 // relative selector. 8326 if element.relative_selector_search_direction().is_empty() { 8327 return; 8328 } 8329 let node = element.as_node(); 8330 let (prev_sibling, next_sibling) = (node.prev_sibling_element(), node.next_sibling_element()); 8331 8332 let inherited = 8333 inherit_relative_selector_search_direction(element.parent_element(), prev_sibling); 8334 if inherited.is_empty() { 8335 return; 8336 } 8337 8338 let data = raw_data.borrow(); 8339 let quirks_mode = data.stylist.quirks_mode(); 8340 // Same comment as insertion applies. 8341 match (prev_sibling, next_sibling) { 8342 (Some(prev_sibling), Some(next_sibling)) => { 8343 // Pretend the element isn't there. 8344 invalidate_relative_selector_prev_sibling_side_effect( 8345 prev_sibling, 8346 quirks_mode, 8347 SiblingTraversalMap::new( 8348 prev_sibling, 8349 prev_sibling.prev_sibling_element(), 8350 Some(next_sibling), 8351 ), 8352 &data.stylist, 8353 ); 8354 invalidate_relative_selector_next_sibling_side_effect( 8355 next_sibling, 8356 quirks_mode, 8357 SiblingTraversalMap::new( 8358 next_sibling, 8359 Some(prev_sibling), 8360 next_sibling.next_sibling_element(), 8361 ), 8362 &data.stylist, 8363 ); 8364 }, 8365 _ => (), 8366 }; 8367 let invalidator = RelativeSelectorInvalidator { 8368 element, 8369 quirks_mode, 8370 snapshot_table: None, 8371 sibling_traversal_map: SiblingTraversalMap::default(), 8372 invalidated: relative_selector_invalidated_at, 8373 _marker: std::marker::PhantomData, 8374 }; 8375 invalidator.invalidate_relative_selectors_for_dom_mutation( 8376 true, 8377 &data.stylist, 8378 inherited, 8379 DomMutationOperation::Remove, 8380 ); 8381 } 8382 8383 #[no_mangle] 8384 pub extern "C" fn Servo_StyleSet_HasStateDependency( 8385 raw_data: &PerDocumentStyleData, 8386 element: &RawGeckoElement, 8387 state: u64, 8388 ) -> bool { 8389 let element = GeckoElement(element); 8390 8391 let state = ElementState::from_bits_retain(state); 8392 let data = raw_data.borrow(); 8393 8394 data.stylist 8395 .any_applicable_rule_data(element, |data| data.has_state_dependency(state)) 8396 } 8397 8398 #[no_mangle] 8399 pub extern "C" fn Servo_StyleSet_HasNthOfCustomStateDependency( 8400 raw_data: &PerDocumentStyleData, 8401 element: &RawGeckoElement, 8402 state: *mut nsAtom, 8403 ) -> bool { 8404 let element = GeckoElement(element); 8405 let data = raw_data.borrow(); 8406 data.stylist 8407 .any_applicable_rule_data(element, |data| unsafe { 8408 AtomIdent::with(state, |atom| data.has_nth_of_custom_state_dependency(atom)) 8409 }) 8410 } 8411 8412 #[no_mangle] 8413 pub extern "C" fn Servo_StyleSet_HasNthOfStateDependency( 8414 raw_data: &PerDocumentStyleData, 8415 element: &RawGeckoElement, 8416 state: u64, 8417 ) -> bool { 8418 let element = GeckoElement(element); 8419 8420 let state = ElementState::from_bits_retain(state); 8421 let data = raw_data.borrow(); 8422 8423 data.stylist 8424 .any_applicable_rule_data(element, |data| data.has_nth_of_state_dependency(state)) 8425 } 8426 8427 #[no_mangle] 8428 pub extern "C" fn Servo_StyleSet_RestyleSiblingsForNthOf(element: &RawGeckoElement, flags: u32) { 8429 let flags = slow_selector_flags_from_node_selector_flags(flags); 8430 let element = GeckoElement(element); 8431 restyle_for_nth_of(element, flags); 8432 } 8433 8434 #[no_mangle] 8435 pub extern "C" fn Servo_StyleSet_HasDocumentStateDependency( 8436 raw_data: &PerDocumentStyleData, 8437 state: u64, 8438 ) -> bool { 8439 let state = DocumentState::from_bits_retain(state); 8440 let data = raw_data.borrow(); 8441 8442 data.stylist.has_document_state_dependency(state) 8443 } 8444 8445 fn computed_or_resolved_value( 8446 style: &ComputedValues, 8447 prop: NonCustomPropertyId, 8448 mut context: Option<&mut resolved::Context>, 8449 value: &mut nsACString, 8450 ) { 8451 let shorthand = match prop.longhand_or_shorthand() { 8452 Ok(longhand) => { 8453 return style 8454 .computed_or_resolved_value(longhand, context, value) 8455 .unwrap() 8456 }, 8457 Err(shorthand) => shorthand, 8458 }; 8459 8460 let mut block = PropertyDeclarationBlock::new(); 8461 for longhand in shorthand.longhands() { 8462 block.push( 8463 style.computed_or_resolved_declaration(longhand, context.as_deref_mut()), 8464 Importance::Normal, 8465 ); 8466 } 8467 block.shorthand_to_css(shorthand, value).unwrap(); 8468 } 8469 8470 #[no_mangle] 8471 pub unsafe extern "C" fn Servo_GetComputedValue( 8472 style: &ComputedValues, 8473 prop: NonCustomCSSPropertyId, 8474 value: &mut nsACString, 8475 ) { 8476 let prop = NonCustomPropertyId::from_noncustomcsspropertyid(prop).unwrap(); 8477 computed_or_resolved_value(style, prop, None, value) 8478 } 8479 8480 #[no_mangle] 8481 pub unsafe extern "C" fn Servo_GetResolvedValue( 8482 style: &ComputedValues, 8483 prop: NonCustomCSSPropertyId, 8484 raw_data: &PerDocumentStyleData, 8485 element: &RawGeckoElement, 8486 value: &mut nsACString, 8487 ) { 8488 let data = raw_data.borrow(); 8489 let device = data.stylist.device(); 8490 let prop = NonCustomPropertyId::from_noncustomcsspropertyid(prop).unwrap(); 8491 let mut context = resolved::Context { 8492 style, 8493 device, 8494 element_info: resolved::ResolvedElementInfo { 8495 element: GeckoElement(element), 8496 }, 8497 for_property: prop, 8498 current_longhand: None, 8499 }; 8500 8501 computed_or_resolved_value(style, prop, Some(&mut context), value) 8502 } 8503 8504 #[no_mangle] 8505 pub unsafe extern "C" fn Servo_GetComputedTypedValue( 8506 style: &ComputedValues, 8507 property: &nsACString, 8508 result: *mut PropertyTypedValueResult, 8509 ) -> bool { 8510 let property_id = get_property_id_from_property!(property, false); 8511 8512 let non_custom_property_id = match property_id.non_custom_id() { 8513 Some(id) => id, 8514 // XXX Handle custom properties here. Tracked in bug 1990426. 8515 None => return false, 8516 }; 8517 8518 let property_typed_value = match non_custom_property_id.longhand_or_shorthand() { 8519 Ok(longhand) => style 8520 .computed_typed_value(longhand) 8521 .map_or(PropertyTypedValue::Unsupported, PropertyTypedValue::Typed), 8522 Err(_) => PropertyTypedValue::Unsupported, 8523 }; 8524 8525 *result = match property_typed_value { 8526 PropertyTypedValue::None => PropertyTypedValueResult::None, 8527 8528 PropertyTypedValue::Unsupported => { 8529 let global_style_data = &*GLOBAL_STYLE_DATA; 8530 8531 let mut block = PropertyDeclarationBlock::new(); 8532 8533 match non_custom_property_id.longhand_or_shorthand() { 8534 Ok(longhand) => { 8535 block.push( 8536 style.computed_or_resolved_declaration(longhand, None), 8537 Importance::Normal, 8538 ); 8539 }, 8540 Err(shorthand) => { 8541 for longhand in shorthand.longhands() { 8542 block.push( 8543 style.computed_or_resolved_declaration(longhand, None), 8544 Importance::Normal, 8545 ); 8546 } 8547 }, 8548 }; 8549 8550 PropertyTypedValueResult::Unsupported( 8551 Arc::new(global_style_data.shared_lock.wrap(block)).into(), 8552 ) 8553 }, 8554 8555 PropertyTypedValue::Typed(typed_value) => PropertyTypedValueResult::Typed(typed_value), 8556 }; 8557 8558 true 8559 } 8560 8561 #[no_mangle] 8562 pub unsafe extern "C" fn Servo_GetCustomPropertyValue( 8563 style: &ComputedValues, 8564 name: &nsACString, 8565 raw_data: &PerDocumentStyleData, 8566 value: &mut nsACString, 8567 ) -> bool { 8568 let data = raw_data.borrow(); 8569 let name = Atom::from(name.as_str_unchecked()); 8570 let custom_registration = data.stylist.get_custom_property_registration(&name); 8571 let computed_value = style.custom_properties.get(custom_registration, &name); 8572 let computed_value = match computed_value { 8573 Some(v) => v, 8574 None => return false, 8575 }; 8576 // TODO(emilio): This might want to return resolved colors and so on for example, see 8577 // https://github.com/w3c/csswg-drafts/issues/10371. 8578 computed_value.to_css(&mut CssWriter::new(value)).unwrap(); 8579 true 8580 } 8581 8582 #[no_mangle] 8583 pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u32 { 8584 // Just expose the custom property items from custom_properties.inherited 8585 // and custom_properties.non_inherited. 8586 let properties = computed_values.custom_properties(); 8587 properties.inherited.len() as u32 + properties.non_inherited.len() as u32 8588 } 8589 8590 #[no_mangle] 8591 pub extern "C" fn Servo_GetCustomPropertyNameAt( 8592 computed_values: &ComputedValues, 8593 index: u32, 8594 ) -> *mut nsAtom { 8595 match &computed_values 8596 .custom_properties 8597 .property_at(index as usize) 8598 { 8599 Some((name, _value)) => name.as_ptr(), 8600 None => ptr::null_mut(), 8601 } 8602 } 8603 8604 #[no_mangle] 8605 pub extern "C" fn Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool { 8606 url.is_fragment() 8607 } 8608 8609 fn relative_selector_dependencies_for_id<'a>( 8610 old_id: *const nsAtom, 8611 new_id: *const nsAtom, 8612 element: &GeckoElement<'a>, 8613 scope: Option<OpaqueElement>, 8614 quirks_mode: QuirksMode, 8615 invalidation_map: &'a InvalidationMap, 8616 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>, 8617 ) { 8618 [old_id, new_id] 8619 .iter() 8620 .filter(|id| !id.is_null()) 8621 .for_each(|id| unsafe { 8622 AtomIdent::with(*id, |atom| { 8623 match invalidation_map.id_to_selector.get(atom, quirks_mode) { 8624 Some(v) => { 8625 for dependency in v { 8626 collector.add_dependency(dependency, *element, scope); 8627 } 8628 }, 8629 None => (), 8630 }; 8631 }) 8632 }); 8633 } 8634 8635 fn relative_selector_dependencies_for_class<'a>( 8636 classes_changed: &SmallVec<[Atom; 8]>, 8637 element: &GeckoElement<'a>, 8638 scope: Option<OpaqueElement>, 8639 quirks_mode: QuirksMode, 8640 invalidation_map: &'a InvalidationMap, 8641 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>, 8642 ) { 8643 classes_changed.iter().for_each(|atom| { 8644 match invalidation_map.class_to_selector.get(atom, quirks_mode) { 8645 Some(v) => { 8646 for dependency in v { 8647 collector.add_dependency(dependency, *element, scope); 8648 } 8649 }, 8650 None => (), 8651 }; 8652 }); 8653 } 8654 8655 fn relative_selector_dependencies_for_custom_state<'a>( 8656 state: *const nsAtom, 8657 element: GeckoElement<'a>, 8658 scope: Option<OpaqueElement>, 8659 invalidation_map: &'a InvalidationMap, 8660 collector: &mut RelativeSelectorDependencyCollector<'a, GeckoElement<'a>>, 8661 ) { 8662 unsafe { 8663 AtomIdent::with(state, |atom| { 8664 match invalidation_map.custom_state_affecting_selectors.get(atom) { 8665 Some(v) => { 8666 for dependency in v { 8667 collector.add_dependency(dependency, element, scope); 8668 } 8669 }, 8670 None => (), 8671 }; 8672 }) 8673 } 8674 } 8675 8676 fn process_relative_selector_invalidations( 8677 element: &GeckoElement, 8678 snapshot_table: &ServoElementSnapshotTable, 8679 data: &PerDocumentStyleDataImpl, 8680 ) { 8681 let snapshot = match snapshot_table.get(element) { 8682 None => return, 8683 Some(s) => s, 8684 }; 8685 let mut states = None; 8686 let mut classes = None; 8687 8688 let quirks_mode: QuirksMode = data.stylist.quirks_mode(); 8689 let invalidator = RelativeSelectorInvalidator { 8690 element: *element, 8691 quirks_mode, 8692 invalidated: relative_selector_invalidated_at, 8693 sibling_traversal_map: SiblingTraversalMap::default(), 8694 snapshot_table: Some(snapshot_table), 8695 _marker: std::marker::PhantomData, 8696 }; 8697 8698 invalidator.invalidate_relative_selectors_for_this( 8699 &data.stylist, 8700 |element, scope, data, quirks_mode, collector| { 8701 let invalidation_map = data.relative_selector_invalidation_map(); 8702 let states = *states.get_or_insert_with(|| { 8703 ElementWrapper::new(*element, snapshot_table).state_changes() 8704 }); 8705 let classes = classes.get_or_insert_with(|| classes_changed(element, snapshot_table)); 8706 if snapshot.id_changed() { 8707 relative_selector_dependencies_for_id( 8708 element 8709 .id() 8710 .map(|id| id.as_ptr().cast_const()) 8711 .unwrap_or(ptr::null()), 8712 snapshot 8713 .id_attr() 8714 .map(|id| id.as_ptr().cast_const()) 8715 .unwrap_or(ptr::null()), 8716 element, 8717 scope, 8718 quirks_mode, 8719 invalidation_map, 8720 collector, 8721 ); 8722 } 8723 relative_selector_dependencies_for_class( 8724 &classes, 8725 element, 8726 scope, 8727 quirks_mode, 8728 invalidation_map, 8729 collector, 8730 ); 8731 snapshot.each_attr_changed(|attr| { 8732 add_relative_selector_attribute_dependency( 8733 element, 8734 &scope, 8735 invalidation_map, 8736 attr, 8737 collector, 8738 ) 8739 }); 8740 invalidation_map 8741 .state_affecting_selectors 8742 .lookup_with_additional(*element, quirks_mode, None, &[], states, |dependency| { 8743 if !dependency.state.intersects(states) { 8744 return true; 8745 } 8746 collector.add_dependency(&dependency.dep, *element, scope); 8747 true 8748 }); 8749 }, 8750 ); 8751 } 8752 8753 #[no_mangle] 8754 pub extern "C" fn Servo_ProcessInvalidations( 8755 set: &PerDocumentStyleData, 8756 element: &RawGeckoElement, 8757 snapshots: *const ServoElementSnapshotTable, 8758 ) { 8759 debug_assert!(!snapshots.is_null()); 8760 8761 let element = GeckoElement(element); 8762 debug_assert!(element.has_snapshot()); 8763 debug_assert!(!element.handled_snapshot()); 8764 8765 let snapshot_table = unsafe { &*snapshots }; 8766 let per_doc_data = set.borrow(); 8767 process_relative_selector_invalidations(&element, snapshot_table, &per_doc_data); 8768 8769 let mut data = element.mutate_data(); 8770 if data.is_none() { 8771 // Snapshot for unstyled element is really only meant for relative selector 8772 // invalidation, so this is fine. 8773 return; 8774 } 8775 8776 let global_style_data = &*GLOBAL_STYLE_DATA; 8777 let guard = global_style_data.shared_lock.read(); 8778 let per_doc_data = set.borrow(); 8779 let shared_style_context = create_shared_context( 8780 &global_style_data, 8781 &guard, 8782 &per_doc_data.stylist, 8783 TraversalFlags::empty(), 8784 snapshot_table, 8785 ); 8786 let mut data = data.as_mut().map(|d| &mut **d); 8787 8788 let mut selector_caches = SelectorCaches::default(); 8789 if let Some(ref mut data) = data { 8790 // FIXME(emilio): Ideally we could share the nth-index-cache across all 8791 // the elements? 8792 let result = data.invalidate_style_if_needed( 8793 element, 8794 &shared_style_context, 8795 None, 8796 &mut selector_caches, 8797 ); 8798 8799 if result.has_invalidated_siblings() { 8800 let parent = element 8801 .traversal_parent() 8802 .expect("How could we invalidate siblings without a common parent?"); 8803 unsafe { 8804 parent.set_dirty_descendants(); 8805 bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0); 8806 } 8807 } else if result.has_invalidated_descendants() { 8808 unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) }; 8809 } else if result.has_invalidated_self() { 8810 unsafe { bindings::Gecko_NoteDirtyElement(element.0) }; 8811 } 8812 } 8813 } 8814 8815 #[no_mangle] 8816 pub extern "C" fn Servo_HasPendingRestyleAncestor( 8817 element: &RawGeckoElement, 8818 may_need_to_flush_layout: bool, 8819 ) -> bool { 8820 let mut has_yet_to_be_styled = false; 8821 let mut element = Some(GeckoElement(element)); 8822 while let Some(e) = element { 8823 if e.has_any_animation() { 8824 return true; 8825 } 8826 8827 // If the element needs a frame, it means that we haven't styled it yet 8828 // after it got inserted in the document, and thus we may need to do 8829 // that for transitions and animations to trigger. 8830 // 8831 // This is a fast path in the common case, but `has_yet_to_be_styled` is 8832 // the real check for this. 8833 if e.needs_frame() { 8834 return true; 8835 } 8836 8837 let data = e.borrow_data(); 8838 if let Some(ref data) = data { 8839 if !data.hint.is_empty() { 8840 return true; 8841 } 8842 if has_yet_to_be_styled && !data.styles.is_display_none() { 8843 return true; 8844 } 8845 // Ideally, DOM mutations wouldn't affect layout trees of siblings. 8846 // 8847 // In practice, this can happen because Gecko deals pretty badly 8848 // with some kinds of content insertion and removals. 8849 // 8850 // If we may need to flush layout, we need frames to accurately 8851 // determine whether we'll actually flush, so if we have to 8852 // reconstruct we need to flush style, which is what will take care 8853 // of ensuring that frames are constructed, even if the style itself 8854 // is up-to-date. 8855 if may_need_to_flush_layout && data.damage.contains(GeckoRestyleDamage::reconstruct()) { 8856 return true; 8857 } 8858 } 8859 has_yet_to_be_styled = data.is_none(); 8860 8861 element = e.traversal_parent(); 8862 } 8863 false 8864 } 8865 8866 #[no_mangle] 8867 pub unsafe extern "C" fn Servo_SelectorList_Parse( 8868 selector_list: &nsACString, 8869 is_chrome: bool, 8870 ) -> *mut SelectorList { 8871 use style::selector_parser::SelectorParser; 8872 8873 let url_data = if is_chrome { 8874 dummy_chrome_url_data() 8875 } else { 8876 dummy_url_data() 8877 }; 8878 8879 let input = selector_list.as_str_unchecked(); 8880 let selector_list = match SelectorParser::parse_author_origin_no_namespace(&input, url_data) { 8881 Ok(selector_list) => selector_list, 8882 Err(..) => return ptr::null_mut(), 8883 }; 8884 8885 Box::into_raw(Box::new(selector_list)) 8886 } 8887 8888 #[no_mangle] 8889 pub unsafe extern "C" fn Servo_SelectorList_Drop(list: *mut SelectorList) { 8890 let _ = Box::from_raw(list); 8891 } 8892 8893 #[no_mangle] 8894 pub unsafe extern "C" fn Servo_IsValidCSSColor(value: &nsACString) -> bool { 8895 let mut input = ParserInput::new(value.as_str_unchecked()); 8896 let mut input = Parser::new(&mut input); 8897 let context = ParserContext::new( 8898 Origin::Author, 8899 dummy_url_data(), 8900 Some(CssRuleType::Style), 8901 ParsingMode::DEFAULT, 8902 QuirksMode::NoQuirks, 8903 /* namespaces = */ Default::default(), 8904 None, 8905 None, 8906 ); 8907 specified::Color::is_valid(&context, &mut input) 8908 } 8909 8910 struct ComputeColorResult { 8911 result_color: AbsoluteColor, 8912 was_current_color: bool, 8913 } 8914 8915 unsafe fn compute_color( 8916 raw_data: Option<&PerDocumentStyleData>, 8917 current_color: &AbsoluteColor, 8918 value: &nsACString, 8919 loader: *mut Loader, 8920 ) -> Option<ComputeColorResult> { 8921 let mut input = ParserInput::new(value.as_str_unchecked()); 8922 let mut input = Parser::new(&mut input); 8923 let reporter = loader.as_mut().and_then(|loader| { 8924 // Make an ErrorReporter that will report errors as being "from DOM". 8925 ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut()) 8926 }); 8927 8928 let context = ParserContext::new( 8929 Origin::Author, 8930 dummy_url_data(), 8931 Some(CssRuleType::Style), 8932 ParsingMode::DEFAULT, 8933 QuirksMode::NoQuirks, 8934 /* namespaces = */ Default::default(), 8935 reporter.as_ref().map(|e| e as &dyn ParseErrorReporter), 8936 None, 8937 ); 8938 8939 let data; 8940 let device = match raw_data { 8941 Some(d) => { 8942 data = d.borrow(); 8943 Some(data.stylist.device()) 8944 }, 8945 None => None, 8946 }; 8947 8948 let computed = specified::Color::parse_and_compute(&context, &mut input, device)?; 8949 8950 let result_color = computed.resolve_to_absolute(current_color); 8951 let was_current_color = computed.is_currentcolor(); 8952 8953 Some(ComputeColorResult { 8954 result_color, 8955 was_current_color, 8956 }) 8957 } 8958 8959 #[no_mangle] 8960 pub unsafe extern "C" fn Servo_ComputeColor( 8961 raw_data: Option<&PerDocumentStyleData>, 8962 current_color: structs::nscolor, 8963 value: &nsACString, 8964 result_color: &mut structs::nscolor, 8965 was_current_color: *mut bool, 8966 loader: *mut Loader, 8967 ) -> bool { 8968 let current_color = style::gecko::values::convert_nscolor_to_absolute_color(current_color); 8969 let Some(result) = compute_color(raw_data, ¤t_color, value, loader) else { 8970 return false; 8971 }; 8972 8973 *result_color = style::gecko::values::convert_absolute_color_to_nscolor(&result.result_color); 8974 if !was_current_color.is_null() { 8975 *was_current_color = result.was_current_color 8976 } 8977 true 8978 } 8979 8980 // This implements https://html.spec.whatwg.org/#update-a-color-well-control-color, 8981 // except the actual serialization steps in step 6 of "serialize a color well control color". 8982 #[no_mangle] 8983 pub unsafe extern "C" fn Servo_ComputeColorWellControlColor( 8984 raw_data: Option<&PerDocumentStyleData>, 8985 value: &nsACString, 8986 to_color_space: ColorSpace, 8987 result_color: &mut AbsoluteColor, 8988 ) -> bool { 8989 if let Some(color) = compute_color(raw_data, &AbsoluteColor::BLACK, value, ptr::null_mut()) { 8990 *result_color = color.result_color.to_color_space(to_color_space); 8991 true 8992 } else { 8993 false 8994 } 8995 } 8996 8997 #[no_mangle] 8998 pub unsafe extern "C" fn Servo_ColorTo( 8999 from_color: &nsACString, 9000 to_color_space: &nsACString, 9001 result_color: &mut nsACString, 9002 result_components: &mut nsTArray<f32>, 9003 result_adjusted: &mut bool, 9004 loader: *mut Loader, 9005 ) -> bool { 9006 // Figure out the color space. 9007 let mut input = ParserInput::new(to_color_space.as_str_unchecked()); 9008 let mut input = Parser::new(&mut input); 9009 let to_color_space = match ColorSpace::parse(&mut input) { 9010 Ok(color_space) => color_space, 9011 Err(_) => { 9012 // Can't parse the color space? Fail the conversion. 9013 return false; 9014 }, 9015 }; 9016 9017 let mut input = ParserInput::new(from_color.as_str_unchecked()); 9018 let mut input = Parser::new(&mut input); 9019 9020 let reporter = loader.as_mut().and_then(|loader| { 9021 // Make an ErrorReporter that will report errors as being "from DOM". 9022 ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut()) 9023 }); 9024 9025 let context = ParserContext::new( 9026 Origin::Author, 9027 dummy_url_data(), 9028 Some(CssRuleType::Style), 9029 ParsingMode::DEFAULT, 9030 QuirksMode::NoQuirks, 9031 /* namespaces = */ Default::default(), 9032 reporter.as_ref().map(|e| e as &dyn ParseErrorReporter), 9033 None, 9034 ); 9035 9036 let specified = match specified::Color::parse(&context, &mut input) { 9037 Ok(color) => color, 9038 Err(_) => return false, 9039 }; 9040 9041 let color = match specified { 9042 specified::Color::Absolute(ref absolute) => &absolute.color, 9043 _ => { 9044 // Can't do anything with a non-absolute color from here, so we 9045 // fail the conversion. 9046 return false; 9047 }, 9048 }; 9049 9050 let color = color.to_color_space(to_color_space); 9051 let mut s = String::new(); 9052 color 9053 .write_author_preferred_value(&mut CssWriter::new(&mut s)) 9054 .unwrap(); 9055 result_color.assign(&s); 9056 9057 result_components.extend(color.raw_components().iter().copied()); 9058 9059 // For now we don't do gamut mapping, so always false. 9060 *result_adjusted = false; 9061 9062 true 9063 } 9064 9065 #[no_mangle] 9066 pub extern "C" fn Servo_ResolveColor( 9067 color: &computed::Color, 9068 foreground: &style::color::AbsoluteColor, 9069 ) -> style::color::AbsoluteColor { 9070 color.resolve_to_absolute(foreground) 9071 } 9072 9073 #[no_mangle] 9074 pub extern "C" fn Servo_ResolveCalcLengthPercentage( 9075 calc: &computed::length_percentage::CalcLengthPercentage, 9076 basis: f32, 9077 ) -> f32 { 9078 calc.resolve(computed::Length::new(basis)).px() 9079 } 9080 9081 /// Result of resolving a math function node potentially containing 9082 /// anchor positioning function. 9083 #[repr(u8)] 9084 pub enum CalcAnchorPositioningFunctionResolution { 9085 /// Anchor positioning function is used, but at least one of them 9086 /// did not resolve to a valid reference - Property using this 9087 /// expression is now invalid at computed time. 9088 Invalid, 9089 /// Anchor positioning function is used, and all of them resolved 9090 /// to valid references, or specified a fallback. 9091 Valid(computed::LengthPercentage), 9092 } 9093 9094 #[no_mangle] 9095 pub extern "C" fn Servo_ResolveAnchorFunctionsInCalcPercentage( 9096 calc: &computed::length_percentage::CalcLengthPercentage, 9097 allowed: &AllowAnchorPosResolutionInCalcPercentage, 9098 params: &AnchorPosOffsetResolutionParams, 9099 out: &mut CalcAnchorPositioningFunctionResolution, 9100 ) { 9101 let resolved = calc.resolve_anchor(*allowed, params); 9102 9103 match resolved { 9104 Err(()) => *out = CalcAnchorPositioningFunctionResolution::Invalid, 9105 Ok((node, clamping_mode)) => { 9106 *out = CalcAnchorPositioningFunctionResolution::Valid( 9107 computed::LengthPercentage::new_calc(node, clamping_mode), 9108 ) 9109 }, 9110 }; 9111 } 9112 9113 #[no_mangle] 9114 pub extern "C" fn Servo_ConvertColorSpace( 9115 color: &AbsoluteColor, 9116 color_space: ColorSpace, 9117 ) -> AbsoluteColor { 9118 color.to_color_space(color_space) 9119 } 9120 9121 #[no_mangle] 9122 pub unsafe extern "C" fn Servo_IntersectionObserverMargin_Parse( 9123 value: &nsACString, 9124 result: *mut IntersectionObserverMargin, 9125 ) -> bool { 9126 let value = value.as_str_unchecked(); 9127 let result = result.as_mut().unwrap(); 9128 9129 let mut input = ParserInput::new(&value); 9130 let mut parser = Parser::new(&mut input); 9131 9132 let url_data = dummy_url_data(); 9133 let context = ParserContext::new( 9134 Origin::Author, 9135 url_data, 9136 Some(CssRuleType::Style), 9137 ParsingMode::DEFAULT, 9138 QuirksMode::NoQuirks, 9139 /* namespaces = */ Default::default(), 9140 None, 9141 None, 9142 ); 9143 9144 let margin = parser.parse_entirely(|p| IntersectionObserverMargin::parse(&context, p)); 9145 match margin { 9146 Ok(margin) => { 9147 *result = margin; 9148 true 9149 }, 9150 Err(..) => false, 9151 } 9152 } 9153 9154 #[no_mangle] 9155 pub extern "C" fn Servo_IntersectionObserverMargin_ToString( 9156 root_margin: &IntersectionObserverMargin, 9157 result: &mut nsACString, 9158 ) { 9159 let mut writer = CssWriter::new(result); 9160 root_margin.to_css(&mut writer).unwrap(); 9161 } 9162 9163 #[no_mangle] 9164 pub extern "C" fn Servo_ParseTransformIntoMatrix( 9165 value: &nsACString, 9166 contain_3d: &mut bool, 9167 result: &mut structs::Matrix4x4Components, 9168 ) -> bool { 9169 use style::properties::longhands::transform; 9170 9171 let string = unsafe { value.as_str_unchecked() }; 9172 let mut input = ParserInput::new(&string); 9173 let mut parser = Parser::new(&mut input); 9174 let context = ParserContext::new( 9175 Origin::Author, 9176 unsafe { dummy_url_data() }, 9177 Some(CssRuleType::Style), 9178 ParsingMode::DEFAULT, 9179 QuirksMode::NoQuirks, 9180 /* namespaces = */ Default::default(), 9181 None, 9182 None, 9183 ); 9184 9185 let transform = match parser.parse_entirely(|t| transform::parse(&context, t)) { 9186 Ok(t) => t, 9187 Err(..) => return false, 9188 }; 9189 9190 let (m, is_3d) = match transform.to_transform_3d_matrix(None) { 9191 Ok(result) => result, 9192 Err(..) => return false, 9193 }; 9194 9195 *result = m.to_array(); 9196 *contain_3d = is_3d; 9197 true 9198 } 9199 9200 #[no_mangle] 9201 pub extern "C" fn Servo_ParseFilters( 9202 value: &nsACString, 9203 ignore_urls: bool, 9204 data: *mut URLExtraData, 9205 out: &mut style::OwnedSlice<Filter>, 9206 ) -> bool { 9207 use style::values::specified::effects::SpecifiedFilter; 9208 9209 let string = unsafe { value.as_str_unchecked() }; 9210 let mut input = ParserInput::new(&string); 9211 let mut parser = Parser::new(&mut input); 9212 let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) }; 9213 let context = ParserContext::new( 9214 Origin::Author, 9215 url_data, 9216 None, 9217 ParsingMode::DEFAULT, 9218 QuirksMode::NoQuirks, 9219 /* namespaces = */ Default::default(), 9220 None, 9221 None, 9222 ); 9223 9224 let mut filters = vec![]; 9225 9226 if parser 9227 .try_parse(|i| i.expect_ident_matching("none")) 9228 .is_ok() 9229 { 9230 return parser.expect_exhausted().is_ok(); 9231 } 9232 9233 if parser.is_exhausted() { 9234 return false; 9235 } 9236 9237 while !parser.is_exhausted() { 9238 let specified_filter = match SpecifiedFilter::parse(&context, &mut parser) { 9239 Ok(f) => f, 9240 Err(..) => return false, 9241 }; 9242 9243 let filter = match specified_filter.to_computed_value_without_context() { 9244 Ok(f) => f, 9245 Err(..) => return false, 9246 }; 9247 9248 if ignore_urls && matches!(filter, Filter::Url(_)) { 9249 continue; 9250 } 9251 9252 filters.push(filter); 9253 } 9254 9255 *out = style::OwnedSlice::from(filters); 9256 true 9257 } 9258 9259 #[no_mangle] 9260 pub unsafe extern "C" fn Servo_ParseFontShorthandForMatching( 9261 value: &nsACString, 9262 data: *mut URLExtraData, 9263 family: &mut FontFamilyList, 9264 style: &mut FontStyle, 9265 stretch: &mut FontStretch, 9266 weight: &mut FontWeight, 9267 size: Option<&mut f32>, 9268 small_caps: Option<&mut bool>, 9269 ) -> bool { 9270 use style::properties::shorthands::font; 9271 use style::values::generics::font::FontStyle as GenericFontStyle; 9272 use style::values::specified::font as specified; 9273 9274 let string = value.as_str_unchecked(); 9275 let mut input = ParserInput::new(&string); 9276 let mut parser = Parser::new(&mut input); 9277 let url_data = UrlExtraData::from_ptr_ref(&data); 9278 let context = ParserContext::new( 9279 Origin::Author, 9280 url_data, 9281 Some(CssRuleType::FontFace), 9282 ParsingMode::DEFAULT, 9283 QuirksMode::NoQuirks, 9284 /* namespaces = */ Default::default(), 9285 None, 9286 None, 9287 ); 9288 9289 let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) { 9290 Ok(f) => f, 9291 Err(..) => return false, 9292 }; 9293 9294 // The system font is not acceptable, so we return false. 9295 match font.font_family { 9296 specified::FontFamily::Values(list) => *family = list, 9297 specified::FontFamily::System(_) => return false, 9298 } 9299 9300 let specified_font_style = match font.font_style { 9301 specified::FontStyle::Specified(ref s) => s, 9302 specified::FontStyle::System(_) => return false, 9303 }; 9304 9305 *style = match *specified_font_style { 9306 GenericFontStyle::Italic => FontStyle::ITALIC, 9307 GenericFontStyle::Oblique(ref angle) => FontStyle::oblique(angle.degrees()), 9308 }; 9309 9310 *stretch = match font.font_stretch { 9311 specified::FontStretch::Keyword(ref k) => k.compute(), 9312 specified::FontStretch::Stretch(ref p) => FontStretch::from_percentage(p.0.get()), 9313 specified::FontStretch::System(_) => return false, 9314 }; 9315 9316 *weight = match font.font_weight { 9317 specified::FontWeight::Absolute(w) => w.compute(), 9318 // Resolve relative font weights against the initial of font-weight 9319 // (normal, which is equivalent to 400). 9320 specified::FontWeight::Bolder => FontWeight::normal().bolder(), 9321 specified::FontWeight::Lighter => FontWeight::normal().lighter(), 9322 specified::FontWeight::System(_) => return false, 9323 }; 9324 9325 // XXX This is unfinished; see values::specified::FontSize::ToComputedValue 9326 // for a more complete implementation (but we can't use it as-is). 9327 if let Some(size) = size { 9328 *size = match font.font_size { 9329 specified::FontSize::Length(lp) => { 9330 use style::values::generics::transform::ToAbsoluteLength; 9331 match lp.to_pixel_length(None) { 9332 Ok(len) => len, 9333 Err(..) => return false, 9334 } 9335 }, 9336 specified::FontSize::Keyword(info) => { 9337 let keyword = if info.kw != specified::FontSizeKeyword::Math { 9338 info.kw 9339 } else { 9340 specified::FontSizeKeyword::Medium 9341 }; 9342 // Map absolute-size keywords to sizes. 9343 // TODO: Maybe get a meaningful quirks / base size from the caller? 9344 let quirks_mode = QuirksMode::NoQuirks; 9345 keyword 9346 .to_length_without_context( 9347 quirks_mode, 9348 computed::Length::new(specified::FONT_MEDIUM_PX), 9349 ) 9350 .0 9351 .px() 9352 }, 9353 // smaller, larger not currently supported 9354 specified::FontSize::Smaller 9355 | specified::FontSize::Larger 9356 | specified::FontSize::System(_) => { 9357 return false; 9358 }, 9359 }; 9360 } 9361 9362 if let Some(small_caps) = small_caps { 9363 use style::computed_values::font_variant_caps::T::SmallCaps; 9364 *small_caps = font.font_variant_caps == SmallCaps; 9365 } 9366 9367 true 9368 } 9369 9370 #[no_mangle] 9371 pub unsafe extern "C" fn Servo_SourceSizeList_Parse(value: &nsACString) -> *mut SourceSizeList { 9372 let value = value.as_str_unchecked(); 9373 let mut input = ParserInput::new(value); 9374 let mut parser = Parser::new(&mut input); 9375 9376 let context = ParserContext::new( 9377 Origin::Author, 9378 dummy_url_data(), 9379 Some(CssRuleType::Style), 9380 ParsingMode::DEFAULT, 9381 QuirksMode::NoQuirks, 9382 /* namespaces = */ Default::default(), 9383 None, 9384 None, 9385 ); 9386 9387 // NB: Intentionally not calling parse_entirely. 9388 let list = SourceSizeList::parse(&context, &mut parser); 9389 Box::into_raw(Box::new(list)) 9390 } 9391 9392 #[no_mangle] 9393 pub unsafe extern "C" fn Servo_SourceSizeList_Evaluate( 9394 raw_data: &PerDocumentStyleData, 9395 list: Option<&SourceSizeList>, 9396 ) -> i32 { 9397 let doc_data = raw_data.borrow(); 9398 let device = doc_data.stylist.device(); 9399 let quirks_mode = doc_data.stylist.quirks_mode(); 9400 9401 let result = match list { 9402 Some(list) => list.evaluate(device, quirks_mode), 9403 None => SourceSizeList::empty().evaluate(device, quirks_mode), 9404 }; 9405 9406 result.0 9407 } 9408 9409 #[no_mangle] 9410 pub unsafe extern "C" fn Servo_SourceSizeList_Drop(list: *mut SourceSizeList) { 9411 let _ = Box::from_raw(list); 9412 } 9413 9414 #[no_mangle] 9415 pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges( 9416 root: &RawGeckoElement, 9417 document_style: &PerDocumentStyleData, 9418 non_document_styles: &nsTArray<&AuthorStyles>, 9419 states_changed: u64, 9420 ) { 9421 use style::invalidation::element::document_state::DocumentStateInvalidationProcessor; 9422 use style::invalidation::element::invalidator::TreeStyleInvalidator; 9423 9424 let document_data = document_style.borrow(); 9425 9426 let iter = document_data 9427 .stylist 9428 .iter_origins() 9429 .map(|(data, _origin)| data) 9430 .chain( 9431 non_document_styles 9432 .iter() 9433 .map(|author_styles| &*author_styles.data), 9434 ); 9435 9436 let mut selector_caches = SelectorCaches::default(); 9437 let root = GeckoElement(root); 9438 let mut processor = DocumentStateInvalidationProcessor::new( 9439 iter, 9440 DocumentState::from_bits_retain(states_changed), 9441 &mut selector_caches, 9442 root.as_node().owner_doc().quirks_mode(), 9443 ); 9444 9445 let result = 9446 TreeStyleInvalidator::new(root, /* stack_limit_checker = */ None, &mut processor) 9447 .invalidate(); 9448 9449 debug_assert!(!result.has_invalidated_siblings(), "How in the world?"); 9450 if result.has_invalidated_descendants() { 9451 bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0); 9452 } else if result.has_invalidated_self() { 9453 bindings::Gecko_NoteDirtyElement(root.0); 9454 } 9455 } 9456 9457 #[no_mangle] 9458 pub unsafe extern "C" fn Servo_PseudoClass_GetStates(name: &nsACString) -> u64 { 9459 let name = name.as_str_unchecked(); 9460 match NonTSPseudoClass::parse_non_functional(name) { 9461 None => 0, 9462 // Ignore :any-link since it contains both visited and unvisited state. 9463 Some(NonTSPseudoClass::AnyLink) => 0, 9464 Some(pseudo_class) => pseudo_class.state_flag().bits(), 9465 } 9466 } 9467 9468 #[no_mangle] 9469 pub unsafe extern "C" fn Servo_UseCounters_Create() -> *mut UseCounters { 9470 Box::into_raw(Box::<UseCounters>::default()) 9471 } 9472 9473 #[no_mangle] 9474 pub unsafe extern "C" fn Servo_UseCounters_Drop(c: *mut UseCounters) { 9475 let _ = Box::from_raw(c); 9476 } 9477 9478 #[no_mangle] 9479 pub unsafe extern "C" fn Servo_UseCounters_Merge( 9480 doc_counters: &UseCounters, 9481 sheet_counters: &UseCounters, 9482 ) { 9483 doc_counters.merge(sheet_counters) 9484 } 9485 9486 #[no_mangle] 9487 pub unsafe extern "C" fn Servo_IsPropertyIdRecordedInUseCounter( 9488 use_counters: &UseCounters, 9489 id: NonCustomCSSPropertyId, 9490 ) -> bool { 9491 let id = NonCustomPropertyId::from_noncustomcsspropertyid(id).unwrap(); 9492 use_counters.non_custom_properties.recorded(id) 9493 } 9494 9495 #[no_mangle] 9496 pub unsafe extern "C" fn Servo_IsUnknownPropertyRecordedInUseCounter( 9497 use_counters: &UseCounters, 9498 p: CountedUnknownProperty, 9499 ) -> bool { 9500 use_counters.counted_unknown_properties.recorded(p) 9501 } 9502 9503 #[no_mangle] 9504 pub unsafe extern "C" fn Servo_IsCustomUseCounterRecorded( 9505 use_counters: &UseCounters, 9506 c: CustomUseCounter, 9507 ) -> bool { 9508 use_counters.custom.recorded(c) 9509 } 9510 9511 #[no_mangle] 9512 pub unsafe extern "C" fn Servo_IsCssPropertyRecordedInUseCounter( 9513 use_counters: &UseCounters, 9514 property: &nsACString, 9515 known_prop: *mut bool, 9516 ) -> bool { 9517 *known_prop = false; 9518 9519 let prop_name = property.as_str_unchecked(); 9520 if let Ok(p) = PropertyId::parse_unchecked_for_testing(prop_name) { 9521 if let Some(id) = p.non_custom_id() { 9522 *known_prop = true; 9523 return use_counters.non_custom_properties.recorded(id); 9524 } 9525 } 9526 9527 if let Some(p) = CountedUnknownProperty::parse_for_testing(prop_name) { 9528 *known_prop = true; 9529 return use_counters.counted_unknown_properties.recorded(p); 9530 } 9531 9532 false 9533 } 9534 9535 #[no_mangle] 9536 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Create( 9537 buffer: *mut u8, 9538 len: usize, 9539 ) -> *mut SharedMemoryBuilder { 9540 Box::into_raw(Box::new(SharedMemoryBuilder::new(buffer, len))) 9541 } 9542 9543 #[no_mangle] 9544 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_AddStylesheet( 9545 builder: &mut SharedMemoryBuilder, 9546 contents: &StylesheetContents, 9547 error_message: &mut nsACString, 9548 ) -> *const LockedCssRules { 9549 // Assert some things we assume when we create a style sheet from shared 9550 // memory. 9551 debug_assert_eq!(contents.quirks_mode, QuirksMode::NoQuirks); 9552 debug_assert!(contents.source_map_url.is_none()); 9553 debug_assert!(contents.source_url.is_none()); 9554 9555 match builder.write(&contents.rules) { 9556 Ok(rules_ptr) => &**rules_ptr, 9557 Err(message) => { 9558 error_message.assign(&message); 9559 ptr::null() 9560 }, 9561 } 9562 } 9563 9564 #[no_mangle] 9565 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_GetLength( 9566 builder: &SharedMemoryBuilder, 9567 ) -> usize { 9568 builder.len() 9569 } 9570 9571 #[no_mangle] 9572 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Drop(builder: *mut SharedMemoryBuilder) { 9573 let _ = Box::from_raw(builder); 9574 } 9575 9576 #[no_mangle] 9577 pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void { 9578 style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr() 9579 } 9580 9581 #[no_mangle] 9582 pub unsafe extern "C" fn Servo_LoadData_GetLazy( 9583 source: &url::LoadDataSource, 9584 ) -> *const url::LoadData { 9585 source.get() 9586 } 9587 9588 #[no_mangle] 9589 pub extern "C" fn Servo_LengthPercentage_ToCss( 9590 lp: &computed::LengthPercentage, 9591 result: &mut nsACString, 9592 ) { 9593 lp.to_css(&mut CssWriter::new(result)).unwrap(); 9594 } 9595 9596 #[no_mangle] 9597 pub extern "C" fn Servo_FontStyle_ToCss(s: &FontStyle, result: &mut nsACString) { 9598 s.to_css(&mut CssWriter::new(result)).unwrap() 9599 } 9600 9601 #[no_mangle] 9602 pub extern "C" fn Servo_FontWeight_ToCss(w: &FontWeight, result: &mut nsACString) { 9603 w.to_css(&mut CssWriter::new(result)).unwrap() 9604 } 9605 9606 #[no_mangle] 9607 pub extern "C" fn Servo_FontStretch_ToCss(s: &FontStretch, result: &mut nsACString) { 9608 s.to_css(&mut CssWriter::new(result)).unwrap() 9609 } 9610 9611 #[no_mangle] 9612 pub extern "C" fn Servo_FontStretch_SerializeKeyword( 9613 s: &FontStretch, 9614 result: &mut nsACString, 9615 ) -> bool { 9616 let kw = match s.as_keyword() { 9617 Some(kw) => kw, 9618 None => return false, 9619 }; 9620 kw.to_css(&mut CssWriter::new(result)).unwrap(); 9621 true 9622 } 9623 9624 #[no_mangle] 9625 pub unsafe extern "C" fn Servo_CursorKind_Parse( 9626 cursor: &nsACString, 9627 result: &mut computed::ui::CursorKind, 9628 ) -> bool { 9629 match computed::ui::CursorKind::from_ident(cursor.as_str_unchecked()) { 9630 Ok(c) => { 9631 *result = c; 9632 true 9633 }, 9634 Err(..) => false, 9635 } 9636 } 9637 9638 #[no_mangle] 9639 pub extern "C" fn Servo_FontFamily_Generic(generic: GenericFontFamily) -> &'static FontFamily { 9640 FontFamily::generic(generic) 9641 } 9642 9643 #[no_mangle] 9644 pub extern "C" fn Servo_FontFamily_ForSystemFont(name: &nsACString, out: &mut FontFamily) { 9645 *out = FontFamily::for_system_font(&name.to_utf8()); 9646 } 9647 9648 #[no_mangle] 9649 pub extern "C" fn Servo_FontFamilyList_WithNames( 9650 names: &nsTArray<computed::font::SingleFontFamily>, 9651 out: &mut FontFamilyList, 9652 ) { 9653 *out = FontFamilyList { 9654 list: style_traits::arc_slice::ArcSlice::from_iter(names.iter().cloned()), 9655 }; 9656 } 9657 9658 #[no_mangle] 9659 pub extern "C" fn Servo_FamilyName_Serialize(name: &FamilyName, result: &mut nsACString) { 9660 name.to_css(&mut CssWriter::new(result)).unwrap() 9661 } 9662 9663 #[no_mangle] 9664 pub extern "C" fn Servo_GenericFontFamily_Parse(input: &nsACString) -> GenericFontFamily { 9665 let context = ParserContext::new( 9666 Origin::Author, 9667 unsafe { dummy_url_data() }, 9668 Some(CssRuleType::Style), 9669 ParsingMode::DEFAULT, 9670 QuirksMode::NoQuirks, 9671 /* namespaces = */ Default::default(), 9672 None, 9673 None, 9674 ); 9675 let value = input.to_utf8(); 9676 let mut input = ParserInput::new(&value); 9677 let mut input = Parser::new(&mut input); 9678 GenericFontFamily::parse(&context, &mut input).unwrap_or(GenericFontFamily::None) 9679 } 9680 9681 #[no_mangle] 9682 pub extern "C" fn Servo_ColorScheme_Parse(input: &nsACString, out: &mut u8) -> bool { 9683 use style::values::specified::ColorScheme; 9684 9685 let context = ParserContext::new( 9686 Origin::Author, 9687 unsafe { dummy_url_data() }, 9688 Some(CssRuleType::Style), 9689 ParsingMode::DEFAULT, 9690 QuirksMode::NoQuirks, 9691 /* namespaces = */ Default::default(), 9692 None, 9693 None, 9694 ); 9695 let input = unsafe { input.as_str_unchecked() }; 9696 let mut input = ParserInput::new(&input); 9697 let mut input = Parser::new(&mut input); 9698 let scheme = match input.parse_entirely(|i| ColorScheme::parse(&context, i)) { 9699 Ok(scheme) => scheme, 9700 Err(..) => return false, 9701 }; 9702 *out = scheme.raw_bits(); 9703 true 9704 } 9705 9706 #[no_mangle] 9707 pub extern "C" fn Servo_LayerBlockRule_GetName(rule: &LayerBlockRule, result: &mut nsACString) { 9708 if let Some(ref name) = rule.name { 9709 name.to_css(&mut CssWriter::new(result)).unwrap() 9710 } 9711 } 9712 9713 #[no_mangle] 9714 pub extern "C" fn Servo_ScopeRule_GetStart(rule: &ScopeRule, result: &mut nsACString) { 9715 if let Some(v) = rule.bounds.start.as_ref() { 9716 v.to_css(&mut CssWriter::new(result)).unwrap(); 9717 } else { 9718 result.set_is_void(true); 9719 } 9720 } 9721 9722 #[no_mangle] 9723 pub extern "C" fn Servo_ScopeRule_GetEnd(rule: &ScopeRule, result: &mut nsACString) { 9724 if let Some(v) = rule.bounds.end.as_ref() { 9725 v.to_css(&mut CssWriter::new(result)).unwrap(); 9726 } else { 9727 result.set_is_void(true); 9728 } 9729 } 9730 9731 #[no_mangle] 9732 pub extern "C" fn Servo_LayerStatementRule_GetNameCount(rule: &LayerStatementRule) -> usize { 9733 rule.names.len() 9734 } 9735 9736 #[no_mangle] 9737 pub extern "C" fn Servo_LayerStatementRule_GetNameAt( 9738 rule: &LayerStatementRule, 9739 index: usize, 9740 result: &mut nsACString, 9741 ) { 9742 if let Some(ref name) = rule.names.get(index) { 9743 name.to_css(&mut CssWriter::new(result)).unwrap() 9744 } 9745 } 9746 9747 #[no_mangle] 9748 pub unsafe extern "C" fn Servo_InvalidateForViewportUnits( 9749 document_style: &PerDocumentStyleData, 9750 root: &RawGeckoElement, 9751 dynamic_only: bool, 9752 ) { 9753 let mut document_data = document_style.borrow_mut(); 9754 let ref mut stylist = document_data.stylist; 9755 let device = stylist.device(); 9756 9757 if !device.used_viewport_size() { 9758 return; 9759 } 9760 9761 if dynamic_only && !device.used_dynamic_viewport_size() { 9762 return; 9763 } 9764 9765 // If the viewport changed, then initial values containing viewport units need to be recomputed. 9766 if stylist 9767 .get_custom_property_initial_values_flags() 9768 .intersects(ComputedValueFlags::USES_VIEWPORT_UNITS) 9769 { 9770 stylist.rebuild_initial_values_for_custom_properties(); 9771 } 9772 9773 if style::invalidation::viewport_units::invalidate(GeckoElement(root)) { 9774 // The invalidation machinery propagates the bits up, but we still need 9775 // to tell the Gecko restyle root machinery about it. 9776 bindings::Gecko_NoteDirtySubtreeForInvalidation(root); 9777 } 9778 } 9779 9780 #[no_mangle] 9781 pub extern "C" fn Servo_InterpolateColor( 9782 interpolation: ColorInterpolationMethod, 9783 start_color: &AbsoluteColor, 9784 end_color: &AbsoluteColor, 9785 progress: f32, 9786 ) -> AbsoluteColor { 9787 style::color::mix::mix( 9788 interpolation, 9789 start_color, 9790 1.0 - progress, 9791 end_color, 9792 progress, 9793 ColorMixFlags::empty(), 9794 ) 9795 } 9796 9797 #[no_mangle] 9798 pub extern "C" fn Servo_EasingFunctionAt( 9799 easing_function: &ComputedTimingFunction, 9800 progress: f64, 9801 before_flag: BeforeFlag, 9802 ) -> f64 { 9803 easing_function.calculate_output(progress, before_flag, 1e-7) 9804 } 9805 9806 fn parse_no_context<'i, F, R>(string: &'i str, parse: F) -> Result<R, ()> 9807 where 9808 F: FnOnce(&ParserContext, &mut Parser<'i, '_>) -> Result<R, ParseError<'i>>, 9809 { 9810 let context = ParserContext::new( 9811 Origin::Author, 9812 unsafe { dummy_url_data() }, 9813 None, 9814 ParsingMode::DEFAULT, 9815 QuirksMode::NoQuirks, 9816 /* namespaces = */ Default::default(), 9817 None, 9818 None, 9819 ); 9820 let mut input = ParserInput::new(string); 9821 Parser::new(&mut input) 9822 .parse_entirely(|i| parse(&context, i)) 9823 .map_err(|_| ()) 9824 } 9825 9826 #[no_mangle] 9827 // Parse a length without style context (for canvas2d letterSpacing/wordSpacing attributes). 9828 // This accepts absolute lengths, and if a font-metrics-getter function is passed, also 9829 // font-relative ones, but not other units (such as percentages, viewport-relative, etc) 9830 // that would require a full style context to resolve. 9831 pub extern "C" fn Servo_ParseLengthWithoutStyleContext( 9832 len: &nsACString, 9833 out: &mut f32, 9834 get_font_metrics: Option<unsafe extern "C" fn(*mut c_void) -> GeckoFontMetrics>, 9835 getter_context: *mut c_void, 9836 ) -> bool { 9837 let metrics_getter = if let Some(getter) = get_font_metrics { 9838 Some(move || -> GeckoFontMetrics { unsafe { getter(getter_context) } }) 9839 } else { 9840 None 9841 }; 9842 let value = parse_no_context(unsafe { len.as_str_unchecked() }, specified::Length::parse) 9843 .and_then(|p| p.to_computed_pixel_length_with_font_metrics(metrics_getter)); 9844 match value { 9845 Ok(v) => { 9846 *out = v; 9847 true 9848 }, 9849 Err(..) => false, 9850 } 9851 } 9852 9853 #[no_mangle] 9854 pub extern "C" fn Servo_SlowRgbToColorName(r: u8, g: u8, b: u8, result: &mut nsACString) -> bool { 9855 let mut candidates = SmallVec::<[&'static str; 5]>::new(); 9856 for (name, color) in cssparser::color::all_named_colors() { 9857 if color == (r, g, b) { 9858 candidates.push(name); 9859 } 9860 } 9861 if candidates.is_empty() { 9862 return false; 9863 } 9864 // DevTools expect the first alphabetically. 9865 candidates.sort(); 9866 result.assign(candidates[0]); 9867 true 9868 } 9869 9870 #[no_mangle] 9871 pub extern "C" fn Servo_SlowRgbToNearestColorName( 9872 r: f32, 9873 g: f32, 9874 b: f32, 9875 color_space: ColorSpace, 9876 result: &mut nsACString, 9877 ) -> bool { 9878 let absolute = |r, g, b, color_space| AbsoluteColor { 9879 components: ColorComponents(r, g, b), 9880 alpha: 1.0, 9881 color_space, 9882 flags: Default::default(), 9883 }; 9884 9885 let input = absolute(r, g, b, color_space).to_color_space(ColorSpace::Oklab); 9886 9887 let mut nearest = (SquaredDistance::from_sqrt(f64::INFINITY), "black"); 9888 for (name, color) in cssparser::color::all_named_colors() { 9889 let color = absolute( 9890 color.0 as f32 / 255.0, 9891 color.1 as f32 / 255.0, 9892 color.2 as f32 / 255.0, 9893 ColorSpace::Srgb, 9894 ) 9895 .to_color_space(ColorSpace::Oklab); 9896 9897 let distance = input.compute_squared_distance(&color).unwrap(); 9898 if distance < nearest.0 { 9899 // DevTools expect the first alphabetically. 9900 nearest = (distance, name); 9901 } 9902 } 9903 result.assign(nearest.1); 9904 return nearest.0 == SquaredDistance::from_sqrt(0.0); 9905 } 9906 9907 #[no_mangle] 9908 pub extern "C" fn Servo_ColorNameToRgb(name: &nsACString, out: &mut structs::nscolor) -> bool { 9909 match cssparser::color::parse_named_color(unsafe { name.as_str_unchecked() }) { 9910 Ok((r, g, b)) => { 9911 *out = style::gecko::values::convert_absolute_color_to_nscolor(&AbsoluteColor::new( 9912 ColorSpace::Srgb, 9913 r, 9914 g, 9915 b, 9916 1.0, 9917 )); 9918 true 9919 }, 9920 _ => false, 9921 } 9922 } 9923 9924 #[repr(u8)] 9925 pub enum RegisterCustomPropertyResult { 9926 SuccessfullyRegistered, 9927 InvalidName, 9928 AlreadyRegistered, 9929 InvalidSyntax, 9930 NoInitialValue, 9931 InvalidInitialValue, 9932 InitialValueNotComputationallyIndependent, 9933 } 9934 9935 /// https://drafts.css-houdini.org/css-properties-values-api-1/#the-registerproperty-function 9936 #[no_mangle] 9937 pub extern "C" fn Servo_RegisterCustomProperty( 9938 per_doc_data: &PerDocumentStyleData, 9939 extra_data: *mut URLExtraData, 9940 name: &nsACString, 9941 syntax: &nsACString, 9942 inherits: bool, 9943 initial_value: Option<&nsACString>, 9944 ) -> RegisterCustomPropertyResult { 9945 use self::RegisterCustomPropertyResult::*; 9946 use style::custom_properties::SpecifiedValue; 9947 use style::properties_and_values::rule::{PropertyRegistrationError, PropertyRuleName}; 9948 use style::properties_and_values::syntax::Descriptor; 9949 9950 let mut per_doc_data = per_doc_data.borrow_mut(); 9951 let url_data = unsafe { UrlExtraData::from_ptr_ref(&extra_data) }; 9952 let name = unsafe { name.as_str_unchecked() }; 9953 let syntax = unsafe { syntax.as_str_unchecked() }; 9954 let initial_value = initial_value.map(|v| unsafe { v.as_str_unchecked() }); 9955 9956 // If name is not a custom property name string, throw a SyntaxError and exit this algorithm. 9957 let name = match style::custom_properties::parse_name(name) { 9958 Ok(n) => Atom::from(n), 9959 Err(()) => return InvalidName, 9960 }; 9961 9962 // If property set already contains an entry with name as its property name (compared 9963 // codepoint-wise), throw an InvalidModificationError and exit this algorithm. 9964 if per_doc_data 9965 .stylist 9966 .custom_property_script_registry() 9967 .get(&name) 9968 .is_some() 9969 { 9970 return AlreadyRegistered; 9971 } 9972 // Attempt to consume a syntax definition from syntax. If it returns failure, throw a 9973 // SyntaxError. Otherwise, let syntax definition be the returned syntax definition. 9974 let Ok(syntax) = Descriptor::from_str(syntax, /* preserve_specified = */ false) else { 9975 return InvalidSyntax; 9976 }; 9977 9978 let initial_value = match initial_value { 9979 Some(v) => { 9980 let mut input = ParserInput::new(v); 9981 let parsed = Parser::new(&mut input) 9982 .parse_entirely(|input| { 9983 input.skip_whitespace(); 9984 SpecifiedValue::parse(input, url_data).map(Arc::new) 9985 }) 9986 .ok(); 9987 if parsed.is_none() { 9988 return InvalidInitialValue; 9989 } 9990 parsed 9991 }, 9992 None => None, 9993 }; 9994 9995 if let Err(error) = 9996 PropertyRegistration::validate_initial_value(&syntax, initial_value.as_deref()) 9997 { 9998 return match error { 9999 PropertyRegistrationError::InitialValueNotComputationallyIndependent => { 10000 InitialValueNotComputationallyIndependent 10001 }, 10002 PropertyRegistrationError::InvalidInitialValue => InvalidInitialValue, 10003 PropertyRegistrationError::NoInitialValue => NoInitialValue, 10004 }; 10005 } 10006 10007 per_doc_data 10008 .stylist 10009 .custom_property_script_registry_mut() 10010 .register(PropertyRegistration { 10011 name: PropertyRuleName(name), 10012 data: PropertyRegistrationData { 10013 syntax, 10014 inherits: if inherits { 10015 PropertyInherits::True 10016 } else { 10017 PropertyInherits::False 10018 }, 10019 initial_value, 10020 }, 10021 url_data: url_data.clone(), 10022 source_location: SourceLocation { line: 0, column: 0 }, 10023 }); 10024 10025 per_doc_data 10026 .stylist 10027 .rebuild_initial_values_for_custom_properties(); 10028 10029 SuccessfullyRegistered 10030 } 10031 10032 #[repr(C)] 10033 pub struct PropDef { 10034 // The name of the property. 10035 pub name: Atom, 10036 // The syntax of the property. 10037 pub syntax: nsCString, 10038 // Whether the property inherits. 10039 pub inherits: bool, 10040 pub has_initial_value: bool, 10041 pub initial_value: nsCString, 10042 // True if the property was set with CSS.registerProperty 10043 pub from_js: bool, 10044 } 10045 10046 impl PropDef { 10047 /// Creates a PropDef from a name and a PropertyRegistration. 10048 pub fn new(name: Atom, property_registration: &PropertyRegistration, from_js: bool) -> Self { 10049 let mut syntax = nsCString::new(); 10050 if let Some(spec) = property_registration.data.syntax.specified_string() { 10051 syntax.assign(spec); 10052 } else { 10053 // FIXME: Descriptor::to_css should behave consistently (probably this shouldn't use 10054 // the ToCss trait). 10055 property_registration 10056 .data 10057 .syntax 10058 .to_css(&mut CssWriter::new(&mut syntax)) 10059 .unwrap(); 10060 }; 10061 let initial_value = property_registration.data.initial_value.to_css_cssstring(); 10062 PropDef { 10063 name, 10064 syntax, 10065 inherits: property_registration.data.inherits(), 10066 has_initial_value: property_registration.data.initial_value.is_some(), 10067 initial_value, 10068 from_js, 10069 } 10070 } 10071 } 10072 10073 #[no_mangle] 10074 pub extern "C" fn Servo_GetRegisteredCustomProperties( 10075 per_doc_data: &PerDocumentStyleData, 10076 custom_properties: &mut nsTArray<PropDef>, 10077 ) { 10078 let stylist = &per_doc_data.borrow().stylist; 10079 10080 custom_properties.extend( 10081 stylist 10082 .custom_property_script_registry() 10083 .get_all() 10084 .iter() 10085 .map(|(name, property_registration)| { 10086 PropDef::new(name.clone(), property_registration, /* from_js */ true) 10087 }), 10088 ); 10089 10090 for (cascade_data, _origin) in stylist.iter_origins() { 10091 custom_properties.extend(cascade_data.custom_property_registrations().iter().map( 10092 |(name, value)| { 10093 let property_registration = &value.last().unwrap().0; 10094 PropDef::new( 10095 name.clone(), 10096 property_registration, 10097 /* from_js */ 10098 false, 10099 ) 10100 }, 10101 )) 10102 } 10103 } 10104 10105 #[no_mangle] 10106 pub unsafe extern "C" fn Servo_GetRegisteredCustomProperty( 10107 per_doc_data: &PerDocumentStyleData, 10108 name: &nsACString, 10109 custom_property: &mut PropDef, 10110 ) -> bool { 10111 let name = name.as_str_unchecked(); 10112 if !name.starts_with("--") { 10113 return false; 10114 } 10115 // We store registered property names without the leading "--". 10116 let name = Atom::from(&name[2..]); 10117 10118 let stylist = &per_doc_data.borrow().stylist; 10119 if let Some(property_registration) = stylist.custom_property_script_registry().get(&name) { 10120 *custom_property = PropDef::new(name, property_registration, /* from_js */ true); 10121 return true; 10122 } 10123 10124 for (cascade_data, _) in stylist.iter_origins() { 10125 if let Some(property_registration) = cascade_data.custom_property_registrations().get(&name) 10126 { 10127 *custom_property = PropDef::new(name, property_registration, /* from_js */ false); 10128 return true; 10129 } 10130 } 10131 10132 false 10133 } 10134 10135 #[no_mangle] 10136 pub unsafe extern "C" fn Servo_Value_Matches_Syntax( 10137 value: &nsACString, 10138 syntax: &nsACString, 10139 extra_data: *mut URLExtraData, 10140 ) -> bool { 10141 use crate::style::properties::CSSWideKeyword; 10142 use style::properties_and_values::syntax::Descriptor; 10143 use style::properties_and_values::value::{AllowComputationallyDependent, SpecifiedValue}; 10144 10145 // Attempt to consume a syntax definition from syntax. 10146 let syntax = unsafe { syntax.as_str_unchecked() }; 10147 let Ok(syntax) = Descriptor::from_str(syntax, /* preserve_specified = */ false) else { 10148 return false; 10149 }; 10150 10151 let css_text = unsafe { value.as_str_unchecked() }; 10152 let mut input = ParserInput::new(css_text); 10153 let mut input = Parser::new(&mut input); 10154 input.skip_whitespace(); 10155 10156 // Consider CSS-wide keywords to match any syntax. 10157 if input.try_parse(CSSWideKeyword::parse).is_ok() { 10158 return true; 10159 } 10160 10161 let url_data = unsafe { UrlExtraData::from_ptr_ref(&extra_data) }; 10162 10163 SpecifiedValue::parse( 10164 &mut input, 10165 &syntax, 10166 url_data, 10167 AllowComputationallyDependent::Yes, 10168 ) 10169 .is_ok() 10170 } 10171 10172 #[repr(C)] 10173 pub struct SelectorWarningData { 10174 /// Index to the selector generating the warning. 10175 pub index: usize, 10176 /// Kind of the warning. 10177 pub kind: SelectorWarningKind, 10178 } 10179 10180 #[no_mangle] 10181 pub extern "C" fn Servo_GetSelectorWarnings( 10182 rule: &LockedStyleRule, 10183 warnings: &mut nsTArray<SelectorWarningData>, 10184 ) { 10185 read_locked_arc(rule, |r| { 10186 for (i, selector) in r.selectors.slice().iter().enumerate() { 10187 for k in SelectorWarningKind::from_selector(selector) { 10188 warnings.push(SelectorWarningData { index: i, kind: k }); 10189 } 10190 } 10191 }); 10192 } 10193 10194 #[no_mangle] 10195 pub extern "C" fn Servo_GetRuleBodyText(initial_text: &nsACString, ret_val: &mut nsACString) { 10196 let css_text = unsafe { initial_text.as_str_unchecked() }; 10197 let mut input = ParserInput::new(&css_text); 10198 let mut input = Parser::new(&mut input); 10199 10200 let mut found_start = false; 10201 10202 // Search forward for the opening brace. 10203 while let Ok(token) = input.next() { 10204 match *token { 10205 Token::CurlyBracketBlock => { 10206 found_start = true; 10207 break; 10208 }, 10209 _ => {}, 10210 } 10211 10212 if token.is_parse_error() { 10213 break; 10214 } 10215 } 10216 10217 if !found_start { 10218 ret_val.set_is_void(true); 10219 return; 10220 } 10221 10222 let token_start = input.position(); 10223 // Parse the nested block to move the parser to the end of the block 10224 let _ = 10225 input.parse_nested_block(|_i| -> Result<(), CssParseError<'_, BasicParseError>> { Ok(()) }); 10226 10227 // We're not guaranteed to have a closing bracket, but when we do, we need to move 10228 // the end offset before it. 10229 let mut token_slice = input.slice_from(token_start); 10230 if token_slice.ends_with("}") { 10231 token_slice = token_slice.strip_suffix("}").unwrap(); 10232 } 10233 ret_val.assign(token_slice); 10234 } 10235 10236 #[no_mangle] 10237 pub extern "C" fn Servo_ReplaceBlockRuleBodyTextInStylesheetText( 10238 stylesheet_text: &nsACString, 10239 line: u32, 10240 column: u32, 10241 new_body_text: &nsACString, 10242 ret_val: &mut nsACString, 10243 ) { 10244 let css_text = unsafe { stylesheet_text.as_str_unchecked() }; 10245 10246 let Some(rule_start_index) = get_byte_index_from_line_and_column(css_text, line, column) else { 10247 ret_val.set_is_void(true); 10248 return; 10249 }; 10250 10251 let mut input = ParserInput::new(&css_text[rule_start_index..]); 10252 let mut input = Parser::new(&mut input); 10253 let mut found_start = false; 10254 10255 // Search forward for the opening brace. 10256 while let Ok(token) = input.next() { 10257 if matches!(*token, Token::CurlyBracketBlock) { 10258 found_start = true; 10259 break; 10260 } 10261 10262 if token.is_parse_error() { 10263 break; 10264 } 10265 } 10266 10267 if !found_start { 10268 ret_val.set_is_void(true); 10269 return; 10270 } 10271 10272 let token_start = input.position(); 10273 let rule_body_start = rule_start_index + token_start.byte_index(); 10274 // Parse the nested block to move the parser to the end of the block 10275 let _ = 10276 input.parse_nested_block(|_i| -> Result<(), CssParseError<'_, BasicParseError>> { Ok(()) }); 10277 let mut rule_body_end = rule_start_index + input.position().byte_index(); 10278 10279 // We're not guaranteed to have a closing bracket, but when we do, we need to move 10280 // the end offset before it. 10281 let token_slice = input.slice_from(token_start); 10282 if token_slice.ends_with("}") { 10283 rule_body_end -= 1; 10284 } 10285 10286 ret_val.append(&css_text[..rule_body_start]); 10287 ret_val.append(new_body_text); 10288 ret_val.append(&css_text[rule_body_end..]); 10289 } 10290 10291 /// Find css_text byte position corresponding to the passed line and column 10292 fn get_byte_index_from_line_and_column(css_text: &str, line: u32, column: u32) -> Option<usize> { 10293 // Find the byte index of the start of the passed line within css_text 10294 let mut line_byte_index = Some(0); 10295 if line != 1 { 10296 let mut current_line = 1; 10297 let mut last_byte = None; 10298 let mut bytes_iter = css_text.bytes(); 10299 line_byte_index = bytes_iter.position(|byte| { 10300 // We want to get the position _after_ the EOF sequence 10301 let on_expected_line = current_line == line; 10302 let is_previous_byte_carriage_return = last_byte == Some(b'\r'); 10303 last_byte = Some(byte); 10304 10305 if byte == b'\r' { 10306 current_line += 1; 10307 } else if byte == b'\n' { 10308 if !is_previous_byte_carriage_return { 10309 current_line += 1; 10310 } else { 10311 return false; 10312 } 10313 } 10314 on_expected_line 10315 }); 10316 } 10317 10318 if line_byte_index.is_none() { 10319 return None; 10320 } 10321 10322 if column == 1 { 10323 return line_byte_index; 10324 } 10325 10326 let line_byte_index = line_byte_index.unwrap(); 10327 let mut current_column = 1; 10328 for (byte_index, _char) in css_text[line_byte_index..].char_indices() { 10329 if current_column == column { 10330 return Some(line_byte_index + byte_index); 10331 } 10332 current_column += 1; 10333 } 10334 10335 None 10336 } 10337 10338 #[repr(C)] 10339 pub struct CSSToken { 10340 pub text: nsCString, 10341 pub token_type: nsCString, 10342 pub has_unit: bool, 10343 pub unit: nsCString, 10344 pub has_number: bool, 10345 pub number: f32, 10346 pub has_value: bool, 10347 pub value: nsCString, 10348 // line and column at which the token starts 10349 pub line: u32, 10350 pub column: u32, 10351 } 10352 10353 #[no_mangle] 10354 pub unsafe extern "C" fn Servo_CSSParser_create(text: &nsACString) -> *mut ParserState { 10355 let css_text = unsafe { text.as_str_unchecked() }; 10356 let mut parser_input = ParserInput::new(&css_text); 10357 let input = Parser::new(&mut parser_input); 10358 Box::into_raw(Box::new(input.state())) 10359 } 10360 10361 #[no_mangle] 10362 pub unsafe extern "C" fn Servo_CSSParser_destroy(state: *mut ParserState) { 10363 drop(Box::from_raw(state)); 10364 } 10365 10366 #[no_mangle] 10367 pub unsafe extern "C" fn Servo_CSSParser_GetCurrentLine(state: &ParserState) -> u32 { 10368 return state.source_location().line; 10369 } 10370 10371 #[no_mangle] 10372 pub unsafe extern "C" fn Servo_CSSParser_GetCurrentColumn(state: &ParserState) -> u32 { 10373 return state.source_location().column; 10374 } 10375 10376 #[no_mangle] 10377 pub unsafe extern "C" fn Servo_CSSParser_NextToken( 10378 text: &nsACString, 10379 state: &mut ParserState, 10380 css_token: &mut CSSToken, 10381 ) -> bool { 10382 let css_text = unsafe { text.as_str_unchecked() }; 10383 let mut parser_input = ParserInput::new(&css_text); 10384 let mut input = Parser::new(&mut parser_input); 10385 input.reset(state); 10386 10387 let token_start = input.position(); 10388 let location_start = state.source_location(); 10389 let Ok(token) = &input.next_including_whitespace_and_comments() else { 10390 return false; 10391 }; 10392 10393 let token_type = match *token { 10394 Token::Ident(_) => "Ident", 10395 Token::AtKeyword(_) => "AtKeyword", 10396 Token::Hash(_) => "Hash", 10397 Token::IDHash(_) => "IDHash", 10398 Token::QuotedString(_) => "QuotedString", 10399 Token::UnquotedUrl(_) => "UnquotedUrl", 10400 Token::Delim(_) => "Delim", 10401 Token::Number { .. } => "Number", 10402 Token::Percentage { .. } => "Percentage", 10403 Token::Dimension { .. } => "Dimension", 10404 Token::WhiteSpace(_) => "WhiteSpace", 10405 Token::Comment(_) => "Comment", 10406 Token::Colon => "Colon", 10407 Token::Semicolon => "Semicolon", 10408 Token::Comma => "Comma", 10409 Token::IncludeMatch => "IncludeMatch", 10410 Token::DashMatch => "DashMatch", 10411 Token::PrefixMatch => "PrefixMatch", 10412 Token::SuffixMatch => "SuffixMatch", 10413 Token::SubstringMatch => "SubstringMatch", 10414 Token::CDO => "CDO", 10415 Token::CDC => "CDC", 10416 Token::Function(_) => "Function", 10417 Token::ParenthesisBlock => "ParenthesisBlock", 10418 Token::SquareBracketBlock => "SquareBracketBlock", 10419 Token::CurlyBracketBlock => "CurlyBracketBlock", 10420 Token::BadUrl(_) => "BadUrl", 10421 Token::BadString(_) => "BadString", 10422 Token::CloseParenthesis => "CloseParenthesis", 10423 Token::CloseSquareBracket => "CloseSquareBracket", 10424 Token::CloseCurlyBracket => "CloseCurlyBracket", 10425 }; 10426 10427 let token_value = match *token { 10428 Token::Ident(value) | 10429 Token::AtKeyword(value) | 10430 Token::Hash(value) | 10431 Token::IDHash(value) | 10432 Token::QuotedString(value) | 10433 Token::UnquotedUrl(value) | 10434 Token::Function(value) | 10435 Token::BadUrl(value) | 10436 Token::BadString(value) => { 10437 let mut text = nsCString::new(); 10438 text.assign(value.as_bytes()); 10439 Some(text) 10440 }, 10441 // value is a str here, we need a different branch to handle it 10442 Token::Comment(value) => { 10443 let mut text = nsCString::new(); 10444 text.assign(value.as_bytes()); 10445 Some(text) 10446 }, 10447 // Delim and WhiteSpace also have value, but they will be similar to text, so don't 10448 // include them 10449 Token::Delim(_) | 10450 Token::WhiteSpace(_) | 10451 // Number, Percentage and Dimension expose numeric values that will be exposed in `number` 10452 Token::Number{..} | 10453 Token::Percentage{..} | 10454 Token::Dimension{..} | 10455 // The rest of the tokens don't expose a string value 10456 Token::Colon | 10457 Token::Semicolon | 10458 Token::Comma | 10459 Token::IncludeMatch | 10460 Token::DashMatch | 10461 Token::PrefixMatch | 10462 Token::SuffixMatch | 10463 Token::SubstringMatch | 10464 Token::CDO | 10465 Token::CDC | 10466 Token::ParenthesisBlock | 10467 Token::SquareBracketBlock | 10468 Token::CurlyBracketBlock | 10469 Token::CloseParenthesis | 10470 Token::CloseSquareBracket | 10471 Token::CloseCurlyBracket => None 10472 }; 10473 10474 let token_unit = match *token { 10475 Token::Dimension { ref unit, .. } => { 10476 let mut unit_text = nsCString::new(); 10477 unit_text.assign(unit.as_bytes()); 10478 Some(unit_text) 10479 }, 10480 _ => None, 10481 }; 10482 10483 let token_number = match *token { 10484 Token::Dimension { ref value, .. } => Some(value), 10485 Token::Number { ref value, .. } => Some(value), 10486 Token::Percentage { ref unit_value, .. } => Some(unit_value), 10487 _ => None, 10488 }; 10489 css_token.has_number = token_number.is_some(); 10490 if css_token.has_number { 10491 css_token.number = *token_number.unwrap(); 10492 } 10493 10494 let need_to_parse_nested_block = match *token { 10495 Token::Function(_) 10496 | Token::ParenthesisBlock 10497 | Token::CurlyBracketBlock 10498 | Token::SquareBracketBlock => true, 10499 _ => false, 10500 }; 10501 10502 let mut text = nsCString::new(); 10503 text.assign(&input.slice_from(token_start)); 10504 10505 css_token.text = text; 10506 css_token.token_type = token_type.into(); 10507 css_token.has_value = token_value.is_some(); 10508 if css_token.has_value { 10509 css_token.value = token_value.unwrap(); 10510 } 10511 css_token.has_unit = token_unit.is_some(); 10512 if css_token.has_unit { 10513 css_token.unit = token_unit.unwrap(); 10514 } 10515 10516 css_token.line = location_start.line; 10517 css_token.column = location_start.column; 10518 10519 if need_to_parse_nested_block { 10520 let _ = input.parse_nested_block(|i| -> Result<(), CssParseError<'_, BasicParseError>> { 10521 *state = i.state(); 10522 Ok(()) 10523 }); 10524 } else { 10525 *state = input.state(); 10526 } 10527 10528 return true; 10529 } 10530 10531 /// Result of resolving an anchor positioning function. 10532 #[repr(u8)] 10533 pub enum AnchorPositioningFunctionResolution { 10534 /// Anchor function invalid. 10535 Invalid, 10536 /// Anchor function resolved to a reference to fallback. 10537 ResolvedReference(*const computed::LengthPercentage), 10538 /// Anchor function resolved to a value. 10539 Resolved(computed::LengthPercentage), 10540 } 10541 10542 fn resolve_anchor_function( 10543 func: &AnchorFunction, 10544 params: &AnchorPosOffsetResolutionParams, 10545 prop_side: PhysicalSide, 10546 ) -> AnchorPositioningFunctionResolution { 10547 if !func.valid_for(prop_side, params.mBaseParams.mPosition) { 10548 return resolve_inset_fallback(func.fallback.as_ref(), params, prop_side); 10549 } 10550 let result = AnchorFunction::resolve(&func.target_element, &func.side, prop_side, params); 10551 match result { 10552 Ok(l) => { 10553 AnchorPositioningFunctionResolution::Resolved(computed::LengthPercentage::new_length(l)) 10554 }, 10555 Err(()) => resolve_inset_fallback(func.fallback.as_ref(), params, prop_side), 10556 } 10557 } 10558 10559 fn resolve_inset_fallback( 10560 fallback: Option<&computed::Inset>, 10561 params: &AnchorPosOffsetResolutionParams, 10562 prop_side: PhysicalSide, 10563 ) -> AnchorPositioningFunctionResolution { 10564 use style::values::computed::length_percentage::Unpacked; 10565 let Some(fallback) = fallback else { 10566 return AnchorPositioningFunctionResolution::Invalid; 10567 }; 10568 match fallback { 10569 computed::Inset::Auto => AnchorPositioningFunctionResolution::Invalid, 10570 computed::Inset::LengthPercentage(lp) => { 10571 AnchorPositioningFunctionResolution::ResolvedReference(lp as *const _) 10572 }, 10573 computed::Inset::AnchorSizeFunction(f) => do_resolve_anchor_size( 10574 f, 10575 params, 10576 AllowAnchorPosResolutionInCalcPercentage::Both(prop_side), 10577 ), 10578 computed::Inset::AnchorFunction(f) => resolve_anchor_function(f, params, prop_side), 10579 computed::Inset::AnchorContainingCalcFunction(clp) => { 10580 let Unpacked::Calc(clp) = clp.unpack() else { 10581 unreachable!(); 10582 }; 10583 match clp.resolve_anchor( 10584 AllowAnchorPosResolutionInCalcPercentage::Both(prop_side), 10585 params, 10586 ) { 10587 Ok((node, clamping_mode)) => AnchorPositioningFunctionResolution::Resolved( 10588 computed::LengthPercentage::new_calc(node, clamping_mode), 10589 ), 10590 Err(_) => AnchorPositioningFunctionResolution::Invalid, 10591 } 10592 }, 10593 } 10594 } 10595 10596 #[no_mangle] 10597 pub extern "C" fn Servo_ResolveAnchorFunction( 10598 func: &AnchorFunction, 10599 params: &AnchorPosOffsetResolutionParams, 10600 prop_side: PhysicalSide, 10601 out: &mut AnchorPositioningFunctionResolution, 10602 ) { 10603 *out = resolve_anchor_function(func, params, prop_side); 10604 } 10605 10606 trait AnchorSizeFallbackResolver { 10607 fn resolve_fallback( 10608 fallback: Option<&Self>, 10609 params: &AnchorPosOffsetResolutionParams, 10610 allowed: AllowAnchorPosResolutionInCalcPercentage, 10611 ) -> AnchorPositioningFunctionResolution; 10612 } 10613 10614 impl AnchorSizeFallbackResolver for computed::Inset { 10615 fn resolve_fallback( 10616 fallback: Option<&Self>, 10617 params: &AnchorPosOffsetResolutionParams, 10618 allowed: AllowAnchorPosResolutionInCalcPercentage, 10619 ) -> AnchorPositioningFunctionResolution { 10620 let Some(fallback) = fallback else { 10621 return AnchorPositioningFunctionResolution::Invalid; 10622 }; 10623 match fallback { 10624 computed::Inset::Auto => AnchorPositioningFunctionResolution::Invalid, 10625 computed::Inset::LengthPercentage(lp) => { 10626 AnchorPositioningFunctionResolution::ResolvedReference(lp as *const _) 10627 }, 10628 computed::Inset::AnchorFunction(f) => { 10629 let side = match allowed { 10630 AllowAnchorPosResolutionInCalcPercentage::Both(s) => s, 10631 AllowAnchorPosResolutionInCalcPercentage::AnchorSizeOnly(_) => { 10632 return AnchorPositioningFunctionResolution::Invalid 10633 }, 10634 }; 10635 resolve_anchor_function(f, params, side) 10636 }, 10637 computed::Inset::AnchorSizeFunction(f) => do_resolve_anchor_size(f, params, allowed), 10638 computed::Inset::AnchorContainingCalcFunction(clp) => { 10639 let Unpacked::Calc(clp) = clp.unpack() else { 10640 unreachable!(); 10641 }; 10642 match clp.resolve_anchor(allowed, ¶ms) { 10643 Ok((node, clamping_mode)) => AnchorPositioningFunctionResolution::Resolved( 10644 computed::LengthPercentage::new_calc(node, clamping_mode), 10645 ), 10646 Err(_) => AnchorPositioningFunctionResolution::Invalid, 10647 } 10648 }, 10649 } 10650 } 10651 } 10652 10653 impl AnchorSizeFallbackResolver for computed::Margin { 10654 fn resolve_fallback( 10655 fallback: Option<&Self>, 10656 params: &AnchorPosOffsetResolutionParams, 10657 allowed: AllowAnchorPosResolutionInCalcPercentage, 10658 ) -> AnchorPositioningFunctionResolution { 10659 let Some(fallback) = fallback else { 10660 return AnchorPositioningFunctionResolution::Invalid; 10661 }; 10662 match fallback { 10663 computed::Margin::Auto => AnchorPositioningFunctionResolution::Invalid, 10664 computed::Margin::LengthPercentage(lp) => { 10665 AnchorPositioningFunctionResolution::ResolvedReference(lp as *const _) 10666 }, 10667 computed::Margin::AnchorSizeFunction(f) => do_resolve_anchor_size(f, params, allowed), 10668 computed::Margin::AnchorContainingCalcFunction(clp) => { 10669 let Unpacked::Calc(clp) = clp.unpack() else { 10670 unreachable!(); 10671 }; 10672 match clp.resolve_anchor(allowed, ¶ms) { 10673 Ok((node, clamping_mode)) => AnchorPositioningFunctionResolution::Resolved( 10674 computed::LengthPercentage::new_calc(node, clamping_mode), 10675 ), 10676 Err(_) => AnchorPositioningFunctionResolution::Invalid, 10677 } 10678 }, 10679 } 10680 } 10681 } 10682 10683 impl AnchorSizeFallbackResolver for computed::Size { 10684 fn resolve_fallback( 10685 fallback: Option<&Self>, 10686 params: &AnchorPosOffsetResolutionParams, 10687 allowed: AllowAnchorPosResolutionInCalcPercentage, 10688 ) -> AnchorPositioningFunctionResolution { 10689 let Some(fallback) = fallback else { 10690 return AnchorPositioningFunctionResolution::Invalid; 10691 }; 10692 match fallback { 10693 computed::Size::Auto 10694 | computed::Size::MaxContent 10695 | computed::Size::MinContent 10696 | computed::Size::FitContent 10697 | computed::Size::MozAvailable 10698 | computed::Size::WebkitFillAvailable 10699 | computed::Size::Stretch 10700 | computed::Size::FitContentFunction(_) => AnchorPositioningFunctionResolution::Invalid, 10701 computed::Size::LengthPercentage(lp) => { 10702 AnchorPositioningFunctionResolution::ResolvedReference(&lp.0 as *const _) 10703 }, 10704 computed::Size::AnchorSizeFunction(f) => do_resolve_anchor_size(f, params, allowed), 10705 computed::Size::AnchorContainingCalcFunction(clp) => { 10706 let Unpacked::Calc(clp) = clp.0.unpack() else { 10707 unreachable!(); 10708 }; 10709 match clp.resolve_anchor(allowed, ¶ms) { 10710 Ok((node, clamping_mode)) => AnchorPositioningFunctionResolution::Resolved( 10711 computed::LengthPercentage::new_calc(node, clamping_mode), 10712 ), 10713 Err(_) => AnchorPositioningFunctionResolution::Invalid, 10714 } 10715 }, 10716 } 10717 } 10718 } 10719 10720 impl AnchorSizeFallbackResolver for computed::MaxSize { 10721 fn resolve_fallback( 10722 fallback: Option<&Self>, 10723 params: &AnchorPosOffsetResolutionParams, 10724 allowed: AllowAnchorPosResolutionInCalcPercentage, 10725 ) -> AnchorPositioningFunctionResolution { 10726 let Some(fallback) = fallback else { 10727 return AnchorPositioningFunctionResolution::Invalid; 10728 }; 10729 match fallback { 10730 computed::MaxSize::None 10731 | computed::MaxSize::MaxContent 10732 | computed::MaxSize::MinContent 10733 | computed::MaxSize::FitContent 10734 | computed::MaxSize::MozAvailable 10735 | computed::MaxSize::WebkitFillAvailable 10736 | computed::MaxSize::Stretch 10737 | computed::MaxSize::FitContentFunction(_) => { 10738 AnchorPositioningFunctionResolution::Invalid 10739 }, 10740 computed::MaxSize::LengthPercentage(lp) => { 10741 AnchorPositioningFunctionResolution::ResolvedReference(&lp.0 as *const _) 10742 }, 10743 computed::MaxSize::AnchorSizeFunction(f) => do_resolve_anchor_size(f, params, allowed), 10744 computed::MaxSize::AnchorContainingCalcFunction(clp) => { 10745 let Unpacked::Calc(clp) = clp.0.unpack() else { 10746 unreachable!(); 10747 }; 10748 match clp.resolve_anchor(allowed, ¶ms) { 10749 Ok((node, clamping_mode)) => AnchorPositioningFunctionResolution::Resolved( 10750 computed::LengthPercentage::new_calc(node, clamping_mode), 10751 ), 10752 Err(_) => AnchorPositioningFunctionResolution::Invalid, 10753 } 10754 }, 10755 } 10756 } 10757 } 10758 10759 fn do_resolve_anchor_size<Value: AnchorSizeFallbackResolver>( 10760 func: &GenericAnchorSizeFunction<Value>, 10761 params: &AnchorPosOffsetResolutionParams, 10762 allowed: AllowAnchorPosResolutionInCalcPercentage, 10763 ) -> AnchorPositioningFunctionResolution { 10764 use style::values::computed::length::resolve_anchor_size; 10765 if !func.valid_for(params.mBaseParams.mPosition) { 10766 return Value::resolve_fallback(func.fallback.as_ref(), params, allowed); 10767 } 10768 let result = resolve_anchor_size( 10769 &func.target_element, 10770 allowed.to_axis(), 10771 func.size, 10772 ¶ms.mBaseParams, 10773 ); 10774 match result { 10775 Ok(l) => { 10776 AnchorPositioningFunctionResolution::Resolved(computed::LengthPercentage::new_length(l)) 10777 }, 10778 Err(()) => return Value::resolve_fallback(func.fallback.as_ref(), params, allowed), 10779 } 10780 } 10781 10782 #[no_mangle] 10783 pub extern "C" fn Servo_ResolveAnchorSizeFunctionForInset( 10784 func: &GenericAnchorSizeFunction<computed::Inset>, 10785 params: &AnchorPosOffsetResolutionParams, 10786 prop_axis: PhysicalAxis, 10787 out: &mut AnchorPositioningFunctionResolution, 10788 ) { 10789 *out = do_resolve_anchor_size( 10790 func, 10791 params, 10792 AllowAnchorPosResolutionInCalcPercentage::AnchorSizeOnly(prop_axis), 10793 ); 10794 } 10795 10796 fn offset_params_from_base_params( 10797 params: &AnchorPosResolutionParams, 10798 ) -> AnchorPosOffsetResolutionParams { 10799 AnchorPosOffsetResolutionParams { 10800 mCBSize: ptr::null(), 10801 mBaseParams: AnchorPosResolutionParams { 10802 mFrame: params.mFrame, 10803 mPosition: params.mPosition, 10804 mCache: params.mCache, 10805 mAutoResolutionOverrideParams: params.mAutoResolutionOverrideParams, 10806 }, 10807 } 10808 } 10809 10810 #[no_mangle] 10811 pub extern "C" fn Servo_ResolveAnchorSizeFunctionForMargin( 10812 func: &GenericAnchorSizeFunction<computed::Margin>, 10813 params: &AnchorPosResolutionParams, 10814 prop_axis: PhysicalAxis, 10815 out: &mut AnchorPositioningFunctionResolution, 10816 ) { 10817 *out = do_resolve_anchor_size( 10818 func, 10819 &offset_params_from_base_params(params), 10820 AllowAnchorPosResolutionInCalcPercentage::AnchorSizeOnly(prop_axis), 10821 ); 10822 } 10823 10824 #[no_mangle] 10825 pub extern "C" fn Servo_ResolveAnchorSizeFunctionForSize( 10826 func: &GenericAnchorSizeFunction<computed::Size>, 10827 params: &AnchorPosResolutionParams, 10828 prop_axis: PhysicalAxis, 10829 out: &mut AnchorPositioningFunctionResolution, 10830 ) { 10831 *out = do_resolve_anchor_size( 10832 func, 10833 &offset_params_from_base_params(params), 10834 AllowAnchorPosResolutionInCalcPercentage::AnchorSizeOnly(prop_axis), 10835 ); 10836 } 10837 10838 #[no_mangle] 10839 pub extern "C" fn Servo_ResolveAnchorSizeFunctionForMaxSize( 10840 func: &GenericAnchorSizeFunction<computed::MaxSize>, 10841 params: &AnchorPosResolutionParams, 10842 prop_axis: PhysicalAxis, 10843 out: &mut AnchorPositioningFunctionResolution, 10844 ) { 10845 *out = do_resolve_anchor_size( 10846 func, 10847 &offset_params_from_base_params(params), 10848 AllowAnchorPosResolutionInCalcPercentage::AnchorSizeOnly(prop_axis), 10849 ); 10850 } 10851 10852 #[no_mangle] 10853 pub extern "C" fn Servo_PhysicalizePositionArea( 10854 area: &mut PositionArea, 10855 cb_wm: &WritingMode, 10856 self_wm: &WritingMode, 10857 ) { 10858 *area = area.to_physical(*cb_wm, *self_wm); 10859 } 10860 10861 /// https://drafts.csswg.org/css-anchor-position-1/#position-area-alignment 10862 #[no_mangle] 10863 pub extern "C" fn Servo_ResolvePositionAreaSelfAlignment( 10864 area: &PositionArea, 10865 axis: LogicalAxis, 10866 cb_wm: &WritingMode, 10867 self_wm: &WritingMode, 10868 out: &mut AlignFlags, 10869 ) { 10870 // As well as converting `area` and `axis` to the same form for comparison 10871 // this also makes sure `area`'s second keyword is explicit (not none). 10872 let physical_area = area.to_physical(*cb_wm, *self_wm); 10873 let physical_axis = axis.to_physical(*cb_wm); 10874 let area_keyword = match physical_axis { 10875 PhysicalAxis::Horizontal => physical_area.first, 10876 PhysicalAxis::Vertical => physical_area.second, 10877 }; 10878 // Note that area_keyword is a physical value (left/right/top/bottom). 10879 let Some(align) = area_keyword.to_self_alignment(axis, cb_wm) else { 10880 debug_assert!( 10881 false, 10882 "ResolvePositionAreaSelfAlignment called on {:?}", 10883 area 10884 ); 10885 return; 10886 }; 10887 *out = align; 10888 }