1 // Copyright 2019 Google LLC. 2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. 3 #ifndef editor_DEFINED 4 #define editor_DEFINED 5 6 #include "modules/skplaintexteditor/include/stringslice.h" 7 #include "modules/skplaintexteditor/include/stringview.h" 8 9 #include "include/core/SkColor.h" 10 #include "include/core/SkFont.h" 11 #include "include/core/SkString.h" 12 #include "include/core/SkTextBlob.h" 13 14 #include <climits> 15 #include <cstdint> 16 #include <utility> 17 #include <vector> 18 19 class SkCanvas; 20 class SkShaper; 21 22 namespace SkPlainTextEditor { 23 24 class Editor { 25 struct TextLine; 26 public: 27 // total height in canvas display units. getHeight()28 int getHeight() const { return fHeight; } 29 30 // set display width in canvas display units 31 void setWidth(int w); // may force re-shape 32 33 // get/set current font (used for shaping and displaying text) font()34 const SkFont& font() const { return fFont; } 35 void setFont(SkFont font); 36 37 struct Text { 38 const std::vector<TextLine>& fLines; 39 struct Iterator { 40 std::vector<TextLine>::const_iterator fPtr; 41 StringView operator*() { return fPtr->fText.view(); } 42 void operator++() { ++fPtr; } 43 bool operator!=(const Iterator& other) const { return fPtr != other.fPtr; } 44 }; beginText45 Iterator begin() const { return Iterator{fLines.begin()}; } endText46 Iterator end() const { return Iterator{fLines.end()}; } 47 }; 48 // Loop over all the lines of text. The lines are not '\0'- or '\n'-terminated. 49 // For example, to dump the entire file to standard output: 50 // for (SkPlainTextEditor::StringView str : editor.text()) { 51 // std::cout.write(str.data, str.size) << '\n'; 52 // } text()53 Text text() const { return Text{fLines}; } 54 55 // get size of line in canvas display units. lineHeight(size_t index)56 int lineHeight(size_t index) const { return fLines[index].fHeight; } 57 58 struct TextPosition { 59 size_t fTextByteIndex = SIZE_MAX; // index into UTF-8 representation of line. 60 size_t fParagraphIndex = SIZE_MAX; // logical line, based on hard newline characters. 61 }; 62 enum class Movement { 63 kNowhere, 64 kLeft, 65 kUp, 66 kRight, 67 kDown, 68 kHome, 69 kEnd, 70 kWordLeft, 71 kWordRight, 72 }; 73 TextPosition move(Editor::Movement move, Editor::TextPosition pos) const; 74 TextPosition getPosition(SkIPoint); 75 SkRect getLocation(TextPosition); 76 // insert into current text. 77 TextPosition insert(TextPosition, const char* utf8Text, size_t byteLen); 78 // remove text between two positions 79 TextPosition remove(TextPosition, TextPosition); 80 81 // If dst is nullptr, returns size of given selection. 82 // Otherwise, fill dst with a copy of the selection, and return the amount copied. 83 size_t copy(TextPosition pos1, TextPosition pos2, char* dst = nullptr) const; lineCount()84 size_t lineCount() const { return fLines.size(); } line(size_t i)85 StringView line(size_t i) const { 86 return i < fLines.size() ? fLines[i].fText.view() : StringView{nullptr, 0}; 87 } 88 89 struct PaintOpts { 90 SkColor4f fBackgroundColor = {1, 1, 1, 1}; 91 SkColor4f fForegroundColor = {0, 0, 0, 1}; 92 // TODO: maybe have multiple selections and cursors, each with separate colors. 93 SkColor4f fSelectionColor = {0.729f, 0.827f, 0.988f, 1}; 94 SkColor4f fCursorColor = {1, 0, 0, 1}; 95 TextPosition fSelectionBegin; 96 TextPosition fSelectionEnd; 97 TextPosition fCursor; 98 }; 99 void paint(SkCanvas* canvas, PaintOpts); 100 101 private: 102 // TODO: rename this to TextParagraph. fLines to fParas. 103 struct TextLine { 104 StringSlice fText; 105 sk_sp<const SkTextBlob> fBlob; 106 std::vector<SkRect> fCursorPos; 107 std::vector<size_t> fLineEndOffsets; 108 std::vector<bool> fWordBoundaries; 109 SkIPoint fOrigin = {0, 0}; 110 int fHeight = 0; 111 bool fShaped = false; 112 TextLineTextLine113 TextLine(StringSlice t) : fText(std::move(t)) {} TextLineTextLine114 TextLine() {} 115 }; 116 std::vector<TextLine> fLines; 117 int fWidth = 0; 118 int fHeight = 0; 119 SkFont fFont; 120 bool fNeedsReshape = false; 121 const char* fLocale = "en"; // TODO: make this setable 122 123 void markDirty(TextLine*); 124 void reshapeAll(); 125 }; 126 } // namespace SkPlainTextEditor 127 128 static inline bool operator==(const SkPlainTextEditor::Editor::TextPosition& u, 129 const SkPlainTextEditor::Editor::TextPosition& v) { 130 return u.fParagraphIndex == v.fParagraphIndex && u.fTextByteIndex == v.fTextByteIndex; 131 } 132 static inline bool operator!=(const SkPlainTextEditor::Editor::TextPosition& u, 133 const SkPlainTextEditor::Editor::TextPosition& v) { return !(u == v); } 134 135 static inline bool operator<(const SkPlainTextEditor::Editor::TextPosition& u, 136 const SkPlainTextEditor::Editor::TextPosition& v) { 137 return u.fParagraphIndex < v.fParagraphIndex || 138 (u.fParagraphIndex == v.fParagraphIndex && u.fTextByteIndex < v.fTextByteIndex); 139 } 140 141 142 #endif // editor_DEFINED 143