| /* Types for drawing 2d "text art". |
| Copyright (C) 2023-2025 Free Software Foundation, Inc. |
| Contributed by David Malcolm <dmalcolm@redhat.com>. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it |
| under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #ifndef GCC_TEXT_ART_TYPES_H |
| #define GCC_TEXT_ART_TYPES_H |
| |
| /* This header uses std::vector, but <vector> can't be directly |
| included due to issues with macros. Hence it must be included from |
| system.h by defining INCLUDE_VECTOR in any source file using it. */ |
| |
| #ifndef INCLUDE_VECTOR |
| # error "You must define INCLUDE_VECTOR before including system.h to use text-art/types.h" |
| #endif |
| |
| #include "cpplib.h" |
| #include "pretty-print.h" |
| |
| namespace text_art { |
| |
| /* Forward decls. */ |
| |
| class canvas; |
| class table; |
| class theme; |
| |
| /* Classes for geometry. |
| We use templates to avoid mixing up e.g. canvas coordinates |
| with table coordinates. */ |
| |
| template <typename CoordinateSystem> |
| struct size |
| { |
| size (int w_, int h_) : w (w_), h (h_) {} |
| int w; |
| int h; |
| }; |
| |
| template <typename CoordinateSystem> |
| struct coord |
| { |
| coord (int x_, int y_) : x (x_), y (y_) {} |
| int x; |
| int y; |
| }; |
| |
| template <typename CoordinateSystem> |
| coord<CoordinateSystem> operator+ (coord<CoordinateSystem> a, |
| coord<CoordinateSystem> b) |
| { |
| return coord<CoordinateSystem> (a.x + b.x, a.y + b.y); |
| } |
| |
| /* A half-open range [start, next) of int. */ |
| |
| template <typename CoordinateSystem> |
| struct range |
| { |
| range (int start_, int next_) |
| : start (start_), next (next_) |
| {} |
| |
| int get_min () const { return start; } |
| int get_max () const { return next - 1; } |
| int get_next () const { return next; } |
| int get_size () const { return next - start; } |
| |
| int get_midpoint () const { return get_min () + get_size () / 2; } |
| |
| int start; |
| int next; |
| }; |
| |
| /* A rectangle area within CoordinateSystem. */ |
| |
| template <typename CoordinateSystem> |
| struct rect |
| { |
| rect (coord<CoordinateSystem> top_left, |
| size<CoordinateSystem> size) |
| : m_top_left (top_left), |
| m_size (size) |
| { |
| } |
| |
| rect (range<CoordinateSystem> x_range, |
| range<CoordinateSystem> y_range) |
| : m_top_left (x_range.get_min (), y_range.get_min ()), |
| m_size (x_range.get_size (), y_range.get_size ()) |
| { |
| } |
| |
| int get_min_x () const { return m_top_left.x; } |
| int get_min_y () const { return m_top_left.y; } |
| int get_max_x () const { return m_top_left.x + m_size.w - 1; } |
| int get_max_y () const { return m_top_left.y + m_size.h - 1; } |
| int get_next_x () const { return m_top_left.x + m_size.w; } |
| int get_next_y () const { return m_top_left.y + m_size.h; } |
| |
| range<CoordinateSystem> get_x_range () const |
| { |
| return range<CoordinateSystem> (get_min_x (), get_next_x ()); |
| } |
| range<CoordinateSystem> get_y_range () const |
| { |
| return range<CoordinateSystem> (get_min_y (), get_next_y ()); |
| } |
| |
| int get_width () const { return m_size.w; } |
| int get_height () const { return m_size.h; } |
| |
| coord<CoordinateSystem> m_top_left; |
| size<CoordinateSystem> m_size; |
| }; |
| |
| template <typename CoordinateSystem> |
| rect<CoordinateSystem> operator+ (rect<CoordinateSystem> r, |
| coord<CoordinateSystem> offset) |
| { |
| return rect<CoordinateSystem> (r.m_top_left + offset, r.m_size); |
| } |
| |
| template <typename ElementType, typename SizeType, typename CoordType> |
| class array2 |
| { |
| public: |
| typedef ElementType element_t; |
| typedef SizeType size_t; |
| typedef CoordType coord_t; |
| |
| array2 (size_t sz) |
| : m_size (sz), |
| m_elements (sz.w * sz.h) |
| { |
| } |
| array2 (array2 &&other) |
| : m_size (other.m_size), |
| m_elements (std::move (other.m_elements)) |
| { |
| } |
| |
| /* Move assignment not implemented or used. */ |
| array2 &operator== (array2 &&other) = delete; |
| |
| /* No copy ctor or assignment op. */ |
| array2 (const array2 &other) = delete; |
| array2 &operator= (const array2 &other) = delete; |
| |
| |
| const size_t &get_size () const { return m_size; } |
| |
| void add_row (const element_t &element) |
| { |
| m_size.h++; |
| m_elements.insert (m_elements.end (), m_size.w, element); |
| } |
| |
| const element_t &get (const coord_t &coord) const |
| { |
| ::size_t idx = get_idx (coord); |
| return m_elements[idx]; |
| } |
| |
| void set (const coord_t &coord, const element_t &element) |
| { |
| ::size_t idx = get_idx (coord); |
| m_elements[idx] = element; |
| } |
| |
| void fill (element_t element) |
| { |
| for (int y = 0; y < m_size.h; y++) |
| for (int x = 0; x < m_size.w; x++) |
| set (coord_t (x, y), element); |
| } |
| |
| private: |
| ::size_t get_idx (const coord_t &coord) const |
| { |
| gcc_assert (coord.x >= 0); |
| gcc_assert (coord.x < m_size.w); |
| gcc_assert (coord.y >= 0); |
| gcc_assert (coord.y < m_size.h); |
| return (coord.y * m_size.w) + coord.x; |
| } |
| |
| size_t m_size; |
| std::vector<element_t> m_elements; |
| }; |
| |
| /* A combination of attributes describing how to style a text cell. |
| We only support those attributes mentioned in invoke.texi: |
| - bold, |
| - underscore, |
| - blink, |
| - inverse, |
| - colors for foreground and background: |
| - default color |
| - named colors |
| - 16-color mode colors (the "bright" variants) |
| - 88-color mode |
| - 256-color mode |
| plus URLs. */ |
| |
| struct style |
| { |
| typedef unsigned char id_t; |
| static const id_t id_plain = 0; |
| |
| /* Colors. */ |
| enum class named_color |
| { |
| DEFAULT, |
| // ANSI order |
| BLACK, |
| RED, |
| GREEN, |
| YELLOW, |
| BLUE, |
| MAGENTA, |
| CYAN, |
| WHITE |
| }; |
| |
| |
| struct color |
| { |
| enum class kind |
| { |
| NAMED, |
| BITS_8, |
| BITS_24, |
| } m_kind; |
| |
| union |
| { |
| struct { |
| enum named_color m_name; |
| bool m_bright; |
| } m_named; |
| uint8_t m_8bit; |
| struct { |
| uint8_t r; |
| uint8_t g; |
| uint8_t b; |
| } m_24bit; |
| } u; |
| |
| /* Constructor for named colors. */ |
| color (enum named_color name = named_color::DEFAULT, |
| bool bright = false) |
| : m_kind (kind::NAMED) |
| { |
| u.m_named.m_name = name; |
| u.m_named.m_bright = bright; |
| } |
| |
| /* Constructor for 8-bit colors. */ |
| color (uint8_t col_val) |
| : m_kind (kind::BITS_8) |
| { |
| u.m_8bit = col_val; |
| } |
| |
| /* Constructor for 24-bit colors. */ |
| color (uint8_t r, uint8_t g, uint8_t b) |
| : m_kind (kind::BITS_24) |
| { |
| u.m_24bit.r = r; |
| u.m_24bit.g = g; |
| u.m_24bit.b = b; |
| } |
| |
| bool operator== (const color &other) const; |
| bool operator!= (const color &other) const |
| { |
| return !(*this == other); |
| } |
| |
| void print_sgr (pretty_printer *pp, bool fg, bool &need_separator) const; |
| }; |
| |
| style () |
| : m_bold (false), |
| m_underscore (false), |
| m_blink (false), |
| m_reverse (false), |
| m_fg_color (named_color::DEFAULT), |
| m_bg_color (named_color::DEFAULT), |
| m_url () |
| {} |
| |
| bool operator== (const style &other) const |
| { |
| return (m_bold == other.m_bold |
| && m_underscore == other.m_underscore |
| && m_blink == other.m_blink |
| && m_reverse == other.m_reverse |
| && m_fg_color == other.m_fg_color |
| && m_bg_color == other.m_bg_color |
| && m_url == other.m_url); |
| } |
| |
| style &set_style_url (const char *url); |
| |
| static void print_changes (pretty_printer *pp, |
| const style &old_style, |
| const style &new_style); |
| |
| bool m_bold; |
| bool m_underscore; |
| bool m_blink; |
| bool m_reverse; |
| color m_fg_color; |
| color m_bg_color; |
| std::vector<cppchar_t> m_url; // empty = no URL |
| }; |
| |
| extern style get_style_from_color_cap_name (const char *name); |
| |
| /* A class to keep track of all the styles in use in a drawing, so that |
| we can refer to them via the compact style::id_t type, rather than |
| via e.g. pointers. */ |
| |
| class style_manager |
| { |
| public: |
| style_manager (); |
| style::id_t get_or_create_id (const style &style); |
| const style &get_style (style::id_t id) const |
| { |
| return m_styles[id]; |
| } |
| void print_any_style_changes (pretty_printer *pp, |
| style::id_t old_id, |
| style::id_t new_id) const; |
| unsigned get_num_styles () const { return m_styles.size (); } |
| |
| private: |
| std::vector<style> m_styles; |
| }; |
| |
| class styled_unichar |
| { |
| public: |
| friend class styled_string; |
| |
| explicit styled_unichar () |
| : m_code (0), |
| m_style_id (style::id_plain) |
| {} |
| explicit styled_unichar (cppchar_t ch) |
| : m_code (ch), |
| m_emoji_variant_p (false), |
| m_style_id (style::id_plain) |
| {} |
| explicit styled_unichar (cppchar_t ch, bool emoji, style::id_t style_id) |
| : m_code (ch), |
| m_emoji_variant_p (emoji), |
| m_style_id (style_id) |
| { |
| gcc_assert (style_id <= 0x7f); |
| } |
| |
| cppchar_t get_code () const { return m_code; } |
| bool emoji_variant_p () const { return m_emoji_variant_p; } |
| style::id_t get_style_id () const { return m_style_id; } |
| |
| bool double_width_p () const |
| { |
| int width = cpp_wcwidth (get_code ()); |
| gcc_assert (width == 1 || width == 2); |
| return width == 2; |
| } |
| |
| bool operator== (const styled_unichar &other) const |
| { |
| return (m_code == other.m_code |
| && m_emoji_variant_p == other.m_emoji_variant_p |
| && m_style_id == other.m_style_id); |
| } |
| |
| void set_emoji_variant () { m_emoji_variant_p = true; } |
| |
| int get_canvas_width () const |
| { |
| return cpp_wcwidth (m_code); |
| } |
| |
| void add_combining_char (cppchar_t ch) |
| { |
| m_combining_chars.push_back (ch); |
| } |
| |
| const std::vector<cppchar_t> get_combining_chars () const |
| { |
| return m_combining_chars; |
| } |
| |
| private: |
| cppchar_t m_code : 24; |
| bool m_emoji_variant_p : 1; |
| style::id_t m_style_id : 7; |
| std::vector<cppchar_t> m_combining_chars; |
| }; |
| |
| class styled_string |
| { |
| public: |
| explicit styled_string () = default; |
| explicit styled_string (style_manager &sm, const char *str); |
| explicit styled_string (cppchar_t cppchar, bool emoji = false); |
| |
| styled_string (styled_string &&) = default; |
| styled_string &operator= (styled_string &&) = default; |
| |
| /* No copy ctor or assignment op. */ |
| styled_string (const styled_string &) = delete; |
| styled_string &operator= (const styled_string &) = delete; |
| |
| /* For the few cases where copying is required, spell it out explicitly. */ |
| styled_string copy () const |
| { |
| styled_string result; |
| result.m_chars = m_chars; |
| return result; |
| } |
| |
| bool operator== (const styled_string &other) const |
| { |
| return m_chars == other.m_chars; |
| } |
| |
| static styled_string from_fmt (style_manager &sm, |
| printer_fn format_decoder, |
| const char *fmt, ...) |
| ATTRIBUTE_GCC_PPDIAG(3, 4); |
| static styled_string from_fmt_va (style_manager &sm, |
| printer_fn format_decoder, |
| const char *fmt, |
| va_list *args) |
| ATTRIBUTE_GCC_PPDIAG(3, 0); |
| |
| size_t size () const { return m_chars.size (); } |
| styled_unichar operator[] (size_t idx) const { return m_chars[idx]; } |
| |
| std::vector<styled_unichar>::const_iterator begin () const |
| { |
| return m_chars.begin (); |
| } |
| std::vector<styled_unichar>::const_iterator end () const |
| { |
| return m_chars.end (); |
| } |
| |
| int calc_canvas_width () const; |
| |
| void append (const styled_string &suffix); |
| |
| void set_url (style_manager &sm, const char *url); |
| |
| private: |
| std::vector<styled_unichar> m_chars; |
| }; |
| |
| enum class x_align |
| { |
| LEFT, |
| CENTER, |
| RIGHT |
| }; |
| |
| enum class y_align |
| { |
| TOP, |
| CENTER, |
| BOTTOM |
| }; |
| |
| /* A set of cardinal directions within a canvas or table. */ |
| |
| struct directions |
| { |
| public: |
| directions (bool up, bool down, bool left, bool right) |
| : m_up (up), m_down (down), m_left (left), m_right (right) |
| { |
| } |
| |
| size_t as_index () const |
| { |
| return (m_up << 3) | (m_down << 2) | (m_left << 1) | m_right; |
| } |
| |
| bool m_up: 1; |
| bool m_down: 1; |
| bool m_left: 1; |
| bool m_right: 1; |
| }; |
| |
| } // namespace text_art |
| |
| #endif /* GCC_TEXT_ART_TYPES_H */ |