diff options
Diffstat (limited to 'servo/ports/geckolib')
-rw-r--r-- | servo/ports/geckolib/Cargo.toml | 1 | ||||
-rw-r--r-- | servo/ports/geckolib/cbindgen.toml | 13 | ||||
-rw-r--r-- | servo/ports/geckolib/glue.rs | 210 | ||||
-rw-r--r-- | servo/ports/geckolib/lib.rs | 1 |
4 files changed, 183 insertions, 42 deletions
diff --git a/servo/ports/geckolib/Cargo.toml b/servo/ports/geckolib/Cargo.toml index ebf4178014..1bdaaa80b7 100644 --- a/servo/ports/geckolib/Cargo.toml +++ b/servo/ports/geckolib/Cargo.toml @@ -31,3 +31,4 @@ style = {path = "../../components/style", features = ["gecko"]} style_traits = {path = "../../components/style_traits"} thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } to_shmem = {path = "../../components/to_shmem"} +lazy_static = "1.0" diff --git a/servo/ports/geckolib/cbindgen.toml b/servo/ports/geckolib/cbindgen.toml index b703dc6c92..8e6818e421 100644 --- a/servo/ports/geckolib/cbindgen.toml +++ b/servo/ports/geckolib/cbindgen.toml @@ -140,6 +140,7 @@ include = [ "ScrollSnapStrictness", "ScrollSnapType", "ScrollTimelineName", + "TransitionBehavior", "ViewTimelineInset", "OverflowAnchor", "OverflowClipBox", @@ -365,9 +366,7 @@ renaming_overrides_prefixing = true "CalcLengthPercentage" = """ inline CSSCoord ResolveToCSSPixels(CSSCoord aBasis) const; - - using CoordRounder = nscoord(*)(float); - nscoord Resolve(nscoord aBasis, CoordRounder) const; + inline nscoord Resolve(nscoord aBasis) const; """ "GenericCalcNode" = """ @@ -428,10 +427,10 @@ renaming_overrides_prefixing = true inline bool IsDefinitelyZero() const; inline CSSCoord ResolveToCSSPixels(CSSCoord aPercentageBasisInCSSPixels) const; template<typename T> inline CSSCoord ResolveToCSSPixelsWith(T aPercentageGetter) const; - template<typename T, typename U> - inline nscoord Resolve(T aPercentageGetter, U aRoundingFunction) const; - template<typename T> - inline nscoord Resolve(nscoord aPercentageBasis, T aRoundingFunction) const; + template<typename T, typename PercentRounder> + inline nscoord Resolve(T aPercentageGetter, PercentRounder) const; + template<typename PercentRounder> + inline nscoord Resolve(nscoord aPercentageBasis, PercentRounder) const; template<typename T> inline nscoord Resolve(T aPercentageGetter) const; inline nscoord Resolve(nscoord aPercentageBasis) const; """ diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index a6c4ef1262..83c55ad9e0 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -6,7 +6,7 @@ use super::error_reporter::ErrorReporter; use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader}; use bincode::{deserialize, serialize}; use cssparser::ToCss as ParserToCss; -use cssparser::{Parser, ParserInput, SourceLocation, UnicodeRange}; +use cssparser::{BasicParseError, ParseError as CssParseError, Parser, ParserInput, SourceLocation, UnicodeRange, Token}; use dom::{DocumentState, ElementState}; use malloc_size_of::MallocSizeOfOps; use nsstring::{nsCString, nsString}; @@ -14,7 +14,6 @@ use selectors::matching::{ElementSelectorFlags, MatchingForInvalidation, Selecto use selectors::{Element, OpaqueElement}; use servo_arc::{Arc, ArcBorrow}; use smallvec::SmallVec; -use style::custom_properties::DeferFontRelativeCustomPropertyResolution; use std::collections::BTreeSet; use std::fmt::Write; use std::iter; @@ -26,6 +25,7 @@ use style::computed_value_flags::ComputedValueFlags; use style::context::ThreadLocalStyleContext; use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext}; use style::counter_style; +use style::custom_properties::DeferFontRelativeCustomPropertyResolution; use style::data::{self, ElementStyles}; use style::dom::{ShowSubtreeData, TDocument, TElement, TNode}; use style::driver; @@ -204,6 +204,9 @@ pub unsafe extern "C" fn Servo_Initialize( // Pretend that we're a Servo Layout thread, to make some assertions happy. thread_state::initialize(thread_state::ThreadState::LAYOUT); + debug_assert!(is_main_thread()); + lazy_static::initialize(&STYLE_THREAD_POOL); + // Perform some debug-only runtime assertions. origin_flags::assert_flags_match(); traversal_flags::assert_traversal_flags_match(); @@ -1204,8 +1207,16 @@ pub struct ShouldTransitionResult { } #[inline] -fn is_transitionable(prop: PropertyDeclarationId) -> bool { - prop.is_animatable() && !prop.is_discrete_animatable() +fn is_transitionable(prop: PropertyDeclarationId, behavior: computed::TransitionBehavior) -> bool { + if !prop.is_animatable() { + return false; + } + + match behavior { + computed::TransitionBehavior::Normal => !prop.is_discrete_animatable(), + // If transition-behavior is allow-discrete, transitionable is the same as animatable. + computed::TransitionBehavior::AllowDiscrete => true, + } } #[no_mangle] @@ -1213,6 +1224,7 @@ pub extern "C" fn Servo_ComputedValues_ShouldTransition( old: &ComputedValues, new: &ComputedValues, prop: &structs::AnimatedPropertyID, + behavior: computed::TransitionBehavior, old_transition_value: Option<&AnimationValue>, start: &mut structs::RefPtr<AnimationValue>, end: &mut structs::RefPtr<AnimationValue>, @@ -1221,7 +1233,7 @@ pub extern "C" fn Servo_ComputedValues_ShouldTransition( return Default::default(); }; let prop = prop.as_borrowed(); - if !is_transitionable(prop) { + if !is_transitionable(prop, behavior) { return Default::default(); } @@ -1241,7 +1253,10 @@ pub extern "C" fn Servo_ComputedValues_ShouldTransition( let Some(old_value) = AnimationValue::from_computed_values(prop, old) else { return Default::default(); }; - if old_value == new_value || !old_value.interpolable_with(&new_value) { + if old_value == new_value + || (matches!(behavior, computed::TransitionBehavior::Normal) + && !old_value.interpolable_with(&new_value)) + { return Default::default(); } @@ -1263,8 +1278,9 @@ pub extern "C" fn Servo_ComputedValues_TransitionValueMatches( let Some(prop) = OwnedPropertyDeclarationId::from_gecko_animated_property_id(prop) else { return false; }; + // Note: the running transitions should be transitionable, so it is always allow-discrete. let prop = prop.as_borrowed(); - if !is_transitionable(prop) { + if !is_transitionable(prop, computed::TransitionBehavior::AllowDiscrete) { return false; } let Some(value) = AnimationValue::from_computed_values(prop, style) else { @@ -1366,7 +1382,9 @@ pub unsafe extern "C" fn Servo_Property_IsInherited( let longhand_id = match prop_id { PropertyId::Custom(property_name) => { let stylist = &per_doc_data.borrow().stylist; - return stylist.get_custom_property_registration(&property_name).inherits() + return stylist + .get_custom_property_registration(&property_name) + .inherits(); }, PropertyId::NonCustom(id) => match id.longhand_or_shorthand() { Ok(lh) => lh, @@ -6156,9 +6174,9 @@ pub extern "C" fn Servo_GetComputedKeyframeValues( raw_data: &PerDocumentStyleData, computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>, ) { - use style::properties::PropertyDeclaration; - use style::custom_properties::CustomPropertiesBuilder; use style::applicable_declarations::CascadePriority; + use style::custom_properties::CustomPropertiesBuilder; + use style::properties::PropertyDeclaration; let data = raw_data.borrow(); let element = GeckoElement(element); let pseudo = PseudoElement::from_pseudo_type(pseudo_type, None); @@ -6197,8 +6215,8 @@ pub extern "C" fn Servo_GetComputedKeyframeValues( let mut seen = PropertyDeclarationIdSet::default(); let mut iter = PrioritizedPropertyIter::new(&keyframe.mPropertyValues); - // FIXME: This is pretty much a hack. Instead, the AnimatedValue should be better - // integrated in the cascade. This would allow us to fix revert() too. + // FIXME (bug 1883255): This is pretty much a hack. Instead, the AnimatedValue should be + // better integrated in the cascade. { let mut builder = CustomPropertiesBuilder::new_with_properties( &data.stylist, @@ -6207,10 +6225,11 @@ pub extern "C" fn Servo_GetComputedKeyframeValues( ); let priority = CascadePriority::same_tree_author_normal_at_root_layer(); for property in &mut iter { - let is_custom = match PropertyId::from_gecko_animated_property_id(&property.mProperty) { - Some(PropertyId::Custom(..)) => true, - _ => false, - }; + let is_custom = + match PropertyId::from_gecko_animated_property_id(&property.mProperty) { + Some(PropertyId::Custom(..)) => true, + _ => false, + }; if !is_custom { break; // Custom props are guaranteed to sort earlier. } @@ -6226,7 +6245,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues( } } iter.reset(); - let _deferred= builder.build(DeferFontRelativeCustomPropertyResolution::No); + let _deferred = builder.build(DeferFontRelativeCustomPropertyResolution::No); debug_assert!( _deferred.is_none(), "Custom property processing deferred despite specifying otherwise?" @@ -6265,7 +6284,8 @@ pub extern "C" fn Servo_GetComputedKeyframeValues( ptr::write( &mut animation_values[property_index], structs::PropertyStyleAnimationValuePair { - mProperty: property.to_gecko_animated_property_id(/* owned = */ true), + mProperty: property + .to_gecko_animated_property_id(/* owned = */ true), mValue: structs::AnimationValue { mServo: value.map_or(structs::RefPtr::null(), |v| { structs::RefPtr::from_arc(Arc::new(v)) @@ -6331,10 +6351,7 @@ pub extern "C" fn Servo_GetAnimationValues( let guard = global_style_data.shared_lock.read(); let guard = declarations.read_with(&guard); - let iter = guard.to_animation_value_iter( - &mut context, - &default_values, - ); + let iter = guard.to_animation_value_iter(&mut context, &default_values); animation_values.extend(iter.map(|v| structs::RefPtr::from_arc(Arc::new(v)))); } @@ -6385,11 +6402,7 @@ pub extern "C" fn Servo_AnimationValue_Compute( .next() { Some((decl, imp)) if imp == Importance::Normal => { - let animation = AnimationValue::from_declaration( - decl, - &mut context, - default_values, - ); + let animation = AnimationValue::from_declaration(decl, &mut context, default_values); animation.map_or(Strong::null(), |value| Arc::new(value).into()) }, _ => Strong::null(), @@ -7267,8 +7280,10 @@ pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForInsertion( let data = raw_data.borrow(); let quirks_mode: QuirksMode = data.stylist.quirks_mode(); - let inherited = - inherit_relative_selector_search_direction(element.parent_element(), element.prev_sibling_element()); + let inherited = inherit_relative_selector_search_direction( + element.parent_element(), + element.prev_sibling_element(), + ); // Technically, we're not handling breakouts, where the anchor is a (later-sibling) descendant. // For descendant case, we're ok since it's a descendant of an element yet to be styled. // For later-sibling descendant, `HAS_SLOW_SELECTOR_LATER_SIBLINGS` is set anyway. @@ -7392,9 +7407,11 @@ fn get_siblings_of_element<'e>( ) -> (Option<GeckoElement<'e>>, Option<GeckoElement<'e>>) { let node = match following_node { Some(n) => n, - None => return match element.as_node().parent_node() { - Some(p) => (p.last_child_element(), None), - None => (None, None), + None => { + return match element.as_node().parent_node() { + Some(p) => (p.last_child_element(), None), + None => (None, None), + } }, }; @@ -7416,12 +7433,12 @@ pub extern "C" fn Servo_StyleSet_MaybeInvalidateRelativeSelectorForRemoval( return; } let following_node = following_node.map(GeckoNode); - let (prev_sibling, next_sibling) = - get_siblings_of_element(element, &following_node); + let (prev_sibling, next_sibling) = get_siblings_of_element(element, &following_node); let data = raw_data.borrow(); let quirks_mode: QuirksMode = data.stylist.quirks_mode(); - let inherited = inherit_relative_selector_search_direction(element.parent_element(), prev_sibling); + let inherited = + inherit_relative_selector_search_direction(element.parent_element(), prev_sibling); if inherited.is_empty() { return; } @@ -7952,6 +7969,74 @@ pub unsafe extern "C" fn Servo_ComputeColor( } #[no_mangle] +pub unsafe extern "C" fn Servo_ColorTo( + from_color: &nsACString, + to_color_space: &nsACString, + result_color: &mut nsACString, + result_components: &mut nsTArray<f32>, + result_adjusted: &mut bool, + loader: *mut Loader, +) -> bool { + // Figure out the color space. + let mut input = ParserInput::new(to_color_space.as_str_unchecked()); + let mut input = Parser::new(&mut input); + let to_color_space = match ColorSpace::parse(&mut input) { + Ok(color_space) => color_space, + Err(_) => { + // Can't parse the color space? Fail the conversion. + return false; + }, + }; + + let mut input = ParserInput::new(from_color.as_str_unchecked()); + let mut input = Parser::new(&mut input); + + let reporter = loader.as_mut().and_then(|loader| { + // Make an ErrorReporter that will report errors as being "from DOM". + ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut()) + }); + + let context = ParserContext::new( + Origin::Author, + dummy_url_data(), + Some(CssRuleType::Style), + ParsingMode::DEFAULT, + QuirksMode::NoQuirks, + /* namespaces = */ Default::default(), + reporter.as_ref().map(|e| e as &dyn ParseErrorReporter), + None, + ); + + let specified = match specified::Color::parse(&context, &mut input) { + Ok(color) => color, + Err(_) => return false, + }; + + let color = match specified { + specified::Color::Absolute(ref absolute) => &absolute.color, + _ => { + // Can't do anything with a non-absolute color from here, so we + // fail the conversion. + return false; + }, + }; + + let color = color.to_color_space(to_color_space); + let mut s = String::new(); + color + .write_author_preferred_value(&mut CssWriter::new(&mut s)) + .unwrap(); + result_color.assign(&s); + + result_components.assign_from_iter_pod(color.raw_components().iter().copied()); + + // For now we don't do gamut mapping, so always false. + *result_adjusted = false; + + true +} + +#[no_mangle] pub extern "C" fn Servo_ResolveColor( color: &computed::Color, foreground: &style::color::AbsoluteColor, @@ -8919,3 +9004,58 @@ pub extern "C" fn Servo_GetSelectorWarnings( } }); } + +#[no_mangle] +pub extern "C" fn Servo_GetRuleBodyTextOffsets( + initial_text: &nsACString, + result_start_offset: &mut u32, + result_end_offset: &mut u32, +) -> bool { + let css_text = unsafe { initial_text.as_str_unchecked() }; + let mut input = ParserInput::new(&css_text); + let mut input = Parser::new(&mut input); + + let mut start_offset = 0; + let mut found_start = false; + + // Search forward for the opening brace. + while let Ok(token) = input.next() { + match *token { + Token::CurlyBracketBlock => { + start_offset = input.position().byte_index(); + found_start = true; + break; + }, + _ => {} + } + + if token.is_parse_error() { + return false; + } + } + + + if !found_start { + return false; + } + + let token_start = input.position(); + // Parse the nested block to move the parser to the end of the block + let _ = input.parse_nested_block( + |_i| -> Result<(), CssParseError<'_, BasicParseError>> { + Ok(()) + } + ); + let mut end_offset = input.position().byte_index(); + // We're not guaranteed to have a closing bracket, but when we do, we need to move + // the end offset before it. + let token_slice = input.slice_from(token_start); + if token_slice.ends_with("}") { + end_offset = end_offset - 1; + } + + *result_start_offset = start_offset as u32; + *result_end_offset = end_offset as u32; + + return true; +} diff --git a/servo/ports/geckolib/lib.rs b/servo/ports/geckolib/lib.rs index c11f6ab36e..8f6f344d4d 100644 --- a/servo/ports/geckolib/lib.rs +++ b/servo/ports/geckolib/lib.rs @@ -23,6 +23,7 @@ extern crate style; extern crate style_traits; extern crate thin_vec; extern crate to_shmem; +extern crate lazy_static; mod error_reporter; #[allow(non_snake_case)] |