Branch data Line data Source code
1 : : /* Types for drawing 2d "text art".
2 : : Copyright (C) 2023-2024 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it
8 : : under the terms of the GNU General Public License as published by
9 : : the Free Software Foundation; either version 3, or (at your option)
10 : : any later version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #ifndef GCC_TEXT_ART_TYPES_H
22 : : #define GCC_TEXT_ART_TYPES_H
23 : :
24 : : /* This header uses std::vector, but <vector> can't be directly
25 : : included due to issues with macros. Hence it must be included from
26 : : system.h by defining INCLUDE_MEMORY in any source file using it. */
27 : :
28 : : #ifndef INCLUDE_VECTOR
29 : : # error "You must define INCLUDE_VECTOR before including system.h to use text-art/types.h"
30 : : #endif
31 : :
32 : : #include "cpplib.h"
33 : : #include "pretty-print.h"
34 : :
35 : : namespace text_art {
36 : :
37 : : /* Forward decls. */
38 : :
39 : : class canvas;
40 : : class table;
41 : : class theme;
42 : :
43 : : /* Classes for geometry.
44 : : We use templates to avoid mixing up e.g. canvas coordinates
45 : : with table coordinates. */
46 : :
47 : : template <typename CoordinateSystem>
48 : : struct size
49 : : {
50 : 4071 : size (int w_, int h_) : w (w_), h (h_) {}
51 : : int w;
52 : : int h;
53 : : };
54 : :
55 : : template <typename CoordinateSystem>
56 : : struct coord
57 : : {
58 : 142886 : coord (int x_, int y_) : x (x_), y (y_) {}
59 : : int x;
60 : : int y;
61 : : };
62 : :
63 : : template <typename CoordinateSystem>
64 : 64838 : coord<CoordinateSystem> operator+ (coord<CoordinateSystem> a,
65 : : coord<CoordinateSystem> b)
66 : : {
67 : 64458 : return coord<CoordinateSystem> (a.x + b.x, a.y + b.y);
68 : : }
69 : :
70 : : /* A half-open range [start, next) of int. */
71 : :
72 : : template <typename CoordinateSystem>
73 : : struct range
74 : : {
75 : 343 : range (int start_, int next_)
76 : 482 : : start (start_), next (next_)
77 : : {}
78 : :
79 : 758 : int get_min () const { return start; }
80 : 10248 : int get_max () const { return next - 1; }
81 : 650 : int get_next () const { return next; }
82 : 488 : int get_size () const { return next - start; }
83 : :
84 : 300 : int get_midpoint () const { return get_min () + get_size () / 2; }
85 : :
86 : : int start;
87 : : int next;
88 : : };
89 : :
90 : : /* A rectangle area within CoordinateSystem. */
91 : :
92 : : template <typename CoordinateSystem>
93 : : struct rect
94 : : {
95 : 3128 : rect (coord<CoordinateSystem> top_left,
96 : : size<CoordinateSystem> size)
97 : 2042 : : m_top_left (top_left),
98 : 1950 : m_size (size)
99 : : {
100 : : }
101 : :
102 : 167 : rect (range<CoordinateSystem> x_range,
103 : : range<CoordinateSystem> y_range)
104 : 167 : : m_top_left (x_range.get_min (), y_range.get_min ()),
105 : 167 : m_size (x_range.get_size (), y_range.get_size ())
106 : : {
107 : : }
108 : :
109 : 3623 : int get_min_x () const { return m_top_left.x; }
110 : 6407 : int get_min_y () const { return m_top_left.y; }
111 : 39 : int get_max_x () const { return m_top_left.x + m_size.w - 1; }
112 : 192 : int get_max_y () const { return m_top_left.y + m_size.h - 1; }
113 : 114854 : int get_next_x () const { return m_top_left.x + m_size.w; }
114 : 13406 : int get_next_y () const { return m_top_left.y + m_size.h; }
115 : :
116 : 192 : range<CoordinateSystem> get_x_range () const
117 : : {
118 : 192 : return range<CoordinateSystem> (get_min_x (), get_next_x ());
119 : : }
120 : 300 : range<CoordinateSystem> get_y_range () const
121 : : {
122 : 300 : return range<CoordinateSystem> (get_min_y (), get_next_y ());
123 : : }
124 : :
125 : 1137 : int get_width () const { return m_size.w; }
126 : 250 : int get_height () const { return m_size.h; }
127 : :
128 : : coord<CoordinateSystem> m_top_left;
129 : : size<CoordinateSystem> m_size;
130 : : };
131 : :
132 : : template <typename CoordinateSystem>
133 : 264 : rect<CoordinateSystem> operator+ (rect<CoordinateSystem> r,
134 : : coord<CoordinateSystem> offset)
135 : : {
136 : 264 : return rect<CoordinateSystem> (r.m_top_left + offset, r.m_size);
137 : : }
138 : :
139 : : template <typename ElementType, typename SizeType, typename CoordType>
140 : 680 : class array2
141 : : {
142 : : public:
143 : : typedef ElementType element_t;
144 : : typedef SizeType size_t;
145 : : typedef CoordType coord_t;
146 : :
147 : 534 : array2 (size_t sz)
148 : 534 : : m_size (sz),
149 : 534 : m_elements (sz.w * sz.h)
150 : : {
151 : : }
152 : 428 : array2 (array2 &&other)
153 : 428 : : m_size (other.m_size),
154 : 428 : m_elements (std::move (other.m_elements))
155 : : {
156 : : }
157 : :
158 : : /* Move assignment not implemented or used. */
159 : : array2 &operator== (array2 &&other) = delete;
160 : :
161 : : /* No copy ctor or assignment op. */
162 : : array2 (const array2 &other) = delete;
163 : : array2 &operator= (const array2 &other) = delete;
164 : :
165 : :
166 : : const size_t &get_size () const { return m_size; }
167 : :
168 : 264 : void add_row (const element_t &element)
169 : : {
170 : 264 : m_size.h++;
171 : 264 : m_elements.insert (m_elements.end (), m_size.w, element);
172 : 264 : }
173 : :
174 : 324256 : const element_t &get (const coord_t &coord) const
175 : : {
176 : 324256 : ::size_t idx = get_idx (coord);
177 : 324256 : return m_elements[idx];
178 : : }
179 : :
180 : 331674 : void set (const coord_t &coord, const element_t &element)
181 : : {
182 : 331674 : ::size_t idx = get_idx (coord);
183 : 331674 : m_elements[idx] = element;
184 : 331674 : }
185 : :
186 : 534 : void fill (element_t element)
187 : : {
188 : 3532 : for (int y = 0; y < m_size.h; y++)
189 : 153915 : for (int x = 0; x < m_size.w; x++)
190 : 150917 : set (coord_t (x, y), element);
191 : 534 : }
192 : :
193 : : private:
194 : 655930 : ::size_t get_idx (const coord_t &coord) const
195 : : {
196 : 655930 : gcc_assert (coord.x >= 0);
197 : 655930 : gcc_assert (coord.x < m_size.w);
198 : 655930 : gcc_assert (coord.y >= 0);
199 : 655930 : gcc_assert (coord.y < m_size.h);
200 : 655930 : return (coord.y * m_size.w) + coord.x;
201 : : }
202 : :
203 : : size_t m_size;
204 : : std::vector<element_t> m_elements;
205 : : };
206 : :
207 : : /* A combination of attributes describing how to style a text cell.
208 : : We only support those attributes mentioned in invoke.texi:
209 : : - bold,
210 : : - underscore,
211 : : - blink,
212 : : - inverse,
213 : : - colors for foreground and background:
214 : : - default color
215 : : - named colors
216 : : - 16-color mode colors (the "bright" variants)
217 : : - 88-color mode
218 : : - 256-color mode
219 : : plus URLs. */
220 : :
221 : 3759 : struct style
222 : : {
223 : : typedef unsigned char id_t;
224 : : static const id_t id_plain = 0;
225 : :
226 : : /* Colors. */
227 : : enum class named_color
228 : : {
229 : : DEFAULT,
230 : : // ANSI order
231 : : BLACK,
232 : : RED,
233 : : GREEN,
234 : : YELLOW,
235 : : BLUE,
236 : : MAGENTA,
237 : : CYAN,
238 : : WHITE
239 : : };
240 : :
241 : :
242 : : struct color
243 : : {
244 : : enum class kind
245 : : {
246 : : NAMED,
247 : : BITS_8,
248 : : BITS_24,
249 : : } m_kind;
250 : :
251 : : union
252 : : {
253 : : struct {
254 : : enum named_color m_name;
255 : : bool m_bright;
256 : : } m_named;
257 : : uint8_t m_8bit;
258 : : struct {
259 : : uint8_t r;
260 : : uint8_t g;
261 : : uint8_t b;
262 : : } m_24bit;
263 : : } u;
264 : :
265 : : /* Constructor for named colors. */
266 : 4594 : color (enum named_color name = named_color::DEFAULT,
267 : : bool bright = false)
268 : 4011 : : m_kind (kind::NAMED)
269 : : {
270 : 4594 : u.m_named.m_name = name;
271 : 1326 : u.m_named.m_bright = bright;
272 : : }
273 : :
274 : : /* Constructor for 8-bit colors. */
275 : 64 : color (uint8_t col_val)
276 : 8 : : m_kind (kind::BITS_8)
277 : : {
278 : 56 : u.m_8bit = col_val;
279 : : }
280 : :
281 : : /* Constructor for 24-bit colors. */
282 : 24 : color (uint8_t r, uint8_t g, uint8_t b)
283 : 8 : : m_kind (kind::BITS_24)
284 : : {
285 : 24 : u.m_24bit.r = r;
286 : 24 : u.m_24bit.g = g;
287 : 16 : u.m_24bit.b = b;
288 : : }
289 : :
290 : : bool operator== (const color &other) const;
291 : 768 : bool operator!= (const color &other) const
292 : : {
293 : 768 : return !(*this == other);
294 : : }
295 : :
296 : : void print_sgr (pretty_printer *pp, bool fg, bool &need_separator) const;
297 : : };
298 : :
299 : 4003 : style ()
300 : 4003 : : m_bold (false),
301 : 3999 : m_underscore (false),
302 : 3999 : m_blink (false),
303 : 4003 : m_reverse (false),
304 : 4003 : m_fg_color (named_color::DEFAULT),
305 : 4003 : m_bg_color (named_color::DEFAULT),
306 : 1472 : m_url ()
307 : : {}
308 : :
309 : 12296 : bool operator== (const style &other) const
310 : : {
311 : 12296 : return (m_bold == other.m_bold
312 : : && m_underscore == other.m_underscore
313 : : && m_blink == other.m_blink
314 : 12296 : && m_reverse == other.m_reverse
315 : 6944 : && m_fg_color == other.m_fg_color
316 : 2656 : && m_bg_color == other.m_bg_color
317 : 13824 : && m_url == other.m_url);
318 : : }
319 : :
320 : : style &set_style_url (const char *url);
321 : :
322 : : static void print_changes (pretty_printer *pp,
323 : : const style &old_style,
324 : : const style &new_style);
325 : :
326 : : bool m_bold;
327 : : bool m_underscore;
328 : : bool m_blink;
329 : : bool m_reverse;
330 : : color m_fg_color;
331 : : color m_bg_color;
332 : : std::vector<cppchar_t> m_url; // empty = no URL
333 : : };
334 : :
335 : : extern style get_style_from_color_cap_name (const char *name);
336 : :
337 : : /* A class to keep track of all the styles in use in a drawing, so that
338 : : we can refer to them via the compact style::id_t type, rather than
339 : : via e.g. pointers. */
340 : :
341 : 483 : class style_manager
342 : : {
343 : : public:
344 : : style_manager ();
345 : : style::id_t get_or_create_id (const style &style);
346 : 214 : const style &get_style (style::id_t id) const
347 : : {
348 : 190 : return m_styles[id];
349 : : }
350 : : void print_any_style_changes (pretty_printer *pp,
351 : : style::id_t old_id,
352 : : style::id_t new_id) const;
353 : 242 : unsigned get_num_styles () const { return m_styles.size (); }
354 : :
355 : : private:
356 : : std::vector<style> m_styles;
357 : : };
358 : :
359 : 1483268 : class styled_unichar
360 : : {
361 : : public:
362 : : friend class styled_string;
363 : :
364 : 146659 : explicit styled_unichar ()
365 : 146659 : : m_code (0),
366 : 146659 : m_style_id (style::id_plain)
367 : : {}
368 : 25493 : explicit styled_unichar (cppchar_t ch)
369 : 25493 : : m_code (ch),
370 : 25493 : m_emoji_variant_p (false),
371 : 8727 : m_style_id (style::id_plain)
372 : 6395 : {}
373 : 25990 : explicit styled_unichar (cppchar_t ch, bool emoji, style::id_t style_id)
374 : 25990 : : m_code (ch),
375 : 25990 : m_emoji_variant_p (emoji),
376 : 25885 : m_style_id (style_id)
377 : : {
378 : 25990 : gcc_assert (style_id <= 0x7f);
379 : 25885 : }
380 : :
381 : 150357 : cppchar_t get_code () const { return m_code; }
382 : 137367 : bool emoji_variant_p () const { return m_emoji_variant_p; }
383 : 151948 : style::id_t get_style_id () const { return m_style_id; }
384 : :
385 : 153016 : bool double_width_p () const
386 : : {
387 : 153016 : int width = cpp_wcwidth (get_code ());
388 : 153016 : gcc_assert (width == 1 || width == 2);
389 : 153016 : return width == 2;
390 : : }
391 : :
392 : 120 : bool operator== (const styled_unichar &other) const
393 : : {
394 : 120 : return (m_code == other.m_code
395 : 120 : && m_emoji_variant_p == other.m_emoji_variant_p
396 : 240 : && m_style_id == other.m_style_id);
397 : : }
398 : :
399 : 4 : void set_emoji_variant () { m_emoji_variant_p = true; }
400 : :
401 : 19411 : int get_canvas_width () const
402 : : {
403 : 19411 : return cpp_wcwidth (m_code);
404 : : }
405 : :
406 : 4 : void add_combining_char (cppchar_t ch)
407 : : {
408 : 4 : m_combining_chars.push_back (ch);
409 : : }
410 : :
411 : 8 : const std::vector<cppchar_t> get_combining_chars () const
412 : : {
413 : 8 : return m_combining_chars;
414 : : }
415 : :
416 : : private:
417 : : cppchar_t m_code : 24;
418 : : bool m_emoji_variant_p : 1;
419 : : style::id_t m_style_id : 7;
420 : : std::vector<cppchar_t> m_combining_chars;
421 : : };
422 : :
423 : 12336 : class styled_string
424 : : {
425 : : public:
426 : 150 : explicit styled_string () = default;
427 : : explicit styled_string (style_manager &sm, const char *str);
428 : : explicit styled_string (cppchar_t cppchar, bool emoji = false);
429 : :
430 : 11045 : styled_string (styled_string &&) = default;
431 : 68 : styled_string &operator= (styled_string &&) = default;
432 : :
433 : : /* No copy ctor or assignment op. */
434 : : styled_string (const styled_string &) = delete;
435 : : styled_string &operator= (const styled_string &) = delete;
436 : :
437 : : /* For the few cases where copying is required, spell it out explicitly. */
438 : 312 : styled_string copy () const
439 : : {
440 : 312 : styled_string result;
441 : 312 : result.m_chars = m_chars;
442 : 312 : return result;
443 : : }
444 : :
445 : 120 : bool operator== (const styled_string &other) const
446 : : {
447 : 120 : return m_chars == other.m_chars;
448 : : }
449 : :
450 : : static styled_string from_fmt (style_manager &sm,
451 : : printer_fn format_decoder,
452 : : const char *fmt, ...)
453 : : ATTRIBUTE_GCC_PPDIAG(3, 4);
454 : : static styled_string from_fmt_va (style_manager &sm,
455 : : printer_fn format_decoder,
456 : : const char *fmt,
457 : : va_list *args)
458 : : ATTRIBUTE_GCC_PPDIAG(3, 0);
459 : :
460 : 240 : size_t size () const { return m_chars.size (); }
461 : 924 : styled_unichar operator[] (size_t idx) const { return m_chars[idx]; }
462 : :
463 : 2780 : std::vector<styled_unichar>::const_iterator begin () const
464 : : {
465 : 2780 : return m_chars.begin ();
466 : : }
467 : 2780 : std::vector<styled_unichar>::const_iterator end () const
468 : : {
469 : 2780 : return m_chars.end ();
470 : : }
471 : :
472 : : int calc_canvas_width () const;
473 : :
474 : : void append (const styled_string &suffix);
475 : :
476 : : void set_url (style_manager &sm, const char *url);
477 : :
478 : : private:
479 : : std::vector<styled_unichar> m_chars;
480 : : };
481 : :
482 : : enum class x_align
483 : : {
484 : : LEFT,
485 : : CENTER,
486 : : RIGHT
487 : : };
488 : :
489 : : enum class y_align
490 : : {
491 : : TOP,
492 : : CENTER,
493 : : BOTTOM
494 : : };
495 : :
496 : : /* A set of cardinal directions within a canvas or table. */
497 : :
498 : : struct directions
499 : : {
500 : : public:
501 : 25959 : directions (bool up, bool down, bool left, bool right)
502 : 14721 : : m_up (up), m_down (down), m_left (left), m_right (right)
503 : : {
504 : : }
505 : :
506 : 16782 : size_t as_index () const
507 : : {
508 : 16782 : return (m_up << 3) | (m_down << 2) | (m_left << 1) | m_right;
509 : : }
510 : :
511 : : bool m_up: 1;
512 : : bool m_down: 1;
513 : : bool m_left: 1;
514 : : bool m_right: 1;
515 : : };
516 : :
517 : : } // namespace text_art
518 : :
519 : : #endif /* GCC_TEXT_ART_TYPES_H */
|