xref: /aosp_15_r20/frameworks/base/libs/hwui/hwui/Typeface.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "Typeface.h"
18 
19 #include <fcntl.h>  // For tests.
20 #include <pthread.h>
21 #ifndef _WIN32
22 #include <sys/mman.h>  // For tests.
23 #endif
24 #include <sys/stat.h>  // For tests.
25 
26 #include "MinikinSkia.h"
27 #include "SkPaint.h"
28 #include "SkStream.h"  // For tests.
29 #include "SkTypeface.h"
30 #include "utils/TypefaceUtils.h"
31 
32 #include <minikin/FontCollection.h>
33 #include <minikin/FontFamily.h>
34 #include <minikin/Layout.h>
35 #include <utils/Log.h>
36 #include <utils/MathUtils.h>
37 
38 namespace android {
39 
computeAPIStyle(int weight,bool italic)40 static Typeface::Style computeAPIStyle(int weight, bool italic) {
41     // This bold detection comes from SkTypeface.h
42     if (weight >= SkFontStyle::kSemiBold_Weight) {
43         return italic ? Typeface::kBoldItalic : Typeface::kBold;
44     } else {
45         return italic ? Typeface::kItalic : Typeface::kNormal;
46     }
47 }
48 
computeMinikinStyle(int weight,bool italic)49 static minikin::FontStyle computeMinikinStyle(int weight, bool italic) {
50     return minikin::FontStyle(uirenderer::MathUtils::clamp(weight, 1, 1000),
51                               static_cast<minikin::FontStyle::Slant>(italic));
52 }
53 
54 // Resolve the relative weight from the baseWeight and target style.
computeRelativeStyle(int baseWeight,Typeface::Style relativeStyle)55 static minikin::FontStyle computeRelativeStyle(int baseWeight, Typeface::Style relativeStyle) {
56     int weight = baseWeight;
57     if ((relativeStyle & Typeface::kBold) != 0) {
58         weight += 300;
59     }
60     bool italic = (relativeStyle & Typeface::kItalic) != 0;
61     return computeMinikinStyle(weight, italic);
62 }
63 
64 const Typeface* gDefaultTypeface = NULL;
65 
resolveDefault(const Typeface * src)66 const Typeface* Typeface::resolveDefault(const Typeface* src) {
67     LOG_ALWAYS_FATAL_IF(src == nullptr && gDefaultTypeface == nullptr);
68     return src == nullptr ? gDefaultTypeface : src;
69 }
70 
createRelative(Typeface * src,Typeface::Style style)71 Typeface* Typeface::createRelative(Typeface* src, Typeface::Style style) {
72     const Typeface* resolvedFace = Typeface::resolveDefault(src);
73     Typeface* result = new Typeface;
74     if (result != nullptr) {
75         result->fFontCollection = resolvedFace->fFontCollection;
76         result->fBaseWeight = resolvedFace->fBaseWeight;
77         result->fAPIStyle = style;
78         result->fStyle = computeRelativeStyle(result->fBaseWeight, style);
79         result->fIsVariationInstance = resolvedFace->fIsVariationInstance;
80     }
81     return result;
82 }
83 
createAbsolute(Typeface * base,int weight,bool italic)84 Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) {
85     const Typeface* resolvedFace = Typeface::resolveDefault(base);
86     Typeface* result = new Typeface();
87     if (result != nullptr) {
88         result->fFontCollection = resolvedFace->fFontCollection;
89         result->fBaseWeight = resolvedFace->fBaseWeight;
90         result->fAPIStyle = computeAPIStyle(weight, italic);
91         result->fStyle = computeMinikinStyle(weight, italic);
92         result->fIsVariationInstance = resolvedFace->fIsVariationInstance;
93     }
94     return result;
95 }
96 
createFromTypefaceWithVariation(Typeface * src,const minikin::VariationSettings & variations)97 Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src,
98                                                     const minikin::VariationSettings& variations) {
99     const Typeface* resolvedFace = Typeface::resolveDefault(src);
100     Typeface* result = new Typeface();
101     if (result != nullptr) {
102         result->fFontCollection =
103                 resolvedFace->fFontCollection->createCollectionWithVariation(variations);
104         if (result->fFontCollection == nullptr) {
105             // None of passed axes are supported by this collection.
106             // So we will reuse the same collection with incrementing reference count.
107             result->fFontCollection = resolvedFace->fFontCollection;
108         }
109         // Do not update styles.
110         // TODO: We may want to update base weight if the 'wght' is specified.
111         result->fBaseWeight = resolvedFace->fBaseWeight;
112         result->fAPIStyle = resolvedFace->fAPIStyle;
113         result->fStyle = resolvedFace->fStyle;
114         result->fIsVariationInstance = true;
115     }
116     return result;
117 }
118 
createWithDifferentBaseWeight(Typeface * src,int weight)119 Typeface* Typeface::createWithDifferentBaseWeight(Typeface* src, int weight) {
120     const Typeface* resolvedFace = Typeface::resolveDefault(src);
121     Typeface* result = new Typeface;
122     if (result != nullptr) {
123         result->fFontCollection = resolvedFace->fFontCollection;
124         result->fBaseWeight = weight;
125         result->fAPIStyle = resolvedFace->fAPIStyle;
126         result->fStyle = computeRelativeStyle(weight, result->fAPIStyle);
127         result->fIsVariationInstance = resolvedFace->fIsVariationInstance;
128     }
129     return result;
130 }
131 
createFromFamilies(std::vector<std::shared_ptr<minikin::FontFamily>> && families,int weight,int italic,const Typeface * fallback)132 Typeface* Typeface::createFromFamilies(std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
133                                        int weight, int italic, const Typeface* fallback) {
134     Typeface* result = new Typeface;
135     if (fallback == nullptr) {
136         result->fFontCollection = minikin::FontCollection::create(std::move(families));
137     } else {
138         result->fFontCollection =
139                 fallback->fFontCollection->createCollectionWithFamilies(std::move(families));
140     }
141 
142     if (weight == RESOLVE_BY_FONT_TABLE || italic == RESOLVE_BY_FONT_TABLE) {
143         int weightFromFont;
144         bool italicFromFont;
145 
146         const minikin::FontStyle defaultStyle;
147         const minikin::MinikinFont* mf =
148                 families.empty() ? nullptr
149                                  : families[0]->getClosestMatch(defaultStyle).typeface().get();
150         if (mf != nullptr) {
151             SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface();
152             const SkFontStyle& style = skTypeface->fontStyle();
153             weightFromFont = style.weight();
154             italicFromFont = style.slant() != SkFontStyle::kUpright_Slant;
155         } else {
156             // We can't obtain any information from fonts. Just use default values.
157             weightFromFont = SkFontStyle::kNormal_Weight;
158             italicFromFont = false;
159         }
160 
161         if (weight == RESOLVE_BY_FONT_TABLE) {
162             weight = weightFromFont;
163         }
164         if (italic == RESOLVE_BY_FONT_TABLE) {
165             italic = italicFromFont ? 1 : 0;
166         }
167     }
168 
169     // Sanitize the invalid value passed from public API.
170     if (weight < 0) {
171         weight = SkFontStyle::kNormal_Weight;
172     }
173 
174     result->fBaseWeight = weight;
175     result->fAPIStyle = computeAPIStyle(weight, italic);
176     result->fStyle = computeMinikinStyle(weight, italic);
177     result->fIsVariationInstance = false;
178     return result;
179 }
180 
setDefault(const Typeface * face)181 void Typeface::setDefault(const Typeface* face) {
182     gDefaultTypeface = face;
183 }
184 
setRobotoTypefaceForTest()185 void Typeface::setRobotoTypefaceForTest() {
186 #ifndef _WIN32
187     const char* kRobotoFont = "/system/fonts/Roboto-Regular.ttf";
188 
189     int fd = open(kRobotoFont, O_RDONLY);
190     LOG_ALWAYS_FATAL_IF(fd == -1, "Failed to open file %s", kRobotoFont);
191     struct stat st = {};
192     LOG_ALWAYS_FATAL_IF(fstat(fd, &st) == -1, "Failed to stat file %s", kRobotoFont);
193     void* data = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
194     std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(data, st.st_size));
195     sk_sp<SkFontMgr> fm = android::FreeTypeFontMgr();
196     LOG_ALWAYS_FATAL_IF(fm == nullptr, "Could not load FreeType SkFontMgr");
197     sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(fontData));
198     LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", kRobotoFont);
199 
200     std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
201             std::move(typeface), 0, data, st.st_size, kRobotoFont, 0, minikin::VariationSettings());
202     std::vector<std::shared_ptr<minikin::Font>> fonts;
203     fonts.push_back(minikin::Font::Builder(font).build());
204 
205     std::shared_ptr<minikin::FontCollection> collection =
206             minikin::FontCollection::create(minikin::FontFamily::create(std::move(fonts)));
207 
208     Typeface* hwTypeface = new Typeface();
209     hwTypeface->fFontCollection = collection;
210     hwTypeface->fAPIStyle = Typeface::kNormal;
211     hwTypeface->fBaseWeight = SkFontStyle::kNormal_Weight;
212     hwTypeface->fStyle = minikin::FontStyle();
213 
214     Typeface::setDefault(hwTypeface);
215 #endif
216 }
217 }  // namespace android
218