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 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