mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
script: Move extended_filtering to the style crate.
We'll need to call it from the style crate in later patches, when matching :lang() against element snapshots.
This commit is contained in:
parent
07b0770d21
commit
524794c09a
4 changed files with 69 additions and 64 deletions
|
@ -113,63 +113,6 @@ pub fn is_token(s: &[u8]) -> bool {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the language is matched, as defined by
|
|
||||||
/// [RFC 4647](https://tools.ietf.org/html/rfc4647#section-3.3.2).
|
|
||||||
pub fn extended_filtering(tag: &str, range: &str) -> bool {
|
|
||||||
let lang_ranges: Vec<&str> = range.split(',').collect();
|
|
||||||
|
|
||||||
lang_ranges.iter().any(|&lang_range| {
|
|
||||||
// step 1
|
|
||||||
let range_subtags: Vec<&str> = lang_range.split('\x2d').collect();
|
|
||||||
let tag_subtags: Vec<&str> = tag.split('\x2d').collect();
|
|
||||||
|
|
||||||
let mut range_iter = range_subtags.iter();
|
|
||||||
let mut tag_iter = tag_subtags.iter();
|
|
||||||
|
|
||||||
// step 2
|
|
||||||
// Note: [Level-4 spec](https://drafts.csswg.org/selectors/#lang-pseudo) check for wild card
|
|
||||||
if let (Some(range_subtag), Some(tag_subtag)) = (range_iter.next(), tag_iter.next()) {
|
|
||||||
if !(range_subtag.eq_ignore_ascii_case(tag_subtag) || range_subtag.eq_ignore_ascii_case("*")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut current_tag_subtag = tag_iter.next();
|
|
||||||
|
|
||||||
// step 3
|
|
||||||
for range_subtag in range_iter {
|
|
||||||
// step 3a
|
|
||||||
if range_subtag.eq_ignore_ascii_case("*") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
match current_tag_subtag.clone() {
|
|
||||||
Some(tag_subtag) => {
|
|
||||||
// step 3c
|
|
||||||
if range_subtag.eq_ignore_ascii_case(tag_subtag) {
|
|
||||||
current_tag_subtag = tag_iter.next();
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
// step 3d
|
|
||||||
if tag_subtag.len() == 1 {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// else step 3e - continue with loop
|
|
||||||
current_tag_subtag = tag_iter.next();
|
|
||||||
if current_tag_subtag.is_none() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// step 3b
|
|
||||||
None => { return false; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// step 4
|
|
||||||
true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// A DOMString.
|
/// A DOMString.
|
||||||
///
|
///
|
||||||
|
|
|
@ -26,7 +26,7 @@ use dom::bindings::js::{JS, LayoutJS, MutNullableJS};
|
||||||
use dom::bindings::js::{Root, RootedReference};
|
use dom::bindings::js::{Root, RootedReference};
|
||||||
use dom::bindings::refcounted::{Trusted, TrustedPromise};
|
use dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||||
use dom::bindings::reflector::DomObject;
|
use dom::bindings::reflector::DomObject;
|
||||||
use dom::bindings::str::{DOMString, extended_filtering};
|
use dom::bindings::str::DOMString;
|
||||||
use dom::bindings::xmlname::{namespace_from_domstring, validate_and_extract, xml_name_type};
|
use dom::bindings::xmlname::{namespace_from_domstring, validate_and_extract, xml_name_type};
|
||||||
use dom::bindings::xmlname::XMLName::InvalidXMLName;
|
use dom::bindings::xmlname::XMLName::InvalidXMLName;
|
||||||
use dom::characterdata::CharacterData;
|
use dom::characterdata::CharacterData;
|
||||||
|
@ -106,6 +106,7 @@ use style::properties::longhands::{self, background_image, border_spacing, font_
|
||||||
use style::restyle_hints::RestyleHint;
|
use style::restyle_hints::RestyleHint;
|
||||||
use style::rule_tree::CascadeLevel;
|
use style::rule_tree::CascadeLevel;
|
||||||
use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser};
|
use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser};
|
||||||
|
use style::selector_parser::extended_filtering;
|
||||||
use style::shared_lock::{SharedRwLock, Locked};
|
use style::shared_lock::{SharedRwLock, Locked};
|
||||||
use style::sink::Push;
|
use style::sink::Push;
|
||||||
use style::stylearc::Arc;
|
use style::stylearc::Arc;
|
||||||
|
@ -2464,8 +2465,10 @@ impl<'a> ::selectors::Element for Root<Element> {
|
||||||
.map_or(false, |attr| attr.value().eq(expected_value))
|
.map_or(false, |attr| attr.value().eq(expected_value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(#15746): This is wrong, we need to instead use extended filtering as per RFC4647
|
// FIXME(heycam): This is wrong, since extended_filtering accepts
|
||||||
// https://tools.ietf.org/html/rfc4647#section-3.3.2
|
// a string containing commas (separating each language tag in
|
||||||
|
// a list) but the pseudo-class instead should be parsing and
|
||||||
|
// storing separate <ident> or <string>s for each language tag.
|
||||||
NonTSPseudoClass::Lang(ref lang) => extended_filtering(&*self.get_lang(), &*lang),
|
NonTSPseudoClass::Lang(ref lang) => extended_filtering(&*self.get_lang(), &*lang),
|
||||||
|
|
||||||
NonTSPseudoClass::ReadOnly =>
|
NonTSPseudoClass::ReadOnly =>
|
||||||
|
|
|
@ -34,7 +34,6 @@ use atomic_refcell::{AtomicRef, AtomicRefCell};
|
||||||
use dom::bindings::inheritance::{CharacterDataTypeId, ElementTypeId};
|
use dom::bindings::inheritance::{CharacterDataTypeId, ElementTypeId};
|
||||||
use dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId};
|
use dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId};
|
||||||
use dom::bindings::js::LayoutJS;
|
use dom::bindings::js::LayoutJS;
|
||||||
use dom::bindings::str::extended_filtering;
|
|
||||||
use dom::characterdata::LayoutCharacterDataHelpers;
|
use dom::characterdata::LayoutCharacterDataHelpers;
|
||||||
use dom::document::{Document, LayoutDocumentHelpers, PendingRestyle};
|
use dom::document::{Document, LayoutDocumentHelpers, PendingRestyle};
|
||||||
use dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers};
|
use dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers};
|
||||||
|
@ -70,7 +69,7 @@ use style::dom::{PresentationalHintsSynthesizer, TElement, TNode, UnsafeNode};
|
||||||
use style::element_state::*;
|
use style::element_state::*;
|
||||||
use style::font_metrics::ServoMetricsProvider;
|
use style::font_metrics::ServoMetricsProvider;
|
||||||
use style::properties::{ComputedValues, PropertyDeclarationBlock};
|
use style::properties::{ComputedValues, PropertyDeclarationBlock};
|
||||||
use style::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
|
use style::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, extended_filtering};
|
||||||
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
|
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
|
||||||
use style::sink::Push;
|
use style::sink::Push;
|
||||||
use style::str::is_whitespace;
|
use style::str::is_whitespace;
|
||||||
|
@ -691,8 +690,10 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
NonTSPseudoClass::AnyLink => self.is_link(),
|
NonTSPseudoClass::AnyLink => self.is_link(),
|
||||||
NonTSPseudoClass::Visited => false,
|
NonTSPseudoClass::Visited => false,
|
||||||
|
|
||||||
// FIXME(#15746): This is wrong, we need to instead use extended filtering as per RFC4647
|
// FIXME(heycam): This is wrong, since extended_filtering accepts
|
||||||
// https://tools.ietf.org/html/rfc4647#section-3.3.2
|
// a string containing commas (separating each language tag in
|
||||||
|
// a list) but the pseudo-class instead should be parsing and
|
||||||
|
// storing separate <ident> or <string>s for each language tag.
|
||||||
NonTSPseudoClass::Lang(ref lang) => extended_filtering(&*self.element.get_lang_for_layout(), &*lang),
|
NonTSPseudoClass::Lang(ref lang) => extended_filtering(&*self.element.get_lang_for_layout(), &*lang),
|
||||||
|
|
||||||
NonTSPseudoClass::ServoNonZeroBorder => unsafe {
|
NonTSPseudoClass::ServoNonZeroBorder => unsafe {
|
||||||
|
|
|
@ -18,6 +18,7 @@ use selectors::Element;
|
||||||
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
||||||
use selectors::parser::SelectorMethods;
|
use selectors::parser::SelectorMethods;
|
||||||
use selectors::visitor::SelectorVisitor;
|
use selectors::visitor::SelectorVisitor;
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -611,3 +612,60 @@ impl<E: Element<Impl=SelectorImpl> + Debug> ElementExt for E {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the language is matched, as defined by
|
||||||
|
/// [RFC 4647](https://tools.ietf.org/html/rfc4647#section-3.3.2).
|
||||||
|
pub fn extended_filtering(tag: &str, range: &str) -> bool {
|
||||||
|
let lang_ranges: Vec<&str> = range.split(',').collect();
|
||||||
|
|
||||||
|
lang_ranges.iter().any(|&lang_range| {
|
||||||
|
// step 1
|
||||||
|
let range_subtags: Vec<&str> = lang_range.split('\x2d').collect();
|
||||||
|
let tag_subtags: Vec<&str> = tag.split('\x2d').collect();
|
||||||
|
|
||||||
|
let mut range_iter = range_subtags.iter();
|
||||||
|
let mut tag_iter = tag_subtags.iter();
|
||||||
|
|
||||||
|
// step 2
|
||||||
|
// Note: [Level-4 spec](https://drafts.csswg.org/selectors/#lang-pseudo) check for wild card
|
||||||
|
if let (Some(range_subtag), Some(tag_subtag)) = (range_iter.next(), tag_iter.next()) {
|
||||||
|
if !(range_subtag.eq_ignore_ascii_case(tag_subtag) || range_subtag.eq_ignore_ascii_case("*")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut current_tag_subtag = tag_iter.next();
|
||||||
|
|
||||||
|
// step 3
|
||||||
|
for range_subtag in range_iter {
|
||||||
|
// step 3a
|
||||||
|
if range_subtag.eq_ignore_ascii_case("*") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match current_tag_subtag.clone() {
|
||||||
|
Some(tag_subtag) => {
|
||||||
|
// step 3c
|
||||||
|
if range_subtag.eq_ignore_ascii_case(tag_subtag) {
|
||||||
|
current_tag_subtag = tag_iter.next();
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// step 3d
|
||||||
|
if tag_subtag.len() == 1 {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// else step 3e - continue with loop
|
||||||
|
current_tag_subtag = tag_iter.next();
|
||||||
|
if current_tag_subtag.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// step 3b
|
||||||
|
None => { return false; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// step 4
|
||||||
|
true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue