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 <vector>
22
23 #include <hb-ot.h>
24 #include <hb.h>
25 #include <log/log.h>
26
27 #include "minikin/HbUtils.h"
28 #include "minikin/MinikinFont.h"
29
30 #include "FontUtils.h"
31 #include "MinikinInternal.h"
32
33 namespace minikin {
34
build()35 std::shared_ptr<Font> Font::Builder::build() {
36 if (mIsWeightSet && mIsSlantSet) {
37 // No need to read OS/2 header of the font file.
38 return std::shared_ptr<Font>(new Font(std::move(mTypeface), FontStyle(mWeight, mSlant),
39 prepareFont(mTypeface), mLocaleListId));
40 }
41
42 HbFontUniquePtr font = prepareFont(mTypeface);
43 FontStyle styleFromFont = analyzeStyle(font);
44 if (!mIsWeightSet) {
45 mWeight = styleFromFont.weight();
46 }
47 if (!mIsSlantSet) {
48 mSlant = styleFromFont.slant();
49 }
50 return std::shared_ptr<Font>(new Font(std::move(mTypeface), FontStyle(mWeight, mSlant),
51 std::move(font), mLocaleListId));
52 }
53
typeface() const54 const std::shared_ptr<MinikinFont>& Font::typeface() const {
55 std::lock_guard lock(mTypefaceMutex);
56 if (mTypeface) return mTypeface;
57 initTypefaceLocked();
58 return mTypeface;
59 }
60
baseFont() const61 const HbFontUniquePtr& Font::baseFont() const {
62 std::lock_guard lock(mTypefaceMutex);
63 if (mBaseFont) return mBaseFont;
64 initTypefaceLocked();
65 mBaseFont = prepareFont(mTypeface);
66 return mBaseFont;
67 }
68
initTypefaceLocked() const69 void Font::initTypefaceLocked() const {
70 if (mTypeface) return;
71 MINIKIN_ASSERT(mTypefaceLoader, "mTypefaceLoader should not be empty when mTypeface is null");
72 mTypeface = mTypefaceLoader(mTypefaceMetadataReader);
73 }
74
75 // static
prepareFont(const std::shared_ptr<MinikinFont> & typeface)76 HbFontUniquePtr Font::prepareFont(const std::shared_ptr<MinikinFont>& typeface) {
77 const char* buf = reinterpret_cast<const char*>(typeface->GetFontData());
78 size_t size = typeface->GetFontSize();
79 uint32_t ttcIndex = typeface->GetFontIndex();
80
81 HbBlobUniquePtr blob(hb_blob_create(buf, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr));
82 HbFaceUniquePtr face(hb_face_create(blob.get(), ttcIndex));
83 HbFontUniquePtr parent(hb_font_create(face.get()));
84 hb_ot_font_set_funcs(parent.get());
85
86 uint32_t upem = hb_face_get_upem(face.get());
87 hb_font_set_scale(parent.get(), upem, upem);
88
89 HbFontUniquePtr font(hb_font_create_sub_font(parent.get()));
90 std::vector<hb_variation_t> variations;
91 variations.reserve(typeface->GetAxes().size());
92 for (const FontVariation& variation : typeface->GetAxes()) {
93 variations.push_back({variation.axisTag, variation.value});
94 }
95 hb_font_set_variations(font.get(), variations.data(), variations.size());
96 return font;
97 }
98
99 // static
analyzeStyle(const HbFontUniquePtr & font)100 FontStyle Font::analyzeStyle(const HbFontUniquePtr& font) {
101 HbBlob os2Table(font, MinikinFont::MakeTag('O', 'S', '/', '2'));
102 if (!os2Table) {
103 return FontStyle();
104 }
105
106 int weight;
107 bool italic;
108 if (!::minikin::analyzeStyle(os2Table.get(), os2Table.size(), &weight, &italic)) {
109 return FontStyle();
110 }
111 // TODO: Update weight/italic based on fvar value.
112 return FontStyle(static_cast<uint16_t>(weight), static_cast<FontStyle::Slant>(italic));
113 }
114
getSupportedAxes() const115 std::unordered_set<AxisTag> Font::getSupportedAxes() const {
116 HbBlob fvarTable(baseFont(), MinikinFont::MakeTag('f', 'v', 'a', 'r'));
117 if (!fvarTable) {
118 return std::unordered_set<AxisTag>();
119 }
120 std::unordered_set<AxisTag> supportedAxes;
121 analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes);
122 return supportedAxes;
123 }
124
125 } // namespace minikin
126