1 // Copyright 2021 Google LLC. 2 #ifndef Texts_DEFINED 3 #define Texts_DEFINED 4 #include <sstream> 5 #include "experimental/sktext/editor/Cursor.h" 6 #include "experimental/sktext/editor/Defaults.h" 7 #include "experimental/sktext/editor/Mouse.h" 8 #include "experimental/sktext/editor/Selection.h" 9 #include "experimental/sktext/include/Text.h" 10 #include "experimental/sktext/include/Types.h" 11 #include "include/core/SkCanvas.h" 12 #include "include/core/SkSurface.h" 13 #include "include/core/SkTime.h" 14 #include "tools/sk_app/Application.h" 15 #include "tools/sk_app/Window.h" 16 #include "tools/skui/ModifierKey.h" 17 18 namespace skia { 19 namespace editor { 20 21 using namespace skia::text; 22 // Shapes text once and then paints it at request (not keeping intermediate data) 23 // TODO: Keep only text blobs 24 class StaticText { 25 public: 26 StaticText(std::u16string text,SkPoint offset,SkSize size,SkSpan<FontBlock> fontBlocks,TextDirection textDirection,TextAlign textAlign)27 StaticText(std::u16string text, SkPoint offset, SkSize size, SkSpan<FontBlock> fontBlocks, TextDirection textDirection, TextAlign textAlign) { 28 fOffset = offset; 29 fSize = size; 30 fFontBlocks = fontBlocks; 31 fText = std::move(text); 32 33 auto unicode = SkUnicode::Make(); 34 fUnicodeText = std::make_unique<UnicodeText>(std::move(unicode), SkSpan<uint16_t>((uint16_t*)fText.data(), fText.size())); 35 fFontResolvedText = fUnicodeText->resolveFonts(fontBlocks); 36 fShapedText = fFontResolvedText->shape(fUnicodeText.get(), DEFAULT_TEXT_DIRECTION); 37 fWrappedText = fShapedText->wrap(fUnicodeText.get(), size.width(), size.height()); 38 fWrappedText->format(DEFAULT_TEXT_ALIGN, DEFAULT_TEXT_DIRECTION); 39 } 40 41 virtual ~StaticText() = default; 42 43 virtual void paint(SkCanvas* canvas, SkSpan<DecoratedBlock> decors); 44 45 std::u16string fText; 46 std::unique_ptr<UnicodeText> fUnicodeText; 47 std::unique_ptr<FontResolvedText> fFontResolvedText; 48 std::unique_ptr<ShapedText> fShapedText; 49 std::unique_ptr<WrappedText> fWrappedText; 50 SkSize fSize; 51 SkPoint fOffset; 52 SkSpan<FontBlock> fFontBlocks; 53 }; 54 55 // The text can change but it's not selectable/editable 56 class DynamicText { 57 public: DynamicText(std::u16string text,SkPoint offset,SkSize size,SkSpan<FontBlock> fontBlocks,SkSpan<DecoratedBlock> decorations,TextDirection textDirection,TextAlign textAlign)58 DynamicText(std::u16string text, 59 SkPoint offset, SkSize size, 60 SkSpan<FontBlock> fontBlocks, 61 SkSpan<DecoratedBlock> decorations, 62 TextDirection textDirection, TextAlign textAlign) { 63 fOffset = offset; 64 fRequiredSize = size; 65 fFontBlocks = fontBlocks; 66 fDecorations = decorations; 67 fTextAlign = textAlign; 68 fTextDirection = textDirection; 69 fText = std::move(text); 70 71 auto unicode = SkUnicode::Make(); 72 fUnicodeText = std::make_unique<UnicodeText>(std::move(unicode), SkSpan<uint16_t>((uint16_t*)fText.data(), fText.size())); 73 fFontResolvedText = fUnicodeText->resolveFonts(fontBlocks); 74 fShapedText = fFontResolvedText->shape(fUnicodeText.get(), fTextDirection); 75 fWrappedText = fShapedText->wrap(fUnicodeText.get(), size.width(), size.height()); 76 fWrappedText->format(fTextAlign, fTextDirection); 77 } 78 79 virtual ~DynamicText() = default; 80 contains(SkScalar x,SkScalar y)81 bool contains(SkScalar x, SkScalar y) { 82 return SkRect::MakeXYWH(fOffset.fX, fOffset.fY, fRequiredSize.fWidth, fRequiredSize.fHeight).contains(x, y); 83 } 84 invalidate()85 void invalidate() { fDrawableText = nullptr; } isValid()86 bool isValid() { return fDrawableText != nullptr; } 87 88 std::vector<TextIndex> getDecorationChunks(SkSpan<DecoratedBlock> decorations) const; 89 rebuild(std::u16string text)90 bool rebuild(std::u16string text) { 91 if (!this->fFontBlocks.empty()) { 92 SkASSERT(this->fFontBlocks.size() == 1); 93 this->fFontBlocks[0].charCount = text.size(); 94 } 95 this->fText = std::move(text); 96 97 auto unicode = SkUnicode::Make(); 98 fUnicodeText = std::make_unique<UnicodeText>(std::move(unicode), SkSpan<uint16_t>((uint16_t*)fText.data(), fText.size())); 99 fFontResolvedText = fUnicodeText->resolveFonts(fFontBlocks); 100 fShapedText = fFontResolvedText->shape(fUnicodeText.get(), fTextDirection); 101 fWrappedText = fShapedText->wrap(fUnicodeText.get(), this->fRequiredSize.fWidth, this->fRequiredSize.fHeight); 102 fWrappedText->format(fTextAlign, fTextDirection); 103 fSelectableText = fWrappedText->prepareToEdit(fUnicodeText.get()); 104 fDrawableText = nullptr; 105 fActualSize = fWrappedText->actualSize(); 106 107 return true; 108 } 109 lineCount()110 size_t lineCount() const { return fSelectableText->countLines(); } getLine(size_t lineIndex)111 BoxLine getLine(size_t lineIndex) { 112 SkASSERT(lineIndex < fSelectableText->countLines()); 113 return fSelectableText->getLine(lineIndex); 114 } 115 actualSize()116 SkRect actualSize() const { 117 return SkRect::MakeXYWH(fOffset.fX, fOffset.fY, fActualSize.fWidth, fActualSize.fHeight); 118 } 119 120 virtual void paint(SkCanvas* canvas); 121 122 protected: 123 std::u16string fText; 124 std::unique_ptr<UnicodeText> fUnicodeText; 125 std::unique_ptr<FontResolvedText> fFontResolvedText; 126 std::unique_ptr<ShapedText> fShapedText; 127 std::unique_ptr<WrappedText> fWrappedText; 128 std::unique_ptr<DrawableText> fDrawableText; 129 std::unique_ptr<SelectableText> fSelectableText; 130 SkSize fRequiredSize; 131 SkSize fActualSize; 132 SkPoint fOffset; 133 SkSpan<FontBlock> fFontBlocks; 134 SkSpan<DecoratedBlock> fDecorations; 135 TextAlign fTextAlign; 136 TextDirection fTextDirection; 137 }; 138 139 // Text can change; supports select/copy/paste 140 class EditableText : public DynamicText { 141 public: EditableText(std::u16string text,SkPoint offset,SkSize size,SkSpan<FontBlock> fontBlocks,SkSpan<DecoratedBlock> decorations,TextDirection textDirection,TextAlign textAlign)142 EditableText(std::u16string text, SkPoint offset, SkSize size, SkSpan<FontBlock> fontBlocks, SkSpan<DecoratedBlock> decorations, TextDirection textDirection, TextAlign textAlign) 143 : DynamicText(text, offset, size, fontBlocks, decorations, textDirection, textAlign) 144 , fSelection(std::make_unique<Selection>(DEFAULT_SELECTION_COLOR)) { 145 } 146 isEmpty()147 bool isEmpty() { return fText.empty(); } 148 adjustedPosition(PositionType positionType,SkPoint point)149 Position adjustedPosition(PositionType positionType, SkPoint point) const { 150 return fSelectableText->adjustedPosition(positionType, point - fOffset); 151 } 152 153 //Position adjustedPosition(PositionType positionType, TextIndex textIndex) const { 154 // return fSelectableText->adjustedPosition(positionType, textIndex); 155 //} 156 previousElement(Position element)157 Position previousElement(Position element) const { return fSelectableText->previousPosition(element); } nextElement(Position current)158 Position nextElement(Position current) const { return fSelectableText->nextPosition(current); } firstElement(PositionType positionType)159 Position firstElement(PositionType positionType) const { return fSelectableText->firstPosition(positionType); } lastElement(PositionType positionType)160 Position lastElement(PositionType positionType) const { return fSelectableText->lastPosition(positionType); } 161 isFirstOnTheLine(Position element)162 bool isFirstOnTheLine(Position element) const { return fSelectableText->isFirstOnTheLine(element); } isLastOnTheLine(Position element)163 bool isLastOnTheLine(Position element) const { return fSelectableText->isLastOnTheLine(element); } 164 removeElement(TextRange toRemove)165 void removeElement(TextRange toRemove) { 166 std::u16string text; 167 text.append(this->fText.substr(0, toRemove.fStart)); 168 text.append(this->fText.substr(toRemove.fEnd, std::u16string::npos)); 169 update(text); 170 } 171 insertElement(SkUnichar unichar,TextIndex toInsert)172 void insertElement(SkUnichar unichar, TextIndex toInsert) { 173 std::u16string text; 174 text.append(fText.substr(0, toInsert)); 175 text.append(1, (unsigned)unichar); 176 text.append(fText.substr(toInsert, std::u16string::npos)); 177 update(text); 178 } 179 replaceElement(SkUnichar unichar,TextRange toReplace)180 void replaceElement(SkUnichar unichar, TextRange toReplace) { 181 std::u16string text; 182 text.append(fText.substr(0, toReplace.fStart)); 183 text.append(1, (unsigned)unichar); 184 text.append(fText.substr(toReplace.fEnd, std::u16string::npos)); 185 } 186 update(std::u16string & text)187 void update(std::u16string& text) { 188 fText = text; 189 // TODO: Update text styles 190 SkASSERT(fFontBlocks.size() == 1); 191 fFontBlocks[0].charCount = fText.size(); 192 SkASSERT(fDecorations.size() == 1); 193 fDecorations[0].charCount = fText.size(); 194 // TODO: update all objects rather than recreate them 195 rebuild(text); 196 197 // TODO: Update the text selection 198 fSelection->clear(); 199 } 200 select(TextRange text,SkRect boundaries)201 void select(TextRange text, SkRect boundaries) { fSelection->select(text, boundaries); } clearSelection()202 void clearSelection() { fSelection->clear(); } 203 204 void paint(SkCanvas* canvas) override; 205 206 SkTArray<DecoratedBlock> mergeSelectionIntoDecorations(); 207 208 protected: 209 std::unique_ptr<Selection> fSelection; 210 }; 211 212 } // namespace editor 213 } // namespace skia 214 #endif // Texts_DEFINED 215