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