blob: cf985f971a9e5606e96fefa9de0bb2f15477c3f9 [file] [log] [blame]
// 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