libabigail
abg-viz-svg.cc
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright (C) 2013-2023 Red Hat, Inc.
5 
6 #include <stdexcept>
7 #include <fstream>
8 
9 #include "abg-internal.h"
10 // <headers defining libabigail's API go under here>
11 ABG_BEGIN_EXPORT_DECLARATIONS
12 
13 #include "abg-viz-svg.h"
14 
16 // </headers defining libabigail's API>
17 
18 namespace abigail
19 {
20 
21 void
22 svg::write()
23 {
24  try
25  {
26  std::string filename(_M_title + ".svg");
27  std::ofstream f(filename);
28  if (!f.is_open() || !f.good())
29  throw std::runtime_error("abigail::svg::write fail");
30 
31  f << _M_sstream.str() << std::endl;
32  }
33  catch(std::exception& e)
34  {
35  throw e;
36  }
37 }
38 
39 // SVG element beginning boilerplate.
40 // Variable: units, x=0, y=0, width, height
41 void
42 svg::start_element()
43 {
44  const std::string start = R"_delimiter_(<?xml version="1.0" encoding="utf-8"?>
45 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
46 <svg version="1.1"
47  id="svg2" xml:space="preserve"
48  xmlns:dc="http://purl.org/dc/elements/1.1/"
49  xmlns:cc="http://creativecommons.org/ns#"
50  xmlns:svg="http://www.w3.org/2000/svg"
51  xmlns="http://www.w3.org/2000/svg"
52  xmlns:xlink="http://www.w3.org/1999/xlink"
53 )_delimiter_";
54 
55  const std::string units("__units");
56  const std::string width("__width");
57  const std::string height("__height");
58 
59  std::string strip = R"_delimiter_(x="0__units" y="0__units"
60 width="__width__units" height="__height__units"
61 viewBox="0 0 __width __height" enable-background="new 0 0 __width __height">
62 )_delimiter_";
63 
64  string_replace(strip, units, units_to_string(_M_canvas._M_units));
65  string_replace(strip, width, std::to_string(_M_canvas._M_width));
66  string_replace(strip, height, std::to_string(_M_canvas._M_height));
67 
68  _M_sstream << start;
69  _M_sstream << strip << std::endl;
70 }
71 
72 // SVG element end boilerplate.
73 void
74 svg::finish_element()
75 {
76  _M_sstream << "</svg>" << std::endl;
77 }
78 
79 void
80 svg::add_title()
81 {
82  _M_sstream << "<title>" << _M_title << "</title>" << std::endl;
83 }
84 
85 // Column labels
86 // Variable: x, y
87 void
88 svg::add_y_label()
89 {
90  unsigned int xcur = 0;
91  const unsigned int padding = 10;
92  const std::string x("__x");
93  const std::string y("__y");
94  const std::string label("__label");
95  const std::string style("__style");
96  const std::string offset("OFFSET");
97  const std::string size("SIZE");
98  const std::string align("ALIGN");
99 
100  // Base text element.
101  std::string text_strip = R"_delimiter_(<text x="__x" y="__y" transform="rotate(270 __x __y)" __style>__label</text>
102 )_delimiter_";
103 
104  // These parts are the same for every text element ...
105  string_replace(text_strip, y, std::to_string(_M_y_origin - padding));
106  string_replace(text_strip, style, _M_typo.to_attribute(typography::start));
107 
108  // ... just the label and the x position in the center of the current column.
109  xcur = _M_x_origin + (.5 * _M_x_space);
110  std::string offset_strip = text_strip;
111  string_replace(offset_strip, x, std::to_string(xcur));
112  string_replace(offset_strip, label, offset);
113 
114  xcur += _M_x_space;
115  std::string size_strip = text_strip;
116  string_replace(size_strip, x, std::to_string(xcur));
117  string_replace(size_strip, label, size);
118 
119  xcur += _M_x_space;
120  std::string align_strip = text_strip;
121  string_replace(align_strip, x, std::to_string(xcur));
122  string_replace(align_strip, label, align);
123 
124  _M_sstream << "<g><!-- vertical labels -->" << std::endl;
125  _M_sstream << offset_strip;
126  _M_sstream << size_strip;
127  _M_sstream << align_strip;
128  _M_sstream << "</g>" << std::endl;
129 }
130 
131 // Draws in 4 vertical hairlines.
132 // Variable: x, y, _M_y_size, _M_y_space
133 void
134 svg::add_y_lines()
135 {
136  unsigned int xcur = 0;
137  const unsigned int yend = _M_y_origin + _M_y_size * _M_y_space;
138  const std::string x("__x");
139  const std::string y1("__y1");
140  const std::string y2("__y2");
141 
142  std::string strip = R"_delimiter_(<path stroke="black" stroke-width="1" d="M __x __y1 L __x __y2"/>
143 )_delimiter_";
144 
145  // These parts are the same for every text element ...
146  string_replace(strip, y1, std::to_string(_M_y_origin - _M_y_space));
147  string_replace(strip, y2, std::to_string(yend));
148 
149  xcur = _M_x_origin;
150  std::string strip_1 = strip;
151  string_replace(strip_1, x, std::to_string(xcur));
152 
153  xcur += _M_x_space;
154  std::string strip_2 = strip;
155  string_replace(strip_2, x, std::to_string(xcur));
156 
157  xcur += _M_x_space;
158  std::string strip_3 = strip;
159  string_replace(strip_3, x, std::to_string(xcur));
160 
161  xcur += _M_x_space;
162  std::string strip_4 = strip;
163  string_replace(strip_4, x, std::to_string(xcur));
164 
165 
166  _M_sstream << "<g><!-- vertical lines -->" << std::endl;
167  _M_sstream << strip_1;
168  _M_sstream << strip_2;
169  _M_sstream << strip_3;
170  _M_sstream << strip_4;
171  _M_sstream << "</g>" << std::endl;
172 }
173 
174 // Add in a row of data.
175 // Columns assumed to be: offset, size, align, data member name/label
176 // Variable: x, y, row type,
177 void
178 svg::add_y_row(const row& __r)
179 {
180  // Background rectangles are horizontally-oriented on column and row
181  // boundaries, and span the second to third column.
182  unsigned int xcur = 0;
183  std::string chroma;
184  const unsigned int ycur = _M_y_origin + (_M_y_size * _M_y_space) + (.5 * _M_y_space);
185  const std::string x("__x");
186  const std::string y("__y");
187  const std::string name("__name");
188  const std::string style("__style");
189  const std::string color("__color");
190  const std::string width("__width");
191  const std::string height("__height");
192  const std::string val("__val");
193 
194  std::string rect_strip = R"_delimiter_(<rect x="__x" y="__y" fill="__color" stroke="__color" stroke-width="1" width="__width" height="__height"/>
195 )_delimiter_";
196 
197  xcur = _M_x_origin + _M_x_space;
198  chroma = color_to_string(__r._M_style._M_fill_color);
199  string_replace(rect_strip, x, std::to_string(xcur));
200  string_replace(rect_strip, y, std::to_string(ycur - (.5 * _M_y_space)));
201  string_replace(rect_strip, width, std::to_string(_M_x_space * 2));
202  string_replace(rect_strip, height, std::to_string(_M_y_space));
203  string_replace(rect_strip, color, chroma);
204 
205 
206  // Text template for each bit of data.
207  std::string text_strip = R"_delimiter_(<text x="__x" y="__y" fill="__color" __style>__val</text>
208 )_delimiter_";
209 
210  // Column 1 offset
211  // Optional offset, if not a primary type row.
212  std::string offset_strip(text_strip);
213  xcur = _M_x_origin + (.5 * _M_x_space);
214  chroma = color_to_string(abigail::color::black);
215  string_replace(offset_strip, x, std::to_string(xcur));
216  string_replace(offset_strip, y, std::to_string(ycur));
217  string_replace(offset_strip, val, std::to_string(__r._M_offset));
218  string_replace(offset_strip, style, _M_typo.to_attribute(typography::middle));
219  string_replace(offset_strip, color, chroma);
220 
221 
222  // Column 2 size
223  std::string size_strip(text_strip);
224  xcur += _M_x_space;
225  chroma = color_to_string(__r._M_style._M_text_color);
226  string_replace(size_strip, x, std::to_string(xcur));
227  string_replace(size_strip, y, std::to_string(ycur));
228  string_replace(size_strip, val, std::to_string(__r._M_size));
229  string_replace(size_strip, style, _M_typo.to_attribute(typography::middle));
230  string_replace(size_strip, color, chroma);
231 
232 
233  // Column 3 align
234  std::string align_strip(text_strip);
235  xcur += _M_x_space;
236  string_replace(align_strip, x, std::to_string(xcur));
237  string_replace(align_strip, y, std::to_string(ycur));
238  string_replace(align_strip, val, std::to_string(__r._M_align));
239  string_replace(align_strip, style, _M_typo.to_attribute(typography::middle));
240  string_replace(align_strip, color, chroma);
241 
242 
243  // Column 4 data member id
244  const unsigned int padding = 10;
245  std::string name_strip(text_strip);
246  xcur = _M_x_origin + (_M_x_size * _M_x_space) + padding;
247  chroma = color_to_string(abigail::color::black);
248  string_replace(name_strip, x, std::to_string(xcur));
249  string_replace(name_strip, y, std::to_string(ycur));
250  string_replace(name_strip, val, __r._M_id);
251  string_replace(name_strip, style, _M_typo.to_attribute(typography::start));
252  string_replace(name_strip, color, chroma);
253 
254 
255  // Write out stripped strings.
256  _M_sstream << "<g><!-- row " << _M_y_size << " -->" << std::endl;
257  _M_sstream << rect_strip;
258  _M_sstream << offset_strip;
259  _M_sstream << size_strip;
260  _M_sstream << align_strip;
261  _M_sstream << name_strip;
262  _M_sstream << "</g>" << std::endl;
263 
264  ++_M_y_size;
265  }
266 
267 
268 }//end namespace abigail
color
Color, conversion function.
Toplevel namespace for libabigail.
units
Measurement abstraction type, conversion function.
void string_replace(std::string &target, const std::string &match, const std::string &replace)
Utility function, like regex_replace.