Skip to content

Commit 002242f

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

File tree

11 files changed

+240
-90
lines changed

11 files changed

+240
-90
lines changed

float-pigment-css/src/group.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -790,9 +790,9 @@ 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, A: StyleNodeAttribute>(
794794
&self,
795-
query: &StyleQuery,
795+
query: &StyleQuery<A>,
796796
media_query_status: &MediaQueryStatus<L>,
797797
node_properties: &mut NodeProperties,
798798
) {
@@ -802,9 +802,9 @@ impl StyleSheetGroup {
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, A: StyleNodeAttribute>(
806806
&self,
807-
query: &[StyleQuery],
807+
query: &[StyleQuery<A>],
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, A: StyleNodeAttribute>(
828828
&self,
829-
query: &[StyleQuery],
829+
query: &[StyleQuery<A>],
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, A: StyleNodeAttribute>(
849849
&self,
850-
query: &[StyleQuery],
850+
query: &[StyleQuery<A>],
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: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,20 +85,42 @@ impl<L: LengthNum> MediaQueryStatus<L> {
8585
}
8686
}
8787

88+
pub trait StyleNodeAttribute: Sized + Clone {
89+
fn name(&self) -> &str;
90+
fn value(&self) -> &str;
91+
}
92+
93+
pub trait StyleNode {
94+
type Attribute: StyleNodeAttribute;
95+
}
96+
8897
/// Represents node information, used for matching rules.
89-
#[derive(Clone, Debug)]
90-
pub struct StyleQuery<'a> {
98+
#[derive(Debug)]
99+
pub struct StyleQuery<'a, A: StyleNodeAttribute> {
91100
pub(super) style_scope: Option<NonZeroUsize>,
92101
pub(super) extra_style_scope: Option<NonZeroUsize>,
93102
pub(super) host_style_scope: Option<NonZeroUsize>,
94103
pub(super) tag_name: &'a str,
95104
pub(super) id: &'a str,
96105
pub(super) classes: &'a [(String, Option<NonZeroUsize>)],
97-
#[allow(unused)]
98-
pub(super) attributes: &'a [String], // TODO support attributes
106+
pub(super) attributes: &'a [A],
99107
}
100108

101-
impl<'a> StyleQuery<'a> {
109+
impl<'a, A: StyleNodeAttribute> Clone for StyleQuery<'a, A> {
110+
fn clone(&self) -> Self {
111+
Self {
112+
style_scope: self.style_scope,
113+
extra_style_scope: self.extra_style_scope,
114+
host_style_scope: self.host_style_scope,
115+
tag_name: self.tag_name,
116+
id: self.id,
117+
classes: self.classes,
118+
attributes: self.attributes,
119+
}
120+
}
121+
}
122+
123+
impl<'a, A: StyleNodeAttribute> StyleQuery<'a, A> {
102124
/// Constructs a style query from tag name, id, classes, etc.
103125
pub fn single(
104126
style_scope: Option<NonZeroUsize>,
@@ -107,7 +129,7 @@ impl<'a> StyleQuery<'a> {
107129
tag_name: &'a str,
108130
id: &'a str,
109131
classes: &'a [(String, Option<NonZeroUsize>)],
110-
attributes: &'a [String],
132+
attributes: &'a [A],
111133
) -> Self {
112134
Self {
113135
style_scope,
@@ -370,3 +392,31 @@ impl MatchedRuleList {
370392
hasher.finish()
371393
}
372394
}
395+
396+
pub struct StyleNodeDefault;
397+
398+
#[derive(Clone)]
399+
pub struct StyleNodeAttributeDefault {
400+
pub name: String,
401+
pub value: String,
402+
}
403+
404+
impl StyleNodeAttributeDefault {
405+
pub fn new(name: String, value: String) -> Self {
406+
Self { name, value }
407+
}
408+
}
409+
410+
impl StyleNode for StyleNodeDefault {
411+
type Attribute = StyleNodeAttributeDefault;
412+
}
413+
414+
impl StyleNodeAttribute for StyleNodeAttributeDefault {
415+
fn name(&self) -> &str {
416+
&self.name
417+
}
418+
419+
fn value(&self) -> &str {
420+
&self.value
421+
}
422+
}

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

Lines changed: 4 additions & 4 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, A: StyleNodeAttribute>(
369369
&self,
370-
query: &[StyleQuery],
370+
query: &[StyleQuery<A>],
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, A: StyleNodeAttribute>(
556556
&mut self,
557-
query: &[StyleQuery],
557+
query: &[StyleQuery<A>],
558558
media_query_status: &MediaQueryStatus<L>,
559559
sheet_style_scope: Option<NonZeroUsize>,
560560
sheet_index: u16,

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, A: StyleNodeAttribute>(
461461
&self,
462-
query: &[StyleQuery],
462+
query: &[StyleQuery<A>],
463463
media_query_status: &MediaQueryStatus<L>,
464464
sheet_style_scope: Option<NonZeroUsize>,
465465
) -> Option<u16> {

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

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use cssparser::{Parser, ParserInput};
1010
use float_pigment_css_macro::{compatibility_enum_check, compatibility_struct_check};
1111

1212
use crate::parser::{parse_selector, ParseState};
13-
use crate::query::StyleQuery;
13+
use crate::query::{StyleNode, StyleNodeAttribute, StyleQuery};
1414

1515
#[cfg_attr(debug_assertions, compatibility_enum_check(selector))]
1616
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
@@ -248,8 +248,13 @@ impl SelectorFragment {
248248
if !self.id.is_empty() {
249249
weight += 1 << 13;
250250
}
251-
let class_count = self.classes.len();
252-
weight += (class_count.min(0xff) << 5) as u16;
251+
let class_and_attr_count = self.classes.len()
252+
+ self
253+
.attributes
254+
.as_ref()
255+
.map(|a| a.len())
256+
.unwrap_or_default();
257+
weight += (class_and_attr_count.min(0xff) << 5) as u16;
253258
if let Some(ref relation) = self.relation {
254259
weight += match &**relation {
255260
SelectorRelationType::None => 0,
@@ -367,9 +372,9 @@ impl Selector {
367372
}
368373
ret
369374
}
370-
pub(crate) fn match_query(
375+
pub(crate) fn match_query<A: StyleNodeAttribute>(
371376
&self,
372-
query: &[StyleQuery],
377+
query: &[StyleQuery<A>],
373378
sheet_style_scope: Option<NonZeroUsize>,
374379
) -> Option<u16> {
375380
let mut cur_weight = 0;
@@ -409,6 +414,69 @@ impl Selector {
409414
matches = false;
410415
}
411416
}
417+
418+
if matches {
419+
if let Some(selector_attributes) = &cur_frag.attributes {
420+
for attribute in selector_attributes.iter() {
421+
let selector_attr_value =
422+
attribute.value.as_deref().unwrap_or_default();
423+
if let Some(element_attr) = cur_query
424+
.attributes
425+
.iter()
426+
.find(|x| x.name() == &attribute.name)
427+
{
428+
let element_attr_value = element_attr.value();
429+
if !match attribute.operator {
430+
AttributeOperator::Set => true,
431+
AttributeOperator::Exact => {
432+
element_attr_value == selector_attr_value
433+
}
434+
AttributeOperator::List => {
435+
if selector_attr_value.is_empty() {
436+
false
437+
} else {
438+
element_attr
439+
.value()
440+
.split(SELECTOR_WHITESPACE)
441+
.any(|x| x == selector_attr_value)
442+
}
443+
}
444+
AttributeOperator::Hyphen => {
445+
if element_attr_value.len()
446+
< selector_attr_value.len()
447+
{
448+
false
449+
} else if element_attr_value.len()
450+
== selector_attr_value.len()
451+
{
452+
element_attr_value == selector_attr_value
453+
} else {
454+
element_attr_value.starts_with(
455+
&alloc::format!(
456+
"{}-",
457+
selector_attr_value
458+
),
459+
)
460+
}
461+
}
462+
AttributeOperator::Begin => element_attr_value
463+
.starts_with(selector_attr_value),
464+
AttributeOperator::End => element_attr_value
465+
.ends_with(selector_attr_value),
466+
AttributeOperator::Contain => {
467+
element_attr_value.contains(selector_attr_value)
468+
}
469+
} {
470+
matches = false;
471+
break;
472+
}
473+
} else {
474+
matches = false;
475+
break;
476+
}
477+
}
478+
}
479+
}
412480
}
413481
if !matches {
414482
if allow_ancestor {

0 commit comments

Comments
 (0)