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/SkTypeface.h"
13 #include "include/private/base/SkTFitsIn.h"
14 #include "modules/skshaper/include/SkShaper.h"
15 #include "src/base/SkUTF.h"
16 #include <limits.h>
17 #include <algorithm>
18 #include <cstring>
19 #include <locale>
20 #include <string>
21 #include <utility>
22
23 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
24
25 #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
26 #include "modules/skshaper/include/SkShaper_harfbuzz.h"
27 #endif
28
29 #if defined(SK_SHAPER_CORETEXT_AVAILABLE)
30 #include "modules/skshaper/include/SkShaper_coretext.h"
31 #endif
32
33 #endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
34
35 #ifdef ENABLE_TEXT_ENHANCE
36 namespace {
GetRSTypefaceOrDefault(std::shared_ptr<RSTypeface> typeface)37 std::shared_ptr<RSTypeface> GetRSTypefaceOrDefault(std::shared_ptr<RSTypeface> typeface) {
38 if (typeface) {
39 return typeface;
40 } else {
41 return RSTypeface::MakeDefault();
42 }
43 }
44 }
45 #endif
46 #ifdef ENABLE_DRAWING_ADAPTER
47 namespace SkiaRsText {
48 #endif
49
50 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
51 #ifdef ENABLE_TEXT_ENHANCE
Make(std::shared_ptr<RSFontMgr> fallback)52 std::unique_ptr<SkShaper> SkShaper::Make(std::shared_ptr<RSFontMgr> fallback) {
53 #else
54 std::unique_ptr<SkShaper> SkShaper::Make(sk_sp<SkFontMgr> fallback) {
55 #endif
56 #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
57 std::unique_ptr<SkShaper> shaper = MakeShapeThenWrap(std::move(fallback));
58 if (shaper) {
59 return shaper;
60 }
61 #elif defined(SK_SHAPER_CORETEXT_AVAILABLE)
62 if (auto shaper = SkShapers::CT::CoreText()) {
63 return shaper;
64 }
65 #endif
66 return SkShapers::Primitive::PrimitiveText();
67 }
68
69 void SkShaper::PurgeCaches() {
70 #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
71 SkShapers::HB::PurgeCaches();
72 #endif
73 }
74
75 std::unique_ptr<SkShaper::BiDiRunIterator>
76 SkShaper::MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) {
77 #if defined(SK_SHAPER_UNICODE_AVAILABLE)
78 std::unique_ptr<SkShaper::BiDiRunIterator> bidi = MakeIcuBiDiRunIterator(utf8, utf8Bytes, bidiLevel);
79 if (bidi) {
80 return bidi;
81 }
82 #endif
83 return std::make_unique<SkShaper::TrivialBiDiRunIterator>(bidiLevel, utf8Bytes);
84 }
85
86 std::unique_ptr<SkShaper::ScriptRunIterator>
87 SkShaper::MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag scriptTag) {
88 #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
89 std::unique_ptr<SkShaper::ScriptRunIterator> script =
90 SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes, scriptTag);
91 if (script) {
92 return script;
93 }
94 #endif
95 return std::make_unique<SkShaper::TrivialScriptRunIterator>(scriptTag, utf8Bytes);
96 }
97 #endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
98
99 SkShaper::SkShaper() {}
100 SkShaper::~SkShaper() {}
101
102 /** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
103 static inline SkUnichar utf8_next(const char** ptr, const char* end) {
104 SkUnichar val = SkUTF::NextUTF8(ptr, end);
105 return val < 0 ? 0xFFFD : val;
106 }
107
108 #ifdef ENABLE_TEXT_ENHANCE
109 class FontMgrRunIterator final : public SkShaper::FontRunIterator {
110 public:
111 FontMgrRunIterator(const char* utf8, size_t utf8Bytes,
112 const RSFont& font, std::shared_ptr<RSFontMgr> fallbackMgr,
113 const char* requestName, RSFontStyle requestStyle,
114 const SkShaper::LanguageRunIterator* lang)
115 : fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes)
116 , fFallbackMgr(std::move(fallbackMgr))
117 , fFont(font)
118 , fFallbackFont(fFont)
119 , fCurrentFont(nullptr)
120 , fRequestName(requestName)
121 , fRequestStyle(requestStyle)
122 , fLanguage(lang)
123 {
124 fFont.SetTypeface(GetRSTypefaceOrDefault(const_cast<RSFont&>(font).GetTypeface()));
125 fFallbackFont.SetTypeface(nullptr);
126 }
127 FontMgrRunIterator(const char* utf8, size_t utf8Bytes,
128 const RSFont& font, std::shared_ptr<RSFontMgr> fallbackMgr)
129 : FontMgrRunIterator(
130 utf8, utf8Bytes, font, std::move(fallbackMgr), nullptr,
131 GetRSTypefaceOrDefault(const_cast<RSFont&>(font).GetTypeface())->GetFontStyle(), nullptr)
132 {}
133
134 void consume() override {
135 SkASSERT(fCurrent < fEnd);
136 SkASSERT(!fLanguage || this->endOfCurrentRun() <= fLanguage->endOfCurrentRun());
137 SkUnichar u = utf8_next(&fCurrent, fEnd);
138 // If the starting typeface can handle this character, use it.
139 if (fFont.UnicharToGlyph(u)) {
140 fCurrentFont = &fFont;
141 // If the current fallback can handle this character, use it.
142 } else if (fFallbackFont.GetTypeface() && fFallbackFont.UnicharToGlyph(u)) {
143 fCurrentFont = &fFallbackFont;
144 // If not, try to find a fallback typeface
145 } else {
146 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
147 int languageCount = fLanguage ? 1 : 0;
148 std::shared_ptr<RSTypeface> candidate(fFallbackMgr->MatchFamilyStyleCharacter(
149 fRequestName, fRequestStyle, &language, languageCount, u));
150 if (candidate) {
151 fFallbackFont.SetTypeface(std::move(candidate));
152 fCurrentFont = &fFallbackFont;
153 } else {
154 fCurrentFont = &fFont;
155 }
156 }
157
158 while (fCurrent < fEnd) {
159 const char* prev = fCurrent;
160 u = utf8_next(&fCurrent, fEnd);
161 // End run if not using initial typeface and initial typeface has this character.
162 if (fCurrentFont->GetTypeface() != fFont.GetTypeface() && fFont.UnicharToGlyph(u)) {
163 fCurrent = prev;
164 return;
165 }
166
167 // End run if current typeface does not have this character and some other font does.
168 if (!fCurrentFont->UnicharToGlyph(u)) {
169 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
170 int languageCount = fLanguage ? 1 : 0;
171 std::shared_ptr<RSTypeface> candidate(fFallbackMgr->MatchFamilyStyleCharacter(
172 fRequestName, fRequestStyle, &language, languageCount, u));
173 if (candidate) {
174 fCurrent = prev;
175 return;
176 }
177 }
178 }
179 }
180 size_t endOfCurrentRun() const override {
181 return fCurrent - fBegin;
182 }
183 bool atEnd() const override {
184 return fCurrent == fEnd;
185 }
186
187 const RSFont& currentFont() const override {
188 return *fCurrentFont;
189 }
190
191 private:
192 char const * fCurrent;
193 char const * const fBegin;
194 char const * const fEnd;
195 std::shared_ptr<RSFontMgr> const fFallbackMgr;
196 RSFont fFont;
197 RSFont fFallbackFont;
198 RSFont* fCurrentFont;
199 char const * const fRequestName;
200 RSFontStyle const fRequestStyle;
201 SkShaper::LanguageRunIterator const * const fLanguage;
202 };
203 #else
204 class FontMgrRunIterator final : public SkShaper::FontRunIterator {
205 public:
206 FontMgrRunIterator(const char* utf8, size_t utf8Bytes,
207 const SkFont& font, sk_sp<SkFontMgr> fallbackMgr,
208 const char* requestName, SkFontStyle requestStyle,
209 const SkShaper::LanguageRunIterator* lang)
210 : fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes)
211 , fFallbackMgr(std::move(fallbackMgr))
212 , fFont(font)
213 , fFallbackFont(fFont)
214 , fCurrentFont(nullptr)
215 , fRequestName(requestName)
216 , fRequestStyle(requestStyle)
217 , fLanguage(lang)
218 {
219 // If fallback is not wanted, clients should use TrivialFontRunIterator.
220 SkASSERT(fFallbackMgr);
221 fFont.setTypeface(font.refTypeface());
222 fFallbackFont.setTypeface(nullptr);
223 }
224 FontMgrRunIterator(const char* utf8, size_t utf8Bytes,
225 const SkFont& font, sk_sp<SkFontMgr> fallbackMgr)
226 : FontMgrRunIterator(utf8, utf8Bytes, font, std::move(fallbackMgr),
227 nullptr, font.getTypeface()->fontStyle(), nullptr)
228 {}
229
230 void consume() override {
231 SkASSERT(fCurrent < fEnd);
232 SkASSERT(!fLanguage || this->endOfCurrentRun() <= fLanguage->endOfCurrentRun());
233 SkUnichar u = utf8_next(&fCurrent, fEnd);
234 // If the starting typeface can handle this character, use it.
235 if (fFont.unicharToGlyph(u)) {
236 fCurrentFont = &fFont;
237 // If the current fallback can handle this character, use it.
238 } else if (fFallbackFont.getTypeface() && fFallbackFont.unicharToGlyph(u)) {
239 fCurrentFont = &fFallbackFont;
240 // If not, try to find a fallback typeface
241 } else {
242 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
243 int languageCount = fLanguage ? 1 : 0;
244 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
245 fRequestName, fRequestStyle, &language, languageCount, u));
246 if (candidate) {
247 fFallbackFont.setTypeface(std::move(candidate));
248 fCurrentFont = &fFallbackFont;
249 } else {
250 fCurrentFont = &fFont;
251 }
252 }
253
254 while (fCurrent < fEnd) {
255 const char* prev = fCurrent;
256 u = utf8_next(&fCurrent, fEnd);
257
258 // End run if not using initial typeface and initial typeface has this character.
259 if (fCurrentFont->getTypeface() != fFont.getTypeface() && fFont.unicharToGlyph(u)) {
260 fCurrent = prev;
261 return;
262 }
263
264 // End run if current typeface does not have this character and some other font does.
265 if (!fCurrentFont->unicharToGlyph(u)) {
266 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
267 int languageCount = fLanguage ? 1 : 0;
268 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
269 fRequestName, fRequestStyle, &language, languageCount, u));
270 if (candidate) {
271 fCurrent = prev;
272 return;
273 }
274 }
275 }
276 }
277 size_t endOfCurrentRun() const override {
278 return fCurrent - fBegin;
279 }
280 bool atEnd() const override {
281 return fCurrent == fEnd;
282 }
283
284 const SkFont& currentFont() const override {
285 return *fCurrentFont;
286 }
287
288 private:
289 char const * fCurrent;
290 char const * const fBegin;
291 char const * const fEnd;
292 sk_sp<SkFontMgr> const fFallbackMgr;
293 SkFont fFont;
294 SkFont fFallbackFont;
295 SkFont* fCurrentFont;
296 char const * const fRequestName;
297 SkFontStyle const fRequestStyle;
298 SkShaper::LanguageRunIterator const * const fLanguage;
299 };
300 #endif
301
302 #ifdef ENABLE_TEXT_ENHANCE
303 std::unique_ptr<SkShaper::FontRunIterator>
304 SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes,
305 const RSFont& font, std::shared_ptr<RSFontMgr> fallback)
306 {
307 return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback));
308 }
309
310 std::unique_ptr<SkShaper::FontRunIterator>
311 SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes, const RSFont& font,
312 std::shared_ptr<RSFontMgr> fallback,
313 const char* requestName, RSFontStyle requestStyle,
314 const SkShaper::LanguageRunIterator* language)
315 {
316 return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback),
317 requestName, requestStyle, language);
318 }
319 #else
320 std::unique_ptr<SkShaper::FontRunIterator>
321 SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes,
322 const SkFont& font, sk_sp<SkFontMgr> fallback)
323 {
324 return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback));
325 }
326
327 std::unique_ptr<SkShaper::FontRunIterator>
328 SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes, const SkFont& font,
329 sk_sp<SkFontMgr> fallback,
330 const char* requestName, SkFontStyle requestStyle,
331 const SkShaper::LanguageRunIterator* language)
332 {
333 return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback),
334 requestName, requestStyle, language);
335 }
336 #endif
337
338 std::unique_ptr<SkShaper::LanguageRunIterator>
339 SkShaper::MakeStdLanguageRunIterator(const char* utf8, size_t utf8Bytes) {
340 return std::make_unique<TrivialLanguageRunIterator>(std::locale().name().c_str(), utf8Bytes);
341 }
342
343 #ifndef ENABLE_TEXT_ENHANCE
344 void SkTextBlobBuilderRunHandler::beginLine() {
345 fCurrentPosition = fOffset;
346 fMaxRunAscent = 0;
347 fMaxRunDescent = 0;
348 fMaxRunLeading = 0;
349 }
350 void SkTextBlobBuilderRunHandler::runInfo(const RunInfo& info) {
351 SkFontMetrics metrics;
352 info.fFont.getMetrics(&metrics);
353 fMaxRunAscent = std::min(fMaxRunAscent, metrics.fAscent);
354 fMaxRunDescent = std::max(fMaxRunDescent, metrics.fDescent);
355 fMaxRunLeading = std::max(fMaxRunLeading, metrics.fLeading);
356 }
357
358 void SkTextBlobBuilderRunHandler::commitRunInfo() {
359 fCurrentPosition.fY -= fMaxRunAscent;
360 }
361
362 SkShaper::RunHandler::Buffer SkTextBlobBuilderRunHandler::runBuffer(const RunInfo& info) {
363 int glyphCount = SkTFitsIn<int>(info.glyphCount) ? info.glyphCount : INT_MAX;
364 int utf8RangeSize = SkTFitsIn<int>(info.utf8Range.size()) ? info.utf8Range.size() : INT_MAX;
365
366 const auto& runBuffer = fBuilder.allocRunTextPos(info.fFont, glyphCount, utf8RangeSize);
367 if (runBuffer.utf8text && fUtf8Text) {
368 memcpy(runBuffer.utf8text, fUtf8Text + info.utf8Range.begin(), utf8RangeSize);
369 }
370 fClusters = runBuffer.clusters;
371 fGlyphCount = glyphCount;
372 fClusterOffset = info.utf8Range.begin();
373
374 return { runBuffer.glyphs,
375 runBuffer.points(),
376 nullptr,
377 runBuffer.clusters,
378 fCurrentPosition };
379 }
380
381 void SkTextBlobBuilderRunHandler::commitRunBuffer(const RunInfo& info) {
382 SkASSERT(0 <= fClusterOffset);
383 for (int i = 0; i < fGlyphCount; ++i) {
384 SkASSERT(fClusters[i] >= (unsigned)fClusterOffset);
385 fClusters[i] -= fClusterOffset;
386 }
387 fCurrentPosition += info.fAdvance;
388 }
389 void SkTextBlobBuilderRunHandler::commitLine() {
390 fOffset += { 0, fMaxRunDescent + fMaxRunLeading - fMaxRunAscent };
391 }
392
393 sk_sp<SkTextBlob> SkTextBlobBuilderRunHandler::makeBlob() {
394 return fBuilder.make();
395 }
396 #endif
397 #ifdef ENABLE_DRAWING_ADAPTER
398 } // namespace SkiaRsText
399 #endif // ENABLE_DRAWING_ADAPTER