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
21bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka#include <cutils/log.h>
22fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka#include <hb.h>
2389e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka#include <hb-ot.h>
24fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka#include <utils/LruCache.h>
25fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
26fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka#include <minikin/MinikinFont.h>
27fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka#include "MinikinInternal.h"
28fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
29fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonakanamespace android {
30fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
31bae347682989d2627081310129a5b60541ed6ad0Seigo Nonakastatic hb_blob_t* referenceTable(hb_face_t* /* face */, hb_tag_t tag, void* userData) {
32fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    MinikinFont* font = reinterpret_cast<MinikinFont*>(userData);
33aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    MinikinDestroyFunc destroy = 0;
34aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    size_t size = 0;
35aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    const void* buffer = font->GetTable(tag, &size, &destroy);
36aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    if (buffer == nullptr) {
37aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien        return nullptr;
38fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
39fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka#ifdef VERBOSE_DEBUG
40aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    ALOGD("referenceTable %c%c%c%c length=%zd",
41aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien        (tag >>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff, size);
42fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka#endif
43aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    return hb_blob_create(reinterpret_cast<const char*>(buffer), size,
44aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien            HB_MEMORY_MODE_READONLY, const_cast<void*>(buffer), destroy);
45fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka}
46fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
4789e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonakaclass HbFontCache : private OnEntryRemoved<int32_t, hb_font_t*> {
48fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonakapublic:
4989e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    HbFontCache() : mCache(kMaxEntries) {
50fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka        mCache.setOnEntryRemovedListener(this);
51fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
52fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
53fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    // callback for OnEntryRemoved
5489e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    void operator()(int32_t& /* key */, hb_font_t*& value) {
5589e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka        hb_font_destroy(value);
56fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
57fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
5889e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    hb_font_t* get(int32_t fontId) {
59fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka        return mCache.get(fontId);
60fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
61fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
6289e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    void put(int32_t fontId, hb_font_t* font) {
6389e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka        mCache.put(fontId, font);
64fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
65fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
66fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    void clear() {
67fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka        mCache.clear();
68fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
69fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
709afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien    void remove(int32_t fontId) {
719afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien        mCache.remove(fontId);
729afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien    }
739afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien
74fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonakaprivate:
75fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    static const size_t kMaxEntries = 100;
76fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
7789e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    LruCache<int32_t, hb_font_t*> mCache;
78fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka};
79fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
8089e80237bc27af084c9ff316d4f47abf426eced8Seigo NonakaHbFontCache* getFontCacheLocked() {
81fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    assertMinikinLocked();
8289e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    static HbFontCache* cache = nullptr;
83fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    if (cache == nullptr) {
8489e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka        cache = new HbFontCache();
85fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
86fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    return cache;
87fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka}
88fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
8989e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonakavoid purgeHbFontCacheLocked() {
90fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    assertMinikinLocked();
9189e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    getFontCacheLocked()->clear();
92fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka}
93fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
946c60831cfce24b0749f50f37231e0a56d8fd4b85Seigo Nonakavoid purgeHbFontLocked(const MinikinFont* minikinFont) {
956c60831cfce24b0749f50f37231e0a56d8fd4b85Seigo Nonaka    assertMinikinLocked();
969afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien    const int32_t fontId = minikinFont->GetUniqueId();
979afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien    getFontCacheLocked()->remove(fontId);
989afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien}
999afcc6e2bd4d89e4e1deb6e18c3c4daca4e114fdRaph Levien
100aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien// Returns a new reference to a hb_font_t object, caller is
101aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien// responsible for calling hb_font_destroy() on it.
10289e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonakahb_font_t* getHbFontLocked(MinikinFont* minikinFont) {
103fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    assertMinikinLocked();
104aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    // TODO: get rid of nullFaceFont
10589e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    static hb_font_t* nullFaceFont = nullptr;
106fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    if (minikinFont == nullptr) {
10789e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka        if (nullFaceFont == nullptr) {
10889e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka            nullFaceFont = hb_font_create(nullptr);
10989e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka        }
110aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien        return hb_font_reference(nullFaceFont);
111fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
112fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
11389e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    HbFontCache* fontCache = getFontCacheLocked();
114fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    const int32_t fontId = minikinFont->GetUniqueId();
11589e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    hb_font_t* font = fontCache->get(fontId);
11689e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    if (font != nullptr) {
117aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien        return hb_font_reference(font);
118fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka    }
119fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
120aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    hb_face_t* face;
121aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    const void* buf = minikinFont->GetFontData();
122aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    if (buf == nullptr) {
123aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien        face = hb_face_create_for_tables(referenceTable, minikinFont, nullptr);
124aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    } else {
125aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien        size_t size = minikinFont->GetFontSize();
126aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien        hb_blob_t* blob = hb_blob_create(reinterpret_cast<const char*>(buf), size,
127aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien            HB_MEMORY_MODE_READONLY, nullptr, nullptr);
128aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien        face = hb_face_create(blob, minikinFont->GetFontIndex());
129aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien        hb_blob_destroy(blob);
130aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    }
13189e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    hb_font_t* parent_font = hb_font_create(face);
13289e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    hb_ot_font_set_funcs(parent_font);
13389e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka
13489e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    unsigned int upem = hb_face_get_upem(face);
13589e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    hb_font_set_scale(parent_font, upem, upem);
13689e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka
13789e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    font = hb_font_create_sub_font(parent_font);
13889e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    hb_font_destroy(parent_font);
13989e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    hb_face_destroy(face);
14089e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka    fontCache->put(fontId, font);
141aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien    return hb_font_reference(font);
142fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka}
143fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka
144fb0d396929e534a3686469b474d4f670864aa5acSeigo Nonaka}  // namespace android
145