From b6d9b77a1581b8fb0a28f080766f560cff5dbc46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 3 Dec 2022 11:25:09 +0000 Subject: [PATCH] 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 --- components/selectors/attr.rs | 27 ++------------ components/selectors/matching.rs | 64 +++++++++++++++++++++----------- components/style/dom_apis.rs | 2 +- 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/components/selectors/attr.rs b/components/selectors/attr.rs index 91588b3b389..3b3b76e453a 100644 --- a/components/selectors/attr.rs +++ b/components/selectors/attr.rs @@ -145,35 +145,16 @@ pub static SELECTOR_WHITESPACE: &[char] = &[' ', '\t', '\n', '\r', '\x0C']; #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "shmem", derive(ToShmem))] pub enum ParsedCaseSensitivity { - // 's' was specified. + /// 's' was specified. ExplicitCaseSensitive, - // 'i' was specified. + /// 'i' was specified. 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, - // 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, } -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)] pub enum CaseSensitivity { CaseSensitive, diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index 1471259ce68..30fd037ce7c 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -2,7 +2,10 @@ * 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/. */ -use crate::attr::{AttrSelectorOperation, NamespaceConstraint, ParsedAttrSelectorOperation}; +use crate::attr::{ + AttrSelectorOperation, CaseSensitivity, NamespaceConstraint, ParsedAttrSelectorOperation, + ParsedCaseSensitivity, +}; use crate::bloom::{BloomFilter, BLOOM_HASH_MASK}; use crate::nth_index_cache::NthIndexCacheInner; use crate::parser::{AncestorHashes, Combinator, Component, LocalName}; @@ -580,12 +583,7 @@ fn matches_local_name(element: &E, local_name: &LocalName) -> bool where E: Element, { - let name = select_name( - element.is_html_element_in_html_document(), - &local_name.name, - &local_name.lower_name, - ) - .borrow(); + let name = select_name(element, &local_name.name, &local_name.lower_name).borrow(); element.has_local_name(name) } @@ -665,14 +663,11 @@ where Component::AttributeInNoNamespaceExists { ref local_name, ref local_name_lower, - } => { - let is_html = element.is_html_element_in_html_document(); - element.attr_matches( - &NamespaceConstraint::Specific(&crate::parser::namespace_empty_string::()), - select_name(is_html, local_name, local_name_lower), - &AttrSelectorOperation::Exists, - ) - }, + } => element.attr_matches( + &NamespaceConstraint::Specific(&crate::parser::namespace_empty_string::()), + select_name(element, local_name, local_name_lower), + &AttrSelectorOperation::Exists, + ), Component::AttributeInNoNamespace { ref local_name, ref value, @@ -683,13 +678,12 @@ where if never_matches { return false; } - let is_html = element.is_html_element_in_html_document(); element.attr_matches( &NamespaceConstraint::Specific(&crate::parser::namespace_empty_string::()), local_name, &AttrSelectorOperation::WithValue { operator, - case_sensitivity: case_sensitivity.to_unconditional(is_html), + case_sensitivity: to_unconditional_case_sensitivity(case_sensitivity, element), expected_value: value, }, ) @@ -698,7 +692,6 @@ where if attr_sel.never_matches { return false; } - let is_html = element.is_html_element_in_html_document(); let empty_string; let namespace = match attr_sel.namespace() { Some(ns) => ns, @@ -709,7 +702,7 @@ where }; element.attr_matches( &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 { ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists, ParsedAttrSelectorOperation::WithValue { @@ -718,7 +711,10 @@ where ref expected_value, } => AttrSelectorOperation::WithValue { operator, - case_sensitivity: case_sensitivity.to_unconditional(is_html), + case_sensitivity: to_unconditional_case_sensitivity( + case_sensitivity, + element, + ), expected_value, }, }, @@ -867,14 +863,38 @@ where } #[inline(always)] -fn select_name<'a, T>(is_html: bool, local_name: &'a T, local_name_lower: &'a T) -> &'a T { - if is_html { +fn select_name<'a, E: Element, T: PartialEq>( + 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 } else { 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] fn matches_generic_nth_child( element: &E, diff --git a/components/style/dom_apis.rs b/components/style/dom_apis.rs index a2bb4c4ecbe..eeadc1ee53f 100644 --- a/components/style/dom_apis.rs +++ b/components/style/dom_apis.rs @@ -365,7 +365,7 @@ where ref lower_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 } else { name