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() const28 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() const34 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;
operator *SkPlainTextEditor::Editor::Text::Iterator41 StringView operator*() { return fPtr->fText.view(); }
operator ++SkPlainTextEditor::Editor::Text::Iterator42 void operator++() { ++fPtr; }
operator !=SkPlainTextEditor::Editor::Text::Iterator43 bool operator!=(const Iterator& other) const { return fPtr != other.fPtr; }
44 };
beginSkPlainTextEditor::Editor::Text45 Iterator begin() const { return Iterator{fLines.begin()}; }
endSkPlainTextEditor::Editor::Text46 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() const53 Text text() const { return Text{fLines}; }
54
55 // get size of line in canvas display units.
lineHeight(size_t index) const56 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() const84 size_t lineCount() const { return fLines.size(); }
line(size_t i) const85 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
TextLineSkPlainTextEditor::Editor::TextLine113 TextLine(StringSlice t) : fText(std::move(t)) {}
TextLineSkPlainTextEditor::Editor::TextLine114 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
operator ==(const SkPlainTextEditor::Editor::TextPosition& u, const SkPlainTextEditor::Editor::TextPosition& v)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 }
operator !=(const SkPlainTextEditor::Editor::TextPosition& u, const SkPlainTextEditor::Editor::TextPosition& v)132 static inline bool operator!=(const SkPlainTextEditor::Editor::TextPosition& u,
133 const SkPlainTextEditor::Editor::TextPosition& v) { return !(u == v); }
134
operator <(const SkPlainTextEditor::Editor::TextPosition& u, const SkPlainTextEditor::Editor::TextPosition& v)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