mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
style: Speed up selector matching with already-lowercase local name selectors
This makes relatively simple changes so that we check lowercase-ness of local-name selectors first. If so, we don't need to check whether we're an HTML element in an HTML document, which requires a fair bit of pointer-chasing. Differential Revision: https://phabricator.services.mozilla.com/D163627
This commit is contained in:
parent
dbba87d73e
commit
b6d9b77a15
3 changed files with 47 additions and 46 deletions
|
@ -145,35 +145,16 @@ pub static SELECTOR_WHITESPACE: &[char] = &[' ', '\t', '\n', '\r', '\x0C'];
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "shmem", derive(ToShmem))]
|
#[cfg_attr(feature = "shmem", derive(ToShmem))]
|
||||||
pub enum ParsedCaseSensitivity {
|
pub enum ParsedCaseSensitivity {
|
||||||
// 's' was specified.
|
/// 's' was specified.
|
||||||
ExplicitCaseSensitive,
|
ExplicitCaseSensitive,
|
||||||
// 'i' was specified.
|
/// 'i' was specified.
|
||||||
AsciiCaseInsensitive,
|
AsciiCaseInsensitive,
|
||||||
// No flags were specified and HTML says this is a case-sensitive attribute.
|
/// No flags were specified and HTML says this is a case-sensitive attribute.
|
||||||
CaseSensitive,
|
CaseSensitive,
|
||||||
// No flags were specified and HTML says this is a case-insensitive attribute.
|
/// No flags were specified and HTML says this is a case-insensitive attribute.
|
||||||
AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument,
|
AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParsedCaseSensitivity {
|
|
||||||
pub fn to_unconditional(self, is_html_element_in_html_document: bool) -> CaseSensitivity {
|
|
||||||
match self {
|
|
||||||
ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
|
|
||||||
if is_html_element_in_html_document =>
|
|
||||||
{
|
|
||||||
CaseSensitivity::AsciiCaseInsensitive
|
|
||||||
},
|
|
||||||
ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
|
|
||||||
CaseSensitivity::CaseSensitive
|
|
||||||
},
|
|
||||||
ParsedCaseSensitivity::CaseSensitive | ParsedCaseSensitivity::ExplicitCaseSensitive => {
|
|
||||||
CaseSensitivity::CaseSensitive
|
|
||||||
},
|
|
||||||
ParsedCaseSensitivity::AsciiCaseInsensitive => CaseSensitivity::AsciiCaseInsensitive,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum CaseSensitivity {
|
pub enum CaseSensitivity {
|
||||||
CaseSensitive,
|
CaseSensitive,
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use crate::attr::{AttrSelectorOperation, NamespaceConstraint, ParsedAttrSelectorOperation};
|
use crate::attr::{
|
||||||
|
AttrSelectorOperation, CaseSensitivity, NamespaceConstraint, ParsedAttrSelectorOperation,
|
||||||
|
ParsedCaseSensitivity,
|
||||||
|
};
|
||||||
use crate::bloom::{BloomFilter, BLOOM_HASH_MASK};
|
use crate::bloom::{BloomFilter, BLOOM_HASH_MASK};
|
||||||
use crate::nth_index_cache::NthIndexCacheInner;
|
use crate::nth_index_cache::NthIndexCacheInner;
|
||||||
use crate::parser::{AncestorHashes, Combinator, Component, LocalName};
|
use crate::parser::{AncestorHashes, Combinator, Component, LocalName};
|
||||||
|
@ -580,12 +583,7 @@ fn matches_local_name<E>(element: &E, local_name: &LocalName<E::Impl>) -> bool
|
||||||
where
|
where
|
||||||
E: Element,
|
E: Element,
|
||||||
{
|
{
|
||||||
let name = select_name(
|
let name = select_name(element, &local_name.name, &local_name.lower_name).borrow();
|
||||||
element.is_html_element_in_html_document(),
|
|
||||||
&local_name.name,
|
|
||||||
&local_name.lower_name,
|
|
||||||
)
|
|
||||||
.borrow();
|
|
||||||
element.has_local_name(name)
|
element.has_local_name(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,14 +663,11 @@ where
|
||||||
Component::AttributeInNoNamespaceExists {
|
Component::AttributeInNoNamespaceExists {
|
||||||
ref local_name,
|
ref local_name,
|
||||||
ref local_name_lower,
|
ref local_name_lower,
|
||||||
} => {
|
} => element.attr_matches(
|
||||||
let is_html = element.is_html_element_in_html_document();
|
&NamespaceConstraint::Specific(&crate::parser::namespace_empty_string::<E::Impl>()),
|
||||||
element.attr_matches(
|
select_name(element, local_name, local_name_lower),
|
||||||
&NamespaceConstraint::Specific(&crate::parser::namespace_empty_string::<E::Impl>()),
|
&AttrSelectorOperation::Exists,
|
||||||
select_name(is_html, local_name, local_name_lower),
|
),
|
||||||
&AttrSelectorOperation::Exists,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Component::AttributeInNoNamespace {
|
Component::AttributeInNoNamespace {
|
||||||
ref local_name,
|
ref local_name,
|
||||||
ref value,
|
ref value,
|
||||||
|
@ -683,13 +678,12 @@ where
|
||||||
if never_matches {
|
if never_matches {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let is_html = element.is_html_element_in_html_document();
|
|
||||||
element.attr_matches(
|
element.attr_matches(
|
||||||
&NamespaceConstraint::Specific(&crate::parser::namespace_empty_string::<E::Impl>()),
|
&NamespaceConstraint::Specific(&crate::parser::namespace_empty_string::<E::Impl>()),
|
||||||
local_name,
|
local_name,
|
||||||
&AttrSelectorOperation::WithValue {
|
&AttrSelectorOperation::WithValue {
|
||||||
operator,
|
operator,
|
||||||
case_sensitivity: case_sensitivity.to_unconditional(is_html),
|
case_sensitivity: to_unconditional_case_sensitivity(case_sensitivity, element),
|
||||||
expected_value: value,
|
expected_value: value,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -698,7 +692,6 @@ where
|
||||||
if attr_sel.never_matches {
|
if attr_sel.never_matches {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let is_html = element.is_html_element_in_html_document();
|
|
||||||
let empty_string;
|
let empty_string;
|
||||||
let namespace = match attr_sel.namespace() {
|
let namespace = match attr_sel.namespace() {
|
||||||
Some(ns) => ns,
|
Some(ns) => ns,
|
||||||
|
@ -709,7 +702,7 @@ where
|
||||||
};
|
};
|
||||||
element.attr_matches(
|
element.attr_matches(
|
||||||
&namespace,
|
&namespace,
|
||||||
select_name(is_html, &attr_sel.local_name, &attr_sel.local_name_lower),
|
select_name(element, &attr_sel.local_name, &attr_sel.local_name_lower),
|
||||||
&match attr_sel.operation {
|
&match attr_sel.operation {
|
||||||
ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,
|
ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,
|
||||||
ParsedAttrSelectorOperation::WithValue {
|
ParsedAttrSelectorOperation::WithValue {
|
||||||
|
@ -718,7 +711,10 @@ where
|
||||||
ref expected_value,
|
ref expected_value,
|
||||||
} => AttrSelectorOperation::WithValue {
|
} => AttrSelectorOperation::WithValue {
|
||||||
operator,
|
operator,
|
||||||
case_sensitivity: case_sensitivity.to_unconditional(is_html),
|
case_sensitivity: to_unconditional_case_sensitivity(
|
||||||
|
case_sensitivity,
|
||||||
|
element,
|
||||||
|
),
|
||||||
expected_value,
|
expected_value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -867,14 +863,38 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn select_name<'a, T>(is_html: bool, local_name: &'a T, local_name_lower: &'a T) -> &'a T {
|
fn select_name<'a, E: Element, T: PartialEq>(
|
||||||
if is_html {
|
element: &E,
|
||||||
|
local_name: &'a T,
|
||||||
|
local_name_lower: &'a T,
|
||||||
|
) -> &'a T {
|
||||||
|
if local_name == local_name_lower || element.is_html_element_in_html_document() {
|
||||||
local_name_lower
|
local_name_lower
|
||||||
} else {
|
} else {
|
||||||
local_name
|
local_name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn to_unconditional_case_sensitivity<'a, E: Element>(
|
||||||
|
parsed: ParsedCaseSensitivity,
|
||||||
|
element: &E,
|
||||||
|
) -> CaseSensitivity {
|
||||||
|
match parsed {
|
||||||
|
ParsedCaseSensitivity::CaseSensitive | ParsedCaseSensitivity::ExplicitCaseSensitive => {
|
||||||
|
CaseSensitivity::CaseSensitive
|
||||||
|
},
|
||||||
|
ParsedCaseSensitivity::AsciiCaseInsensitive => CaseSensitivity::AsciiCaseInsensitive,
|
||||||
|
ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
|
||||||
|
if element.is_html_element_in_html_document() {
|
||||||
|
CaseSensitivity::AsciiCaseInsensitive
|
||||||
|
} else {
|
||||||
|
CaseSensitivity::CaseSensitive
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches_generic_nth_child<E>(
|
fn matches_generic_nth_child<E>(
|
||||||
element: &E,
|
element: &E,
|
||||||
|
|
|
@ -365,7 +365,7 @@ where
|
||||||
ref lower_name,
|
ref lower_name,
|
||||||
} = *local_name;
|
} = *local_name;
|
||||||
|
|
||||||
let chosen_name = if element.is_html_element_in_html_document() {
|
let chosen_name = if name == lower_name || element.is_html_element_in_html_document() {
|
||||||
lower_name
|
lower_name
|
||||||
} else {
|
} else {
|
||||||
name
|
name
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue