+#include <stdexcept>
+
#include "svg_analyzer.h"
#include "svgpp_context.h"
#include "svgpp_document_traverser.h"
-SVGAnalyzer::SVGAnalyzer(char *text) {
+SVGAnalyzer::SVGAnalyzer(char *text)
+ : m_svg(SVG::SVGElement(SVG::SVGElementType::Svg)) {
+ m_elements_in_process.push_back(&m_svg);
SvgppContext context{this};
traverseDocumentWithSvgpp(context, text);
+ if (m_elements_in_process.size() != 1) {
+ throw std::runtime_error{
+ "Wrong number of elements in process after traversing SVG document"};
+ }
}
void SVGAnalyzer::on_enter_element_svg() { m_num_svgs++; }
-void SVGAnalyzer::on_enter_element_g() { m_num_groups++; }
+void SVGAnalyzer::on_enter_element_g() {
+ enter_element(SVG::SVGElementType::Group);
+ m_num_groups++;
+}
-void SVGAnalyzer::on_enter_element_circle() { m_num_circles++; }
+void SVGAnalyzer::on_enter_element_circle() {
+ enter_element(SVG::SVGElementType::Circle);
+ m_num_circles++;
+}
-void SVGAnalyzer::on_enter_element_ellipse() { m_num_ellipses++; }
+void SVGAnalyzer::on_enter_element_ellipse() {
+ enter_element(SVG::SVGElementType::Ellipse);
+ m_num_ellipses++;
+}
-void SVGAnalyzer::on_enter_element_line() { m_num_lines++; }
+void SVGAnalyzer::on_enter_element_line() {
+ enter_element(SVG::SVGElementType::Line);
+ m_num_lines++;
+}
-void SVGAnalyzer::on_enter_element_path() { m_num_paths++; }
+void SVGAnalyzer::on_enter_element_path() {
+ enter_element(SVG::SVGElementType::Path);
+ m_num_paths++;
+}
-void SVGAnalyzer::on_enter_element_polygon() { m_num_polygons++; }
+void SVGAnalyzer::on_enter_element_polygon() {
+ enter_element(SVG::SVGElementType::Polygon);
+ m_num_polygons++;
+}
-void SVGAnalyzer::on_enter_element_polyline() { m_num_polylines++; }
+void SVGAnalyzer::on_enter_element_polyline() {
+ enter_element(SVG::SVGElementType::Polyline);
+ m_num_polylines++;
+}
-void SVGAnalyzer::on_enter_element_rect() { m_num_rects++; }
+void SVGAnalyzer::on_enter_element_rect() {
+ enter_element(SVG::SVGElementType::Rect);
+ m_num_rects++;
+}
+
+void SVGAnalyzer::on_enter_element_title() {
+ enter_element(SVG::SVGElementType::Title);
+ m_num_titles++;
+}
+
+void SVGAnalyzer::on_exit_element() { m_elements_in_process.pop_back(); }
-void SVGAnalyzer::on_enter_element_title() { m_num_titles++; }
+SVG::SVGElement &SVGAnalyzer::current_element() {
+ if (m_elements_in_process.empty()) {
+ throw std::runtime_error{"No current element"};
+ }
+ return *m_elements_in_process.back();
+}
+
+void SVGAnalyzer::enter_element(SVG::SVGElementType type) {
+ if (m_elements_in_process.empty()) {
+ throw std::runtime_error{
+ "No element is currently being processed by the SVG++ document "
+ "traverser when entering a new element. Expecting at least the top "
+ "level 'svg' to be in process"};
+ }
+ auto &element = current_element();
+ element.children.emplace_back(type);
+ m_elements_in_process.push_back(&element.children.back());
+}
#pragma once
#include <cstddef>
+#include <vector>
#include "svg_analyzer_interface.h"
+#include "svg_element.h"
/**
* @brief The SVGAnalyzer class analyzes the contents of an SVG document.
void on_enter_element_polyline() override;
void on_enter_element_rect() override;
void on_enter_element_title() override;
+ void on_exit_element() override;
std::size_t num_svgs() const { return m_num_svgs; };
std::size_t num_groups() const { return m_num_groups; };
std::size_t num_circles() const { return m_num_circles; };
std::size_t num_titles() const { return m_num_titles; };
private:
+ /// Get the current element being processed by the SVG document traverser
+ SVG::SVGElement ¤t_element();
+ /// Enter a new SVG element retrieved by the SVG document traverser into the
+ /// list of elements currently being processed
+ void enter_element(SVG::SVGElementType type);
+
+ /// A list of pointers to elements currently being processed by the SVG++
+ /// document traverser, in hierarchical order. The front element is the top
+ /// level SVG and the back element is the current element.
+ std::vector<SVG::SVGElement *> m_elements_in_process;
std::size_t m_num_svgs = 1; // the top level svg is implicit. See
// https://github.com/svgpp/svgpp/issues/98
std::size_t m_num_groups = 0;
std::size_t m_num_polylines = 0;
std::size_t m_num_rects = 0;
std::size_t m_num_titles = 0;
+ /// The top level SVG `svg` element corresponding to the Graphviz graph
+ SVG::SVGElement m_svg;
};