summaryrefslogtreecommitdiffstats
path: root/servo/ports/geckolib
diff options
context:
space:
mode:
Diffstat (limited to 'servo/ports/geckolib')
-rw-r--r--servo/ports/geckolib/Cargo.toml1
-rw-r--r--servo/ports/geckolib/cbindgen.toml13
-rw-r--r--servo/ports/geckolib/glue.rs210
-rw-r--r--servo/ports/geckolib/lib.rs1
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)]