xref: /aosp_15_r20/external/skia/src/core/SkFontMgr.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2015 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/SkFontMgr.h"
9 
10 #include "include/core/SkData.h"
11 #include "include/core/SkFontStyle.h"
12 #include "include/core/SkStream.h"
13 #include "include/core/SkTypeface.h"
14 #include "include/core/SkTypes.h"
15 
16 #include <utility>
17 
18 struct SkFontArguments;
19 
20 class SkEmptyFontStyleSet : public SkFontStyleSet {
21 public:
count()22     int count() override { return 0; }
getStyle(int,SkFontStyle *,SkString *)23     void getStyle(int, SkFontStyle*, SkString*) override {
24         SkDEBUGFAIL("SkFontStyleSet::getStyle called on empty set");
25     }
createTypeface(int index)26     sk_sp<SkTypeface> createTypeface(int index) override {
27         SkDEBUGFAIL("SkFontStyleSet::createTypeface called on empty set");
28         return nullptr;
29     }
matchStyle(const SkFontStyle &)30     sk_sp<SkTypeface> matchStyle(const SkFontStyle&) override {
31         return nullptr;
32     }
33 };
34 
CreateEmpty()35 sk_sp<SkFontStyleSet> SkFontStyleSet::CreateEmpty() {
36     return sk_sp<SkFontStyleSet>(new SkEmptyFontStyleSet);
37 }
38 
39 ///////////////////////////////////////////////////////////////////////////////
40 
41 class SkEmptyFontMgr : public SkFontMgr {
42 protected:
onCountFamilies() const43     int onCountFamilies() const override {
44         return 0;
45     }
onGetFamilyName(int index,SkString * familyName) const46     void onGetFamilyName(int index, SkString* familyName) const override {
47         SkDEBUGFAIL("onGetFamilyName called with bad index");
48     }
onCreateStyleSet(int index) const49     sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
50         SkDEBUGFAIL("onCreateStyleSet called with bad index");
51         return nullptr;
52     }
onMatchFamily(const char[]) const53     sk_sp<SkFontStyleSet> onMatchFamily(const char[]) const override {
54         return SkFontStyleSet::CreateEmpty();
55     }
56 
onMatchFamilyStyle(const char[],const SkFontStyle &) const57     sk_sp<SkTypeface> onMatchFamilyStyle(const char[], const SkFontStyle&) const override {
58         return nullptr;
59     }
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const60     sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[],
61                                                   const SkFontStyle& style,
62                                                   const char* bcp47[],
63                                                   int bcp47Count,
64                                                   SkUnichar character) const override {
65         return nullptr;
66     }
67 
onMakeFromData(sk_sp<SkData>,int) const68     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int) const override {
69         return nullptr;
70     }
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,int) const71     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>, int) const override {
72         return nullptr;
73     }
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,const SkFontArguments &) const74     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
75                                            const SkFontArguments&) const override {
76         return nullptr;
77     }
onMakeFromFile(const char[],int) const78     sk_sp<SkTypeface> onMakeFromFile(const char[], int) const override {
79         return nullptr;
80     }
onLegacyMakeTypeface(const char[],SkFontStyle) const81     sk_sp<SkTypeface> onLegacyMakeTypeface(const char [], SkFontStyle) const override {
82         return nullptr;
83     }
84 };
85 
emptyOnNull(sk_sp<SkFontStyleSet> && fsset)86 static sk_sp<SkFontStyleSet> emptyOnNull(sk_sp<SkFontStyleSet>&& fsset) {
87     if (!fsset) {
88         fsset = SkFontStyleSet::CreateEmpty();
89     }
90     return std::move(fsset);
91 }
92 
countFamilies() const93 int SkFontMgr::countFamilies() const {
94     return this->onCountFamilies();
95 }
96 
getFamilyName(int index,SkString * familyName) const97 void SkFontMgr::getFamilyName(int index, SkString* familyName) const {
98     this->onGetFamilyName(index, familyName);
99 }
100 
createStyleSet(int index) const101 sk_sp<SkFontStyleSet> SkFontMgr::createStyleSet(int index) const {
102     return emptyOnNull(this->onCreateStyleSet(index));
103 }
104 
matchFamily(const char familyName[]) const105 sk_sp<SkFontStyleSet> SkFontMgr::matchFamily(const char familyName[]) const {
106     return emptyOnNull(this->onMatchFamily(familyName));
107 }
108 
matchFamilyStyle(const char familyName[],const SkFontStyle & fs) const109 sk_sp<SkTypeface> SkFontMgr::matchFamilyStyle(const char familyName[],
110                                         const SkFontStyle& fs) const {
111     return this->onMatchFamilyStyle(familyName, fs);
112 }
113 
matchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const114 sk_sp<SkTypeface> SkFontMgr::matchFamilyStyleCharacter(const char familyName[], const SkFontStyle& style,
115                                                  const char* bcp47[], int bcp47Count,
116                                                  SkUnichar character) const {
117     return this->onMatchFamilyStyleCharacter(familyName, style, bcp47, bcp47Count, character);
118 }
119 
makeFromData(sk_sp<SkData> data,int ttcIndex) const120 sk_sp<SkTypeface> SkFontMgr::makeFromData(sk_sp<SkData> data, int ttcIndex) const {
121     if (nullptr == data) {
122         return nullptr;
123     }
124     return this->onMakeFromData(std::move(data), ttcIndex);
125 }
126 
makeFromStream(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const127 sk_sp<SkTypeface> SkFontMgr::makeFromStream(std::unique_ptr<SkStreamAsset> stream,
128                                             int ttcIndex) const {
129     if (nullptr == stream) {
130         return nullptr;
131     }
132     return this->onMakeFromStreamIndex(std::move(stream), ttcIndex);
133 }
134 
makeFromStream(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const135 sk_sp<SkTypeface> SkFontMgr::makeFromStream(std::unique_ptr<SkStreamAsset> stream,
136                                             const SkFontArguments& args) const {
137     if (nullptr == stream) {
138         return nullptr;
139     }
140     return this->onMakeFromStreamArgs(std::move(stream), args);
141 }
142 
makeFromFile(const char path[],int ttcIndex) const143 sk_sp<SkTypeface> SkFontMgr::makeFromFile(const char path[], int ttcIndex) const {
144     if (nullptr == path) {
145         return nullptr;
146     }
147     return this->onMakeFromFile(path, ttcIndex);
148 }
149 
legacyMakeTypeface(const char familyName[],SkFontStyle style) const150 sk_sp<SkTypeface> SkFontMgr::legacyMakeTypeface(const char familyName[], SkFontStyle style) const {
151     return this->onLegacyMakeTypeface(familyName, style);
152 }
153 
RefEmpty()154 sk_sp<SkFontMgr> SkFontMgr::RefEmpty() {
155     static sk_sp<SkFontMgr> singleton(new SkEmptyFontMgr);
156     return singleton;
157 }
158 
159 /**
160 * Width has the greatest priority.
161 * If the value of pattern.width is 5 (normal) or less,
162 *    narrower width values are checked first, then wider values.
163 * If the value of pattern.width is greater than 5 (normal),
164 *    wider values are checked first, followed by narrower values.
165 *
166 * Italic/Oblique has the next highest priority.
167 * If italic requested and there is some italic font, use it.
168 * If oblique requested and there is some oblique font, use it.
169 * If italic requested and there is some oblique font, use it.
170 * If oblique requested and there is some italic font, use it.
171 *
172 * Exact match.
173 * If pattern.weight < 400, weights below pattern.weight are checked
174 *   in descending order followed by weights above pattern.weight
175 *   in ascending order until a match is found.
176 * If pattern.weight > 500, weights above pattern.weight are checked
177 *   in ascending order followed by weights below pattern.weight
178 *   in descending order until a match is found.
179 * If pattern.weight is 400, 500 is checked first
180 *   and then the rule for pattern.weight < 400 is used.
181 * If pattern.weight is 500, 400 is checked first
182 *   and then the rule for pattern.weight < 400 is used.
183 */
matchStyleCSS3(const SkFontStyle & pattern)184 sk_sp<SkTypeface> SkFontStyleSet::matchStyleCSS3(const SkFontStyle& pattern) {
185     int count = this->count();
186     if (0 == count) {
187         return nullptr;
188     }
189 
190     struct Score {
191         int score;
192         int index;
193         Score& operator +=(int rhs) { this->score += rhs; return *this; }
194         Score& operator <<=(int rhs) { this->score <<= rhs; return *this; }
195         bool operator <(const Score& that) { return this->score < that.score; }
196     };
197 
198     Score maxScore = { 0, 0 };
199     for (int i = 0; i < count; ++i) {
200         SkFontStyle current;
201         this->getStyle(i, &current, nullptr);
202         Score currentScore = { 0, i };
203 
204         // CSS stretch / SkFontStyle::Width
205         // Takes priority over everything else.
206         if (pattern.width() <= SkFontStyle::kNormal_Width) {
207             if (current.width() <= pattern.width()) {
208                 currentScore += 10 - pattern.width() + current.width();
209             } else {
210                 currentScore += 10 - current.width();
211             }
212         } else {
213             if (current.width() > pattern.width()) {
214                 currentScore += 10 + pattern.width() - current.width();
215             } else {
216                 currentScore += current.width();
217             }
218         }
219         currentScore <<= 8;
220 
221         // CSS style (normal, italic, oblique) / SkFontStyle::Slant (upright, italic, oblique)
222         // Takes priority over all valid weights.
223         static_assert(SkFontStyle::kUpright_Slant == 0 &&
224                       SkFontStyle::kItalic_Slant  == 1 &&
225                       SkFontStyle::kOblique_Slant == 2,
226                       "SkFontStyle::Slant values not as required.");
227         SkASSERT(0 <= pattern.slant() && pattern.slant() <= 2 &&
228                  0 <= current.slant() && current.slant() <= 2);
229         static const int score[3][3] = {
230             /*               Upright Italic Oblique  [current]*/
231             /*   Upright */ {   3   ,  1   ,   2   },
232             /*   Italic  */ {   1   ,  3   ,   2   },
233             /*   Oblique */ {   1   ,  2   ,   3   },
234             /* [pattern] */
235         };
236         currentScore += score[pattern.slant()][current.slant()];
237         currentScore <<= 8;
238 
239         // Synthetics (weight, style) [no stretch synthetic?]
240 
241         // CSS weight / SkFontStyle::Weight
242         // The 'closer' to the target weight, the higher the score.
243         // 1000 is the 'heaviest' recognized weight
244         if (pattern.weight() == current.weight()) {
245             currentScore += 1000;
246         // less than 400 prefer lighter weights
247         } else if (pattern.weight() < 400) {
248             if (current.weight() <= pattern.weight()) {
249                 currentScore += 1000 - pattern.weight() + current.weight();
250             } else {
251                 currentScore += 1000 - current.weight();
252             }
253         // between 400 and 500 prefer heavier up to 500, then lighter weights
254         } else if (pattern.weight() <= 500) {
255             if (current.weight() >= pattern.weight() && current.weight() <= 500) {
256                 currentScore += 1000 + pattern.weight() - current.weight();
257             } else if (current.weight() <= pattern.weight()) {
258                 currentScore += 500 + current.weight();
259             } else {
260                 currentScore += 1000 - current.weight();
261             }
262         // greater than 500 prefer heavier weights
263         } else if (pattern.weight() > 500) {
264             if (current.weight() > pattern.weight()) {
265                 currentScore += 1000 + pattern.weight() - current.weight();
266             } else {
267                 currentScore += current.weight();
268             }
269         }
270 
271         if (maxScore < currentScore) {
272             maxScore = currentScore;
273         }
274     }
275 
276     return this->createTypeface(maxScore.index);
277 }
278