LCOV - code coverage report
Current view: top level - src/terminal - terminalframebuffer.h (source / functions) Hit Total Coverage
Test: mosh-1.3.2 Code Coverage Lines: 115 135 85.2 %
Date: 2022-02-06 20:19:53 Functions: 14 15 93.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :     Mosh: the mobile shell
       3             :     Copyright 2012 Keith Winstein
       4             : 
       5             :     This program is free software: you can redistribute it and/or modify
       6             :     it under the terms of the GNU General Public License as published by
       7             :     the Free Software Foundation, either version 3 of the License, or
       8             :     (at your option) any later version.
       9             : 
      10             :     This program is distributed in the hope that it will be useful,
      11             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :     GNU General Public License for more details.
      14             : 
      15             :     You should have received a copy of the GNU General Public License
      16             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             : 
      18             :     In addition, as a special exception, the copyright holders give
      19             :     permission to link the code of portions of this program with the
      20             :     OpenSSL library under certain conditions as described in each
      21             :     individual source file, and distribute linked combinations including
      22             :     the two.
      23             : 
      24             :     You must obey the GNU General Public License in all respects for all
      25             :     of the code used other than OpenSSL. If you modify file(s) with this
      26             :     exception, you may extend this exception to your version of the
      27             :     file(s), but you are not obligated to do so. If you do not wish to do
      28             :     so, delete this exception statement from your version. If you delete
      29             :     this exception statement from all source files in the program, then
      30             :     also delete it here.
      31             : */
      32             : 
      33             : #ifndef TERMINALFB_HPP
      34             : #define TERMINALFB_HPP
      35             : 
      36             : #include <assert.h>
      37             : #include <limits.h>
      38             : #include <stdint.h>
      39             : 
      40             : #include <vector>
      41             : #include <deque>
      42             : #include <string>
      43             : #include <list>
      44             : 
      45             : #include "shared.h"
      46             : 
      47             : /* Terminal framebuffer */
      48             : 
      49             : namespace Terminal {
      50             :   using shared::shared_ptr;
      51             :   using shared::make_shared;
      52             :   typedef uint32_t color_type;
      53             : 
      54             :   class Renditions {
      55             :   public:
      56             :     typedef enum { bold, faint, italic, underlined, blink, inverse, invisible, SIZE } attribute_type;
      57             : 
      58             :   private:
      59             :     static const uint64_t true_color_mask = 0x1000000;
      60             :     uint64_t foreground_color : 25;
      61             :     uint64_t background_color : 25;
      62             :     uint64_t attributes : 8;
      63             : 
      64             :   public:
      65             :     Renditions( color_type s_background );
      66             :     void set_foreground_color( int num );
      67             :     void set_background_color( int num );
      68             :     void set_rendition( color_type num );
      69             :     std::string sgr( void ) const;
      70             : 
      71        7398 :     static unsigned int make_true_color( unsigned int r, unsigned int g, unsigned int b ) {
      72        7398 :       return true_color_mask | (r << 16) | (g << 8) | b;
      73             :     }
      74             : 
      75             :     static bool is_true_color(unsigned int color) {
      76             :       return (color & true_color_mask) != 0;
      77             :     }
      78             : 
      79             :     // unsigned int get_foreground_rendition() const { return foreground_color; }
      80    48051945 :     unsigned int get_background_rendition() const { return background_color; }
      81             : 
      82    42452437 :     bool operator==( const Renditions &x ) const
      83             :     {
      84    42452437 :       return ( attributes == x.attributes )
      85    42452028 :         && ( foreground_color == x.foreground_color )
      86    84884949 :         && ( background_color == x.background_color );
      87             :     }
      88        4208 :     void set_attribute( attribute_type attr, bool val )
      89             :     {
      90        4208 :       attributes = val ?
      91        4206 :         ( attributes | (1 << attr) ) :
      92           2 :         ( attributes & ~(1 << attr) );
      93        4208 :     }
      94       41830 :     bool get_attribute( attribute_type attr ) const { return attributes & ( 1 << attr ); }
      95       10550 :     void clear_attributes() { attributes = 0; }
      96             :   };
      97             : 
      98  1940974982 :   class Cell {
      99             :   private:
     100             :     typedef std::string content_type; /* can be std::string, std::vector<uint8_t>, or __gnu_cxx::__vstring */
     101             :     content_type contents;
     102             :     Renditions renditions;
     103             :     unsigned int wide : 1; /* 0 = narrow, 1 = wide */
     104             :     unsigned int fallback : 1; /* first character is combining character */
     105             :     unsigned int wrap : 1;
     106             : 
     107             :   private:
     108             :     Cell();
     109             :   public:
     110             :     Cell( color_type background_color );
     111             : 
     112             :     void reset( color_type background_color );
     113             : 
     114    31060700 :     bool operator==( const Cell &x ) const
     115             :     {
     116    31060700 :       return ( (contents == x.contents)
     117    30474865 :                && (fallback == x.fallback)
     118    30474865 :                && (wide == x.wide)
     119    30474865 :                && (renditions == x.renditions)
     120    61535148 :                && (wrap == x.wrap) );
     121             :     }
     122             : 
     123       43467 :     bool operator!=( const Cell &x ) const { return !operator==( x ); }
     124             : 
     125             :     /* Accessors for contents field */
     126             :     std::string debug_contents( void ) const;
     127             : 
     128     1655001 :     bool empty( void ) const { return contents.empty(); }
     129             :     /* 32 seems like a reasonable limit on combining characters */
     130          12 :     bool full( void ) const { return contents.size() >= 32; }
     131         982 :     void clear( void ) { contents.clear(); }
     132             : 
     133    20423150 :     bool is_blank( void ) const
     134             :     {
     135             :       // XXX fix.
     136    20423150 :       return ( contents.empty()
     137      241516 :                || contents == " "
     138    20618438 :                || contents == "\xC2\xA0" );
     139             :     }
     140             : 
     141    10257723 :     bool contents_match ( const Cell &other ) const
     142             :     {
     143    20323449 :       return ( is_blank() && other.is_blank() )
     144    10259013 :              || ( contents == other.contents );
     145             :     }
     146             : 
     147             :     bool compare( const Cell &other ) const;
     148             : 
     149             :     // Is this a printing ISO 8859-1 character?
     150    24028354 :     static bool isprint_iso8859_1( const wchar_t c )
     151             :     {
     152    24028354 :       return ( c <= 0xff && c >= 0xa0 ) || ( c <= 0x7e && c >= 0x20 );
     153             :     }
     154             : 
     155           0 :    static void append_to_str( std::string &dest, const wchar_t c )
     156             :     {
     157             :       /* ASCII?  Cheat. */
     158           0 :       if ( static_cast<uint32_t>(c) <= 0x7f ) {
     159           0 :         dest.push_back( static_cast<char>(c) );
     160           0 :         return;
     161             :       }
     162           0 :       static mbstate_t ps = mbstate_t();
     163           0 :       char tmp[MB_LEN_MAX];
     164           0 :       size_t ignore = wcrtomb(NULL, 0, &ps);
     165           0 :       (void)ignore;
     166           0 :       size_t len = wcrtomb(tmp, c, &ps);
     167           0 :       dest.append( tmp, len );
     168             :     }
     169             : 
     170    24029016 :     void append( const wchar_t c )
     171             :     {
     172             :       /* ASCII?  Cheat. */
     173    24029016 :       if ( static_cast<uint32_t>(c) <= 0x7f ) {
     174    24027822 :         contents.push_back( static_cast<char>(c) );
     175    24027822 :         return;
     176             :       }
     177        1194 :       static mbstate_t ps = mbstate_t();
     178        1194 :       char tmp[MB_LEN_MAX];
     179        1194 :       size_t ignore = wcrtomb(NULL, 0, &ps);
     180        1194 :       (void)ignore;
     181        1194 :       size_t len = wcrtomb(tmp, c, &ps);
     182        1194 :       contents.insert( contents.end(), tmp, tmp+len );
     183             :     }
     184             : 
     185    21101133 :     void print_grapheme( std::string &output ) const
     186             :     {
     187    21101133 :       if ( contents.empty() ) {
     188    20083264 :         output.append( 1, ' ' );
     189    20083264 :         return;
     190             :       }
     191             :       /*
     192             :        * cells that begin with combining character get combiner
     193             :        * attached to no-break space
     194             :        */
     195     1017869 :       if ( fallback ) {
     196          52 :         output.append( "\xC2\xA0" );
     197             :       }
     198     1017869 :       output.append( contents );
     199             :     }
     200             : 
     201             :     /* Other accessors */
     202     1656511 :     const Renditions& get_renditions( void ) const { return renditions; }
     203          18 :     Renditions& get_renditions( void ) { return renditions; }
     204    24028342 :     void set_renditions( const Renditions& r ) { renditions = r; }
     205           4 :     bool get_wide( void ) const { return wide; }
     206    24028342 :     void set_wide( bool w ) { wide = w; }
     207    29611014 :     unsigned int get_width( void ) const { return wide + 1; }
     208             :     bool get_fallback( void ) const { return fallback; }
     209           4 :     void set_fallback( bool f ) { fallback = f; }
     210      385328 :     bool get_wrap( void ) const { return wrap; }
     211        1876 :     void set_wrap( bool f ) { wrap = f; }
     212             :   };
     213             : 
     214    24048969 :   class Row {
     215             :   public:
     216             :     typedef std::vector<Cell> cells_type;
     217             :     cells_type cells;
     218             :     // gen is a generation counter.  It can be used to quickly rule
     219             :     // out the possibility of two rows being identical; this is useful
     220             :     // in scrolling.
     221             :     uint64_t gen;
     222             : 
     223             :   private:
     224             :     Row();
     225             :   public:
     226             :     Row( const size_t s_width, const color_type background_color );
     227             : 
     228             :     void insert_cell( int col, color_type background_color );
     229             :     void delete_cell( int col, color_type background_color );
     230             : 
     231             :     void reset( color_type background_color );
     232             : 
     233      385758 :     bool operator==( const Row &x ) const
     234             :     {
     235      385758 :       return ( gen == x.gen && cells == x.cells );
     236             :     }
     237             : 
     238      385328 :     bool get_wrap( void ) const { return cells.back().get_wrap(); }
     239        1876 :     void set_wrap( bool w ) { cells.back().set_wrap( w ); }
     240             : 
     241             :     uint64_t get_gen() const;
     242             :   };
     243             : 
     244             :   class SavedCursor {
     245             :   public:
     246             :     int cursor_col, cursor_row;
     247             :     Renditions renditions;
     248             :     /* not implemented: character set shift state */
     249             :     bool auto_wrap_mode;
     250             :     bool origin_mode;
     251             :     /* not implemented: state of selective erase */
     252             : 
     253             :     SavedCursor();
     254             :   };
     255             : 
     256           0 :   class DrawState {
     257             :   private:
     258             :     int width, height;
     259             : 
     260             :     void new_grapheme( void );
     261             :     void snap_cursor_to_border( void );
     262             : 
     263             :     int cursor_col, cursor_row;
     264             :     int combining_char_col, combining_char_row;
     265             : 
     266             :     bool default_tabs;
     267             :     std::vector<bool> tabs;
     268             : 
     269             :     void reinitialize_tabs( unsigned int start );
     270             : 
     271             :     int scrolling_region_top_row, scrolling_region_bottom_row;
     272             : 
     273             :     Renditions renditions;
     274             : 
     275             :     SavedCursor save;
     276             : 
     277             :   public:
     278             :     bool next_print_will_wrap;
     279             :     bool origin_mode;
     280             :     bool auto_wrap_mode;
     281             :     bool insert_mode;
     282             :     bool cursor_visible;
     283             :     bool reverse_video;
     284             :     bool bracketed_paste;
     285             : 
     286             :     enum MouseReportingMode {
     287             :       MOUSE_REPORTING_NONE = 0,
     288             :       MOUSE_REPORTING_X10 = 9,
     289             :       MOUSE_REPORTING_VT220 = 1000,
     290             :       MOUSE_REPORTING_VT220_HILIGHT = 1001,
     291             :       MOUSE_REPORTING_BTN_EVENT = 1002,
     292             :       MOUSE_REPORTING_ANY_EVENT = 1003
     293             :     } mouse_reporting_mode;
     294             : 
     295             :     bool mouse_focus_event;       // 1004
     296             :     bool mouse_alternate_scroll;  // 1007
     297             : 
     298             :     enum MouseEncodingMode {
     299             :       MOUSE_ENCODING_DEFAULT = 0,
     300             :       MOUSE_ENCODING_UTF8 = 1005,
     301             :       MOUSE_ENCODING_SGR = 1006,
     302             :       MOUSE_ENCODING_URXVT = 1015
     303             :     } mouse_encoding_mode;
     304             : 
     305             :     bool application_mode_cursor_keys;
     306             : 
     307             :     /* bold, etc. */
     308             : 
     309             :     void move_row( int N, bool relative = false );
     310             :     void move_col( int N, bool relative = false, bool implicit = false );
     311             : 
     312    24076789 :     int get_cursor_col( void ) const { return cursor_col; }
     313    23997298 :     int get_cursor_row( void ) const { return cursor_row; }
     314          12 :     int get_combining_char_col( void ) const { return combining_char_col; }
     315          12 :     int get_combining_char_row( void ) const { return combining_char_row; }
     316      652357 :     int get_width( void ) const { return width; }
     317     1272074 :     int get_height( void ) const { return height; }
     318             : 
     319             :     void set_tab( void );
     320             :     void clear_tab( int col );
     321           0 :     void clear_default_tabs( void ) { default_tabs = false; }
     322             :     /* Default tabs can't be restored without resetting the draw state. */
     323             :     int get_next_tab( int count ) const;
     324             : 
     325             :     void set_scrolling_region( int top, int bottom );
     326             : 
     327    95531190 :     int get_scrolling_region_top_row( void ) const { return scrolling_region_top_row; }
     328    71666659 :     int get_scrolling_region_bottom_row( void ) const { return scrolling_region_bottom_row; }
     329             : 
     330             :     int limit_top( void ) const;
     331             :     int limit_bottom( void ) const;
     332             : 
     333        5200 :     void set_foreground_color( int x ) { renditions.set_foreground_color( x ); }
     334        5212 :     void set_background_color( int x ) { renditions.set_background_color( x ); }
     335       14918 :     void add_rendition( color_type x ) { renditions.set_rendition( x ); }
     336       24199 :     const Renditions& get_renditions( void ) const { return renditions; }
     337    24028342 :     Renditions& get_renditions( void ) { return renditions; }
     338    24186798 :     int get_background_rendition( void ) const { return renditions.get_background_rendition(); }
     339             : 
     340             :     void save_cursor( void );
     341             :     void restore_cursor( void );
     342           0 :     void clear_saved_cursor( void ) { save = SavedCursor(); }
     343             : 
     344             :     void resize( int s_width, int s_height );
     345             : 
     346             :     DrawState( int s_width, int s_height );
     347             : 
     348       16609 :     bool operator==( const DrawState &x ) const
     349             :     {
     350             :       /* only compare fields that affect display */
     351       16609 :       return ( width == x.width ) && ( height == x.height ) && ( cursor_col == x.cursor_col )
     352       16609 :         && ( cursor_row == x.cursor_row ) && ( cursor_visible == x.cursor_visible ) &&
     353       15467 :         ( reverse_video == x.reverse_video ) && ( renditions == x.renditions ) &&
     354       15467 :   ( bracketed_paste == x.bracketed_paste ) && ( mouse_reporting_mode == x.mouse_reporting_mode ) &&
     355       32076 :   ( mouse_focus_event == x.mouse_focus_event ) && ( mouse_alternate_scroll == x.mouse_alternate_scroll) &&
     356       15467 :   ( mouse_encoding_mode == x.mouse_encoding_mode );
     357             :     }
     358             :   };
     359             : 
     360             :   class Framebuffer {
     361             :     // To minimize copying of rows and cells, we use shared_ptr to
     362             :     // share unchanged rows between multiple Framebuffers.  If we
     363             :     // write to a row in a Framebuffer and it is shared with other
     364             :     // owners, we copy it first.  The shared_ptr naturally manages the
     365             :     // usage of the actual rows themselves.
     366             :     //
     367             :     // We gain a couple of free extras by doing this:
     368             :     //
     369             :     // * A quick check for equality between rows in different
     370             :     // Framebuffers is to simply compare the pointer values.  If they
     371             :     // are equal, then the rows are obviously identical.
     372             :     // * If no row is shared, the frame has not been modified.
     373             :   public:
     374             :     typedef std::vector<wchar_t> title_type;
     375             :     typedef shared_ptr<Row> row_pointer;
     376             :     typedef std::vector<row_pointer> rows_type; /* can be either std::vector or std::deque */
     377             : 
     378             :   private:
     379             :     rows_type rows;
     380             :     title_type icon_name;
     381             :     title_type window_title;
     382             :     title_type clipboard;
     383             :     unsigned int bell_count;
     384             :     bool title_initialized; /* true if the window title has been set via an OSC */
     385             : 
     386    23865147 :     row_pointer newrow( void )
     387             :     {
     388    23865147 :       const size_t w = ds.get_width();
     389    23865147 :       const color_type c = ds.get_background_rendition();
     390    23865147 :       return make_shared<Row>( w, c );
     391             :     }
     392             : 
     393             :   public:
     394             :     Framebuffer( int s_width, int s_height );
     395             :     Framebuffer( const Framebuffer &other );
     396             :     Framebuffer &operator=( const Framebuffer &other );
     397             :     DrawState ds;
     398             : 
     399       24199 :     const rows_type &get_rows() const { return rows; }
     400             : 
     401             :     void scroll( int N );
     402             :     void move_rows_autoscroll( int rows );
     403             : 
     404      954674 :     inline const Row *get_row( int row ) const
     405             :     {
     406      578066 :       if ( row == -1 ) row = ds.get_cursor_row();
     407             : 
     408      954674 :       return rows.at( row ).get();
     409             :     }
     410             : 
     411    20759523 :     inline const Cell *get_cell( int row = -1, int col = -1 ) const
     412             :     {
     413    20759523 :       if ( row == -1 ) row = ds.get_cursor_row();
     414    20759523 :       if ( col == -1 ) col = ds.get_cursor_col();
     415             : 
     416    20759523 :       return &rows.at( row )->cells.at( col );
     417             :     }
     418             : 
     419    24185988 :     Row *get_mutable_row( int row )
     420             :     {
     421    24185988 :       if ( row == -1 ) row = ds.get_cursor_row();
     422    24185988 :       row_pointer &mutable_row = rows.at( row );
     423             :       // If the row is shared, copy it.
     424    24185988 :       if (!mutable_row.unique()) {
     425       81984 :         mutable_row = make_shared<Row>( *mutable_row );
     426             :       }
     427    24185988 :       return mutable_row.get();
     428             :     }
     429             : 
     430    24181242 :     Cell *get_mutable_cell( int row = -1, int col = -1 )
     431             :     {
     432    24181242 :       if ( row == -1 ) row = ds.get_cursor_row();
     433    24181242 :       if ( col == -1 ) col = ds.get_cursor_col();
     434             : 
     435    24181242 :       return &get_mutable_row( row )->cells.at( col );
     436             :     }
     437             : 
     438             :     Cell *get_combining_cell( void );
     439             : 
     440             :     void apply_renditions_to_cell( Cell *cell );
     441             : 
     442             :     void insert_line( int before_row, int count );
     443             :     void delete_line( int row, int count );
     444             : 
     445             :     void insert_cell( int row, int col );
     446             :     void delete_cell( int row, int col );
     447             : 
     448             :     void reset( void );
     449             :     void soft_reset( void );
     450             : 
     451           0 :     void set_title_initialized( void ) { title_initialized = true; }
     452       24199 :     bool is_title_initialized( void ) const { return title_initialized; }
     453           0 :     void set_icon_name( const title_type &s ) { icon_name = s; }
     454           0 :     void set_window_title( const title_type &s ) { window_title = s; }
     455           0 :     void set_clipboard( const title_type &s ) { clipboard = s; }
     456           0 :     const title_type & get_icon_name( void ) const { return icon_name; }
     457           0 :     const title_type & get_window_title( void ) const { return window_title; }
     458       24199 :     const title_type & get_clipboard( void ) const { return clipboard; }
     459             : 
     460             :     void prefix_window_title( const title_type &s );
     461             : 
     462             :     void resize( int s_width, int s_height );
     463             : 
     464    24179896 :     void reset_cell( Cell *c ) { c->reset( ds.get_background_rendition() ); }
     465        4454 :     void reset_row( Row *r ) { r->reset( ds.get_background_rendition() ); }
     466             : 
     467           0 :     void ring_bell( void ) { bell_count++; }
     468       24199 :     unsigned int get_bell_count( void ) const { return bell_count; }
     469             : 
     470       85482 :     bool operator==( const Framebuffer &x ) const
     471             :     {
     472       85482 :       return ( rows == x.rows ) && ( window_title == x.window_title ) && ( clipboard  == x.clipboard ) && ( bell_count == x.bell_count ) && ( ds == x.ds );
     473             :     }
     474             :   };
     475             : }
     476             : 
     477             : #endif

Generated by: LCOV version 1.14