• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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