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