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