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