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