зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #20117 - style: Somewhat miscelaneous cleanup (from emilio:misc-cleanup); r=nox
Source-Repo: https://github.com/servo/servo Source-Revision: bbfca28a4f3770896955375d01f1c489b4632fd3 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : cca02ea2c160395889cfd6eb60c62a065d490300
This commit is contained in:
Родитель
fc6411f333
Коммит
e47cb58448
|
@ -47,14 +47,19 @@ impl<'a> RecalcStyleAndConstructFlows<'a> {
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
|
impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
|
||||||
where E: TElement,
|
where
|
||||||
E::ConcreteNode: LayoutNode,
|
E: TElement,
|
||||||
E::FontMetricsProvider: Send,
|
E::ConcreteNode: LayoutNode,
|
||||||
|
E::FontMetricsProvider: Send,
|
||||||
{
|
{
|
||||||
fn process_preorder<F>(&self, traversal_data: &PerLevelTraversalData,
|
fn process_preorder<F>(
|
||||||
context: &mut StyleContext<E>, node: E::ConcreteNode,
|
&self,
|
||||||
note_child: F)
|
traversal_data: &PerLevelTraversalData,
|
||||||
where F: FnMut(E::ConcreteNode)
|
context: &mut StyleContext<E>, node: E::ConcreteNode,
|
||||||
|
note_child: F,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
F: FnMut(E::ConcreteNode)
|
||||||
{
|
{
|
||||||
// FIXME(pcwalton): Stop allocating here. Ideally this should just be
|
// FIXME(pcwalton): Stop allocating here. Ideally this should just be
|
||||||
// done by the HTML parser.
|
// done by the HTML parser.
|
||||||
|
|
|
@ -341,7 +341,7 @@ pub struct ServoLayoutElement<'le> {
|
||||||
impl<'le> fmt::Debug for ServoLayoutElement<'le> {
|
impl<'le> fmt::Debug for ServoLayoutElement<'le> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "<{}", self.element.local_name())?;
|
write!(f, "<{}", self.element.local_name())?;
|
||||||
if let &Some(ref id) = unsafe { &*self.element.id_attribute() } {
|
if let Some(id) = self.id() {
|
||||||
write!(f, " id={}", id)?;
|
write!(f, " id={}", id)?;
|
||||||
}
|
}
|
||||||
write!(f, "> ({:#x})", self.as_node().opaque().0)
|
write!(f, "> ({:#x})", self.as_node().opaque().0)
|
||||||
|
@ -372,7 +372,7 @@ impl<'le> TElement for ServoLayoutElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_state(&self) -> ElementState {
|
fn state(&self) -> ElementState {
|
||||||
self.element.get_state_for_layout()
|
self.element.get_state_for_layout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,9 +382,9 @@ impl<'le> TElement for ServoLayoutElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_id(&self) -> Option<Atom> {
|
fn id(&self) -> Option<&Atom> {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.element.id_attribute()).clone()
|
(*self.element.id_attribute()).as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,12 +692,12 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_local_name(&self) -> &LocalName {
|
fn local_name(&self) -> &LocalName {
|
||||||
self.element.local_name()
|
self.element.local_name()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_namespace(&self) -> &Namespace {
|
fn namespace(&self) -> &Namespace {
|
||||||
self.element.namespace()
|
self.element.namespace()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,7 +787,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
fn is_html_slot_element(&self) -> bool {
|
fn is_html_slot_element(&self) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.element.is_html_element() &&
|
self.element.is_html_element() &&
|
||||||
self.get_local_name() == &local_name!("slot")
|
self.local_name() == &local_name!("slot")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,8 +1025,8 @@ impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNod
|
||||||
loop {
|
loop {
|
||||||
let next_node = if let Some(ref node) = current_node {
|
let next_node = if let Some(ref node) = current_node {
|
||||||
if let Some(element) = node.as_element() {
|
if let Some(element) = node.as_element() {
|
||||||
if element.get_local_name() == &local_name!("summary") &&
|
if element.local_name() == &local_name!("summary") &&
|
||||||
element.get_namespace() == &ns!(html) {
|
element.namespace() == &ns!(html) {
|
||||||
self.current_node = None;
|
self.current_node = None;
|
||||||
return Some(node.clone());
|
return Some(node.clone());
|
||||||
}
|
}
|
||||||
|
@ -1044,8 +1044,8 @@ impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNod
|
||||||
let node = self.current_node.clone();
|
let node = self.current_node.clone();
|
||||||
let node = node.and_then(|node| {
|
let node = node.and_then(|node| {
|
||||||
if node.is_element() &&
|
if node.is_element() &&
|
||||||
node.as_element().unwrap().get_local_name() == &local_name!("summary") &&
|
node.as_element().unwrap().local_name() == &local_name!("summary") &&
|
||||||
node.as_element().unwrap().get_namespace() == &ns!(html) {
|
node.as_element().unwrap().namespace() == &ns!(html) {
|
||||||
unsafe { node.dangerous_next_sibling() }
|
unsafe { node.dangerous_next_sibling() }
|
||||||
} else {
|
} else {
|
||||||
Some(node)
|
Some(node)
|
||||||
|
@ -1193,13 +1193,13 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_local_name(&self) -> &LocalName {
|
fn local_name(&self) -> &LocalName {
|
||||||
self.element.get_local_name()
|
self.element.local_name()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_namespace(&self) -> &Namespace {
|
fn namespace(&self) -> &Namespace {
|
||||||
self.element.get_namespace()
|
self.element.namespace()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_pseudo_element(
|
fn match_pseudo_element(
|
||||||
|
|
|
@ -2628,12 +2628,12 @@ impl<'a> SelectorsElement for DomRoot<Element> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_local_name(&self) -> &LocalName {
|
fn local_name(&self) -> &LocalName {
|
||||||
self.local_name()
|
Element::local_name(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_namespace(&self) -> &Namespace {
|
fn namespace(&self) -> &Namespace {
|
||||||
self.namespace()
|
Element::namespace(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class<F>(
|
fn match_non_ts_pseudo_class<F>(
|
||||||
|
|
|
@ -347,8 +347,8 @@ pub trait ThreadSafeLayoutElement
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_details_summary_pseudo(&self) -> Option<Self> {
|
fn get_details_summary_pseudo(&self) -> Option<Self> {
|
||||||
if self.get_local_name() == &local_name!("details") &&
|
if self.local_name() == &local_name!("details") &&
|
||||||
self.get_namespace() == &ns!(html) {
|
self.namespace() == &ns!(html) {
|
||||||
Some(self.with_pseudo(PseudoElementType::DetailsSummary))
|
Some(self.with_pseudo(PseudoElementType::DetailsSummary))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -357,8 +357,8 @@ pub trait ThreadSafeLayoutElement
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_details_content_pseudo(&self) -> Option<Self> {
|
fn get_details_content_pseudo(&self) -> Option<Self> {
|
||||||
if self.get_local_name() == &local_name!("details") &&
|
if self.local_name() == &local_name!("details") &&
|
||||||
self.get_namespace() == &ns!(html) &&
|
self.namespace() == &ns!(html) &&
|
||||||
self.get_attr(&ns!(), &local_name!("open")).is_some() {
|
self.get_attr(&ns!(), &local_name!("open")).is_some() {
|
||||||
Some(self.with_pseudo(PseudoElementType::DetailsContent))
|
Some(self.with_pseudo(PseudoElementType::DetailsContent))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -553,7 +553,7 @@ where
|
||||||
&local_name.name,
|
&local_name.name,
|
||||||
&local_name.lower_name
|
&local_name.lower_name
|
||||||
).borrow();
|
).borrow();
|
||||||
element.get_local_name() == name
|
element.local_name() == name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines whether the given element matches the given compound selector.
|
/// Determines whether the given element matches the given compound selector.
|
||||||
|
@ -655,11 +655,11 @@ where
|
||||||
}
|
}
|
||||||
Component::Namespace(_, ref url) |
|
Component::Namespace(_, ref url) |
|
||||||
Component::DefaultNamespace(ref url) => {
|
Component::DefaultNamespace(ref url) => {
|
||||||
element.get_namespace() == url.borrow()
|
element.namespace() == url.borrow()
|
||||||
}
|
}
|
||||||
Component::ExplicitNoNamespace => {
|
Component::ExplicitNoNamespace => {
|
||||||
let ns = ::parser::namespace_empty_string::<E::Impl>();
|
let ns = ::parser::namespace_empty_string::<E::Impl>();
|
||||||
element.get_namespace() == ns.borrow()
|
element.namespace() == ns.borrow()
|
||||||
}
|
}
|
||||||
Component::ID(ref id) => {
|
Component::ID(ref id) => {
|
||||||
element.has_id(id, context.shared.classes_and_ids_case_sensitivity())
|
element.has_id(id, context.shared.classes_and_ids_case_sensitivity())
|
||||||
|
@ -860,8 +860,8 @@ where
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn same_type<E: Element>(a: &E, b: &E) -> bool {
|
fn same_type<E: Element>(a: &E, b: &E) -> bool {
|
||||||
a.get_local_name() == b.get_local_name() &&
|
a.local_name() == b.local_name() &&
|
||||||
a.get_namespace() == b.get_namespace()
|
a.namespace() == b.namespace()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -53,16 +53,17 @@ pub trait Element: Sized + Clone + Debug {
|
||||||
|
|
||||||
fn is_html_element_in_html_document(&self) -> bool;
|
fn is_html_element_in_html_document(&self) -> bool;
|
||||||
|
|
||||||
fn get_local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName;
|
fn local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName;
|
||||||
|
|
||||||
/// Empty string for no namespace
|
/// Empty string for no namespace
|
||||||
fn get_namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl;
|
fn namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl;
|
||||||
|
|
||||||
fn attr_matches(&self,
|
fn attr_matches(
|
||||||
ns: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
|
&self,
|
||||||
local_name: &<Self::Impl as SelectorImpl>::LocalName,
|
ns: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
|
||||||
operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>)
|
local_name: &<Self::Impl as SelectorImpl>::LocalName,
|
||||||
-> bool;
|
operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>,
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class<F>(
|
fn match_non_ts_pseudo_class<F>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -92,15 +93,17 @@ pub trait Element: Sized + Clone + Debug {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_id(&self,
|
fn has_id(
|
||||||
id: &<Self::Impl as SelectorImpl>::Identifier,
|
&self,
|
||||||
case_sensitivity: CaseSensitivity)
|
id: &<Self::Impl as SelectorImpl>::Identifier,
|
||||||
-> bool;
|
case_sensitivity: CaseSensitivity,
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
fn has_class(&self,
|
fn has_class(
|
||||||
name: &<Self::Impl as SelectorImpl>::ClassName,
|
&self,
|
||||||
case_sensitivity: CaseSensitivity)
|
name: &<Self::Impl as SelectorImpl>::ClassName,
|
||||||
-> bool;
|
case_sensitivity: CaseSensitivity,
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
/// Returns whether this element matches `:empty`.
|
/// Returns whether this element matches `:empty`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -606,7 +606,6 @@ pub fn update_style_for_animation_frame(mut new_style: &mut Arc<ComputedValues>,
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
/// Updates a single animation and associated style based on the current time.
|
/// Updates a single animation and associated style based on the current time.
|
||||||
/// If `damage` is provided, inserts the appropriate restyle damage.
|
|
||||||
pub fn update_style_for_animation<E>(
|
pub fn update_style_for_animation<E>(
|
||||||
context: &SharedStyleContext,
|
context: &SharedStyleContext,
|
||||||
animation: &Animation,
|
animation: &Animation,
|
||||||
|
@ -796,8 +795,11 @@ where
|
||||||
|
|
||||||
/// Update the style in the node when it finishes.
|
/// Update the style in the node when it finishes.
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
pub fn complete_expired_transitions(node: OpaqueNode, style: &mut Arc<ComputedValues>,
|
pub fn complete_expired_transitions(
|
||||||
context: &SharedStyleContext) -> bool {
|
node: OpaqueNode,
|
||||||
|
style: &mut Arc<ComputedValues>,
|
||||||
|
context: &SharedStyleContext,
|
||||||
|
) -> bool {
|
||||||
let had_animations_to_expire;
|
let had_animations_to_expire;
|
||||||
{
|
{
|
||||||
let all_expired_animations = context.expired_animations.read();
|
let all_expired_animations = context.expired_animations.read();
|
||||||
|
|
|
@ -98,10 +98,10 @@ where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
F: FnMut(u32),
|
F: FnMut(u32),
|
||||||
{
|
{
|
||||||
f(element.get_local_name().get_hash());
|
f(element.local_name().get_hash());
|
||||||
f(element.get_namespace().get_hash());
|
f(element.namespace().get_hash());
|
||||||
|
|
||||||
if let Some(id) = element.get_id() {
|
if let Some(id) = element.id() {
|
||||||
f(id.get_hash());
|
f(id.get_hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -282,6 +282,7 @@ pub struct ElementCascadeInputs {
|
||||||
|
|
||||||
impl ElementCascadeInputs {
|
impl ElementCascadeInputs {
|
||||||
/// Construct inputs from previous cascade results, if any.
|
/// Construct inputs from previous cascade results, if any.
|
||||||
|
#[inline]
|
||||||
pub fn new_from_element_data(data: &ElementData) -> Self {
|
pub fn new_from_element_data(data: &ElementData) -> Self {
|
||||||
debug_assert!(data.has_styles());
|
debug_assert!(data.has_styles());
|
||||||
ElementCascadeInputs {
|
ElementCascadeInputs {
|
||||||
|
@ -383,8 +384,9 @@ impl fmt::Display for TraversalStatistics {
|
||||||
impl TraversalStatistics {
|
impl TraversalStatistics {
|
||||||
/// Computes the traversal time given the start time in seconds.
|
/// Computes the traversal time given the start time in seconds.
|
||||||
pub fn finish<E, D>(&mut self, traversal: &D, parallel: bool, start: f64)
|
pub fn finish<E, D>(&mut self, traversal: &D, parallel: bool, start: f64)
|
||||||
where E: TElement,
|
where
|
||||||
D: DomTraversal<E>,
|
E: TElement,
|
||||||
|
D: DomTraversal<E>,
|
||||||
{
|
{
|
||||||
let threshold = traversal.shared_context().options.style_statistics_threshold;
|
let threshold = traversal.shared_context().options.style_statistics_threshold;
|
||||||
let stylist = traversal.shared_context().stylist;
|
let stylist = traversal.shared_context().stylist;
|
||||||
|
@ -447,23 +449,27 @@ pub enum SequentialTask<E: TElement> {
|
||||||
/// Entry to avoid an unused type parameter error on servo.
|
/// Entry to avoid an unused type parameter error on servo.
|
||||||
Unused(SendElement<E>),
|
Unused(SendElement<E>),
|
||||||
|
|
||||||
/// Performs one of a number of possible tasks related to updating animations based on the
|
/// Performs one of a number of possible tasks related to updating
|
||||||
/// |tasks| field. These include updating CSS animations/transitions that changed as part
|
/// animations based on the |tasks| field. These include updating CSS
|
||||||
/// of the non-animation style traversal, and updating the computed effect properties.
|
/// animations/transitions that changed as part of the non-animation style
|
||||||
|
/// traversal, and updating the computed effect properties.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
UpdateAnimations {
|
UpdateAnimations {
|
||||||
/// The target element or pseudo-element.
|
/// The target element or pseudo-element.
|
||||||
el: SendElement<E>,
|
el: SendElement<E>,
|
||||||
/// The before-change style for transitions. We use before-change style as the initial
|
/// The before-change style for transitions. We use before-change style
|
||||||
/// value of its Keyframe. Required if |tasks| includes CSSTransitions.
|
/// as the initial value of its Keyframe. Required if |tasks| includes
|
||||||
|
/// CSSTransitions.
|
||||||
before_change_style: Option<Arc<ComputedValues>>,
|
before_change_style: Option<Arc<ComputedValues>>,
|
||||||
/// The tasks which are performed in this SequentialTask.
|
/// The tasks which are performed in this SequentialTask.
|
||||||
tasks: UpdateAnimationsTasks
|
tasks: UpdateAnimationsTasks
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Performs one of a number of possible tasks as a result of animation-only restyle.
|
/// Performs one of a number of possible tasks as a result of animation-only
|
||||||
/// Currently we do only process for resolving descendant elements that were display:none
|
/// restyle.
|
||||||
/// subtree for SMIL animation.
|
///
|
||||||
|
/// Currently we do only process for resolving descendant elements that were
|
||||||
|
/// display:none subtree for SMIL animation.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
PostAnimation {
|
PostAnimation {
|
||||||
/// The target element.
|
/// The target element.
|
||||||
|
@ -491,17 +497,19 @@ impl<E: TElement> SequentialTask<E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a task to update various animation-related state on
|
/// Creates a task to update various animation-related state on a given
|
||||||
/// a given (pseudo-)element.
|
/// (pseudo-)element.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub fn update_animations(el: E,
|
pub fn update_animations(
|
||||||
before_change_style: Option<Arc<ComputedValues>>,
|
el: E,
|
||||||
tasks: UpdateAnimationsTasks) -> Self {
|
before_change_style: Option<Arc<ComputedValues>>,
|
||||||
|
tasks: UpdateAnimationsTasks,
|
||||||
|
) -> Self {
|
||||||
use self::SequentialTask::*;
|
use self::SequentialTask::*;
|
||||||
UpdateAnimations {
|
UpdateAnimations {
|
||||||
el: unsafe { SendElement::new(el) },
|
el: unsafe { SendElement::new(el) },
|
||||||
before_change_style: before_change_style,
|
before_change_style,
|
||||||
tasks: tasks,
|
tasks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +520,7 @@ impl<E: TElement> SequentialTask<E> {
|
||||||
use self::SequentialTask::*;
|
use self::SequentialTask::*;
|
||||||
PostAnimation {
|
PostAnimation {
|
||||||
el: unsafe { SendElement::new(el) },
|
el: unsafe { SendElement::new(el) },
|
||||||
tasks: tasks,
|
tasks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use {Atom, Namespace, LocalName};
|
use {Atom, Namespace, LocalName, WeakAtom};
|
||||||
use applicable_declarations::ApplicableDeclarationBlock;
|
use applicable_declarations::ApplicableDeclarationBlock;
|
||||||
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
||||||
#[cfg(feature = "gecko")] use context::PostAnimationTasks;
|
#[cfg(feature = "gecko")] use context::PostAnimationTasks;
|
||||||
|
@ -17,9 +17,6 @@ use element_state::ElementState;
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::FontMetricsProvider;
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
|
use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
|
||||||
#[cfg(feature = "gecko")] use properties::LonghandId;
|
|
||||||
#[cfg(feature = "gecko")] use properties::animated_properties::AnimationValue;
|
|
||||||
use rule_tree::CascadeLevel;
|
|
||||||
use selector_parser::{AttrValue, PseudoClassStringArg, PseudoElement, SelectorImpl};
|
use selector_parser::{AttrValue, PseudoClassStringArg, PseudoElement, SelectorImpl};
|
||||||
use selectors::Element as SelectorsElement;
|
use selectors::Element as SelectorsElement;
|
||||||
use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode};
|
use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode};
|
||||||
|
@ -27,7 +24,6 @@ use selectors::sink::Push;
|
||||||
use servo_arc::{Arc, ArcBorrow};
|
use servo_arc::{Arc, ArcBorrow};
|
||||||
use shared_lock::Locked;
|
use shared_lock::Locked;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[cfg(feature = "gecko")] use hash::FnvHashMap;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -439,49 +435,39 @@ pub trait TElement
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get this element's SMIL override declarations.
|
/// Get this element's SMIL override declarations.
|
||||||
fn get_smil_override(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
|
fn smil_override(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get this element's animation rule by the cascade level.
|
|
||||||
fn get_animation_rule_by_cascade(&self,
|
|
||||||
_cascade_level: CascadeLevel)
|
|
||||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the combined animation and transition rules.
|
/// Get the combined animation and transition rules.
|
||||||
fn get_animation_rules(&self) -> AnimationRules {
|
///
|
||||||
|
/// FIXME(emilio): Is this really useful?
|
||||||
|
fn animation_rules(&self) -> AnimationRules {
|
||||||
if !self.may_have_animations() {
|
if !self.may_have_animations() {
|
||||||
return AnimationRules(None, None)
|
return AnimationRules(None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimationRules(
|
AnimationRules(self.animation_rule(), self.transition_rule())
|
||||||
self.get_animation_rule(),
|
|
||||||
self.get_transition_rule(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get this element's animation rule.
|
/// Get this element's animation rule.
|
||||||
fn get_animation_rule(&self)
|
fn animation_rule(&self) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get this element's transition rule.
|
/// Get this element's transition rule.
|
||||||
fn get_transition_rule(&self)
|
fn transition_rule(&self) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get this element's state, for non-tree-structural pseudos.
|
/// Get this element's state, for non-tree-structural pseudos.
|
||||||
fn get_state(&self) -> ElementState;
|
fn state(&self) -> ElementState;
|
||||||
|
|
||||||
/// Whether this element has an attribute with a given namespace.
|
/// Whether this element has an attribute with a given namespace.
|
||||||
fn has_attr(&self, namespace: &Namespace, attr: &LocalName) -> bool;
|
fn has_attr(&self, namespace: &Namespace, attr: &LocalName) -> bool;
|
||||||
|
|
||||||
/// The ID for this element.
|
/// The ID for this element.
|
||||||
fn get_id(&self) -> Option<Atom>;
|
fn id(&self) -> Option<&WeakAtom>;
|
||||||
|
|
||||||
/// Internal iterator for the classes of this element.
|
/// Internal iterator for the classes of this element.
|
||||||
fn each_class<F>(&self, callback: F) where F: FnMut(&Atom);
|
fn each_class<F>(&self, callback: F) where F: FnMut(&Atom);
|
||||||
|
@ -779,12 +765,6 @@ pub trait TElement
|
||||||
cut_off_inheritance
|
cut_off_inheritance
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the current existing CSS transitions, by |property, end value| pairs in a FnvHashMap.
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
fn get_css_transitions_info(
|
|
||||||
&self,
|
|
||||||
) -> FnvHashMap<LonghandId, Arc<AnimationValue>>;
|
|
||||||
|
|
||||||
/// Does a rough (and cheap) check for whether or not transitions might need to be updated that
|
/// Does a rough (and cheap) check for whether or not transitions might need to be updated that
|
||||||
/// will quickly return false for the common case of no transitions specified or running. If
|
/// will quickly return false for the common case of no transitions specified or running. If
|
||||||
/// this returns false, we definitely don't need to update transitions but if it returns true
|
/// this returns false, we definitely don't need to update transitions but if it returns true
|
||||||
|
@ -808,17 +788,6 @@ pub trait TElement
|
||||||
after_change_style: &ComputedValues
|
after_change_style: &ComputedValues
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
|
||||||
/// Returns true if we need to update transitions for the specified property on this element.
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
fn needs_transitions_update_per_property(
|
|
||||||
&self,
|
|
||||||
property: &LonghandId,
|
|
||||||
combined_duration: f32,
|
|
||||||
before_change_style: &ComputedValues,
|
|
||||||
after_change_style: &ComputedValues,
|
|
||||||
existing_transitions: &FnvHashMap<LonghandId, Arc<AnimationValue>>
|
|
||||||
) -> bool;
|
|
||||||
|
|
||||||
/// Returns the value of the `xml:lang=""` attribute (or, if appropriate,
|
/// Returns the value of the `xml:lang=""` attribute (or, if appropriate,
|
||||||
/// the `lang=""` attribute) on this element.
|
/// the `lang=""` attribute) on this element.
|
||||||
fn lang_attr(&self) -> Option<AttrValue>;
|
fn lang_attr(&self) -> Option<AttrValue>;
|
||||||
|
|
|
@ -349,9 +349,9 @@ where
|
||||||
Component::LocalName(LocalName { ref name, ref lower_name }) => {
|
Component::LocalName(LocalName { ref name, ref lower_name }) => {
|
||||||
collect_all_elements::<E, Q, _>(root, results, |element| {
|
collect_all_elements::<E, Q, _>(root, results, |element| {
|
||||||
if element.is_html_element_in_html_document() {
|
if element.is_html_element_in_html_document() {
|
||||||
element.get_local_name() == lower_name.borrow()
|
element.local_name() == lower_name.borrow()
|
||||||
} else {
|
} else {
|
||||||
element.get_local_name() == name.borrow()
|
element.local_name() == name.borrow()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
//! A gecko snapshot, that stores the element attributes and state before they
|
//! A gecko snapshot, that stores the element attributes and state before they
|
||||||
//! change in order to properly calculate restyle hints.
|
//! change in order to properly calculate restyle hints.
|
||||||
|
|
||||||
|
use WeakAtom;
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use gecko::snapshot_helpers;
|
use gecko::snapshot_helpers;
|
||||||
|
@ -80,17 +81,20 @@ impl GeckoElementSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// selectors::Element::attr_matches
|
/// selectors::Element::attr_matches
|
||||||
pub fn attr_matches(&self,
|
pub fn attr_matches(
|
||||||
ns: &NamespaceConstraint<&Namespace>,
|
&self,
|
||||||
local_name: &Atom,
|
ns: &NamespaceConstraint<&Namespace>,
|
||||||
operation: &AttrSelectorOperation<&Atom>)
|
local_name: &Atom,
|
||||||
-> bool {
|
operation: &AttrSelectorOperation<&Atom>,
|
||||||
|
) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
match *operation {
|
match *operation {
|
||||||
AttrSelectorOperation::Exists => {
|
AttrSelectorOperation::Exists => {
|
||||||
bindings:: Gecko_SnapshotHasAttr(self,
|
bindings:: Gecko_SnapshotHasAttr(
|
||||||
ns.atom_or_null(),
|
self,
|
||||||
local_name.as_ptr())
|
ns.atom_or_null(),
|
||||||
|
local_name.as_ptr(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
AttrSelectorOperation::WithValue { operator, case_sensitivity, expected_value } => {
|
AttrSelectorOperation::WithValue { operator, case_sensitivity, expected_value } => {
|
||||||
let ignore_case = match case_sensitivity {
|
let ignore_case = match case_sensitivity {
|
||||||
|
@ -163,7 +167,7 @@ impl ElementSnapshot for GeckoElementSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn id_attr(&self) -> Option<Atom> {
|
fn id_attr(&self) -> Option<&WeakAtom> {
|
||||||
if !self.has_any(Flags::Id) {
|
if !self.has_any(Flags::Id) {
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
|
@ -172,10 +176,11 @@ impl ElementSnapshot for GeckoElementSnapshot {
|
||||||
bindings::Gecko_SnapshotAtomAttrValue(self, atom!("id").as_ptr())
|
bindings::Gecko_SnapshotAtomAttrValue(self, atom!("id").as_ptr())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME(emilio): This should assert, since this flag is exact.
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(Atom::from(ptr))
|
Some(unsafe { WeakAtom::new(ptr) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,6 @@ use std::cell::RefCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::DerefMut;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||||
use stylist::CascadeData;
|
use stylist::CascadeData;
|
||||||
|
@ -226,7 +225,7 @@ impl<'ln> GeckoNode<'ln> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(parent) = parent_el {
|
if let Some(parent) = parent_el {
|
||||||
if parent.has_shadow_root() || parent.get_xbl_binding().is_some() {
|
if parent.shadow_root().is_some() || parent.xbl_binding().is_some() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,7 +419,7 @@ impl<'lb> GeckoXBLBinding<'lb> {
|
||||||
|
|
||||||
// This duplicates the logic in Gecko's
|
// This duplicates the logic in Gecko's
|
||||||
// nsBindingManager::GetBindingWithContent.
|
// nsBindingManager::GetBindingWithContent.
|
||||||
fn get_binding_with_content(&self) -> Option<Self> {
|
fn binding_with_content(&self) -> Option<Self> {
|
||||||
let mut binding = *self;
|
let mut binding = *self;
|
||||||
loop {
|
loop {
|
||||||
if !binding.anon_content().is_null() {
|
if !binding.anon_content().is_null() {
|
||||||
|
@ -455,8 +454,8 @@ pub struct GeckoElement<'le>(pub &'le RawGeckoElement);
|
||||||
|
|
||||||
impl<'le> fmt::Debug for GeckoElement<'le> {
|
impl<'le> fmt::Debug for GeckoElement<'le> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "<{}", self.get_local_name())?;
|
write!(f, "<{}", self.local_name())?;
|
||||||
if let Some(id) = self.get_id() {
|
if let Some(id) = self.id() {
|
||||||
write!(f, " id={}", id)?;
|
write!(f, " id={}", id)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,22 +518,23 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this element has a shadow root.
|
/// Returns true if this element has a shadow root.
|
||||||
fn has_shadow_root(&self) -> bool {
|
#[inline]
|
||||||
self.get_extended_slots()
|
fn shadow_root(&self) -> Option<&structs::ShadowRoot> {
|
||||||
.map_or(false, |slots| !slots.mShadowRoot.mRawPtr.is_null())
|
let slots = self.extended_slots()?;
|
||||||
|
unsafe { slots.mShadowRoot.mRawPtr.as_ref() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the DOM slots for this Element, if they exist.
|
/// Returns a reference to the DOM slots for this Element, if they exist.
|
||||||
fn get_dom_slots(&self) -> Option<&structs::FragmentOrElement_nsDOMSlots> {
|
fn dom_slots(&self) -> Option<&structs::FragmentOrElement_nsDOMSlots> {
|
||||||
let slots = self.as_node().0.mSlots as *const structs::FragmentOrElement_nsDOMSlots;
|
let slots = self.as_node().0.mSlots as *const structs::FragmentOrElement_nsDOMSlots;
|
||||||
unsafe { slots.as_ref() }
|
unsafe { slots.as_ref() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the extended DOM slots for this Element.
|
/// Returns a reference to the extended DOM slots for this Element.
|
||||||
fn get_extended_slots(
|
fn extended_slots(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<&structs::FragmentOrElement_nsExtendedDOMSlots> {
|
) -> Option<&structs::FragmentOrElement_nsExtendedDOMSlots> {
|
||||||
self.get_dom_slots().and_then(|s| unsafe {
|
self.dom_slots().and_then(|s| unsafe {
|
||||||
(s._base.mExtendedSlots.mPtr as *const structs::FragmentOrElement_nsExtendedDOMSlots).as_ref()
|
(s._base.mExtendedSlots.mPtr as *const structs::FragmentOrElement_nsExtendedDOMSlots).as_ref()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -545,7 +545,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_xbl_binding(&self) -> Option<GeckoXBLBinding<'le>> {
|
fn xbl_binding(&self) -> Option<GeckoXBLBinding<'le>> {
|
||||||
if !self.may_be_in_binding_manager() {
|
if !self.may_be_in_binding_manager() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -554,21 +554,20 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_xbl_binding_with_content(&self) -> Option<GeckoXBLBinding<'le>> {
|
fn xbl_binding_with_content(&self) -> Option<GeckoXBLBinding<'le>> {
|
||||||
self.get_xbl_binding()
|
self.xbl_binding().and_then(|b| b.binding_with_content())
|
||||||
.and_then(|b| b.get_binding_with_content())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn has_xbl_binding_with_content(&self) -> bool {
|
fn has_xbl_binding_with_content(&self) -> bool {
|
||||||
!self.get_xbl_binding_with_content().is_none()
|
!self.xbl_binding_with_content().is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This and has_xbl_binding_parent duplicate the logic in Gecko's virtual
|
/// This and has_xbl_binding_parent duplicate the logic in Gecko's virtual
|
||||||
/// nsINode::GetBindingParent function, which only has two implementations:
|
/// nsINode::GetBindingParent function, which only has two implementations:
|
||||||
/// one for XUL elements, and one for other elements. We just hard code in
|
/// one for XUL elements, and one for other elements. We just hard code in
|
||||||
/// our knowledge of those two implementations here.
|
/// our knowledge of those two implementations here.
|
||||||
fn get_xbl_binding_parent(&self) -> Option<Self> {
|
fn xbl_binding_parent(&self) -> Option<Self> {
|
||||||
if self.is_xul_element() {
|
if self.is_xul_element() {
|
||||||
// FIXME(heycam): Having trouble with bindgen on nsXULElement,
|
// FIXME(heycam): Having trouble with bindgen on nsXULElement,
|
||||||
// where the binding parent is stored in a member variable
|
// where the binding parent is stored in a member variable
|
||||||
|
@ -578,7 +577,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let binding_parent = unsafe {
|
let binding_parent = unsafe {
|
||||||
self.get_non_xul_xbl_binding_parent_raw_content().as_ref()
|
self.non_xul_xbl_binding_parent_raw_content().as_ref()
|
||||||
}.map(GeckoNode::from_content).and_then(|n| n.as_element());
|
}.map(GeckoNode::from_content).and_then(|n| n.as_element());
|
||||||
|
|
||||||
debug_assert!(binding_parent == unsafe {
|
debug_assert!(binding_parent == unsafe {
|
||||||
|
@ -588,9 +587,9 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_non_xul_xbl_binding_parent_raw_content(&self) -> *mut nsIContent {
|
fn non_xul_xbl_binding_parent_raw_content(&self) -> *mut nsIContent {
|
||||||
debug_assert!(!self.is_xul_element());
|
debug_assert!(!self.is_xul_element());
|
||||||
self.get_extended_slots()
|
self.extended_slots()
|
||||||
.map_or(ptr::null_mut(), |slots| slots._base.mBindingParent)
|
.map_or(ptr::null_mut(), |slots| slots._base.mBindingParent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,7 +600,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
// rather than in slots. So just get it through FFI for now.
|
// rather than in slots. So just get it through FFI for now.
|
||||||
unsafe { bindings::Gecko_GetBindingParent(self.0).is_some() }
|
unsafe { bindings::Gecko_GetBindingParent(self.0).is_some() }
|
||||||
} else {
|
} else {
|
||||||
!self.get_non_xul_xbl_binding_parent_raw_content().is_null()
|
!self.non_xul_xbl_binding_parent_raw_content().is_null()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,36 +614,13 @@ impl<'le> GeckoElement<'le> {
|
||||||
self.namespace_id() == (structs::root::kNameSpaceID_XUL as i32)
|
self.namespace_id() == (structs::root::kNameSpaceID_XUL as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the specified element data, return any existing data.
|
|
||||||
///
|
|
||||||
/// Like `ensure_data`, only safe to call with exclusive access to the
|
|
||||||
/// element.
|
|
||||||
pub unsafe fn set_data(&self, replace_data: Option<ElementData>) -> Option<ElementData> {
|
|
||||||
match (self.get_data(), replace_data) {
|
|
||||||
(Some(old), Some(replace_data)) => {
|
|
||||||
Some(mem::replace(old.borrow_mut().deref_mut(), replace_data))
|
|
||||||
}
|
|
||||||
(Some(old), None) => {
|
|
||||||
let old_data = mem::replace(old.borrow_mut().deref_mut(), ElementData::default());
|
|
||||||
self.0.mServoData.set(ptr::null_mut());
|
|
||||||
Some(old_data)
|
|
||||||
}
|
|
||||||
(None, Some(replace_data)) => {
|
|
||||||
let ptr = Box::into_raw(Box::new(AtomicRefCell::new(replace_data)));
|
|
||||||
self.0.mServoData.set(ptr);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
(None, None) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn has_id(&self) -> bool {
|
fn has_id(&self) -> bool {
|
||||||
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasID)
|
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasID)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_state_internal(&self) -> u64 {
|
fn state_internal(&self) -> u64 {
|
||||||
if !self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasLockedStyleStates) {
|
if !self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasLockedStyleStates) {
|
||||||
return self.0.mState.mStates;
|
return self.0.mState.mStates;
|
||||||
}
|
}
|
||||||
|
@ -660,8 +636,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn may_have_class(&self) -> bool {
|
fn may_have_class(&self) -> bool {
|
||||||
self.as_node()
|
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementMayHaveClass)
|
||||||
.get_bool_flag(nsINode_BooleanFlag::ElementMayHaveClass)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -672,7 +647,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_before_or_after_pseudo(&self, is_before: bool) -> Option<Self> {
|
fn before_or_after_pseudo(&self, is_before: bool) -> Option<Self> {
|
||||||
if !self.has_properties() {
|
if !self.has_properties() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -682,12 +657,11 @@ impl<'le> GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn may_have_style_attribute(&self) -> bool {
|
fn may_have_style_attribute(&self) -> bool {
|
||||||
self.as_node()
|
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementMayHaveStyle)
|
||||||
.get_bool_flag(nsINode_BooleanFlag::ElementMayHaveStyle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_document_theme(&self) -> DocumentTheme {
|
fn document_theme(&self) -> DocumentTheme {
|
||||||
let node = self.as_node();
|
let node = self.as_node();
|
||||||
unsafe { Gecko_GetDocumentLWTheme(node.owner_doc().0) }
|
unsafe { Gecko_GetDocumentLWTheme(node.owner_doc().0) }
|
||||||
}
|
}
|
||||||
|
@ -771,6 +745,76 @@ impl<'le> GeckoElement<'le> {
|
||||||
self.is_in_native_anonymous_subtree() ||
|
self.is_in_native_anonymous_subtree() ||
|
||||||
(!self.is_in_shadow_tree() && self.has_xbl_binding_parent())
|
(!self.is_in_shadow_tree() && self.has_xbl_binding_parent())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn css_transitions_info(&self) -> FnvHashMap<LonghandId, Arc<AnimationValue>> {
|
||||||
|
use gecko_bindings::bindings::Gecko_ElementTransitions_EndValueAt;
|
||||||
|
use gecko_bindings::bindings::Gecko_ElementTransitions_Length;
|
||||||
|
|
||||||
|
let collection_length =
|
||||||
|
unsafe { Gecko_ElementTransitions_Length(self.0) } as usize;
|
||||||
|
let mut map = FnvHashMap::with_capacity_and_hasher(
|
||||||
|
collection_length,
|
||||||
|
Default::default()
|
||||||
|
);
|
||||||
|
|
||||||
|
for i in 0..collection_length {
|
||||||
|
let raw_end_value = unsafe {
|
||||||
|
Gecko_ElementTransitions_EndValueAt(self.0, i)
|
||||||
|
};
|
||||||
|
|
||||||
|
let end_value = AnimationValue::arc_from_borrowed(&raw_end_value)
|
||||||
|
.expect("AnimationValue not found in ElementTransitions");
|
||||||
|
|
||||||
|
let property = end_value.id();
|
||||||
|
map.insert(property, end_value.clone_arc());
|
||||||
|
}
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
|
fn needs_transitions_update_per_property(
|
||||||
|
&self,
|
||||||
|
longhand_id: &LonghandId,
|
||||||
|
combined_duration: f32,
|
||||||
|
before_change_style: &ComputedValues,
|
||||||
|
after_change_style: &ComputedValues,
|
||||||
|
existing_transitions: &FnvHashMap<LonghandId, Arc<AnimationValue>>,
|
||||||
|
) -> bool {
|
||||||
|
use values::animated::{Animate, Procedure};
|
||||||
|
|
||||||
|
// If there is an existing transition, update only if the end value
|
||||||
|
// differs.
|
||||||
|
//
|
||||||
|
// If the end value has not changed, we should leave the currently
|
||||||
|
// running transition as-is since we don't want to interrupt its timing
|
||||||
|
// function.
|
||||||
|
if let Some(ref existing) = existing_transitions.get(longhand_id) {
|
||||||
|
let after_value =
|
||||||
|
AnimationValue::from_computed_values(
|
||||||
|
longhand_id,
|
||||||
|
after_change_style
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
return ***existing != after_value
|
||||||
|
}
|
||||||
|
|
||||||
|
let from = AnimationValue::from_computed_values(
|
||||||
|
&longhand_id,
|
||||||
|
before_change_style,
|
||||||
|
);
|
||||||
|
let to = AnimationValue::from_computed_values(
|
||||||
|
&longhand_id,
|
||||||
|
after_change_style,
|
||||||
|
);
|
||||||
|
|
||||||
|
debug_assert_eq!(to.is_some(), from.is_some());
|
||||||
|
|
||||||
|
combined_duration > 0.0f32 &&
|
||||||
|
from != to &&
|
||||||
|
from.unwrap().animate(
|
||||||
|
to.as_ref().unwrap(),
|
||||||
|
Procedure::Interpolate { progress: 0.5 }
|
||||||
|
).is_ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts flags from the layout used by rust-selectors to the layout used
|
/// Converts flags from the layout used by rust-selectors to the layout used
|
||||||
|
@ -928,11 +972,11 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn before_pseudo_element(&self) -> Option<Self> {
|
fn before_pseudo_element(&self) -> Option<Self> {
|
||||||
self.get_before_or_after_pseudo(/* is_before = */ true)
|
self.before_or_after_pseudo(/* is_before = */ true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn after_pseudo_element(&self) -> Option<Self> {
|
fn after_pseudo_element(&self) -> Option<Self> {
|
||||||
self.get_before_or_after_pseudo(/* is_before = */ false)
|
self.before_or_after_pseudo(/* is_before = */ false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure this accurately represents the rules that an element may ever
|
/// Ensure this accurately represents the rules that an element may ever
|
||||||
|
@ -946,11 +990,11 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
return self.as_node().owner_doc().as_node();
|
return self.as_node().owner_doc().as_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.get_xbl_binding().is_some() {
|
if self.xbl_binding().is_some() {
|
||||||
return self.as_node();
|
return self.as_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(parent) = self.get_xbl_binding_parent() {
|
if let Some(parent) = self.xbl_binding_parent() {
|
||||||
return parent.as_node();
|
return parent.as_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1059,9 +1103,9 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
unsafe { Gecko_UnsetDirtyStyleAttr(self.0) };
|
unsafe { Gecko_UnsetDirtyStyleAttr(self.0) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_smil_override(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
|
fn smil_override(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let slots = self.get_extended_slots()?;
|
let slots = self.extended_slots()?;
|
||||||
|
|
||||||
let base_declaration: &structs::DeclarationBlock =
|
let base_declaration: &structs::DeclarationBlock =
|
||||||
slots.mSMILOverrideStyleDeclaration.mRawPtr.as_ref()?;
|
slots.mSMILOverrideStyleDeclaration.mRawPtr.as_ref()?;
|
||||||
|
@ -1083,32 +1127,17 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_animation_rule_by_cascade(
|
fn animation_rule(&self) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
&self,
|
|
||||||
cascade_level: ServoCascadeLevel,
|
|
||||||
) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
|
||||||
match cascade_level {
|
|
||||||
ServoCascadeLevel::Animations => self.get_animation_rule(),
|
|
||||||
ServoCascadeLevel::Transitions => self.get_transition_rule(),
|
|
||||||
_ => panic!("Unsupported cascade level for getting the animation rule")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_animation_rule(
|
|
||||||
&self,
|
|
||||||
) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
|
||||||
get_animation_rule(self, CascadeLevel::Animations)
|
get_animation_rule(self, CascadeLevel::Animations)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_transition_rule(
|
fn transition_rule(&self) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
&self,
|
|
||||||
) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
|
||||||
get_animation_rule(self, CascadeLevel::Transitions)
|
get_animation_rule(self, CascadeLevel::Transitions)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_state(&self) -> ElementState {
|
fn state(&self) -> ElementState {
|
||||||
ElementState::from_bits_truncate(self.get_state_internal())
|
ElementState::from_bits_truncate(self.state_internal())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1118,7 +1147,9 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_id(&self) -> Option<Atom> {
|
// FIXME(emilio): we should probably just return a reference to the Atom.
|
||||||
|
#[inline]
|
||||||
|
fn id(&self) -> Option<&WeakAtom> {
|
||||||
if !self.has_id() {
|
if !self.has_id() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -1127,10 +1158,12 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
bindings::Gecko_AtomAttrValue(self.0, atom!("id").as_ptr())
|
bindings::Gecko_AtomAttrValue(self.0, atom!("id").as_ptr())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME(emilio): Pretty sure the has_id flag is exact and we could
|
||||||
|
// assert here.
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(Atom::from(ptr))
|
Some(unsafe { WeakAtom::new(ptr) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1203,7 +1236,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_visited_link(&self) -> bool {
|
fn is_visited_link(&self) -> bool {
|
||||||
self.get_state().intersects(ElementState::IN_VISITED_STATE)
|
self.state().intersects(ElementState::IN_VISITED_STATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1296,10 +1329,10 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
if !pseudo.is_before_or_after() {
|
if !pseudo.is_before_or_after() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return self.parent_element()
|
// FIXME(emilio): When would the parent of a ::before / ::after
|
||||||
.map_or(false, |p| {
|
// pseudo-element be null?
|
||||||
p.as_node()
|
return self.parent_element().map_or(false, |p| {
|
||||||
.get_bool_flag(nsINode_BooleanFlag::ElementHasAnimations)
|
p.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasAnimations)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasAnimations)
|
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasAnimations)
|
||||||
|
@ -1377,7 +1410,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
let mut current = Some(self.rule_hash_target());
|
let mut current = Some(self.rule_hash_target());
|
||||||
|
|
||||||
while let Some(element) = current {
|
while let Some(element) = current {
|
||||||
if let Some(binding) = element.get_xbl_binding() {
|
if let Some(binding) = element.xbl_binding() {
|
||||||
binding.each_xbl_cascade_data(&mut f);
|
binding.each_xbl_cascade_data(&mut f);
|
||||||
|
|
||||||
// If we're not looking at our original element, allow the
|
// If we're not looking at our original element, allow the
|
||||||
|
@ -1396,7 +1429,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
current = element.get_xbl_binding_parent();
|
current = element.xbl_binding_parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If current has something, this means we cut off inheritance at some
|
// If current has something, this means we cut off inheritance at some
|
||||||
|
@ -1405,37 +1438,10 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xbl_binding_anonymous_content(&self) -> Option<GeckoNode<'le>> {
|
fn xbl_binding_anonymous_content(&self) -> Option<GeckoNode<'le>> {
|
||||||
self.get_xbl_binding_with_content()
|
self.xbl_binding_with_content()
|
||||||
.map(|b| unsafe { GeckoNode::from_content(&*b.anon_content()) })
|
.map(|b| unsafe { GeckoNode::from_content(&*b.anon_content()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_css_transitions_info(
|
|
||||||
&self,
|
|
||||||
) -> FnvHashMap<LonghandId, Arc<AnimationValue>> {
|
|
||||||
use gecko_bindings::bindings::Gecko_ElementTransitions_EndValueAt;
|
|
||||||
use gecko_bindings::bindings::Gecko_ElementTransitions_Length;
|
|
||||||
|
|
||||||
let collection_length =
|
|
||||||
unsafe { Gecko_ElementTransitions_Length(self.0) } as usize;
|
|
||||||
let mut map = FnvHashMap::with_capacity_and_hasher(
|
|
||||||
collection_length,
|
|
||||||
Default::default()
|
|
||||||
);
|
|
||||||
|
|
||||||
for i in 0..collection_length {
|
|
||||||
let raw_end_value = unsafe {
|
|
||||||
Gecko_ElementTransitions_EndValueAt(self.0, i)
|
|
||||||
};
|
|
||||||
|
|
||||||
let end_value = AnimationValue::arc_from_borrowed(&raw_end_value)
|
|
||||||
.expect("AnimationValue not found in ElementTransitions");
|
|
||||||
|
|
||||||
let property = end_value.id();
|
|
||||||
map.insert(property, end_value.clone_arc());
|
|
||||||
}
|
|
||||||
map
|
|
||||||
}
|
|
||||||
|
|
||||||
fn might_need_transitions_update(
|
fn might_need_transitions_update(
|
||||||
&self,
|
&self,
|
||||||
old_values: Option<&ComputedValues>,
|
old_values: Option<&ComputedValues>,
|
||||||
|
@ -1473,7 +1479,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
fn needs_transitions_update(
|
fn needs_transitions_update(
|
||||||
&self,
|
&self,
|
||||||
before_change_style: &ComputedValues,
|
before_change_style: &ComputedValues,
|
||||||
after_change_style: &ComputedValues
|
after_change_style: &ComputedValues,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
use gecko_bindings::structs::nsCSSPropertyID;
|
use gecko_bindings::structs::nsCSSPropertyID;
|
||||||
use properties::LonghandIdSet;
|
use properties::LonghandIdSet;
|
||||||
|
@ -1485,7 +1491,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
|
|
||||||
let after_change_box_style = after_change_style.get_box();
|
let after_change_box_style = after_change_style.get_box();
|
||||||
let transitions_count = after_change_box_style.transition_property_count();
|
let transitions_count = after_change_box_style.transition_property_count();
|
||||||
let existing_transitions = self.get_css_transitions_info();
|
let existing_transitions = self.css_transitions_info();
|
||||||
|
|
||||||
// Check if this property is none, custom or unknown.
|
// Check if this property is none, custom or unknown.
|
||||||
let is_none_or_custom_property = |property: nsCSSPropertyID| -> bool {
|
let is_none_or_custom_property = |property: nsCSSPropertyID| -> bool {
|
||||||
|
@ -1545,51 +1551,6 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn needs_transitions_update_per_property(
|
|
||||||
&self,
|
|
||||||
longhand_id: &LonghandId,
|
|
||||||
combined_duration: f32,
|
|
||||||
before_change_style: &ComputedValues,
|
|
||||||
after_change_style: &ComputedValues,
|
|
||||||
existing_transitions: &FnvHashMap<LonghandId, Arc<AnimationValue>>,
|
|
||||||
) -> bool {
|
|
||||||
use values::animated::{Animate, Procedure};
|
|
||||||
|
|
||||||
// If there is an existing transition, update only if the end value
|
|
||||||
// differs.
|
|
||||||
//
|
|
||||||
// If the end value has not changed, we should leave the currently
|
|
||||||
// running transition as-is since we don't want to interrupt its timing
|
|
||||||
// function.
|
|
||||||
if let Some(ref existing) = existing_transitions.get(longhand_id) {
|
|
||||||
let after_value =
|
|
||||||
AnimationValue::from_computed_values(
|
|
||||||
longhand_id,
|
|
||||||
after_change_style
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
return ***existing != after_value
|
|
||||||
}
|
|
||||||
|
|
||||||
let from = AnimationValue::from_computed_values(
|
|
||||||
&longhand_id,
|
|
||||||
before_change_style,
|
|
||||||
);
|
|
||||||
let to = AnimationValue::from_computed_values(
|
|
||||||
&longhand_id,
|
|
||||||
after_change_style,
|
|
||||||
);
|
|
||||||
|
|
||||||
debug_assert_eq!(to.is_some(), from.is_some());
|
|
||||||
|
|
||||||
combined_duration > 0.0f32 &&
|
|
||||||
from != to &&
|
|
||||||
from.unwrap().animate(
|
|
||||||
to.as_ref().unwrap(),
|
|
||||||
Procedure::Interpolate { progress: 0.5 }
|
|
||||||
).is_ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn lang_attr(&self) -> Option<AttrValue> {
|
fn lang_attr(&self) -> Option<AttrValue> {
|
||||||
let ptr = unsafe { bindings::Gecko_LangValue(self.0) };
|
let ptr = unsafe { bindings::Gecko_LangValue(self.0) };
|
||||||
|
@ -1620,7 +1581,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_html_document_body_element(&self) -> bool {
|
fn is_html_document_body_element(&self) -> bool {
|
||||||
if self.get_local_name() != &*local_name!("body") {
|
if self.local_name() != &*local_name!("body") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1686,15 +1647,15 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
let ns = self.namespace_id();
|
let ns = self.namespace_id();
|
||||||
// <th> elements get a default MozCenterOrInherit which may get overridden
|
// <th> elements get a default MozCenterOrInherit which may get overridden
|
||||||
if ns == structs::kNameSpaceID_XHTML as i32 {
|
if ns == structs::kNameSpaceID_XHTML as i32 {
|
||||||
if self.get_local_name().as_ptr() == atom!("th").as_ptr() {
|
if self.local_name().as_ptr() == atom!("th").as_ptr() {
|
||||||
hints.push(TH_RULE.clone());
|
hints.push(TH_RULE.clone());
|
||||||
} else if self.get_local_name().as_ptr() == atom!("table").as_ptr() &&
|
} else if self.local_name().as_ptr() == atom!("table").as_ptr() &&
|
||||||
self.as_node().owner_doc().quirks_mode() == QuirksMode::Quirks {
|
self.as_node().owner_doc().quirks_mode() == QuirksMode::Quirks {
|
||||||
hints.push(TABLE_COLOR_RULE.clone());
|
hints.push(TABLE_COLOR_RULE.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ns == structs::kNameSpaceID_SVG as i32 {
|
if ns == structs::kNameSpaceID_SVG as i32 {
|
||||||
if self.get_local_name().as_ptr() == atom!("text").as_ptr() {
|
if self.local_name().as_ptr() == atom!("text").as_ptr() {
|
||||||
hints.push(SVG_TEXT_DISABLE_ZOOM_RULE.clone());
|
hints.push(SVG_TEXT_DISABLE_ZOOM_RULE.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1739,7 +1700,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let active = self.get_state().intersects(NonTSPseudoClass::Active.state_flag());
|
let active = self.state().intersects(NonTSPseudoClass::Active.state_flag());
|
||||||
if active {
|
if active {
|
||||||
let declarations = unsafe { Gecko_GetActiveLinkAttrDeclarationBlock(self.0) };
|
let declarations = unsafe { Gecko_GetActiveLinkAttrDeclarationBlock(self.0) };
|
||||||
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||||
|
@ -1771,7 +1732,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
// MathML's default lang has precedence over both `lang` and `xml:lang`
|
// MathML's default lang has precedence over both `lang` and `xml:lang`
|
||||||
if ns == structs::kNameSpaceID_MathML as i32 {
|
if ns == structs::kNameSpaceID_MathML as i32 {
|
||||||
if self.get_local_name().as_ptr() == atom!("math").as_ptr() {
|
if self.local_name().as_ptr() == atom!("math").as_ptr() {
|
||||||
hints.push(MATHML_LANG_RULE.clone());
|
hints.push(MATHML_LANG_RULE.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1818,7 +1779,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn assigned_slot(&self) -> Option<Self> {
|
fn assigned_slot(&self) -> Option<Self> {
|
||||||
let slot = self.get_extended_slots()?._base.mAssignedSlot.mRawPtr;
|
let slot = self.extended_slots()?._base.mAssignedSlot.mRawPtr;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
Some(GeckoElement(&slot.as_ref()?._base._base._base._base))
|
Some(GeckoElement(&slot.as_ref()?._base._base._base._base))
|
||||||
|
@ -1964,14 +1925,14 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_local_name(&self) -> &WeakAtom {
|
fn local_name(&self) -> &WeakAtom {
|
||||||
unsafe {
|
unsafe {
|
||||||
WeakAtom::new(self.as_node().node_info().mInner.mName)
|
WeakAtom::new(self.as_node().node_info().mInner.mName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_namespace(&self) -> &WeakNamespace {
|
fn namespace(&self) -> &WeakNamespace {
|
||||||
unsafe {
|
unsafe {
|
||||||
let namespace_manager = structs::nsContentUtils_sNameSpaceManager;
|
let namespace_manager = structs::nsContentUtils_sNameSpaceManager;
|
||||||
WeakNamespace::new((*namespace_manager).mURIArray[self.namespace_id() as usize].mRawPtr)
|
WeakNamespace::new((*namespace_manager).mURIArray[self.namespace_id() as usize].mRawPtr)
|
||||||
|
@ -2037,7 +1998,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
NonTSPseudoClass::Active |
|
NonTSPseudoClass::Active |
|
||||||
NonTSPseudoClass::Hover |
|
NonTSPseudoClass::Hover |
|
||||||
NonTSPseudoClass::MozAutofillPreview => {
|
NonTSPseudoClass::MozAutofillPreview => {
|
||||||
self.get_state().intersects(pseudo_class.state_flag())
|
self.state().intersects(pseudo_class.state_flag())
|
||||||
},
|
},
|
||||||
NonTSPseudoClass::AnyLink => self.is_link(),
|
NonTSPseudoClass::AnyLink => self.is_link(),
|
||||||
NonTSPseudoClass::Link => {
|
NonTSPseudoClass::Link => {
|
||||||
|
@ -2085,13 +2046,13 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
self.is_html_element_in_html_document()
|
self.is_html_element_in_html_document()
|
||||||
}
|
}
|
||||||
NonTSPseudoClass::MozLWTheme => {
|
NonTSPseudoClass::MozLWTheme => {
|
||||||
self.get_document_theme() != DocumentTheme::Doc_Theme_None
|
self.document_theme() != DocumentTheme::Doc_Theme_None
|
||||||
}
|
}
|
||||||
NonTSPseudoClass::MozLWThemeBrightText => {
|
NonTSPseudoClass::MozLWThemeBrightText => {
|
||||||
self.get_document_theme() == DocumentTheme::Doc_Theme_Bright
|
self.document_theme() == DocumentTheme::Doc_Theme_Bright
|
||||||
}
|
}
|
||||||
NonTSPseudoClass::MozLWThemeDarkText => {
|
NonTSPseudoClass::MozLWThemeDarkText => {
|
||||||
self.get_document_theme() == DocumentTheme::Doc_Theme_Dark
|
self.document_theme() == DocumentTheme::Doc_Theme_Dark
|
||||||
}
|
}
|
||||||
NonTSPseudoClass::MozWindowInactive => {
|
NonTSPseudoClass::MozWindowInactive => {
|
||||||
let state_bit = DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE;
|
let state_bit = DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE;
|
||||||
|
@ -2130,8 +2091,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
NonTSPseudoClass::Dir(ref dir) => {
|
NonTSPseudoClass::Dir(ref dir) => {
|
||||||
match **dir {
|
match **dir {
|
||||||
Direction::Ltr => self.get_state().intersects(ElementState::IN_LTR_STATE),
|
Direction::Ltr => self.state().intersects(ElementState::IN_LTR_STATE),
|
||||||
Direction::Rtl => self.get_state().intersects(ElementState::IN_RTL_STATE),
|
Direction::Rtl => self.state().intersects(ElementState::IN_RTL_STATE),
|
||||||
Direction::Other(..) => false,
|
Direction::Other(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2154,7 +2115,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_link(&self) -> bool {
|
fn is_link(&self) -> bool {
|
||||||
self.get_state().intersects(NonTSPseudoClass::AnyLink.state_flag())
|
self.state().intersects(NonTSPseudoClass::AnyLink.state_flag())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -2197,7 +2158,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_html_slot_element(&self) -> bool {
|
fn is_html_slot_element(&self) -> bool {
|
||||||
self.is_html_element() &&
|
self.is_html_element() &&
|
||||||
self.get_local_name().as_ptr() == local_name!("slot").as_ptr()
|
self.local_name().as_ptr() == local_name!("slot").as_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -2216,8 +2177,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
// If this element is the shadow root of an use-element shadow
|
// If this element is the shadow root of an use-element shadow
|
||||||
// tree, according to the spec, we should not match rules
|
// tree, according to the spec, we should not match rules
|
||||||
// cross the shadow DOM boundary.
|
// cross the shadow DOM boundary.
|
||||||
e.get_local_name() == &*local_name!("use") &&
|
e.local_name() == &*local_name!("use") &&
|
||||||
e.get_namespace() == &*ns!("http://www.w3.org/2000/svg")
|
e.namespace() == &*ns!("http://www.w3.org/2000/svg")
|
||||||
},
|
},
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! A wrapper over an element and a snapshot, that allows us to selector-match
|
//! A wrapper over an element and a snapshot, that allows us to selector-match
|
||||||
//! against a past state of the element.
|
//! against a past state of the element.
|
||||||
|
|
||||||
use {Atom, CaseSensitivityExt, LocalName, Namespace};
|
use {Atom, CaseSensitivityExt, LocalName, Namespace, WeakAtom};
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
|
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
|
||||||
|
@ -44,7 +44,7 @@ pub trait ElementSnapshot : Sized {
|
||||||
|
|
||||||
/// The ID attribute per this snapshot. Should only be called if
|
/// The ID attribute per this snapshot. Should only be called if
|
||||||
/// `has_attrs()` returns true.
|
/// `has_attrs()` returns true.
|
||||||
fn id_attr(&self) -> Option<Atom>;
|
fn id_attr(&self) -> Option<&WeakAtom>;
|
||||||
|
|
||||||
/// Whether this snapshot contains the class `name`. Should only be called
|
/// Whether this snapshot contains the class `name`. Should only be called
|
||||||
/// if `has_attrs()` returns true.
|
/// if `has_attrs()` returns true.
|
||||||
|
@ -53,7 +53,8 @@ pub trait ElementSnapshot : Sized {
|
||||||
/// A callback that should be called for each class of the snapshot. Should
|
/// A callback that should be called for each class of the snapshot. Should
|
||||||
/// only be called if `has_attrs()` returns true.
|
/// only be called if `has_attrs()` returns true.
|
||||||
fn each_class<F>(&self, F)
|
fn each_class<F>(&self, F)
|
||||||
where F: FnMut(&Atom);
|
where
|
||||||
|
F: FnMut(&Atom);
|
||||||
|
|
||||||
/// The `xml:lang=""` or `lang=""` attribute value per this snapshot.
|
/// The `xml:lang=""` or `lang=""` attribute value per this snapshot.
|
||||||
fn lang_attr(&self) -> Option<AttrValue>;
|
fn lang_attr(&self) -> Option<AttrValue>;
|
||||||
|
@ -63,7 +64,8 @@ pub trait ElementSnapshot : Sized {
|
||||||
/// selector-match against a past state of the element.
|
/// selector-match against a past state of the element.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ElementWrapper<'a, E>
|
pub struct ElementWrapper<'a, E>
|
||||||
where E: TElement,
|
where
|
||||||
|
E: TElement,
|
||||||
{
|
{
|
||||||
element: E,
|
element: E,
|
||||||
cached_snapshot: Cell<Option<&'a Snapshot>>,
|
cached_snapshot: Cell<Option<&'a Snapshot>>,
|
||||||
|
@ -109,7 +111,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
match snapshot.state() {
|
match snapshot.state() {
|
||||||
Some(state) => state ^ self.element.get_state(),
|
Some(state) => state ^ self.element.state(),
|
||||||
None => ElementState::empty(),
|
None => ElementState::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +135,8 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E> fmt::Debug for ElementWrapper<'a, E>
|
impl<'a, E> fmt::Debug for ElementWrapper<'a, E>
|
||||||
where E: TElement,
|
where
|
||||||
|
E: TElement,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
// Ignore other fields for now, can change later if needed.
|
// Ignore other fields for now, can change later if needed.
|
||||||
|
@ -142,7 +145,8 @@ impl<'a, E> fmt::Debug for ElementWrapper<'a, E>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E> Element for ElementWrapper<'a, E>
|
impl<'a, E> Element for ElementWrapper<'a, E>
|
||||||
where E: TElement,
|
where
|
||||||
|
E: TElement,
|
||||||
{
|
{
|
||||||
type Impl = SelectorImpl;
|
type Impl = SelectorImpl;
|
||||||
|
|
||||||
|
@ -186,7 +190,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
||||||
}
|
}
|
||||||
let state = match self.snapshot().and_then(|s| s.state()) {
|
let state = match self.snapshot().and_then(|s| s.state()) {
|
||||||
Some(snapshot_state) => snapshot_state,
|
Some(snapshot_state) => snapshot_state,
|
||||||
None => self.element.get_state(),
|
None => self.element.state(),
|
||||||
};
|
};
|
||||||
return state.contains(selector_flag);
|
return state.contains(selector_flag);
|
||||||
}
|
}
|
||||||
|
@ -291,27 +295,32 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
||||||
.map(|e| ElementWrapper::new(e, self.snapshot_map))
|
.map(|e| ElementWrapper::new(e, self.snapshot_map))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn is_html_element_in_html_document(&self) -> bool {
|
fn is_html_element_in_html_document(&self) -> bool {
|
||||||
self.element.is_html_element_in_html_document()
|
self.element.is_html_element_in_html_document()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn is_html_slot_element(&self) -> bool {
|
fn is_html_slot_element(&self) -> bool {
|
||||||
self.element.is_html_slot_element()
|
self.element.is_html_slot_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_local_name(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName {
|
#[inline]
|
||||||
self.element.get_local_name()
|
fn local_name(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName {
|
||||||
|
self.element.local_name()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_namespace(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl {
|
#[inline]
|
||||||
self.element.get_namespace()
|
fn namespace(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl {
|
||||||
|
self.element.namespace()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attr_matches(&self,
|
fn attr_matches(
|
||||||
ns: &NamespaceConstraint<&Namespace>,
|
&self,
|
||||||
local_name: &LocalName,
|
ns: &NamespaceConstraint<&Namespace>,
|
||||||
operation: &AttrSelectorOperation<&AttrValue>)
|
local_name: &LocalName,
|
||||||
-> bool {
|
operation: &AttrSelectorOperation<&AttrValue>,
|
||||||
|
) -> bool {
|
||||||
match self.snapshot() {
|
match self.snapshot() {
|
||||||
Some(snapshot) if snapshot.has_attrs() => {
|
Some(snapshot) if snapshot.has_attrs() => {
|
||||||
snapshot.attr_matches(ns, local_name, operation)
|
snapshot.attr_matches(ns, local_name, operation)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! An invalidation processor for style changes due to state and attribute
|
//! An invalidation processor for style changes due to state and attribute
|
||||||
//! changes.
|
//! changes.
|
||||||
|
|
||||||
use Atom;
|
use {Atom, WeakAtom};
|
||||||
use context::{QuirksMode, SharedStyleContext};
|
use context::{QuirksMode, SharedStyleContext};
|
||||||
use data::ElementData;
|
use data::ElementData;
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
|
@ -42,8 +42,8 @@ where
|
||||||
snapshot: &'a Snapshot,
|
snapshot: &'a Snapshot,
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
lookup_element: E,
|
lookup_element: E,
|
||||||
removed_id: Option<&'a Atom>,
|
removed_id: Option<&'a WeakAtom>,
|
||||||
added_id: Option<&'a Atom>,
|
added_id: Option<&'a WeakAtom>,
|
||||||
classes_removed: &'a SmallVec<[Atom; 8]>,
|
classes_removed: &'a SmallVec<[Atom; 8]>,
|
||||||
classes_added: &'a SmallVec<[Atom; 8]>,
|
classes_added: &'a SmallVec<[Atom; 8]>,
|
||||||
state_changes: ElementState,
|
state_changes: ElementState,
|
||||||
|
@ -200,7 +200,7 @@ where
|
||||||
let mut id_added = None;
|
let mut id_added = None;
|
||||||
if snapshot.id_changed() {
|
if snapshot.id_changed() {
|
||||||
let old_id = snapshot.id_attr();
|
let old_id = snapshot.id_attr();
|
||||||
let current_id = element.get_id();
|
let current_id = element.id();
|
||||||
|
|
||||||
if old_id != current_id {
|
if old_id != current_id {
|
||||||
id_removed = old_id;
|
id_removed = old_id;
|
||||||
|
@ -239,8 +239,8 @@ where
|
||||||
snapshot: &snapshot,
|
snapshot: &snapshot,
|
||||||
quirks_mode: self.shared_context.quirks_mode(),
|
quirks_mode: self.shared_context.quirks_mode(),
|
||||||
nth_index_cache: self.matching_context.nth_index_cache.as_mut().map(|c| &mut **c),
|
nth_index_cache: self.matching_context.nth_index_cache.as_mut().map(|c| &mut **c),
|
||||||
removed_id: id_removed.as_ref(),
|
removed_id: id_removed,
|
||||||
added_id: id_added.as_ref(),
|
added_id: id_added,
|
||||||
classes_removed: &classes_removed,
|
classes_removed: &classes_removed,
|
||||||
classes_added: &classes_added,
|
classes_added: &classes_added,
|
||||||
descendant_invalidations,
|
descendant_invalidations,
|
||||||
|
|
|
@ -66,7 +66,7 @@ impl Invalidation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Invalidation::ID(ref id) => {
|
Invalidation::ID(ref id) => {
|
||||||
if let Some(ref element_id) = element.get_id() {
|
if let Some(ref element_id) = element.id() {
|
||||||
if case_sensitivity.eq_atom(element_id, id) {
|
if case_sensitivity.eq_atom(element_id, id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ impl Invalidation {
|
||||||
// This could look at the quirks mode of the document, instead
|
// This could look at the quirks mode of the document, instead
|
||||||
// of testing against both names, but it's probably not worth
|
// of testing against both names, but it's probably not worth
|
||||||
// it.
|
// it.
|
||||||
let local_name = element.get_local_name();
|
let local_name = element.local_name();
|
||||||
return *local_name == **name || *local_name == **lower_name
|
return *local_name == **name || *local_name == **lower_name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl ChildCascadeRequirement {
|
||||||
|
|
||||||
/// Determines which styles are being cascaded currently.
|
/// Determines which styles are being cascaded currently.
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum CascadeVisitedMode {
|
enum CascadeVisitedMode {
|
||||||
/// Cascade the regular, unvisited styles.
|
/// Cascade the regular, unvisited styles.
|
||||||
Unvisited,
|
Unvisited,
|
||||||
/// Cascade the styles used when an element's relevant link is visited. A
|
/// Cascade the styles used when an element's relevant link is visited. A
|
||||||
|
@ -81,18 +81,115 @@ pub enum CascadeVisitedMode {
|
||||||
Visited,
|
Visited,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CascadeVisitedMode {
|
|
||||||
/// Returns whether the cascade should filter to only visited dependent
|
|
||||||
/// properties based on the cascade mode.
|
|
||||||
pub fn visited_dependent_only(&self) -> bool {
|
|
||||||
*self == CascadeVisitedMode::Visited
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait PrivateMatchMethods: TElement {
|
trait PrivateMatchMethods: TElement {
|
||||||
|
/// Updates the rule nodes without re-running selector matching, using just
|
||||||
|
/// the rule tree, for a specific visited mode.
|
||||||
|
///
|
||||||
|
/// Returns true if an !important rule was replaced.
|
||||||
|
fn replace_rules_internal(
|
||||||
|
&self,
|
||||||
|
replacements: RestyleHint,
|
||||||
|
context: &mut StyleContext<Self>,
|
||||||
|
cascade_visited: CascadeVisitedMode,
|
||||||
|
cascade_inputs: &mut ElementCascadeInputs,
|
||||||
|
) -> bool {
|
||||||
|
use properties::PropertyDeclarationBlock;
|
||||||
|
use shared_lock::Locked;
|
||||||
|
|
||||||
|
debug_assert!(replacements.intersects(RestyleHint::replacements()) &&
|
||||||
|
(replacements & !RestyleHint::replacements()).is_empty());
|
||||||
|
|
||||||
|
let stylist = &context.shared.stylist;
|
||||||
|
let guards = &context.shared.guards;
|
||||||
|
|
||||||
|
let primary_rules =
|
||||||
|
match cascade_visited {
|
||||||
|
CascadeVisitedMode::Unvisited => cascade_inputs.primary.rules.as_mut(),
|
||||||
|
CascadeVisitedMode::Visited => cascade_inputs.primary.visited_rules.as_mut(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let primary_rules = match primary_rules {
|
||||||
|
Some(r) => r,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let replace_rule_node = |level: CascadeLevel,
|
||||||
|
pdb: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
|
||||||
|
path: &mut StrongRuleNode| -> bool {
|
||||||
|
let mut important_rules_changed = false;
|
||||||
|
let new_node =
|
||||||
|
stylist.rule_tree().update_rule_at_level(
|
||||||
|
level,
|
||||||
|
pdb,
|
||||||
|
path,
|
||||||
|
guards,
|
||||||
|
&mut important_rules_changed,
|
||||||
|
);
|
||||||
|
if let Some(n) = new_node {
|
||||||
|
*path = n;
|
||||||
|
}
|
||||||
|
important_rules_changed
|
||||||
|
};
|
||||||
|
|
||||||
|
if !context.shared.traversal_flags.for_animation_only() {
|
||||||
|
let mut result = false;
|
||||||
|
if replacements.contains(RestyleHint::RESTYLE_STYLE_ATTRIBUTE) {
|
||||||
|
let style_attribute = self.style_attribute();
|
||||||
|
result |= replace_rule_node(
|
||||||
|
CascadeLevel::StyleAttributeNormal,
|
||||||
|
style_attribute,
|
||||||
|
primary_rules,
|
||||||
|
);
|
||||||
|
result |= replace_rule_node(
|
||||||
|
CascadeLevel::StyleAttributeImportant,
|
||||||
|
style_attribute,
|
||||||
|
primary_rules,
|
||||||
|
);
|
||||||
|
// FIXME(emilio): Still a hack!
|
||||||
|
self.unset_dirty_style_attribute();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Animation restyle hints are processed prior to other restyle
|
||||||
|
// hints in the animation-only traversal.
|
||||||
|
//
|
||||||
|
// Non-animation restyle hints will be processed in a subsequent
|
||||||
|
// normal traversal.
|
||||||
|
if replacements.intersects(RestyleHint::for_animations()) {
|
||||||
|
debug_assert!(context.shared.traversal_flags.for_animation_only());
|
||||||
|
|
||||||
|
if replacements.contains(RestyleHint::RESTYLE_SMIL) {
|
||||||
|
replace_rule_node(
|
||||||
|
CascadeLevel::SMILOverride,
|
||||||
|
self.smil_override(),
|
||||||
|
primary_rules,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if replacements.contains(RestyleHint::RESTYLE_CSS_TRANSITIONS) {
|
||||||
|
replace_rule_node(
|
||||||
|
CascadeLevel::Transitions,
|
||||||
|
self.transition_rule().as_ref().map(|a| a.borrow_arc()),
|
||||||
|
primary_rules,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if replacements.contains(RestyleHint::RESTYLE_CSS_ANIMATIONS) {
|
||||||
|
replace_rule_node(
|
||||||
|
CascadeLevel::Animations,
|
||||||
|
self.animation_rule().as_ref().map(|a| a.borrow_arc()),
|
||||||
|
primary_rules,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// If there is no transition rule in the ComputedValues, it returns None.
|
/// If there is no transition rule in the ComputedValues, it returns None.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
fn get_after_change_style(
|
fn after_change_style(
|
||||||
&self,
|
&self,
|
||||||
context: &mut StyleContext<Self>,
|
context: &mut StyleContext<Self>,
|
||||||
primary_style: &Arc<ComputedValues>
|
primary_style: &Arc<ComputedValues>
|
||||||
|
@ -130,34 +227,54 @@ trait PrivateMatchMethods: TElement {
|
||||||
fn needs_animations_update(
|
fn needs_animations_update(
|
||||||
&self,
|
&self,
|
||||||
context: &mut StyleContext<Self>,
|
context: &mut StyleContext<Self>,
|
||||||
old_values: Option<&Arc<ComputedValues>>,
|
old_values: Option<&ComputedValues>,
|
||||||
new_values: &ComputedValues,
|
new_values: &ComputedValues,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let new_box_style = new_values.get_box();
|
let new_box_style = new_values.get_box();
|
||||||
let has_new_animation_style = new_box_style.specifies_animations();
|
let has_new_animation_style = new_box_style.specifies_animations();
|
||||||
let has_animations = self.has_css_animations();
|
|
||||||
|
|
||||||
old_values.map_or(has_new_animation_style, |old| {
|
let old = match old_values {
|
||||||
let old_box_style = old.get_box();
|
Some(old) => old,
|
||||||
let old_display_style = old_box_style.clone_display();
|
None => return has_new_animation_style,
|
||||||
let new_display_style = new_box_style.clone_display();
|
};
|
||||||
|
|
||||||
// If the traverse is triggered by CSS rule changes, we need to
|
let old_box_style = old.get_box();
|
||||||
// try to update all CSS animations on the element if the element
|
|
||||||
// has or will have CSS animation style regardless of whether the
|
let keyframes_could_have_changed =
|
||||||
// animation is running or not.
|
context.shared.traversal_flags.contains(TraversalFlags::ForCSSRuleChanges);
|
||||||
// TODO: We should check which @keyframes changed/added/deleted
|
|
||||||
// and update only animations corresponding to those @keyframes.
|
// If the traversal is triggered due to changes in CSS rules changes, we
|
||||||
(context.shared.traversal_flags.contains(TraversalFlags::ForCSSRuleChanges) &&
|
// need to try to update all CSS animations on the element if the
|
||||||
(has_new_animation_style || has_animations)) ||
|
// element has or will have CSS animation style regardless of whether
|
||||||
!old_box_style.animations_equals(new_box_style) ||
|
// the animation is running or not.
|
||||||
(old_display_style == Display::None &&
|
//
|
||||||
new_display_style != Display::None &&
|
// TODO: We should check which @keyframes were added/changed/deleted and
|
||||||
has_new_animation_style) ||
|
// update only animations corresponding to those @keyframes.
|
||||||
(old_display_style != Display::None &&
|
if keyframes_could_have_changed &&
|
||||||
new_display_style == Display::None &&
|
(has_new_animation_style || self.has_css_animations())
|
||||||
has_animations)
|
{
|
||||||
})
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the animations changed, well...
|
||||||
|
if !old_box_style.animations_equals(new_box_style) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let old_display = old_box_style.clone_display();
|
||||||
|
let new_display = new_box_style.clone_display();
|
||||||
|
|
||||||
|
// If we were display: none, we may need to trigger animations.
|
||||||
|
if old_display == Display::None && new_display != Display::None {
|
||||||
|
return has_new_animation_style;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are becoming display: none, we may need to stop animations.
|
||||||
|
if old_display != Display::None && new_display == Display::None {
|
||||||
|
return self.has_css_animations();
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a SequentialTask for resolving descendants in a SMIL display property
|
/// Create a SequentialTask for resolving descendants in a SMIL display property
|
||||||
|
@ -192,12 +309,14 @@ trait PrivateMatchMethods: TElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
fn process_animations(&self,
|
fn process_animations(
|
||||||
context: &mut StyleContext<Self>,
|
&self,
|
||||||
old_values: &mut Option<Arc<ComputedValues>>,
|
context: &mut StyleContext<Self>,
|
||||||
new_values: &mut Arc<ComputedValues>,
|
old_values: &mut Option<Arc<ComputedValues>>,
|
||||||
restyle_hint: RestyleHint,
|
new_values: &mut Arc<ComputedValues>,
|
||||||
important_rules_changed: bool) {
|
restyle_hint: RestyleHint,
|
||||||
|
important_rules_changed: bool,
|
||||||
|
) {
|
||||||
use context::UpdateAnimationsTasks;
|
use context::UpdateAnimationsTasks;
|
||||||
|
|
||||||
if context.shared.traversal_flags.for_animation_only() {
|
if context.shared.traversal_flags.for_animation_only() {
|
||||||
|
@ -214,14 +333,14 @@ trait PrivateMatchMethods: TElement {
|
||||||
// in addition to the unvisited styles.
|
// in addition to the unvisited styles.
|
||||||
|
|
||||||
let mut tasks = UpdateAnimationsTasks::empty();
|
let mut tasks = UpdateAnimationsTasks::empty();
|
||||||
if self.needs_animations_update(context, old_values.as_ref(), new_values) {
|
if self.needs_animations_update(context, old_values.as_ref().map(|s| &**s), new_values) {
|
||||||
tasks.insert(UpdateAnimationsTasks::CSS_ANIMATIONS);
|
tasks.insert(UpdateAnimationsTasks::CSS_ANIMATIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
let before_change_style = if self.might_need_transitions_update(old_values.as_ref().map(|s| &**s),
|
let before_change_style = if self.might_need_transitions_update(old_values.as_ref().map(|s| &**s),
|
||||||
new_values) {
|
new_values) {
|
||||||
let after_change_style = if self.has_css_transitions() {
|
let after_change_style = if self.has_css_transitions() {
|
||||||
self.get_after_change_style(context, new_values)
|
self.after_change_style(context, new_values)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -235,8 +354,10 @@ trait PrivateMatchMethods: TElement {
|
||||||
let after_change_style_ref =
|
let after_change_style_ref =
|
||||||
after_change_style.as_ref().unwrap_or(&new_values);
|
after_change_style.as_ref().unwrap_or(&new_values);
|
||||||
|
|
||||||
self.needs_transitions_update(old_values.as_ref().unwrap(),
|
self.needs_transitions_update(
|
||||||
after_change_style_ref)
|
old_values.as_ref().unwrap(),
|
||||||
|
after_change_style_ref,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
if needs_transitions_update {
|
if needs_transitions_update {
|
||||||
|
@ -245,7 +366,8 @@ trait PrivateMatchMethods: TElement {
|
||||||
}
|
}
|
||||||
tasks.insert(UpdateAnimationsTasks::CSS_TRANSITIONS);
|
tasks.insert(UpdateAnimationsTasks::CSS_TRANSITIONS);
|
||||||
|
|
||||||
// We need to clone old_values into SequentialTask, so we can use it later.
|
// We need to clone old_values into SequentialTask, so we can
|
||||||
|
// use it later.
|
||||||
old_values.clone()
|
old_values.clone()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -273,29 +395,38 @@ trait PrivateMatchMethods: TElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
fn process_animations(&self,
|
fn process_animations(
|
||||||
context: &mut StyleContext<Self>,
|
&self,
|
||||||
old_values: &mut Option<Arc<ComputedValues>>,
|
context: &mut StyleContext<Self>,
|
||||||
new_values: &mut Arc<ComputedValues>,
|
old_values: &mut Option<Arc<ComputedValues>>,
|
||||||
_restyle_hint: RestyleHint,
|
new_values: &mut Arc<ComputedValues>,
|
||||||
_important_rules_changed: bool) {
|
_restyle_hint: RestyleHint,
|
||||||
|
_important_rules_changed: bool,
|
||||||
|
) {
|
||||||
use animation;
|
use animation;
|
||||||
use dom::TNode;
|
use dom::TNode;
|
||||||
|
|
||||||
let mut possibly_expired_animations = vec![];
|
let mut possibly_expired_animations = vec![];
|
||||||
let shared_context = context.shared;
|
let shared_context = context.shared;
|
||||||
if let Some(ref mut old) = *old_values {
|
if let Some(ref mut old) = *old_values {
|
||||||
self.update_animations_for_cascade(shared_context, old,
|
// FIXME(emilio, #20116): This makes no sense.
|
||||||
&mut possibly_expired_animations,
|
self.update_animations_for_cascade(
|
||||||
&context.thread_local.font_metrics_provider);
|
shared_context,
|
||||||
|
old,
|
||||||
|
&mut possibly_expired_animations,
|
||||||
|
&context.thread_local.font_metrics_provider,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_animations_sender = &context.thread_local.new_animations_sender;
|
let new_animations_sender = &context.thread_local.new_animations_sender;
|
||||||
let this_opaque = self.as_node().opaque();
|
let this_opaque = self.as_node().opaque();
|
||||||
// Trigger any present animations if necessary.
|
// Trigger any present animations if necessary.
|
||||||
animation::maybe_start_animations(&shared_context,
|
animation::maybe_start_animations(
|
||||||
new_animations_sender,
|
&shared_context,
|
||||||
this_opaque, &new_values);
|
new_animations_sender,
|
||||||
|
this_opaque,
|
||||||
|
&new_values,
|
||||||
|
);
|
||||||
|
|
||||||
// Trigger transitions if necessary. This will reset `new_values` back
|
// Trigger transitions if necessary. This will reset `new_values` back
|
||||||
// to its old value if it did trigger a transition.
|
// to its old value if it did trigger a transition.
|
||||||
|
@ -303,10 +434,11 @@ trait PrivateMatchMethods: TElement {
|
||||||
animation::start_transitions_if_applicable(
|
animation::start_transitions_if_applicable(
|
||||||
new_animations_sender,
|
new_animations_sender,
|
||||||
this_opaque,
|
this_opaque,
|
||||||
&**values,
|
&values,
|
||||||
new_values,
|
new_values,
|
||||||
&shared_context.timer,
|
&shared_context.timer,
|
||||||
&possibly_expired_animations);
|
&possibly_expired_animations,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,12 +555,20 @@ trait PrivateMatchMethods: TElement {
|
||||||
ChildCascadeRequirement::MustCascadeChildrenIfInheritResetStyle
|
ChildCascadeRequirement::MustCascadeChildrenIfInheritResetStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(emilio, #20116): It's not clear to me that the name of this method
|
||||||
|
// represents anything of what it does.
|
||||||
|
//
|
||||||
|
// Also, this function gets the old style, for some reason I don't really
|
||||||
|
// get, but the functions called (mainly update_style_for_animation) expects
|
||||||
|
// the new style, wtf?
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
fn update_animations_for_cascade(&self,
|
fn update_animations_for_cascade(
|
||||||
context: &SharedStyleContext,
|
&self,
|
||||||
style: &mut Arc<ComputedValues>,
|
context: &SharedStyleContext,
|
||||||
possibly_expired_animations: &mut Vec<::animation::PropertyAnimation>,
|
style: &mut Arc<ComputedValues>,
|
||||||
font_metrics: &::font_metrics::FontMetricsProvider) {
|
possibly_expired_animations: &mut Vec<::animation::PropertyAnimation>,
|
||||||
|
font_metrics: &::font_metrics::FontMetricsProvider,
|
||||||
|
) {
|
||||||
use animation::{self, Animation};
|
use animation::{self, Animation};
|
||||||
use dom::TNode;
|
use dom::TNode;
|
||||||
|
|
||||||
|
@ -436,36 +576,38 @@ trait PrivateMatchMethods: TElement {
|
||||||
let this_opaque = self.as_node().opaque();
|
let this_opaque = self.as_node().opaque();
|
||||||
animation::complete_expired_transitions(this_opaque, style, context);
|
animation::complete_expired_transitions(this_opaque, style, context);
|
||||||
|
|
||||||
// Merge any running transitions into the current style, and cancel them.
|
// Merge any running animations into the current style, and cancel them.
|
||||||
let had_running_animations = context.running_animations
|
let had_running_animations =
|
||||||
.read()
|
context.running_animations.read().get(&this_opaque).is_some();
|
||||||
.get(&this_opaque)
|
if !had_running_animations {
|
||||||
.is_some();
|
return;
|
||||||
if had_running_animations {
|
}
|
||||||
let mut all_running_animations = context.running_animations.write();
|
|
||||||
for running_animation in all_running_animations.get_mut(&this_opaque).unwrap() {
|
let mut all_running_animations = context.running_animations.write();
|
||||||
// This shouldn't happen frequently, but under some
|
for running_animation in all_running_animations.get_mut(&this_opaque).unwrap() {
|
||||||
// circumstances mainly huge load or debug builds, the
|
// This shouldn't happen frequently, but under some circumstances
|
||||||
// constellation might be delayed in sending the
|
// mainly huge load or debug builds, the constellation might be
|
||||||
// `TickAllAnimations` message to layout.
|
// delayed in sending the `TickAllAnimations` message to layout.
|
||||||
//
|
//
|
||||||
// Thus, we can't assume all the animations have been already
|
// Thus, we can't assume all the animations have been already
|
||||||
// updated by layout, because other restyle due to script might
|
// updated by layout, because other restyle due to script might be
|
||||||
// be triggered by layout before the animation tick.
|
// triggered by layout before the animation tick.
|
||||||
//
|
//
|
||||||
// See #12171 and the associated PR for an example where this
|
// See #12171 and the associated PR for an example where this
|
||||||
// happened while debugging other release panic.
|
// happened while debugging other release panic.
|
||||||
if !running_animation.is_expired() {
|
if running_animation.is_expired() {
|
||||||
animation::update_style_for_animation::<Self>(
|
continue;
|
||||||
context,
|
}
|
||||||
running_animation,
|
|
||||||
style,
|
animation::update_style_for_animation::<Self>(
|
||||||
font_metrics,
|
context,
|
||||||
);
|
running_animation,
|
||||||
if let Animation::Transition(_, _, ref frame, _) = *running_animation {
|
style,
|
||||||
possibly_expired_animations.push(frame.property_animation.clone())
|
font_metrics,
|
||||||
}
|
);
|
||||||
}
|
|
||||||
|
if let Animation::Transition(_, _, ref frame, _) = *running_animation {
|
||||||
|
possibly_expired_animations.push(frame.property_animation.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -484,7 +626,7 @@ pub trait MatchMethods : TElement {
|
||||||
/// Returns itself if the element has no parent. In practice this doesn't
|
/// Returns itself if the element has no parent. In practice this doesn't
|
||||||
/// happen because the root element is blockified per spec, but it could
|
/// happen because the root element is blockified per spec, but it could
|
||||||
/// happen if we decide to not blockify for roots of disconnected subtrees,
|
/// happen if we decide to not blockify for roots of disconnected subtrees,
|
||||||
/// which is a kind of dubious beahavior.
|
/// which is a kind of dubious behavior.
|
||||||
fn layout_parent(&self) -> Self {
|
fn layout_parent(&self) -> Self {
|
||||||
let mut current = self.clone();
|
let mut current = self.clone();
|
||||||
loop {
|
loop {
|
||||||
|
@ -608,11 +750,9 @@ pub trait MatchMethods : TElement {
|
||||||
// case.
|
// case.
|
||||||
let pseudo = PseudoElement::from_eager_index(i);
|
let pseudo = PseudoElement::from_eager_index(i);
|
||||||
let new_pseudo_should_exist =
|
let new_pseudo_should_exist =
|
||||||
new.as_ref().map_or(false,
|
new.as_ref().map_or(false, |s| pseudo.should_exist(s));
|
||||||
|s| pseudo.should_exist(s));
|
|
||||||
let old_pseudo_should_exist =
|
let old_pseudo_should_exist =
|
||||||
old.as_ref().map_or(false,
|
old.as_ref().map_or(false, |s| pseudo.should_exist(s));
|
||||||
|s| pseudo.should_exist(s));
|
|
||||||
if new_pseudo_should_exist != old_pseudo_should_exist {
|
if new_pseudo_should_exist != old_pseudo_should_exist {
|
||||||
data.damage |= RestyleDamage::reconstruct();
|
data.damage |= RestyleDamage::reconstruct();
|
||||||
return cascade_requirement;
|
return cascade_requirement;
|
||||||
|
@ -630,10 +770,12 @@ pub trait MatchMethods : TElement {
|
||||||
///
|
///
|
||||||
/// TODO(emilio): This is somewhat inefficient, because it doesn't take
|
/// TODO(emilio): This is somewhat inefficient, because it doesn't take
|
||||||
/// advantage of us knowing that the traversal is sequential.
|
/// advantage of us knowing that the traversal is sequential.
|
||||||
fn apply_selector_flags(&self,
|
fn apply_selector_flags(
|
||||||
map: &mut SelectorFlagsMap<Self>,
|
&self,
|
||||||
element: &Self,
|
map: &mut SelectorFlagsMap<Self>,
|
||||||
flags: ElementSelectorFlags) {
|
element: &Self,
|
||||||
|
flags: ElementSelectorFlags,
|
||||||
|
) {
|
||||||
// Handle flags that apply to the element.
|
// Handle flags that apply to the element.
|
||||||
let self_flags = flags.for_self();
|
let self_flags = flags.for_self();
|
||||||
if !self_flags.is_empty() {
|
if !self_flags.is_empty() {
|
||||||
|
@ -692,107 +834,6 @@ pub trait MatchMethods : TElement {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the rule nodes without re-running selector matching, using just
|
|
||||||
/// the rule tree, for a specific visited mode.
|
|
||||||
///
|
|
||||||
/// Returns true if an !important rule was replaced.
|
|
||||||
fn replace_rules_internal(
|
|
||||||
&self,
|
|
||||||
replacements: RestyleHint,
|
|
||||||
context: &mut StyleContext<Self>,
|
|
||||||
cascade_visited: CascadeVisitedMode,
|
|
||||||
cascade_inputs: &mut ElementCascadeInputs,
|
|
||||||
) -> bool {
|
|
||||||
use properties::PropertyDeclarationBlock;
|
|
||||||
use shared_lock::Locked;
|
|
||||||
|
|
||||||
debug_assert!(replacements.intersects(RestyleHint::replacements()) &&
|
|
||||||
(replacements & !RestyleHint::replacements()).is_empty());
|
|
||||||
|
|
||||||
let stylist = &context.shared.stylist;
|
|
||||||
let guards = &context.shared.guards;
|
|
||||||
|
|
||||||
let primary_rules =
|
|
||||||
match cascade_visited {
|
|
||||||
CascadeVisitedMode::Unvisited => cascade_inputs.primary.rules.as_mut(),
|
|
||||||
CascadeVisitedMode::Visited => cascade_inputs.primary.visited_rules.as_mut(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let primary_rules = match primary_rules {
|
|
||||||
Some(r) => r,
|
|
||||||
None => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let replace_rule_node = |level: CascadeLevel,
|
|
||||||
pdb: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
|
|
||||||
path: &mut StrongRuleNode| -> bool {
|
|
||||||
let mut important_rules_changed = false;
|
|
||||||
let new_node = stylist.rule_tree()
|
|
||||||
.update_rule_at_level(level,
|
|
||||||
pdb,
|
|
||||||
path,
|
|
||||||
guards,
|
|
||||||
&mut important_rules_changed);
|
|
||||||
if let Some(n) = new_node {
|
|
||||||
*path = n;
|
|
||||||
}
|
|
||||||
important_rules_changed
|
|
||||||
};
|
|
||||||
|
|
||||||
if !context.shared.traversal_flags.for_animation_only() {
|
|
||||||
let mut result = false;
|
|
||||||
if replacements.contains(RestyleHint::RESTYLE_STYLE_ATTRIBUTE) {
|
|
||||||
let style_attribute = self.style_attribute();
|
|
||||||
result |= replace_rule_node(CascadeLevel::StyleAttributeNormal,
|
|
||||||
style_attribute,
|
|
||||||
primary_rules);
|
|
||||||
result |= replace_rule_node(CascadeLevel::StyleAttributeImportant,
|
|
||||||
style_attribute,
|
|
||||||
primary_rules);
|
|
||||||
// FIXME(emilio): Still a hack!
|
|
||||||
self.unset_dirty_style_attribute();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Animation restyle hints are processed prior to other restyle
|
|
||||||
// hints in the animation-only traversal.
|
|
||||||
//
|
|
||||||
// Non-animation restyle hints will be processed in a subsequent
|
|
||||||
// normal traversal.
|
|
||||||
if replacements.intersects(RestyleHint::for_animations()) {
|
|
||||||
debug_assert!(context.shared.traversal_flags.for_animation_only());
|
|
||||||
|
|
||||||
if replacements.contains(RestyleHint::RESTYLE_SMIL) {
|
|
||||||
replace_rule_node(CascadeLevel::SMILOverride,
|
|
||||||
self.get_smil_override(),
|
|
||||||
primary_rules);
|
|
||||||
}
|
|
||||||
|
|
||||||
let replace_rule_node_for_animation = |level: CascadeLevel,
|
|
||||||
primary_rules: &mut StrongRuleNode| {
|
|
||||||
let animation_rule = self.get_animation_rule_by_cascade(level);
|
|
||||||
replace_rule_node(level,
|
|
||||||
animation_rule.as_ref().map(|a| a.borrow_arc()),
|
|
||||||
primary_rules);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Apply Transition rules and Animation rules if the corresponding restyle hint
|
|
||||||
// is contained.
|
|
||||||
if replacements.contains(RestyleHint::RESTYLE_CSS_TRANSITIONS) {
|
|
||||||
replace_rule_node_for_animation(CascadeLevel::Transitions,
|
|
||||||
primary_rules);
|
|
||||||
}
|
|
||||||
|
|
||||||
if replacements.contains(RestyleHint::RESTYLE_CSS_ANIMATIONS) {
|
|
||||||
replace_rule_node_for_animation(CascadeLevel::Animations,
|
|
||||||
primary_rules);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given the old and new style of this element, and whether it's a
|
/// Given the old and new style of this element, and whether it's a
|
||||||
/// pseudo-element, compute the restyle damage used to determine which
|
/// pseudo-element, compute the restyle damage used to determine which
|
||||||
/// kind of layout or painting operations we'll need.
|
/// kind of layout or painting operations we'll need.
|
||||||
|
|
|
@ -77,9 +77,11 @@ type WorkUnit<N> = ArrayVec<[SendNode<N>; WORK_UNIT_MAX]>;
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn create_thread_local_context<'scope, E, D>(
|
fn create_thread_local_context<'scope, E, D>(
|
||||||
traversal: &'scope D,
|
traversal: &'scope D,
|
||||||
slot: &mut Option<ThreadLocalStyleContext<E>>)
|
slot: &mut Option<ThreadLocalStyleContext<E>>,
|
||||||
where E: TElement + 'scope,
|
)
|
||||||
D: DomTraversal<E>
|
where
|
||||||
|
E: TElement + 'scope,
|
||||||
|
D: DomTraversal<E>,
|
||||||
{
|
{
|
||||||
*slot = Some(ThreadLocalStyleContext::new(traversal.shared_context()));
|
*slot = Some(ThreadLocalStyleContext::new(traversal.shared_context()));
|
||||||
}
|
}
|
||||||
|
@ -99,15 +101,18 @@ fn create_thread_local_context<'scope, E, D>(
|
||||||
/// a thread-local cache to share styles between siblings.
|
/// a thread-local cache to share styles between siblings.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
|
fn top_down_dom<'a, 'scope, E, D>(
|
||||||
root: OpaqueNode,
|
nodes: &'a [SendNode<E::ConcreteNode>],
|
||||||
mut traversal_data: PerLevelTraversalData,
|
root: OpaqueNode,
|
||||||
scope: &'a rayon::Scope<'scope>,
|
mut traversal_data: PerLevelTraversalData,
|
||||||
pool: &'scope rayon::ThreadPool,
|
scope: &'a rayon::Scope<'scope>,
|
||||||
traversal: &'scope D,
|
pool: &'scope rayon::ThreadPool,
|
||||||
tls: &'scope ScopedTLS<'scope, ThreadLocalStyleContext<E>>)
|
traversal: &'scope D,
|
||||||
where E: TElement + 'scope,
|
tls: &'scope ScopedTLS<'scope, ThreadLocalStyleContext<E>>,
|
||||||
D: DomTraversal<E>,
|
)
|
||||||
|
where
|
||||||
|
E: TElement + 'scope,
|
||||||
|
D: DomTraversal<E>,
|
||||||
{
|
{
|
||||||
debug_assert!(nodes.len() <= WORK_UNIT_MAX);
|
debug_assert!(nodes.len() <= WORK_UNIT_MAX);
|
||||||
|
|
||||||
|
|
|
@ -1096,14 +1096,16 @@ impl StrongRuleNode {
|
||||||
/// Returns true if any properties specified by `rule_type_mask` was set by
|
/// Returns true if any properties specified by `rule_type_mask` was set by
|
||||||
/// an author rule.
|
/// an author rule.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub fn has_author_specified_rules<E>(&self,
|
pub fn has_author_specified_rules<E>(
|
||||||
mut element: E,
|
&self,
|
||||||
mut pseudo: Option<PseudoElement>,
|
mut element: E,
|
||||||
guards: &StylesheetGuards,
|
mut pseudo: Option<PseudoElement>,
|
||||||
rule_type_mask: u32,
|
guards: &StylesheetGuards,
|
||||||
author_colors_allowed: bool)
|
rule_type_mask: u32,
|
||||||
-> bool
|
author_colors_allowed: bool,
|
||||||
where E: ::dom::TElement
|
) -> bool
|
||||||
|
where
|
||||||
|
E: ::dom::TElement
|
||||||
{
|
{
|
||||||
use gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BACKGROUND;
|
use gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BACKGROUND;
|
||||||
use gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BORDER;
|
use gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BORDER;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! A data structure to efficiently index structs containing selectors by local
|
//! A data structure to efficiently index structs containing selectors by local
|
||||||
//! name, ids and hash.
|
//! name, ids and hash.
|
||||||
|
|
||||||
use {Atom, LocalName};
|
use {Atom, LocalName, WeakAtom};
|
||||||
use applicable_declarations::ApplicableDeclarationList;
|
use applicable_declarations::ApplicableDeclarationList;
|
||||||
use context::QuirksMode;
|
use context::QuirksMode;
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
|
@ -175,8 +175,8 @@ impl SelectorMap<Rule> {
|
||||||
// At the end, we're going to sort the rules that we added, so remember
|
// At the end, we're going to sort the rules that we added, so remember
|
||||||
// where we began.
|
// where we began.
|
||||||
let init_len = matching_rules_list.len();
|
let init_len = matching_rules_list.len();
|
||||||
if let Some(id) = rule_hash_target.get_id() {
|
if let Some(id) = rule_hash_target.id() {
|
||||||
if let Some(rules) = self.id_hash.get(&id, quirks_mode) {
|
if let Some(rules) = self.id_hash.get(id, quirks_mode) {
|
||||||
SelectorMap::get_matching_rules(
|
SelectorMap::get_matching_rules(
|
||||||
element,
|
element,
|
||||||
rules,
|
rules,
|
||||||
|
@ -201,7 +201,7 @@ impl SelectorMap<Rule> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(rules) = self.local_name_hash.get(rule_hash_target.get_local_name()) {
|
if let Some(rules) = self.local_name_hash.get(rule_hash_target.local_name()) {
|
||||||
SelectorMap::get_matching_rules(
|
SelectorMap::get_matching_rules(
|
||||||
element,
|
element,
|
||||||
rules,
|
rules,
|
||||||
|
@ -315,8 +315,8 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||||
F: FnMut(&'a T) -> bool
|
F: FnMut(&'a T) -> bool
|
||||||
{
|
{
|
||||||
// Id.
|
// Id.
|
||||||
if let Some(id) = element.get_id() {
|
if let Some(id) = element.id() {
|
||||||
if let Some(v) = self.id_hash.get(&id, quirks_mode) {
|
if let Some(v) = self.id_hash.get(id, quirks_mode) {
|
||||||
for entry in v.iter() {
|
for entry in v.iter() {
|
||||||
if !f(&entry) {
|
if !f(&entry) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -344,7 +344,7 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local name.
|
// Local name.
|
||||||
if let Some(v) = self.local_name_hash.get(element.get_local_name()) {
|
if let Some(v) = self.local_name_hash.get(element.local_name()) {
|
||||||
for entry in v.iter() {
|
for entry in v.iter() {
|
||||||
if !f(&entry) {
|
if !f(&entry) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -374,7 +374,7 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||||
&'a self,
|
&'a self,
|
||||||
element: E,
|
element: E,
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
additional_id: Option<&Atom>,
|
additional_id: Option<&WeakAtom>,
|
||||||
additional_classes: &[Atom],
|
additional_classes: &[Atom],
|
||||||
mut f: F,
|
mut f: F,
|
||||||
) -> bool
|
) -> bool
|
||||||
|
@ -535,7 +535,7 @@ impl<V: 'static> MaybeCaseInsensitiveHashMap<Atom, V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HashMap::get
|
/// HashMap::get
|
||||||
pub fn get(&self, key: &Atom, quirks_mode: QuirksMode) -> Option<&V> {
|
pub fn get(&self, key: &WeakAtom, quirks_mode: QuirksMode) -> Option<&V> {
|
||||||
if quirks_mode == QuirksMode::Quirks {
|
if quirks_mode == QuirksMode::Quirks {
|
||||||
self.0.get(&key.to_ascii_lowercase())
|
self.0.get(&key.to_ascii_lowercase())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -696,8 +696,8 @@ impl ElementSnapshot for ServoElementSnapshot {
|
||||||
self.attrs.is_some()
|
self.attrs.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id_attr(&self) -> Option<Atom> {
|
fn id_attr(&self) -> Option<&Atom> {
|
||||||
self.get_attr(&ns!(), &local_name!("id")).map(|v| v.as_atom().clone())
|
self.get_attr(&ns!(), &local_name!("id")).map(|v| v.as_atom())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||||
|
|
|
@ -145,8 +145,8 @@ pub fn may_match_different_id_rules<E>(
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
{
|
{
|
||||||
let element_id = element.get_id();
|
let element_id = element.id();
|
||||||
let candidate_id = candidate.get_id();
|
let candidate_id = candidate.id();
|
||||||
|
|
||||||
if element_id == candidate_id {
|
if element_id == candidate_id {
|
||||||
return false;
|
return false;
|
||||||
|
@ -155,7 +155,7 @@ where
|
||||||
let stylist = &shared_context.stylist;
|
let stylist = &shared_context.stylist;
|
||||||
|
|
||||||
let may_have_rules_for_element = match element_id {
|
let may_have_rules_for_element = match element_id {
|
||||||
Some(ref id) => stylist.may_have_rules_for_id(id, element),
|
Some(id) => stylist.may_have_rules_for_id(id, element),
|
||||||
None => false
|
None => false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
match candidate_id {
|
match candidate_id {
|
||||||
Some(ref id) => stylist.may_have_rules_for_id(id, candidate),
|
Some(id) => stylist.may_have_rules_for_id(id, candidate),
|
||||||
None => false
|
None => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -676,12 +676,12 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if *target.get_local_name() != *candidate.element.get_local_name() {
|
if target.local_name() != candidate.element.local_name() {
|
||||||
trace!("Miss: Local Name");
|
trace!("Miss: Local Name");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if *target.get_namespace() != *candidate.element.get_namespace() {
|
if target.namespace() != candidate.element.namespace() {
|
||||||
trace!("Miss: Namespace");
|
trace!("Miss: Namespace");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -700,7 +700,7 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
// We do not ignore visited state here, because Gecko
|
// We do not ignore visited state here, because Gecko
|
||||||
// needs to store extra bits on visited style contexts,
|
// needs to store extra bits on visited style contexts,
|
||||||
// so these contexts cannot be shared
|
// so these contexts cannot be shared
|
||||||
if target.element.get_state() != candidate.get_state() {
|
if target.element.state() != candidate.state() {
|
||||||
trace!("Miss: User and Author State");
|
trace!("Miss: User and Author State");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -439,8 +439,8 @@ where
|
||||||
self.element,
|
self.element,
|
||||||
implemented_pseudo.as_ref(),
|
implemented_pseudo.as_ref(),
|
||||||
self.element.style_attribute(),
|
self.element.style_attribute(),
|
||||||
self.element.get_smil_override(),
|
self.element.smil_override(),
|
||||||
self.element.get_animation_rules(),
|
self.element.animation_rules(),
|
||||||
self.rule_inclusion,
|
self.rule_inclusion,
|
||||||
&mut applicable_declarations,
|
&mut applicable_declarations,
|
||||||
&mut matching_context,
|
&mut matching_context,
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
//! Selector matching.
|
//! Selector matching.
|
||||||
|
|
||||||
use {Atom, LocalName, Namespace};
|
use {Atom, LocalName, Namespace, WeakAtom};
|
||||||
use applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
|
use applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
|
||||||
use context::{CascadeInputs, QuirksMode};
|
use context::{CascadeInputs, QuirksMode};
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
|
@ -1385,7 +1385,7 @@ impl Stylist {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn may_have_rules_for_id<E>(
|
pub fn may_have_rules_for_id<E>(
|
||||||
&self,
|
&self,
|
||||||
id: &Atom,
|
id: &WeakAtom,
|
||||||
element: E,
|
element: E,
|
||||||
) -> bool
|
) -> bool
|
||||||
where
|
where
|
||||||
|
|
Загрузка…
Ссылка в новой задаче