HbFontCache.cpp revision 9afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fd
1/*
2 * Copyright (C) 2015 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 "HbFontCache.h"
20
21#include <cutils/log.h>
22#include <hb.h>
23#include <hb-ot.h>
24#include <utils/LruCache.h>
25
26#include <minikin/MinikinFont.h>
27#include "MinikinInternal.h"
28
29namespace android {
30
31static hb_blob_t* referenceTable(hb_face_t* /* face */, hb_tag_t tag, void* userData) {
32    MinikinFont* font = reinterpret_cast<MinikinFont*>(userData);
33    size_t length = 0;
34    bool ok = font->GetTable(tag, NULL, &length);
35    if (!ok) {
36        return 0;
37    }
38    char* buffer = reinterpret_cast<char*>(malloc(length));
39    if (!buffer) {
40        return 0;
41    }
42    ok = font->GetTable(tag, reinterpret_cast<uint8_t*>(buffer), &length);
43#ifdef VERBOSE_DEBUG
44    ALOGD("referenceTable %c%c%c%c length=%zd %d",
45        (tag >>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff, length, ok);
46#endif
47    if (!ok) {
48        free(buffer);
49        return 0;
50    }
51    return hb_blob_create(const_cast<char*>(buffer), length,
52            HB_MEMORY_MODE_WRITABLE, buffer, free);
53}
54
55class HbFontCache : private OnEntryRemoved<int32_t, hb_font_t*> {
56public:
57    HbFontCache() : mCache(kMaxEntries) {
58        mCache.setOnEntryRemovedListener(this);
59    }
60
61    // callback for OnEntryRemoved
62    void operator()(int32_t& /* key */, hb_font_t*& value) {
63        hb_font_destroy(value);
64    }
65
66    hb_font_t* get(int32_t fontId) {
67        return mCache.get(fontId);
68    }
69
70    void put(int32_t fontId, hb_font_t* font) {
71        mCache.put(fontId, font);
72    }
73
74    void clear() {
75        mCache.clear();
76    }
77
78    void remove(int32_t fontId) {
79        mCache.remove(fontId);
80    }
81
82private:
83    static const size_t kMaxEntries = 100;
84
85    LruCache<int32_t, hb_font_t*> mCache;
86};
87
88HbFontCache* getFontCacheLocked() {
89    assertMinikinLocked();
90    static HbFontCache* cache = nullptr;
91    if (cache == nullptr) {
92        cache = new HbFontCache();
93    }
94    return cache;
95}
96
97void purgeHbFontCacheLocked() {
98    assertMinikinLocked();
99    getFontCacheLocked()->clear();
100}
101
102void purgeHbFont(const MinikinFont* minikinFont) {
103    AutoMutex _l(gMinikinLock);
104    const int32_t fontId = minikinFont->GetUniqueId();
105    getFontCacheLocked()->remove(fontId);
106}
107
108hb_font_t* getHbFontLocked(MinikinFont* minikinFont) {
109    assertMinikinLocked();
110    static hb_font_t* nullFaceFont = nullptr;
111    if (minikinFont == nullptr) {
112        if (nullFaceFont == nullptr) {
113            nullFaceFont = hb_font_create(nullptr);
114        }
115        return nullFaceFont;
116    }
117
118    HbFontCache* fontCache = getFontCacheLocked();
119    const int32_t fontId = minikinFont->GetUniqueId();
120    hb_font_t* font = fontCache->get(fontId);
121    if (font != nullptr) {
122        return font;
123    }
124
125    hb_face_t* face = hb_face_create_for_tables(referenceTable, minikinFont, nullptr);
126    hb_font_t* parent_font = hb_font_create(face);
127    hb_ot_font_set_funcs(parent_font);
128
129    unsigned int upem = hb_face_get_upem(face);
130    hb_font_set_scale(parent_font, upem, upem);
131
132    font = hb_font_create_sub_font(parent_font);
133    hb_font_destroy(parent_font);
134    hb_face_destroy(face);
135    fontCache->put(fontId, font);
136    return font;
137}
138
139}  // namespace android
140