Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions float-pigment-css/src/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,21 +790,21 @@ impl StyleSheetGroup {
/// Query a single node selector (usually for testing only).
///
/// Note that the font size and `em` values will be converted to `px` values.
pub fn query_single<L: LengthNum>(
pub fn query_single<L: LengthNum, T: StyleNode>(
&self,
query: &StyleQuery,
query: T,
media_query_status: &MediaQueryStatus<L>,
node_properties: &mut NodeProperties,
) {
self.query_ancestor_path(&[query.clone()], media_query_status, node_properties, None)
self.query_ancestor_path(&[query], media_query_status, node_properties, None)
}

/// Find rules that matches the query.
///
/// The query is a `&[StyleQuery]` which means all selector information of the ancestors and the node itself.
pub fn for_each_matched_rule<L: LengthNum>(
pub fn for_each_matched_rule<L: LengthNum, T: StyleNode>(
&self,
query: &[StyleQuery],
query: &[T],
media_query_status: &MediaQueryStatus<L>,
mut f: impl FnMut(MatchedRuleRef, Option<&LinkedStyleSheet>),
) {
Expand All @@ -824,9 +824,9 @@ impl StyleSheetGroup {
/// Get a rule list that matches the query.
///
/// The query is a `&[StyleQuery]` which means all selector information of the ancestors and the node itself.
pub fn query_matched_rules<L: LengthNum>(
pub fn query_matched_rules<L: LengthNum, T: StyleNode>(
&self,
query: &[StyleQuery],
query: &[T],
media_query_status: &MediaQueryStatus<L>,
) -> MatchedRuleList {
let mut rules = vec![];
Expand All @@ -845,9 +845,9 @@ impl StyleSheetGroup {
///
/// The query is a `&[StyleQuery]` which means all selector information of the ancestors and the node itself.
/// Note that the font size and `em` values will be converted to `px` values.
pub fn query_ancestor_path<L: LengthNum>(
pub fn query_ancestor_path<L: LengthNum, T: StyleNode>(
&self,
query: &[StyleQuery],
query: &[T],
media_query_status: &MediaQueryStatus<L>,
node_properties: &mut NodeProperties,
parent_node_properties: Option<&NodeProperties>,
Expand Down
4 changes: 2 additions & 2 deletions float-pigment-css/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1611,15 +1611,15 @@ fn parse_attribute_selector<'a, 't: 'a, 'i: 't>(
// [name=value]
Ok(&Token::Delim('=')) => AttributeOperator::Exact,
// [name~=value]
Ok(&Token::IncludeMatch) => AttributeOperator::Contain,
Ok(&Token::IncludeMatch) => AttributeOperator::List,
// [name|=value]
Ok(&Token::DashMatch) => AttributeOperator::Hyphen,
// [name^=value]
Ok(&Token::PrefixMatch) => AttributeOperator::Begin,
// [name$=value]
Ok(&Token::SuffixMatch) => AttributeOperator::End,
// [name*=value]
Ok(&Token::SubstringMatch) => AttributeOperator::List,
Ok(&Token::SubstringMatch) => AttributeOperator::Contain,
Ok(_) => {
return Err(location.new_custom_error(CustomError::UnexpectedTokenInAttributeSelector))
}
Expand Down
169 changes: 159 additions & 10 deletions float-pigment-css/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,103 @@ impl<L: LengthNum> MediaQueryStatus<L> {
}
}

pub trait StyleNodeClass {
fn name(&self) -> &str;
fn scope(&self) -> Option<NonZeroUsize>;
}

impl StyleNodeClass for (String, Option<NonZeroUsize>) {
fn name(&self) -> &str {
&self.0
}

fn scope(&self) -> Option<NonZeroUsize> {
self.1
}
}

pub enum StyleNodeAttributeCaseSensitivity {
CaseSensitive,
CaseInsensitive,
}

impl StyleNodeAttributeCaseSensitivity {
pub fn eq(&self, a: &str, b: &str) -> bool {
match self {
Self::CaseSensitive => a == b,
Self::CaseInsensitive => a.eq_ignore_ascii_case(b),
}
}

pub fn starts_with(&self, a: &str, b: &str) -> bool {
// FIXME: reduce memory allocation
match self {
Self::CaseSensitive => a.starts_with(b),
Self::CaseInsensitive => a.to_ascii_lowercase().starts_with(&b.to_ascii_lowercase()),
}
}

pub fn ends_with(&self, a: &str, b: &str) -> bool {
// FIXME: reduce memory allocation
match self {
Self::CaseSensitive => a.ends_with(b),
Self::CaseInsensitive => a.to_ascii_lowercase().ends_with(&b.to_ascii_lowercase()),
}
}

pub fn contains(&self, a: &str, b: &str) -> bool {
// FIXME: reduce memory allocation
match self {
Self::CaseSensitive => a.contains(b),
Self::CaseInsensitive => a.to_ascii_lowercase().contains(&b.to_ascii_lowercase()),
}
}
}

pub trait StyleNode {
type Class: StyleNodeClass;
type ClassIter<'a>: Iterator<Item = &'a Self::Class>
where
Self: 'a;

fn style_scope(&self) -> Option<NonZeroUsize>;
fn extra_style_scope(&self) -> Option<NonZeroUsize>;
fn host_style_scope(&self) -> Option<NonZeroUsize>;
fn tag_name(&self) -> &str;
fn id(&self) -> Option<&str>;
fn classes(&self) -> Self::ClassIter<'_>;
fn attribute(&self, name: &str) -> Option<(&str, StyleNodeAttributeCaseSensitivity)>;

fn contain_scope(&self, scope: Option<NonZeroUsize>) -> bool {
scope.is_none()
|| self.style_scope() == scope
|| self.extra_style_scope() == scope
|| self.host_style_scope() == scope
}
}

/// Represents node information, used for matching rules.
#[derive(Clone, Debug)]
#[derive(Debug)]
pub struct StyleQuery<'a> {
pub(super) style_scope: Option<NonZeroUsize>,
pub(super) extra_style_scope: Option<NonZeroUsize>,
pub(super) host_style_scope: Option<NonZeroUsize>,
pub(super) tag_name: &'a str,
pub(super) id: &'a str,
pub(super) classes: &'a [(String, Option<NonZeroUsize>)],
#[allow(unused)]
pub(super) attributes: &'a [String], // TODO support attributes
}

impl Clone for StyleQuery<'_> {
fn clone(&self) -> Self {
Self {
style_scope: self.style_scope,
extra_style_scope: self.extra_style_scope,
host_style_scope: self.host_style_scope,
tag_name: self.tag_name,
id: self.id,
classes: self.classes,
}
}
}

impl<'a> StyleQuery<'a> {
Expand All @@ -107,7 +193,6 @@ impl<'a> StyleQuery<'a> {
tag_name: &'a str,
id: &'a str,
classes: &'a [(String, Option<NonZeroUsize>)],
attributes: &'a [String],
) -> Self {
Self {
style_scope,
Expand All @@ -116,15 +201,79 @@ impl<'a> StyleQuery<'a> {
tag_name,
id,
classes,
attributes,
}
}
}

pub(crate) fn contain_scope(&self, scope: Option<NonZeroUsize>) -> bool {
scope.is_none()
|| self.style_scope == scope
|| self.extra_style_scope == scope
|| self.host_style_scope == scope
impl<'a> StyleNode for StyleQuery<'a> {
type Class = (String, Option<NonZeroUsize>);
type ClassIter<'c>
= core::slice::Iter<'c, Self::Class>
where
'a: 'c;

fn style_scope(&self) -> Option<NonZeroUsize> {
self.style_scope
}

fn extra_style_scope(&self) -> Option<NonZeroUsize> {
self.extra_style_scope
}

fn host_style_scope(&self) -> Option<NonZeroUsize> {
self.host_style_scope
}

fn tag_name(&self) -> &str {
self.tag_name
}

fn id(&self) -> Option<&str> {
Some(self.id)
}

fn classes(&self) -> Self::ClassIter<'_> {
self.classes.iter()
}

fn attribute(&self, name: &str) -> Option<(&str, StyleNodeAttributeCaseSensitivity)> {
None
}
}

impl<'b, 'a: 'b> StyleNode for &'b StyleQuery<'a> {
type Class = (String, Option<NonZeroUsize>);
type ClassIter<'c>
= core::slice::Iter<'c, Self::Class>
where
'b: 'c;

fn style_scope(&self) -> Option<NonZeroUsize> {
self.style_scope
}

fn extra_style_scope(&self) -> Option<NonZeroUsize> {
self.extra_style_scope
}

fn host_style_scope(&self) -> Option<NonZeroUsize> {
self.host_style_scope
}

fn tag_name(&self) -> &str {
self.tag_name
}

fn id(&self) -> Option<&str> {
Some(self.id)
}

fn classes(&self) -> Self::ClassIter<'_> {
self.classes.iter()
}

fn attribute(&self, name: &str) -> Option<(&str, StyleNodeAttributeCaseSensitivity)> {
None
}
}

Expand Down
14 changes: 7 additions & 7 deletions float-pigment-css/src/sheet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,9 @@ impl LinkedStyleSheet {
Err(rule)
}

pub(crate) fn for_each_matched_rule<L: LengthNum>(
pub(crate) fn for_each_matched_rule<L: LengthNum, T: StyleNode>(
&self,
query: &[StyleQuery],
query: &[T],
media_query_status: &MediaQueryStatus<L>,
sheet_index: u16,
mut f: impl FnMut(MatchedRuleRef),
Expand Down Expand Up @@ -552,9 +552,9 @@ impl StyleSheet {
}
}

fn for_each_matched_rule<L: LengthNum>(
fn for_each_matched_rule<L: LengthNum, T: StyleNode>(
&mut self,
query: &[StyleQuery],
query: &[T],
media_query_status: &MediaQueryStatus<L>,
sheet_style_scope: Option<NonZeroUsize>,
sheet_index: u16,
Expand Down Expand Up @@ -589,9 +589,9 @@ impl StyleSheet {
Some(x) => x,
None => return,
};
for (class, scope) in query_last.classes.iter() {
if sheet_style_scope.is_none() || sheet_style_scope == *scope {
if let Some(rules) = class_index.get(class) {
for class in query_last.classes() {
if sheet_style_scope.is_none() || sheet_style_scope == class.scope() {
if let Some(rules) = class_index.get(class.name()) {
for r in rules {
if let Some(selector_weight) =
r.match_query(query, media_query_status, sheet_style_scope)
Expand Down
4 changes: 2 additions & 2 deletions float-pigment-css/src/sheet/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,9 +457,9 @@ impl Rule {
self.properties.iter()
}

pub(crate) fn match_query<L: LengthNum>(
pub(crate) fn match_query<L: LengthNum, T: StyleNode>(
&self,
query: &[StyleQuery],
query: &[T],
media_query_status: &MediaQueryStatus<L>,
sheet_style_scope: Option<NonZeroUsize>,
) -> Option<u16> {
Expand Down
Loading
Loading