11a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien/* 21a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * Copyright (C) 2014 The Android Open Source Project 31a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * 41a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * Licensed under the Apache License, Version 2.0 (the "License"); 51a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * you may not use this file except in compliance with the License. 61a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * You may obtain a copy of the License at 71a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * 81a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * http://www.apache.org/licenses/LICENSE-2.0 91a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * 101a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * Unless required by applicable law or agreed to in writing, software 111a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * distributed under the License is distributed on an "AS IS" BASIS, 121a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * See the License for the specific language governing permissions and 141a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * limitations under the License. 151a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien */ 161a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien 171a73f732f91e97c9c66b808c245ddda36a10e987Raph Levienpackage android.graphics; 181a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien 1999975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournaderimport android.annotation.Nullable; 20d573794d83a049fe59e289944f0cd77406dd776aRaph Levienimport android.content.res.AssetManager; 21ff55115121a7a2753ba2265cb3201a3a14c0874dSeigo Nonakaimport android.graphics.fonts.FontVariationAxis; 2299975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournaderimport android.text.TextUtils; 23296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levienimport android.util.Log; 2446dd24a710ee93ef9d75ea74e8a196e213f2e1daSiyamed Sinir 258b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonakaimport dalvik.annotation.optimization.CriticalNative; 26d573794d83a049fe59e289944f0cd77406dd776aRaph Levien 27abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonakaimport libcore.util.NativeAllocationRegistry; 28abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka 29296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levienimport java.io.FileInputStream; 30296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levienimport java.io.IOException; 31fb95699364e555148b437cfa1e5c69384f843845Ben Wagnerimport java.nio.ByteBuffer; 32296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levienimport java.nio.channels.FileChannel; 33a87b07d7fafd59ae26073a80cd742b17ea427ecdBen Wagner 341a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien/** 351a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * A family of typefaces with different styles. 361a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * 371a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * @hide 381a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien */ 391a73f732f91e97c9c66b808c245ddda36a10e987Raph Levienpublic class FontFamily { 40296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien 41296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien private static String TAG = "FontFamily"; 42296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien 43abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka private static final NativeAllocationRegistry sBuilderRegistry = new NativeAllocationRegistry( 44abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka FontFamily.class.getClassLoader(), nGetBuilderReleaseFunc(), 64); 45abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka 46abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka private @Nullable Runnable mNativeBuilderCleaner; 47abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka 48abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka private static final NativeAllocationRegistry sFamilyRegistry = new NativeAllocationRegistry( 49abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka FontFamily.class.getClassLoader(), nGetFamilyReleaseFunc(), 64); 50abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka 519a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien /** 529a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien * @hide 539a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien */ 541a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien public long mNativePtr; 559a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien 568b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka // Points native font family builder. Must be zero after freezing this family. 578b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka private long mBuilderPtr; 588b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka 591a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien public FontFamily() { 608b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka mBuilderPtr = nInitBuilder(null, 0); 61abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka mNativeBuilderCleaner = sBuilderRegistry.registerNativeAllocation(this, mBuilderPtr); 62f9e3d311275c37fe5f2562993687a1627780a6d0Raph Levien } 63f9e3d311275c37fe5f2562993687a1627780a6d0Raph Levien 6499975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader public FontFamily(@Nullable String[] langs, int variant) { 6599975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader final String langsString; 6699975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader if (langs == null || langs.length == 0) { 6799975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader langsString = null; 6899975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader } else if (langs.length == 1) { 6999975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader langsString = langs[0]; 7099975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader } else { 7199975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader langsString = TextUtils.join(",", langs); 7299975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader } 7399975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader mBuilderPtr = nInitBuilder(langsString, variant); 74abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka mNativeBuilderCleaner = sBuilderRegistry.registerNativeAllocation(this, mBuilderPtr); 758b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka } 768b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka 775b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka /** 785b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka * Finalize the FontFamily creation. 795b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka * 805b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka * @return boolean returns false if some error happens in native code, e.g. broken font file is 815b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka * passed, etc. 825b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka */ 835b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka public boolean freeze() { 848b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka if (mBuilderPtr == 0) { 858b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka throw new IllegalStateException("This FontFamily is already frozen"); 868b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka } 878b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka mNativePtr = nCreateFamily(mBuilderPtr); 88abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka mNativeBuilderCleaner.run(); 898b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka mBuilderPtr = 0; 90abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka if (mNativePtr != 0) { 91abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka sFamilyRegistry.registerNativeAllocation(this, mNativePtr); 92abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka } 935b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka return mNativePtr != 0; 948b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka } 958b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka 968b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka public void abortCreation() { 978b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka if (mBuilderPtr == 0) { 988b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka throw new IllegalStateException("This FontFamily is already frozen or abandoned"); 999a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien } 100abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka mNativeBuilderCleaner.run(); 1018b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka mBuilderPtr = 0; 1021a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien } 10315cf4757dc0099301662f8a26da561434cc07cfaRaph Levien 104ff55115121a7a2753ba2265cb3201a3a14c0874dSeigo Nonaka public boolean addFont(String path, int ttcIndex, FontVariationAxis[] axes, int weight, 10520e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka int italic) { 1068b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka if (mBuilderPtr == 0) { 1078b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka throw new IllegalStateException("Unable to call addFont after freezing."); 1088b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka } 109296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien try (FileInputStream file = new FileInputStream(path)) { 110296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien FileChannel fileChannel = file.getChannel(); 111296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien long fontSize = fileChannel.size(); 112296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien ByteBuffer fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); 11320e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka if (axes != null) { 114ff55115121a7a2753ba2265cb3201a3a14c0874dSeigo Nonaka for (FontVariationAxis axis : axes) { 115ff55115121a7a2753ba2265cb3201a3a14c0874dSeigo Nonaka nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue()); 11620e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka } 11720e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka } 11820e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka return nAddFont(mBuilderPtr, fontBuffer, ttcIndex, weight, italic); 119296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien } catch (IOException e) { 120296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien Log.e(TAG, "Error mapping font file " + path); 121296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien return false; 122296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien } 123d573794d83a049fe59e289944f0cd77406dd776aRaph Levien } 124d573794d83a049fe59e289944f0cd77406dd776aRaph Levien 125ff55115121a7a2753ba2265cb3201a3a14c0874dSeigo Nonaka public boolean addFontFromBuffer(ByteBuffer font, int ttcIndex, FontVariationAxis[] axes, 12620e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka int weight, int italic) { 1278b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka if (mBuilderPtr == 0) { 1288b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka throw new IllegalStateException("Unable to call addFontWeightStyle after freezing."); 1298b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka } 13020e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka if (axes != null) { 131ff55115121a7a2753ba2265cb3201a3a14c0874dSeigo Nonaka for (FontVariationAxis axis : axes) { 132ff55115121a7a2753ba2265cb3201a3a14c0874dSeigo Nonaka nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue()); 13320e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka } 134ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka } 13520e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka return nAddFontWeightStyle(mBuilderPtr, font, ttcIndex, weight, italic); 136117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien } 137117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien 138b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri /** 139b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri * @param mgr The AssetManager to use for this context. 140b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri * @param path The path to the font file to load. 141b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri * @param cookie If available, the resource cookie given by Resources. 142b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri * @param isAsset {@code true} if this is from the assets/ folder, {@code false} if from 143b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri * resources 144b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri * @param weight The weight of the font. If 0 is given, the weight and italic will be resolved 145b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri * using the OS/2 table in the font. 146b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri * @param isItalic Whether this font is italic. If the weight is set to 0, this will be resolved 147b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri * using the OS/2 table in the font. 148b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri * @return 149b44abf290190ceee037f24c47493a34de45fa3f4Clara Bayarri */ 15018e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie, 15120e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka boolean isAsset, int ttcIndex, int weight, int isItalic, 152ff55115121a7a2753ba2265cb3201a3a14c0874dSeigo Nonaka FontVariationAxis[] axes) { 1538b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka if (mBuilderPtr == 0) { 1548b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka throw new IllegalStateException("Unable to call addFontFromAsset after freezing."); 1558b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka } 15620e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka if (axes != null) { 157ff55115121a7a2753ba2265cb3201a3a14c0874dSeigo Nonaka for (FontVariationAxis axis : axes) { 158ff55115121a7a2753ba2265cb3201a3a14c0874dSeigo Nonaka nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue()); 15920e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka } 16020e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka } 16120e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka return nAddFontFromAssetManager(mBuilderPtr, mgr, path, cookie, isAsset, ttcIndex, weight, 16220e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka isItalic); 1631a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien } 1641a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien 1652660aca4912b4bd890c5c76688f67f1898dc7b97Seigo Nonaka // TODO: Remove once internal user stop using private API. 1662660aca4912b4bd890c5c76688f67f1898dc7b97Seigo Nonaka private static boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex) { 1672660aca4912b4bd890c5c76688f67f1898dc7b97Seigo Nonaka return nAddFont(builderPtr, font, ttcIndex, -1, -1); 1682660aca4912b4bd890c5c76688f67f1898dc7b97Seigo Nonaka } 1692660aca4912b4bd890c5c76688f67f1898dc7b97Seigo Nonaka 17099975a3e25e11f5c5958d8a901d37902087c75fdRoozbeh Pournader private static native long nInitBuilder(String langs, int variant); 1718b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka 1728b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka @CriticalNative 1738b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka private static native long nCreateFamily(long mBuilderPtr); 1748b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka 1758b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka @CriticalNative 176abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka private static native long nGetBuilderReleaseFunc(); 1778b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka 1788b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka @CriticalNative 179abe50314163dcc8faf05cf21d649899146bbdbdcSeigo Nonaka private static native long nGetFamilyReleaseFunc(); 18020e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka // By passing -1 to weigth argument, the weight value is resolved by OS/2 table in the font. 18120e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka // By passing -1 to italic argument, the italic value is resolved by OS/2 table in the font. 18220e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka private static native boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex, 18320e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka int weight, int isItalic); 1848b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka private static native boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font, 18520e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka int ttcIndex, int weight, int isItalic); 1868b48e624457e438fcc2b6b9363329036ef2f7743Seigo Nonaka private static native boolean nAddFontFromAssetManager(long builderPtr, AssetManager mgr, 18720e5d91739fb88a02afb4888bf9f938308bc9b7bSeigo Nonaka String path, int cookie, boolean isAsset, int ttcIndex, int weight, int isItalic); 188ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka 189ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka // The added axis values are only valid for the next nAddFont* method call. 190ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka @CriticalNative 191ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka private static native void nAddAxisValue(long builderPtr, int tag, float value); 1921a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien} 193