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