Skip to content

Commit fe981cb

Browse files
committed
feat: impl attribute matching
1 parent 9623a3c commit fe981cb

File tree

11 files changed

+363
-101
lines changed

11 files changed

+363
-101
lines changed

float-pigment-css/src/group.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -790,21 +790,21 @@ impl StyleSheetGroup {
790790
/// Query a single node selector (usually for testing only).
791791
///
792792
/// Note that the font size and `em` values will be converted to `px` values.
793-
pub fn query_single<L: LengthNum>(
793+
pub fn query_single<L: LengthNum, T: StyleNode>(
794794
&self,
795-
query: &StyleQuery,
795+
query: T,
796796
media_query_status: &MediaQueryStatus<L>,
797797
node_properties: &mut NodeProperties,
798798
) {
799-
self.query_ancestor_path(&[query.clone()], media_query_status, node_properties, None)
799+
self.query_ancestor_path(&[query], media_query_status, node_properties, None)
800800
}
801801

802802
/// Find rules that matches the query.
803803
///
804804
/// The query is a `&[StyleQuery]` which means all selector information of the ancestors and the node itself.
805-
pub fn for_each_matched_rule<L: LengthNum>(
805+
pub fn for_each_matched_rule<L: LengthNum, T: StyleNode>(
806806
&self,
807-
query: &[StyleQuery],
807+
query: &[T],
808808
media_query_status: &MediaQueryStatus<L>,
809809
mut f: impl FnMut(MatchedRuleRef, Option<&LinkedStyleSheet>),
810810
) {
@@ -824,9 +824,9 @@ impl StyleSheetGroup {
824824
/// Get a rule list that matches the query.
825825
///
826826
/// The query is a `&[StyleQuery]` which means all selector information of the ancestors and the node itself.
827-
pub fn query_matched_rules<L: LengthNum>(
827+
pub fn query_matched_rules<L: LengthNum, T: StyleNode>(
828828
&self,
829-
query: &[StyleQuery],
829+
query: &[T],
830830
media_query_status: &MediaQueryStatus<L>,
831831
) -> MatchedRuleList {
832832
let mut rules = vec![];
@@ -845,9 +845,9 @@ impl StyleSheetGroup {
845845
///
846846
/// The query is a `&[StyleQuery]` which means all selector information of the ancestors and the node itself.
847847
/// Note that the font size and `em` values will be converted to `px` values.
848-
pub fn query_ancestor_path<L: LengthNum>(
848+
pub fn query_ancestor_path<L: LengthNum, T: StyleNode>(
849849
&self,
850-
query: &[StyleQuery],
850+
query: &[T],
851851
media_query_status: &MediaQueryStatus<L>,
852852
node_properties: &mut NodeProperties,
853853
parent_node_properties: Option<&NodeProperties>,

float-pigment-css/src/parser/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,15 +1611,15 @@ fn parse_attribute_selector<'a, 't: 'a, 'i: 't>(
16111611
// [name=value]
16121612
Ok(&Token::Delim('=')) => AttributeOperator::Exact,
16131613
// [name~=value]
1614-
Ok(&Token::IncludeMatch) => AttributeOperator::Contain,
1614+
Ok(&Token::IncludeMatch) => AttributeOperator::List,
16151615
// [name|=value]
16161616
Ok(&Token::DashMatch) => AttributeOperator::Hyphen,
16171617
// [name^=value]
16181618
Ok(&Token::PrefixMatch) => AttributeOperator::Begin,
16191619
// [name$=value]
16201620
Ok(&Token::SuffixMatch) => AttributeOperator::End,
16211621
// [name*=value]
1622-
Ok(&Token::SubstringMatch) => AttributeOperator::List,
1622+
Ok(&Token::SubstringMatch) => AttributeOperator::Contain,
16231623
Ok(_) => {
16241624
return Err(location.new_custom_error(CustomError::UnexpectedTokenInAttributeSelector))
16251625
}

float-pigment-css/src/query.rs

Lines changed: 121 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,17 +85,65 @@ impl<L: LengthNum> MediaQueryStatus<L> {
8585
}
8686
}
8787

88+
pub trait StyleNodeClass {
89+
fn name(&self) -> &str;
90+
fn scope(&self) -> Option<NonZeroUsize>;
91+
}
92+
93+
impl StyleNodeClass for (String, Option<NonZeroUsize>) {
94+
fn name(&self) -> &str {
95+
&self.0
96+
}
97+
98+
fn scope(&self) -> Option<NonZeroUsize> {
99+
self.1
100+
}
101+
}
102+
103+
pub trait StyleNode {
104+
type Class: StyleNodeClass;
105+
type ClassIter<'a>: Iterator<Item = &'a Self::Class>
106+
where
107+
Self: 'a;
108+
109+
fn style_scope(&self) -> Option<NonZeroUsize>;
110+
fn extra_style_scope(&self) -> Option<NonZeroUsize>;
111+
fn host_style_scope(&self) -> Option<NonZeroUsize>;
112+
fn tag_name(&self) -> &str;
113+
fn id(&self) -> Option<&str>;
114+
fn classes(&self) -> Self::ClassIter<'_>;
115+
fn attribute(&self, name: &str) -> Option<&str>;
116+
117+
fn contain_scope(&self, scope: Option<NonZeroUsize>) -> bool {
118+
scope.is_none()
119+
|| self.style_scope() == scope
120+
|| self.extra_style_scope() == scope
121+
|| self.host_style_scope() == scope
122+
}
123+
}
124+
88125
/// Represents node information, used for matching rules.
89-
#[derive(Clone, Debug)]
126+
#[derive(Debug)]
90127
pub struct StyleQuery<'a> {
91128
pub(super) style_scope: Option<NonZeroUsize>,
92129
pub(super) extra_style_scope: Option<NonZeroUsize>,
93130
pub(super) host_style_scope: Option<NonZeroUsize>,
94131
pub(super) tag_name: &'a str,
95132
pub(super) id: &'a str,
96133
pub(super) classes: &'a [(String, Option<NonZeroUsize>)],
97-
#[allow(unused)]
98-
pub(super) attributes: &'a [String], // TODO support attributes
134+
}
135+
136+
impl Clone for StyleQuery<'_> {
137+
fn clone(&self) -> Self {
138+
Self {
139+
style_scope: self.style_scope,
140+
extra_style_scope: self.extra_style_scope,
141+
host_style_scope: self.host_style_scope,
142+
tag_name: self.tag_name,
143+
id: self.id,
144+
classes: self.classes,
145+
}
146+
}
99147
}
100148

101149
impl<'a> StyleQuery<'a> {
@@ -107,7 +155,6 @@ impl<'a> StyleQuery<'a> {
107155
tag_name: &'a str,
108156
id: &'a str,
109157
classes: &'a [(String, Option<NonZeroUsize>)],
110-
attributes: &'a [String],
111158
) -> Self {
112159
Self {
113160
style_scope,
@@ -116,15 +163,79 @@ impl<'a> StyleQuery<'a> {
116163
tag_name,
117164
id,
118165
classes,
119-
attributes,
120166
}
121167
}
168+
}
169+
170+
impl<'a> StyleNode for StyleQuery<'a> {
171+
type Class = (String, Option<NonZeroUsize>);
172+
type ClassIter<'c>
173+
= core::slice::Iter<'c, Self::Class>
174+
where
175+
'a: 'c;
176+
177+
fn style_scope(&self) -> Option<NonZeroUsize> {
178+
self.style_scope
179+
}
122180

123-
pub(crate) fn contain_scope(&self, scope: Option<NonZeroUsize>) -> bool {
124-
scope.is_none()
125-
|| self.style_scope == scope
126-
|| self.extra_style_scope == scope
127-
|| self.host_style_scope == scope
181+
fn extra_style_scope(&self) -> Option<NonZeroUsize> {
182+
self.extra_style_scope
183+
}
184+
185+
fn host_style_scope(&self) -> Option<NonZeroUsize> {
186+
self.host_style_scope
187+
}
188+
189+
fn tag_name(&self) -> &str {
190+
self.tag_name
191+
}
192+
193+
fn id(&self) -> Option<&str> {
194+
Some(self.id)
195+
}
196+
197+
fn classes(&self) -> Self::ClassIter<'_> {
198+
self.classes.iter()
199+
}
200+
201+
fn attribute(&self, name: &str) -> Option<&str> {
202+
None
203+
}
204+
}
205+
206+
impl<'b, 'a: 'b> StyleNode for &'b StyleQuery<'a> {
207+
type Class = (String, Option<NonZeroUsize>);
208+
type ClassIter<'c>
209+
= core::slice::Iter<'c, Self::Class>
210+
where
211+
'b: 'c;
212+
213+
fn style_scope(&self) -> Option<NonZeroUsize> {
214+
self.style_scope
215+
}
216+
217+
fn extra_style_scope(&self) -> Option<NonZeroUsize> {
218+
self.extra_style_scope
219+
}
220+
221+
fn host_style_scope(&self) -> Option<NonZeroUsize> {
222+
self.host_style_scope
223+
}
224+
225+
fn tag_name(&self) -> &str {
226+
self.tag_name
227+
}
228+
229+
fn id(&self) -> Option<&str> {
230+
Some(self.id)
231+
}
232+
233+
fn classes(&self) -> Self::ClassIter<'_> {
234+
self.classes.iter()
235+
}
236+
237+
fn attribute(&self, name: &str) -> Option<&str> {
238+
None
128239
}
129240
}
130241

float-pigment-css/src/sheet/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,9 @@ impl LinkedStyleSheet {
365365
Err(rule)
366366
}
367367

368-
pub(crate) fn for_each_matched_rule<L: LengthNum>(
368+
pub(crate) fn for_each_matched_rule<L: LengthNum, T: StyleNode>(
369369
&self,
370-
query: &[StyleQuery],
370+
query: &[T],
371371
media_query_status: &MediaQueryStatus<L>,
372372
sheet_index: u16,
373373
mut f: impl FnMut(MatchedRuleRef),
@@ -552,9 +552,9 @@ impl StyleSheet {
552552
}
553553
}
554554

555-
fn for_each_matched_rule<L: LengthNum>(
555+
fn for_each_matched_rule<L: LengthNum, T: StyleNode>(
556556
&mut self,
557-
query: &[StyleQuery],
557+
query: &[T],
558558
media_query_status: &MediaQueryStatus<L>,
559559
sheet_style_scope: Option<NonZeroUsize>,
560560
sheet_index: u16,
@@ -589,9 +589,9 @@ impl StyleSheet {
589589
Some(x) => x,
590590
None => return,
591591
};
592-
for (class, scope) in query_last.classes.iter() {
593-
if sheet_style_scope.is_none() || sheet_style_scope == *scope {
594-
if let Some(rules) = class_index.get(class) {
592+
for class in query_last.classes() {
593+
if sheet_style_scope.is_none() || sheet_style_scope == class.scope() {
594+
if let Some(rules) = class_index.get(class.name()) {
595595
for r in rules {
596596
if let Some(selector_weight) =
597597
r.match_query(query, media_query_status, sheet_style_scope)

float-pigment-css/src/sheet/rule.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,9 +457,9 @@ impl Rule {
457457
self.properties.iter()
458458
}
459459

460-
pub(crate) fn match_query<L: LengthNum>(
460+
pub(crate) fn match_query<L: LengthNum, T: StyleNode>(
461461
&self,
462-
query: &[StyleQuery],
462+
query: &[T],
463463
media_query_status: &MediaQueryStatus<L>,
464464
sheet_style_scope: Option<NonZeroUsize>,
465465
) -> Option<u16> {

0 commit comments

Comments
 (0)