diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs index 32294ad1ce1..6619059d54c 100644 --- a/components/style/gecko/arc_types.rs +++ b/components/style/gecko/arc_types.rs @@ -8,20 +8,23 @@ #![allow(non_snake_case, missing_docs)] -use gecko_bindings::bindings::{RawServoMediaList, RawServoMediaRule, RawServoNamespaceRule, RawServoPageRule}; +use gecko_bindings::bindings::{RawServoKeyframe, RawServoKeyframesRule}; +use gecko_bindings::bindings::{RawServoMediaList, RawServoMediaRule}; +use gecko_bindings::bindings::{RawServoNamespaceRule, RawServoPageRule}; use gecko_bindings::bindings::{RawServoRuleNode, RawServoRuleNodeStrong, RawServoDocumentRule}; use gecko_bindings::bindings::{RawServoStyleSheet, RawServoImportRule, RawServoSupportsRule}; use gecko_bindings::bindings::{ServoComputedValues, ServoCssRules}; use gecko_bindings::structs::{RawServoDeclarationBlock, RawServoStyleRule}; use gecko_bindings::structs::RawServoAnimationValue; use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI}; +use keyframes::Keyframe; use media_queries::MediaList; use properties::{ComputedValues, PropertyDeclarationBlock}; use properties::animated_properties::AnimationValue; use rule_tree::StrongRuleNode; use shared_lock::Locked; use std::{mem, ptr}; -use stylesheets::{CssRules, Stylesheet, StyleRule, ImportRule, MediaRule}; +use stylesheets::{CssRules, Stylesheet, StyleRule, ImportRule, KeyframesRule, MediaRule}; use stylesheets::{NamespaceRule, PageRule, SupportsRule, DocumentRule}; macro_rules! impl_arc_ffi { @@ -64,6 +67,12 @@ impl_arc_ffi!(Locked => RawServoImportRule impl_arc_ffi!(AnimationValue => RawServoAnimationValue [Servo_AnimationValue_AddRef, Servo_AnimationValue_Release]); +impl_arc_ffi!(Locked => RawServoKeyframe + [Servo_Keyframe_AddRef, Servo_Keyframe_Release]); + +impl_arc_ffi!(Locked => RawServoKeyframesRule + [Servo_KeyframesRule_AddRef, Servo_KeyframesRule_Release]); + impl_arc_ffi!(Locked => RawServoMediaList [Servo_MediaList_AddRef, Servo_MediaList_Release]); diff --git a/components/style/keyframes.rs b/components/style/keyframes.rs index a817d42b076..ab797b191f3 100644 --- a/components/style/keyframes.rs +++ b/components/style/keyframes.rs @@ -71,7 +71,7 @@ impl KeyframePercentage { /// A keyframes selector is a list of percentages or from/to symbols, which are /// converted at parse time to percentages. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub struct KeyframeSelector(Vec); impl ToCss for KeyframeSelector { diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 4b8438e59d9..2c55c73fd8d 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -25,7 +25,7 @@ pub use gecko::rules::{CounterStyleRule, FontFaceRule}; use gecko_bindings::structs::URLExtraData; #[cfg(feature = "gecko")] use gecko_bindings::sugar::refptr::RefPtr; -use keyframes::{Keyframe, parse_keyframe_list}; +use keyframes::{Keyframe, KeyframeSelector, parse_keyframe_list}; use media_queries::{Device, MediaList, parse_media_query_list}; use parking_lot::RwLock; use parser::{PARSING_MODE_DEFAULT, Parse, ParserContext, log_css_error}; @@ -586,6 +586,24 @@ impl ToCssWithGuard for KeyframesRule { } } +impl KeyframesRule { + /// Returns the index of the last keyframe that matches the given selector. + /// If the selector is not valid, or no keyframe is found, returns None. + /// + /// Related spec: + /// https://drafts.csswg.org/css-animations-1/#interface-csskeyframesrule-findrule + pub fn find_rule(&self, guard: &SharedRwLockReadGuard, selector: &str) -> Option { + if let Ok(selector) = Parser::new(selector).parse_entirely(KeyframeSelector::parse) { + for (i, keyframe) in self.keyframes.iter().enumerate().rev() { + if keyframe.read_with(guard).selector == selector { + return Some(i); + } + } + } + None + } +} + #[allow(missing_docs)] #[derive(Debug)] pub struct MediaRule { diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index d04625727aa..c56d9ebb39f 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -29,6 +29,8 @@ use style::gecko_bindings::bindings; use style::gecko_bindings::bindings::{RawGeckoKeyframeListBorrowed, RawGeckoKeyframeListBorrowedMut}; use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong}; use style::gecko_bindings::bindings::{RawServoDocumentRule, RawServoDocumentRuleBorrowed}; +use style::gecko_bindings::bindings::{RawServoKeyframe, RawServoKeyframeBorrowed, RawServoKeyframeStrong}; +use style::gecko_bindings::bindings::{RawServoKeyframesRule, RawServoKeyframesRuleBorrowed}; use style::gecko_bindings::bindings::{RawServoMediaList, RawServoMediaListBorrowed, RawServoMediaListStrong}; use style::gecko_bindings::bindings::{RawServoMediaRule, RawServoMediaRuleBorrowed}; use style::gecko_bindings::bindings::{RawServoNamespaceRule, RawServoNamespaceRuleBorrowed}; @@ -74,7 +76,7 @@ use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasFFI, HasArcFFI, use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong}; use style::gecko_bindings::sugar::refptr::RefPtr; use style::gecko_properties::{self, style_structs}; -use style::keyframes::KeyframesStepValue; +use style::keyframes::{Keyframe, KeyframeSelector, KeyframesStepValue}; use style::media_queries::{MediaList, parse_media_query_list}; use style::parallel; use style::parser::{PARSING_MODE_DEFAULT, ParserContext}; @@ -92,7 +94,7 @@ use style::string_cache::Atom; use style::style_adjuster::StyleAdjuster; use style::stylearc::Arc; use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers}; -use style::stylesheets::{ImportRule, MediaRule, NamespaceRule, Origin}; +use style::stylesheets::{ImportRule, KeyframesRule, MediaRule, NamespaceRule, Origin}; use style::stylesheets::{PageRule, Stylesheet, StyleRule, SupportsRule, DocumentRule}; use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; use style::supports::parse_condition_or_declaration; @@ -100,6 +102,7 @@ use style::thread_state; use style::timer::Timer; use style::traversal::{ANIMATION_ONLY, FOR_RECONSTRUCT, UNSTYLED_CHILDREN_ONLY}; use style::traversal::{resolve_style, DomTraversal, TraversalDriver, TraversalFlags}; +use style::values::{CustomIdent, KeyframesName}; use style_traits::ToCss; use super::stylesheet_loader::StylesheetLoader; @@ -774,6 +777,28 @@ pub extern "C" fn Servo_CssRules_DeleteRule(rules: ServoCssRulesBorrowed, index: }) } +macro_rules! impl_basic_rule_funcs_without_getter { + { ($rule_type:ty, $raw_type:ty), + debug: $debug:ident, + to_css: $to_css:ident, + } => { + #[no_mangle] + pub extern "C" fn $debug(rule: &$raw_type, result: *mut nsACString) { + read_locked_arc(rule, |rule: &$rule_type| { + write!(unsafe { result.as_mut().unwrap() }, "{:?}", *rule).unwrap(); + }) + } + + #[no_mangle] + pub extern "C" fn $to_css(rule: &$raw_type, result: *mut nsAString) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::<$rule_type>::as_arc(&rule); + rule.read_with(&guard).to_css(&guard, unsafe { result.as_mut().unwrap() }).unwrap(); + } + } +} + macro_rules! impl_basic_rule_funcs { { ($name:ident, $rule_type:ty, $raw_type:ty), getter: $getter:ident, @@ -801,19 +826,9 @@ macro_rules! impl_basic_rule_funcs { } } - #[no_mangle] - pub extern "C" fn $debug(rule: &$raw_type, result: *mut nsACString) { - read_locked_arc(rule, |rule: &$rule_type| { - write!(unsafe { result.as_mut().unwrap() }, "{:?}", *rule).unwrap(); - }) - } - - #[no_mangle] - pub extern "C" fn $to_css(rule: &$raw_type, result: *mut nsAString) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let rule = Locked::<$rule_type>::as_arc(&rule); - rule.read_with(&guard).to_css(&guard, unsafe { result.as_mut().unwrap() }).unwrap(); + impl_basic_rule_funcs_without_getter! { ($rule_type, $raw_type), + debug: $debug, + to_css: $to_css, } } } @@ -840,6 +855,17 @@ impl_basic_rule_funcs! { (Style, StyleRule, RawServoStyleRule), to_css: Servo_StyleRule_GetCssText, } +impl_basic_rule_funcs_without_getter! { (Keyframe, RawServoKeyframe), + debug: Servo_Keyframe_Debug, + to_css: Servo_Keyframe_GetCssText, +} + +impl_basic_rule_funcs! { (Keyframes, KeyframesRule, RawServoKeyframesRule), + getter: Servo_CssRules_GetKeyframesRuleAt, + debug: Servo_KeyframesRule_Debug, + to_css: Servo_KeyframesRule_GetCssText, +} + impl_group_rule_funcs! { (Media, MediaRule, RawServoMediaRule), get_rules: Servo_MediaRule_GetRules, getter: Servo_CssRules_GetMediaRuleAt, @@ -918,6 +944,99 @@ pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowe }) } +#[no_mangle] +pub extern "C" fn Servo_Keyframe_GetKeyText(keyframe: RawServoKeyframeBorrowed, result: *mut nsAString) { + read_locked_arc(keyframe, |keyframe: &Keyframe| { + keyframe.selector.to_css(unsafe { result.as_mut().unwrap() }).unwrap() + }) +} + +#[no_mangle] +pub extern "C" fn Servo_Keyframe_SetKeyText(keyframe: RawServoKeyframeBorrowed, text: *const nsACString) -> bool { + let text = unsafe { text.as_ref().unwrap().as_str_unchecked() }; + if let Ok(selector) = Parser::new(&text).parse_entirely(KeyframeSelector::parse) { + write_locked_arc(keyframe, |keyframe: &mut Keyframe| { + keyframe.selector = selector; + }); + true + } else { + false + } +} + +#[no_mangle] +pub extern "C" fn Servo_Keyframe_GetStyle(keyframe: RawServoKeyframeBorrowed) -> RawServoDeclarationBlockStrong { + read_locked_arc(keyframe, |keyframe: &Keyframe| keyframe.block.clone().into_strong()) +} + +#[no_mangle] +pub extern "C" fn Servo_Keyframe_SetStyle(keyframe: RawServoKeyframeBorrowed, + declarations: RawServoDeclarationBlockBorrowed) { + let declarations = Locked::::as_arc(&declarations); + write_locked_arc(keyframe, |keyframe: &mut Keyframe| { + keyframe.block = declarations.clone(); + }) +} + +#[no_mangle] +pub extern "C" fn Servo_KeyframesRule_GetName(rule: RawServoKeyframesRuleBorrowed) -> *mut nsIAtom { + read_locked_arc(rule, |rule: &KeyframesRule| rule.name.as_atom().as_ptr()) +} + +#[no_mangle] +pub extern "C" fn Servo_KeyframesRule_SetName(rule: RawServoKeyframesRuleBorrowed, name: *mut nsIAtom) { + write_locked_arc(rule, |rule: &mut KeyframesRule| { + rule.name = KeyframesName::Ident(CustomIdent(unsafe { Atom::from_addrefed(name) })); + }) +} + +#[no_mangle] +pub extern "C" fn Servo_KeyframesRule_GetCount(rule: RawServoKeyframesRuleBorrowed) -> u32 { + read_locked_arc(rule, |rule: &KeyframesRule| rule.keyframes.len() as u32) +} + +#[no_mangle] +pub extern "C" fn Servo_KeyframesRule_GetKeyframe(rule: RawServoKeyframesRuleBorrowed, index: u32) + -> RawServoKeyframeStrong { + read_locked_arc(rule, |rule: &KeyframesRule| { + rule.keyframes[index as usize].clone().into_strong() + }) +} + +#[no_mangle] +pub extern "C" fn Servo_KeyframesRule_FindRule(rule: RawServoKeyframesRuleBorrowed, + key: *const nsACString) -> u32 { + let key = unsafe { key.as_ref().unwrap().as_str_unchecked() }; + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + Locked::::as_arc(&rule).read_with(&guard) + .find_rule(&guard, key).map(|index| index as u32) + .unwrap_or(u32::max_value()) +} + +#[no_mangle] +pub extern "C" fn Servo_KeyframesRule_AppendRule(rule: RawServoKeyframesRuleBorrowed, + sheet: RawServoStyleSheetBorrowed, + css: *const nsACString) -> bool { + let css = unsafe { css.as_ref().unwrap().as_str_unchecked() }; + let sheet = Stylesheet::as_arc(&sheet); + if let Ok(keyframe) = Keyframe::parse(css, sheet) { + write_locked_arc(rule, |rule: &mut KeyframesRule| { + rule.keyframes.push(keyframe); + }); + true + } else { + false + } +} + +#[no_mangle] +pub extern "C" fn Servo_KeyframesRule_DeleteRule(rule: RawServoKeyframesRuleBorrowed, index: u32) { + write_locked_arc(rule, |rule: &mut KeyframesRule| { + rule.keyframes.remove(index as usize); + }) +} + #[no_mangle] pub extern "C" fn Servo_MediaRule_GetMedia(rule: RawServoMediaRuleBorrowed) -> RawServoMediaListStrong { read_locked_arc(rule, |rule: &MediaRule| {