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