mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #18650 - hiikezoe:custom-properties-in-keyframes, r=<try>
Handle custom properties in keyframes <!-- Please describe your changes on the following line: --> https://bugzilla.mozilla.org/show_bug.cgi?id=1402219 --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18650) <!-- Reviewable:end -->
This commit is contained in:
commit
92eb88277f
12 changed files with 1450 additions and 728 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1068,6 +1068,7 @@ dependencies = [
|
|||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"selectors 0.19.0",
|
||||
"servo_arc 0.0.1",
|
||||
"smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"style 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"stylo_tests 0.0.1",
|
||||
|
@ -3235,6 +3236,7 @@ dependencies = [
|
|||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"selectors 0.19.0",
|
||||
"size_of_test 0.0.1",
|
||||
"smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"style 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
]
|
||||
|
|
|
@ -2601,7 +2601,9 @@ extern "C" {
|
|||
property: nsCSSPropertyID,
|
||||
buffer: *mut nsAString,
|
||||
computed_values:
|
||||
ServoStyleContextBorrowedOrNull);
|
||||
ServoStyleContextBorrowedOrNull,
|
||||
custom_properties:
|
||||
RawServoDeclarationBlockBorrowedOrNull);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_DeclarationBlock_Count(declarations:
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -151,16 +151,21 @@ pub struct AnimationValueIterator<'a, 'cx, 'cx_a:'cx> {
|
|||
iter: DeclarationImportanceIterator<'a>,
|
||||
context: &'cx mut Context<'cx_a>,
|
||||
default_values: &'a ComputedValues,
|
||||
/// Custom properties in a keyframe if exists.
|
||||
extra_custom_properties: &'a Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
}
|
||||
|
||||
impl<'a, 'cx, 'cx_a:'cx> AnimationValueIterator<'a, 'cx, 'cx_a> {
|
||||
fn new(declarations: &'a PropertyDeclarationBlock,
|
||||
context: &'cx mut Context<'cx_a>,
|
||||
default_values: &'a ComputedValues) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
|
||||
default_values: &'a ComputedValues,
|
||||
extra_custom_properties: &'a Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
|
||||
AnimationValueIterator {
|
||||
iter: declarations.declaration_importance_iter(),
|
||||
context: context,
|
||||
default_values: default_values,
|
||||
context,
|
||||
default_values,
|
||||
extra_custom_properties,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,8 +180,12 @@ impl<'a, 'cx, 'cx_a:'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> {
|
|||
Some((decl, importance)) => {
|
||||
if importance == Importance::Normal {
|
||||
let property = AnimatableLonghand::from_declaration(decl);
|
||||
let animation = AnimationValue::from_declaration(decl, &mut self.context,
|
||||
self.default_values);
|
||||
let animation = AnimationValue::from_declaration(
|
||||
decl,
|
||||
&mut self.context,
|
||||
self.extra_custom_properties,
|
||||
self.default_values
|
||||
);
|
||||
debug_assert!(property.is_none() == animation.is_none(),
|
||||
"The failure condition of AnimatableLonghand::from_declaration \
|
||||
and AnimationValue::from_declaration should be the same");
|
||||
|
@ -248,11 +257,13 @@ impl PropertyDeclarationBlock {
|
|||
}
|
||||
|
||||
/// Return an iterator of (AnimatableLonghand, AnimationValue).
|
||||
pub fn to_animation_value_iter<'a, 'cx, 'cx_a:'cx>(&'a self,
|
||||
context: &'cx mut Context<'cx_a>,
|
||||
default_values: &'a ComputedValues)
|
||||
-> AnimationValueIterator<'a, 'cx, 'cx_a> {
|
||||
AnimationValueIterator::new(self, context, default_values)
|
||||
pub fn to_animation_value_iter<'a, 'cx, 'cx_a:'cx>(
|
||||
&'a self,
|
||||
context: &'cx mut Context<'cx_a>,
|
||||
default_values: &'a ComputedValues,
|
||||
extra_custom_properties: &'a Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
|
||||
AnimationValueIterator::new(self, context, default_values, extra_custom_properties)
|
||||
}
|
||||
|
||||
/// Returns whether this block contains any declaration with `!important`.
|
||||
|
@ -573,6 +584,7 @@ impl PropertyDeclarationBlock {
|
|||
property: &PropertyId,
|
||||
dest: &mut W,
|
||||
computed_values: Option<&ComputedValues>,
|
||||
custom_properties_block: Option<&PropertyDeclarationBlock>,
|
||||
) -> fmt::Result
|
||||
where
|
||||
W: fmt::Write,
|
||||
|
@ -581,17 +593,29 @@ impl PropertyDeclarationBlock {
|
|||
Err(_longhand_or_custom) => {
|
||||
if self.declarations.len() == 1 {
|
||||
let declaration = &self.declarations[0];
|
||||
// If we have a longhand declaration with variables, those variables will be
|
||||
// stored as unparsed values. As a temporary measure to produce sensible results
|
||||
// in Gecko's getKeyframes() implementation for CSS animations, if
|
||||
// |computed_values| is supplied, we use it to expand such variable
|
||||
// declarations. This will be fixed properly in Gecko bug 1391537.
|
||||
let custom_properties = if let Some(cv) = computed_values {
|
||||
// If there are extra custom properties for this declaration block,
|
||||
// factor them in too.
|
||||
if let Some(block) = custom_properties_block {
|
||||
block.cascade_custom_properties(cv.custom_properties())
|
||||
} else {
|
||||
cv.custom_properties()
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match (declaration, computed_values) {
|
||||
// If we have a longhand declaration with variables, those variables will be
|
||||
// stored as unparsed values. As a temporary measure to produce sensible results
|
||||
// in Gecko's getKeyframes() implementation for CSS animations, if
|
||||
// |computed_values| is supplied, we use it to expand such variable
|
||||
// declarations. This will be fixed properly in Gecko bug 1391537.
|
||||
(&PropertyDeclaration::WithVariables(id, ref unparsed),
|
||||
Some(ref computed_values)) => unparsed
|
||||
Some(ref _computed_values)) => unparsed
|
||||
.substitute_variables(
|
||||
id,
|
||||
&computed_values.custom_properties(),
|
||||
&custom_properties,
|
||||
QuirksMode::NoQuirks,
|
||||
)
|
||||
.to_css(dest),
|
||||
|
@ -652,6 +676,38 @@ impl PropertyDeclarationBlock {
|
|||
decl.get_css_wide_keyword().is_some()
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a custom properties map which is the result of cascading custom
|
||||
/// properties in this declaration block along with context's custom
|
||||
/// properties.
|
||||
pub fn cascade_custom_properties_with_context(
|
||||
&self,
|
||||
context: &Context,
|
||||
) -> Option<Arc<::custom_properties::CustomPropertiesMap>> {
|
||||
self.cascade_custom_properties(context.style().custom_properties())
|
||||
}
|
||||
|
||||
/// Returns a custom properties map which is the result of cascading custom
|
||||
/// properties in this declaration block along with the given custom
|
||||
/// properties.
|
||||
pub fn cascade_custom_properties(
|
||||
&self,
|
||||
inherited_custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
) -> Option<Arc<::custom_properties::CustomPropertiesMap>> {
|
||||
let mut custom_properties = None;
|
||||
// FIXME: Use PrecomputedHasher instead.
|
||||
let mut seen_custom = HashSet::new();
|
||||
|
||||
for declaration in self.normal_declaration_iter() {
|
||||
if let PropertyDeclaration::Custom(ref name, ref value) = *declaration {
|
||||
::custom_properties::cascade(
|
||||
&mut custom_properties, &inherited_custom_properties,
|
||||
&mut seen_custom, name, value.borrow());
|
||||
}
|
||||
}
|
||||
::custom_properties::finish_cascade(
|
||||
custom_properties, &inherited_custom_properties)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for PropertyDeclarationBlock {
|
||||
|
|
|
@ -26,6 +26,7 @@ use properties::longhands::visibility::computed_value::T as Visibility;
|
|||
#[cfg(feature = "gecko")] use properties::{PropertyId, PropertyDeclarationId, LonghandId};
|
||||
#[cfg(feature = "gecko")] use properties::{ShorthandId};
|
||||
use selectors::parser::SelectorParseError;
|
||||
use servo_arc::Arc;
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp;
|
||||
|
@ -568,6 +569,7 @@ impl AnimationValue {
|
|||
pub fn from_declaration(
|
||||
decl: &PropertyDeclaration,
|
||||
context: &mut Context,
|
||||
extra_custom_properties: &Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
initial: &ComputedValues
|
||||
) -> Option<Self> {
|
||||
use properties::LonghandId;
|
||||
|
@ -641,9 +643,14 @@ impl AnimationValue {
|
|||
}
|
||||
},
|
||||
PropertyDeclaration::WithVariables(id, ref unparsed) => {
|
||||
let custom_props = context.style().custom_properties();
|
||||
let substituted = unparsed.substitute_variables(id, &custom_props, context.quirks_mode);
|
||||
AnimationValue::from_declaration(&substituted, context, initial)
|
||||
let substituted = if extra_custom_properties.is_some() {
|
||||
unparsed.substitute_variables(
|
||||
id, &extra_custom_properties, context.quirks_mode)
|
||||
} else {
|
||||
unparsed.substitute_variables(
|
||||
id, &context.style().custom_properties(), context.quirks_mode)
|
||||
};
|
||||
AnimationValue::from_declaration(&substituted, context, extra_custom_properties, initial)
|
||||
},
|
||||
_ => None // non animatable properties will get included because of shorthands. ignore.
|
||||
}
|
||||
|
|
|
@ -1514,6 +1514,12 @@ impl PropertyDeclaration {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if this property is a custom property, false
|
||||
/// otherwise.
|
||||
pub fn is_custom(&self) -> bool {
|
||||
matches!(*self, PropertyDeclaration::Custom(_, _))
|
||||
}
|
||||
|
||||
/// The `context` parameter controls this:
|
||||
///
|
||||
/// https://drafts.csswg.org/css-animations/#keyframes
|
||||
|
|
|
@ -28,6 +28,7 @@ parking_lot = "0.4"
|
|||
# for the cargo problem behind this.
|
||||
selectors = {path = "../../components/selectors", features = ["gecko_like_types"]}
|
||||
servo_arc = {path = "../../components/servo_arc"}
|
||||
smallvec = "0.4"
|
||||
style = {path = "../../components/style", features = ["gecko"]}
|
||||
style_traits = {path = "../../components/style_traits"}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ use style::gecko_bindings::bindings::RawServoAnimationValueBorrowed;
|
|||
use style::gecko_bindings::bindings::RawServoAnimationValueMapBorrowedMut;
|
||||
use style::gecko_bindings::bindings::RawServoAnimationValueStrong;
|
||||
use style::gecko_bindings::bindings::RawServoAnimationValueTableBorrowed;
|
||||
use style::gecko_bindings::bindings::RawServoDeclarationBlockBorrowedOrNull;
|
||||
use style::gecko_bindings::bindings::RawServoStyleRuleBorrowed;
|
||||
use style::gecko_bindings::bindings::RawServoStyleSet;
|
||||
use style::gecko_bindings::bindings::ServoStyleContextBorrowedOrNull;
|
||||
|
@ -593,7 +594,7 @@ pub extern "C" fn Servo_AnimationValue_Serialize(value: RawServoAnimationValueBo
|
|||
let mut string = String::new();
|
||||
let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
|
||||
.single_value_to_css(&get_property_id_from_nscsspropertyid!(property, ()), &mut string,
|
||||
None);
|
||||
None, None /* No extra custom properties */);
|
||||
debug_assert!(rv.is_ok());
|
||||
|
||||
let buffer = unsafe { buffer.as_mut().unwrap() };
|
||||
|
@ -2286,17 +2287,25 @@ pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclar
|
|||
pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
|
||||
declarations: RawServoDeclarationBlockBorrowed,
|
||||
property_id: nsCSSPropertyID, buffer: *mut nsAString,
|
||||
computed_values: ServoStyleContextBorrowedOrNull)
|
||||
computed_values: ServoStyleContextBorrowedOrNull,
|
||||
custom_properties: RawServoDeclarationBlockBorrowedOrNull)
|
||||
{
|
||||
let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
|
||||
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
|
||||
let mut string = String::new();
|
||||
let rv = decls.single_value_to_css(&property_id, &mut string, computed_values);
|
||||
debug_assert!(rv.is_ok());
|
||||
|
||||
let buffer = unsafe { buffer.as_mut().unwrap() };
|
||||
buffer.assign_utf8(&string);
|
||||
})
|
||||
let global_style_data = &*GLOBAL_STYLE_DATA;
|
||||
let guard = global_style_data.shared_lock.read();
|
||||
let decls = Locked::<PropertyDeclarationBlock>::as_arc(&declarations).read_with(&guard);
|
||||
|
||||
let mut string = String::new();
|
||||
|
||||
let custom_properties = Locked::<PropertyDeclarationBlock>::arc_from_borrowed(&custom_properties);
|
||||
let custom_properties = custom_properties.map(|block| block.read_with(&guard));
|
||||
let rv = decls.single_value_to_css(
|
||||
&property_id, &mut string, computed_values, custom_properties);
|
||||
debug_assert!(rv.is_ok());
|
||||
|
||||
let buffer = unsafe { buffer.as_mut().unwrap() };
|
||||
buffer.assign_utf8(&string);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -3342,7 +3351,23 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
|
|||
let guard = global_style_data.shared_lock.read();
|
||||
let default_values = data.default_computed_values();
|
||||
|
||||
let mut raw_custom_properties_block; // To make the raw block alive in the scope.
|
||||
for (index, keyframe) in keyframes.iter().enumerate() {
|
||||
let mut custom_properties = None;
|
||||
for property in keyframe.mPropertyValues.iter() {
|
||||
// Find the block for custom properties first.
|
||||
if property.mProperty == nsCSSPropertyID::eCSSPropertyExtra_variable {
|
||||
raw_custom_properties_block = unsafe {
|
||||
&*property.mServoDeclarationBlock.mRawPtr.clone()
|
||||
};
|
||||
let guard = Locked::<PropertyDeclarationBlock>::as_arc(
|
||||
&raw_custom_properties_block).read_with(&guard);
|
||||
custom_properties = guard.cascade_custom_properties_with_context(&context);
|
||||
// There should be one PropertyDeclarationBlock for custom properties.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let ref mut animation_values = computed_keyframes[index];
|
||||
|
||||
let mut seen = LonghandIdSet::new();
|
||||
|
@ -3393,8 +3418,13 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
|
|||
let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() };
|
||||
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
|
||||
let guard = declarations.read_with(&guard);
|
||||
let iter = guard.to_animation_value_iter(
|
||||
&mut context,
|
||||
&default_values,
|
||||
&custom_properties,
|
||||
);
|
||||
|
||||
for anim in guard.to_animation_value_iter(&mut context, &default_values) {
|
||||
for anim in iter {
|
||||
maybe_append_animation_value(anim.0, Some(anim.1));
|
||||
}
|
||||
}
|
||||
|
@ -3433,7 +3463,13 @@ pub extern "C" fn Servo_GetAnimationValues(declarations: RawServoDeclarationBloc
|
|||
|
||||
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
|
||||
let guard = declarations.read_with(&guard);
|
||||
for (index, anim) in guard.to_animation_value_iter(&mut context, &default_values).enumerate() {
|
||||
let no_extra_custom_properties = None; // SMIL has no extra custom properties.
|
||||
let iter = guard.to_animation_value_iter(
|
||||
&mut context,
|
||||
&default_values,
|
||||
&no_extra_custom_properties,
|
||||
);
|
||||
for (index, anim) in iter.enumerate() {
|
||||
unsafe { animation_values.set_len((index + 1) as u32) };
|
||||
animation_values[index].set_arc_leaky(Arc::new(anim.1));
|
||||
}
|
||||
|
@ -3472,7 +3508,13 @@ pub extern "C" fn Servo_AnimationValue_Compute(element: RawGeckoElementBorrowed,
|
|||
// We only compute the first element in declarations.
|
||||
match declarations.read_with(&guard).declaration_importance_iter().next() {
|
||||
Some((decl, imp)) if imp == Importance::Normal => {
|
||||
let animation = AnimationValue::from_declaration(decl, &mut context, default_values);
|
||||
let no_extra_custom_properties = None; // No extra custom properties for devtools.
|
||||
let animation = AnimationValue::from_declaration(
|
||||
decl,
|
||||
&mut context,
|
||||
&no_extra_custom_properties,
|
||||
default_values,
|
||||
);
|
||||
animation.map_or(RawServoAnimationValueStrong::null(), |value| {
|
||||
Arc::new(value).into_strong()
|
||||
})
|
||||
|
@ -3552,6 +3594,8 @@ pub extern "C" fn Servo_StyleSet_GetKeyframesForName(raw_data: RawServoStyleSetB
|
|||
name: *const nsACString,
|
||||
inherited_timing_function: nsTimingFunctionBorrowed,
|
||||
keyframes: RawGeckoKeyframeListBorrowedMut) -> bool {
|
||||
use smallvec::SmallVec;
|
||||
|
||||
debug_assert!(keyframes.len() == 0,
|
||||
"keyframes should be initially empty");
|
||||
|
||||
|
@ -3623,6 +3667,25 @@ pub extern "C" fn Servo_StyleSet_GetKeyframesForName(raw_data: RawServoStyleSetB
|
|||
guard.normal_declaration_iter()
|
||||
.filter(|declaration| declaration.is_animatable());
|
||||
|
||||
let custom_properties: SmallVec<[&PropertyDeclaration; 1]> =
|
||||
guard.normal_declaration_iter()
|
||||
.filter(|declaration| declaration.is_custom())
|
||||
.collect();
|
||||
|
||||
if custom_properties.len() > 0 {
|
||||
let mut pdb = PropertyDeclarationBlock::new();
|
||||
for custom in custom_properties.iter() {
|
||||
pdb.push((*custom).clone(), Importance::Normal);
|
||||
}
|
||||
unsafe {
|
||||
let pair =
|
||||
Gecko_AppendPropertyValuePair(&mut (*keyframe).mPropertyValues,
|
||||
nsCSSPropertyID::eCSSPropertyExtra_variable);
|
||||
(*pair).mServoDeclarationBlock.set_arc_leaky(
|
||||
Arc::new(global_style_data.shared_lock.wrap(pdb)));
|
||||
}
|
||||
}
|
||||
|
||||
for declaration in animatable {
|
||||
let property = AnimatableLonghand::from_declaration(declaration).unwrap();
|
||||
// Skip the 'display' property because although it is animatable from SMIL,
|
||||
|
|
|
@ -11,6 +11,7 @@ extern crate libc;
|
|||
extern crate malloc_size_of;
|
||||
extern crate selectors;
|
||||
extern crate servo_arc;
|
||||
extern crate smallvec;
|
||||
#[macro_use] extern crate style;
|
||||
extern crate style_traits;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ log = {version = "0.3.5", features = ["release_max_level_info"]}
|
|||
malloc_size_of = {path = "../../../components/malloc_size_of"}
|
||||
selectors = {path = "../../../components/selectors", features = ["gecko_like_types"]}
|
||||
size_of_test = {path = "../../../components/size_of_test"}
|
||||
smallvec = "0.4"
|
||||
style_traits = {path = "../../../components/style_traits"}
|
||||
style = {path = "../../../components/style", features = ["gecko"]}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ extern crate geckoservo;
|
|||
#[macro_use] extern crate log;
|
||||
extern crate malloc_size_of;
|
||||
extern crate selectors;
|
||||
extern crate smallvec;
|
||||
#[macro_use] extern crate size_of_test;
|
||||
#[macro_use] extern crate style;
|
||||
extern crate style_traits;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue