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