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: OneLineShaper(ParagraphImpl * paragraph)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 , fUniqueRunId(paragraph->fRuns.size()){ } 26 27 bool shape(); 28 unresolvedGlyphs()29 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 { RunBlockRunBlock42 RunBlock() : fRun(nullptr) { } 43 44 // First unresolved block RunBlockRunBlock45 explicit RunBlock(TextRange text) : fRun(nullptr), fText(text) { } 46 RunBlockRunBlock47 RunBlock(std::shared_ptr<Run> run, TextRange text, GlyphRange glyphs, size_t score) 48 : fRun(std::move(run)) 49 , fText(text) 50 , fGlyphs(glyphs) { } 51 52 // Entire run comes as one block fully resolved RunBlockRunBlock53 explicit RunBlock(std::shared_ptr<Run> run) 54 : fRun(std::move(run)) 55 , fText(fRun->fTextRange) 56 , fGlyphs(GlyphRange(0, fRun->size())) { } 57 58 std::shared_ptr<Run> fRun; 59 TextRange fText; 60 GlyphRange fGlyphs; isFullyResolvedRunBlock61 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 #ifdef ENABLE_TEXT_ENHANCE 80 using TypefaceVisitor = std::function<Resolved(std::shared_ptr<RSTypeface> typeface)>; 81 #else 82 using TypefaceVisitor = std::function<Resolved(sk_sp<SkTypeface> typeface)>; 83 #endif 84 void matchResolvedFonts(const TextStyle& textStyle, const TypefaceVisitor& visitor); 85 86 #ifdef ENABLE_TEXT_ENHANCE 87 bool isUnresolvedCombineGlyphRange(std::shared_ptr<Run> run, size_t glyphStart, size_t glyphEnd, 88 size_t charStart) const; 89 void splitUnresolvedBlockAndStageResolvedSubBlock( 90 std::deque<RunBlock>& stagedUnresolvedBlocks, const RunBlock& unresolvedBlock); 91 void shapeUnresolvedTextSeparatelyFromUnresolvedBlock(const TextStyle& textStyle, const TypefaceVisitor& visitor); 92 void matchResolvedFontsFindTypeface(const TextStyle& textStyle, std::shared_ptr<RSTypeface>& typeface, 93 SkUnichar& unicode); 94 void matchResolvedFontsByUnicode(const TextStyle& textStyle, const TypefaceVisitor& visitor, 95 std::vector<RunBlock>& hopelessBlocks); 96 #endif 97 98 #ifdef SK_DEBUG 99 void printState(); 100 #endif 101 void finish(const Block& block, SkScalar height, SkScalar& advanceX); 102 beginLine()103 void beginLine() override {} runInfo(const RunInfo &)104 void runInfo(const RunInfo&) override {} commitRunInfo()105 void commitRunInfo() override {} commitLine()106 void commitLine() override {} 107 runBuffer(const RunInfo & info)108 Buffer runBuffer(const RunInfo& info) override { 109 fCurrentRun = std::make_shared<Run>(fParagraph, 110 info, 111 fCurrentText.start, 112 fHeight, 113 fUseHalfLeading, 114 fBaselineShift, 115 ++fUniqueRunId, 116 fAdvance.fX); 117 return fCurrentRun->newRunBuffer(); 118 } 119 120 void commitRunBuffer(const RunInfo&) override; 121 122 #ifdef ENABLE_TEXT_ENHANCE 123 void adjustRange(GlyphRange& glyphs, TextRange& textRange); 124 #endif 125 TextRange clusteredText(GlyphRange& glyphs); clusterIndex(GlyphIndex glyph)126 ClusterIndex clusterIndex(GlyphIndex glyph) { 127 return fCurrentText.start + fCurrentRun->fClusterIndexes[glyph]; 128 } 129 void addFullyResolved(); 130 void addUnresolvedWithRun(GlyphRange glyphRange); 131 void sortOutGlyphs(std::function<void(GlyphRange)>&& sortOutUnresolvedBLock); 132 ClusterRange normalizeTextRange(GlyphRange glyphRange); 133 void fillGaps(size_t); 134 #ifdef ENABLE_TEXT_ENHANCE 135 BlockRange generateBlockRange(const Block& block, const TextRange& textRange); 136 #endif 137 138 ParagraphImpl* fParagraph; 139 TextRange fCurrentText; 140 SkScalar fHeight; 141 bool fUseHalfLeading; 142 SkScalar fBaselineShift; 143 SkVector fAdvance; 144 size_t fUnresolvedGlyphs; 145 size_t fUniqueRunId; 146 147 // TODO: Something that is not thead-safe since we don't need it 148 std::shared_ptr<Run> fCurrentRun; 149 std::deque<RunBlock> fUnresolvedBlocks; 150 std::vector<RunBlock> fResolvedBlocks; 151 152 // Keeping all resolved typefaces 153 struct FontKey { 154 FontKeyFontKey155 FontKey() {} 156 157 #ifdef ENABLE_TEXT_ENHANCE FontKeyFontKey158 FontKey(SkUnichar unicode, RSFontStyle fontStyle, SkString locale) 159 : fUnicode(unicode), fFontStyle(fontStyle), fLocale(locale) { } 160 #else FontKeyFontKey161 FontKey(SkUnichar unicode, SkFontStyle fontStyle, SkString locale) 162 : fUnicode(unicode), fFontStyle(fontStyle), fLocale(std::move(locale)) { } 163 #endif 164 SkUnichar fUnicode; 165 #ifdef ENABLE_TEXT_ENHANCE 166 RSFontStyle fFontStyle; 167 #else 168 SkFontStyle fFontStyle; 169 #endif 170 SkString fLocale; 171 172 bool operator==(const FontKey& other) const; 173 174 struct Hasher { 175 uint32_t operator()(const FontKey& key) const; 176 }; 177 }; 178 179 #ifdef ENABLE_TEXT_ENHANCE 180 std::unordered_map<FontKey, std::shared_ptr<RSTypeface>, FontKey::Hasher> fFallbackFonts; 181 #else 182 skia_private::THashMap<FontKey, sk_sp<SkTypeface>, FontKey::Hasher> fFallbackFonts; 183 #endif 184 }; 185 186 } // namespace textlayout 187 } // namespace skia 188 #endif 189