Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2014 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 <nativehelper/JNIHelp.h>
     20 #include <core_jni_helpers.h>
     21 
     22 #include "SkData.h"
     23 #include "SkFontMgr.h"
     24 #include "SkRefCnt.h"
     25 #include "SkTypeface.h"
     26 #include "GraphicsJNI.h"
     27 #include <nativehelper/ScopedPrimitiveArray.h>
     28 #include <nativehelper/ScopedUtfChars.h>
     29 #include <android_runtime/AndroidRuntime.h>
     30 #include <android_runtime/android_util_AssetManager.h>
     31 #include <androidfw/AssetManager.h>
     32 #include "Utils.h"
     33 #include "FontUtils.h"
     34 
     35 #include <hwui/MinikinSkia.h>
     36 #include <hwui/Typeface.h>
     37 #include <utils/FatVector.h>
     38 #include <minikin/FontFamily.h>
     39 
     40 #include <memory>
     41 
     42 namespace android {
     43 
     44 struct NativeFamilyBuilder {
     45     NativeFamilyBuilder(uint32_t langId, int variant)
     46         : langId(langId), variant(variant), allowUnsupportedFont(false) {}
     47     uint32_t langId;
     48     int variant;
     49     bool allowUnsupportedFont;
     50     std::vector<minikin::Font> fonts;
     51     std::vector<minikin::FontVariation> axes;
     52 };
     53 
     54 static jlong FontFamily_initBuilder(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
     55     NativeFamilyBuilder* builder;
     56     if (lang != nullptr) {
     57         ScopedUtfChars str(env, lang);
     58         builder = new NativeFamilyBuilder(
     59                 minikin::FontStyle::registerLanguageList(str.c_str()), variant);
     60     } else {
     61         builder = new NativeFamilyBuilder(minikin::FontStyle::registerLanguageList(""), variant);
     62     }
     63     return reinterpret_cast<jlong>(builder);
     64 }
     65 
     66 static jlong FontFamily_create(jlong builderPtr) {
     67     if (builderPtr == 0) {
     68         return 0;
     69     }
     70     std::unique_ptr<NativeFamilyBuilder> builder(
     71             reinterpret_cast<NativeFamilyBuilder*>(builderPtr));
     72     std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
     73             builder->langId, builder->variant, std::move(builder->fonts));
     74     if (family->getCoverage().length() == 0 && !builder->allowUnsupportedFont) {
     75         return 0;
     76     }
     77     return reinterpret_cast<jlong>(new FontFamilyWrapper(std::move(family)));
     78 }
     79 
     80 static void FontFamily_allowUnsupportedFont(jlong builderPtr) {
     81     if (builderPtr == 0) {
     82         return;
     83     }
     84     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
     85     builder->allowUnsupportedFont = true;
     86 }
     87 
     88 static void FontFamily_abort(jlong builderPtr) {
     89     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
     90     delete builder;
     91 }
     92 
     93 static void FontFamily_unref(jlong familyPtr) {
     94     FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
     95     delete family;
     96 }
     97 
     98 static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
     99         jint givenWeight, jint givenItalic) {
    100     uirenderer::FatVector<SkFontMgr::FontParameters::Axis, 2> skiaAxes;
    101     for (const auto& axis : builder->axes) {
    102         skiaAxes.emplace_back(SkFontMgr::FontParameters::Axis{axis.axisTag, axis.value});
    103     }
    104 
    105     const size_t fontSize = data->size();
    106     const void* fontPtr = data->data();
    107     std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
    108 
    109     SkFontMgr::FontParameters params;
    110     params.setCollectionIndex(ttcIndex);
    111     params.setAxes(skiaAxes.data(), skiaAxes.size());
    112 
    113     sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
    114     sk_sp<SkTypeface> face(fm->createFromStream(fontData.release(), params));
    115     if (face == NULL) {
    116         ALOGE("addFont failed to create font, invalid request");
    117         builder->axes.clear();
    118         return false;
    119     }
    120     std::shared_ptr<minikin::MinikinFont> minikinFont =
    121             std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
    122                     builder->axes);
    123 
    124     int weight = givenWeight / 100;
    125     bool italic = givenItalic == 1;
    126     if (givenWeight == RESOLVE_BY_FONT_TABLE || givenItalic == RESOLVE_BY_FONT_TABLE) {
    127         int os2Weight;
    128         bool os2Italic;
    129         if (!minikin::FontFamily::analyzeStyle(minikinFont, &os2Weight, &os2Italic)) {
    130             ALOGE("analyzeStyle failed. Using default style");
    131             os2Weight = 4;
    132             os2Italic = false;
    133         }
    134         if (givenWeight == RESOLVE_BY_FONT_TABLE) {
    135             weight = os2Weight;
    136         }
    137         if (givenItalic == RESOLVE_BY_FONT_TABLE) {
    138             italic = os2Italic;
    139         }
    140     }
    141 
    142     builder->fonts.push_back(minikin::Font(minikinFont, minikin::FontStyle(weight, italic)));
    143     builder->axes.clear();
    144     return true;
    145 }
    146 
    147 static void release_global_ref(const void* /*data*/, void* context) {
    148     JNIEnv* env = AndroidRuntime::getJNIEnv();
    149     bool needToAttach = (env == NULL);
    150     if (needToAttach) {
    151         JavaVMAttachArgs args;
    152         args.version = JNI_VERSION_1_4;
    153         args.name = "release_font_data";
    154         args.group = NULL;
    155         jint result = AndroidRuntime::getJavaVM()->AttachCurrentThread(&env, &args);
    156         if (result != JNI_OK) {
    157             ALOGE("failed to attach to thread to release global ref.");
    158             return;
    159         }
    160     }
    161 
    162     jobject obj = reinterpret_cast<jobject>(context);
    163     env->DeleteGlobalRef(obj);
    164 
    165     if (needToAttach) {
    166        AndroidRuntime::getJavaVM()->DetachCurrentThread();
    167     }
    168 }
    169 
    170 static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong builderPtr, jobject bytebuf,
    171         jint ttcIndex, jint weight, jint isItalic) {
    172     NPE_CHECK_RETURN_ZERO(env, bytebuf);
    173     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
    174     const void* fontPtr = env->GetDirectBufferAddress(bytebuf);
    175     if (fontPtr == NULL) {
    176         ALOGE("addFont failed to create font, buffer invalid");
    177         builder->axes.clear();
    178         return false;
    179     }
    180     jlong fontSize = env->GetDirectBufferCapacity(bytebuf);
    181     if (fontSize < 0) {
    182         ALOGE("addFont failed to create font, buffer size invalid");
    183         builder->axes.clear();
    184         return false;
    185     }
    186     jobject fontRef = MakeGlobalRefOrDie(env, bytebuf);
    187     sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
    188             release_global_ref, reinterpret_cast<void*>(fontRef)));
    189     return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
    190 }
    191 
    192 static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong builderPtr,
    193         jobject font, jint ttcIndex, jint weight, jint isItalic) {
    194     NPE_CHECK_RETURN_ZERO(env, font);
    195     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
    196     const void* fontPtr = env->GetDirectBufferAddress(font);
    197     if (fontPtr == NULL) {
    198         ALOGE("addFont failed to create font, buffer invalid");
    199         builder->axes.clear();
    200         return false;
    201     }
    202     jlong fontSize = env->GetDirectBufferCapacity(font);
    203     if (fontSize < 0) {
    204         ALOGE("addFont failed to create font, buffer size invalid");
    205         builder->axes.clear();
    206         return false;
    207     }
    208     jobject fontRef = MakeGlobalRefOrDie(env, font);
    209     sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
    210             release_global_ref, reinterpret_cast<void*>(fontRef)));
    211     return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
    212 }
    213 
    214 static void releaseAsset(const void* ptr, void* context) {
    215     delete static_cast<Asset*>(context);
    216 }
    217 
    218 static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong builderPtr,
    219         jobject jassetMgr, jstring jpath, jint cookie, jboolean isAsset, jint ttcIndex,
    220         jint weight, jint isItalic) {
    221     NPE_CHECK_RETURN_ZERO(env, jassetMgr);
    222     NPE_CHECK_RETURN_ZERO(env, jpath);
    223 
    224     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
    225     AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
    226     if (NULL == mgr) {
    227         builder->axes.clear();
    228         return false;
    229     }
    230 
    231     ScopedUtfChars str(env, jpath);
    232     if (str.c_str() == nullptr) {
    233         builder->axes.clear();
    234         return false;
    235     }
    236 
    237     Asset* asset;
    238     if (isAsset) {
    239         asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
    240     } else {
    241         asset = cookie ? mgr->openNonAsset(static_cast<int32_t>(cookie), str.c_str(),
    242                 Asset::ACCESS_BUFFER) : mgr->openNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
    243     }
    244 
    245     if (NULL == asset) {
    246         builder->axes.clear();
    247         return false;
    248     }
    249 
    250     const void* buf = asset->getBuffer(false);
    251     if (NULL == buf) {
    252         delete asset;
    253         builder->axes.clear();
    254         return false;
    255     }
    256 
    257     sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset, asset));
    258     return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
    259 }
    260 
    261 static void FontFamily_addAxisValue(jlong builderPtr, jint tag, jfloat value) {
    262     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
    263     builder->axes.push_back({static_cast<minikin::AxisTag>(tag), value});
    264 }
    265 
    266 ///////////////////////////////////////////////////////////////////////////////
    267 
    268 static const JNINativeMethod gFontFamilyMethods[] = {
    269     { "nInitBuilder",          "(Ljava/lang/String;I)J", (void*)FontFamily_initBuilder },
    270     { "nCreateFamily",         "(J)J", (void*)FontFamily_create },
    271     { "nAllowUnsupportedFont", "(J)V", (void*)FontFamily_allowUnsupportedFont },
    272     { "nAbort",                "(J)V", (void*)FontFamily_abort },
    273     { "nUnrefFamily",          "(J)V", (void*)FontFamily_unref },
    274     { "nAddFont",              "(JLjava/nio/ByteBuffer;III)Z", (void*)FontFamily_addFont },
    275     { "nAddFontWeightStyle",   "(JLjava/nio/ByteBuffer;III)Z",
    276             (void*)FontFamily_addFontWeightStyle },
    277     { "nAddFontFromAssetManager",    "(JLandroid/content/res/AssetManager;Ljava/lang/String;IZIII)Z",
    278             (void*)FontFamily_addFontFromAssetManager },
    279     { "nAddAxisValue",         "(JIF)V", (void*)FontFamily_addAxisValue },
    280 };
    281 
    282 int register_android_graphics_FontFamily(JNIEnv* env)
    283 {
    284     int err = RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
    285             NELEM(gFontFamilyMethods));
    286 
    287     init_FontUtils(env);
    288     return err;
    289 }
    290 
    291 }
    292