[librsvg: 10/11] (#483): Support attribute matching selectors




commit 4683044f09b41cc7904cfbf543b539c0abdf8153
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Sep 7 17:35:36 2020 -0500

    (#483): Support attribute matching selectors
    
    This implements selectors::Element::attr_matches().
    
    Fixes https://gitlab.gnome.org/GNOME/librsvg/-/issues/483

 rsvg_internals/src/css.rs                          |  26 ++++++++++++++----
 rsvg_internals/src/element.rs                      |  30 ++++++++++++++-------
 .../reftests/483-attribute-selectors-ref.png       | Bin 0 -> 334 bytes
 .../fixtures/reftests/483-attribute-selectors.svg  |  23 ++++++++++++++++
 4 files changed, 64 insertions(+), 15 deletions(-)
---
diff --git a/rsvg_internals/src/css.rs b/rsvg_internals/src/css.rs
index da32460e..f1c91e35 100644
--- a/rsvg_internals/src/css.rs
+++ b/rsvg_internals/src/css.rs
@@ -464,12 +464,28 @@ impl selectors::Element for RsvgElement {
 
     fn attr_matches(
         &self,
-        _ns: &NamespaceConstraint<&Namespace>,
-        _local_name: &LocalName,
-        _operation: &AttrSelectorOperation<&String>,
+        ns: &NamespaceConstraint<&Namespace>,
+        local_name: &LocalName,
+        operation: &AttrSelectorOperation<&String>,
     ) -> bool {
-        // unsupported
-        false
+        self.0
+            .borrow_element()
+            .get_attributes()
+            .iter()
+            .find(|(attr, _)| {
+                // do we have an attribute that matches the namespace and local_name?
+                match *ns {
+                    NamespaceConstraint::Any => *local_name == attr.local,
+                    NamespaceConstraint::Specific(ns) => {
+                        QualName::new(None, ns.clone(), local_name.clone()) == *attr
+                    }
+                }
+            })
+            .map(|(_, value)| {
+                // we have one; does the attribute's value match the expected operation?
+                operation.eval_str(value)
+            })
+            .unwrap_or(false)
     }
 
     fn match_non_ts_pseudo_class<F>(
diff --git a/rsvg_internals/src/element.rs b/rsvg_internals/src/element.rs
index aa7e6e8f..20f467ea 100644
--- a/rsvg_internals/src/element.rs
+++ b/rsvg_internals/src/element.rs
@@ -192,17 +192,16 @@ impl<T: SetAttributes + Draw> ElementInner<T> {
                 .iter()
                 .find(|(attr, _)| attr.expanded() == expanded_name!("", "style"))
                 .map(|(_, value)| value)
-                .unwrap_or("")
+                .unwrap_or(""),
         );
     }
 
     fn set_transform_attribute(&mut self) -> Result<(), ElementError> {
-        self.transform = self.attributes
+        self.transform = self
+            .attributes
             .iter()
             .find(|(attr, _)| attr.expanded() == expanded_name!("", "transform"))
-            .map(|(attr, value)| {
-                Transform::parse_str(value).attribute(attr)
-            })
+            .map(|(attr, value)| Transform::parse_str(value).attribute(attr))
             .unwrap_or_else(|| Ok(Transform::default()))?;
 
         Ok(())
@@ -215,17 +214,20 @@ impl<T: SetAttributes + Draw> ElementInner<T> {
             match attr.expanded() {
                 expanded_name!("", "requiredExtensions") if cond => {
                     cond = RequiredExtensions::from_attribute(value)
-                        .map(|RequiredExtensions(res)| res).attribute(attr)?;
+                        .map(|RequiredExtensions(res)| res)
+                        .attribute(attr)?;
                 }
 
                 expanded_name!("", "requiredFeatures") if cond => {
                     cond = RequiredFeatures::from_attribute(value)
-                        .map(|RequiredFeatures(res)| res).attribute(attr)?;
+                        .map(|RequiredFeatures(res)| res)
+                        .attribute(attr)?;
                 }
 
                 expanded_name!("", "systemLanguage") if cond => {
                     cond = SystemLanguage::from_attribute(value, &LOCALE)
-                        .map(|SystemLanguage(res)| res).attribute(attr)?;
+                        .map(|SystemLanguage(res)| res)
+                        .attribute(attr)?;
                 }
 
                 _ => {}
@@ -239,7 +241,10 @@ impl<T: SetAttributes + Draw> ElementInner<T> {
 
     /// Hands the `attrs` to the node's state, to apply the presentation attributes.
     fn set_presentation_attributes(&mut self) -> Result<(), ElementError> {
-        match self.specified_values.parse_presentation_attributes(&self.attributes) {
+        match self
+            .specified_values
+            .parse_presentation_attributes(&self.attributes)
+        {
             Ok(_) => Ok(()),
             Err(e) => {
                 // FIXME: we'll ignore errors here for now.
@@ -638,7 +643,12 @@ impl fmt::Display for Element {
 
 macro_rules! e {
     ($name:ident, $element_type:ident) => {
-        pub fn $name(element_name: &QualName, attributes: Attributes, id: Option<String>, class: 
Option<String>) -> Element {
+        pub fn $name(
+            element_name: &QualName,
+            attributes: Attributes,
+            id: Option<String>,
+            class: Option<String>,
+        ) -> Element {
             let mut element_impl = <$element_type>::default();
 
             let result = element_impl.set_attributes(&attributes);
diff --git a/tests/fixtures/reftests/483-attribute-selectors-ref.png 
b/tests/fixtures/reftests/483-attribute-selectors-ref.png
new file mode 100644
index 00000000..63f8a370
Binary files /dev/null and b/tests/fixtures/reftests/483-attribute-selectors-ref.png differ
diff --git a/tests/fixtures/reftests/483-attribute-selectors.svg 
b/tests/fixtures/reftests/483-attribute-selectors.svg
new file mode 100644
index 00000000..5b3230c9
--- /dev/null
+++ b/tests/fixtures/reftests/483-attribute-selectors.svg
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"; width="150" height="100">
+  <style type="text/css">
+    rect[id] { fill: blue; }
+
+    rect[id="rojo"] { fill: red; }
+    rect[id|="rojo"] { fill: red; }
+
+    rect[id^="verde"] { fill: lime; }
+    rect[id$="verde"] { fill: lime; }
+
+    rect[id*="azul"] { fill: blue; }
+  </style>
+
+  <rect x="0" y="0" width="50" height="50" id="rojo"/>
+  <rect x="0" y="50" width="50" height="50" id="rojo-jojojo"/>
+
+  <rect x="50" y="0" width="50" height="50" id="verdecito"/>
+  <rect x="50" y="50" width="50" height="50" id="superverde"/>
+
+  <rect x="100" y="0" width="50" height="50" id="cualquier_cosa"/>
+  <rect x="100" y="50" width="50" height="50" id="superazulito"/>
+</svg>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]