Auto merge of #19744 - emilio:doc-invalidation-preparation, r=upsuper

style: A few trivial changes in preparation for document state invalidation.

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/19744)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-01-11 07:50:55 -06:00 committed by GitHub
commit 9b3fc43f5a
7 changed files with 106 additions and 94 deletions

View file

@ -246,8 +246,8 @@ impl ElementData {
return InvalidationResult::empty(); return InvalidationResult::empty();
} }
use invalidation::element::collector::StateAndAttrInvalidationProcessor;
use invalidation::element::invalidator::TreeStyleInvalidator; use invalidation::element::invalidator::TreeStyleInvalidator;
use invalidation::element::state_and_attributes::StateAndAttrInvalidationProcessor;
debug!("invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \ debug!("invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
handled_snapshot: {}, pseudo: {:?}", handled_snapshot: {}, pseudo: {:?}",

View file

@ -116,9 +116,6 @@ macro_rules! apply_non_ts_list {
], ],
string: [ string: [
("lang", Lang, lang, _, _), ("lang", Lang, lang, _, _),
],
keyword: [
("-moz-locale-dir", MozLocaleDir, mozLocaleDir, _, _),
] ]
} }
} }

View file

@ -36,9 +36,8 @@ pub type PseudoClassStringArg = Box<[u16]>;
macro_rules! pseudo_class_name { macro_rules! pseudo_class_name {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*], string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => { /// Our representation of a non tree-structural pseudo-class.
#[doc = "Our representation of a non tree-structural pseudo-class."]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum NonTSPseudoClass { pub enum NonTSPseudoClass {
$( $(
@ -49,10 +48,6 @@ macro_rules! pseudo_class_name {
#[doc = $s_css] #[doc = $s_css]
$s_name(PseudoClassStringArg), $s_name(PseudoClassStringArg),
)* )*
$(
#[doc = $k_css]
$k_name(Box<[u16]>),
)*
/// The `:dir` pseudo-class. /// The `:dir` pseudo-class.
Dir(Box<Direction>), Dir(Box<Direction>),
/// The non-standard `:-moz-any` pseudo-class. /// The non-standard `:-moz-any` pseudo-class.
@ -60,6 +55,8 @@ macro_rules! pseudo_class_name {
/// TODO(emilio): We disallow combinators and pseudos here, so we /// TODO(emilio): We disallow combinators and pseudos here, so we
/// should use SimpleSelector instead /// should use SimpleSelector instead
MozAny(Box<[Selector<SelectorImpl>]>), MozAny(Box<[Selector<SelectorImpl>]>),
/// The non-standard `:-moz-locale-dir` pseudo-class.
MozLocaleDir(Box<Direction>),
} }
} }
} }
@ -71,8 +68,7 @@ impl ToCss for NonTSPseudoClass {
use fmt::Write; use fmt::Write;
macro_rules! pseudo_class_serialize { macro_rules! pseudo_class_serialize {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*], string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
match *self { match *self {
$(NonTSPseudoClass::$name => concat!(":", $css),)* $(NonTSPseudoClass::$name => concat!(":", $css),)*
$(NonTSPseudoClass::$s_name(ref s) => { $(NonTSPseudoClass::$s_name(ref s) => {
@ -87,16 +83,14 @@ impl ToCss for NonTSPseudoClass {
} }
return dest.write_str(")") return dest.write_str(")")
}, )* }, )*
$(NonTSPseudoClass::$k_name(ref s) => { NonTSPseudoClass::MozLocaleDir(ref dir) => {
// Don't include the terminating nul. dest.write_str(":-moz-locale-dir(")?;
let value = String::from_utf16(&s[..s.len() - 1]).unwrap(); dir.to_css(dest)?;
dest.write_str(concat!(":", $k_css, "("))?;
dest.write_str(&value)?;
return dest.write_char(')') return dest.write_char(')')
}, )* },
NonTSPseudoClass::Dir(ref dir) => { NonTSPseudoClass::Dir(ref dir) => {
dest.write_str(":dir(")?; dest.write_str(":dir(")?;
(**dir).to_css(dest)?; dir.to_css(dest)?;
return dest.write_char(')') return dest.write_char(')')
}, },
NonTSPseudoClass::MozAny(ref selectors) => { NonTSPseudoClass::MozAny(ref selectors) => {
@ -146,13 +140,14 @@ impl NonTSPseudoClass {
} }
macro_rules! pseudo_class_check_is_enabled_in { macro_rules! pseudo_class_check_is_enabled_in {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*], string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
match *self { match *self {
$(NonTSPseudoClass::$name => check_flag!($flags),)* $(NonTSPseudoClass::$name => check_flag!($flags),)*
$(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)* $(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)*
$(NonTSPseudoClass::$k_name(..) => check_flag!($k_flags),)* // TODO(emilio): Maybe -moz-locale-dir shouldn't be
NonTSPseudoClass::Dir(_) => false, // content-exposed.
NonTSPseudoClass::MozLocaleDir(_) |
NonTSPseudoClass::Dir(_) |
NonTSPseudoClass::MozAny(_) => false, NonTSPseudoClass::MozAny(_) => false,
} }
} }
@ -191,13 +186,12 @@ impl NonTSPseudoClass {
} }
macro_rules! pseudo_class_state { macro_rules! pseudo_class_state {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*], string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
match *self { match *self {
$(NonTSPseudoClass::$name => flag!($state),)* $(NonTSPseudoClass::$name => flag!($state),)*
$(NonTSPseudoClass::$s_name(..) => flag!($s_state),)* $(NonTSPseudoClass::$s_name(..) => flag!($s_state),)*
$(NonTSPseudoClass::$k_name(..) => flag!($k_state),)* NonTSPseudoClass::Dir(..) |
NonTSPseudoClass::Dir(..) => ElementState::empty(), NonTSPseudoClass::MozLocaleDir(..) |
NonTSPseudoClass::MozAny(..) => ElementState::empty(), NonTSPseudoClass::MozAny(..) => ElementState::empty(),
} }
} }
@ -256,12 +250,11 @@ impl NonTSPseudoClass {
} }
macro_rules! pseudo_class_geckotype { macro_rules! pseudo_class_geckotype {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*], string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
match *self { match *self {
$(NonTSPseudoClass::$name => gecko_type!($gecko_type),)* $(NonTSPseudoClass::$name => gecko_type!($gecko_type),)*
$(NonTSPseudoClass::$s_name(..) => gecko_type!($s_gecko_type),)* $(NonTSPseudoClass::$s_name(..) => gecko_type!($s_gecko_type),)*
$(NonTSPseudoClass::$k_name(..) => gecko_type!($k_gecko_type),)* NonTSPseudoClass::MozLocaleDir(_) => gecko_type!(mozLocaleDir),
NonTSPseudoClass::Dir(_) => gecko_type!(dir), NonTSPseudoClass::Dir(_) => gecko_type!(dir),
NonTSPseudoClass::MozAny(_) => gecko_type!(any), NonTSPseudoClass::MozAny(_) => gecko_type!(any),
} }
@ -353,8 +346,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
) -> Result<NonTSPseudoClass, ParseError<'i>> { ) -> Result<NonTSPseudoClass, ParseError<'i>> {
macro_rules! pseudo_class_parse { macro_rules! pseudo_class_parse {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*], string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
match_ignore_ascii_case! { &name, match_ignore_ascii_case! { &name,
$($css => NonTSPseudoClass::$name,)* $($css => NonTSPseudoClass::$name,)*
_ => return Err(location.new_custom_error( _ => return Err(location.new_custom_error(
@ -378,8 +370,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
) -> Result<NonTSPseudoClass, ParseError<'i>> { ) -> Result<NonTSPseudoClass, ParseError<'i>> {
macro_rules! pseudo_class_string_parse { macro_rules! pseudo_class_string_parse {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*], string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
match_ignore_ascii_case! { &name, match_ignore_ascii_case! { &name,
$($s_css => { $($s_css => {
let name = parser.expect_ident_or_string()?; let name = parser.expect_ident_or_string()?;
@ -388,23 +379,15 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
let utf16: Vec<u16> = name.encode_utf16().chain(Some(0u16)).collect(); let utf16: Vec<u16> = name.encode_utf16().chain(Some(0u16)).collect();
NonTSPseudoClass::$s_name(utf16.into_boxed_slice()) NonTSPseudoClass::$s_name(utf16.into_boxed_slice())
}, )* }, )*
$($k_css => { "-moz-locale-dir" => {
let name = parser.expect_ident()?; NonTSPseudoClass::MozLocaleDir(
// Convert to ASCII-lowercase nul-terminated UTF-16 string. Box::new(Direction::parse(parser)?)
let utf16: Vec<u16> = name.encode_utf16().map(utf16_to_ascii_lowercase) )
.chain(Some(0u16)).collect(); },
NonTSPseudoClass::$k_name(utf16.into_boxed_slice())
}, )*
"dir" => { "dir" => {
let name: &str = parser.expect_ident()?; NonTSPseudoClass::Dir(
let direction = match_ignore_ascii_case! { name, Box::new(Direction::parse(parser)?)
"rtl" => Direction::Rtl, )
"ltr" => Direction::Ltr,
_ => {
Direction::Other(Box::from(name))
},
};
NonTSPseudoClass::Dir(Box::new(direction))
}, },
"-moz-any" => { "-moz-any" => {
NonTSPseudoClass::MozAny( NonTSPseudoClass::MozAny(
@ -496,13 +479,6 @@ impl SelectorImpl {
} }
} }
fn utf16_to_ascii_lowercase(unit: u16) -> u16 {
match unit {
65...90 => unit + 32, // A-Z => a-z
_ => unit
}
}
unsafe impl HasFFI for SelectorList<SelectorImpl> { unsafe impl HasFFI for SelectorList<SelectorImpl> {
type FFIType = RawServoSelectorList; type FFIType = RawServoSelectorList;
} }

View file

@ -46,7 +46,6 @@ use gecko_bindings::bindings::Gecko_GetUnvisitedLinkAttrDeclarationBlock;
use gecko_bindings::bindings::Gecko_GetVisitedLinkAttrDeclarationBlock; use gecko_bindings::bindings::Gecko_GetVisitedLinkAttrDeclarationBlock;
use gecko_bindings::bindings::Gecko_IsSignificantChild; use gecko_bindings::bindings::Gecko_IsSignificantChild;
use gecko_bindings::bindings::Gecko_MatchLang; use gecko_bindings::bindings::Gecko_MatchLang;
use gecko_bindings::bindings::Gecko_MatchStringArgPseudo;
use gecko_bindings::bindings::Gecko_UnsetDirtyStyleAttr; use gecko_bindings::bindings::Gecko_UnsetDirtyStyleAttr;
use gecko_bindings::bindings::Gecko_UpdateAnimations; use gecko_bindings::bindings::Gecko_UpdateAnimations;
use gecko_bindings::structs; use gecko_bindings::structs;
@ -2111,7 +2110,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
self.get_document_theme() == DocumentTheme::Doc_Theme_Dark self.get_document_theme() == DocumentTheme::Doc_Theme_Dark
} }
NonTSPseudoClass::MozWindowInactive => { NonTSPseudoClass::MozWindowInactive => {
self.document_state().contains(DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE) self.document_state()
.contains(DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE)
} }
NonTSPseudoClass::MozPlaceholder => false, NonTSPseudoClass::MozPlaceholder => false,
NonTSPseudoClass::MozAny(ref sels) => { NonTSPseudoClass::MozAny(ref sels) => {
@ -2125,13 +2125,15 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::Lang(ref lang_arg) => { NonTSPseudoClass::Lang(ref lang_arg) => {
self.match_element_lang(None, lang_arg) self.match_element_lang(None, lang_arg)
} }
NonTSPseudoClass::MozLocaleDir(ref s) => { NonTSPseudoClass::MozLocaleDir(ref dir) => {
unsafe { let doc_is_rtl =
Gecko_MatchStringArgPseudo( self.document_state()
self.0, .contains(DocumentState::NS_DOCUMENT_STATE_RTL_LOCALE);
pseudo_class.to_gecko_pseudoclasstype().unwrap(),
s.as_ptr(), match **dir {
) Direction::Ltr => !doc_is_rtl,
Direction::Rtl => doc_is_rtl,
Direction::Other(..) => false,
} }
} }
NonTSPseudoClass::Dir(ref dir) => { NonTSPseudoClass::Dir(ref dir) => {

View file

@ -4,8 +4,8 @@
//! Invalidation of element styles due to attribute or style changes. //! Invalidation of element styles due to attribute or style changes.
pub mod collector;
pub mod element_wrapper; pub mod element_wrapper;
pub mod invalidation_map; pub mod invalidation_map;
pub mod invalidator; pub mod invalidator;
pub mod restyle_hints; pub mod restyle_hints;
pub mod state_and_attributes;

View file

@ -93,6 +93,50 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
} }
} }
/// Whether we should process the descendants of a given element for style
/// invalidation.
pub fn should_process_descendants(data: &ElementData) -> bool {
!data.styles.is_display_none() &&
!data.hint.contains(RestyleHint::RESTYLE_DESCENDANTS)
}
/// Propagates the bits after invalidating a descendant child.
pub fn invalidated_descendants<E>(element: E, child: E)
where
E: TElement,
{
if child.get_data().is_none() {
return;
}
// The child may not be a flattened tree child of the current element,
// but may be arbitrarily deep.
//
// Since we keep the traversal flags in terms of the flattened tree,
// we need to propagate it as appropriate.
let mut current = child.traversal_parent();
while let Some(parent) = current.take() {
unsafe { parent.set_dirty_descendants() };
current = parent.traversal_parent();
if parent == element {
break;
}
}
}
/// Sets the appropriate restyle hint after invalidating the style of a given
/// element.
pub fn invalidated_self<E>(element: E)
where
E: TElement,
{
if let Some(mut data) = element.mutate_data() {
data.hint.insert(RestyleHint::RESTYLE_SELF);
}
}
impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'a, E> for StateAndAttrInvalidationProcessor<'a, 'b, E> impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'a, E> for StateAndAttrInvalidationProcessor<'a, 'b, E>
where where
E: TElement, E: TElement,
@ -251,17 +295,15 @@ where
fn should_process_descendants(&mut self, element: E) -> bool { fn should_process_descendants(&mut self, element: E) -> bool {
if element == self.element { if element == self.element {
return !self.data.styles.is_display_none() && return should_process_descendants(&self.data)
!self.data.hint.contains(RestyleHint::RESTYLE_DESCENDANTS)
} }
let data = match element.borrow_data() { let data = match element.borrow_data() {
Some(d) => d,
None => return false, None => return false,
Some(data) => data,
}; };
!data.styles.is_display_none() && should_process_descendants(&data)
!data.hint.contains(RestyleHint::RESTYLE_DESCENDANTS)
} }
fn recursion_limit_exceeded(&mut self, element: E) { fn recursion_limit_exceeded(&mut self, element: E) {
@ -276,31 +318,12 @@ where
} }
fn invalidated_descendants(&mut self, element: E, child: E) { fn invalidated_descendants(&mut self, element: E, child: E) {
if child.get_data().is_none() { invalidated_descendants(element, child)
return;
}
// The child may not be a flattened tree child of the current element,
// but may be arbitrarily deep.
//
// Since we keep the traversal flags in terms of the flattened tree,
// we need to propagate it as appropriate.
let mut current = child.traversal_parent();
while let Some(parent) = current.take() {
unsafe { parent.set_dirty_descendants() };
current = parent.traversal_parent();
if parent == element {
break;
}
}
} }
fn invalidated_self(&mut self, element: E) { fn invalidated_self(&mut self, element: E) {
debug_assert_ne!(element, self.element); debug_assert_ne!(element, self.element);
if let Some(mut data) = element.mutate_data() { invalidated_self(element);
data.hint.insert(RestyleHint::RESTYLE_SELF);
}
} }
} }

View file

@ -183,9 +183,23 @@ pub enum Direction {
/// right-to-left semantic directionality /// right-to-left semantic directionality
Rtl, Rtl,
/// Some other provided directionality value /// Some other provided directionality value
///
/// TODO(emilio): If we atomize we can then unbox in NonTSPseudoClass.
Other(Box<str>), Other(Box<str>),
} }
impl Direction {
/// Parse a direction value.
pub fn parse<'i, 't>(parser: &mut CssParser<'i, 't>) -> Result<Self, ParseError<'i>> {
let ident = parser.expect_ident()?;
Ok(match_ignore_ascii_case! { &ident,
"rtl" => Direction::Rtl,
"ltr" => Direction::Ltr,
_ => Direction::Other(Box::from(ident.as_ref())),
})
}
}
impl ToCss for Direction { impl ToCss for Direction {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: Write {
let dir_str = match *self { let dir_str = match *self {