Bug 1317209 - Part 7: Support transition cascade level.
Implement the mapping between EffectCompositor::CascadeLevel in Gecko and
EffectCompositor_CascadeLevel in Servo, so we can pass it as a parameter.
MozReview-Commit-ID: GRedooyGE8c
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -55,22 +55,22 @@ public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(EffectCompositor)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EffectCompositor)
void Disconnect() {
mPresContext = nullptr;
}
// Animations can be applied at two different levels in the CSS cascade:
- enum class CascadeLevel {
+ enum class CascadeLevel : uint32_t {
// The animations sheet (CSS animations, script-generated animations,
// and CSS transitions that are no longer tied to CSS markup)
- Animations,
+ Animations = 0,
// The transitions sheet (CSS transitions that are tied to CSS markup)
- Transitions
+ Transitions = 1
};
// We don't define this as part of CascadeLevel as then we'd have to add
// explicit checks for the Count enum value everywhere CascadeLevel is used.
static const size_t kCascadeLevelCount =
static_cast<size_t>(CascadeLevel::Transitions) + 1;
// NOTE: This can return null after Disconnect().
nsPresContext* PresContext() const { return mPresContext; }
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -324,48 +324,46 @@ Gecko_GetServoDeclarationBlock(RawGeckoE
return nullptr;
}
return reinterpret_cast<const RawServoDeclarationBlockStrong*>
(decl->AsServo()->RefRaw());
}
RawServoDeclarationBlockStrong
Gecko_GetAnimationRule(RawGeckoElementBorrowed aElement,
- nsIAtom* aPseudoTag)
+ nsIAtom* aPseudoTag,
+ EffectCompositor::CascadeLevel aCascadeLevel)
{
MOZ_ASSERT(aElement, "Invalid GeckoElement");
const RawServoDeclarationBlockStrong emptyDeclarationBlock{ nullptr };
nsIDocument* doc = aElement->GetComposedDoc();
if (!doc || !doc->GetShell()) {
return emptyDeclarationBlock;
}
nsPresContext* presContext = doc->GetShell()->GetPresContext();
if (!presContext) {
return emptyDeclarationBlock;
}
- // FIXME: support different cascading levels in the later patch
CSSPseudoElementType pseudoType =
aPseudoTag
? nsCSSPseudoElements::GetPseudoType(
aPseudoTag,
nsCSSProps::EnabledState::eIgnoreEnabledState)
: CSSPseudoElementType::NotPseudo;
if (pseudoType != CSSPseudoElementType::NotPseudo &&
pseudoType != CSSPseudoElementType::before &&
pseudoType != CSSPseudoElementType::after) {
return emptyDeclarationBlock;
}
ServoAnimationRule* rule =
- presContext->EffectCompositor()->GetServoAnimationRule(
- aElement,
- pseudoType,
- EffectCompositor::CascadeLevel::Animations);
+ presContext->EffectCompositor()
+ ->GetServoAnimationRule(aElement, pseudoType, aCascadeLevel);
if (!rule) {
return emptyDeclarationBlock;
}
return rule->GetValues();
}
void
Gecko_FillAllBackgroundLists(nsStyleImageLayers* aLayers, uint32_t aMaxLen)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -8,16 +8,17 @@
#define mozilla_ServoBindings_h
#include <stdint.h>
#include "mozilla/ServoTypes.h"
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/ServoElementSnapshot.h"
#include "mozilla/css/SheetParsingMode.h"
+#include "mozilla/EffectCompositor.h"
#include "nsChangeHint.h"
#include "nsCSSPseudoClasses.h"
#include "nsStyleStruct.h"
/*
* API for Servo to access Gecko data structures. This file must compile as valid
* C code in order for the binding generator to parse it.
*
@@ -156,17 +157,18 @@ SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNC
// Style attributes.
RawServoDeclarationBlockStrongBorrowedOrNull
Gecko_GetServoDeclarationBlock(RawGeckoElementBorrowed element);
// Animations
RawServoDeclarationBlockStrong
Gecko_GetAnimationRule(RawGeckoElementBorrowed aElement,
- nsIAtom* aPseudoTag);
+ nsIAtom* aPseudoTag,
+ mozilla::EffectCompositor::CascadeLevel aCascadeLevel);
// Atoms.
nsIAtom* Gecko_Atomize(const char* aString, uint32_t aLength);
void Gecko_AddRefAtom(nsIAtom* aAtom);
void Gecko_ReleaseAtom(nsIAtom* aAtom);
const uint16_t* Gecko_GetAtomAsUTF16(nsIAtom* aAtom, uint32_t* aLength);
bool Gecko_AtomEqualsUTF8(nsIAtom* aAtom, const char* aString, uint32_t aLength);
bool Gecko_AtomEqualsUTF8IgnoreCase(nsIAtom* aAtom, const char* aString, uint32_t aLength);
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -222,16 +222,21 @@ fn fmt_subtree<F, N: TNode>(f: &mut fmt:
/// A trait used to synthesize presentational hints for HTML element attributes.
pub trait PresentationalHintsSynthetizer {
/// Generate the proper applicable declarations due to presentational hints,
/// and insert them into `hints`.
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
where V: Push<ApplicableDeclarationBlock>;
}
+/// The animation rules. The first one is for Animation cascade level, and the second one is for
+/// Transition cascade level.
+pub struct AnimationRules(pub Option<Arc<RwLock<PropertyDeclarationBlock>>>,
+ pub Option<Arc<RwLock<PropertyDeclarationBlock>>>);
+
/// The element trait, the main abstraction the style crate acts over.
pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
/// The concrete node type.
type ConcreteNode: TNode<ConcreteElement = Self>;
/// Get this element as a node.
fn as_node(&self) -> Self::ConcreteNode;
@@ -243,20 +248,19 @@ pub trait TElement : PartialEq + Debug +
} else {
self.parent_element()
}
}
/// Get this element's style attribute.
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>>;
- /// Get this element's animation rule.
- fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>)
- -> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
- None
+ /// Get this element's animation rules.
+ fn get_animation_rules(&self, _pseudo: Option<&PseudoElement>) -> AnimationRules {
+ AnimationRules(None, None)
}
/// Get this element's state, for non-tree-structural pseudos.
fn get_state(&self) -> ElementState;
/// Whether this element has an attribute with a given namespace.
fn has_attr(&self, namespace: &Namespace, attr: &LocalName) -> bool;
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -11,16 +11,17 @@
//! `components/script/layout_wrapper.rs`.
//!
//! This theoretically should live in its own crate, but now it lives in the
//! style system it's kind of pointless in the Stylo case, and only Servo forces
//! the separation between the style system implementation and everything else.
use atomic_refcell::AtomicRefCell;
use data::ElementData;
+use dom::AnimationRules;
use dom::{LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode};
use dom::{OpaqueNode, PresentationalHintsSynthetizer};
use element_state::ElementState;
use error_reporting::StdoutErrorReporter;
use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
use gecko::snapshot_helpers;
use gecko_bindings::bindings;
use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator};
@@ -32,16 +33,17 @@ use gecko_bindings::bindings::{Gecko_Set
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_GetAnimationRule;
use gecko_bindings::bindings::Gecko_GetStyleContext;
use gecko_bindings::structs;
use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode};
use gecko_bindings::structs::{nsIAtom, nsIContent, nsStyleContext};
use gecko_bindings::structs::NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO;
use gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
+use gecko_bindings::structs::EffectCompositor_CascadeLevel as Cascade;
use parking_lot::RwLock;
use parser::ParserContextExtraData;
use properties::{ComputedValues, parse_style_attribute};
use properties::PropertyDeclarationBlock;
use selector_parser::{ElementExt, Snapshot};
use selectors::Element;
use selectors::parser::{AttrSelector, NamespaceConstraint};
use servo_url::ServoUrl;
@@ -331,20 +333,23 @@ impl<'le> TElement for GeckoElement<'le>
unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
}
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> {
let declarations = unsafe { Gecko_GetServoDeclarationBlock(self.0) };
declarations.map(|s| s.as_arc_opt()).unwrap_or(None)
}
- fn get_animation_rule(&self, pseudo: Option<&PseudoElement>)
- -> Option<Arc<RwLock<PropertyDeclarationBlock>>> {
+ fn get_animation_rules(&self, pseudo: Option<&PseudoElement>) -> AnimationRules {
let atom_ptr = pseudo.map(|p| p.as_atom().as_ptr()).unwrap_or(ptr::null_mut());
- unsafe { Gecko_GetAnimationRule(self.0, atom_ptr) }.into_arc_opt()
+ unsafe {
+ AnimationRules(
+ Gecko_GetAnimationRule(self.0, atom_ptr, Cascade::Animations).into_arc_opt(),
+ Gecko_GetAnimationRule(self.0, atom_ptr, Cascade::Transitions).into_arc_opt())
+ }
}
fn get_state(&self) -> ElementState {
unsafe {
ElementState::from_bits_truncate(Gecko_ElementState(self.0))
}
}
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -1,13 +1,14 @@
/* automatically generated by rust-bindgen */
pub use nsstring::{nsACString, nsAString};
type nsACString_internal = nsACString;
type nsAString_internal = nsAString;
+use gecko_bindings::structs::EffectCompositor_CascadeLevel;
use gecko_bindings::structs::RawGeckoDocument;
use gecko_bindings::structs::RawGeckoElement;
use gecko_bindings::structs::RawGeckoNode;
use gecko_bindings::structs::RawGeckoAnimationValueList;
use gecko_bindings::structs::RawServoAnimationValue;
use gecko_bindings::structs::RawServoAnimationValueBorrowedList;
use gecko_bindings::structs::RawGeckoPresContext;
use gecko_bindings::structs::RawGeckoPresContextOwned;
@@ -498,17 +499,18 @@ extern "C" {
-> u32;
}
extern "C" {
pub fn Gecko_GetServoDeclarationBlock(element: RawGeckoElementBorrowed)
-> RawServoDeclarationBlockStrongBorrowedOrNull;
}
extern "C" {
pub fn Gecko_GetAnimationRule(element: RawGeckoElementBorrowed,
- aAtom: *mut nsIAtom)
+ aAtom: *mut nsIAtom,
+ aCascadeLevel: EffectCompositor_CascadeLevel)
-> RawServoDeclarationBlockStrong;
}
extern "C" {
pub fn Gecko_Atomize(aString: *const ::std::os::raw::c_char, aLength: u32)
-> *mut nsIAtom;
}
extern "C" {
pub fn Gecko_AddRefAtom(aAtom: *mut nsIAtom);
--- a/servo/components/style/gecko_bindings/structs_debug.rs
+++ b/servo/components/style/gecko_bindings/structs_debug.rs
@@ -3568,16 +3568,22 @@ pub mod root {
#[test]
fn bindgen_test_layout_StyleComplexColor() {
assert_eq!(::std::mem::size_of::<StyleComplexColor>() , 8usize);
assert_eq!(::std::mem::align_of::<StyleComplexColor>() , 4usize);
}
impl Clone for StyleComplexColor {
fn clone(&self) -> Self { *self }
}
+ #[repr(u32)]
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum EffectCompositor_CascadeLevel {
+ Animations = 0,
+ Transitions = 1,
+ }
#[repr(C)]
#[derive(Debug)]
pub struct PropertyStyleAnimationValuePair {
pub mProperty: root::nsCSSPropertyID,
pub mValue: root::mozilla::StyleAnimationValue,
pub mServoValue: root::RefPtr<root::RawServoAnimationValue>,
}
#[test]
--- a/servo/components/style/gecko_bindings/structs_release.rs
+++ b/servo/components/style/gecko_bindings/structs_release.rs
@@ -3539,16 +3539,22 @@ pub mod root {
#[test]
fn bindgen_test_layout_StyleComplexColor() {
assert_eq!(::std::mem::size_of::<StyleComplexColor>() , 8usize);
assert_eq!(::std::mem::align_of::<StyleComplexColor>() , 4usize);
}
impl Clone for StyleComplexColor {
fn clone(&self) -> Self { *self }
}
+ #[repr(u32)]
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum EffectCompositor_CascadeLevel {
+ Aniamtions = 0,
+ Transitions = 1,
+ }
#[repr(C)]
#[derive(Debug)]
pub struct PropertyStyleAnimationValuePair {
pub mProperty: root::nsCSSPropertyID,
pub mValue: root::mozilla::StyleAnimationValue,
pub mServoValue: root::RefPtr<root::RawServoAnimationValue>,
}
#[test]
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -584,36 +584,36 @@ impl<E: TElement> PrivateMatchMethods fo
pub trait MatchMethods : TElement {
/// Runs selector matching of this element, and returns the result.
fn match_element(&self, context: &StyleContext<Self>, parent_bf: Option<&BloomFilter>)
-> MatchResults
{
let mut applicable_declarations: Vec<ApplicableDeclarationBlock> = Vec::with_capacity(16);
let stylist = &context.shared.stylist;
let style_attribute = self.style_attribute();
- let animation_rule = self.get_animation_rule(None);
+ let animation_rules = self.get_animation_rules(None);
// Compute the primary rule node.
let mut primary_relations =
stylist.push_applicable_declarations(self,
parent_bf,
style_attribute,
- animation_rule,
+ animation_rules,
None,
&mut applicable_declarations,
MatchingReason::ForStyling);
let primary_rule_node = compute_rule_node(context, &mut applicable_declarations);
// Compute the pseudo rule nodes.
let mut per_pseudo: PseudoRuleNodes = HashMap::with_hasher(Default::default());
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
debug_assert!(applicable_declarations.is_empty());
- let pseudo_animation_rule = self.get_animation_rule(Some(&pseudo));
+ let pseudo_animation_rules = self.get_animation_rules(Some(&pseudo));
stylist.push_applicable_declarations(self, parent_bf, None,
- pseudo_animation_rule,
+ pseudo_animation_rules,
Some(&pseudo.clone()),
&mut applicable_declarations,
MatchingReason::ForStyling);
if !applicable_declarations.is_empty() {
let rule_node = compute_rule_node(context, &mut applicable_declarations);
per_pseudo.insert(pseudo, rule_node);
}
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -3,30 +3,30 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Selector matching.
#![deny(missing_docs)]
use {Atom, LocalName};
use data::ComputedStyle;
-use dom::{PresentationalHintsSynthetizer, TElement};
+use dom::{AnimationRules, PresentationalHintsSynthetizer, TElement};
use error_reporting::StdoutErrorReporter;
use keyframes::KeyframesAnimation;
use media_queries::Device;
use parking_lot::RwLock;
use properties::{self, CascadeFlags, ComputedValues, INHERIT_ALL, Importance};
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use quickersort::sort_by;
use restyle_hints::{RestyleHint, DependencySet};
use rule_tree::{RuleTree, StrongRuleNode, StyleSource};
use selector_parser::{ElementExt, SelectorImpl, PseudoElement, Snapshot};
use selectors::Element;
use selectors::bloom::BloomFilter;
-use selectors::matching::AFFECTED_BY_ANIMATIONS;
+use selectors::matching::{AFFECTED_BY_ANIMATIONS, AFFECTED_BY_TRANSITIONS};
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
use selectors::matching::{MatchingReason, StyleRelations, matches_complex_selector};
use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector};
use sink::Push;
use smallvec::VecLike;
use std::borrow::Borrow;
use std::collections::HashMap;
use std::fmt;
@@ -382,17 +382,17 @@ impl Stylist {
return None;
}
let mut declarations = vec![];
self.push_applicable_declarations(element,
None,
None,
- None,
+ AnimationRules(None, None),
Some(pseudo),
&mut declarations,
MatchingReason::ForStyling);
let rule_node =
self.rule_tree.insert_ordered_rules(
declarations.into_iter().map(|a| (a.source, a.importance)));
@@ -487,17 +487,17 @@ impl Stylist {
///
/// The returned `StyleRelations` indicate hints about which kind of rules
/// have matched.
pub fn push_applicable_declarations<E, V>(
&self,
element: &E,
parent_bf: Option<&BloomFilter>,
style_attribute: Option<&Arc<RwLock<PropertyDeclarationBlock>>>,
- animation_rule: Option<Arc<RwLock<PropertyDeclarationBlock>>>,
+ animation_rules: AnimationRules,
pseudo_element: Option<&PseudoElement>,
applicable_declarations: &mut V,
reason: MatchingReason) -> StyleRelations
where E: ElementExt +
fmt::Debug +
PresentationalHintsSynthetizer,
V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>
{
@@ -559,17 +559,19 @@ impl Stylist {
applicable_declarations,
ApplicableDeclarationBlock::from_declarations(sa.clone(), Importance::Normal));
}
}
debug!("style attr: {:?}", relations);
// Step 5: Animations.
- if let Some(anim) = animation_rule {
+ // The animations sheet (CSS animations, script-generated animations,
+ // and CSS transitions that are no longer tied to CSS markup)
+ if let Some(anim) = animation_rules.0 {
relations |= AFFECTED_BY_ANIMATIONS;
Push::push(
applicable_declarations,
ApplicableDeclarationBlock::from_declarations(anim.clone(), Importance::Normal));
}
debug!("animation: {:?}", relations);
// Step 6: Author-supplied `!important` rules.
@@ -612,16 +614,26 @@ impl Stylist {
parent_bf,
applicable_declarations,
&mut relations,
reason,
Importance::Important);
debug!("UA important: {:?}", relations);
+ // Step 10: Transitions.
+ // The transitions sheet (CSS transitions that are tied to CSS markup)
+ if let Some(anim) = animation_rules.1 {
+ relations |= AFFECTED_BY_TRANSITIONS;
+ Push::push(
+ applicable_declarations,
+ ApplicableDeclarationBlock::from_declarations(anim.clone(), Importance::Normal));
+ }
+ debug!("transition: {:?}", relations);
+
debug!("push_applicable_declarations: shareable: {:?}", relations);
relations
}
/// Return whether the device is dirty, that is, whether the screen size or
/// media type have changed (for now).
#[inline]