mirror of
https://github.com/servo/servo.git
synced 2025-08-01 03:30:33 +01:00
Auto merge of #16963 - BorisChiou:stylo/animation/omta, r=emilio
stylo: Bug 1334036 - Enable animations running on compositor. These are interdependent patches of Bug 1334036, which enables off-main thread animations. We add one FFI to get the property id set which overriding animations, so we can make sure the cascade result is correct for off-main thread animations. --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix [Bug 1334036](https://bugzilla.mozilla.org/show_bug.cgi?id=1334036) - [X] These changes do not require tests because we support off-main thread animation only on Gecko, and there are enough test cases there. <!-- 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/16963) <!-- Reviewable:end -->
This commit is contained in:
commit
5a012cc9b1
11 changed files with 1543 additions and 1267 deletions
|
@ -486,7 +486,10 @@ impl<'le> TElement for ServoLayoutElement<'le> {
|
|||
}
|
||||
|
||||
fn has_animations(&self) -> bool {
|
||||
unreachable!("this should be only called on gecko");
|
||||
// We use this function not only for Gecko but also for Servo to know if this element has
|
||||
// animations, so we maybe try to get the important rules of this element. This is used for
|
||||
// off-main thread animations, but we don't support it on Servo, so return false directly.
|
||||
false
|
||||
}
|
||||
|
||||
fn has_css_animations(&self) -> bool {
|
||||
|
|
|
@ -13,6 +13,7 @@ use properties::longhands::display::computed_value as display;
|
|||
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
||||
use rule_tree::StrongRuleNode;
|
||||
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
|
||||
use shared_lock::StylesheetGuards;
|
||||
#[cfg(feature = "servo")] use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "servo")] use std::hash::BuildHasherDefault;
|
||||
|
@ -506,6 +507,24 @@ impl ElementData {
|
|||
true
|
||||
}
|
||||
|
||||
/// Return true if important rules are different.
|
||||
/// We use this to make sure the cascade of off-main thread animations is correct.
|
||||
/// Note: Ignore custom properties for now because we only support opacity and transform
|
||||
/// properties for animations running on compositor. Actually, we only care about opacity
|
||||
/// and transform for now, but it's fine to compare all properties and let the user
|
||||
/// the check which properties do they want.
|
||||
/// If it costs too much, get_properties_overriding_animations() should return a set
|
||||
/// containing only opacity and transform properties.
|
||||
pub fn important_rules_are_different(&self,
|
||||
rules: &StrongRuleNode,
|
||||
guards: &StylesheetGuards) -> bool {
|
||||
debug_assert!(self.has_styles());
|
||||
let (important_rules, _custom) =
|
||||
self.styles().primary.rules.get_properties_overriding_animations(&guards);
|
||||
let (other_important_rules, _custom) = rules.get_properties_overriding_animations(&guards);
|
||||
important_rules != other_important_rules
|
||||
}
|
||||
|
||||
/// Returns true if the Element has a RestyleData.
|
||||
pub fn has_restyle(&self) -> bool {
|
||||
self.restyle.is_some()
|
||||
|
|
|
@ -10,6 +10,7 @@ use gecko_bindings::structs::mozilla::css::URLValue;
|
|||
use gecko_bindings::structs::mozilla::Side;
|
||||
use gecko_bindings::structs::RawGeckoAnimationPropertySegment;
|
||||
use gecko_bindings::structs::RawGeckoComputedTiming;
|
||||
use gecko_bindings::structs::RawGeckoCSSPropertyIDList;
|
||||
use gecko_bindings::structs::RawGeckoDocument;
|
||||
use gecko_bindings::structs::RawGeckoElement;
|
||||
use gecko_bindings::structs::RawGeckoKeyframeList;
|
||||
|
@ -48,6 +49,7 @@ use gecko_bindings::structs::nsCSSCounterStyleRule;
|
|||
use gecko_bindings::structs::nsCSSFontFaceRule;
|
||||
use gecko_bindings::structs::nsCSSKeyword;
|
||||
use gecko_bindings::structs::nsCSSPropertyID;
|
||||
use gecko_bindings::structs::nsCSSPropertyIDSet;
|
||||
use gecko_bindings::structs::nsCSSShadowArray;
|
||||
use gecko_bindings::structs::nsCSSUnit;
|
||||
use gecko_bindings::structs::nsCSSValue;
|
||||
|
@ -316,6 +318,10 @@ pub type RawGeckoPresContextBorrowed<'a> = &'a RawGeckoPresContext;
|
|||
pub type RawGeckoPresContextBorrowedOrNull<'a> = Option<&'a RawGeckoPresContext>;
|
||||
pub type RawGeckoStyleAnimationListBorrowed<'a> = &'a RawGeckoStyleAnimationList;
|
||||
pub type RawGeckoStyleAnimationListBorrowedOrNull<'a> = Option<&'a RawGeckoStyleAnimationList>;
|
||||
pub type nsCSSPropertyIDSetBorrowed<'a> = &'a nsCSSPropertyIDSet;
|
||||
pub type nsCSSPropertyIDSetBorrowedOrNull<'a> = Option<&'a nsCSSPropertyIDSet>;
|
||||
pub type nsCSSPropertyIDSetBorrowedMut<'a> = &'a mut nsCSSPropertyIDSet;
|
||||
pub type nsCSSPropertyIDSetBorrowedMutOrNull<'a> = Option<&'a mut nsCSSPropertyIDSet>;
|
||||
pub type nsCSSValueBorrowed<'a> = &'a nsCSSValue;
|
||||
pub type nsCSSValueBorrowedOrNull<'a> = Option<&'a nsCSSValue>;
|
||||
pub type nsCSSValueBorrowedMut<'a> = &'a mut nsCSSValue;
|
||||
|
@ -352,6 +358,10 @@ pub type RawGeckoServoStyleRuleListBorrowed<'a> = &'a RawGeckoServoStyleRuleList
|
|||
pub type RawGeckoServoStyleRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoServoStyleRuleList>;
|
||||
pub type RawGeckoServoStyleRuleListBorrowedMut<'a> = &'a mut RawGeckoServoStyleRuleList;
|
||||
pub type RawGeckoServoStyleRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoServoStyleRuleList>;
|
||||
pub type RawGeckoCSSPropertyIDListBorrowed<'a> = &'a RawGeckoCSSPropertyIDList;
|
||||
pub type RawGeckoCSSPropertyIDListBorrowedOrNull<'a> = Option<&'a RawGeckoCSSPropertyIDList>;
|
||||
pub type RawGeckoCSSPropertyIDListBorrowedMut<'a> = &'a mut RawGeckoCSSPropertyIDList;
|
||||
pub type RawGeckoCSSPropertyIDListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoCSSPropertyIDList>;
|
||||
|
||||
extern "C" {
|
||||
pub fn Gecko_EnsureTArrayCapacity(aArray: *mut ::std::os::raw::c_void,
|
||||
|
@ -1177,6 +1187,9 @@ extern "C" {
|
|||
extern "C" {
|
||||
pub fn Gecko_NewCSSValueSharedList(len: u32) -> *mut nsCSSValueSharedList;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_NewNoneTransform() -> *mut nsCSSValueSharedList;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_CSSValue_GetArrayItem(css_value: nsCSSValueBorrowedMut,
|
||||
index: i32) -> nsCSSValueBorrowedMut;
|
||||
|
@ -1363,6 +1376,10 @@ extern "C" {
|
|||
ident: *const u16,
|
||||
set_slow_selector: *mut bool) -> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_AddPropertyToSet(arg1: nsCSSPropertyIDSetBorrowedMut,
|
||||
arg2: nsCSSPropertyID);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_Construct_Default_nsStyleFont(ptr: *mut nsStyleFont,
|
||||
pres_context:
|
||||
|
@ -2076,6 +2093,14 @@ extern "C" {
|
|||
pub fn Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID)
|
||||
-> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_GetProperties_Overriding_Animation(arg1:
|
||||
RawGeckoElementBorrowed,
|
||||
arg2:
|
||||
RawGeckoCSSPropertyIDListBorrowed,
|
||||
arg3:
|
||||
nsCSSPropertyIDSetBorrowedMut);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_AnimationValues_Interpolate(from:
|
||||
RawServoAnimationValueBorrowed,
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -379,6 +379,39 @@ pub enum StyleSharingResult {
|
|||
StyleWasShared(usize),
|
||||
}
|
||||
|
||||
/// The result status for match primary rules.
|
||||
#[derive(Debug)]
|
||||
pub struct RulesMatchedResult {
|
||||
/// Indicate that the rule nodes are changed.
|
||||
rule_nodes_changed: bool,
|
||||
/// Indicate that there are any changes of important rules overriding animations.
|
||||
important_rules_overriding_animation_changed: bool,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags that represent the result of replace_rules.
|
||||
pub flags RulesChanged: u8 {
|
||||
/// Normal rules are changed.
|
||||
const NORMAL_RULES_CHANGED = 0x01,
|
||||
/// Important rules are changed.
|
||||
const IMPORTANT_RULES_CHANGED = 0x02,
|
||||
}
|
||||
}
|
||||
|
||||
impl RulesChanged {
|
||||
/// Return true if there are any normal rules changed.
|
||||
#[inline]
|
||||
pub fn normal_rules_changed(&self) -> bool {
|
||||
self.contains(NORMAL_RULES_CHANGED)
|
||||
}
|
||||
|
||||
/// Return true if there are any important rules changed.
|
||||
#[inline]
|
||||
pub fn important_rules_changed(&self) -> bool {
|
||||
self.contains(IMPORTANT_RULES_CHANGED)
|
||||
}
|
||||
}
|
||||
|
||||
trait PrivateMatchMethods: TElement {
|
||||
/// Returns the closest parent element that doesn't have a display: contents
|
||||
/// style (and thus generates a box).
|
||||
|
@ -536,7 +569,8 @@ trait PrivateMatchMethods: TElement {
|
|||
/// setting them on the ElementData.
|
||||
fn cascade_primary(&self,
|
||||
context: &mut StyleContext<Self>,
|
||||
data: &mut ElementData) {
|
||||
data: &mut ElementData,
|
||||
important_rules_changed: bool) {
|
||||
// Collect some values.
|
||||
let (mut styles, restyle) = data.styles_and_restyle_mut();
|
||||
let mut primary_style = &mut styles.primary;
|
||||
|
@ -551,7 +585,8 @@ trait PrivateMatchMethods: TElement {
|
|||
self.process_animations(context,
|
||||
&mut old_values,
|
||||
&mut new_values,
|
||||
primary_style);
|
||||
primary_style,
|
||||
important_rules_changed);
|
||||
}
|
||||
|
||||
if let Some(old) = old_values {
|
||||
|
@ -647,8 +682,9 @@ trait PrivateMatchMethods: TElement {
|
|||
context: &mut StyleContext<Self>,
|
||||
old_values: &mut Option<Arc<ComputedValues>>,
|
||||
new_values: &mut Arc<ComputedValues>,
|
||||
primary_style: &ComputedStyle) {
|
||||
use context::{CSS_ANIMATIONS, CSS_TRANSITIONS, EFFECT_PROPERTIES};
|
||||
primary_style: &ComputedStyle,
|
||||
important_rules_changed: bool) {
|
||||
use context::{CASCADE_RESULTS, CSS_ANIMATIONS, CSS_TRANSITIONS, EFFECT_PROPERTIES};
|
||||
use context::UpdateAnimationsTasks;
|
||||
|
||||
let mut tasks = UpdateAnimationsTasks::empty();
|
||||
|
@ -694,6 +730,9 @@ trait PrivateMatchMethods: TElement {
|
|||
|
||||
if self.has_animations() {
|
||||
tasks.insert(EFFECT_PROPERTIES);
|
||||
if important_rules_changed {
|
||||
tasks.insert(CASCADE_RESULTS);
|
||||
}
|
||||
}
|
||||
|
||||
if !tasks.is_empty() {
|
||||
|
@ -709,7 +748,8 @@ trait PrivateMatchMethods: TElement {
|
|||
context: &mut StyleContext<Self>,
|
||||
old_values: &mut Option<Arc<ComputedValues>>,
|
||||
new_values: &mut Arc<ComputedValues>,
|
||||
_primary_style: &ComputedStyle) {
|
||||
_primary_style: &ComputedStyle,
|
||||
_important_rules_changed: bool) {
|
||||
use animation;
|
||||
|
||||
let possibly_expired_animations =
|
||||
|
@ -881,17 +921,14 @@ pub trait MatchMethods : TElement {
|
|||
{
|
||||
// Perform selector matching for the primary style.
|
||||
let mut relations = StyleRelations::empty();
|
||||
let _rule_node_changed = self.match_primary(context,
|
||||
data,
|
||||
&mut relations);
|
||||
let result = self.match_primary(context, data, &mut relations);
|
||||
|
||||
// Cascade properties and compute primary values.
|
||||
self.cascade_primary(context, data);
|
||||
self.cascade_primary(context, data, result.important_rules_overriding_animation_changed);
|
||||
|
||||
// Match and cascade eager pseudo-elements.
|
||||
if !data.styles().is_display_none() {
|
||||
let _pseudo_rule_nodes_changed =
|
||||
self.match_pseudos(context, data);
|
||||
let _pseudo_rule_nodes_changed = self.match_pseudos(context, data);
|
||||
self.cascade_pseudos(context, data);
|
||||
}
|
||||
|
||||
|
@ -925,20 +962,22 @@ pub trait MatchMethods : TElement {
|
|||
/// Performs the cascade, without matching.
|
||||
fn cascade_primary_and_pseudos(&self,
|
||||
context: &mut StyleContext<Self>,
|
||||
mut data: &mut ElementData)
|
||||
mut data: &mut ElementData,
|
||||
important_rules_changed: bool)
|
||||
{
|
||||
self.cascade_primary(context, &mut data);
|
||||
self.cascade_primary(context, &mut data, important_rules_changed);
|
||||
self.cascade_pseudos(context, &mut data);
|
||||
}
|
||||
|
||||
/// Runs selector matching to (re)compute the primary rule node for this element.
|
||||
///
|
||||
/// Returns whether the primary rule node changed.
|
||||
/// Returns RulesMatchedResult which indicates whether the primary rule node changed
|
||||
/// and whether the change includes important rules.
|
||||
fn match_primary(&self,
|
||||
context: &mut StyleContext<Self>,
|
||||
data: &mut ElementData,
|
||||
relations: &mut StyleRelations)
|
||||
-> bool
|
||||
-> RulesMatchedResult
|
||||
{
|
||||
let implemented_pseudo = self.implemented_pseudo_element();
|
||||
if let Some(ref pseudo) = implemented_pseudo {
|
||||
|
@ -977,7 +1016,16 @@ pub trait MatchMethods : TElement {
|
|||
}
|
||||
}
|
||||
|
||||
return data.set_primary_rules(rules);
|
||||
let important_rules_changed =
|
||||
self.has_animations() &&
|
||||
data.has_styles() &&
|
||||
data.important_rules_are_different(&rules,
|
||||
&context.shared.guards);
|
||||
|
||||
return RulesMatchedResult {
|
||||
rule_nodes_changed: data.set_primary_rules(rules),
|
||||
important_rules_overriding_animation_changed: important_rules_changed,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1015,7 +1063,15 @@ pub trait MatchMethods : TElement {
|
|||
&mut applicable_declarations,
|
||||
&context.shared.guards);
|
||||
|
||||
return data.set_primary_rules(primary_rule_node);
|
||||
let important_rules_changed = self.has_animations() &&
|
||||
data.has_styles() &&
|
||||
data.important_rules_are_different(&primary_rule_node,
|
||||
&context.shared.guards);
|
||||
|
||||
RulesMatchedResult {
|
||||
rule_nodes_changed: data.set_primary_rules(primary_rule_node),
|
||||
important_rules_overriding_animation_changed: important_rules_changed,
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs selector matching to (re)compute eager pseudo-element rule nodes
|
||||
|
@ -1155,18 +1211,19 @@ pub trait MatchMethods : TElement {
|
|||
}
|
||||
|
||||
/// Updates the rule nodes without re-running selector matching, using just
|
||||
/// the rule tree. Returns true if the rule nodes changed.
|
||||
/// the rule tree. Returns RulesChanged which indicates whether the rule nodes changed
|
||||
/// and whether the important rules changed.
|
||||
fn replace_rules(&self,
|
||||
hint: RestyleHint,
|
||||
context: &StyleContext<Self>,
|
||||
data: &mut AtomicRefMut<ElementData>)
|
||||
-> bool {
|
||||
-> RulesChanged {
|
||||
use properties::PropertyDeclarationBlock;
|
||||
use shared_lock::Locked;
|
||||
|
||||
let element_styles = &mut data.styles_mut();
|
||||
let primary_rules = &mut element_styles.primary.rules;
|
||||
let mut rule_node_changed = false;
|
||||
let mut result = RulesChanged::empty();
|
||||
|
||||
{
|
||||
let mut replace_rule_node = |level: CascadeLevel,
|
||||
|
@ -1176,7 +1233,11 @@ pub trait MatchMethods : TElement {
|
|||
.update_rule_at_level(level, pdb, path, &context.shared.guards);
|
||||
if let Some(n) = new_node {
|
||||
*path = n;
|
||||
rule_node_changed = true;
|
||||
if level.is_important() {
|
||||
result.insert(IMPORTANT_RULES_CHANGED);
|
||||
} else {
|
||||
result.insert(NORMAL_RULES_CHANGED);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1224,7 +1285,7 @@ pub trait MatchMethods : TElement {
|
|||
}
|
||||
}
|
||||
|
||||
rule_node_changed
|
||||
result
|
||||
}
|
||||
|
||||
/// Attempts to share a style with another node. This method is unsafe
|
||||
|
|
|
@ -2241,7 +2241,7 @@ fn static_assert() {
|
|||
% endfor
|
||||
}
|
||||
</%def>
|
||||
pub fn convert_transform(input: Vec<longhands::transform::computed_value::ComputedOperation>,
|
||||
pub fn convert_transform(input: &[longhands::transform::computed_value::ComputedOperation],
|
||||
output: &mut structs::root::RefPtr<structs::root::nsCSSValueSharedList>) {
|
||||
use gecko_bindings::structs::nsCSSKeyword::*;
|
||||
use gecko_bindings::sugar::refptr::RefPtr;
|
||||
|
@ -2261,7 +2261,7 @@ fn static_assert() {
|
|||
let servo = iter.next().expect("Gecko_NewCSSValueSharedList should create a shared \
|
||||
value list of the same length as the transform vector");
|
||||
unsafe {
|
||||
match servo {
|
||||
match *servo {
|
||||
${transform_function_arm("Matrix", "matrix3d", ["number"] * 16)}
|
||||
${transform_function_arm("MatrixWithPercents", "matrix3d", ["number"] * 12 + ["lop"] * 2
|
||||
+ ["length"] + ["number"])}
|
||||
|
@ -2287,7 +2287,7 @@ fn static_assert() {
|
|||
}
|
||||
return;
|
||||
};
|
||||
Self::convert_transform(vec, &mut self.gecko.mSpecifiedTransform);
|
||||
Self::convert_transform(&vec, &mut self.gecko.mSpecifiedTransform);
|
||||
}
|
||||
|
||||
pub fn copy_transform_from(&mut self, other: &Self) {
|
||||
|
|
|
@ -250,7 +250,7 @@ pub mod animated_properties {
|
|||
}
|
||||
|
||||
/// A set of longhand properties
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct LonghandIdSet {
|
||||
storage: [u32; (${len(data.longhands)} - 1 + 32) / 32]
|
||||
}
|
||||
|
@ -954,7 +954,7 @@ impl PropertyId {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a property id from Gecko's nsCSSPropertyID.
|
||||
/// Returns an nsCSSPropertyID.
|
||||
#[cfg(feature = "gecko")]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub fn to_nscsspropertyid(&self) -> Result<nsCSSPropertyID, ()> {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#[cfg(feature = "servo")]
|
||||
use heapsize::HeapSizeOf;
|
||||
use properties::{Importance, PropertyDeclarationBlock};
|
||||
use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock};
|
||||
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
|
||||
use smallvec::SmallVec;
|
||||
use std::io::{self, Write};
|
||||
|
@ -1092,6 +1092,42 @@ impl StrongRuleNode {
|
|||
.take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride)
|
||||
.any(|node| node.cascade_level().is_animation())
|
||||
}
|
||||
|
||||
/// Get a set of properties whose CascadeLevel are higher than Animations but not equal to
|
||||
/// Transitions. If there are any custom properties, we set the boolean value of the returned
|
||||
/// tuple to true.
|
||||
pub fn get_properties_overriding_animations(&self, guards: &StylesheetGuards)
|
||||
-> (LonghandIdSet, bool) {
|
||||
use properties::PropertyDeclarationId;
|
||||
|
||||
// We want to iterate over cascade levels that override the animations level, i.e.
|
||||
// !important levels and the transitions level. However, we actually want to skip the
|
||||
// transitions level because although it is higher in the cascade than animations, when
|
||||
// both transitions and animations are present for a given element and property, transitions
|
||||
// are suppressed so that they don't actually override animations.
|
||||
let iter = self.self_and_ancestors()
|
||||
.skip_while(|node| node.cascade_level() == CascadeLevel::Transitions)
|
||||
.take_while(|node| node.cascade_level() > CascadeLevel::Animations);
|
||||
let mut result = (LonghandIdSet::new(), false);
|
||||
for node in iter {
|
||||
let style = node.style_source().unwrap();
|
||||
for &(ref decl, important) in style.read(node.cascade_level().guard(guards))
|
||||
.declarations()
|
||||
.iter() {
|
||||
// Although we are only iterating over cascade levels that override animations,
|
||||
// in a given property declaration block we can have a mixture of !important and
|
||||
// non-!important declarations but only the !important declarations actually
|
||||
// override animations.
|
||||
if important.important() {
|
||||
match decl.id() {
|
||||
PropertyDeclarationId::Longhand(id) => result.0.insert(id),
|
||||
PropertyDeclarationId::Custom(_) => result.1 = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over a rule node and its ancestors.
|
||||
|
|
|
@ -747,12 +747,12 @@ fn compute_style<E, D>(_traversal: &D,
|
|||
element.match_and_cascade(context, &mut data, StyleSharingBehavior::Allow);
|
||||
}
|
||||
CascadeWithReplacements(hint) => {
|
||||
let _rule_nodes_changed =
|
||||
element.replace_rules(hint, context, &mut data);
|
||||
element.cascade_primary_and_pseudos(context, &mut data);
|
||||
let rules_changed = element.replace_rules(hint, context, &mut data);
|
||||
element.cascade_primary_and_pseudos(context, &mut data,
|
||||
rules_changed.important_rules_changed());
|
||||
}
|
||||
CascadeOnly => {
|
||||
element.cascade_primary_and_pseudos(context, &mut data);
|
||||
element.cascade_primary_and_pseudos(context, &mut data, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -40,11 +40,14 @@ use style::gecko_bindings::bindings::{RawServoStyleSheetBorrowed, ServoComputedV
|
|||
use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedValuesStrong};
|
||||
use style::gecko_bindings::bindings::{RawServoSupportsRule, RawServoSupportsRuleBorrowed};
|
||||
use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong};
|
||||
use style::gecko_bindings::bindings::{nsACString, nsAString};
|
||||
use style::gecko_bindings::bindings::{nsACString, nsAString, nsCSSPropertyIDSetBorrowedMut};
|
||||
use style::gecko_bindings::bindings::Gecko_AddPropertyToSet;
|
||||
use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
|
||||
use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
|
||||
use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
|
||||
use style::gecko_bindings::bindings::Gecko_NewNoneTransform;
|
||||
use style::gecko_bindings::bindings::RawGeckoAnimationPropertySegmentBorrowed;
|
||||
use style::gecko_bindings::bindings::RawGeckoCSSPropertyIDListBorrowed;
|
||||
use style::gecko_bindings::bindings::RawGeckoComputedKeyframeValuesListBorrowedMut;
|
||||
use style::gecko_bindings::bindings::RawGeckoComputedTimingBorrowed;
|
||||
use style::gecko_bindings::bindings::RawGeckoElementBorrowed;
|
||||
|
@ -247,20 +250,29 @@ pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed,
|
|||
debug!("Servo_TraverseSubtree: {:?}", element);
|
||||
|
||||
let traversal_flags = match (root_behavior, restyle_behavior) {
|
||||
(Root::Normal, Restyle::Normal) => TraversalFlags::empty(),
|
||||
(Root::UnstyledChildrenOnly, Restyle::Normal) => UNSTYLED_CHILDREN_ONLY,
|
||||
(Root::Normal, Restyle::Normal) |
|
||||
(Root::Normal, Restyle::ForAnimationOnly)
|
||||
=> TraversalFlags::empty(),
|
||||
(Root::UnstyledChildrenOnly, Restyle::Normal) |
|
||||
(Root::UnstyledChildrenOnly, Restyle::ForAnimationOnly)
|
||||
=> UNSTYLED_CHILDREN_ONLY,
|
||||
(Root::Normal, Restyle::ForReconstruct) => FOR_RECONSTRUCT,
|
||||
_ => panic!("invalid combination of TraversalRootBehavior and TraversalRestyleBehavior"),
|
||||
};
|
||||
|
||||
if element.has_animation_only_dirty_descendants() ||
|
||||
element.has_animation_restyle_hints() {
|
||||
let needs_animation_only_restyle = element.has_animation_only_dirty_descendants() ||
|
||||
element.has_animation_restyle_hints();
|
||||
if needs_animation_only_restyle {
|
||||
traverse_subtree(element,
|
||||
raw_data,
|
||||
traversal_flags | ANIMATION_ONLY,
|
||||
unsafe { &*snapshots });
|
||||
}
|
||||
|
||||
if restyle_behavior == Restyle::ForAnimationOnly {
|
||||
return needs_animation_only_restyle;
|
||||
}
|
||||
|
||||
traverse_subtree(element,
|
||||
raw_data,
|
||||
traversal_flags,
|
||||
|
@ -449,7 +461,15 @@ pub extern "C" fn Servo_AnimationValue_GetTransform(value: RawServoAnimationValu
|
|||
{
|
||||
let value = AnimationValue::as_arc(&value);
|
||||
if let AnimationValue::Transform(ref servo_list) = **value {
|
||||
style_structs::Box::convert_transform(servo_list.0.clone().unwrap(), unsafe { &mut *list });
|
||||
let list = unsafe { &mut *list };
|
||||
match servo_list.0 {
|
||||
Some(ref servo_list) => {
|
||||
style_structs::Box::convert_transform(servo_list, list);
|
||||
},
|
||||
None => unsafe {
|
||||
list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("The AnimationValue should be transform");
|
||||
}
|
||||
|
@ -1319,6 +1339,38 @@ pub extern "C" fn Servo_ParseEasing(easing: *const nsAString,
|
|||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_GetProperties_Overriding_Animation(element: RawGeckoElementBorrowed,
|
||||
list: RawGeckoCSSPropertyIDListBorrowed,
|
||||
set: nsCSSPropertyIDSetBorrowedMut) {
|
||||
let element = GeckoElement(element);
|
||||
let element_data = match element.borrow_data() {
|
||||
Some(data) => data,
|
||||
None => return
|
||||
};
|
||||
let global_style_data = &*GLOBAL_STYLE_DATA;
|
||||
let guard = global_style_data.shared_lock.read();
|
||||
let guards = StylesheetGuards::same(&guard);
|
||||
let (overridden, custom) =
|
||||
element_data.styles().primary.rules.get_properties_overriding_animations(&guards);
|
||||
for p in list.iter() {
|
||||
match PropertyId::from_nscsspropertyid(*p) {
|
||||
Ok(property) => {
|
||||
if let PropertyId::Longhand(id) = property {
|
||||
if overridden.contains(id) {
|
||||
unsafe { Gecko_AddPropertyToSet(set, *p) };
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
if *p == nsCSSPropertyID::eCSSPropertyExtra_variable && custom {
|
||||
unsafe { Gecko_AddPropertyToSet(set, *p) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_ParseStyleAttribute(data: *const nsACString,
|
||||
raw_extra_data: *mut URLExtraData,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue