1// Copyright 2021 Google LLC. 2#include "experimental/sktext/editor/Texts.h" 3 4using namespace skia::text; 5 6namespace skia { 7namespace editor { 8 9void 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 24std::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 34void 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 52SkTArray<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