1 // Copyright 2021 Google LLC.
2 #include "experimental/sktext/editor/Texts.h"
3
4 using namespace skia::text;
5
6 namespace skia {
7 namespace editor {
8
paint(SkCanvas * canvas)9 void DynamicText::paint(SkCanvas* canvas) {
10 if (!fDrawableText) {
11 auto chunks = this->getDecorationChunks(fDecorations);
12 fDrawableText = fWrappedText->prepareToDraw<DrawableText>(fUnicodeText.get(),
13 PositionType::kGraphemeCluster,
14 SkSpan<TextIndex>(chunks.data(), chunks.size()));
15 }
16
17 auto foregroundPaint = fDecorations[0].foregroundPaint;
18 auto textBlobs = fDrawableText->getTextBlobs();
19 for (auto& textBLob : textBlobs) {
20 canvas->drawTextBlob(textBLob, 0, 0, foregroundPaint);
21 }
22 }
23
getDecorationChunks(SkSpan<DecoratedBlock> decorations) const24 std::vector<TextIndex> DynamicText::getDecorationChunks(SkSpan<DecoratedBlock> decorations) const {
25 std::vector<TextIndex> result;
26 TextIndex textIndex = 0;
27 for (auto& decoration : decorations) {
28 textIndex += decoration.charCount;
29 result.emplace_back(textIndex);
30 }
31 return result;
32 }
33
paint(SkCanvas * canvas)34 void EditableText::paint(SkCanvas* canvas) {
35
36 if (fSelection->isEmpty()) {
37 DynamicText::paint(canvas);
38 } else {
39 auto decorations = mergeSelectionIntoDecorations();
40 auto chunks = this->getDecorationChunks(SkSpan<DecoratedBlock>(decorations.data(), decorations.size()));
41 fDrawableText = fWrappedText->prepareToDraw<DrawableText>(fUnicodeText.get(),
42 PositionType::kGraphemeCluster,
43 SkSpan<TextIndex>(chunks.data(), chunks.size()));
44 }
45 auto foregroundPaint = fDecorations[0].foregroundPaint;
46 auto textBlobs = fDrawableText->getTextBlobs();
47 for (auto& textBLob : textBlobs) {
48 canvas->drawTextBlob(textBLob, 0, 0, foregroundPaint);
49 }
50 }
51
mergeSelectionIntoDecorations()52 SkTArray<DecoratedBlock> EditableText::mergeSelectionIntoDecorations() {
53 SkTArray<DecoratedBlock> merged;
54 merged.reserve_back(fDecorations.size() + fSelection->count());
55
56 size_t indexDecor = 0ul; // index in fDecorations
57 size_t decorPos = 0ul;
58 for (auto& selected : fSelection->fTextRanges) {
59 // Add all the decoration blocks that are placed before the selected block
60 DecoratedBlock& decor = fDecorations[indexDecor];
61 while (indexDecor < fDecorations.size()) {
62 decor = fDecorations[indexDecor++];
63 if (decorPos + decor.charCount >= selected.fStart) {
64 break;
65 }
66 // The entire decoration block is before
67 merged.emplace_back(decor);
68 decorPos += decor.charCount;
69 }
70
71 auto lastDecorPos = decorPos;
72 if (selected.fStart > decorPos) {
73 // The decoration block is has a part that is before the selection so we add it
74 merged.emplace_back(selected.fStart - decorPos, decor.foregroundPaint, decor.backgroundPaint);
75 decorPos = selected.fStart;
76 }
77 SkASSERT(decorPos == selected.fStart);
78
79 // So the next decoration intersects the selection (and the selection wins)
80 merged.emplace_back(selected.width(), fSelection->fForeground, fSelection->fBackground);
81 decorPos += selected.width();
82 SkASSERT(decorPos == selected.fEnd);
83
84 if (lastDecorPos + decor.charCount > selected.fEnd) {
85 // We still need to add the rest of the decoration block
86 merged.emplace_back(lastDecorPos + decor.charCount - selected.fEnd, decor.foregroundPaint, decor.backgroundPaint);
87 decorPos += lastDecorPos + decor.charCount - selected.fEnd;
88 }
89 }
90 return merged;
91 }
92
93 } // namespace editor
94 } // namespace skia
95