Skip to content

Commit c9d2aac

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

File tree

5 files changed

+108
-23
lines changed

5 files changed

+108
-23
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, T: StyleNode>(
794794
&self,
795-
query: &StyleQuery,
795+
query: &StyleQuery<T>,
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, T: StyleNode>(
806806
&self,
807-
query: &[StyleQuery],
807+
query: &[StyleQuery<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: &[StyleQuery<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: &[StyleQuery<T>],
851851
media_query_status: &MediaQueryStatus<L>,
852852
node_properties: &mut NodeProperties,
853853
parent_node_properties: Option<&NodeProperties>,

float-pigment-css/src/query.rs

Lines changed: 28 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 StyleQueryAttribute {
89+
fn name(&self) -> &str;
90+
fn value(&self) -> &str;
91+
}
92+
93+
pub trait StyleNode {
94+
type Attribute: StyleQueryAttribute + Sized + Clone;
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, T: StyleNode> {
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 [T::Attribute],
107+
}
108+
109+
impl<'a, T: StyleNode> Clone for StyleQuery<'a, T> {
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+
}
99121
}
100122

101-
impl<'a> StyleQuery<'a> {
123+
impl<'a, T: StyleNode> StyleQuery<'a, T> {
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 [T::Attribute],
111133
) -> Self {
112134
Self {
113135
style_scope,

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

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

Lines changed: 66 additions & 3 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, StyleQuery, StyleQueryAttribute};
1414

1515
#[cfg_attr(debug_assertions, compatibility_enum_check(selector))]
1616
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
@@ -367,9 +367,9 @@ impl Selector {
367367
}
368368
ret
369369
}
370-
pub(crate) fn match_query(
370+
pub(crate) fn match_query<T: StyleNode>(
371371
&self,
372-
query: &[StyleQuery],
372+
query: &[StyleQuery<T>],
373373
sheet_style_scope: Option<NonZeroUsize>,
374374
) -> Option<u16> {
375375
let mut cur_weight = 0;
@@ -409,6 +409,69 @@ impl Selector {
409409
matches = false;
410410
}
411411
}
412+
413+
if matches {
414+
if let Some(selector_attributes) = &cur_frag.attributes {
415+
for attribute in selector_attributes.iter() {
416+
let selector_attr_value =
417+
attribute.value.as_deref().unwrap_or_default();
418+
if let Some(element_attr) = cur_query
419+
.attributes
420+
.iter()
421+
.find(|x| x.name() == &attribute.name)
422+
{
423+
let element_attr_value = element_attr.value();
424+
if !match attribute.operator {
425+
AttributeOperator::Set => true,
426+
AttributeOperator::Exact => {
427+
element_attr_value == selector_attr_value
428+
}
429+
AttributeOperator::List => {
430+
if selector_attr_value.is_empty() {
431+
false
432+
} else {
433+
element_attr
434+
.value()
435+
.split(SELECTOR_WHITESPACE)
436+
.any(|x| x == selector_attr_value)
437+
}
438+
}
439+
AttributeOperator::Hyphen => {
440+
if element_attr_value.len()
441+
< selector_attr_value.len()
442+
{
443+
false
444+
} else if element_attr_value.len()
445+
== selector_attr_value.len()
446+
{
447+
element_attr_value == selector_attr_value
448+
} else {
449+
element_attr_value.starts_with(
450+
&alloc::format!(
451+
"{}-",
452+
selector_attr_value
453+
),
454+
)
455+
}
456+
}
457+
AttributeOperator::Begin => element_attr_value
458+
.starts_with(selector_attr_value),
459+
AttributeOperator::End => element_attr_value
460+
.ends_with(selector_attr_value),
461+
AttributeOperator::Contain => {
462+
element_attr_value.contains(selector_attr_value)
463+
}
464+
} {
465+
matches = false;
466+
break;
467+
}
468+
} else {
469+
matches = false;
470+
break;
471+
}
472+
}
473+
}
474+
}
412475
}
413476
if !matches {
414477
if allow_ancestor {

0 commit comments

Comments
 (0)