mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 21:57:04 +00:00
Merge pull request #7745 from dotCooCoo/fix/svg-css-not-rule-budget
SVG import: :not() rules test only the rules indexed for the element
This commit is contained in:
@@ -556,10 +556,12 @@ impl Styles {
|
||||
}
|
||||
|
||||
/// The properties rules with a `:not()` set on `n`, each with its value after the cascade.
|
||||
/// Only the rules [`Index::candidates`] gives for `n` are tested, as in [`Styles::matched_bytes`].
|
||||
pub(super) fn set_by_not_rules(&self, n: XNode) -> Vec<(String, String)> {
|
||||
let declared = self.declared(n);
|
||||
let mut out: Vec<(String, String)> = Vec::new();
|
||||
for r in self.rules.iter().filter(|r| r.selector.has_not() && r.selector.matches(n)) {
|
||||
let rules = self.index.candidates(n).into_iter().filter_map(|i| self.rules.get(i));
|
||||
for r in rules.filter(|r| r.selector.has_not() && r.selector.matches(n)) {
|
||||
for (k, ..) in r.decls.iter() {
|
||||
if !out.iter().any(|(o, _)| o == k)
|
||||
&& let Some(v) = declared.get(k)
|
||||
|
||||
@@ -334,6 +334,26 @@ fn not_selectors() {
|
||||
);
|
||||
}
|
||||
|
||||
/// The `:not()` rules filed under classes an element lacks are not tested against it, so
|
||||
/// [`Styles::set_by_not_rules`] tests no more rules than [`Styles::matched_bytes`] counts.
|
||||
#[test]
|
||||
fn not_rules_test_only_the_indexed_candidates() {
|
||||
const N: usize = 2_000;
|
||||
let rules: String = (0..N).map(|i| format!(".c{i}:not(.skip) {{ fill: #{i:06x} }}\n")).collect();
|
||||
let rects: String = (0..N).map(|i| format!(r#"<rect id="r{i}" class="c{i}"/>"#)).collect();
|
||||
let svg = format!(r#"<svg xmlns="http://www.w3.org/2000/svg"><style>{rules}</style>{rects}<rect id="skip" class="c0 skip"/></svg>"#);
|
||||
with_doc(&svg, |doc, st| {
|
||||
let before = selector_tests();
|
||||
for i in 0..N {
|
||||
assert_eq!(st.set_by_not_rules(by_id(doc, &format!("r{i}"))), [("fill".to_string(), format!("#{i:06x}"))]);
|
||||
}
|
||||
assert!(st.set_by_not_rules(by_id(doc, "skip")).is_empty());
|
||||
// Testing every `:not()` rule against every element would test N × N selectors.
|
||||
let tests = selector_tests() - before;
|
||||
assert!(tests <= 3 * N as u64, "finding the :not() rules of {N} elements tested {tests} selectors");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decl_comments_are_stripped() {
|
||||
let d = |k: &str, v: &str| (k.to_string(), v.to_string(), false);
|
||||
|
||||
Reference in New Issue
Block a user