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/AssetManager2.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 #include <minikin/LocaleList.h>
     40 
     41 #include <memory>
     42 
     43 namespace android {
     44 
     45 struct NativeFamilyBuilder {
     46     NativeFamilyBuilder(uint32_t langId, int variant)
     47         : langId(langId), variant(static_cast<minikin::FontFamily::Variant>(variant)) {}
     48     uint32_t langId;
     49     minikin::FontFamily::Variant variant;
     50     std::vector<minikin::Font> fonts;
     51     std::vector<minikin::FontVariation> axes;
     52 };
     53 
     54 static inline NativeFamilyBuilder* toNativeBuilder(jlong ptr) {
     55     return reinterpret_cast<NativeFamilyBuilder*>(ptr);
     56 }
     57 
     58 static inline FontFamilyWrapper* toFamily(jlong ptr) {
     59     return reinterpret_cast<FontFamilyWrapper*>(ptr);
     60 }
     61 
     62 template<typename Ptr> static inline jlong toJLong(Ptr ptr) {
     63     return reinterpret_cast<jlong>(ptr);
     64 }
     65 
     66 static jlong FontFamily_initBuilder(JNIEnv* env, jobject clazz, jstring langs, jint variant) {
     67     NativeFamilyBuilder* builder;
     68     if (langs != nullptr) {
     69         ScopedUtfChars str(env, langs);
     70         builder = new NativeFamilyBuilder(minikin::registerLocaleList(str.c_str()), variant);
     71     } else {
     72         builder = new NativeFamilyBuilder(minikin::registerLocaleList(""), variant);
     73     }
     74     return toJLong(builder);
     75 }
     76 
     77 static jlong FontFamily_create(jlong builderPtr) {
     78     if (builderPtr == 0) {
     79         return 0;
     80     }
     81     NativeFamilyBuilder* builder = toNativeBuilder(builderPtr);
     82     if (builder->fonts.empty()) {
     83         return 0;
     84     }
     85     std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
     86             builder->langId, builder->variant, std::move(builder->fonts));
     87     if (family->getCoverage().length() == 0) {
     88         return 0;
     89     }
     90     return toJLong(new FontFamilyWrapper(std::move(family)));
     91 }
     92 
     93 static void releaseBuilder(jlong builderPtr) {
     94     delete toNativeBuilder(builderPtr);
     95 }
     96 
     97 static jlong FontFamily_getBuilderReleaseFunc() {
     98     return toJLong(&releaseBuilder);
     99 }
    100 
    101 static void releaseFamily(jlong familyPtr) {
    102     delete toFamily(familyPtr);
    103 }
    104 
    105 static jlong FontFamily_getFamilyReleaseFunc() {
    106     return toJLong(&releaseFamily);
    107 }
    108 
    109 static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
    110         jint weight, jint italic) {
    111     uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
    112     for (const auto& axis : builder->axes) {
    113         skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
    114     }
    115 
    116     const size_t fontSize = data->size();
    117     const void* fontPtr = data->data();
    118     std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
    119 
    120     SkFontArguments params;
    121     params.setCollectionIndex(ttcIndex);
    122     params.setAxes(skiaAxes.data(), skiaAxes.size());
    123 
    124     sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
    125     sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), params));
    126     if (face == NULL) {
    127         ALOGE("addFont failed to create font, invalid request");
    128         builder->axes.clear();
    129         return false;
    130     }
    131     std::shared_ptr<minikin::MinikinFont> minikinFont =
    132             std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
    133                     builder->axes);
    134     minikin::Font::Builder fontBuilder(minikinFont);
    135 
    136     if (weight != RESOLVE_BY_FONT_TABLE) {
    137         fontBuilder.setWeight(weight);
    138     }
    139     if (italic != RESOLVE_BY_FONT_TABLE) {
    140         fontBuilder.setSlant(static_cast<minikin::FontStyle::Slant>(italic != 0));
    141     }
    142     builder->fonts.push_back(fontBuilder.build());
    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 = toNativeBuilder(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 = toNativeBuilder(builderPtr);
    225     Guarded<AssetManager2>* 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     std::unique_ptr<Asset> asset;
    238     {
    239       ScopedLock<AssetManager2> locked_mgr(*mgr);
    240       if (isAsset) {
    241           asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
    242       } else if (cookie > 0) {
    243           // Valid java cookies are 1-based, but AssetManager cookies are 0-based.
    244           asset = locked_mgr->OpenNonAsset(str.c_str(), static_cast<ApkAssetsCookie>(cookie - 1),
    245                   Asset::ACCESS_BUFFER);
    246       } else {
    247           asset = locked_mgr->OpenNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
    248       }
    249     }
    250 
    251     if (nullptr == asset) {
    252         builder->axes.clear();
    253         return false;
    254     }
    255 
    256     const void* buf = asset->getBuffer(false);
    257     if (NULL == buf) {
    258         builder->axes.clear();
    259         return false;
    260     }
    261 
    262     sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset,
    263             asset.release()));
    264     return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
    265 }
    266 
    267 static void FontFamily_addAxisValue(jlong builderPtr, jint tag, jfloat value) {
    268     NativeFamilyBuilder* builder = toNativeBuilder(builderPtr);
    269     builder->axes.push_back({static_cast<minikin::AxisTag>(tag), value});
    270 }
    271 
    272 ///////////////////////////////////////////////////////////////////////////////
    273 
    274 static const JNINativeMethod gFontFamilyMethods[] = {
    275     { "nInitBuilder",           "(Ljava/lang/String;I)J", (void*)FontFamily_initBuilder },
    276     { "nCreateFamily",          "(J)J", (void*)FontFamily_create },
    277     { "nGetBuilderReleaseFunc", "()J", (void*)FontFamily_getBuilderReleaseFunc },
    278     { "nGetFamilyReleaseFunc",  "()J", (void*)FontFamily_getFamilyReleaseFunc },
    279     { "nAddFont",               "(JLjava/nio/ByteBuffer;III)Z", (void*)FontFamily_addFont },
    280     { "nAddFontWeightStyle",    "(JLjava/nio/ByteBuffer;III)Z",
    281             (void*)FontFamily_addFontWeightStyle },
    282     { "nAddFontFromAssetManager",    "(JLandroid/content/res/AssetManager;Ljava/lang/String;IZIII)Z",
    283             (void*)FontFamily_addFontFromAssetManager },
    284     { "nAddAxisValue",         "(JIF)V", (void*)FontFamily_addAxisValue },
    285 };
    286 
    287 int register_android_graphics_FontFamily(JNIEnv* env)
    288 {
    289     int err = RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
    290             NELEM(gFontFamilyMethods));
    291 
    292     init_FontUtils(env);
    293     return err;
    294 }
    295 
    296 }
    297