зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1309752: Animate logical properties. r=birtles
The setup is that AnimationValue only contains physical properties, and we physicalize when building keyframes and transitions. MozReview-Commit-ID: 9dI20N0LFrk
This commit is contained in:
Родитель
476d05caeb
Коммит
9b504cb749
|
@ -136,6 +136,7 @@ SERVO_BINDING_FUNC(Servo_StyleSet_NoteStyleSheetsChanged, void,
|
|||
SERVO_BINDING_FUNC(Servo_StyleSet_GetKeyframesForName, bool,
|
||||
RawServoStyleSetBorrowed set,
|
||||
RawGeckoElementBorrowed element,
|
||||
ComputedStyleBorrowed style,
|
||||
nsAtom* name,
|
||||
nsTimingFunctionBorrowed timing_function,
|
||||
RawGeckoKeyframeListBorrowedMut keyframe_list)
|
||||
|
|
|
@ -1976,7 +1976,9 @@ Gecko_AppendPropertyValuePair(nsTArray<PropertyValuePair>* aProperties,
|
|||
nsCSSPropertyID aProperty)
|
||||
{
|
||||
MOZ_ASSERT(aProperties);
|
||||
return aProperties->AppendElement(PropertyValuePair {aProperty});
|
||||
MOZ_ASSERT(aProperty == eCSSPropertyExtra_variable ||
|
||||
!nsCSSProps::PropHasFlags(aProperty, CSSPropFlags::IsLogical));
|
||||
return aProperties->AppendElement(PropertyValuePair { aProperty });
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1159,6 +1159,7 @@ ServoStyleSet::AssertTreeIsClean()
|
|||
|
||||
bool
|
||||
ServoStyleSet::GetKeyframesForName(const Element& aElement,
|
||||
const ComputedStyle& aStyle,
|
||||
nsAtom* aName,
|
||||
const nsTimingFunction& aTimingFunction,
|
||||
nsTArray<Keyframe>& aKeyframes)
|
||||
|
@ -1166,6 +1167,7 @@ ServoStyleSet::GetKeyframesForName(const Element& aElement,
|
|||
MOZ_ASSERT(!StylistNeedsUpdate());
|
||||
return Servo_StyleSet_GetKeyframesForName(mRawSet.get(),
|
||||
&aElement,
|
||||
&aStyle,
|
||||
aName,
|
||||
&aTimingFunction,
|
||||
&aKeyframes);
|
||||
|
|
|
@ -336,7 +336,8 @@ public:
|
|||
inline already_AddRefed<ComputedStyle>
|
||||
ResolveServoStyle(dom::Element* aElement);
|
||||
|
||||
bool GetKeyframesForName(const dom::Element& aElement,
|
||||
bool GetKeyframesForName(const dom::Element&,
|
||||
const ComputedStyle&,
|
||||
nsAtom* aName,
|
||||
const nsTimingFunction& aTimingFunction,
|
||||
nsTArray<Keyframe>& aKeyframes);
|
||||
|
|
|
@ -360,12 +360,12 @@ public:
|
|||
const nsTimingFunction& aTimingFunction,
|
||||
nsTArray<Keyframe>& aKeyframes)
|
||||
{
|
||||
ServoStyleSet* styleSet = aPresContext->StyleSet();
|
||||
MOZ_ASSERT(styleSet);
|
||||
return styleSet->GetKeyframesForName(aElement,
|
||||
aName,
|
||||
aTimingFunction,
|
||||
aKeyframes);
|
||||
return aPresContext->StyleSet()->GetKeyframesForName(
|
||||
aElement,
|
||||
*mComputedStyle,
|
||||
aName,
|
||||
aTimingFunction,
|
||||
aKeyframes);
|
||||
}
|
||||
void SetKeyframes(KeyframeEffect& aEffect, nsTArray<Keyframe>&& aKeyframes)
|
||||
{
|
||||
|
@ -647,13 +647,13 @@ nsAnimationManager::DoUpdateAnimations(
|
|||
|
||||
// Build the updated animations list, extracting matching animations from
|
||||
// the existing collection as we go.
|
||||
OwningCSSAnimationPtrArray newAnimations;
|
||||
newAnimations = BuildAnimations(mPresContext,
|
||||
aTarget,
|
||||
aStyleDisplay,
|
||||
aBuilder,
|
||||
collection,
|
||||
mMaybeReferencedAnimations);
|
||||
OwningCSSAnimationPtrArray newAnimations =
|
||||
BuildAnimations(mPresContext,
|
||||
aTarget,
|
||||
aStyleDisplay,
|
||||
aBuilder,
|
||||
collection,
|
||||
mMaybeReferencedAnimations);
|
||||
|
||||
if (newAnimations.IsEmpty()) {
|
||||
if (collection) {
|
||||
|
|
|
@ -544,15 +544,18 @@ nsTransitionManager::DoUpdateTransitions(
|
|||
for (nsCSSPropertyID p = nsCSSPropertyID(0);
|
||||
p < eCSSProperty_COUNT_no_shorthands;
|
||||
p = nsCSSPropertyID(p + 1)) {
|
||||
p = nsCSSProps::Physicalize(p, aNewStyle);
|
||||
allTransitionProperties.AddProperty(p);
|
||||
}
|
||||
} else if (nsCSSProps::IsShorthand(property)) {
|
||||
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(
|
||||
subprop, property, CSSEnabledState::eForAllContent) {
|
||||
allTransitionProperties.AddProperty(*subprop);
|
||||
auto p = nsCSSProps::Physicalize(*subprop, aNewStyle);
|
||||
allTransitionProperties.AddProperty(p);
|
||||
}
|
||||
} else {
|
||||
allTransitionProperties.AddProperty(property);
|
||||
allTransitionProperties.AddProperty(
|
||||
nsCSSProps::Physicalize(property, aNewStyle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -656,13 +659,15 @@ nsTransitionManager::ConsiderInitiatingTransition(
|
|||
nsCSSPropertyIDSet& aPropertiesChecked)
|
||||
{
|
||||
// IsShorthand itself will assert if aProperty is not a property.
|
||||
MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
|
||||
"property out of range");
|
||||
MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty), "property out of range");
|
||||
NS_ASSERTION(!aElementTransitions ||
|
||||
aElementTransitions->mElement == aElement, "Element mismatch");
|
||||
|
||||
// A later item in transition-property already specified a transition for this
|
||||
// property, so we ignore this one.
|
||||
aProperty = nsCSSProps::Physicalize(aProperty, aNewStyle);
|
||||
|
||||
// A later item in transition-property already specified a transition for
|
||||
// this property, so we ignore this one.
|
||||
//
|
||||
// See http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html .
|
||||
if (aPropertiesChecked.HasProperty(aProperty)) {
|
||||
return false;
|
||||
|
|
|
@ -882,6 +882,7 @@ impl<'le> GeckoElement<'le> {
|
|||
.expect("AnimationValue not found in ElementTransitions");
|
||||
|
||||
let property = end_value.id();
|
||||
debug_assert!(!property.is_logical());
|
||||
map.insert(property, end_value.clone_arc());
|
||||
}
|
||||
map
|
||||
|
@ -896,6 +897,7 @@ impl<'le> GeckoElement<'le> {
|
|||
existing_transitions: &FnvHashMap<LonghandId, Arc<AnimationValue>>,
|
||||
) -> bool {
|
||||
use values::animated::{Animate, Procedure};
|
||||
debug_assert!(!longhand_id.is_logical());
|
||||
|
||||
// If there is an existing transition, update only if the end value
|
||||
// differs.
|
||||
|
@ -1657,6 +1659,8 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
let transition_property: TransitionProperty = property.into();
|
||||
|
||||
let mut property_check_helper = |property: LonghandId| -> bool {
|
||||
let property =
|
||||
property.to_physical(after_change_style.writing_mode);
|
||||
transitions_to_keep.insert(property);
|
||||
self.needs_transitions_update_per_property(
|
||||
property,
|
||||
|
|
|
@ -223,12 +223,6 @@ class Longhand(object):
|
|||
and animation_value_type != "discrete"
|
||||
self.is_animatable_with_computed_value = animation_value_type == "ComputedValue" \
|
||||
or animation_value_type == "discrete"
|
||||
if self.logical:
|
||||
# Logical properties will be animatable (i.e. the animation type is
|
||||
# discrete). For now, it is still non-animatable.
|
||||
self.animatable = False
|
||||
self.transitionable = False
|
||||
self.animation_value_type = None
|
||||
|
||||
# See compute_damage for the various values this can take
|
||||
self.servo_restyle_damage = servo_restyle_damage
|
||||
|
|
|
@ -131,12 +131,15 @@ impl<'a> DoubleEndedIterator for DeclarationImportanceIterator<'a> {
|
|||
}
|
||||
|
||||
/// Iterator over `PropertyDeclaration` for Importance::Normal.
|
||||
///
|
||||
/// TODO(emilio): This should be replaced by `impl Trait`, returning a
|
||||
/// filter()ed iterator when available instead, and all the boilerplate below
|
||||
/// should go.
|
||||
pub struct NormalDeclarationIterator<'a>(DeclarationImportanceIterator<'a>);
|
||||
|
||||
impl<'a> NormalDeclarationIterator<'a> {
|
||||
/// Constructor.
|
||||
#[inline]
|
||||
pub fn new(declarations: &'a [PropertyDeclaration], important: &'a SmallBitVec) -> Self {
|
||||
fn new(declarations: &'a [PropertyDeclaration], important: &'a SmallBitVec) -> Self {
|
||||
NormalDeclarationIterator(
|
||||
DeclarationImportanceIterator::new(declarations, important)
|
||||
)
|
||||
|
@ -146,6 +149,7 @@ impl<'a> NormalDeclarationIterator<'a> {
|
|||
impl<'a> Iterator for NormalDeclarationIterator<'a> {
|
||||
type Item = &'a PropertyDeclaration;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
let (decl, importance) = self.0.iter.next()?;
|
||||
|
@ -155,11 +159,24 @@ impl<'a> Iterator for NormalDeclarationIterator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for NormalDeclarationIterator<'a> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
let (decl, importance) = self.0.iter.next_back()?;
|
||||
if !importance {
|
||||
return Some(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator for AnimationValue to be generated from PropertyDeclarationBlock.
|
||||
pub struct AnimationValueIterator<'a, 'cx, 'cx_a:'cx> {
|
||||
iter: NormalDeclarationIterator<'a>,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||
|
||||
<%
|
||||
from data import to_idl_name, SYSTEM_FONT_LONGHANDS
|
||||
from data import to_idl_name, SYSTEM_FONT_LONGHANDS, to_camel_case
|
||||
from itertools import groupby
|
||||
%>
|
||||
|
||||
|
@ -114,7 +114,7 @@ pub fn nscsspropertyid_is_transitionable(property: nsCSSPropertyID) -> bool {
|
|||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||
pub enum AnimatedProperty {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
% if prop.animatable and not prop.logical:
|
||||
<%
|
||||
value_type = "longhands::{}::computed_value::T".format(prop.ident)
|
||||
if not prop.is_animatable_with_computed_value:
|
||||
|
@ -131,7 +131,7 @@ impl AnimatedProperty {
|
|||
pub fn name(&self) -> &'static str {
|
||||
match *self {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
% if prop.animatable and not prop.logical:
|
||||
AnimatedProperty::${prop.camel_case}(..) => "${prop.name}",
|
||||
% endif
|
||||
% endfor
|
||||
|
@ -143,7 +143,7 @@ impl AnimatedProperty {
|
|||
pub fn does_animate(&self) -> bool {
|
||||
match *self {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
% if prop.animatable and not prop.logical:
|
||||
AnimatedProperty::${prop.camel_case}(ref from, ref to) => from != to,
|
||||
% endif
|
||||
% endfor
|
||||
|
@ -154,7 +154,7 @@ impl AnimatedProperty {
|
|||
pub fn has_the_same_end_value_as(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
% if prop.animatable and not prop.logical:
|
||||
(&AnimatedProperty::${prop.camel_case}(_, ref this_end_value),
|
||||
&AnimatedProperty::${prop.camel_case}(_, ref other_end_value)) => {
|
||||
this_end_value == other_end_value
|
||||
|
@ -173,7 +173,7 @@ impl AnimatedProperty {
|
|||
{
|
||||
match *self {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
% if prop.animatable and not prop.logical:
|
||||
AnimatedProperty::${prop.camel_case}(ref from, ref to) => {
|
||||
// https://drafts.csswg.org/web-animations/#discrete-animation-type
|
||||
% if prop.animation_value_type == "discrete":
|
||||
|
@ -203,9 +203,12 @@ impl AnimatedProperty {
|
|||
old_style: &ComputedValues,
|
||||
new_style: &ComputedValues,
|
||||
) -> Option<AnimatedProperty> {
|
||||
// FIXME(emilio): Handle the case where old_style and new_style's
|
||||
// writing mode differ.
|
||||
let property = property.to_physical(new_style.writing_mode);
|
||||
Some(match property {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
% if prop.animatable and not prop.logical:
|
||||
LonghandId::${prop.camel_case} => {
|
||||
let old_computed = old_style.clone_${prop.ident}();
|
||||
let new_computed = new_style.clone_${prop.ident}();
|
||||
|
@ -254,11 +257,10 @@ unsafe impl HasSimpleFFI for AnimationValueMap {}
|
|||
#[repr(u16)]
|
||||
pub enum AnimationValue {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
/// `${prop.name}`
|
||||
% if prop.animatable and not prop.logical:
|
||||
${prop.camel_case}(${prop.animated_type()}),
|
||||
% else:
|
||||
/// `${prop.name}` (not animatable)
|
||||
${prop.camel_case}(Void),
|
||||
% endif
|
||||
% endfor
|
||||
|
@ -267,8 +269,11 @@ pub enum AnimationValue {
|
|||
<%
|
||||
animated = []
|
||||
unanimated = []
|
||||
animated_with_logical = []
|
||||
for prop in data.longhands:
|
||||
if prop.animatable:
|
||||
animated_with_logical.append(prop)
|
||||
if prop.animatable and not prop.logical:
|
||||
animated.append(prop)
|
||||
else:
|
||||
unanimated.append(prop)
|
||||
|
@ -370,7 +375,7 @@ impl AnimationValue {
|
|||
let id = unsafe { *(self as *const _ as *const LonghandId) };
|
||||
debug_assert_eq!(id, match *self {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
% if prop.animatable and not prop.logical:
|
||||
AnimationValue::${prop.camel_case}(..) => LonghandId::${prop.camel_case},
|
||||
% else:
|
||||
AnimationValue::${prop.camel_case}(void) => void::unreachable(void),
|
||||
|
@ -444,17 +449,18 @@ impl AnimationValue {
|
|||
%>
|
||||
|
||||
let animatable = match *decl {
|
||||
% for (specified_ty, ty, boxed, to_animated, inherit, system), props in groupby(animated, key=keyfunc):
|
||||
% for (specified_ty, ty, boxed, to_animated, inherit, system), props in groupby(animated_with_logical, key=keyfunc):
|
||||
${" |\n".join("PropertyDeclaration::{}(ref value)".format(prop.camel_case) for prop in props)} => {
|
||||
let decl_repr = unsafe {
|
||||
&*(decl as *const _ as *const PropertyDeclarationVariantRepr<${specified_ty}>)
|
||||
};
|
||||
let longhand_id = unsafe {
|
||||
*(&decl_repr.tag as *const u16 as *const LonghandId)
|
||||
};
|
||||
% if inherit:
|
||||
context.for_non_inherited_property = None;
|
||||
% else:
|
||||
context.for_non_inherited_property = unsafe {
|
||||
Some(*(&decl_repr.tag as *const u16 as *const LonghandId))
|
||||
};
|
||||
context.for_non_inherited_property = Some(longhand_id);
|
||||
% endif
|
||||
% if system:
|
||||
if let Some(sf) = value.get_system() {
|
||||
|
@ -475,7 +481,7 @@ impl AnimationValue {
|
|||
ptr::write(
|
||||
&mut out as *mut _ as *mut AnimationValueVariantRepr<${ty}>,
|
||||
AnimationValueVariantRepr {
|
||||
tag: decl_repr.tag,
|
||||
tag: longhand_id.to_physical(context.builder.writing_mode) as u16,
|
||||
value,
|
||||
},
|
||||
);
|
||||
|
@ -492,24 +498,40 @@ impl AnimationValue {
|
|||
LonghandId::${prop.camel_case} => {
|
||||
let style_struct = match declaration.keyword {
|
||||
% if not prop.style_struct.inherited:
|
||||
CSSWideKeyword::Unset |
|
||||
CSSWideKeyword::Unset |
|
||||
% endif
|
||||
CSSWideKeyword::Initial => {
|
||||
initial.get_${prop.style_struct.name_lower}()
|
||||
},
|
||||
% if prop.style_struct.inherited:
|
||||
CSSWideKeyword::Unset |
|
||||
CSSWideKeyword::Unset |
|
||||
% endif
|
||||
CSSWideKeyword::Inherit => {
|
||||
context.builder
|
||||
.get_parent_${prop.style_struct.name_lower}()
|
||||
},
|
||||
};
|
||||
let computed = style_struct.clone_${prop.ident}();
|
||||
let computed = style_struct
|
||||
% if prop.logical:
|
||||
.clone_${prop.ident}(context.builder.writing_mode);
|
||||
% else:
|
||||
.clone_${prop.ident}();
|
||||
% endif
|
||||
|
||||
% if not prop.is_animatable_with_computed_value:
|
||||
let computed = computed.to_animated_value();
|
||||
% endif
|
||||
AnimationValue::${prop.camel_case}(computed)
|
||||
|
||||
% if prop.logical:
|
||||
let wm = context.builder.writing_mode;
|
||||
<%helpers:logical_setter_helper name="${prop.name}">
|
||||
<%def name="inner(physical_ident)">
|
||||
AnimationValue::${to_camel_case(physical_ident)}(computed)
|
||||
</%def>
|
||||
</%helpers:logical_setter_helper>
|
||||
% else:
|
||||
AnimationValue::${prop.camel_case}(computed)
|
||||
% endif
|
||||
},
|
||||
% endif
|
||||
% endfor
|
||||
|
@ -548,9 +570,10 @@ impl AnimationValue {
|
|||
property: LonghandId,
|
||||
style: &ComputedValues,
|
||||
) -> Option<Self> {
|
||||
let property = property.to_physical(style.writing_mode);
|
||||
Some(match property {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
% if prop.animatable and not prop.logical:
|
||||
LonghandId::${prop.camel_case} => {
|
||||
let computed = style.clone_${prop.ident}();
|
||||
AnimationValue::${prop.camel_case}(
|
||||
|
@ -656,7 +679,7 @@ impl ToAnimatedZero for AnimationValue {
|
|||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
||||
match *self {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable and prop.animation_value_type != "discrete":
|
||||
% if prop.animatable and not prop.logical and prop.animation_value_type != "discrete":
|
||||
AnimationValue::${prop.camel_case}(ref base) => {
|
||||
Ok(AnimationValue::${prop.camel_case}(base.to_animated_zero()?))
|
||||
},
|
||||
|
@ -2924,43 +2947,67 @@ impl ToAnimatedZero for AnimatedFilter {
|
|||
}
|
||||
}
|
||||
|
||||
/// A comparator to sort PropertyIds such that longhands are sorted before shorthands,
|
||||
/// shorthands with fewer components are sorted before shorthands with more components,
|
||||
/// and otherwise shorthands are sorted by IDL name as defined by [Web Animations][property-order].
|
||||
/// The category a property falls into for ordering purposes.
|
||||
///
|
||||
/// https://drafts.csswg.org/web-animations/#calculating-computed-keyframes
|
||||
///
|
||||
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
|
||||
enum PropertyCategory {
|
||||
Custom,
|
||||
PhysicalLonghand,
|
||||
LogicalLonghand,
|
||||
Shorthand,
|
||||
}
|
||||
|
||||
impl PropertyCategory {
|
||||
fn of(id: &PropertyId) -> Self {
|
||||
match *id {
|
||||
PropertyId::Shorthand(..) |
|
||||
PropertyId::ShorthandAlias(..) => PropertyCategory::Shorthand,
|
||||
PropertyId::Longhand(id) |
|
||||
PropertyId::LonghandAlias(id, ..) => {
|
||||
if id.is_logical() {
|
||||
PropertyCategory::LogicalLonghand
|
||||
} else {
|
||||
PropertyCategory::PhysicalLonghand
|
||||
}
|
||||
}
|
||||
PropertyId::Custom(..) => PropertyCategory::Custom,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A comparator to sort PropertyIds such that physical longhands are sorted
|
||||
/// before logical longhands and shorthands, shorthands with fewer components
|
||||
/// are sorted before shorthands with more components, and otherwise shorthands
|
||||
/// are sorted by IDL name as defined by [Web Animations][property-order].
|
||||
///
|
||||
/// Using this allows us to prioritize values specified by longhands (or smaller
|
||||
/// shorthand subsets) when longhands and shorthands are both specified on the one keyframe.
|
||||
///
|
||||
/// Example orderings that result from this:
|
||||
///
|
||||
/// margin-left, margin
|
||||
///
|
||||
/// and:
|
||||
///
|
||||
/// border-top-color, border-color, border-top, border
|
||||
/// shorthand subsets) when longhands and shorthands are both specified on the
|
||||
/// one keyframe.
|
||||
///
|
||||
/// [property-order] https://drafts.csswg.org/web-animations/#calculating-computed-keyframes
|
||||
pub fn compare_property_priority(a: &PropertyId, b: &PropertyId) -> cmp::Ordering {
|
||||
match (a.as_shorthand(), b.as_shorthand()) {
|
||||
// Within shorthands, sort by the number of subproperties, then by IDL name.
|
||||
(Ok(a), Ok(b)) => {
|
||||
let subprop_count_a = a.longhands().count();
|
||||
let subprop_count_b = b.longhands().count();
|
||||
subprop_count_a
|
||||
.cmp(&subprop_count_b)
|
||||
.then_with(|| {
|
||||
get_idl_name_sort_order(a).cmp(&get_idl_name_sort_order(b))
|
||||
})
|
||||
},
|
||||
let a_category = PropertyCategory::of(a);
|
||||
let b_category = PropertyCategory::of(b);
|
||||
|
||||
// Longhands go before shorthands.
|
||||
(Ok(_), Err(_)) => cmp::Ordering::Greater,
|
||||
(Err(_), Ok(_)) => cmp::Ordering::Less,
|
||||
|
||||
// Both are longhands or custom properties in which case they don't overlap and should
|
||||
// sort equally.
|
||||
_ => cmp::Ordering::Equal,
|
||||
if a_category != b_category {
|
||||
return a_category.cmp(&b_category);
|
||||
}
|
||||
|
||||
if a_category == PropertyCategory::Shorthand {
|
||||
let a = a.as_shorthand().unwrap();
|
||||
let b = b.as_shorthand().unwrap();
|
||||
// Within shorthands, sort by the number of subproperties, then by IDL
|
||||
// name.
|
||||
let subprop_count_a = a.longhands().count();
|
||||
let subprop_count_b = b.longhands().count();
|
||||
return subprop_count_a.cmp(&subprop_count_b).then_with(|| {
|
||||
get_idl_name_sort_order(a).cmp(&get_idl_name_sort_order(b))
|
||||
});
|
||||
}
|
||||
|
||||
cmp::Ordering::Equal
|
||||
}
|
||||
|
||||
fn get_idl_name_sort_order(shorthand: ShorthandId) -> u32 {
|
||||
|
|
|
@ -4675,6 +4675,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(
|
|||
}
|
||||
|
||||
let mut maybe_append_animation_value = |property: LonghandId, value: Option<AnimationValue>| {
|
||||
debug_assert!(!property.is_logical());
|
||||
if seen.contains(property) {
|
||||
return;
|
||||
}
|
||||
|
@ -4881,6 +4882,7 @@ fn fill_in_missing_keyframe_values(
|
|||
pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
|
||||
raw_data: RawServoStyleSetBorrowed,
|
||||
element: RawGeckoElementBorrowed,
|
||||
style: ComputedStyleBorrowed,
|
||||
name: *mut nsAtom,
|
||||
inherited_timing_function: nsTimingFunctionBorrowed,
|
||||
keyframes: RawGeckoKeyframeListBorrowedMut,
|
||||
|
@ -4906,6 +4908,8 @@ pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
|
|||
let mut has_complete_final_keyframe = false;
|
||||
let mut current_offset = -1.;
|
||||
|
||||
let writing_mode = style.writing_mode;
|
||||
|
||||
// Iterate over the keyframe rules backwards so we can drop overridden
|
||||
// properties (since declarations in later rules override those in earlier
|
||||
// ones).
|
||||
|
@ -4937,7 +4941,14 @@ pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
|
|||
// to represent that all properties animated by the keyframes
|
||||
// animation should be set to the underlying computed value for
|
||||
// that keyframe.
|
||||
let mut seen = LonghandIdSet::new();
|
||||
for property in animation.properties_changed.iter() {
|
||||
let property = property.to_physical(writing_mode);
|
||||
if seen.contains(property) {
|
||||
continue;
|
||||
}
|
||||
seen.insert(property);
|
||||
|
||||
Gecko_AppendPropertyValuePair(
|
||||
&mut (*keyframe).mPropertyValues,
|
||||
property.to_nscsspropertyid(),
|
||||
|
@ -4956,7 +4967,10 @@ pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
|
|||
|
||||
// Filter out non-animatable properties and properties with
|
||||
// !important.
|
||||
for declaration in guard.normal_declaration_iter() {
|
||||
//
|
||||
// Also, iterate in reverse to respect the source order in case
|
||||
// there are logical and physical longhands in the same block.
|
||||
for declaration in guard.normal_declaration_iter().rev() {
|
||||
let id = declaration.id();
|
||||
|
||||
let id = match id {
|
||||
|
@ -4972,7 +4986,7 @@ pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
|
|||
continue;
|
||||
}
|
||||
|
||||
id
|
||||
id.to_physical(writing_mode)
|
||||
}
|
||||
PropertyDeclarationId::Custom(..) => {
|
||||
custom_properties.push(
|
||||
|
@ -4996,7 +5010,7 @@ pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
|
|||
(*pair).mServoDeclarationBlock.set_arc_leaky(
|
||||
Arc::new(global_style_data.shared_lock.wrap(
|
||||
PropertyDeclarationBlock::with_one(
|
||||
declaration.clone(),
|
||||
declaration.to_physical(writing_mode),
|
||||
Importance::Normal,
|
||||
)
|
||||
))
|
||||
|
@ -5024,10 +5038,15 @@ pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
|
|||
}
|
||||
}
|
||||
|
||||
let mut properties_changed = LonghandIdSet::new();
|
||||
for property in animation.properties_changed.iter() {
|
||||
properties_changed.insert(property.to_physical(writing_mode));
|
||||
}
|
||||
|
||||
// Append property values that are missing in the initial or the final keyframes.
|
||||
if !has_complete_initial_keyframe {
|
||||
fill_in_missing_keyframe_values(
|
||||
&animation.properties_changed,
|
||||
&properties_changed,
|
||||
inherited_timing_function,
|
||||
&properties_set_at_start,
|
||||
Offset::Zero,
|
||||
|
@ -5036,7 +5055,7 @@ pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
|
|||
}
|
||||
if !has_complete_final_keyframe {
|
||||
fill_in_missing_keyframe_values(
|
||||
&animation.properties_changed,
|
||||
&properties_changed,
|
||||
inherited_timing_function,
|
||||
&properties_set_at_end,
|
||||
Offset::One,
|
||||
|
|
Загрузка…
Ссылка в новой задаче