/src/skia/modules/skparagraph/src/OneLineShaper.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2019 Google LLC. |
2 | | #ifndef LineBreaker_DEFINED |
3 | | #define LineBreaker_DEFINED |
4 | | |
5 | | #include <functional> // std::function |
6 | | #include <queue> |
7 | | #include "include/core/SkSpan.h" |
8 | | #include "modules/skparagraph/include/TextStyle.h" |
9 | | #include "modules/skparagraph/src/ParagraphImpl.h" |
10 | | #include "modules/skparagraph/src/Run.h" |
11 | | |
12 | | namespace skia { |
13 | | namespace textlayout { |
14 | | |
15 | | class ParagraphImpl; |
16 | | class OneLineShaper : public SkShaper::RunHandler { |
17 | | public: |
18 | | explicit OneLineShaper(ParagraphImpl* paragraph) |
19 | | : fParagraph(paragraph) |
20 | | , fHeight(0.0f) |
21 | | , fUseHalfLeading(false) |
22 | | , fBaselineShift(0.0f) |
23 | | , fAdvance(SkPoint::Make(0.0f, 0.0f)) |
24 | | , fUnresolvedGlyphs(0) |
25 | 0 | , fUniqueRunId(paragraph->fRuns.size()){ } |
26 | | |
27 | | bool shape(); |
28 | | |
29 | 0 | size_t unresolvedGlyphs() { return fUnresolvedGlyphs; } |
30 | | |
31 | | /** |
32 | | * This method is based on definition of https://unicode.org/reports/tr51/#def_emoji_sequence |
33 | | * It determines if the string begins with an emoji sequence and, |
34 | | * if so, return the first codepoint, moving 'begin' pointer to the next once. |
35 | | * Otherwise it does not move the pointer and returns -1. |
36 | | */ |
37 | | static SkUnichar getEmojiSequenceStart(SkUnicode* unicode, const char** begin, const char* end); |
38 | | |
39 | | private: |
40 | | |
41 | | struct RunBlock { |
42 | 0 | RunBlock() : fRun(nullptr) { } |
43 | | |
44 | | // First unresolved block |
45 | 0 | explicit RunBlock(TextRange text) : fRun(nullptr), fText(text) { } |
46 | | |
47 | | RunBlock(std::shared_ptr<Run> run, TextRange text, GlyphRange glyphs, size_t score) |
48 | | : fRun(std::move(run)) |
49 | | , fText(text) |
50 | 0 | , fGlyphs(glyphs) { } |
51 | | |
52 | | // Entire run comes as one block fully resolved |
53 | | explicit RunBlock(std::shared_ptr<Run> run) |
54 | | : fRun(std::move(run)) |
55 | | , fText(fRun->fTextRange) |
56 | 0 | , fGlyphs(GlyphRange(0, fRun->size())) { } |
57 | | |
58 | | std::shared_ptr<Run> fRun; |
59 | | TextRange fText; |
60 | | GlyphRange fGlyphs; |
61 | 0 | bool isFullyResolved() { return fRun != nullptr && fGlyphs.width() == fRun->size(); } |
62 | | }; |
63 | | |
64 | | using ShapeVisitor = |
65 | | std::function<SkScalar(TextRange textRange, SkSpan<Block>, SkScalar&, TextIndex, uint8_t)>; |
66 | | bool iterateThroughShapingRegions(const ShapeVisitor& shape); |
67 | | |
68 | | using ShapeSingleFontVisitor = |
69 | | std::function<void(Block, skia_private::TArray<SkShaper::Feature>)>; |
70 | | void iterateThroughFontStyles( |
71 | | TextRange textRange, SkSpan<Block> styleSpan, const ShapeSingleFontVisitor& visitor); |
72 | | |
73 | | enum Resolved { |
74 | | Nothing, |
75 | | Something, |
76 | | Everything |
77 | | }; |
78 | | |
79 | | using TypefaceVisitor = std::function<Resolved(sk_sp<SkTypeface> typeface)>; |
80 | | void matchResolvedFonts(const TextStyle& textStyle, const TypefaceVisitor& visitor); |
81 | | #ifdef SK_DEBUG |
82 | | void printState(); |
83 | | #endif |
84 | | void finish(const Block& block, SkScalar height, SkScalar& advanceX); |
85 | | |
86 | 0 | void beginLine() override {} |
87 | 0 | void runInfo(const RunInfo&) override {} |
88 | 0 | void commitRunInfo() override {} |
89 | 0 | void commitLine() override {} |
90 | | |
91 | 0 | Buffer runBuffer(const RunInfo& info) override { |
92 | 0 | fCurrentRun = std::make_shared<Run>(fParagraph, |
93 | 0 | info, |
94 | 0 | fCurrentText.start, |
95 | 0 | fHeight, |
96 | 0 | fUseHalfLeading, |
97 | 0 | fBaselineShift, |
98 | 0 | ++fUniqueRunId, |
99 | 0 | fAdvance.fX); |
100 | 0 | return fCurrentRun->newRunBuffer(); |
101 | 0 | } |
102 | | |
103 | | void commitRunBuffer(const RunInfo&) override; |
104 | | |
105 | | TextRange clusteredText(GlyphRange& glyphs); |
106 | 0 | ClusterIndex clusterIndex(GlyphIndex glyph) { |
107 | 0 | return fCurrentText.start + fCurrentRun->fClusterIndexes[glyph]; |
108 | 0 | } |
109 | | void addFullyResolved(); |
110 | | void addUnresolvedWithRun(GlyphRange glyphRange); |
111 | | void sortOutGlyphs(std::function<void(GlyphRange)>&& sortOutUnresolvedBLock); |
112 | | ClusterRange normalizeTextRange(GlyphRange glyphRange); |
113 | | void fillGaps(size_t); |
114 | | |
115 | | ParagraphImpl* fParagraph; |
116 | | TextRange fCurrentText; |
117 | | SkScalar fHeight; |
118 | | bool fUseHalfLeading; |
119 | | SkScalar fBaselineShift; |
120 | | SkVector fAdvance; |
121 | | size_t fUnresolvedGlyphs; |
122 | | size_t fUniqueRunId; |
123 | | |
124 | | // TODO: Something that is not thead-safe since we don't need it |
125 | | std::shared_ptr<Run> fCurrentRun; |
126 | | std::deque<RunBlock> fUnresolvedBlocks; |
127 | | std::vector<RunBlock> fResolvedBlocks; |
128 | | |
129 | | // Keeping all resolved typefaces |
130 | | struct FontKey { |
131 | | |
132 | 0 | FontKey() {} |
133 | | |
134 | | FontKey(SkUnichar unicode, SkFontStyle fontStyle, SkString locale) |
135 | 0 | : fUnicode(unicode), fFontStyle(fontStyle), fLocale(std::move(locale)) { } |
136 | | SkUnichar fUnicode; |
137 | | SkFontStyle fFontStyle; |
138 | | SkString fLocale; |
139 | | |
140 | | bool operator==(const FontKey& other) const; |
141 | | |
142 | | struct Hasher { |
143 | | uint32_t operator()(const FontKey& key) const; |
144 | | }; |
145 | | }; |
146 | | |
147 | | skia_private::THashMap<FontKey, sk_sp<SkTypeface>, FontKey::Hasher> fFallbackFonts; |
148 | | }; |
149 | | |
150 | | } // namespace textlayout |
151 | | } // namespace skia |
152 | | #endif |