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 package android.graphics; 18 19 import android.annotation.Nullable; 20 import android.content.res.AssetManager; 21 import android.graphics.fonts.FontVariationAxis; 22 import android.text.TextUtils; 23 import android.util.Log; 24 25 import dalvik.annotation.optimization.CriticalNative; 26 27 import libcore.util.NativeAllocationRegistry; 28 29 import java.io.FileInputStream; 30 import java.io.IOException; 31 import java.nio.ByteBuffer; 32 import java.nio.channels.FileChannel; 33 34 /** 35 * A family of typefaces with different styles. 36 * 37 * @hide 38 */ 39 public class FontFamily { 40 41 private static String TAG = "FontFamily"; 42 43 private static final NativeAllocationRegistry sBuilderRegistry = new NativeAllocationRegistry( 44 FontFamily.class.getClassLoader(), nGetBuilderReleaseFunc(), 64); 45 46 private @Nullable Runnable mNativeBuilderCleaner; 47 48 private static final NativeAllocationRegistry sFamilyRegistry = new NativeAllocationRegistry( 49 FontFamily.class.getClassLoader(), nGetFamilyReleaseFunc(), 64); 50 51 /** 52 * @hide 53 */ 54 public long mNativePtr; 55 56 // Points native font family builder. Must be zero after freezing this family. 57 private long mBuilderPtr; 58 59 public FontFamily() { 60 mBuilderPtr = nInitBuilder(null, 0); 61 mNativeBuilderCleaner = sBuilderRegistry.registerNativeAllocation(this, mBuilderPtr); 62 } 63 64 public FontFamily(@Nullable String[] langs, int variant) { 65 final String langsString; 66 if (langs == null || langs.length == 0) { 67 langsString = null; 68 } else if (langs.length == 1) { 69 langsString = langs[0]; 70 } else { 71 langsString = TextUtils.join(",", langs); 72 } 73 mBuilderPtr = nInitBuilder(langsString, variant); 74 mNativeBuilderCleaner = sBuilderRegistry.registerNativeAllocation(this, mBuilderPtr); 75 } 76 77 /** 78 * Finalize the FontFamily creation. 79 * 80 * @return boolean returns false if some error happens in native code, e.g. broken font file is 81 * passed, etc. 82 */ 83 public boolean freeze() { 84 if (mBuilderPtr == 0) { 85 throw new IllegalStateException("This FontFamily is already frozen"); 86 } 87 mNativePtr = nCreateFamily(mBuilderPtr); 88 mNativeBuilderCleaner.run(); 89 mBuilderPtr = 0; 90 if (mNativePtr != 0) { 91 sFamilyRegistry.registerNativeAllocation(this, mNativePtr); 92 } 93 return mNativePtr != 0; 94 } 95 96 public void abortCreation() { 97 if (mBuilderPtr == 0) { 98 throw new IllegalStateException("This FontFamily is already frozen or abandoned"); 99 } 100 mNativeBuilderCleaner.run(); 101 mBuilderPtr = 0; 102 } 103 104 public boolean addFont(String path, int ttcIndex, FontVariationAxis[] axes, int weight, 105 int italic) { 106 if (mBuilderPtr == 0) { 107 throw new IllegalStateException("Unable to call addFont after freezing."); 108 } 109 try (FileInputStream file = new FileInputStream(path)) { 110 FileChannel fileChannel = file.getChannel(); 111 long fontSize = fileChannel.size(); 112 ByteBuffer fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); 113 if (axes != null) { 114 for (FontVariationAxis axis : axes) { 115 nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue()); 116 } 117 } 118 return nAddFont(mBuilderPtr, fontBuffer, ttcIndex, weight, italic); 119 } catch (IOException e) { 120 Log.e(TAG, "Error mapping font file " + path); 121 return false; 122 } 123 } 124 125 public boolean addFontFromBuffer(ByteBuffer font, int ttcIndex, FontVariationAxis[] axes, 126 int weight, int italic) { 127 if (mBuilderPtr == 0) { 128 throw new IllegalStateException("Unable to call addFontWeightStyle after freezing."); 129 } 130 if (axes != null) { 131 for (FontVariationAxis axis : axes) { 132 nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue()); 133 } 134 } 135 return nAddFontWeightStyle(mBuilderPtr, font, ttcIndex, weight, italic); 136 } 137 138 /** 139 * @param mgr The AssetManager to use for this context. 140 * @param path The path to the font file to load. 141 * @param cookie If available, the resource cookie given by Resources. 142 * @param isAsset {@code true} if this is from the assets/ folder, {@code false} if from 143 * resources 144 * @param weight The weight of the font. If 0 is given, the weight and italic will be resolved 145 * using the OS/2 table in the font. 146 * @param isItalic Whether this font is italic. If the weight is set to 0, this will be resolved 147 * using the OS/2 table in the font. 148 * @return 149 */ 150 public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie, 151 boolean isAsset, int ttcIndex, int weight, int isItalic, 152 FontVariationAxis[] axes) { 153 if (mBuilderPtr == 0) { 154 throw new IllegalStateException("Unable to call addFontFromAsset after freezing."); 155 } 156 if (axes != null) { 157 for (FontVariationAxis axis : axes) { 158 nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue()); 159 } 160 } 161 return nAddFontFromAssetManager(mBuilderPtr, mgr, path, cookie, isAsset, ttcIndex, weight, 162 isItalic); 163 } 164 165 // TODO: Remove once internal user stop using private API. 166 private static boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex) { 167 return nAddFont(builderPtr, font, ttcIndex, -1, -1); 168 } 169 170 private static native long nInitBuilder(String langs, int variant); 171 172 @CriticalNative 173 private static native long nCreateFamily(long mBuilderPtr); 174 175 @CriticalNative 176 private static native long nGetBuilderReleaseFunc(); 177 178 @CriticalNative 179 private static native long nGetFamilyReleaseFunc(); 180 // By passing -1 to weigth argument, the weight value is resolved by OS/2 table in the font. 181 // By passing -1 to italic argument, the italic value is resolved by OS/2 table in the font. 182 private static native boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex, 183 int weight, int isItalic); 184 private static native boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font, 185 int ttcIndex, int weight, int isItalic); 186 private static native boolean nAddFontFromAssetManager(long builderPtr, AssetManager mgr, 187 String path, int cookie, boolean isAsset, int ttcIndex, int weight, int isItalic); 188 189 // The added axis values are only valid for the next nAddFont* method call. 190 @CriticalNative 191 private static native void nAddAxisValue(long builderPtr, int tag, float value); 192 } 193