Home | History | Annotate | Download | only in minikin
      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 
     29 namespace android {
     30 
     31 static hb_blob_t* referenceTable(hb_face_t* /* face */, hb_tag_t tag, void* userData) {
     32     MinikinFont* font = reinterpret_cast<MinikinFont*>(userData);
     33     MinikinDestroyFunc destroy = 0;
     34     size_t size = 0;
     35     const void* buffer = font->GetTable(tag, &size, &destroy);
     36     if (buffer == nullptr) {
     37         return nullptr;
     38     }
     39 #ifdef VERBOSE_DEBUG
     40     ALOGD("referenceTable %c%c%c%c length=%zd",
     41         (tag >>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff, size);
     42 #endif
     43     return hb_blob_create(reinterpret_cast<const char*>(buffer), size,
     44             HB_MEMORY_MODE_READONLY, const_cast<void*>(buffer), destroy);
     45 }
     46 
     47 class HbFontCache : private OnEntryRemoved<int32_t, hb_font_t*> {
     48 public:
     49     HbFontCache() : mCache(kMaxEntries) {
     50         mCache.setOnEntryRemovedListener(this);
     51     }
     52 
     53     // callback for OnEntryRemoved
     54     void operator()(int32_t& /* key */, hb_font_t*& value) {
     55         hb_font_destroy(value);
     56     }
     57 
     58     hb_font_t* get(int32_t fontId) {
     59         return mCache.get(fontId);
     60     }
     61 
     62     void put(int32_t fontId, hb_font_t* font) {
     63         mCache.put(fontId, font);
     64     }
     65 
     66     void clear() {
     67         mCache.clear();
     68     }
     69 
     70     void remove(int32_t fontId) {
     71         mCache.remove(fontId);
     72     }
     73 
     74 private:
     75     static const size_t kMaxEntries = 100;
     76 
     77     LruCache<int32_t, hb_font_t*> mCache;
     78 };
     79 
     80 HbFontCache* getFontCacheLocked() {
     81     assertMinikinLocked();
     82     static HbFontCache* cache = nullptr;
     83     if (cache == nullptr) {
     84         cache = new HbFontCache();
     85     }
     86     return cache;
     87 }
     88 
     89 void purgeHbFontCacheLocked() {
     90     assertMinikinLocked();
     91     getFontCacheLocked()->clear();
     92 }
     93 
     94 void purgeHbFontLocked(const MinikinFont* minikinFont) {
     95     assertMinikinLocked();
     96     const int32_t fontId = minikinFont->GetUniqueId();
     97     getFontCacheLocked()->remove(fontId);
     98 }
     99 
    100 // Returns a new reference to a hb_font_t object, caller is
    101 // responsible for calling hb_font_destroy() on it.
    102 hb_font_t* getHbFontLocked(MinikinFont* minikinFont) {
    103     assertMinikinLocked();
    104     // TODO: get rid of nullFaceFont
    105     static hb_font_t* nullFaceFont = nullptr;
    106     if (minikinFont == nullptr) {
    107         if (nullFaceFont == nullptr) {
    108             nullFaceFont = hb_font_create(nullptr);
    109         }
    110         return hb_font_reference(nullFaceFont);
    111     }
    112 
    113     HbFontCache* fontCache = getFontCacheLocked();
    114     const int32_t fontId = minikinFont->GetUniqueId();
    115     hb_font_t* font = fontCache->get(fontId);
    116     if (font != nullptr) {
    117         return hb_font_reference(font);
    118     }
    119 
    120     hb_face_t* face;
    121     const void* buf = minikinFont->GetFontData();
    122     if (buf == nullptr) {
    123         face = hb_face_create_for_tables(referenceTable, minikinFont, nullptr);
    124     } else {
    125         size_t size = minikinFont->GetFontSize();
    126         hb_blob_t* blob = hb_blob_create(reinterpret_cast<const char*>(buf), size,
    127             HB_MEMORY_MODE_READONLY, nullptr, nullptr);
    128         face = hb_face_create(blob, minikinFont->GetFontIndex());
    129         hb_blob_destroy(blob);
    130     }
    131     hb_font_t* parent_font = hb_font_create(face);
    132     hb_ot_font_set_funcs(parent_font);
    133 
    134     unsigned int upem = hb_face_get_upem(face);
    135     hb_font_set_scale(parent_font, upem, upem);
    136 
    137     font = hb_font_create_sub_font(parent_font);
    138     hb_font_destroy(parent_font);
    139     hb_face_destroy(face);
    140     fontCache->put(fontId, font);
    141     return hb_font_reference(font);
    142 }
    143 
    144 }  // namespace android
    145