| // Copyright 2021 Google LLC. |
| #include "experimental/sktext/src/Paint.h" |
| |
| namespace skia { |
| namespace text { |
| |
| bool Paint::drawText(std::u16string text, SkCanvas* canvas, SkScalar x, SkScalar y) { |
| SkPaint foregroundPaint(SkColors::kBlack); |
| SkPaint backgroundPaint(SkColors::kWhite); |
| return drawText(std::move(text), canvas, TextDirection::kLtr, TextAlign::kLeft, foregroundPaint, backgroundPaint, SkString("Roboto"), 14, SkFontStyle::Normal(), x, y); |
| } |
| |
| bool Paint::drawText(std::u16string text, SkCanvas* canvas, SkScalar width) { |
| SkPaint foregroundPaint(SkColors::kBlack); |
| SkPaint backgroundPaint(SkColors::kWhite); |
| return drawText(std::move(text), canvas, |
| TextDirection::kLtr, TextAlign::kLeft, foregroundPaint, backgroundPaint, SkString("Roboto"), 14, SkFontStyle::Normal(), |
| SkSize::Make(width, SK_ScalarInfinity), 0, 0); |
| } |
| |
| bool Paint::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) { |
| return drawText(std::move(text), canvas, |
| textDirection, textAlign, foreground, background, |
| fontFamily, fontSize, fontStyle, SkSize::Make(SK_ScalarInfinity, SK_ScalarInfinity), x, y); |
| } |
| |
| bool Paint::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) { |
| |
| size_t textSize = text.size(); |
| sk_sp<TrivialFontChain> fontChain = sk_make_sp<TrivialFontChain>(fontFamily.c_str(), fontSize, fontStyle); |
| FontBlock fontBlock(text.size(), fontChain); |
| if (fontChain->getTypeface() == nullptr || fontChain->getTypeface().get() == nullptr) { |
| return false; |
| } |
| |
| auto formattedText = Paint::layout(std::move(text), textDirection, textAlign, reqSize, SkSpan<FontBlock>(&fontBlock, 1)); |
| if (formattedText == nullptr) { |
| return false; |
| } |
| |
| DecoratedBlock decoratedBlock(textSize, foreground, background); |
| Paint paint; |
| paint.paint(canvas, SkPoint::Make(x, y), nullptr, formattedText.get(), SkSpan<DecoratedBlock>(&decoratedBlock, 1)); |
| |
| return true; |
| } |
| |
| void Paint::onGlyphRun(const SkFont& font, |
| DirTextRange dirTextRange, |
| SkRect bounds, |
| TextIndex trailingSpaces, |
| size_t glyphCount, |
| const uint16_t glyphs[], |
| const SkPoint positions[], |
| const TextIndex clusters[]) { |
| |
| DecoratedBlock decoratedBlock = findDecoratedBlock(dirTextRange); |
| |
| SkTextBlobBuilder builder; |
| const auto& blobBuffer = builder.allocRunPos(font , SkToInt(glyphCount)); |
| sk_careful_memcpy(blobBuffer.glyphs, glyphs, glyphCount * sizeof(uint16_t)); |
| sk_careful_memcpy(blobBuffer.points(), positions, glyphCount * sizeof(SkPoint)); |
| auto blob = builder.make(); |
| if (!decoratedBlock.backgroundPaint.nothingToDraw()) { |
| bounds.offset(fXY.fX, fXY.fY); |
| fCanvas->drawRect(bounds, decoratedBlock.backgroundPaint); |
| } |
| fCanvas->drawTextBlob(blob, fXY.fX, fXY.fY, decoratedBlock.foregroundPaint); |
| } |
| |
| std::unique_ptr<WrappedText> Paint::layout(std::u16string text, |
| TextDirection textDirection, TextAlign textAlign, |
| SkSize reqSize, |
| SkSpan<FontBlock> fontBlocks) { |
| auto unicode = SkUnicode::Make(); |
| auto unicodeText = std::make_unique<UnicodeText>(std::move(unicode), SkSpan<uint16_t>((uint16_t*)text.data(), text.size())); |
| auto fontResolvedText = unicodeText->resolveFonts(fontBlocks); |
| auto shapedText = fontResolvedText->shape(unicodeText.get(), TextDirection::kLtr); |
| auto wrappedText = shapedText->wrap(unicodeText.get(), reqSize.width(), reqSize.height()); |
| wrappedText->format(textAlign, textDirection); |
| return wrappedText; |
| } |
| |
| DecoratedBlock Paint::findDecoratedBlock(TextRange textRange) { |
| TextIndex start = 0; |
| for (auto& block : fDecoratedBlocks) { |
| if (start + block.charCount <= textRange.fStart) { |
| start += block.charCount; |
| continue; |
| } else if (start >= textRange.fEnd) { |
| break; |
| } |
| return block; |
| } |
| return DecoratedBlock(0, SkPaint(), SkPaint()); |
| } |
| |
| void Paint::paint(SkCanvas* canvas, SkPoint xy, UnicodeText* unicodeText, WrappedText* wrappedText, SkSpan<DecoratedBlock> decoratedBlocks) { |
| fCanvas = canvas; |
| fXY = xy; |
| fDecoratedBlocks = decoratedBlocks; |
| |
| SkTArray<size_t> chunks; |
| chunks.resize(decoratedBlocks.size()); |
| size_t index = 0; |
| for (size_t i = 0; i < decoratedBlocks.size(); ++i) { |
| index += decoratedBlocks[i].charCount; |
| chunks[i] = index; |
| } |
| |
| if (chunks.size() == 1) { |
| wrappedText->visit( this); |
| } else { |
| wrappedText->visit(unicodeText, this, PositionType::kGraphemeCluster, SkSpan<size_t>(chunks.data(), chunks.size())); |
| } |
| } |
| |
| } // namespace text |
| } // namespace skia |