]> granicus.if.org Git - graphviz/commitdiff
tests: SvgAnalyzer: add handling of the 'fill' attribute
authorMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Wed, 27 Jul 2022 12:28:44 +0000 (14:28 +0200)
committerMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Tue, 16 Aug 2022 10:21:45 +0000 (12:21 +0200)
tests/svg_analyzer.cpp
tests/svg_analyzer.h
tests/svg_analyzer_interface.h
tests/svg_element.cpp
tests/svg_element.h
tests/svgpp_context.cpp
tests/svgpp_context.h
tests/svgpp_document_traverser.cpp
tests/test_svg_analyzer.cpp

index 339a88d019016ed93f79f71285e628595c4c8e3d..2bc011657a08400c5e4623dc3f9b7160ac7e7c5d 100644 (file)
@@ -115,6 +115,10 @@ void SVGAnalyzer::set_class(std::string_view class_) {
   current_element().attributes.class_ = class_;
 }
 
+void SVGAnalyzer::set_fill(std::string_view fill) {
+  current_element().attributes.fill = fill;
+}
+
 void SVGAnalyzer::set_height(double height) {
   current_element().attributes.height = height;
 }
index 5a2e777701bff05110f9c5eaa7430003dc4d7f2e..12a201f9a1f0f4f9881fb8019d2076a8c3bb8a52 100644 (file)
@@ -27,6 +27,7 @@ public:
   void on_enter_element_text() override;
   void on_enter_element_title() override;
   void on_exit_element() override;
+  void set_fill(std::string_view fill) override;
   void set_height(double height) override;
   void set_id(std::string_view id) override;
   void set_class(std::string_view) override;
index d2091a231d1024bb28d9d5599e787be6f5c17c85..a574770d3f0ef8016a227d5f11093b0a7c8ebb8a 100644 (file)
@@ -27,6 +27,7 @@ public:
   virtual void on_enter_element_title() = 0;
   virtual void on_exit_element() = 0;
   virtual void set_class(std::string_view) = 0;
+  virtual void set_fill(std::string_view fill) = 0;
   virtual void set_height(double height) = 0;
   virtual void set_id(std::string_view id) = 0;
   virtual void set_text(std::string_view text) = 0;
index 35768d83aa272f605cbee1a10489866ab57affae..55e5c56764b35a4c5c0abf376a7a7eeef38cac92 100644 (file)
@@ -36,6 +36,25 @@ static std::string xml_encode(const std::string &text) {
   return out;
 }
 
+// convert a valid color specification to the flavor that Graphviz uses
+static std::string to_graphviz_color(const std::string &color) {
+  if (color == "rgb(0,0,0)") {
+    return "black";
+  } else if (color == "rgb(255,255,255)") {
+    return "white";
+  } else if (color.starts_with("rgb")) {
+    const auto comma1 = color.find_first_of(",");
+    const auto r = std::stoi(color.substr(4, comma1 - 1));
+    const auto comma2 = color.find_first_of(",", comma1 + 1);
+    const auto g = std::stoi(color.substr(comma1 + 1, comma2 - 1));
+    const auto close_par = color.find_first_of(")", comma2 + 1);
+    const auto b = std::stoi(color.substr(comma2 + 1, close_par - 1));
+    return fmt::format("#{:02x}{:02x}{:02x}", r, g, b);
+  } else {
+    return color;
+  }
+}
+
 void SVG::SVGElement::append_attribute(std::string &output,
                                        const std::string &attribute) const {
   if (attribute.empty()) {
@@ -47,6 +66,14 @@ void SVG::SVGElement::append_attribute(std::string &output,
   output += attribute;
 }
 
+std::string SVG::SVGElement::fill_attribute_to_string() const {
+  if (attributes.fill.empty()) {
+    return "";
+  }
+
+  return fmt::format(R"(fill="{}")", to_graphviz_color(attributes.fill));
+}
+
 std::string SVG::SVGElement::id_attribute_to_string() const {
   if (attributes.id.empty()) {
     return "";
@@ -93,7 +120,7 @@ void SVG::SVGElement::to_string_impl(std::string &output,
   append_attribute(attributes_str, id_attribute_to_string());
   switch (type) {
   case SVG::SVGElementType::Ellipse:
-    // ignore for now
+    append_attribute(attributes_str, fill_attribute_to_string());
     break;
   case SVG::SVGElementType::Group:
     attributes_str += fmt::format(R"( class="{}")", attributes.class_);
@@ -105,13 +132,13 @@ void SVG::SVGElement::to_string_impl(std::string &output,
     }
     break;
   case SVG::SVGElementType::Path:
-    // ignore for now
+    append_attribute(attributes_str, fill_attribute_to_string());
     break;
   case SVG::SVGElementType::Polygon:
-    // ignore for now
+    append_attribute(attributes_str, fill_attribute_to_string());
     break;
   case SVG::SVGElementType::Polyline:
-    // ignore for now
+    append_attribute(attributes_str, fill_attribute_to_string());
     break;
   case SVG::SVGElementType::Svg:
     attributes_str += fmt::format(
index 8b8d6cc457c0ac2a8a4c3dd2ba949e618a030968..87d27bfc42d2034de22270f1ca9ccd2c6e8fad90 100644 (file)
@@ -42,6 +42,7 @@ std::string_view tag(SVG::SVGElementType type);
 
 struct SVGAttributes {
   std::string class_;
+  std::string fill;
   double height;
   std::string id;
   std::optional<SVGMatrix> transform;
@@ -82,6 +83,7 @@ private:
   void append_attribute(std::string &output,
                         const std::string &attribute) const;
   std::string id_attribute_to_string() const;
+  std::string fill_attribute_to_string() const;
   void to_string_impl(std::string &output, std::size_t indent_size,
                       std::size_t current_indent) const;
 };
index b8a14853fa1fa0eeae35a2e0ad5fe6c0259cbfc2..ea32be5e35f1327647bf34c9c20e5bcf087346db 100644 (file)
@@ -1,10 +1,17 @@
 #include <any>
+#include <stdexcept>
 
 #include <boost/array.hpp>
+#include <fmt/format.h>
 
 #include "svg_analyzer_interface.h"
 #include "svgpp_context.h"
 
+static std::string to_color_string(SvgppContext::color_t color) {
+  return fmt::format("rgb({},{},{})", (color >> 16) & 0xff, (color >> 8) & 0xff,
+                     (color >> 0) & 0xff);
+}
+
 SvgppContext::SvgppContext(ISVGAnalyzer *svgAnalyzer)
     : m_svgAnalyzer(svgAnalyzer){};
 
@@ -119,6 +126,21 @@ void SvgppContext::set(svgpp::tag::attribute::cx a, const double v) {
   (void)v;
 }
 
+void SvgppContext::set(svgpp::tag::attribute::fill, svgpp::tag::value::none) {
+  m_svgAnalyzer->set_fill("none");
+}
+
+void SvgppContext::set(svgpp::tag::attribute::fill,
+                       svgpp::tag::value::currentColor) {
+  throw std::runtime_error{
+      "the 'fill' attribute 'currentColor' value is not yet implemented"};
+}
+
+void SvgppContext::set(svgpp::tag::attribute::fill, color_t color,
+                       svgpp::tag::skip_icc_color) {
+  m_svgAnalyzer->set_fill(to_color_string(color));
+}
+
 void SvgppContext::transform_matrix(const boost::array<double, 6> &matrix) {
   double a = matrix.at(0);
   double b = matrix.at(1);
index 8c0568b0962145499c26fc1b075f3339238d1e8b..f024f0e3e50d50b7c6c59c85b9e8afe8b1812fb2 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <any>
+#include <stdexcept>
 
 #include <boost/range/iterator_range_core.hpp>
 #include <svgpp/svgpp.hpp>
@@ -48,6 +49,56 @@ public:
   void path_exit();
   void set(svgpp::tag::attribute::cy cy, double v);
   void set(svgpp::tag::attribute::cx cx, double v);
+
+  void set(svgpp::tag::attribute::fill, svgpp::tag::value::none);
+  void set(svgpp::tag::attribute::fill, svgpp::tag::value::currentColor);
+  using color_t = int;
+  void set(svgpp::tag::attribute::fill, color_t color,
+           svgpp::tag::skip_icc_color = svgpp::tag::skip_icc_color());
+  template <class IRI> void set(svgpp::tag::attribute::fill, IRI const &) {
+    throw std::runtime_error{
+        "this flavor of the 'fill' attribute is not yet implemented"};
+  };
+  template <class IRI>
+  void set(svgpp::tag::attribute::fill, svgpp::tag::iri_fragment, IRI const &) {
+    throw std::runtime_error{
+        "this flavor of the 'fill' attribute is not yet implemented"};
+  };
+  template <class IRI>
+  void set(svgpp::tag::attribute::fill, IRI const &, svgpp::tag::value::none) {
+    throw std::runtime_error{
+        "this flavor of the 'fill' attribute is not yet implemented"};
+  };
+  template <class IRI>
+  void set(svgpp::tag::attribute::fill, svgpp::tag::iri_fragment, IRI const &,
+           svgpp::tag::value::none) {
+    throw std::runtime_error{
+        "this flavor of the 'fill' attribute is not yet implemented"};
+  };
+  template <class IRI>
+  void set(svgpp::tag::attribute::fill, IRI const &,
+           svgpp::tag::value::currentColor) {
+    throw std::runtime_error{
+        "this flavor of the 'fill' attribute is not yet implemented"};
+  };
+  template <class IRI>
+  void set(svgpp::tag::attribute::fill, svgpp::tag::iri_fragment, IRI const &,
+           svgpp::tag::value::currentColor) {
+    throw std::runtime_error{
+        "this flavor of the 'fill' attribute is not yet implemented"};
+  };
+  template <class IRI>
+  void set(svgpp::tag::attribute::fill, IRI const &, color_t,
+           svgpp::tag::skip_icc_color = svgpp::tag::skip_icc_color()) {
+    throw std::runtime_error{
+        "this flavor of the 'fill' attribute is not yet implemented"};
+  };
+  template <class IRI>
+  void set(svgpp::tag::attribute::fill, svgpp::tag::iri_fragment, IRI const &,
+           color_t, svgpp::tag::skip_icc_color = svgpp::tag::skip_icc_color()) {
+    throw std::runtime_error{
+        "this flavor of the 'fill' attribute is not yet implemented"};
+  };
   void transform_matrix(const boost::array<double, 6> &matrix);
   void set(svgpp::tag::attribute::r r, double v);
   void set(svgpp::tag::attribute::rx rx, double v);
index 19133e7bcd633efe5c842a7d975f6bf7ed1c9a37..a73c9599c65de3ccbf622d1d7a0d542803063b11 100644 (file)
@@ -27,6 +27,7 @@ void traverseDocumentWithSvgpp(SvgppContext &context, char *text) {
     using processed_attributes_t =
         boost::mpl::set<svgpp::traits::shapes_attributes_by_element,
                         svgpp::tag::attribute::class_,    //
+                        svgpp::tag::attribute::fill,      //
                         svgpp::tag::attribute::height,    //
                         svgpp::tag::attribute::id,        //
                         svgpp::tag::attribute::transform, //
index 3fe9749f46bedb39c2972b745904513561bdd789..12bb9ae97de5fcf5d91af72de1ae7fd6bbd29767 100644 (file)
@@ -123,7 +123,7 @@ TEST_CASE(
     boost::split(recreated_svg_lines, recreated_svg, boost::is_any_of("\n"));
     for (std::size_t i = 0; i < original_svg_lines.size(); i++) {
       REQUIRE(i < recreated_svg_lines.size());
-      if (recreated_svg_lines[i] == "<polygon/>") {
+      if (recreated_svg_lines[i] == "<polygon fill=\"white\"/>") {
         // stop comparison here since we do not yet handle all attributes on the
         // 'polygon' element
         break;
@@ -140,8 +140,8 @@ TEST_CASE(
       CHECK(recreated_svg.find("<text>a</text>") != std::string::npos);
       CHECK(recreated_svg.find("<text>b</text>") != std::string::npos);
     }
-    CHECK(recreated_svg.find("<polygon/>") != std::string::npos);
-    CHECK(recreated_svg.find("<path/>") != std::string::npos);
+    CHECK(recreated_svg.find("<polygon fill=\"white\"/>") != std::string::npos);
+    CHECK(recreated_svg.find("<path fill=\"none\"/>") != std::string::npos);
     CHECK(recreated_svg.find("<!-- a -->") != std::string::npos);
     CHECK(recreated_svg.find("<!-- b -->") != std::string::npos);
     CHECK(recreated_svg.find("<!-- a&#45;&gt;b -->") != std::string::npos);