• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 #define LOG_TAG "Minikin"
18 
19 #include "minikin/Font.h"
20 
21 #include <hb-ot.h>
22 #include <hb.h>
23 #include <log/log.h>
24 
25 #include <vector>
26 
27 #include "FontUtils.h"
28 #include "LocaleListCache.h"
29 #include "MinikinInternal.h"
30 #include "minikin/HbUtils.h"
31 #include "minikin/MinikinFont.h"
32 #include "minikin/MinikinFontFactory.h"
33 
34 namespace minikin {
35 
build()36 std::shared_ptr<Font> Font::Builder::build() {
37     if (mIsWeightSet && mIsSlantSet) {
38         // No need to read OS/2 header of the font file.
39         return std::shared_ptr<Font>(new Font(std::move(mTypeface), FontStyle(mWeight, mSlant),
40                                               prepareFont(mTypeface), mLocaleListId));
41     }
42 
43     HbFontUniquePtr font = prepareFont(mTypeface);
44     FontStyle styleFromFont = analyzeStyle(font);
45     if (!mIsWeightSet) {
46         mWeight = styleFromFont.weight();
47     }
48     if (!mIsSlantSet) {
49         mSlant = styleFromFont.slant();
50     }
51     return std::shared_ptr<Font>(new Font(std::move(mTypeface), FontStyle(mWeight, mSlant),
52                                           std::move(font), mLocaleListId));
53 }
54 
Font(BufferReader * reader)55 Font::Font(BufferReader* reader) : mExternalRefsHolder(nullptr), mTypefaceMetadataReader(nullptr) {
56     mStyle = FontStyle(reader);
57     mLocaleListId = LocaleListCache::readFrom(reader);
58     mTypefaceMetadataReader = *reader;
59     MinikinFontFactory::getInstance().skip(reader);
60 }
61 
writeTo(BufferWriter * writer) const62 void Font::writeTo(BufferWriter* writer) const {
63     mStyle.writeTo(writer);
64     LocaleListCache::writeTo(writer, mLocaleListId);
65     MinikinFontFactory::getInstance().write(writer, typeface().get());
66 }
67 
Font(Font && o)68 Font::Font(Font&& o) noexcept
69         : mStyle(o.mStyle),
70           mLocaleListId(o.mLocaleListId),
71           mTypefaceMetadataReader(o.mTypefaceMetadataReader) {
72     mExternalRefsHolder.store(o.mExternalRefsHolder.exchange(nullptr));
73 }
74 
operator =(Font && o)75 Font& Font::operator=(Font&& o) noexcept {
76     resetExternalRefs(o.mExternalRefsHolder.exchange(nullptr));
77     mStyle = o.mStyle;
78     mLocaleListId = o.mLocaleListId;
79     mTypefaceMetadataReader = o.mTypefaceMetadataReader;
80     return *this;
81 }
82 
~Font()83 Font::~Font() {
84     resetExternalRefs(nullptr);
85 }
86 
resetExternalRefs(ExternalRefs * refs)87 void Font::resetExternalRefs(ExternalRefs* refs) {
88     ExternalRefs* oldRefs = mExternalRefsHolder.exchange(refs);
89     if (oldRefs != nullptr) {
90         delete oldRefs;
91     }
92 }
93 
typeface() const94 const std::shared_ptr<MinikinFont>& Font::typeface() const {
95     return getExternalRefs()->mTypeface;
96 }
97 
baseFont() const98 const HbFontUniquePtr& Font::baseFont() const {
99     return getExternalRefs()->mBaseFont;
100 }
101 
getExternalRefs() const102 const Font::ExternalRefs* Font::getExternalRefs() const {
103     // Thread safety note: getExternalRefs() is thread-safe.
104     // getExternalRefs() returns the first ExternalRefs set to mExternalRefsHolder.
105     // When multiple threads called getExternalRefs() at the same time and
106     // mExternalRefsHolder is not set, multiple ExternalRefs may be created,
107     // but only one ExternalRefs will be set to mExternalRefsHolder and
108     // others will be deleted.
109     Font::ExternalRefs* externalRefs = mExternalRefsHolder.load();
110     if (externalRefs) return externalRefs;
111     // mExternalRefsHolder is null. Try creating an ExternalRefs.
112     std::shared_ptr<MinikinFont> typeface =
113             MinikinFontFactory::getInstance().create(mTypefaceMetadataReader);
114     HbFontUniquePtr font = prepareFont(typeface);
115     Font::ExternalRefs* newExternalRefs =
116             new Font::ExternalRefs(std::move(typeface), std::move(font));
117     // Set the new ExternalRefs to mExternalRefsHolder if it is still null.
118     Font::ExternalRefs* expected = nullptr;
119     if (mExternalRefsHolder.compare_exchange_strong(expected, newExternalRefs)) {
120         return newExternalRefs;
121     } else {
122         // Another thread has already created and set an ExternalRefs.
123         // Delete ours and use theirs instead.
124         delete newExternalRefs;
125         // compare_exchange_strong writes the stored value into 'expected'
126         // when comparison fails.
127         return expected;
128     }
129 }
130 
131 // static
prepareFont(const std::shared_ptr<MinikinFont> & typeface)132 HbFontUniquePtr Font::prepareFont(const std::shared_ptr<MinikinFont>& typeface) {
133     const char* buf = reinterpret_cast<const char*>(typeface->GetFontData());
134     size_t size = typeface->GetFontSize();
135     uint32_t ttcIndex = typeface->GetFontIndex();
136 
137     HbBlobUniquePtr blob(hb_blob_create(buf, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr));
138     HbFaceUniquePtr face(hb_face_create(blob.get(), ttcIndex));
139     HbFontUniquePtr parent(hb_font_create(face.get()));
140     hb_ot_font_set_funcs(parent.get());
141 
142     uint32_t upem = hb_face_get_upem(face.get());
143     hb_font_set_scale(parent.get(), upem, upem);
144 
145     HbFontUniquePtr font(hb_font_create_sub_font(parent.get()));
146     std::vector<hb_variation_t> variations;
147     variations.reserve(typeface->GetAxes().size());
148     for (const FontVariation& variation : typeface->GetAxes()) {
149         variations.push_back({variation.axisTag, variation.value});
150     }
151     hb_font_set_variations(font.get(), variations.data(), variations.size());
152     return font;
153 }
154 
155 // static
analyzeStyle(const HbFontUniquePtr & font)156 FontStyle Font::analyzeStyle(const HbFontUniquePtr& font) {
157     HbBlob os2Table(font, MinikinFont::MakeTag('O', 'S', '/', '2'));
158     if (!os2Table) {
159         return FontStyle();
160     }
161 
162     int weight;
163     bool italic;
164     if (!::minikin::analyzeStyle(os2Table.get(), os2Table.size(), &weight, &italic)) {
165         return FontStyle();
166     }
167     // TODO: Update weight/italic based on fvar value.
168     return FontStyle(static_cast<uint16_t>(weight), static_cast<FontStyle::Slant>(italic));
169 }
170 
getSupportedAxes() const171 std::unordered_set<AxisTag> Font::getSupportedAxes() const {
172     HbBlob fvarTable(baseFont(), MinikinFont::MakeTag('f', 'v', 'a', 'r'));
173     if (!fvarTable) {
174         return std::unordered_set<AxisTag>();
175     }
176     std::unordered_set<AxisTag> supportedAxes;
177     analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes);
178     return supportedAxes;
179 }
180 
181 }  // namespace minikin
182