• 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/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