Implement CSSKeyframesRule and CSSKeyframeRule for stylo.

This commit is contained in:
Xidorn Quan 2017-05-19 13:25:06 +10:00
parent 32a10073c1
commit 462cc49e42
4 changed files with 165 additions and 19 deletions

View file

@ -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<ImportRule> => RawServoImportRule
impl_arc_ffi!(AnimationValue => RawServoAnimationValue
[Servo_AnimationValue_AddRef, Servo_AnimationValue_Release]);
impl_arc_ffi!(Locked<Keyframe> => RawServoKeyframe
[Servo_Keyframe_AddRef, Servo_Keyframe_Release]);
impl_arc_ffi!(Locked<KeyframesRule> => RawServoKeyframesRule
[Servo_KeyframesRule_AddRef, Servo_KeyframesRule_Release]);
impl_arc_ffi!(Locked<MediaList> => RawServoMediaList
[Servo_MediaList_AddRef, Servo_MediaList_Release]);

View file

@ -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<KeyframePercentage>);
impl ToCss for KeyframeSelector {

View file

@ -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<usize> {
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 {

View file

@ -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::<PropertyDeclarationBlock>::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::<KeyframesRule>::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| {