1 // Copyright 2021 Google LLC. 2 #include "experimental/sktext/src/Paint.h" 3 4 namespace skia { 5 namespace text { 6 drawText(std::u16string text,SkCanvas * canvas,SkScalar x,SkScalar y)7 bool Paint::drawText(std::u16string text, SkCanvas* canvas, SkScalar x, SkScalar y) { 8 SkPaint foregroundPaint(SkColors::kBlack); 9 SkPaint backgroundPaint(SkColors::kWhite); 10 return drawText(std::move(text), canvas, TextDirection::kLtr, TextAlign::kLeft, foregroundPaint, backgroundPaint, SkString("Roboto"), 14, SkFontStyle::Normal(), x, y); 11 } 12 drawText(std::u16string text,SkCanvas * canvas,SkScalar width)13 bool Paint::drawText(std::u16string text, SkCanvas* canvas, SkScalar width) { 14 SkPaint foregroundPaint(SkColors::kBlack); 15 SkPaint backgroundPaint(SkColors::kWhite); 16 return drawText(std::move(text), canvas, 17 TextDirection::kLtr, TextAlign::kLeft, foregroundPaint, backgroundPaint, SkString("Roboto"), 14, SkFontStyle::Normal(), 18 SkSize::Make(width, SK_ScalarInfinity), 0, 0); 19 } 20 drawText(std::u16string text,SkCanvas * canvas,TextDirection textDirection,TextAlign textAlign,SkPaint foreground,SkPaint background,const SkString & fontFamily,SkScalar fontSize,SkFontStyle fontStyle,SkScalar x,SkScalar y)21 bool Paint::drawText(std::u16string text, SkCanvas* canvas, 22 TextDirection textDirection, TextAlign textAlign, 23 SkPaint foreground, SkPaint background, 24 const SkString& fontFamily, SkScalar fontSize, SkFontStyle fontStyle, SkScalar x, SkScalar y) { 25 return drawText(std::move(text), canvas, 26 textDirection, textAlign, foreground, background, 27 fontFamily, fontSize, fontStyle, SkSize::Make(SK_ScalarInfinity, SK_ScalarInfinity), x, y); 28 } 29 drawText(std::u16string text,SkCanvas * canvas,TextDirection textDirection,TextAlign textAlign,SkPaint foreground,SkPaint background,const SkString & fontFamily,SkScalar fontSize,SkFontStyle fontStyle,SkSize reqSize,SkScalar x,SkScalar y)30 bool Paint::drawText(std::u16string text, SkCanvas* canvas, 31 TextDirection textDirection, TextAlign textAlign, 32 SkPaint foreground, SkPaint background, 33 const SkString& fontFamily, SkScalar fontSize, SkFontStyle fontStyle, SkSize reqSize, SkScalar x, SkScalar y) { 34 35 size_t textSize = text.size(); 36 sk_sp<TrivialFontChain> fontChain = sk_make_sp<TrivialFontChain>(fontFamily.c_str(), fontSize, fontStyle); 37 FontBlock fontBlock(text.size(), fontChain); 38 if (fontChain->getTypeface() == nullptr || fontChain->getTypeface().get() == nullptr) { 39 return false; 40 } 41 42 auto formattedText = Paint::layout(std::move(text), textDirection, textAlign, reqSize, SkSpan<FontBlock>(&fontBlock, 1)); 43 if (formattedText == nullptr) { 44 return false; 45 } 46 47 DecoratedBlock decoratedBlock(textSize, foreground, background); 48 Paint paint; 49 paint.paint(canvas, SkPoint::Make(x, y), nullptr, formattedText.get(), SkSpan<DecoratedBlock>(&decoratedBlock, 1)); 50 51 return true; 52 } 53 onGlyphRun(const SkFont & font,DirTextRange dirTextRange,SkRect bounds,TextIndex trailingSpaces,size_t glyphCount,const uint16_t glyphs[],const SkPoint positions[],const TextIndex clusters[])54 void Paint::onGlyphRun(const SkFont& font, 55 DirTextRange dirTextRange, 56 SkRect bounds, 57 TextIndex trailingSpaces, 58 size_t glyphCount, 59 const uint16_t glyphs[], 60 const SkPoint positions[], 61 const TextIndex clusters[]) { 62 63 DecoratedBlock decoratedBlock = findDecoratedBlock(dirTextRange); 64 65 SkTextBlobBuilder builder; 66 const auto& blobBuffer = builder.allocRunPos(font , SkToInt(glyphCount)); 67 sk_careful_memcpy(blobBuffer.glyphs, glyphs, glyphCount * sizeof(uint16_t)); 68 sk_careful_memcpy(blobBuffer.points(), positions, glyphCount * sizeof(SkPoint)); 69 auto blob = builder.make(); 70 if (!decoratedBlock.backgroundPaint.nothingToDraw()) { 71 bounds.offset(fXY.fX, fXY.fY); 72 fCanvas->drawRect(bounds, decoratedBlock.backgroundPaint); 73 } 74 fCanvas->drawTextBlob(blob, fXY.fX, fXY.fY, decoratedBlock.foregroundPaint); 75 } 76 layout(std::u16string text,TextDirection textDirection,TextAlign textAlign,SkSize reqSize,SkSpan<FontBlock> fontBlocks)77 std::unique_ptr<WrappedText> Paint::layout(std::u16string text, 78 TextDirection textDirection, TextAlign textAlign, 79 SkSize reqSize, 80 SkSpan<FontBlock> fontBlocks) { 81 auto unicode = SkUnicode::Make(); 82 auto unicodeText = std::make_unique<UnicodeText>(std::move(unicode), SkSpan<uint16_t>((uint16_t*)text.data(), text.size())); 83 auto fontResolvedText = unicodeText->resolveFonts(fontBlocks); 84 auto shapedText = fontResolvedText->shape(unicodeText.get(), TextDirection::kLtr); 85 auto wrappedText = shapedText->wrap(unicodeText.get(), reqSize.width(), reqSize.height()); 86 wrappedText->format(textAlign, textDirection); 87 return wrappedText; 88 } 89 findDecoratedBlock(TextRange textRange)90 DecoratedBlock Paint::findDecoratedBlock(TextRange textRange) { 91 TextIndex start = 0; 92 for (auto& block : fDecoratedBlocks) { 93 if (start + block.charCount <= textRange.fStart) { 94 start += block.charCount; 95 continue; 96 } else if (start >= textRange.fEnd) { 97 break; 98 } 99 return block; 100 } 101 return DecoratedBlock(0, SkPaint(), SkPaint()); 102 } 103 paint(SkCanvas * canvas,SkPoint xy,UnicodeText * unicodeText,WrappedText * wrappedText,SkSpan<DecoratedBlock> decoratedBlocks)104 void Paint::paint(SkCanvas* canvas, SkPoint xy, UnicodeText* unicodeText, WrappedText* wrappedText, SkSpan<DecoratedBlock> decoratedBlocks) { 105 fCanvas = canvas; 106 fXY = xy; 107 fDecoratedBlocks = decoratedBlocks; 108 109 SkTArray<size_t> chunks; 110 chunks.resize(decoratedBlocks.size()); 111 size_t index = 0; 112 for (size_t i = 0; i < decoratedBlocks.size(); ++i) { 113 index += decoratedBlocks[i].charCount; 114 chunks[i] = index; 115 } 116 117 if (chunks.size() == 1) { 118 wrappedText->visit( this); 119 } else { 120 wrappedText->visit(unicodeText, this, PositionType::kGraphemeCluster, SkSpan<size_t>(chunks.data(), chunks.size())); 121 } 122 } 123 124 } // namespace text 125 } // namespace skia 126