FontFamily.cpp revision a7f6bba1a3565c19715e878dfe7f0e01022944ff
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 "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 <ScopedPrimitiveArray.h> 28#include <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 34#include <hwui/MinikinSkia.h> 35#include <hwui/TypefaceImpl.h> 36#include <minikin/FontFamily.h> 37 38#include <memory> 39 40namespace android { 41 42static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) { 43 if (lang == NULL) { 44 return (jlong)new FontFamily(variant); 45 } 46 ScopedUtfChars str(env, lang); 47 uint32_t langId = FontStyle::registerLanguageList(str.c_str()); 48 return (jlong)new FontFamily(langId, variant); 49} 50 51static void FontFamily_unref(JNIEnv* env, jobject clazz, jlong familyPtr) { 52 FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr); 53 fontFamily->Unref(); 54} 55 56static jboolean addSkTypeface(FontFamily* family, SkTypeface* face) { 57 MinikinFont* minikinFont = new MinikinFontSkia(face); 58 bool result = family->addFont(minikinFont); 59 minikinFont->Unref(); 60 return result; 61} 62 63static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr, jstring path, 64 jint ttcIndex) { 65 NPE_CHECK_RETURN_ZERO(env, path); 66 ScopedUtfChars str(env, path); 67 SkTypeface* face = SkTypeface::CreateFromFile(str.c_str(), ttcIndex); 68 if (face == NULL) { 69 ALOGE("addFont failed to create font %s", str.c_str()); 70 return false; 71 } 72 FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr); 73 return addSkTypeface(fontFamily, face); 74} 75 76static struct { 77 jmethodID mGet; 78 jmethodID mSize; 79} gListClassInfo; 80 81static struct { 82 jfieldID mTag; 83 jfieldID mStyleValue; 84} gAxisClassInfo; 85 86static void release_global_ref(const void* /*data*/, void* context) { 87 JNIEnv* env = AndroidRuntime::getJNIEnv(); 88 bool needToAttach = (env == NULL); 89 if (needToAttach) { 90 JavaVMAttachArgs args; 91 args.version = JNI_VERSION_1_4; 92 args.name = "release_font_data"; 93 args.group = NULL; 94 jint result = AndroidRuntime::getJavaVM()->AttachCurrentThread(&env, &args); 95 if (result != JNI_OK) { 96 ALOGE("failed to attach to thread to release global ref."); 97 return; 98 } 99 } 100 101 jobject obj = reinterpret_cast<jobject>(context); 102 env->DeleteGlobalRef(obj); 103 104 if (needToAttach) { 105 AndroidRuntime::getJavaVM()->DetachCurrentThread(); 106 } 107} 108 109static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr, 110 jobject font, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) { 111 NPE_CHECK_RETURN_ZERO(env, font); 112 113 // Declare axis native type. 114 std::unique_ptr<SkFontMgr::FontParameters::Axis[]> skiaAxes; 115 int skiaAxesLength = 0; 116 if (listOfAxis) { 117 jint listSize = env->CallIntMethod(listOfAxis, gListClassInfo.mSize); 118 119 skiaAxes.reset(new SkFontMgr::FontParameters::Axis[listSize]); 120 skiaAxesLength = listSize; 121 for (jint i = 0; i < listSize; ++i) { 122 jobject axisObject = env->CallObjectMethod(listOfAxis, gListClassInfo.mGet, i); 123 if (!axisObject) { 124 skiaAxes[i].fTag = 0; 125 skiaAxes[i].fStyleValue = 0; 126 continue; 127 } 128 129 jint tag = env->GetIntField(axisObject, gAxisClassInfo.mTag); 130 jfloat stylevalue = env->GetFloatField(axisObject, gAxisClassInfo.mStyleValue); 131 skiaAxes[i].fTag = tag; 132 skiaAxes[i].fStyleValue = SkFloatToScalar(stylevalue); 133 } 134 } 135 136 void* fontPtr = env->GetDirectBufferAddress(font); 137 if (fontPtr == NULL) { 138 ALOGE("addFont failed to create font, buffer invalid"); 139 return false; 140 } 141 jlong fontSize = env->GetDirectBufferCapacity(font); 142 if (fontSize < 0) { 143 ALOGE("addFont failed to create font, buffer size invalid"); 144 return false; 145 } 146 jobject fontRef = MakeGlobalRefOrDie(env, font); 147 SkAutoTUnref<SkData> data(SkData::NewWithProc(fontPtr, fontSize, 148 release_global_ref, reinterpret_cast<void*>(fontRef))); 149 std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(data)); 150 151 SkFontMgr::FontParameters params; 152 params.setCollectionIndex(ttcIndex); 153 params.setAxes(skiaAxes.get(), skiaAxesLength); 154 155 SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault()); 156 SkTypeface* face = fm->createFromStream(fontData.release(), params); 157 if (face == NULL) { 158 ALOGE("addFont failed to create font, invalid request"); 159 return false; 160 } 161 FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr); 162 MinikinFont* minikinFont = new MinikinFontSkia(face); 163 fontFamily->addFont(minikinFont, FontStyle(weight / 100, isItalic)); 164 minikinFont->Unref(); 165 return true; 166} 167 168static void releaseAsset(const void* ptr, void* context) { 169 delete static_cast<Asset*>(context); 170} 171 172static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPtr, 173 jobject jassetMgr, jstring jpath) { 174 NPE_CHECK_RETURN_ZERO(env, jassetMgr); 175 NPE_CHECK_RETURN_ZERO(env, jpath); 176 177 AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr); 178 if (NULL == mgr) { 179 return false; 180 } 181 182 ScopedUtfChars str(env, jpath); 183 Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER); 184 if (NULL == asset) { 185 return false; 186 } 187 188 const void* buf = asset->getBuffer(false); 189 if (NULL == buf) { 190 delete asset; 191 return false; 192 } 193 194 SkAutoTUnref<SkData> data(SkData::NewWithProc(buf, asset->getLength(), releaseAsset, asset)); 195 SkMemoryStream* stream = new SkMemoryStream(data); 196 // CreateFromStream takes ownership of stream. 197 SkTypeface* face = SkTypeface::CreateFromStream(stream); 198 if (face == NULL) { 199 ALOGE("addFontFromAsset failed to create font %s", str.c_str()); 200 return false; 201 } 202 FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr); 203 return addSkTypeface(fontFamily, face); 204} 205 206/////////////////////////////////////////////////////////////////////////////// 207 208static const JNINativeMethod gFontFamilyMethods[] = { 209 { "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create }, 210 { "nUnrefFamily", "(J)V", (void*)FontFamily_unref }, 211 { "nAddFont", "(JLjava/lang/String;I)Z", (void*)FontFamily_addFont }, 212 { "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z", 213 (void*)FontFamily_addFontWeightStyle }, 214 { "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z", 215 (void*)FontFamily_addFontFromAsset }, 216}; 217 218int register_android_graphics_FontFamily(JNIEnv* env) 219{ 220 int err = RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods, 221 NELEM(gFontFamilyMethods)); 222 223 jclass listClass = FindClassOrDie(env, "java/util/List"); 224 gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;"); 225 gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I"); 226 227 jclass axisClass = FindClassOrDie(env, "android/graphics/FontListParser$Axis"); 228 gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "tag", "I"); 229 gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "styleValue", "F"); 230 231 return err; 232} 233 234} 235