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