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