Bug 1317209 - Part 7: Support transition cascade level. draft
authorBoris Chiou <boris.chiou@gmail.com>
Wed, 18 Jan 2017 11:58:06 +0800
changeset 465474 0bf5244e35719a47212494f32c13eb11b363a287
parent 465473 8cb32439f2991fc5501900a969eb2061bfb354f1
child 543150 68220594321b1edae14941f8cce3f8f9e5e3c63b
push id42602
push userbmo:boris.chiou@gmail.com
push dateTue, 24 Jan 2017 04:27:32 +0000
bugs1317209
milestone53.0a1
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
dom/animation/EffectCompositor.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
servo/components/style/dom.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/gecko_bindings/bindings.rs
servo/components/style/gecko_bindings/structs_debug.rs
servo/components/style/gecko_bindings/structs_release.rs
servo/components/style/matching.rs
servo/components/style/stylist.rs
--- 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]