blob: 8e93fec101049ce37d018f8e1d562a59e5c0968b [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"
16#include "src/core/SkMakeUnique.h"
17#include "src/core/SkTextBlobPriv.h"
18#include "src/utils/SkUTF.h"
Ben Wagner1383a382019-04-03 17:53:53 -040019
20#include <limits.h>
21#include <string.h>
22#include <locale>
23#include <string>
24#include <utility>
Florin Malita9867f612018-12-12 10:54:49 -050025
Florin Malita42684332019-07-26 14:54:40 -040026std::unique_ptr<SkShaper> SkShaper::Make(sk_sp<SkFontMgr> fontmgr) {
Ben Wagnerb0591942019-02-15 14:46:18 -050027#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
Florin Malita42684332019-07-26 14:54:40 -040028 std::unique_ptr<SkShaper> shaper = SkShaper::MakeShaperDrivenWrapper(std::move(fontmgr));
Ben Wagnerb0591942019-02-15 14:46:18 -050029 if (shaper) {
30 return shaper;
31 }
32#endif
33 return SkShaper::MakePrimitive();
34}
35
Ben Wagner1ca50522019-10-01 17:54:28 -040036std::unique_ptr<SkShaper::BiDiRunIterator>
37SkShaper::MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) {
38#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
39 std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
40 SkShaper::MakeIcuBiDiRunIterator(utf8, utf8Bytes, bidiLevel);
41 if (bidi) {
42 return bidi;
43 }
44#endif
45 return skstd::make_unique<SkShaper::TrivialBiDiRunIterator>(bidiLevel, utf8Bytes);
46}
47
48std::unique_ptr<SkShaper::ScriptRunIterator>
49SkShaper::MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag scriptTag) {
50#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
51 std::unique_ptr<SkShaper::ScriptRunIterator> script =
52 SkShaper::MakeHbIcuScriptRunIterator(utf8, utf8Bytes);
53 if (script) {
54 return script;
55 }
56#endif
57 return skstd::make_unique<SkShaper::TrivialScriptRunIterator>(scriptTag, utf8Bytes);
58}
59
Ben Wagnerb0591942019-02-15 14:46:18 -050060SkShaper::SkShaper() {}
61SkShaper::~SkShaper() {}
62
Ben Wagner1383a382019-04-03 17:53:53 -040063/** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
64static inline SkUnichar utf8_next(const char** ptr, const char* end) {
65 SkUnichar val = SkUTF::NextUTF8(ptr, end);
66 return val < 0 ? 0xFFFD : val;
67}
68
69class FontMgrRunIterator final : public SkShaper::FontRunIterator {
70public:
Ben Wagner1ca50522019-10-01 17:54:28 -040071 FontMgrRunIterator(const char* utf8, size_t utf8Bytes,
72 const SkFont& font, sk_sp<SkFontMgr> fallbackMgr,
73 const char* requestName, SkFontStyle requestStyle,
74 const SkShaper::LanguageRunIterator* lang)
Ben Wagner1383a382019-04-03 17:53:53 -040075 : fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes)
76 , fFallbackMgr(std::move(fallbackMgr))
77 , fFont(font)
78 , fFallbackFont(fFont)
79 , fCurrentFont(nullptr)
Ben Wagner1ca50522019-10-01 17:54:28 -040080 , fRequestName(requestName)
81 , fRequestStyle(requestStyle)
82 , fLanguage(lang)
Ben Wagner1383a382019-04-03 17:53:53 -040083 {
84 fFont.setTypeface(font.refTypefaceOrDefault());
85 fFallbackFont.setTypeface(nullptr);
86 }
Ben Wagner1ca50522019-10-01 17:54:28 -040087 FontMgrRunIterator(const char* utf8, size_t utf8Bytes,
88 const SkFont& font, sk_sp<SkFontMgr> fallbackMgr)
89 : FontMgrRunIterator(utf8, utf8Bytes, font, std::move(fallbackMgr),
90 nullptr, font.refTypefaceOrDefault()->fontStyle(), nullptr)
91 {}
92
Ben Wagner1383a382019-04-03 17:53:53 -040093 void consume() override {
94 SkASSERT(fCurrent < fEnd);
Ben Wagner1ca50522019-10-01 17:54:28 -040095 SkASSERT(!fLanguage || this->endOfCurrentRun() <= fLanguage->endOfCurrentRun());
Ben Wagner1383a382019-04-03 17:53:53 -040096 SkUnichar u = utf8_next(&fCurrent, fEnd);
97 // If the starting typeface can handle this character, use it.
98 if (fFont.unicharToGlyph(u)) {
99 fCurrentFont = &fFont;
100 // If the current fallback can handle this character, use it.
101 } else if (fFallbackFont.getTypeface() && fFallbackFont.unicharToGlyph(u)) {
102 fCurrentFont = &fFallbackFont;
103 // If not, try to find a fallback typeface
104 } else {
Ben Wagner1ca50522019-10-01 17:54:28 -0400105 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
106 int languageCount = fLanguage ? 1 : 0;
Ben Wagner1383a382019-04-03 17:53:53 -0400107 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
Ben Wagner1ca50522019-10-01 17:54:28 -0400108 fRequestName, fRequestStyle, &language, languageCount, u));
Ben Wagner1383a382019-04-03 17:53:53 -0400109 if (candidate) {
110 fFallbackFont.setTypeface(std::move(candidate));
111 fCurrentFont = &fFallbackFont;
112 } else {
113 fCurrentFont = &fFont;
114 }
115 }
116
117 while (fCurrent < fEnd) {
118 const char* prev = fCurrent;
119 u = utf8_next(&fCurrent, fEnd);
120
121 // End run if not using initial typeface and initial typeface has this character.
122 if (fCurrentFont->getTypeface() != fFont.getTypeface() && fFont.unicharToGlyph(u)) {
123 fCurrent = prev;
124 return;
125 }
126
127 // End run if current typeface does not have this character and some other font does.
128 if (!fCurrentFont->unicharToGlyph(u)) {
Ben Wagner1ca50522019-10-01 17:54:28 -0400129 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
130 int languageCount = fLanguage ? 1 : 0;
Ben Wagner1383a382019-04-03 17:53:53 -0400131 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
Ben Wagner1ca50522019-10-01 17:54:28 -0400132 fRequestName, fRequestStyle, &language, languageCount, u));
Ben Wagner1383a382019-04-03 17:53:53 -0400133 if (candidate) {
134 fCurrent = prev;
135 return;
136 }
137 }
138 }
139 }
140 size_t endOfCurrentRun() const override {
141 return fCurrent - fBegin;
142 }
143 bool atEnd() const override {
144 return fCurrent == fEnd;
145 }
146
147 const SkFont& currentFont() const override {
148 return *fCurrentFont;
149 }
150
151private:
152 char const * fCurrent;
153 char const * const fBegin;
154 char const * const fEnd;
Ben Wagner1ca50522019-10-01 17:54:28 -0400155 sk_sp<SkFontMgr> const fFallbackMgr;
Ben Wagner1383a382019-04-03 17:53:53 -0400156 SkFont fFont;
157 SkFont fFallbackFont;
158 SkFont* fCurrentFont;
Ben Wagner1ca50522019-10-01 17:54:28 -0400159 char const * const fRequestName;
160 SkFontStyle const fRequestStyle;
161 SkShaper::LanguageRunIterator const * const fLanguage;
Ben Wagner1383a382019-04-03 17:53:53 -0400162};
163
164std::unique_ptr<SkShaper::FontRunIterator>
165SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes,
166 const SkFont& font, sk_sp<SkFontMgr> fallback)
167{
168 return skstd::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback));
169}
170
Ben Wagner1ca50522019-10-01 17:54:28 -0400171std::unique_ptr<SkShaper::FontRunIterator>
172SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes, const SkFont& font,
173 sk_sp<SkFontMgr> fallback,
174 const char* requestName, SkFontStyle requestStyle,
175 const SkShaper::LanguageRunIterator* language)
176{
177 return skstd::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback),
178 requestName, requestStyle, language);
179}
180
Ben Wagner1383a382019-04-03 17:53:53 -0400181std::unique_ptr<SkShaper::LanguageRunIterator>
182SkShaper::MakeStdLanguageRunIterator(const char* utf8, size_t utf8Bytes) {
Mike Reedc7221652019-05-30 14:09:33 -0400183 return skstd::make_unique<TrivialLanguageRunIterator>(std::locale().name().c_str(), utf8Bytes);
Ben Wagner1383a382019-04-03 17:53:53 -0400184}
185
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400186void SkTextBlobBuilderRunHandler::beginLine() {
187 fCurrentPosition = fOffset;
188 fMaxRunAscent = 0;
189 fMaxRunDescent = 0;
190 fMaxRunLeading = 0;
191}
192void SkTextBlobBuilderRunHandler::runInfo(const RunInfo& info) {
193 SkFontMetrics metrics;
194 info.fFont.getMetrics(&metrics);
195 fMaxRunAscent = SkTMin(fMaxRunAscent, metrics.fAscent);
196 fMaxRunDescent = SkTMax(fMaxRunDescent, metrics.fDescent);
197 fMaxRunLeading = SkTMax(fMaxRunLeading, metrics.fLeading);
198}
199
200void SkTextBlobBuilderRunHandler::commitRunInfo() {
201 fCurrentPosition.fY -= fMaxRunAscent;
202}
203
204SkShaper::RunHandler::Buffer SkTextBlobBuilderRunHandler::runBuffer(const RunInfo& info) {
205 int glyphCount = SkTFitsIn<int>(info.glyphCount) ? info.glyphCount : INT_MAX;
206 int utf8RangeSize = SkTFitsIn<int>(info.utf8Range.size()) ? info.utf8Range.size() : INT_MAX;
207
208 const auto& runBuffer = SkTextBlobBuilderPriv::AllocRunTextPos(&fBuilder, info.fFont, glyphCount,
209 utf8RangeSize, SkString());
Ben Wagner454e5fb2019-02-08 17:46:38 -0500210 if (runBuffer.utf8text && fUtf8Text) {
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400211 memcpy(runBuffer.utf8text, fUtf8Text + info.utf8Range.begin(), utf8RangeSize);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500212 }
213 fClusters = runBuffer.clusters;
214 fGlyphCount = glyphCount;
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400215 fClusterOffset = info.utf8Range.begin();
Ben Wagner454e5fb2019-02-08 17:46:38 -0500216
Florin Malita9867f612018-12-12 10:54:49 -0500217 return { runBuffer.glyphs,
Mike Reed22451cc2019-01-01 15:40:28 -0500218 runBuffer.points(),
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400219 nullptr,
220 runBuffer.clusters,
221 fCurrentPosition };
Florin Malita9867f612018-12-12 10:54:49 -0500222}
223
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400224void SkTextBlobBuilderRunHandler::commitRunBuffer(const RunInfo& info) {
Ben Wagner18ea3c72019-02-15 16:35:48 -0500225 SkASSERT(0 <= fClusterOffset);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500226 for (int i = 0; i < fGlyphCount; ++i) {
Ben Wagner18ea3c72019-02-15 16:35:48 -0500227 SkASSERT(fClusters[i] >= (unsigned)fClusterOffset);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500228 fClusters[i] -= fClusterOffset;
229 }
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400230 fCurrentPosition += info.fAdvance;
231}
232void SkTextBlobBuilderRunHandler::commitLine() {
233 fOffset += { 0, fMaxRunDescent + fMaxRunLeading - fMaxRunAscent };
Ben Wagner454e5fb2019-02-08 17:46:38 -0500234}
235
Florin Malita950243d2019-01-11 11:08:35 -0500236sk_sp<SkTextBlob> SkTextBlobBuilderRunHandler::makeBlob() {
Florin Malita9867f612018-12-12 10:54:49 -0500237 return fBuilder.make();
238}