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::FamilyVariant>(variant)) {} 48 uint32_t langId; 49 minikin::FamilyVariant 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 true /* isCustomFallback */); 88 if (family->getCoverage().length() == 0) { 89 return 0; 90 } 91 return toJLong(new FontFamilyWrapper(std::move(family))); 92 } 93 94 static void releaseBuilder(jlong builderPtr) { 95 delete toNativeBuilder(builderPtr); 96 } 97 98 static jlong FontFamily_getBuilderReleaseFunc() { 99 return toJLong(&releaseBuilder); 100 } 101 102 static void releaseFamily(jlong familyPtr) { 103 delete toFamily(familyPtr); 104 } 105 106 static jlong FontFamily_getFamilyReleaseFunc() { 107 return toJLong(&releaseFamily); 108 } 109 110 static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex, 111 jint weight, jint italic) { 112 uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes; 113 for (const auto& axis : builder->axes) { 114 skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value}); 115 } 116 117 const size_t fontSize = data->size(); 118 const void* fontPtr = data->data(); 119 std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data))); 120 121 SkFontArguments params; 122 params.setCollectionIndex(ttcIndex); 123 params.setAxes(skiaAxes.data(), skiaAxes.size()); 124 125 sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault()); 126 sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), params)); 127 if (face == NULL) { 128 ALOGE("addFont failed to create font, invalid request"); 129 builder->axes.clear(); 130 return false; 131 } 132 std::shared_ptr<minikin::MinikinFont> minikinFont = 133 std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, "", ttcIndex, 134 builder->axes); 135 minikin::Font::Builder fontBuilder(minikinFont); 136 137 if (weight != RESOLVE_BY_FONT_TABLE) { 138 fontBuilder.setWeight(weight); 139 } 140 if (italic != RESOLVE_BY_FONT_TABLE) { 141 fontBuilder.setSlant(static_cast<minikin::FontStyle::Slant>(italic != 0)); 142 } 143 builder->fonts.push_back(fontBuilder.build()); 144 builder->axes.clear(); 145 return true; 146 } 147 148 static void release_global_ref(const void* /*data*/, void* context) { 149 JNIEnv* env = AndroidRuntime::getJNIEnv(); 150 bool needToAttach = (env == NULL); 151 if (needToAttach) { 152 JavaVMAttachArgs args; 153 args.version = JNI_VERSION_1_4; 154 args.name = "release_font_data"; 155 args.group = NULL; 156 jint result = AndroidRuntime::getJavaVM()->AttachCurrentThread(&env, &args); 157 if (result != JNI_OK) { 158 ALOGE("failed to attach to thread to release global ref."); 159 return; 160 } 161 } 162 163 jobject obj = reinterpret_cast<jobject>(context); 164 env->DeleteGlobalRef(obj); 165 166 if (needToAttach) { 167 AndroidRuntime::getJavaVM()->DetachCurrentThread(); 168 } 169 } 170 171 static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong builderPtr, jobject bytebuf, 172 jint ttcIndex, jint weight, jint isItalic) { 173 NPE_CHECK_RETURN_ZERO(env, bytebuf); 174 NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr); 175 const void* fontPtr = env->GetDirectBufferAddress(bytebuf); 176 if (fontPtr == NULL) { 177 ALOGE("addFont failed to create font, buffer invalid"); 178 builder->axes.clear(); 179 return false; 180 } 181 jlong fontSize = env->GetDirectBufferCapacity(bytebuf); 182 if (fontSize < 0) { 183 ALOGE("addFont failed to create font, buffer size invalid"); 184 builder->axes.clear(); 185 return false; 186 } 187 jobject fontRef = MakeGlobalRefOrDie(env, bytebuf); 188 sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize, 189 release_global_ref, reinterpret_cast<void*>(fontRef))); 190 return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic); 191 } 192 193 static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong builderPtr, 194 jobject font, jint ttcIndex, jint weight, jint isItalic) { 195 NPE_CHECK_RETURN_ZERO(env, font); 196 NativeFamilyBuilder* builder = toNativeBuilder(builderPtr); 197 const void* fontPtr = env->GetDirectBufferAddress(font); 198 if (fontPtr == NULL) { 199 ALOGE("addFont failed to create font, buffer invalid"); 200 builder->axes.clear(); 201 return false; 202 } 203 jlong fontSize = env->GetDirectBufferCapacity(font); 204 if (fontSize < 0) { 205 ALOGE("addFont failed to create font, buffer size invalid"); 206 builder->axes.clear(); 207 return false; 208 } 209 jobject fontRef = MakeGlobalRefOrDie(env, font); 210 sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize, 211 release_global_ref, reinterpret_cast<void*>(fontRef))); 212 return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic); 213 } 214 215 static void releaseAsset(const void* ptr, void* context) { 216 delete static_cast<Asset*>(context); 217 } 218 219 static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong builderPtr, 220 jobject jassetMgr, jstring jpath, jint cookie, jboolean isAsset, jint ttcIndex, 221 jint weight, jint isItalic) { 222 NPE_CHECK_RETURN_ZERO(env, jassetMgr); 223 NPE_CHECK_RETURN_ZERO(env, jpath); 224 225 NativeFamilyBuilder* builder = toNativeBuilder(builderPtr); 226 Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(env, jassetMgr); 227 if (NULL == mgr) { 228 builder->axes.clear(); 229 return false; 230 } 231 232 ScopedUtfChars str(env, jpath); 233 if (str.c_str() == nullptr) { 234 builder->axes.clear(); 235 return false; 236 } 237 238 std::unique_ptr<Asset> asset; 239 { 240 ScopedLock<AssetManager2> locked_mgr(*mgr); 241 if (isAsset) { 242 asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER); 243 } else if (cookie > 0) { 244 // Valid java cookies are 1-based, but AssetManager cookies are 0-based. 245 asset = locked_mgr->OpenNonAsset(str.c_str(), static_cast<ApkAssetsCookie>(cookie - 1), 246 Asset::ACCESS_BUFFER); 247 } else { 248 asset = locked_mgr->OpenNonAsset(str.c_str(), Asset::ACCESS_BUFFER); 249 } 250 } 251 252 if (nullptr == asset) { 253 builder->axes.clear(); 254 return false; 255 } 256 257 const void* buf = asset->getBuffer(false); 258 if (NULL == buf) { 259 builder->axes.clear(); 260 return false; 261 } 262 263 sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset, 264 asset.release())); 265 return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic); 266 } 267 268 static void FontFamily_addAxisValue(jlong builderPtr, jint tag, jfloat value) { 269 NativeFamilyBuilder* builder = toNativeBuilder(builderPtr); 270 builder->axes.push_back({static_cast<minikin::AxisTag>(tag), value}); 271 } 272 273 /////////////////////////////////////////////////////////////////////////////// 274 275 static const JNINativeMethod gFontFamilyMethods[] = { 276 { "nInitBuilder", "(Ljava/lang/String;I)J", (void*)FontFamily_initBuilder }, 277 { "nCreateFamily", "(J)J", (void*)FontFamily_create }, 278 { "nGetBuilderReleaseFunc", "()J", (void*)FontFamily_getBuilderReleaseFunc }, 279 { "nGetFamilyReleaseFunc", "()J", (void*)FontFamily_getFamilyReleaseFunc }, 280 { "nAddFont", "(JLjava/nio/ByteBuffer;III)Z", (void*)FontFamily_addFont }, 281 { "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;III)Z", 282 (void*)FontFamily_addFontWeightStyle }, 283 { "nAddFontFromAssetManager", "(JLandroid/content/res/AssetManager;Ljava/lang/String;IZIII)Z", 284 (void*)FontFamily_addFontFromAssetManager }, 285 { "nAddAxisValue", "(JIF)V", (void*)FontFamily_addAxisValue }, 286 }; 287 288 int register_android_graphics_FontFamily(JNIEnv* env) 289 { 290 int err = RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods, 291 NELEM(gFontFamilyMethods)); 292 293 init_FontUtils(env); 294 return err; 295 } 296 297 } 298