xref: /aosp_15_r20/external/skia/modules/skshaper/src/SkShaper.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/SkTypeface.h"
13 #include "include/private/base/SkTFitsIn.h"
14 #include "modules/skshaper/include/SkShaper.h"
15 #include "src/base/SkUTF.h"
16 #include <limits.h>
17 #include <algorithm>
18 #include <cstring>
19 #include <locale>
20 #include <string>
21 #include <utility>
22 
23 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
24 
25 #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
26 #include "modules/skshaper/include/SkShaper_harfbuzz.h"
27 #endif
28 
29 #if defined(SK_SHAPER_CORETEXT_AVAILABLE)
30 #include "modules/skshaper/include/SkShaper_coretext.h"
31 #endif
32 
33 #endif  // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
34 
35 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
Make(sk_sp<SkFontMgr> fallback)36 std::unique_ptr<SkShaper> SkShaper::Make(sk_sp<SkFontMgr> fallback) {
37 #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
38     std::unique_ptr<SkShaper> shaper = MakeShapeThenWrap(std::move(fallback));
39     if (shaper) {
40         return shaper;
41     }
42 #elif defined(SK_SHAPER_CORETEXT_AVAILABLE)
43     if (auto shaper = SkShapers::CT::CoreText()) {
44         return shaper;
45     }
46 #endif
47     return SkShapers::Primitive::PrimitiveText();
48 }
49 
PurgeCaches()50 void SkShaper::PurgeCaches() {
51 #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
52     SkShapers::HB::PurgeCaches();
53 #endif
54 }
55 
56 std::unique_ptr<SkShaper::BiDiRunIterator>
MakeBiDiRunIterator(const char * utf8,size_t utf8Bytes,uint8_t bidiLevel)57 SkShaper::MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) {
58 #if defined(SK_SHAPER_UNICODE_AVAILABLE)
59       std::unique_ptr<SkShaper::BiDiRunIterator> bidi = MakeIcuBiDiRunIterator(utf8, utf8Bytes, bidiLevel);
60       if (bidi) {
61           return bidi;
62       }
63 #endif
64     return std::make_unique<SkShaper::TrivialBiDiRunIterator>(bidiLevel, utf8Bytes);
65 }
66 
67 std::unique_ptr<SkShaper::ScriptRunIterator>
MakeScriptRunIterator(const char * utf8,size_t utf8Bytes,SkFourByteTag scriptTag)68 SkShaper::MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag scriptTag) {
69 #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
70     std::unique_ptr<SkShaper::ScriptRunIterator> script =
71             SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes, scriptTag);
72     if (script) {
73         return script;
74     }
75 #endif
76     return std::make_unique<SkShaper::TrivialScriptRunIterator>(scriptTag, utf8Bytes);
77 }
78 #endif  // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
79 
SkShaper()80 SkShaper::SkShaper() {}
~SkShaper()81 SkShaper::~SkShaper() {}
82 
83 /** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
utf8_next(const char ** ptr,const char * end)84 static 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 
89 class FontMgrRunIterator final : public SkShaper::FontRunIterator {
90 public:
FontMgrRunIterator(const char * utf8,size_t utf8Bytes,const SkFont & font,sk_sp<SkFontMgr> fallbackMgr,const char * requestName,SkFontStyle requestStyle,const SkShaper::LanguageRunIterator * lang)91     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)
95         : fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes)
96         , fFallbackMgr(std::move(fallbackMgr))
97         , fFont(font)
98         , fFallbackFont(fFont)
99         , fCurrentFont(nullptr)
100         , fRequestName(requestName)
101         , fRequestStyle(requestStyle)
102         , fLanguage(lang)
103     {
104         // If fallback is not wanted, clients should use TrivialFontRunIterator.
105         SkASSERT(fFallbackMgr);
106         fFont.setTypeface(font.refTypeface());
107         fFallbackFont.setTypeface(nullptr);
108     }
FontMgrRunIterator(const char * utf8,size_t utf8Bytes,const SkFont & font,sk_sp<SkFontMgr> fallbackMgr)109     FontMgrRunIterator(const char* utf8, size_t utf8Bytes,
110                        const SkFont& font, sk_sp<SkFontMgr> fallbackMgr)
111         : FontMgrRunIterator(utf8, utf8Bytes, font, std::move(fallbackMgr),
112                              nullptr, font.getTypeface()->fontStyle(), nullptr)
113     {}
114 
consume()115     void consume() override {
116         SkASSERT(fCurrent < fEnd);
117         SkASSERT(!fLanguage || this->endOfCurrentRun() <= fLanguage->endOfCurrentRun());
118         SkUnichar u = utf8_next(&fCurrent, fEnd);
119         // If the starting typeface can handle this character, use it.
120         if (fFont.unicharToGlyph(u)) {
121             fCurrentFont = &fFont;
122         // If the current fallback can handle this character, use it.
123         } else if (fFallbackFont.getTypeface() && fFallbackFont.unicharToGlyph(u)) {
124             fCurrentFont = &fFallbackFont;
125         // If not, try to find a fallback typeface
126         } else {
127             const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
128             int languageCount = fLanguage ? 1 : 0;
129             sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
130                 fRequestName, fRequestStyle, &language, languageCount, u));
131             if (candidate) {
132                 fFallbackFont.setTypeface(std::move(candidate));
133                 fCurrentFont = &fFallbackFont;
134             } else {
135                 fCurrentFont = &fFont;
136             }
137         }
138 
139         while (fCurrent < fEnd) {
140             const char* prev = fCurrent;
141             u = utf8_next(&fCurrent, fEnd);
142 
143             // End run if not using initial typeface and initial typeface has this character.
144             if (fCurrentFont->getTypeface() != fFont.getTypeface() && fFont.unicharToGlyph(u)) {
145                 fCurrent = prev;
146                 return;
147             }
148 
149             // End run if current typeface does not have this character and some other font does.
150             if (!fCurrentFont->unicharToGlyph(u)) {
151                 const char* language = fLanguage ? fLanguage->currentLanguage() : nullptr;
152                 int languageCount = fLanguage ? 1 : 0;
153                 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
154                     fRequestName, fRequestStyle, &language, languageCount, u));
155                 if (candidate) {
156                     fCurrent = prev;
157                     return;
158                 }
159             }
160         }
161     }
endOfCurrentRun() const162     size_t endOfCurrentRun() const override {
163         return fCurrent - fBegin;
164     }
atEnd() const165     bool atEnd() const override {
166         return fCurrent == fEnd;
167     }
168 
currentFont() const169     const SkFont& currentFont() const override {
170         return *fCurrentFont;
171     }
172 
173 private:
174     char const * fCurrent;
175     char const * const fBegin;
176     char const * const fEnd;
177     sk_sp<SkFontMgr> const fFallbackMgr;
178     SkFont fFont;
179     SkFont fFallbackFont;
180     SkFont* fCurrentFont;
181     char const * const fRequestName;
182     SkFontStyle const fRequestStyle;
183     SkShaper::LanguageRunIterator const * const fLanguage;
184 };
185 
186 std::unique_ptr<SkShaper::FontRunIterator>
MakeFontMgrRunIterator(const char * utf8,size_t utf8Bytes,const SkFont & font,sk_sp<SkFontMgr> fallback)187 SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes,
188                                  const SkFont& font, sk_sp<SkFontMgr> fallback)
189 {
190     return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback));
191 }
192 
193 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)194 SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes, const SkFont& font,
195                                  sk_sp<SkFontMgr> fallback,
196                                  const char* requestName, SkFontStyle requestStyle,
197                                  const SkShaper::LanguageRunIterator* language)
198 {
199     return std::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback),
200                                                 requestName, requestStyle, language);
201 }
202 
203 std::unique_ptr<SkShaper::LanguageRunIterator>
MakeStdLanguageRunIterator(const char * utf8,size_t utf8Bytes)204 SkShaper::MakeStdLanguageRunIterator(const char* utf8, size_t utf8Bytes) {
205     return std::make_unique<TrivialLanguageRunIterator>(std::locale().name().c_str(), utf8Bytes);
206 }
207 
beginLine()208 void SkTextBlobBuilderRunHandler::beginLine() {
209     fCurrentPosition = fOffset;
210     fMaxRunAscent = 0;
211     fMaxRunDescent = 0;
212     fMaxRunLeading = 0;
213 }
runInfo(const RunInfo & info)214 void SkTextBlobBuilderRunHandler::runInfo(const RunInfo& info) {
215     SkFontMetrics metrics;
216     info.fFont.getMetrics(&metrics);
217     fMaxRunAscent = std::min(fMaxRunAscent, metrics.fAscent);
218     fMaxRunDescent = std::max(fMaxRunDescent, metrics.fDescent);
219     fMaxRunLeading = std::max(fMaxRunLeading, metrics.fLeading);
220 }
221 
commitRunInfo()222 void SkTextBlobBuilderRunHandler::commitRunInfo() {
223     fCurrentPosition.fY -= fMaxRunAscent;
224 }
225 
runBuffer(const RunInfo & info)226 SkShaper::RunHandler::Buffer SkTextBlobBuilderRunHandler::runBuffer(const RunInfo& info) {
227     int glyphCount = SkTFitsIn<int>(info.glyphCount) ? info.glyphCount : INT_MAX;
228     int utf8RangeSize = SkTFitsIn<int>(info.utf8Range.size()) ? info.utf8Range.size() : INT_MAX;
229 
230     const auto& runBuffer = fBuilder.allocRunTextPos(info.fFont, glyphCount, utf8RangeSize);
231     if (runBuffer.utf8text && fUtf8Text) {
232         memcpy(runBuffer.utf8text, fUtf8Text + info.utf8Range.begin(), utf8RangeSize);
233     }
234     fClusters = runBuffer.clusters;
235     fGlyphCount = glyphCount;
236     fClusterOffset = info.utf8Range.begin();
237 
238     return { runBuffer.glyphs,
239              runBuffer.points(),
240              nullptr,
241              runBuffer.clusters,
242              fCurrentPosition };
243 }
244 
commitRunBuffer(const RunInfo & info)245 void SkTextBlobBuilderRunHandler::commitRunBuffer(const RunInfo& info) {
246     SkASSERT(0 <= fClusterOffset);
247     for (int i = 0; i < fGlyphCount; ++i) {
248         SkASSERT(fClusters[i] >= (unsigned)fClusterOffset);
249         fClusters[i] -= fClusterOffset;
250     }
251     fCurrentPosition += info.fAdvance;
252 }
commitLine()253 void SkTextBlobBuilderRunHandler::commitLine() {
254     fOffset += { 0, fMaxRunDescent + fMaxRunLeading - fMaxRunAscent };
255 }
256 
makeBlob()257 sk_sp<SkTextBlob> SkTextBlobBuilderRunHandler::makeBlob() {
258     return fBuilder.make();
259 }
260