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