1fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka/*
2fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka * Copyright (C) 2015 The Android Open Source Project
3fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka *
4fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License");
5fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka * you may not use this file except in compliance with the License.
6fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka * You may obtain a copy of the License at
7fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka *
8fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka *      http://www.apache.org/licenses/LICENSE-2.0
9fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka *
10fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka * Unless required by applicable law or agreed to in writing, software
11fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS,
12fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka * See the License for the specific language governing permissions and
14fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka * limitations under the License.
15fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka */
16fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
17fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka#define LOG_TAG "Minikin"
18fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
1989e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka#include "HbFontCache.h"
20fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
2139ab40115fae6d0c948e435233b3dd997ee7d8e5Mark Salyzyn#include <log/log.h>
22555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn#include <utils/LruCache.h>
23555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn
24fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka#include <hb.h>
2589e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka#include <hb-ot.h>
26fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
27fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka#include <minikin/MinikinFont.h>
28fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka#include "MinikinInternal.h"
29fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
3014e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakanamespace minikin {
31fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
3214e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakaclass HbFontCache : private android::OnEntryRemoved<int32_t, hb_font_t*> {
33fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonakapublic:
3489e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    HbFontCache() : mCache(kMaxEntries) {
35fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka        mCache.setOnEntryRemovedListener(this);
36fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
37fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
38fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    // callback for OnEntryRemoved
3989e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    void operator()(int32_t& /* key */, hb_font_t*& value) {
4089e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka        hb_font_destroy(value);
41fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
42fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
4389e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    hb_font_t* get(int32_t fontId) {
44fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka        return mCache.get(fontId);
45fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
46fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
4789e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    void put(int32_t fontId, hb_font_t* font) {
4889e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka        mCache.put(fontId, font);
49fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
50fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
51fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    void clear() {
52fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka        mCache.clear();
53fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
54fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
559afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien    void remove(int32_t fontId) {
569afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien        mCache.remove(fontId);
579afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien    }
589afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien
59fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonakaprivate:
60fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    static const size_t kMaxEntries = 100;
61fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
6214e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka    android::LruCache<int32_t, hb_font_t*> mCache;
63fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka};
64fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
65fd4124c53399581dd94eac5a9749bc07b474a294Seigo NonakaHbFontCache* getFontCacheLocked() {
66fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    assertMinikinLocked();
67fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    static HbFontCache* cache = nullptr;
68fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    if (cache == nullptr) {
69fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka        cache = new HbFontCache();
70fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
71fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    return cache;
72fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka}
73fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
7489e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonakavoid purgeHbFontCacheLocked() {
75fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    assertMinikinLocked();
76fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    getFontCacheLocked()->clear();
77fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka}
78fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
796c60831cfce24b0749f50f37231e0a56d8fd4b85Seigo Nonakavoid purgeHbFontLocked(const MinikinFont* minikinFont) {
80fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    assertMinikinLocked();
81fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    const int32_t fontId = minikinFont->GetUniqueId();
82fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    getFontCacheLocked()->remove(fontId);
839afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien}
849afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien
85aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien// Returns a new reference to a hb_font_t object, caller is
86aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien// responsible for calling hb_font_destroy() on it.
87dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonakahb_font_t* getHbFontLocked(const MinikinFont* minikinFont) {
88fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    assertMinikinLocked();
89fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    // TODO: get rid of nullFaceFont
90fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    static hb_font_t* nullFaceFont = nullptr;
91fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    if (minikinFont == nullptr) {
92fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka        if (nullFaceFont == nullptr) {
93fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka            nullFaceFont = hb_font_create(nullptr);
94fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka        }
95fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka        return hb_font_reference(nullFaceFont);
96fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    }
97fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka
98fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    HbFontCache* fontCache = getFontCacheLocked();
99fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    const int32_t fontId = minikinFont->GetUniqueId();
100fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    hb_font_t* font = fontCache->get(fontId);
101fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    if (font != nullptr) {
102fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka        return hb_font_reference(font);
103fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    }
104fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka
105fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    hb_face_t* face;
106fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    const void* buf = minikinFont->GetFontData();
107fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    size_t size = minikinFont->GetFontSize();
108fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    hb_blob_t* blob = hb_blob_create(reinterpret_cast<const char*>(buf), size,
109fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka        HB_MEMORY_MODE_READONLY, nullptr, nullptr);
110fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    face = hb_face_create(blob, minikinFont->GetFontIndex());
111fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    hb_blob_destroy(blob);
112fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka
113fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    hb_font_t* parent_font = hb_font_create(face);
114fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    hb_ot_font_set_funcs(parent_font);
115fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka
116fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    unsigned int upem = hb_face_get_upem(face);
117fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    hb_font_set_scale(parent_font, upem, upem);
118fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka
119fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    font = hb_font_create_sub_font(parent_font);
120fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    std::vector<hb_variation_t> variations;
121fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    for (const FontVariation& variation : minikinFont->GetAxes()) {
122fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka        variations.push_back({variation.axisTag, variation.value});
123fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    }
124fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    hb_font_set_variations(font, variations.data(), variations.size());
125fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    hb_font_destroy(parent_font);
126fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    hb_face_destroy(face);
127fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    fontCache->put(fontId, font);
128fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    return hb_font_reference(font);
129fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka}
130fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
13114e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka}  // namespace minikin
132