summaryrefslogtreecommitdiff
path: root/include/minikin/FontCollection.h
blob: ee0315e409282cdd87f44543c953d1414ccb53de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef MINIKIN_FONT_COLLECTION_H
#define MINIKIN_FONT_COLLECTION_H

#include <gtest/gtest_prod.h>

#include <memory>
#include <unordered_map>
#include <vector>

#include "minikin/Buffer.h"
#include "minikin/Font.h"
#include "minikin/FontFamily.h"
#include "minikin/MinikinFont.h"
#include "minikin/U16StringPiece.h"

namespace minikin {

// The maximum number of font families.
constexpr uint32_t MAX_FAMILY_COUNT = 254;

class LocaleList;

class FontCollection {
public:
    static std::shared_ptr<FontCollection> create(
            const std::vector<std::shared_ptr<FontFamily>>& typefaces);
    static std::shared_ptr<FontCollection> create(std::shared_ptr<FontFamily>&& typeface);

    static std::vector<std::shared_ptr<FontCollection>> readVector(BufferReader* reader);
    static void writeVector(BufferWriter* writer,
                            const std::vector<std::shared_ptr<FontCollection>>& fontCollections);

    // Helper class for representing font family match result in packed bits.
    struct FamilyMatchResult {
    public:
        struct Builder {
        public:
            Builder() : mSize(0), mBits(0) {}

            Builder& add(uint8_t x) {
                if (mSize >= 7) [[unlikely]] {
                        return *this;
                    }
                mBits = mBits | (static_cast<uint64_t>(x) << (8 * mSize));
                mSize++;
                return *this;
            }

            Builder& reset() {
                mSize = 0;
                mBits = 0;
                return *this;
            }

            uint8_t size() const { return mSize; }

            bool empty() const { return size() == 0; }

            FamilyMatchResult build() {
                return FamilyMatchResult(mBits | (static_cast<uint64_t>(mSize) << 56));
            }

        private:
            uint8_t mSize;
            uint64_t mBits;
        };

        // Helper class for iterating FamilyMatchResult
        class iterator {
        public:
            inline bool operator==(const iterator& o) const {
                return mOffset == o.mOffset && mResult == o.mResult;
            }

            inline bool operator!=(const iterator& o) const { return !(*this == o); }
            inline uint8_t operator*() const { return mResult[mOffset]; }
            inline iterator& operator++() {
                mOffset++;
                return *this;
            }

        private:
            friend struct FamilyMatchResult;
            iterator(const FamilyMatchResult& result, uint32_t offset)
                    : mResult(result), mOffset(offset) {}
            const FamilyMatchResult& mResult;
            uint32_t mOffset;
        };

        // Create empty FamilyMatchResult.
        FamilyMatchResult() : mBits(0) {}

        inline uint8_t size() const { return static_cast<uint8_t>(mBits >> 56); }

        inline uint8_t operator[](uint32_t pos) const {
            return static_cast<uint8_t>(mBits >> (pos * 8));
        }

        inline bool empty() const { return size() == 0; }

        inline bool operator==(const FamilyMatchResult& o) const { return mBits == o.mBits; }

        // Returns the common family indices between l and r.
        static FamilyMatchResult intersect(FamilyMatchResult l, FamilyMatchResult r);

        // Iterator
        inline iterator begin() const { return iterator(*this, 0); }
        inline iterator end() const { return iterator(*this, size()); }

        FamilyMatchResult(const FamilyMatchResult& o) = default;
        FamilyMatchResult& operator=(const FamilyMatchResult& o) = default;

    private:
        explicit FamilyMatchResult(uint64_t bits) : mBits(bits) {}
        uint64_t mBits;
    };

    struct Run {
        FamilyMatchResult familyMatch;
        int start;
        int end;
    };

    FakedFont getBestFont(U16StringPiece textBuf, const Run& run, FontStyle style);

    // Perform the itemization until given max runs.
    std::vector<Run> itemize(U16StringPiece text, FontStyle style, uint32_t localeListId,
                             FamilyVariant familyVariant, uint32_t runMax) const;

    // Perform the itemization until end of the text.
    std::vector<Run> itemize(U16StringPiece text, FontStyle style, uint32_t localeListId,
                             FamilyVariant familyVariant) const {
        return itemize(text, style, localeListId, familyVariant, text.size());
    }

    MinikinExtent getReferenceExtentForLocale(const MinikinPaint& paint) const;

    // Returns true if there is a glyph for the code point and variation selector pair.
    // Returns false if no fonts have a glyph for the code point and variation
    // selector pair, or invalid variation selector is passed.
    bool hasVariationSelector(uint32_t baseCodepoint, uint32_t variationSelector) const;

    // Get base font with fakery information (fake bold could affect metrics)
    FakedFont baseFontFaked(FontStyle style);

    // Creates new FontCollection based on this collection while applying font variations. Returns
    // nullptr if none of variations apply to this collection.
    std::shared_ptr<FontCollection> createCollectionWithVariation(
            const std::vector<FontVariation>& variations);
    // Creates new FontCollection that uses the specified families as top families and
    // families from this FontCollection as fallback.
    std::shared_ptr<FontCollection> createCollectionWithFamilies(
            std::vector<std::shared_ptr<FontFamily>>&& families) const;

    size_t getSupportedAxesCount() const { return mSupportedAxesCount; }
    AxisTag getSupportedAxisAt(size_t index) const { return mSupportedAxes[index]; }

    uint32_t getId() const;

    size_t getFamilyCount() const { return mFamilyCount; }

    const std::shared_ptr<FontFamily>& getFamilyAt(size_t index) const {
        if (mFamilyIndices != nullptr) {
            index = mFamilyIndices[index];
        }
        return (*mMaybeSharedFamilies)[index];
    }

private:
    FRIEND_TEST(FontCollectionTest, bufferTest);

    explicit FontCollection(const std::vector<std::shared_ptr<FontFamily>>& typefaces);
    FontCollection(
            BufferReader* reader,
            const std::shared_ptr<std::vector<std::shared_ptr<FontFamily>>>& allFontFamilies);
    // Write fields of the instance, using fontFamilyToIndexMap for finding
    // indices for FontFamily.
    void writeTo(BufferWriter* writer,
                 const std::unordered_map<std::shared_ptr<FontFamily>, uint32_t>&
                         fontFamilyToIndexMap) const;
    static void collectAllFontFamilies(
            const std::vector<std::shared_ptr<FontCollection>>& fontCollections,
            std::vector<std::shared_ptr<FontFamily>>* outAllFontFamilies,
            std::unordered_map<std::shared_ptr<FontFamily>, uint32_t>* outFontFamilyToIndexMap);

    static const int kLogCharsPerPage = 8;
    static const int kPageMask = (1 << kLogCharsPerPage) - 1;

    // mFamilyVec holds the indices of the family (as in getFamilyAt()) and
    // mRanges holds the range of indices of mFamilyVec.
    // The maximum number of pages is 0x10FF (U+10FFFF >> 8). The maximum number of
    // the fonts is 0xFF. Thus, technically the maximum length of mFamilyVec is 0x10EE01
    // (0x10FF * 0xFF). However, in practice, 16-bit integers are enough since most fonts supports
    // only limited range of code points.
    struct Range {
        uint16_t start;
        uint16_t end;
    };

    // Initialize the FontCollection.
    void init(const std::vector<std::shared_ptr<FontFamily>>& typefaces);

    FamilyMatchResult getFamilyForChar(uint32_t ch, uint32_t vs, uint32_t localeListId,
                                       FamilyVariant variant) const;

    uint32_t calcFamilyScore(uint32_t ch, uint32_t vs, FamilyVariant variant, uint32_t localeListId,
                             const std::shared_ptr<FontFamily>& fontFamily) const;

    uint32_t calcCoverageScore(uint32_t ch, uint32_t vs, uint32_t localeListId,
                               const std::shared_ptr<FontFamily>& fontFamily) const;

    bool isPrimaryFamily(const std::shared_ptr<FontFamily>& fontFamily) const;

    void filterFamilyByLocale(const LocaleList& localeList,
                              const std::function<void(const FontFamily& family)>& callback) const;

    static uint32_t calcLocaleMatchingScore(uint32_t userLocaleListId,
                                            const FontFamily& fontFamily);

    static uint32_t calcVariantMatchingScore(FamilyVariant variant, const FontFamily& fontFamily);

    // unique id for this font collection (suitable for cache key)
    uint32_t mId;

    // Highest UTF-32 code point that can be mapped
    uint32_t mMaxChar;

    // This vector has pointers to the all font family instances in this collection.
    // This vector can't be empty.
    // This vector may be shared with other font collections.
    // (1) When shared, this vector is a union of all font family instances
    //     shared by multiple font collections.
    //     mFamilyIndices will be non-null in this case.
    //     The i-th family in this collection will be
    //     mMaybeSharedFamilies[mFamilyIndices[i]].
    // (2) When not shared, mFamilyIndices will be null and
    //     the i-th family in this collection will be mMaybeSharedFamilies[i].
    // Use getFamilyAt(i) to access the i-th font in this family.
    std::shared_ptr<std::vector<std::shared_ptr<FontFamily>>> mMaybeSharedFamilies;
    uint32_t mFamilyCount;
    const uint32_t* mFamilyIndices;

    // Following two vectors are pre-calculated tables for resolving coverage faster.
    // For example, to iterate over all fonts which support Unicode code point U+XXYYZZ,
    // iterate font families index from mFamilyVec[mRanges[0xXXYY].start] to
    // mFamilyVec[mRange[0xXXYY].end] instead of whole mFamilies.
    // This vector contains indices into mFamilies.
    // This vector can't be empty.
    uint32_t mRangesCount;
    const Range* mRanges;
    uint32_t mFamilyVecCount;
    const uint8_t* mFamilyVec;

    // This vector has pointers to the font family instances which have cmap 14 subtables.
    std::vector<std::shared_ptr<FontFamily>> mVSFamilyVec;

    // Set of supported axes in this collection.
    uint32_t mSupportedAxesCount;
    // mSupportedAxes is sorted.
    std::unique_ptr<AxisTag[]> mSupportedAxes;

    // Owns allocated memory if this class is created from font families, otherwise these are
    // nullptr.
    std::unique_ptr<Range[]> mOwnedRanges;
    std::vector<uint8_t> mOwnedFamilyVec;
};

}  // namespace minikin

#endif  // MINIKIN_FONT_COLLECTION_H