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 <log/log.h>
     22 #include <utils/LruCache.h>
     23 
     24 #include <hb.h>
     25 #include <hb-ot.h>
     26 
     27 #include <minikin/MinikinFont.h>
     28 #include "MinikinInternal.h"
     29 
     30 namespace minikin {
     31 
     32 class HbFontCache : private android::OnEntryRemoved<int32_t, hb_font_t*> {
     33 public:
     34     HbFontCache() : mCache(kMaxEntries) {
     35         mCache.setOnEntryRemovedListener(this);
     36     }
     37 
     38     // callback for OnEntryRemoved
     39     void operator()(int32_t& /* key */, hb_font_t*& value) {
     40         hb_font_destroy(value);
     41     }
     42 
     43     hb_font_t* get(int32_t fontId) {
     44         return mCache.get(fontId);
     45     }
     46 
     47     void put(int32_t fontId, hb_font_t* font) {
     48         mCache.put(fontId, font);
     49     }
     50 
     51     void clear() {
     52         mCache.clear();
     53     }
     54 
     55     void remove(int32_t fontId) {
     56         mCache.remove(fontId);
     57     }
     58 
     59 private:
     60     static const size_t kMaxEntries = 100;
     61 
     62     android::LruCache<int32_t, hb_font_t*> mCache;
     63 };
     64 
     65 HbFontCache* getFontCacheLocked() {
     66     assertMinikinLocked();
     67     static HbFontCache* cache = nullptr;
     68     if (cache == nullptr) {
     69         cache = new HbFontCache();
     70     }
     71     return cache;
     72 }
     73 
     74 void purgeHbFontCacheLocked() {
     75     assertMinikinLocked();
     76     getFontCacheLocked()->clear();
     77 }
     78 
     79 void purgeHbFontLocked(const MinikinFont* minikinFont) {
     80     assertMinikinLocked();
     81     const int32_t fontId = minikinFont->GetUniqueId();
     82     getFontCacheLocked()->remove(fontId);
     83 }
     84 
     85 // Returns a new reference to a hb_font_t object, caller is
     86 // responsible for calling hb_font_destroy() on it.
     87 hb_font_t* getHbFontLocked(const MinikinFont* minikinFont) {
     88     assertMinikinLocked();
     89     // TODO: get rid of nullFaceFont
     90     static hb_font_t* nullFaceFont = nullptr;
     91     if (minikinFont == nullptr) {
     92         if (nullFaceFont == nullptr) {
     93             nullFaceFont = hb_font_create(nullptr);
     94         }
     95         return hb_font_reference(nullFaceFont);
     96     }
     97 
     98     HbFontCache* fontCache = getFontCacheLocked();
     99     const int32_t fontId = minikinFont->GetUniqueId();
    100     hb_font_t* font = fontCache->get(fontId);
    101     if (font != nullptr) {
    102         return hb_font_reference(font);
    103     }
    104 
    105     hb_face_t* face;
    106     const void* buf = minikinFont->GetFontData();
    107     size_t size = minikinFont->GetFontSize();
    108     hb_blob_t* blob = hb_blob_create(reinterpret_cast<const char*>(buf), size,
    109         HB_MEMORY_MODE_READONLY, nullptr, nullptr);
    110     face = hb_face_create(blob, minikinFont->GetFontIndex());
    111     hb_blob_destroy(blob);
    112 
    113     hb_font_t* parent_font = hb_font_create(face);
    114     hb_ot_font_set_funcs(parent_font);
    115 
    116     unsigned int upem = hb_face_get_upem(face);
    117     hb_font_set_scale(parent_font, upem, upem);
    118 
    119     font = hb_font_create_sub_font(parent_font);
    120     std::vector<hb_variation_t> variations;
    121     for (const FontVariation& variation : minikinFont->GetAxes()) {
    122         variations.push_back({variation.axisTag, variation.value});
    123     }
    124     hb_font_set_variations(font, variations.data(), variations.size());
    125     hb_font_destroy(parent_font);
    126     hb_face_destroy(face);
    127     fontCache->put(fontId, font);
    128     return hb_font_reference(font);
    129 }
    130 
    131 }  // namespace minikin
    132