OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 // |MotermModel| is a class providing a model for terminal emulation. The basic |
| 6 // operations are providing "input" bytes (this is input from the point of view |
| 7 // of the terminal; from the point of view of applications, it's output) and |
| 8 // determining what character to display at any given position (with what |
| 9 // attributes). |
| 10 // |
| 11 // Note that no termios-style processing of the "input" bytes is done. The |
| 12 // "input" bytes should be as seen on the wire by a serial terminal. |
| 13 // |
| 14 // This class does not handle "output" from the terminal (i.e., its keyboard, |
| 15 // and thus "input" to applications). |
| 16 // |
| 17 // The current implementation is on top of FreeBSD's libteken, though it would |
| 18 // be straightforward to replace it with another terminal emulation library (or |
| 19 // implement one directly). |
| 20 |
| 21 #ifndef APPS_MOTERM_MOTERM_MODEL_H_ |
| 22 #define APPS_MOTERM_MOTERM_MODEL_H_ |
| 23 |
| 24 #include <stddef.h> |
| 25 #include <stdint.h> |
| 26 |
| 27 #include "base/macros.h" |
| 28 #include "base/memory/scoped_ptr.h" |
| 29 #include "third_party/libteken/teken/teken.h" |
| 30 |
| 31 class MotermModel { |
| 32 public: |
| 33 // Position: zero-based, starting from upper-left. (Quantities are signed to |
| 34 // allow for relative and off-screen positions.) |
| 35 struct Position { |
| 36 Position(int row = 0, int column = 0) : row(row), column(column) {} |
| 37 |
| 38 int row; |
| 39 int column; |
| 40 }; |
| 41 |
| 42 struct Size { |
| 43 Size(unsigned rows = 0, unsigned columns = 0) |
| 44 : rows(rows), columns(columns) {} |
| 45 |
| 46 unsigned rows; |
| 47 unsigned columns; |
| 48 }; |
| 49 |
| 50 struct Rectangle { |
| 51 Rectangle(int row = 0, |
| 52 int column = 0, |
| 53 unsigned rows = 0, |
| 54 unsigned columns = 0) |
| 55 : position(row, column), size(rows, columns) {} |
| 56 |
| 57 bool IsEmpty() const { return !size.rows || !size.columns; } |
| 58 |
| 59 Position position; |
| 60 Size size; |
| 61 }; |
| 62 |
| 63 struct Color { |
| 64 Color(uint8_t red = 0, uint8_t green = 0, uint8_t blue = 0) |
| 65 : red(red), green(green), blue(blue) {} |
| 66 |
| 67 uint8_t red; |
| 68 uint8_t green; |
| 69 uint8_t blue; |
| 70 }; |
| 71 |
| 72 using Attributes = uint32_t; |
| 73 static const Attributes kAttributesBold = 1; |
| 74 static const Attributes kAttributesUnderline = 2; |
| 75 static const Attributes kAttributesBlink = 4; |
| 76 |
| 77 struct CharacterInfo { |
| 78 CharacterInfo(uint32_t code_point, |
| 79 Attributes attributes, |
| 80 const Color& foreground_color, |
| 81 const Color& background_color) |
| 82 : code_point(code_point), |
| 83 attributes(attributes), |
| 84 foreground_color(foreground_color), |
| 85 background_color(background_color) {} |
| 86 |
| 87 uint32_t code_point; // Unicode, of course. |
| 88 Attributes attributes; |
| 89 Color foreground_color; |
| 90 Color background_color; |
| 91 }; |
| 92 |
| 93 struct StateChanges { |
| 94 StateChanges() : cursor_moved(false), bell_count(0), dirty_rect() {} |
| 95 |
| 96 bool IsDirty() const { |
| 97 return cursor_moved || bell_count > 0 || !dirty_rect.IsEmpty(); |
| 98 } |
| 99 void Reset() { *this = StateChanges(); } |
| 100 |
| 101 bool cursor_moved; |
| 102 unsigned bell_count; |
| 103 Rectangle dirty_rect; |
| 104 }; |
| 105 |
| 106 // Maximum number of rows/columns. |
| 107 static const unsigned kMaxRows = 500; // TODO(vtl): Made up number. |
| 108 static const unsigned kMaxColumns = T_NUMCOL; |
| 109 |
| 110 MotermModel(const Size& max_size, const Size& size); |
| 111 ~MotermModel(); |
| 112 |
| 113 // Process the given input bytes, reporting (additional) state changes to |
| 114 // |*state_changes| (note: this does not "reset" |*state_changes|, so that |
| 115 // state changes can be accumulated across multiple calls). |
| 116 void ProcessInput(const void* input_bytes, |
| 117 size_t num_input_bytes, |
| 118 StateChanges* state_changes); |
| 119 |
| 120 Size GetSize() const; |
| 121 Position GetCursorPosition() const; |
| 122 CharacterInfo GetCharacterInfoAt(const Position& position) const; |
| 123 |
| 124 void SetSize(const Size& size, bool reset); |
| 125 |
| 126 private: |
| 127 teken_char_t& character_at(unsigned row, unsigned column) { |
| 128 return characters_[row * max_size_.columns + column]; |
| 129 } |
| 130 teken_attr_t& attribute_at(unsigned row, unsigned column) { |
| 131 return attributes_[row * max_size_.columns + column]; |
| 132 } |
| 133 |
| 134 // libteken callbacks: |
| 135 void OnBell(); |
| 136 void OnCursor(const teken_pos_t* pos); |
| 137 void OnPutchar(const teken_pos_t* pos, |
| 138 teken_char_t ch, |
| 139 const teken_attr_t* attr); |
| 140 void OnFill(const teken_rect_t* rect, |
| 141 teken_char_t ch, |
| 142 const teken_attr_t* attr); |
| 143 void OnCopy(const teken_rect_t* rect, const teken_pos_t* pos); |
| 144 void OnParam(int cmd, unsigned val); |
| 145 void OnRespond(const void* buf, size_t size); |
| 146 |
| 147 // Thunks for libteken callbacks: |
| 148 static void OnBellThunk(void* ctx); |
| 149 static void OnCursorThunk(void* ctx, const teken_pos_t* pos); |
| 150 static void OnPutcharThunk(void* ctx, |
| 151 const teken_pos_t* pos, |
| 152 teken_char_t ch, |
| 153 const teken_attr_t* attr); |
| 154 static void OnFillThunk(void* ctx, |
| 155 const teken_rect_t* rect, |
| 156 teken_char_t ch, |
| 157 const teken_attr_t* attr); |
| 158 static void OnCopyThunk(void* ctx, |
| 159 const teken_rect_t* rect, |
| 160 const teken_pos_t* pos); |
| 161 static void OnParamThunk(void* ctx, int cmd, unsigned val); |
| 162 static void OnRespondThunk(void* ctx, const void* buf, size_t size); |
| 163 |
| 164 const Size max_size_; |
| 165 |
| 166 scoped_ptr<teken_char_t[]> characters_; |
| 167 scoped_ptr<teken_attr_t[]> attributes_; |
| 168 |
| 169 teken_t terminal_; |
| 170 |
| 171 // Used by the callbacks. ("Usually" null, but must be non-null whenever a |
| 172 // callback may be called -- it'll point to a stack variable.) |
| 173 StateChanges* current_state_changes_; |
| 174 |
| 175 DISALLOW_COPY_AND_ASSIGN(MotermModel); |
| 176 }; |
| 177 |
| 178 #endif // APPS_MOTERM_MOTERM_MODEL_H_ |
OLD | NEW |