1 | /* |
2 | * Copyright 2018 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #include "include/core/SkFont.h" |
9 | #include "include/core/SkFontMetrics.h" |
10 | #include "include/core/SkFontMgr.h" |
11 | #include "include/core/SkFontStyle.h" |
12 | #include "include/core/SkString.h" |
13 | #include "include/core/SkTypeface.h" |
14 | #include "include/private/SkTFitsIn.h" |
15 | #include "modules/skshaper/include/SkShaper.h" |
16 | #include "src/core/SkTextBlobPriv.h" |
17 | #include "src/utils/SkUTF.h" |
18 | |
19 | #include <limits.h> |
20 | #include <string.h> |
21 | #include <locale> |
22 | #include <string> |
23 | #include <utility> |
24 | |
25 | std::unique_ptr<SkShaper> SkShaper::Make(sk_sp<SkFontMgr> fontmgr) { |
26 | #ifdef SK_SHAPER_HARFBUZZ_AVAILABLE |
27 | std::unique_ptr<SkShaper> shaper = SkShaper::MakeShaperDrivenWrapper(std::move(fontmgr)); |
28 | if (shaper) { |
29 | return shaper; |
30 | } |
31 | #endif |
32 | return SkShaper::MakePrimitive(); |
33 | } |
34 | |
35 | std::unique_ptr<SkShaper::BiDiRunIterator> |
36 | SkShaper::MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) { |
37 | #ifdef SK_SHAPER_HARFBUZZ_AVAILABLE |
38 | std::unique_ptr<SkShaper::BiDiRunIterator> bidi = |
39 | SkShaper::MakeIcuBiDiRunIterator(utf8, utf8Bytes, bidiLevel); |
40 | if (bidi) { |
41 | return bidi; |
42 | } |
43 | #endif |
44 | return std::make_unique<SkShaper::TrivialBiDiRunIterator>(bidiLevel, utf8Bytes); |
45 | } |
46 | |
47 | std::unique_ptr<SkShaper::ScriptRunIterator> |
48 | SkShaper::MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag scriptTag) { |
49 | #ifdef SK_SHAPER_HARFBUZZ_AVAILABLE |
50 | std::unique_ptr<SkShaper::ScriptRunIterator> script = |
51 | SkShaper::MakeHbIcuScriptRunIterator(utf8, utf8Bytes); |
52 | if (script) { |
53 | return script; |
54 | } |
55 | #endif |
56 | return std::make_unique<SkShaper::TrivialScriptRunIterator>(scriptTag, utf8Bytes); |
57 | } |
58 | |
59 | SkShaper::SkShaper() {} |
60 | SkShaper::~SkShaper() {} |
61 | |
62 | /** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */ |
63 | static inline SkUnichar utf8_next(const char** ptr, const char* end) { |
64 | SkUnichar val = SkUTF::NextUTF8(ptr, end); |
65 | return val < 0 ? 0xFFFD : val; |
66 | } |
67 | |
68 | class FontMgrRunIterator final : public SkShaper::FontRunIterator { |
69 | public: |
70 | FontMgrRunIterator(const char* utf8, size_t utf8Bytes, |
71 | const SkFont& font, sk_sp<SkFontMgr> fallbackMgr, |
72 | const char* requestName, SkFontStyle requestStyle, |
73 | const SkShaper::LanguageRunIterator* lang) |
74 | : fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes) |
75 | , fFallbackMgr(std::move(fallbackMgr)) |
76 | , fFont(font) |
77 | , fFallbackFont(fFont) |
78 | , fCurrentFont(nullptr) |
79 | , fRequestName(requestName) |
80 | , fRequestStyle(requestStyle) |
81 | , fLanguage(lang) |
82 | { |
83 | fFont.setTypeface(font.refTypefaceOrDefault()); |
84 | fFallbackFont.setTypeface(nullptr); |
85 | } |
86 | FontMgrRunIterator(const char* utf8, size_t utf8Bytes, |
87 | const SkFont& font, sk_sp<SkFontMgr> fallbackMgr) |
88 | : FontMgrRunIterator(utf8, utf8Bytes, font, std::move(fallbackMgr), |
89 | nullptr, font.refTypefaceOrDefault()->fontStyle(), nullptr) |
90 | {} |
91 | |
92 | void consume() override { |
93 | SkASSERT(fCurrent < fEnd); |
94 | SkASSERT(!fLanguage || this->endOfCurrentRun() <= fLanguage->endOfCurrentRun()); |
95 | SkUnichar u = utf8_next(&fCurrent, fEnd); |
96 | // If the starting typeface can handle this character, use it. |
97 | if (fFont.unicharToGlyph(u)) { |
98 | fCurrentFont = &fFont; |
99 | // If the current fallback can handle this character, use it. |
100 | } else if (fFallbackFont.getTypeface() && fFallbackFont.unicharToGlyph(u)) { |
101 | fCurrentFont = &fFallbackFont; |
102 | // If not, try to find a fallback typeface |
103 | } else { |
104 | const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr; |
105 | int languageCount = fLanguage ? 1 : 0; |
106 | sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter( |
107 | fRequestName, fRequestStyle, &language, languageCount, u)); |
108 | if (candidate) { |
109 | fFallbackFont.setTypeface(std::move(candidate)); |
110 | fCurrentFont = &fFallbackFont; |
111 | } else { |
112 | fCurrentFont = &fFont; |
113 | } |
114 | } |
115 | |
116 | while (fCurrent < fEnd) { |
117 | const char* prev = fCurrent; |
118 | u = utf8_next(&fCurrent, fEnd); |
119 | |
120 | // End run if not using initial typeface and initial typeface has this character. |
121 | if (fCurrentFont->getTypeface() != fFont.getTypeface() && fFont.unicharToGlyph(u)) { |
122 | fCurrent = prev; |
123 | return; |
124 | } |
125 | |
126 | // End run if current typeface does not have this character and some other font does. |
127 | if (!fCurrentFont->unicharToGlyph(u)) { |
128 | const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr; |
129 | int languageCount = fLanguage ? 1 : 0; |
130 | sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter( |
131 | fRequestName, fRequestStyle, &language, languageCount, u)); |
132 | if (candidate) { |
133 | fCurrent = prev; |
134 | return; |
135 | } |
136 | } |
137 | } |
138 | } |
139 | size_t endOfCurrentRun() const override { |
140 | return fCurrent - fBegin; |
141 | } |
142 | bool atEnd() const override { |
143 | return fCurrent == fEnd; |
144 | } |
145 | |
146 | const SkFont& currentFont() const override { |
147 | return *fCurrentFont; |
148 | } |
149 | |
150 | private: |
151 | char const * fCurrent; |
152 | char const * const fBegin; |
153 | char const * const fEnd; |
154 | sk_sp<SkFontMgr> const fFallbackMgr; |
155 | SkFont fFont; |
156 | SkFont fFallbackFont; |
157 | SkFont* fCurrentFont; |
158 | char const * const fRequestName; |
159 | SkFontStyle const fRequestStyle; |
160 | SkShaper::LanguageRunIterator const * const fLanguage; |
161 | }; |
162 | |
163 | std::unique_ptr<SkShaper::FontRunIterator> |
164 | SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes, |
165 | const SkFont& font, sk_sp<SkFontMgr> fallback) |
166 | { |
167 | return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback)); |
168 | } |
169 | |
170 | std::unique_ptr<SkShaper::FontRunIterator> |
171 | SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes, const SkFont& font, |
172 | sk_sp<SkFontMgr> fallback, |
173 | const char* requestName, SkFontStyle requestStyle, |
174 | const SkShaper::LanguageRunIterator* language) |
175 | { |
176 | return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback), |
177 | requestName, requestStyle, language); |
178 | } |
179 | |
180 | std::unique_ptr<SkShaper::LanguageRunIterator> |
181 | SkShaper::MakeStdLanguageRunIterator(const char* utf8, size_t utf8Bytes) { |
182 | return std::make_unique<TrivialLanguageRunIterator>(std::locale().name().c_str(), utf8Bytes); |
183 | } |
184 | |
185 | void SkTextBlobBuilderRunHandler::beginLine() { |
186 | fCurrentPosition = fOffset; |
187 | fMaxRunAscent = 0; |
188 | fMaxRunDescent = 0; |
189 | fMaxRunLeading = 0; |
190 | } |
191 | void SkTextBlobBuilderRunHandler::runInfo(const RunInfo& info) { |
192 | SkFontMetrics metrics; |
193 | info.fFont.getMetrics(&metrics); |
194 | fMaxRunAscent = std::min(fMaxRunAscent, metrics.fAscent); |
195 | fMaxRunDescent = std::max(fMaxRunDescent, metrics.fDescent); |
196 | fMaxRunLeading = std::max(fMaxRunLeading, metrics.fLeading); |
197 | } |
198 | |
199 | void SkTextBlobBuilderRunHandler::commitRunInfo() { |
200 | fCurrentPosition.fY -= fMaxRunAscent; |
201 | } |
202 | |
203 | SkShaper::RunHandler::Buffer SkTextBlobBuilderRunHandler::runBuffer(const RunInfo& info) { |
204 | int glyphCount = SkTFitsIn<int>(info.glyphCount) ? info.glyphCount : INT_MAX; |
205 | int utf8RangeSize = SkTFitsIn<int>(info.utf8Range.size()) ? info.utf8Range.size() : INT_MAX; |
206 | |
207 | const auto& runBuffer = SkTextBlobBuilderPriv::AllocRunTextPos(&fBuilder, info.fFont, glyphCount, |
208 | utf8RangeSize, SkString()); |
209 | if (runBuffer.utf8text && fUtf8Text) { |
210 | memcpy(runBuffer.utf8text, fUtf8Text + info.utf8Range.begin(), utf8RangeSize); |
211 | } |
212 | fClusters = runBuffer.clusters; |
213 | fGlyphCount = glyphCount; |
214 | fClusterOffset = info.utf8Range.begin(); |
215 | |
216 | return { runBuffer.glyphs, |
217 | runBuffer.points(), |
218 | nullptr, |
219 | runBuffer.clusters, |
220 | fCurrentPosition }; |
221 | } |
222 | |
223 | void SkTextBlobBuilderRunHandler::commitRunBuffer(const RunInfo& info) { |
224 | SkASSERT(0 <= fClusterOffset); |
225 | for (int i = 0; i < fGlyphCount; ++i) { |
226 | SkASSERT(fClusters[i] >= (unsigned)fClusterOffset); |
227 | fClusters[i] -= fClusterOffset; |
228 | } |
229 | fCurrentPosition += info.fAdvance; |
230 | } |
231 | void SkTextBlobBuilderRunHandler::commitLine() { |
232 | fOffset += { 0, fMaxRunDescent + fMaxRunLeading - fMaxRunAscent }; |
233 | } |
234 | |
235 | sk_sp<SkTextBlob> SkTextBlobBuilderRunHandler::makeBlob() { |
236 | return fBuilder.make(); |
237 | } |
238 | |