]> gitweb.michael.orlitzky.com - libsvgtiny.git/commitdiff
src/svgtiny_css.c: implement node_is_lang() select handler
authorMichael Orlitzky <michael@orlitzky.com>
Tue, 17 Oct 2023 01:22:28 +0000 (21:22 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Mon, 20 Nov 2023 16:42:26 +0000 (11:42 -0500)
src/svgtiny_css.c

index de82a835071e602853810ad0f5e6c38554891fdc..dc2a613ea7878a933121885b066ae59d31879582 100644 (file)
@@ -54,6 +54,8 @@ static css_error node_is_enabled(void *pw, void *node, bool *is_enabled);
 static css_error node_is_disabled(void *pw, void *node, bool *is_disabled);
 static css_error node_is_checked(void *pw, void *node, bool *is_checked);
 static css_error node_is_target(void *pw, void *node, bool *is_target);
+static css_error node_is_lang(void *pw, void *node,
+               lwc_string *lang, bool *is_lang);
 
 
 /**
@@ -1657,3 +1659,86 @@ css_error node_is_target(void *pw, void *node, bool *is_target)
        *is_target = false;
        return CSS_OK;
 }
+
+
+/**
+ * Check if the given node is the given language
+ *
+ * This test is corresponds to the CSS :lang() selector and is not
+ * fully implemented yet: it looks only for "lang" attributes on the
+ * given element and its parents, and performs a simple substring
+ * check. This results in a partial implementation of CSS Level 3 for
+ * SVG 2.0. In particular, it ignores all "xml:lang" attributes in
+ * favor of the "lang" attribute that is defined only in SVG 2.0.
+ *
+ * \param pw            Pointer to the current SVG parser state; unused
+ * \param node          Libdom SVG node to check
+ * \param lang          The language to match
+ * \param is_lang       Pointer to the boolean return value
+ *
+ * \return CSS_OK on success, or CSS_NOMEM if anything goes wrong
+ */
+static css_error node_is_lang(void *pw, void *node,
+               lwc_string *lang, bool *is_lang)
+{
+       UNUSED(pw);
+       /* SVG2 elements support both "lang" and "xml:lang"
+        * attributes; earlier versions have only the XML
+        * attribute. It would not be too hard to add support for
+        * xml:lang" here. The main difficulty standing in the way of
+        * a full Level 4 implementation is the complexity of the
+        * :lang() selector:
+        *
+        *   https://www.w3.org/TR/selectors-4/#the-lang-pseudo
+        *
+        */
+
+       css_error c_err;
+       dom_exception d_err;
+       dom_node *n; /* current node */
+       dom_node *p; /* parent node */
+       bool match;  /* retval from node_has_attribute_substring() */
+
+       /* Define the attribute name "lang" that we're looking for.
+        * We only use a css_qname here because that's what the
+        * node_has_attribute_substring() takes; the namespace
+        * portion of it is irrelevant. */
+       css_qname attr;
+       attr.ns = NULL;
+
+       if (lwc_intern_string("lang", 4, &attr.name) != lwc_error_ok) {
+               return CSS_NOMEM;
+       }
+
+       *is_lang = false; /* default to no match */
+       n = (dom_node *)node;
+
+       /* Loop through all parents of the given node looking for a
+        * substring match */
+       while (n != NULL) {
+               c_err = _node_has_attribute_substring(pw, (void *)n, &attr,
+                                               lang, &match, true);
+               if (c_err != CSS_OK) {
+                       lwc_string_destroy(attr.name);
+                       return c_err;
+               }
+               if (match) {
+                       /* matched this element; we're done */
+                       lwc_string_destroy(attr.name);
+                       *is_lang = true;
+                       return CSS_OK;
+               }
+
+               /* no match on this element, try its parent */
+               d_err = dom_node_get_parent_node(n, &p);
+               if (d_err != DOM_NO_ERR) {
+                       lwc_string_destroy(attr.name);
+                       return CSS_NOMEM;
+               }
+               n = p;
+       }
+
+       /* If we never find a match we may wind up here */
+       lwc_string_destroy(attr.name);
+       return CSS_OK;
+}