blob: c47e3ad0d9eb071fd83dd210b61d8d654d162014 [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
18#include "modules/skshaper/src/SkUnicode.h"
19#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 Wagner1ca50522019-10-01 17:54:28 -040039std::unique_ptr<SkShaper::BiDiRunIterator>
40SkShaper::MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) {
Julia Lavrova1798f4f2020-08-26 14:22:48 +000041#ifdef SK_UNICODE_AVAILABLE
42 auto unicode = SkUnicode::Make();
Julia Lavrova36700ef2020-08-25 11:42:51 -040043 if (!unicode) {
44 return nullptr;
45 }
Ben Wagner1ca50522019-10-01 17:54:28 -040046 std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
Julia Lavrova1798f4f2020-08-26 14:22:48 +000047 SkShaper::MakeSkUnicodeBidiRunIterator(unicode.get(),
48 utf8,
49 utf8Bytes,
50 bidiLevel);
Ben Wagner1ca50522019-10-01 17:54:28 -040051 if (bidi) {
52 return bidi;
53 }
54#endif
Mike Kleinf46d5ca2019-12-11 10:45:01 -050055 return std::make_unique<SkShaper::TrivialBiDiRunIterator>(bidiLevel, utf8Bytes);
Ben Wagner1ca50522019-10-01 17:54:28 -040056}
57
58std::unique_ptr<SkShaper::ScriptRunIterator>
59SkShaper::MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag scriptTag) {
Julia Lavrova36700ef2020-08-25 11:42:51 -040060#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_UNICODE_AVAILABLE)
61 auto unicode = SkUnicode::Make();
62 if (!unicode) {
63 return nullptr;
64 }
Ben Wagner1ca50522019-10-01 17:54:28 -040065 std::unique_ptr<SkShaper::ScriptRunIterator> script =
Julia Lavrova36700ef2020-08-25 11:42:51 -040066 SkShaper::MakeSkUnicodeHbScriptRunIterator(unicode.get(), utf8, utf8Bytes);
Ben Wagner1ca50522019-10-01 17:54:28 -040067 if (script) {
68 return script;
69 }
70#endif
Mike Kleinf46d5ca2019-12-11 10:45:01 -050071 return std::make_unique<SkShaper::TrivialScriptRunIterator>(scriptTag, utf8Bytes);
Ben Wagner1ca50522019-10-01 17:54:28 -040072}
73
Ben Wagnerb0591942019-02-15 14:46:18 -050074SkShaper::SkShaper() {}
75SkShaper::~SkShaper() {}
76
Ben Wagner1383a382019-04-03 17:53:53 -040077/** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
78static inline SkUnichar utf8_next(const char** ptr, const char* end) {
79 SkUnichar val = SkUTF::NextUTF8(ptr, end);
80 return val < 0 ? 0xFFFD : val;
81}
82
83class FontMgrRunIterator final : public SkShaper::FontRunIterator {
84public:
Ben Wagner1ca50522019-10-01 17:54:28 -040085 FontMgrRunIterator(const char* utf8, size_t utf8Bytes,
86 const SkFont& font, sk_sp<SkFontMgr> fallbackMgr,
87 const char* requestName, SkFontStyle requestStyle,
88 const SkShaper::LanguageRunIterator* lang)
Ben Wagner1383a382019-04-03 17:53:53 -040089 : fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes)
90 , fFallbackMgr(std::move(fallbackMgr))
91 , fFont(font)
92 , fFallbackFont(fFont)
93 , fCurrentFont(nullptr)
Ben Wagner1ca50522019-10-01 17:54:28 -040094 , fRequestName(requestName)
95 , fRequestStyle(requestStyle)
96 , fLanguage(lang)
Ben Wagner1383a382019-04-03 17:53:53 -040097 {
98 fFont.setTypeface(font.refTypefaceOrDefault());
99 fFallbackFont.setTypeface(nullptr);
100 }
Ben Wagner1ca50522019-10-01 17:54:28 -0400101 FontMgrRunIterator(const char* utf8, size_t utf8Bytes,
102 const SkFont& font, sk_sp<SkFontMgr> fallbackMgr)
103 : FontMgrRunIterator(utf8, utf8Bytes, font, std::move(fallbackMgr),
104 nullptr, font.refTypefaceOrDefault()->fontStyle(), nullptr)
105 {}
106
Ben Wagner1383a382019-04-03 17:53:53 -0400107 void consume() override {
108 SkASSERT(fCurrent < fEnd);
Ben Wagner1ca50522019-10-01 17:54:28 -0400109 SkASSERT(!fLanguage || this->endOfCurrentRun() <= fLanguage->endOfCurrentRun());
Ben Wagner1383a382019-04-03 17:53:53 -0400110 SkUnichar u = utf8_next(&fCurrent, fEnd);
111 // If the starting typeface can handle this character, use it.
112 if (fFont.unicharToGlyph(u)) {
113 fCurrentFont = &fFont;
114 // If the current fallback can handle this character, use it.
115 } else if (fFallbackFont.getTypeface() && fFallbackFont.unicharToGlyph(u)) {
116 fCurrentFont = &fFallbackFont;
117 // If not, try to find a fallback typeface
118 } else {
Ben Wagner1ca50522019-10-01 17:54:28 -0400119 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
120 int languageCount = fLanguage ? 1 : 0;
Ben Wagner1383a382019-04-03 17:53:53 -0400121 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
Ben Wagner1ca50522019-10-01 17:54:28 -0400122 fRequestName, fRequestStyle, &language, languageCount, u));
Ben Wagner1383a382019-04-03 17:53:53 -0400123 if (candidate) {
124 fFallbackFont.setTypeface(std::move(candidate));
125 fCurrentFont = &fFallbackFont;
126 } else {
127 fCurrentFont = &fFont;
128 }
129 }
130
131 while (fCurrent < fEnd) {
132 const char* prev = fCurrent;
133 u = utf8_next(&fCurrent, fEnd);
134
135 // End run if not using initial typeface and initial typeface has this character.
136 if (fCurrentFont->getTypeface() != fFont.getTypeface() && fFont.unicharToGlyph(u)) {
137 fCurrent = prev;
138 return;
139 }
140
141 // End run if current typeface does not have this character and some other font does.
142 if (!fCurrentFont->unicharToGlyph(u)) {
Ben Wagner1ca50522019-10-01 17:54:28 -0400143 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
144 int languageCount = fLanguage ? 1 : 0;
Ben Wagner1383a382019-04-03 17:53:53 -0400145 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
Ben Wagner1ca50522019-10-01 17:54:28 -0400146 fRequestName, fRequestStyle, &language, languageCount, u));
Ben Wagner1383a382019-04-03 17:53:53 -0400147 if (candidate) {
148 fCurrent = prev;
149 return;
150 }
151 }
152 }
153 }
154 size_t endOfCurrentRun() const override {
155 return fCurrent - fBegin;
156 }
157 bool atEnd() const override {
158 return fCurrent == fEnd;
159 }
160
161 const SkFont& currentFont() const override {
162 return *fCurrentFont;
163 }
164
165private:
166 char const * fCurrent;
167 char const * const fBegin;
168 char const * const fEnd;
Ben Wagner1ca50522019-10-01 17:54:28 -0400169 sk_sp<SkFontMgr> const fFallbackMgr;
Ben Wagner1383a382019-04-03 17:53:53 -0400170 SkFont fFont;
171 SkFont fFallbackFont;
172 SkFont* fCurrentFont;
Ben Wagner1ca50522019-10-01 17:54:28 -0400173 char const * const fRequestName;
174 SkFontStyle const fRequestStyle;
175 SkShaper::LanguageRunIterator const * const fLanguage;
Ben Wagner1383a382019-04-03 17:53:53 -0400176};
177
178std::unique_ptr<SkShaper::FontRunIterator>
179SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes,
180 const SkFont& font, sk_sp<SkFontMgr> fallback)
181{
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500182 return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback));
Ben Wagner1383a382019-04-03 17:53:53 -0400183}
184
Ben Wagner1ca50522019-10-01 17:54:28 -0400185std::unique_ptr<SkShaper::FontRunIterator>
186SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes, const SkFont& font,
187 sk_sp<SkFontMgr> fallback,
188 const char* requestName, SkFontStyle requestStyle,
189 const SkShaper::LanguageRunIterator* language)
190{
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500191 return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback),
Ben Wagner1ca50522019-10-01 17:54:28 -0400192 requestName, requestStyle, language);
193}
194
Ben Wagner1383a382019-04-03 17:53:53 -0400195std::unique_ptr<SkShaper::LanguageRunIterator>
196SkShaper::MakeStdLanguageRunIterator(const char* utf8, size_t utf8Bytes) {
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500197 return std::make_unique<TrivialLanguageRunIterator>(std::locale().name().c_str(), utf8Bytes);
Ben Wagner1383a382019-04-03 17:53:53 -0400198}
199
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400200void SkTextBlobBuilderRunHandler::beginLine() {
201 fCurrentPosition = fOffset;
202 fMaxRunAscent = 0;
203 fMaxRunDescent = 0;
204 fMaxRunLeading = 0;
205}
206void SkTextBlobBuilderRunHandler::runInfo(const RunInfo& info) {
207 SkFontMetrics metrics;
208 info.fFont.getMetrics(&metrics);
Brian Osman788b9162020-02-07 10:36:46 -0500209 fMaxRunAscent = std::min(fMaxRunAscent, metrics.fAscent);
210 fMaxRunDescent = std::max(fMaxRunDescent, metrics.fDescent);
211 fMaxRunLeading = std::max(fMaxRunLeading, metrics.fLeading);
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400212}
213
214void SkTextBlobBuilderRunHandler::commitRunInfo() {
215 fCurrentPosition.fY -= fMaxRunAscent;
216}
217
218SkShaper::RunHandler::Buffer SkTextBlobBuilderRunHandler::runBuffer(const RunInfo& info) {
219 int glyphCount = SkTFitsIn<int>(info.glyphCount) ? info.glyphCount : INT_MAX;
220 int utf8RangeSize = SkTFitsIn<int>(info.utf8Range.size()) ? info.utf8Range.size() : INT_MAX;
221
222 const auto& runBuffer = SkTextBlobBuilderPriv::AllocRunTextPos(&fBuilder, info.fFont, glyphCount,
223 utf8RangeSize, SkString());
Ben Wagner454e5fb2019-02-08 17:46:38 -0500224 if (runBuffer.utf8text && fUtf8Text) {
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400225 memcpy(runBuffer.utf8text, fUtf8Text + info.utf8Range.begin(), utf8RangeSize);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500226 }
227 fClusters = runBuffer.clusters;
228 fGlyphCount = glyphCount;
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400229 fClusterOffset = info.utf8Range.begin();
Ben Wagner454e5fb2019-02-08 17:46:38 -0500230
Florin Malita9867f612018-12-12 10:54:49 -0500231 return { runBuffer.glyphs,
Mike Reed22451cc2019-01-01 15:40:28 -0500232 runBuffer.points(),
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400233 nullptr,
234 runBuffer.clusters,
235 fCurrentPosition };
Florin Malita9867f612018-12-12 10:54:49 -0500236}
237
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400238void SkTextBlobBuilderRunHandler::commitRunBuffer(const RunInfo& info) {
Ben Wagner18ea3c72019-02-15 16:35:48 -0500239 SkASSERT(0 <= fClusterOffset);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500240 for (int i = 0; i < fGlyphCount; ++i) {
Ben Wagner18ea3c72019-02-15 16:35:48 -0500241 SkASSERT(fClusters[i] >= (unsigned)fClusterOffset);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500242 fClusters[i] -= fClusterOffset;
243 }
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400244 fCurrentPosition += info.fAdvance;
245}
246void SkTextBlobBuilderRunHandler::commitLine() {
247 fOffset += { 0, fMaxRunDescent + fMaxRunLeading - fMaxRunAscent };
Ben Wagner454e5fb2019-02-08 17:46:38 -0500248}
249
Florin Malita950243d2019-01-11 11:08:35 -0500250sk_sp<SkTextBlob> SkTextBlobBuilderRunHandler::makeBlob() {
Florin Malita9867f612018-12-12 10:54:49 -0500251 return fBuilder.make();
252}