blob: bb8311500a0375af19dbc2f7ff7abd4b917980f8 [file] [log] [blame]
Florin Malita9867f612018-12-12 10:54:49 -05001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkFont.h"
9#include "include/core/SkFontMetrics.h"
10#include "include/core/SkFontMgr.h"
Ben Wagner1ca50522019-10-01 17:54:28 -040011#include "include/core/SkFontStyle.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkString.h"
13#include "include/core/SkTypeface.h"
14#include "include/private/SkTFitsIn.h"
15#include "modules/skshaper/include/SkShaper.h"
Julia Lavrova90787fe2020-07-20 17:32:03 +000016
17#ifdef SK_UNICODE_AVAILABLE
Florin Malita40f3db42021-07-27 14:02:28 -040018#include "modules/skunicode/include/SkUnicode.h"
Julia Lavrova90787fe2020-07-20 17:32:03 +000019#endif
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/core/SkTextBlobPriv.h"
21#include "src/utils/SkUTF.h"
Ben Wagner1383a382019-04-03 17:53:53 -040022
23#include <limits.h>
24#include <string.h>
25#include <locale>
26#include <string>
27#include <utility>
Florin Malita9867f612018-12-12 10:54:49 -050028
Florin Malita42684332019-07-26 14:54:40 -040029std::unique_ptr<SkShaper> SkShaper::Make(sk_sp<SkFontMgr> fontmgr) {
Ben Wagnerb0591942019-02-15 14:46:18 -050030#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
Florin Malita42684332019-07-26 14:54:40 -040031 std::unique_ptr<SkShaper> shaper = SkShaper::MakeShaperDrivenWrapper(std::move(fontmgr));
Ben Wagnerb0591942019-02-15 14:46:18 -050032 if (shaper) {
33 return shaper;
34 }
35#endif
36 return SkShaper::MakePrimitive();
37}
38
Ben Wagnerdd9449c2021-01-26 19:25:39 -050039void SkShaper::PurgeCaches() {
40#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
41 PurgeHarfBuzzCache();
42#endif
43}
44
Ben Wagner1ca50522019-10-01 17:54:28 -040045std::unique_ptr<SkShaper::BiDiRunIterator>
46SkShaper::MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) {
Julia Lavrova1798f4f2020-08-26 14:22:48 +000047#ifdef SK_UNICODE_AVAILABLE
48 auto unicode = SkUnicode::Make();
Julia Lavrova36700ef2020-08-25 11:42:51 -040049 if (!unicode) {
50 return nullptr;
51 }
Ben Wagner1ca50522019-10-01 17:54:28 -040052 std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
Julia Lavrova1798f4f2020-08-26 14:22:48 +000053 SkShaper::MakeSkUnicodeBidiRunIterator(unicode.get(),
54 utf8,
55 utf8Bytes,
56 bidiLevel);
Ben Wagner1ca50522019-10-01 17:54:28 -040057 if (bidi) {
58 return bidi;
59 }
60#endif
Mike Kleinf46d5ca2019-12-11 10:45:01 -050061 return std::make_unique<SkShaper::TrivialBiDiRunIterator>(bidiLevel, utf8Bytes);
Ben Wagner1ca50522019-10-01 17:54:28 -040062}
63
64std::unique_ptr<SkShaper::ScriptRunIterator>
65SkShaper::MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag scriptTag) {
Julia Lavrova36700ef2020-08-25 11:42:51 -040066#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_UNICODE_AVAILABLE)
67 auto unicode = SkUnicode::Make();
68 if (!unicode) {
69 return nullptr;
70 }
Ben Wagner1ca50522019-10-01 17:54:28 -040071 std::unique_ptr<SkShaper::ScriptRunIterator> script =
Julia Lavrova36700ef2020-08-25 11:42:51 -040072 SkShaper::MakeSkUnicodeHbScriptRunIterator(unicode.get(), utf8, utf8Bytes);
Ben Wagner1ca50522019-10-01 17:54:28 -040073 if (script) {
74 return script;
75 }
76#endif
Mike Kleinf46d5ca2019-12-11 10:45:01 -050077 return std::make_unique<SkShaper::TrivialScriptRunIterator>(scriptTag, utf8Bytes);
Ben Wagner1ca50522019-10-01 17:54:28 -040078}
79
Ben Wagnerb0591942019-02-15 14:46:18 -050080SkShaper::SkShaper() {}
81SkShaper::~SkShaper() {}
82
Ben Wagner1383a382019-04-03 17:53:53 -040083/** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
84static 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
89class FontMgrRunIterator final : public SkShaper::FontRunIterator {
90public:
Ben Wagner1ca50522019-10-01 17:54:28 -040091 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)
Ben Wagner1383a382019-04-03 17:53:53 -040095 : fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes)
96 , fFallbackMgr(std::move(fallbackMgr))
97 , fFont(font)
98 , fFallbackFont(fFont)
99 , fCurrentFont(nullptr)
Ben Wagner1ca50522019-10-01 17:54:28 -0400100 , fRequestName(requestName)
101 , fRequestStyle(requestStyle)
102 , fLanguage(lang)
Ben Wagner1383a382019-04-03 17:53:53 -0400103 {
104 fFont.setTypeface(font.refTypefaceOrDefault());
105 fFallbackFont.setTypeface(nullptr);
106 }
Ben Wagner1ca50522019-10-01 17:54:28 -0400107 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
Ben Wagner1383a382019-04-03 17:53:53 -0400113 void consume() override {
114 SkASSERT(fCurrent < fEnd);
Ben Wagner1ca50522019-10-01 17:54:28 -0400115 SkASSERT(!fLanguage || this->endOfCurrentRun() <= fLanguage->endOfCurrentRun());
Ben Wagner1383a382019-04-03 17:53:53 -0400116 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 {
Ben Wagner1ca50522019-10-01 17:54:28 -0400125 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
126 int languageCount = fLanguage ? 1 : 0;
Ben Wagner1383a382019-04-03 17:53:53 -0400127 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
Ben Wagner1ca50522019-10-01 17:54:28 -0400128 fRequestName, fRequestStyle, &language, languageCount, u));
Ben Wagner1383a382019-04-03 17:53:53 -0400129 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)) {
Ben Wagner1ca50522019-10-01 17:54:28 -0400149 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
150 int languageCount = fLanguage ? 1 : 0;
Ben Wagner1383a382019-04-03 17:53:53 -0400151 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
Ben Wagner1ca50522019-10-01 17:54:28 -0400152 fRequestName, fRequestStyle, &language, languageCount, u));
Ben Wagner1383a382019-04-03 17:53:53 -0400153 if (candidate) {
154 fCurrent = prev;
155 return;
156 }
157 }
158 }
159 }
160 size_t endOfCurrentRun() const override {
161 return fCurrent - fBegin;
162 }
163 bool atEnd() const override {
164 return fCurrent == fEnd;
165 }
166
167 const SkFont& currentFont() const override {
168 return *fCurrentFont;
169 }
170
171private:
172 char const * fCurrent;
173 char const * const fBegin;
174 char const * const fEnd;
Ben Wagner1ca50522019-10-01 17:54:28 -0400175 sk_sp<SkFontMgr> const fFallbackMgr;
Ben Wagner1383a382019-04-03 17:53:53 -0400176 SkFont fFont;
177 SkFont fFallbackFont;
178 SkFont* fCurrentFont;
Ben Wagner1ca50522019-10-01 17:54:28 -0400179 char const * const fRequestName;
180 SkFontStyle const fRequestStyle;
181 SkShaper::LanguageRunIterator const * const fLanguage;
Ben Wagner1383a382019-04-03 17:53:53 -0400182};
183
184std::unique_ptr<SkShaper::FontRunIterator>
185SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes,
186 const SkFont& font, sk_sp<SkFontMgr> fallback)
187{
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500188 return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback));
Ben Wagner1383a382019-04-03 17:53:53 -0400189}
190
Ben Wagner1ca50522019-10-01 17:54:28 -0400191std::unique_ptr<SkShaper::FontRunIterator>
192SkShaper::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{
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500197 return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback),
Ben Wagner1ca50522019-10-01 17:54:28 -0400198 requestName, requestStyle, language);
199}
200
Ben Wagner1383a382019-04-03 17:53:53 -0400201std::unique_ptr<SkShaper::LanguageRunIterator>
202SkShaper::MakeStdLanguageRunIterator(const char* utf8, size_t utf8Bytes) {
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500203 return std::make_unique<TrivialLanguageRunIterator>(std::locale().name().c_str(), utf8Bytes);
Ben Wagner1383a382019-04-03 17:53:53 -0400204}
205
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400206void SkTextBlobBuilderRunHandler::beginLine() {
207 fCurrentPosition = fOffset;
208 fMaxRunAscent = 0;
209 fMaxRunDescent = 0;
210 fMaxRunLeading = 0;
211}
212void SkTextBlobBuilderRunHandler::runInfo(const RunInfo& info) {
213 SkFontMetrics metrics;
214 info.fFont.getMetrics(&metrics);
Brian Osman788b9162020-02-07 10:36:46 -0500215 fMaxRunAscent = std::min(fMaxRunAscent, metrics.fAscent);
216 fMaxRunDescent = std::max(fMaxRunDescent, metrics.fDescent);
217 fMaxRunLeading = std::max(fMaxRunLeading, metrics.fLeading);
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400218}
219
220void SkTextBlobBuilderRunHandler::commitRunInfo() {
221 fCurrentPosition.fY -= fMaxRunAscent;
222}
223
224SkShaper::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
Ben Wagner5d9c20e2021-02-24 11:43:07 -0500228 const auto& runBuffer = fBuilder.allocRunTextPos(info.fFont, glyphCount, utf8RangeSize);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500229 if (runBuffer.utf8text && fUtf8Text) {
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400230 memcpy(runBuffer.utf8text, fUtf8Text + info.utf8Range.begin(), utf8RangeSize);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500231 }
232 fClusters = runBuffer.clusters;
233 fGlyphCount = glyphCount;
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400234 fClusterOffset = info.utf8Range.begin();
Ben Wagner454e5fb2019-02-08 17:46:38 -0500235
Florin Malita9867f612018-12-12 10:54:49 -0500236 return { runBuffer.glyphs,
Mike Reed22451cc2019-01-01 15:40:28 -0500237 runBuffer.points(),
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400238 nullptr,
239 runBuffer.clusters,
240 fCurrentPosition };
Florin Malita9867f612018-12-12 10:54:49 -0500241}
242
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400243void SkTextBlobBuilderRunHandler::commitRunBuffer(const RunInfo& info) {
Ben Wagner18ea3c72019-02-15 16:35:48 -0500244 SkASSERT(0 <= fClusterOffset);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500245 for (int i = 0; i < fGlyphCount; ++i) {
Ben Wagner18ea3c72019-02-15 16:35:48 -0500246 SkASSERT(fClusters[i] >= (unsigned)fClusterOffset);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500247 fClusters[i] -= fClusterOffset;
248 }
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400249 fCurrentPosition += info.fAdvance;
250}
251void SkTextBlobBuilderRunHandler::commitLine() {
252 fOffset += { 0, fMaxRunDescent + fMaxRunLeading - fMaxRunAscent };
Ben Wagner454e5fb2019-02-08 17:46:38 -0500253}
254
Florin Malita950243d2019-01-11 11:08:35 -0500255sk_sp<SkTextBlob> SkTextBlobBuilderRunHandler::makeBlob() {
Florin Malita9867f612018-12-12 10:54:49 -0500256 return fBuilder.make();
257}