From: Magnus Jacobsson Date: Thu, 28 Jul 2022 10:58:49 +0000 (+0200) Subject: tests: SvgAnalyzer: add handling of the 'd' attribute X-Git-Tag: 5.0.1~7^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6f0b07bda73e24318422274d5713712694d4f883;p=graphviz tests: SvgAnalyzer: add handling of the 'd' attribute --- diff --git a/tests/svg_analyzer.cpp b/tests/svg_analyzer.cpp index be7b3bc29..23ffd9d37 100644 --- a/tests/svg_analyzer.cpp +++ b/tests/svg_analyzer.cpp @@ -69,6 +69,21 @@ void SVGAnalyzer::on_enter_element_title() { void SVGAnalyzer::on_exit_element() { m_elements_in_process.pop_back(); } +void SVGAnalyzer::path_cubic_bezier_to(double x1, double y1, double x2, + double y2, double x, double y) { + auto &path_points = current_element().path_points; + path_points.emplace_back(x1, y1); + path_points.emplace_back(x2, y2); + path_points.emplace_back(x, y); +} + +void SVGAnalyzer::path_move_to(double x, double y) { + auto &paths = current_element().path_points; + paths.emplace_back(x, y); +} + +void SVGAnalyzer::path_exit() {} + SVG::SVGElement &SVGAnalyzer::grandparent_element() { if (m_elements_in_process.empty()) { throw std::runtime_error{"No current element to get grandparent of"}; diff --git a/tests/svg_analyzer.h b/tests/svg_analyzer.h index 861c36f63..f4a418dea 100644 --- a/tests/svg_analyzer.h +++ b/tests/svg_analyzer.h @@ -27,6 +27,10 @@ public: void on_enter_element_text() override; void on_enter_element_title() override; void on_exit_element() override; + void path_cubic_bezier_to(double x1, double y1, double x2, double y2, + double x, double y) override; + void path_move_to(double x, double y) override; + void path_exit() override; void set_cx(double cx) override; void set_cy(double cy) override; void set_font_family(std::string_view font_family) override; diff --git a/tests/svg_analyzer_interface.h b/tests/svg_analyzer_interface.h index 295f82f93..2d147bcf3 100644 --- a/tests/svg_analyzer_interface.h +++ b/tests/svg_analyzer_interface.h @@ -26,6 +26,10 @@ public: virtual void on_enter_element_text() = 0; virtual void on_enter_element_title() = 0; virtual void on_exit_element() = 0; + virtual void path_exit() = 0; + virtual void path_move_to(double x, double y) = 0; + virtual void path_cubic_bezier_to(double x1, double y1, double x2, double y2, + double x, double y) = 0; virtual void set_class(std::string_view) = 0; virtual void set_cx(double cx) = 0; virtual void set_cy(double cy) = 0; diff --git a/tests/svg_element.cpp b/tests/svg_element.cpp index ff07e5f80..256687038 100644 --- a/tests/svg_element.cpp +++ b/tests/svg_element.cpp @@ -156,10 +156,29 @@ void SVG::SVGElement::to_string_impl(std::string &output, transform->a, transform->d, transform->c, transform->e, transform->f); } break; - case SVG::SVGElementType::Path: + case SVG::SVGElementType::Path: { append_attribute(attributes_str, fill_attribute_to_string()); append_attribute(attributes_str, stroke_attribute_to_string()); + attributes_str += R"|( d=")|"; + auto command = 'M'; + for (const auto &point : path_points) { + attributes_str += fmt::format("{}{},{}", command, point.x, point.y); + switch (command) { + case 'M': + command = 'C'; + break; + case 'C': + command = ' '; + break; + case ' ': + break; + default: + UNREACHABLE(); + } + } + attributes_str += '"'; break; + } case SVG::SVGElementType::Polygon: append_attribute(attributes_str, fill_attribute_to_string()); append_attribute(attributes_str, stroke_attribute_to_string()); diff --git a/tests/svg_element.h b/tests/svg_element.h index 928834700..c8864c355 100644 --- a/tests/svg_element.h +++ b/tests/svg_element.h @@ -87,6 +87,8 @@ public: std::string graphviz_id; /// The Graphviz release version std::string graphviz_version; + /// The points given by the `d` attribute of a path element + std::vector path_points; /// The SVG element text node contents. Not to be confused with an SVG `text` /// element std::string text; diff --git a/tests/svgpp_context.cpp b/tests/svgpp_context.cpp index db4cf826f..d7127cbed 100644 --- a/tests/svgpp_context.cpp +++ b/tests/svgpp_context.cpp @@ -63,58 +63,45 @@ void SvgppContext::on_exit_element() { m_svgAnalyzer->on_exit_element(); } void SvgppContext::path_move_to(double x, double y, svgpp::tag::coordinate::absolute c) { - (void)x; - (void)y; - (void)c; + if (!c.is_absolute) { + throw std::runtime_error{ + "'path_move_to' using relative coordinates is not yet implemented"}; + } + m_svgAnalyzer->path_move_to(x, y); } -void SvgppContext::path_line_to(double x, double y, - svgpp::tag::coordinate::absolute c) { - (void)x; - (void)y; - (void)c; +void SvgppContext::path_line_to(double, double, + svgpp::tag::coordinate::absolute) { + throw std::runtime_error{"'path_line_to' is not yet implemented"}; } void SvgppContext::path_cubic_bezier_to(double x1, double y1, double x2, double y2, double x, double y, svgpp::tag::coordinate::absolute c) { - (void)x1; - (void)y1; - (void)x2; - (void)y2; - (void)x; - (void)y; - (void)c; -} - -void SvgppContext::path_quadratic_bezier_to( - double x1, double y1, double x, double y, - svgpp::tag::coordinate::absolute c) { - (void)x1; - (void)y1; - (void)x; - (void)y; - (void)c; -} - -void SvgppContext::path_elliptical_arc_to(double rx, double ry, - double x_axis_rotation, - bool large_arc_flag, bool sweep_flag, - double x, double y, - svgpp::tag::coordinate::absolute c) { - (void)rx; - (void)ry; - (void)x_axis_rotation; - (void)large_arc_flag; - (void)sweep_flag; - (void)x; - (void)y; - (void)c; -} - -void SvgppContext::path_close_subpath() {} - -void SvgppContext::path_exit() {} + if (!c.is_absolute) { + throw std::runtime_error{ + "'path_cubic_bezier_to' using relative coordinates " + "is not yet implemented"}; + } + m_svgAnalyzer->path_cubic_bezier_to(x1, y1, x2, y2, x, y); +} + +void SvgppContext::path_quadratic_bezier_to(double, double, double, double, + svgpp::tag::coordinate::absolute) { + throw std::runtime_error{"'path_quadratic_bezier_to' is not yet implemented"}; +} + +void SvgppContext::path_elliptical_arc_to(double, double, double, bool, bool, + double, double, + svgpp::tag::coordinate::absolute) { + throw std::runtime_error{"'path_elliptical_arc_to' is not yet implemented"}; +} + +void SvgppContext::path_close_subpath() { + throw std::runtime_error{"'path_close_subpath' is not yet implemented"}; +} + +void SvgppContext::path_exit() { m_svgAnalyzer->path_exit(); } void SvgppContext::set(svgpp::tag::attribute::cy, const double v) { m_svgAnalyzer->set_cy(v); diff --git a/tests/svgpp_document_traverser.cpp b/tests/svgpp_document_traverser.cpp index 8ee6a9ee7..62e4d6e5b 100644 --- a/tests/svgpp_document_traverser.cpp +++ b/tests/svgpp_document_traverser.cpp @@ -29,6 +29,7 @@ void traverseDocumentWithSvgpp(SvgppContext &context, char *text) { 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, // diff --git a/tests/test_svg_analyzer.cpp b/tests/test_svg_analyzer.cpp index e84f5d8ac..6b1b6b888 100644 --- a/tests/test_svg_analyzer.cpp +++ b/tests/test_svg_analyzer.cpp @@ -115,32 +115,17 @@ TEST_CASE( const auto indent_size = 0; auto recreated_svg = svgAnalyzer.svg_string(indent_size); - // compare the initial lines of the recreated SVG that we can fully recreate - // with the original SVG - std::vector original_svg_lines; - boost::split(original_svg_lines, original_svg, boost::is_any_of("\n")); - std::vector recreated_svg_lines; - 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] == - ("")) { - // stop comparison here for the 'cylinder' node shape since we do not - // yet handle all attributes on the 'path' element - break; + // compare the recreated SVG with the original SVG + if (recreated_svg != original_svg) { + std::vector original_svg_lines; + boost::split(original_svg_lines, original_svg, boost::is_any_of("\n")); + std::vector recreated_svg_lines; + 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()); + REQUIRE(recreated_svg_lines[i] == original_svg_lines[i]); } - REQUIRE(recreated_svg_lines[i] == original_svg_lines[i]); + REQUIRE(recreated_svg_lines.size() == original_svg_lines.size()); } - - // do some sanity checks of the parts of the recreated SVG that we cannot - // yet compare with the original SVG - CHECK(recreated_svg.find("g1") != std::string::npos); - CHECK(recreated_svg.find("a") != std::string::npos); - CHECK(recreated_svg.find("b") != std::string::npos); - CHECK(recreated_svg.find("") != - std::string::npos); - CHECK(recreated_svg.find("") != std::string::npos); - CHECK(recreated_svg.find("") != std::string::npos); - CHECK(recreated_svg.find("") != std::string::npos); } }