]> granicus.if.org Git - graphviz/commitdiff
tests: SVGAnalyzer: add handling of the 'stroke-width' attribute
authorMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Wed, 10 Aug 2022 07:36:08 +0000 (09:36 +0200)
committerMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Mon, 5 Sep 2022 06:14:44 +0000 (08:14 +0200)
tests/CMakeLists.txt
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_penwidth.cpp [new file with mode: 0644]

index 0b962959bb3af0c64efdbb10b7408637611c196b..73daa0e529a5f7dfdee752e00d67177d73329c76 100644 (file)
@@ -89,3 +89,4 @@ CREATE_TEST(simple)
 CREATE_TEST(subgraph_layout)
 CREATE_TEST(subgraphs)
 CREATE_TEST(svg_analyzer)
+CREATE_TEST(svg_analyzer_penwidth)
index 8b1d1ae9f164b80de7a927a11d9deeb39bb5de8c..348275055997e27167f46039b684f41a2a3db17e 100644 (file)
@@ -227,6 +227,10 @@ void SVGAnalyzer::set_stroke(std::string_view stroke) {
   current_element().attributes.stroke = stroke;
 }
 
+void SVGAnalyzer::set_stroke_width(double stroke_width) {
+  current_element().attributes.stroke_width = stroke_width;
+}
+
 void SVGAnalyzer::set_id(std::string_view id) {
   current_element().attributes.id = id;
 }
index 8c48dcbe6f3fe15cd6403208d8b29e32c0be0b40..f035e312d486700e0a4f3c9b8edecbdd6cfc9e37 100644 (file)
@@ -46,6 +46,7 @@ public:
   void set_ry(double ry) override;
   void set_class(std::string_view) override;
   void set_stroke(std::string_view stroke) override;
+  void set_stroke_width(double stroke_width) override;
   void set_point(std::pair<double, double> point) override;
   void set_text(std::string_view text) override;
   void set_text_anchor(std::string_view text_anchor) override;
index 2d147bcf3ade403d3998c5a6731abe578af223f8..0487134cfe4a0fbd533ad6185efffe7d55f57e80 100644 (file)
@@ -42,6 +42,7 @@ public:
   virtual void set_ry(double ry) = 0;
   virtual void set_point(std::pair<double, double> point) = 0;
   virtual void set_stroke(std::string_view stroke) = 0;
+  virtual void set_stroke_width(double stroke_width) = 0;
   virtual void set_text(std::string_view text) = 0;
   virtual void set_text_anchor(std::string_view text_anchor) = 0;
   virtual void set_transform(double a, double b, double c, double d, double e,
index 0209e95bfbdbda1da0ed9900966718c67e1911bf..f2fee723c4f82ab5f662cbc27de9fa9829b8b62c 100644 (file)
@@ -202,6 +202,15 @@ std::string SVG::SVGElement::stroke_attribute_to_string() const {
                      stroke_to_graphviz_color(attributes.stroke));
 }
 
+std::string SVG::SVGElement::stroke_width_attribute_to_string() const {
+  if (attributes.stroke_width == 1) {
+    // Graphviz doesn't set `stroke-width` to 1 since that's the default
+    return "";
+  }
+
+  return fmt::format(R"(stroke-width="{}")", attributes.stroke_width);
+}
+
 std::string SVG::SVGElement::to_string(std::size_t indent_size = 2) const {
   std::string output;
   output += R"(<?xml version="1.0" encoding="UTF-8" standalone="no"?>)"
@@ -242,6 +251,7 @@ void SVG::SVGElement::to_string_impl(std::string &output,
   case SVG::SVGElementType::Ellipse:
     append_attribute(attributes_str, fill_attribute_to_string());
     append_attribute(attributes_str, stroke_attribute_to_string());
+    append_attribute(attributes_str, stroke_width_attribute_to_string());
     attributes_str +=
         fmt::format(R"( cx="{}" cy="{}" rx="{}" ry="{}")", attributes.cx,
                     attributes.cy, attributes.rx, attributes.ry);
@@ -258,6 +268,7 @@ void SVG::SVGElement::to_string_impl(std::string &output,
   case SVG::SVGElementType::Path: {
     append_attribute(attributes_str, fill_attribute_to_string());
     append_attribute(attributes_str, stroke_attribute_to_string());
+    append_attribute(attributes_str, stroke_width_attribute_to_string());
     attributes_str += R"|( d=")|";
     auto command = 'M';
     for (const auto &point : path_points) {
@@ -281,11 +292,13 @@ void SVG::SVGElement::to_string_impl(std::string &output,
   case SVG::SVGElementType::Polygon:
     append_attribute(attributes_str, fill_attribute_to_string());
     append_attribute(attributes_str, stroke_attribute_to_string());
+    append_attribute(attributes_str, stroke_width_attribute_to_string());
     append_attribute(attributes_str, points_attribute_to_string());
     break;
   case SVG::SVGElementType::Polyline:
     append_attribute(attributes_str, fill_attribute_to_string());
     append_attribute(attributes_str, stroke_attribute_to_string());
+    append_attribute(attributes_str, stroke_width_attribute_to_string());
     append_attribute(attributes_str, points_attribute_to_string());
     break;
   case SVG::SVGElementType::Svg:
index 11c3f5fe4247def3e4b7bb3bd0fd21a4f26a4c40..5aed78a018ee20cfe49ed317baf10f4eff8937b9 100644 (file)
@@ -65,6 +65,7 @@ struct SVGAttributes {
   double rx;
   double ry;
   std::string stroke;
+  double stroke_width = 1;
   std::string text_anchor;
   std::optional<SVGMatrix> transform;
   SVGRect viewBox;
@@ -118,6 +119,7 @@ private:
   std::string fill_attribute_to_string() const;
   std::string points_attribute_to_string() const;
   std::string stroke_attribute_to_string() const;
+  std::string stroke_width_attribute_to_string() const;
   std::string stroke_to_graphviz_color(const std::string &color) const;
   SVG::SVGRect text_bbox() const;
   void to_string_impl(std::string &output, std::size_t indent_size,
index 2b19d03c4dce92340422abaccc2226ebdc00ac3c..24d321fa52882116ca998cb05f0853f8b345a0dd 100644 (file)
@@ -142,6 +142,10 @@ void SvgppContext::set(svgpp::tag::attribute::stroke,
   m_svg_analyzer->set_stroke(to_color_string(color));
 }
 
+void SvgppContext::set(svgpp::tag::attribute::stroke_width, const double v) {
+  m_svg_analyzer->set_stroke_width(v);
+}
+
 void SvgppContext::transform_matrix(const boost::array<double, 6> &matrix) {
   double a = matrix.at(0);
   double b = matrix.at(1);
index fdf5da37861781db1592df8174f4461aab2977c0..69551426cd1e1685b91c4229947ceb21b06a6a3d 100644 (file)
@@ -149,6 +149,7 @@ public:
     throw std::runtime_error{
         "this flavor of the 'stroke' attribute is not yet implemented"};
   };
+  void set(svgpp::tag::attribute::stroke_width, double v);
   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 62e4d6e5bfb536567b6af94db61dd9ec3839aed7..e02f69ea5603f4dd9b2213c1855155d210ad668e 100644 (file)
@@ -1,3 +1,7 @@
+// The pre-processed boost::mpl::set allows only 20 elements, but we need more
+#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
+#define BOOST_MPL_LIMIT_SET_SIZE 40
+
 #include <rapidxml_ns/rapidxml_ns.hpp>
 #include <svgpp/policy/xml/rapidxml_ns.hpp>
 #include <svgpp/svgpp.hpp>
@@ -26,25 +30,26 @@ 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::cx,          //
-                        svgpp::tag::attribute::cy,          //
-                        svgpp::tag::attribute::d,           //
-                        svgpp::tag::attribute::fill,        //
-                        svgpp::tag::attribute::font_family, //
-                        svgpp::tag::attribute::font_size,   //
-                        svgpp::tag::attribute::height,      //
-                        svgpp::tag::attribute::id,          //
-                        svgpp::tag::attribute::points,      //
-                        svgpp::tag::attribute::rx,          //
-                        svgpp::tag::attribute::ry,          //
-                        svgpp::tag::attribute::stroke,      //
-                        svgpp::tag::attribute::text_anchor, //
-                        svgpp::tag::attribute::transform,   //
-                        svgpp::tag::attribute::viewBox,     //
-                        svgpp::tag::attribute::width,       //
-                        svgpp::tag::attribute::x,           //
-                        svgpp::tag::attribute::y            //
+                        svgpp::tag::attribute::class_,       //
+                        svgpp::tag::attribute::cx,           //
+                        svgpp::tag::attribute::cy,           //
+                        svgpp::tag::attribute::d,            //
+                        svgpp::tag::attribute::fill,         //
+                        svgpp::tag::attribute::font_family,  //
+                        svgpp::tag::attribute::font_size,    //
+                        svgpp::tag::attribute::height,       //
+                        svgpp::tag::attribute::id,           //
+                        svgpp::tag::attribute::points,       //
+                        svgpp::tag::attribute::rx,           //
+                        svgpp::tag::attribute::ry,           //
+                        svgpp::tag::attribute::stroke,       //
+                        svgpp::tag::attribute::stroke_width, //
+                        svgpp::tag::attribute::text_anchor,  //
+                        svgpp::tag::attribute::transform,    //
+                        svgpp::tag::attribute::viewBox,      //
+                        svgpp::tag::attribute::width,        //
+                        svgpp::tag::attribute::x,            //
+                        svgpp::tag::attribute::y             //
                         >::type;
 
     svgpp::document_traversal<
diff --git a/tests/test_svg_analyzer_penwidth.cpp b/tests/test_svg_analyzer_penwidth.cpp
new file mode 100644 (file)
index 0000000..7f42a2c
--- /dev/null
@@ -0,0 +1,23 @@
+#include <catch2/catch.hpp>
+#include <fmt/format.h>
+
+#include "svg_analyzer.h"
+#include "test_utilities.h"
+
+TEST_CASE("SvgAnalyzer penwidth",
+          "Test that the SvgAnalyzer can recreate the original SVG with the "
+          "correct `stroke-width` attribute when the Graphviz `penwidth` "
+          "attribute is used for nodes and edges") {
+
+  const auto shape = GENERATE(from_range(all_node_shapes));
+  INFO(fmt::format("Shape: {}", shape));
+
+  const auto penwidth = GENERATE(0.5, 1.0, 2.0);
+  INFO(fmt::format("Node and edge penwidth: {}", penwidth));
+
+  auto dot = fmt::format(
+      "digraph g1 {{node [shape={} penwidth={}]; edge [penwidth={}]; a -> b}}",
+      shape, penwidth, penwidth);
+
+  SVGAnalyzer::make_from_dot(dot).re_create_and_verify_svg();
+}