OSDN Git Service

Fix boot loop issue on Android Wear.
[android-x86/frameworks-base.git] / graphics / java / android / graphics / Typeface.java
1 /*
2  * Copyright (C) 2006 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 static android.content.res.FontResourcesParser.ProviderResourceEntry;
20 import static android.content.res.FontResourcesParser.FontFileResourceEntry;
21 import static android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry;
22 import static android.content.res.FontResourcesParser.FamilyResourceEntry;
23
24 import static java.lang.annotation.RetentionPolicy.SOURCE;
25
26 import android.annotation.IntDef;
27 import android.annotation.IntRange;
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.content.Context;
31 import android.content.res.AssetManager;
32 import android.graphics.FontListParser;
33 import android.graphics.fonts.FontRequest;
34 import android.graphics.fonts.FontResult;
35 import android.graphics.fonts.FontVariationAxis;
36 import android.graphics.fonts.FontVariationAxis.InvalidFormatException;
37 import android.net.Uri;
38 import android.os.Bundle;
39 import android.os.Handler;
40 import android.os.ParcelFileDescriptor;
41 import android.os.ResultReceiver;
42 import android.provider.FontsContract;
43 import android.text.FontConfig;
44 import android.util.Base64;
45 import android.util.Log;
46 import android.util.LongSparseArray;
47 import android.util.LruCache;
48 import android.util.SparseArray;
49
50 import com.android.internal.annotations.GuardedBy;
51 import com.android.internal.util.Preconditions;
52
53 import libcore.io.IoUtils;
54
55 import org.xmlpull.v1.XmlPullParserException;
56
57 import java.io.File;
58 import java.io.FileDescriptor;
59 import java.io.FileInputStream;
60 import java.io.FileNotFoundException;
61 import java.io.IOException;
62 import java.lang.annotation.Retention;
63 import java.lang.annotation.RetentionPolicy;
64 import java.nio.ByteBuffer;
65 import java.nio.channels.FileChannel;
66 import java.util.Arrays;
67 import java.util.ArrayList;
68 import java.util.Arrays;
69 import java.util.Collections;
70 import java.util.HashMap;
71 import java.util.List;
72 import java.util.Map;
73 import java.util.concurrent.atomic.AtomicReference;
74
75 /**
76  * The Typeface class specifies the typeface and intrinsic style of a font.
77  * This is used in the paint, along with optionally Paint settings like
78  * textSize, textSkewX, textScaleX to specify
79  * how text appears when drawn (and measured).
80  */
81 public class Typeface {
82
83     private static String TAG = "Typeface";
84
85     /** The default NORMAL typeface object */
86     public static final Typeface DEFAULT;
87     /**
88      * The default BOLD typeface object. Note: this may be not actually be
89      * bold, depending on what fonts are installed. Call getStyle() to know
90      * for sure.
91      */
92     public static final Typeface DEFAULT_BOLD;
93     /** The NORMAL style of the default sans serif typeface. */
94     public static final Typeface SANS_SERIF;
95     /** The NORMAL style of the default serif typeface. */
96     public static final Typeface SERIF;
97     /** The NORMAL style of the default monospace typeface. */
98     public static final Typeface MONOSPACE;
99
100     static Typeface[] sDefaults;
101     private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache =
102             new LongSparseArray<>(3);
103     @GuardedBy("sLock")
104     private static FontsContract sFontsContract;
105     @GuardedBy("sLock")
106     private static Handler sHandler;
107
108     /**
109      * Cache for Typeface objects dynamically loaded from assets. Currently max size is 16.
110      */
111     @GuardedBy("sLock")
112     private static final LruCache<String, Typeface> sDynamicTypefaceCache = new LruCache<>(16);
113
114     static Typeface sDefaultTypeface;
115     static Map<String, Typeface> sSystemFontMap;
116     static FontFamily[] sFallbackFonts;
117     private static final Object sLock = new Object();
118
119     static final String FONTS_CONFIG = "fonts.xml";
120
121     /**
122      * @hide
123      */
124     public long native_instance;
125
126     // Style
127     public static final int NORMAL = 0;
128     public static final int BOLD = 1;
129     public static final int ITALIC = 2;
130     public static final int BOLD_ITALIC = 3;
131
132     private int mStyle = 0;
133     private int mBaseWeight = 0;
134
135     // Value for weight and italic. Indicates the value is resolved by font metadata.
136     // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
137     /** @hide */
138     public static final int RESOLVE_BY_FONT_TABLE = -1;
139
140     // Style value for building typeface.
141     private static final int STYLE_NORMAL = 0;
142     private static final int STYLE_ITALIC = 1;
143
144     private int[] mSupportedAxes;
145     private static final int[] EMPTY_AXES = {};
146
147     private static void setDefault(Typeface t) {
148         sDefaultTypeface = t;
149         nativeSetDefault(t.native_instance);
150     }
151
152     /** Returns the typeface's intrinsic style attributes */
153     public int getStyle() {
154         return mStyle;
155     }
156
157     /** Returns true if getStyle() has the BOLD bit set. */
158     public final boolean isBold() {
159         return (mStyle & BOLD) != 0;
160     }
161
162     /** Returns true if getStyle() has the ITALIC bit set. */
163     public final boolean isItalic() {
164         return (mStyle & ITALIC) != 0;
165     }
166
167     /**
168      * @hide
169      * Used by Resources to load a font resource of type font file.
170      */
171     @Nullable
172     public static Typeface createFromResources(AssetManager mgr, String path, int cookie) {
173         if (sFallbackFonts != null) {
174             synchronized (sDynamicTypefaceCache) {
175                 final String key = Builder.createAssetUid(
176                         mgr, path, 0 /* ttcIndex */, null /* axes */);
177                 Typeface typeface = sDynamicTypefaceCache.get(key);
178                 if (typeface != null) return typeface;
179
180                 FontFamily fontFamily = new FontFamily();
181                 // TODO: introduce ttc index and variation settings to resource type font.
182                 if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */,
183                         0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */,
184                         RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) {
185                     if (!fontFamily.freeze()) {
186                         return null;
187                     }
188                     FontFamily[] families = {fontFamily};
189                     typeface = createFromFamiliesWithDefault(families);
190                     sDynamicTypefaceCache.put(key, typeface);
191                     return typeface;
192                 }
193             }
194         }
195         return null;
196     }
197
198     /**
199      * @hide
200      * Used by Resources to load a font resource of type xml.
201      */
202     @Nullable
203     public static Typeface createFromResources(
204             FamilyResourceEntry entry, AssetManager mgr, String path) {
205         if (sFallbackFonts != null) {
206             Typeface typeface = findFromCache(mgr, path);
207             if (typeface != null) return typeface;
208
209             if (entry instanceof ProviderResourceEntry) {
210                 final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry;
211                 // Downloadable font
212                 typeface = findFromCache(providerEntry.getAuthority(), providerEntry.getQuery());
213                 if (typeface != null) {
214                     return typeface;
215                 }
216                 List<List<String>> givenCerts = providerEntry.getCerts();
217                 List<List<byte[]>> certs = new ArrayList<>();
218                 if (givenCerts != null) {
219                     for (int i = 0; i < givenCerts.size(); i++) {
220                         List<String> certSet = givenCerts.get(i);
221                         List<byte[]> byteArraySet = new ArrayList<>();
222                         for (int j = 0; j < certSet.size(); j++) {
223                             byteArraySet.add(Base64.decode(certSet.get(j), Base64.DEFAULT));
224                         }
225                         certs.add(byteArraySet);
226                     }
227                 }
228                 // Downloaded font and it wasn't cached, request it again and return a
229                 // default font instead (nothing we can do now).
230                 create(new FontRequest(providerEntry.getAuthority(), providerEntry.getPackage(),
231                         providerEntry.getQuery(), certs), NO_OP_REQUEST_CALLBACK);
232                 return DEFAULT;
233             }
234
235             // family is FontFamilyFilesResourceEntry
236             final FontFamilyFilesResourceEntry filesEntry =
237                     (FontFamilyFilesResourceEntry) entry;
238
239             FontFamily fontFamily = new FontFamily();
240             for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
241                 if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(),
242                         0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */,
243                         fontFile.getWeight(), fontFile.isItalic() ? STYLE_ITALIC : STYLE_NORMAL,
244                         null /* axes */)) {
245                     return null;
246                 }
247             }
248             // Due to backward compatibility, even if the font is not supported by our font stack,
249             // we need to place the empty font at the first place. The typeface with empty font
250             // behaves different from default typeface especially in fallback font selection.
251             fontFamily.allowUnsupportedFont();
252             fontFamily.freeze();
253             FontFamily[] familyChain = { fontFamily };
254             typeface = createFromFamiliesWithDefault(familyChain);
255             synchronized (sDynamicTypefaceCache) {
256                 final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
257                         null /* axes */);
258                 sDynamicTypefaceCache.put(key, typeface);
259             }
260             return typeface;
261         }
262         return null;
263     }
264
265     /**
266      * Used by resources for cached loading if the font is available.
267      * @hide
268      */
269     public static Typeface findFromCache(AssetManager mgr, String path) {
270         synchronized (sDynamicTypefaceCache) {
271             final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, null /* axes */);
272             Typeface typeface = sDynamicTypefaceCache.get(key);
273             if (typeface != null) {
274                 return typeface;
275             }
276         }
277         return null;
278     }
279
280     /**
281      * Set the application context so we can generate font requests from the provider. This should
282      * be called from ActivityThread when the application binds, as we preload fonts.
283      * @hide
284      */
285     public static void setApplicationContext(Context context) {
286         synchronized (sLock) {
287             if (sFontsContract == null) {
288                 sFontsContract = new FontsContract(context);
289                 sHandler = new Handler();
290             }
291         }
292     }
293
294     /**
295      * Create a typeface object given a font request. The font will be asynchronously fetched,
296      * therefore the result is delivered to the given callback. See {@link FontRequest}.
297      * Only one of the methods in callback will be invoked, depending on whether the request
298      * succeeds or fails. These calls will happen on the main thread.
299      * @param request A {@link FontRequest} object that identifies the provider and query for the
300      *                request. May not be null.
301      * @param callback A callback that will be triggered when results are obtained. May not be null.
302      */
303     @Deprecated
304     public static void create(@NonNull FontRequest request, @NonNull FontRequestCallback callback) {
305         // Check the cache first
306         // TODO: would the developer want to avoid a cache hit and always ask for the freshest
307         // result?
308         Typeface cachedTypeface = findFromCache(
309                 request.getProviderAuthority(), request.getQuery());
310         if (cachedTypeface != null) {
311             sHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface));
312             return;
313         }
314         synchronized (sLock) {
315             if (sFontsContract == null) {
316                 throw new RuntimeException("Context not initialized, can't query provider");
317             }
318             final ResultReceiver receiver = new ResultReceiver(null) {
319                 @Override
320                 public void onReceiveResult(int resultCode, Bundle resultData) {
321                     sHandler.post(() -> receiveResult(request, callback, resultCode, resultData));
322                 }
323             };
324             sFontsContract.getFont(request, receiver);
325         }
326     }
327
328     private static Typeface findFromCache(String providerAuthority, String query) {
329         synchronized (sDynamicTypefaceCache) {
330             final String key = createProviderUid(providerAuthority, query);
331             Typeface typeface = sDynamicTypefaceCache.get(key);
332             if (typeface != null) {
333                 return typeface;
334             }
335         }
336         return null;
337     }
338
339     private static void receiveResult(FontRequest request, FontRequestCallback callback,
340             int resultCode, Bundle resultData) {
341         Typeface cachedTypeface = findFromCache(
342                 request.getProviderAuthority(), request.getQuery());
343         if (cachedTypeface != null) {
344             // We already know the result.
345             // Probably the requester requests the same font again in a short interval.
346             callback.onTypefaceRetrieved(cachedTypeface);
347             return;
348         }
349         if (resultCode != FontsContract.Columns.RESULT_CODE_OK) {
350             callback.onTypefaceRequestFailed(resultCode);
351             return;
352         }
353         if (resultData == null) {
354             callback.onTypefaceRequestFailed(
355                     FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND);
356             return;
357         }
358         List<FontResult> resultList =
359                 resultData.getParcelableArrayList(FontsContract.PARCEL_FONT_RESULTS);
360         if (resultList == null || resultList.isEmpty()) {
361             callback.onTypefaceRequestFailed(
362                     FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND);
363             return;
364         }
365         FontFamily fontFamily = new FontFamily();
366         for (int i = 0; i < resultList.size(); ++i) {
367             FontResult result = resultList.get(i);
368             ParcelFileDescriptor fd = result.getFileDescriptor();
369             if (fd == null) {
370                 callback.onTypefaceRequestFailed(
371                         FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
372                 return;
373             }
374             try (FileInputStream is = new FileInputStream(fd.getFileDescriptor())) {
375                 FileChannel fileChannel = is.getChannel();
376                 long fontSize = fileChannel.size();
377                 ByteBuffer fontBuffer = fileChannel.map(
378                         FileChannel.MapMode.READ_ONLY, 0, fontSize);
379                 int weight = result.getWeight();
380                 int italic = result.getItalic() ? STYLE_ITALIC : STYLE_NORMAL;
381                 FontVariationAxis[] axes = null;
382                 try {
383                     axes = FontVariationAxis.fromFontVariationSettings(
384                             result.getFontVariationSettings());
385                 } catch (FontVariationAxis.InvalidFormatException e) {
386                     // TODO: Nice to pass FontVariationAxis[] directly instead of string.
387                 }
388                 if (!fontFamily.addFontFromBuffer(fontBuffer, result.getTtcIndex(),
389                         axes, weight, italic)) {
390                     Log.e(TAG, "Error creating font " + request.getQuery());
391                     callback.onTypefaceRequestFailed(
392                             FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
393                     return;
394                 }
395             } catch (IOException e) {
396                 Log.e(TAG, "Error reading font " + request.getQuery(), e);
397                 callback.onTypefaceRequestFailed(
398                         FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
399                 return;
400             } finally {
401                 IoUtils.closeQuietly(fd);
402             }
403         }
404         if (!fontFamily.freeze()) {
405             callback.onTypefaceRequestFailed(
406                     FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
407             return;
408         }
409         Typeface typeface = Typeface.createFromFamiliesWithDefault(new FontFamily[] { fontFamily });
410         synchronized (sDynamicTypefaceCache) {
411             String key = createProviderUid(request.getProviderAuthority(), request.getQuery());
412             sDynamicTypefaceCache.put(key, typeface);
413         }
414         callback.onTypefaceRetrieved(typeface);
415     }
416
417     /**
418      * Interface used to receive asynchronously fetched typefaces.
419      */
420     @Deprecated
421     public interface FontRequestCallback {
422         /**
423          * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
424          * provider was not found on the device.
425          */
426         int FAIL_REASON_PROVIDER_NOT_FOUND = FontsContract.RESULT_CODE_PROVIDER_NOT_FOUND;
427         /**
428          * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
429          * provider must be authenticated and the given certificates do not match its signature.
430          */
431         int FAIL_REASON_WRONG_CERTIFICATES = FontsContract.RESULT_CODE_WRONG_CERTIFICATES;
432         /**
433          * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
434          * returned by the provider was not loaded properly.
435          */
436         int FAIL_REASON_FONT_LOAD_ERROR = -3;
437         /**
438          * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
439          * provider did not return any results for the given query.
440          */
441         int FAIL_REASON_FONT_NOT_FOUND = FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
442         /**
443          * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
444          * provider found the queried font, but it is currently unavailable.
445          */
446         int FAIL_REASON_FONT_UNAVAILABLE = FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
447         /**
448          * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
449          * query was not supported by the provider.
450          */
451         int FAIL_REASON_MALFORMED_QUERY = FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
452
453         /** @hide */
454         @IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
455                 FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE,
456                 FAIL_REASON_MALFORMED_QUERY })
457         @Retention(RetentionPolicy.SOURCE)
458         @interface FontRequestFailReason {}
459
460         /**
461          * Called then a Typeface request done via {@link Typeface#create(FontRequest,
462          * FontRequestCallback)} is complete. Note that this method will not be called if
463          * {@link #onTypefaceRequestFailed(int)} is called instead.
464          * @param typeface  The Typeface object retrieved.
465          */
466         void onTypefaceRetrieved(Typeface typeface);
467
468         /**
469          * Called when a Typeface request done via {@link Typeface#create(FontRequest,
470          * FontRequestCallback)} fails.
471          * @param reason One of {@link #FAIL_REASON_PROVIDER_NOT_FOUND},
472          *               {@link #FAIL_REASON_FONT_NOT_FOUND},
473          *               {@link #FAIL_REASON_FONT_LOAD_ERROR},
474          *               {@link #FAIL_REASON_FONT_UNAVAILABLE} or
475          *               {@link #FAIL_REASON_MALFORMED_QUERY}.
476          */
477         void onTypefaceRequestFailed(@FontRequestFailReason int reason);
478     }
479
480     private static final FontRequestCallback NO_OP_REQUEST_CALLBACK = new FontRequestCallback() {
481         @Override
482         public void onTypefaceRetrieved(Typeface typeface) {
483             // Do nothing.
484         }
485
486         @Override
487         public void onTypefaceRequestFailed(@FontRequestFailReason int reason) {
488             // Do nothing.
489         }
490     };
491
492     /**
493      * A builder class for creating new Typeface instance.
494      *
495      * <p>
496      * Examples,
497      * 1) Create Typeface from ttf file.
498      * <pre>
499      * <code>
500      * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf");
501      * Typeface typeface = builder.build();
502      * </code>
503      * </pre>
504      *
505      * 2) Create Typeface from ttc file in assets directory.
506      * <pre>
507      * <code>
508      * Typeface.Builder buidler = new Typeface.Builder(getAssets(), "your_font_file.ttc");
509      * builder.setTtcIndex(2);  // Set index of font collection.
510      * Typeface typeface = builder.build();
511      * </code>
512      * </pre>
513      *
514      * 3) Create Typeface with variation settings.
515      * <pre>
516      * <code>
517      * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf");
518      * builder.setFontVariationSettings("'wght' 700, 'slnt' 20, 'ital' 1");
519      * builder.setWeight(700);  // Tell the system that this is a bold font.
520      * builder.setItalic(true);  // Tell the system that this is an italic style font.
521      * Typeface typeface = builder.build();
522      * </code>
523      * </pre>
524      * </p>
525      */
526     public static final class Builder {
527         /** @hide */
528         public static final int NORMAL_WEIGHT = 400;
529         /** @hide */
530         public static final int BOLD_WEIGHT = 700;
531
532         private int mTtcIndex;
533         private FontVariationAxis[] mAxes;
534
535         private AssetManager mAssetManager;
536         private String mPath;
537         private FileDescriptor mFd;
538
539         private FontsContract.FontInfo[] mFonts;
540         private Map<Uri, ByteBuffer> mFontBuffers;
541
542         private String mFallbackFamilyName;
543
544         private int mWeight = RESOLVE_BY_FONT_TABLE;
545         private int mItalic = RESOLVE_BY_FONT_TABLE;
546
547         /**
548          * Constructs a builder with a file path.
549          *
550          * @param path The file object refers to the font file.
551          */
552         public Builder(@NonNull File path) {
553             mPath = path.getAbsolutePath();
554         }
555
556         /**
557          * Constructs a builder with a file descriptor.
558          *
559          * @param fd The file descriptor. The passed fd must be mmap-able.
560          */
561         public Builder(@NonNull FileDescriptor fd) {
562             mFd = fd;
563         }
564
565         /**
566          * Constructs a builder with a file path.
567          *
568          * @param path The full path to the font file.
569          */
570         public Builder(@NonNull String path) {
571             mPath = path;
572         }
573
574         /**
575          * Constructs a builder from an asset manager and a file path in an asset directory.
576          *
577          * @param assetManager The application's asset manager
578          * @param path The file name of the font data in the asset directory
579          */
580         public Builder(@NonNull AssetManager assetManager, @NonNull String path) {
581             mAssetManager = Preconditions.checkNotNull(assetManager);
582             mPath = Preconditions.checkStringNotEmpty(path);
583         }
584
585         /**
586          * Constracts a builder from an array of FontsContract.FontInfo.
587          *
588          * Since {@link FontsContract.FontInfo} holds information about TTC indices and
589          * variation settings, there is no need to call {@link #setTtcIndex} or
590          * {@link #setFontVariationSettings}. Similary, {@link FontsContract.FontInfo} holds
591          * weight and italic information, so {@link #setWeight} and {@link #setItalic} are used
592          * for style matching during font selection.
593          *
594          * @param results The array of {@link FontsContract.FontInfo}
595          * @param buffers The mapping from URI to buffers to be used during building.
596          * @hide
597          */
598         public Builder(@NonNull FontsContract.FontInfo[] fonts,
599                 @NonNull Map<Uri, ByteBuffer> buffers) {
600             mFonts = fonts;
601             mFontBuffers = buffers;
602         }
603
604         /**
605          * Sets weight of the font.
606          *
607          * Tells the system the weight of the given font. If not provided, the system will resolve
608          * the weight value by reading font tables.
609          * @param weight a weight value.
610          */
611         public Builder setWeight(@IntRange(from = 1, to = 1000) int weight) {
612             mWeight = weight;
613             return this;
614         }
615
616         /**
617          * Sets italic information of the font.
618          *
619          * Tells the system the style of the given font. If not provided, the system will resolve
620          * the style by reading font tables.
621          * @param italic {@code true} if the font is italic. Otherwise {@code false}.
622          */
623         public Builder setItalic(boolean italic) {
624             mItalic = italic ? STYLE_ITALIC : STYLE_NORMAL;
625             return this;
626         }
627
628         /**
629          * Sets an index of the font collection.
630          *
631          * Can not be used for Typeface source. build() method will return null for invalid index.
632          * @param ttcIndex An index of the font collection. If the font source is not font
633          *                 collection, do not call this method or specify 0.
634          */
635         public Builder setTtcIndex(@IntRange(from = 0) int ttcIndex) {
636             if (mFonts != null) {
637                 throw new IllegalArgumentException(
638                         "TTC index can not be specified for FontResult source.");
639             }
640             mTtcIndex = ttcIndex;
641             return this;
642         }
643
644         /**
645          * Sets a font variation settings.
646          *
647          * @param variationSettings See {@link android.widget.TextView#setFontVariationSettings}.
648          * @throws InvalidFormatException If given string is not a valid font variation settings
649          *                                format.
650          */
651         public Builder setFontVariationSettings(@Nullable String variationSettings)
652                 throws InvalidFormatException {
653             if (mFonts != null) {
654                 throw new IllegalArgumentException(
655                         "Font variation settings can not be specified for FontResult source.");
656             }
657             if (mAxes != null) {
658                 throw new IllegalStateException("Font variation settings are already set.");
659             }
660             mAxes = FontVariationAxis.fromFontVariationSettings(variationSettings);
661             return this;
662         }
663
664         /**
665          * Sets a font variation settings.
666          *
667          * @param axes An array of font variation axis tag-value pairs.
668          */
669         public Builder setFontVariationSettings(@Nullable FontVariationAxis[] axes) {
670             if (mFonts != null) {
671                 throw new IllegalArgumentException(
672                         "Font variation settings can not be specified for FontResult source.");
673             }
674             if (mAxes != null) {
675                 throw new IllegalStateException("Font variation settings are already set.");
676             }
677             mAxes = axes;
678             return this;
679         }
680
681         /**
682          * Sets a fallback family name.
683          *
684          * By specifying a fallback family name, a fallback Typeface will be returned if the
685          * {@link #build} method fails to create a Typeface from the provided font. The fallback
686          * family will be resolved with the provided weight and italic information specified by
687          * {@link #setWeight} and {@link #setItalic}.
688          *
689          * If {@link #setWeight} is not called, the fallback family keeps the default weight.
690          * Similary, if {@link #setItalic} is not called, the fallback family keeps the default
691          * italic information. For example, calling {@code builder.setFallback("sans-serif-light")}
692          * is equivalent to calling {@code builder.setFallback("sans-serif").setWeight(300)} in
693          * terms of fallback. The default weight and italic information are overridden by calling
694          * {@link #setWeight} and {@link #setItalic}. For example, if a Typeface is constructed
695          * using {@code builder.setFallback("sans-serif-light").setWeight(700)}, the fallback text
696          * will render as sans serif bold.
697          *
698          * @param familyName A family name to be used for fallback if the provided font can not be
699          *                   used. By passing {@code null}, build() returns {@code null}.
700          *                   If {@link #setFallback} is not called on the builder, {@code null}
701          *                   is assumed.
702          */
703         public Builder setFallback(@Nullable String familyName) {
704             mFallbackFamilyName = familyName;
705             return this;
706         }
707
708         /**
709          * Creates a unique id for a given AssetManager and asset path.
710          *
711          * @param mgr  AssetManager instance
712          * @param path The path for the asset.
713          * @param ttcIndex The TTC index for the font.
714          * @param axes The font variation settings.
715          * @return Unique id for a given AssetManager and asset path.
716          */
717         private static String createAssetUid(final AssetManager mgr, String path, int ttcIndex,
718                 @Nullable FontVariationAxis[] axes) {
719             final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers();
720             final StringBuilder builder = new StringBuilder();
721             final int size = pkgs.size();
722             for (int i = 0; i < size; i++) {
723                 builder.append(pkgs.valueAt(i));
724                 builder.append("-");
725             }
726             builder.append(path);
727             builder.append("-");
728             builder.append(Integer.toString(ttcIndex));
729             builder.append("-");
730             if (axes != null) {
731                 for (FontVariationAxis axis : axes) {
732                     builder.append(axis.getTag());
733                     builder.append("-");
734                     builder.append(Float.toString(axis.getStyleValue()));
735                 }
736             }
737             return builder.toString();
738         }
739
740         private static final Object sLock = new Object();
741         // TODO: Unify with Typeface.sTypefaceCache.
742         @GuardedBy("sLock")
743         private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache =
744                 new LongSparseArray<>(3);
745
746         private Typeface resolveFallbackTypeface() {
747             if (mFallbackFamilyName == null) {
748                 return null;
749             }
750
751             Typeface base =  sSystemFontMap.get(mFallbackFamilyName);
752             if (base == null) {
753                 base = sDefaultTypeface;
754             }
755
756             if (mWeight == RESOLVE_BY_FONT_TABLE && mItalic == RESOLVE_BY_FONT_TABLE) {
757                 return base;
758             }
759
760             final int weight = (mWeight == RESOLVE_BY_FONT_TABLE) ? base.mBaseWeight : mWeight;
761             final boolean italic =
762                     (mItalic == RESOLVE_BY_FONT_TABLE) ? (base.mStyle & ITALIC) != 0 : mItalic == 1;
763             final int key = weight << 1 | (italic ? 1 : 0);
764
765             Typeface typeface;
766             synchronized(sLock) {
767                 SparseArray<Typeface> innerCache = sTypefaceCache.get(base.native_instance);
768                 if (innerCache != null) {
769                     typeface = innerCache.get(key);
770                     if (typeface != null) {
771                         return typeface;
772                     }
773                 }
774
775                 typeface = new Typeface(
776                         nativeCreateFromTypefaceWithExactStyle(
777                                 base.native_instance, weight, italic));
778
779                 if (innerCache == null) {
780                     innerCache = new SparseArray<>(4); // [regular, bold] x [upright, italic]
781                     sTypefaceCache.put(base.native_instance, innerCache);
782                 }
783                 innerCache.put(key, typeface);
784             }
785             return typeface;
786         }
787
788         /**
789          * Generates new Typeface from specified configuration.
790          *
791          * @return Newly created Typeface. May return null if some parameters are invalid.
792          */
793         public Typeface build() {
794             if (mFd != null) {  // set source by setSourceFromFile(FileDescriptor)
795                 try (FileInputStream fis = new FileInputStream(mFd)) {
796                     FileChannel channel = fis.getChannel();
797                     long size = channel.size();
798                     ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
799
800                     final FontFamily fontFamily = new FontFamily();
801                     if (!fontFamily.addFontFromBuffer(buffer, mTtcIndex, mAxes, mWeight, mItalic)) {
802                         fontFamily.abortCreation();
803                         return resolveFallbackTypeface();
804                     }
805                     if (!fontFamily.freeze()) {
806                         return resolveFallbackTypeface();
807                     }
808                     FontFamily[] families = { fontFamily };
809                     return createFromFamiliesWithDefault(families);
810                 } catch (IOException e) {
811                     return resolveFallbackTypeface();
812                 }
813             } else if (mAssetManager != null) {  // set source by setSourceFromAsset()
814                 final String key = createAssetUid(mAssetManager, mPath, mTtcIndex, mAxes);
815                 synchronized (sLock) {
816                     Typeface typeface = sDynamicTypefaceCache.get(key);
817                     if (typeface != null) return typeface;
818                     final FontFamily fontFamily = new FontFamily();
819                     if (!fontFamily.addFontFromAssetManager(mAssetManager, mPath, mTtcIndex,
820                             true /* isAsset */, mTtcIndex, mWeight, mItalic, mAxes)) {
821                         fontFamily.abortCreation();
822                         return resolveFallbackTypeface();
823                     }
824                     if (!fontFamily.freeze()) {
825                         return resolveFallbackTypeface();
826                     }
827                     FontFamily[] families = { fontFamily };
828                     typeface = createFromFamiliesWithDefault(families);
829                     sDynamicTypefaceCache.put(key, typeface);
830                     return typeface;
831                 }
832             } else if (mPath != null) {  // set source by setSourceFromFile(File)
833                 final FontFamily fontFamily = new FontFamily();
834                 if (!fontFamily.addFont(mPath, mTtcIndex, mAxes, mWeight, mItalic)) {
835                     fontFamily.abortCreation();
836                     return resolveFallbackTypeface();
837                 }
838                 if (!fontFamily.freeze()) {
839                     return resolveFallbackTypeface();
840                 }
841                 FontFamily[] families = { fontFamily };
842                 return createFromFamiliesWithDefault(families);
843             } else if (mFonts != null) {
844                 final FontFamily fontFamily = new FontFamily();
845                 boolean atLeastOneFont = false;
846                 for (FontsContract.FontInfo font : mFonts) {
847                     final ByteBuffer fontBuffer = mFontBuffers.get(font.getUri());
848                     if (fontBuffer == null) {
849                         continue;  // skip
850                     }
851                     final boolean success = fontFamily.addFontFromBuffer(fontBuffer,
852                             font.getTtcIndex(), font.getAxes(), font.getWeight(),
853                             font.isItalic() ? STYLE_ITALIC : STYLE_NORMAL);
854                     if (!success) {
855                         fontFamily.abortCreation();
856                         return null;
857                     }
858                     atLeastOneFont = true;
859                 }
860                 if (!atLeastOneFont) {
861                     // No fonts are avaialble. No need to create new Typeface and returns fallback
862                     // Typeface instead.
863                     fontFamily.abortCreation();
864                     return null;
865                 }
866                 fontFamily.freeze();
867                 FontFamily[] families = { fontFamily };
868                 return createFromFamiliesWithDefault(families);
869             }
870
871             // Must not reach here.
872             throw new IllegalArgumentException("No source was set.");
873         }
874     }
875
876     /**
877      * Create a typeface object given a family name, and option style information.
878      * If null is passed for the name, then the "default" font will be chosen.
879      * The resulting typeface object can be queried (getStyle()) to discover what
880      * its "real" style characteristics are.
881      *
882      * @param familyName May be null. The name of the font family.
883      * @param style  The style (normal, bold, italic) of the typeface.
884      *               e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
885      * @return The best matching typeface.
886      */
887     public static Typeface create(String familyName, int style) {
888         if (sSystemFontMap != null) {
889             return create(sSystemFontMap.get(familyName), style);
890         }
891         return null;
892     }
893
894     /**
895      * Create a typeface object that best matches the specified existing
896      * typeface and the specified Style. Use this call if you want to pick a new
897      * style from the same family of an existing typeface object. If family is
898      * null, this selects from the default font's family.
899      *
900      * @param family May be null. The name of the existing type face.
901      * @param style  The style (normal, bold, italic) of the typeface.
902      *               e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
903      * @return The best matching typeface.
904      */
905     public static Typeface create(Typeface family, int style) {
906         if (style < 0 || style > 3) {
907             style = 0;
908         }
909         long ni = 0;
910         if (family != null) {
911             // Return early if we're asked for the same face/style
912             if (family.mStyle == style) {
913                 return family;
914             }
915
916             ni = family.native_instance;
917         }
918
919         Typeface typeface;
920         SparseArray<Typeface> styles = sTypefaceCache.get(ni);
921
922         if (styles != null) {
923             typeface = styles.get(style);
924             if (typeface != null) {
925                 return typeface;
926             }
927         }
928
929         typeface = new Typeface(nativeCreateFromTypeface(ni, style));
930         if (styles == null) {
931             styles = new SparseArray<Typeface>(4);
932             sTypefaceCache.put(ni, styles);
933         }
934         styles.put(style, typeface);
935
936         return typeface;
937     }
938
939     /** @hide */
940     public static Typeface createFromTypefaceWithVariation(Typeface family,
941             List<FontVariationAxis> axes) {
942         final long ni = family == null ? 0 : family.native_instance;
943         return new Typeface(nativeCreateFromTypefaceWithVariation(ni, axes));
944     }
945
946     /**
947      * Returns one of the default typeface objects, based on the specified style
948      *
949      * @return the default typeface that corresponds to the style
950      */
951     public static Typeface defaultFromStyle(int style) {
952         return sDefaults[style];
953     }
954
955     /**
956      * Create a new typeface from the specified font data.
957      *
958      * @param mgr  The application's asset manager
959      * @param path The file name of the font data in the assets directory
960      * @return The new typeface.
961      */
962     public static Typeface createFromAsset(AssetManager mgr, String path) {
963         if (path == null) {
964             throw new NullPointerException();  // for backward compatibility
965         }
966         if (sFallbackFonts != null) {
967             synchronized (sLock) {
968                 Typeface typeface = new Builder(mgr, path).build();
969                 if (typeface != null) return typeface;
970
971                 final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
972                         null /* axes */);
973                 typeface = sDynamicTypefaceCache.get(key);
974                 if (typeface != null) return typeface;
975
976                 final FontFamily fontFamily = new FontFamily();
977                 if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */,
978                         0 /* ttc index */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE,
979                         null /* axes */)) {
980                     // Due to backward compatibility, even if the font is not supported by our font
981                     // stack, we need to place the empty font at the first place. The typeface with
982                     // empty font behaves different from default typeface especially in fallback
983                     // font selection.
984                     fontFamily.allowUnsupportedFont();
985                     fontFamily.freeze();
986                     final FontFamily[] families = { fontFamily };
987                     typeface = createFromFamiliesWithDefault(families);
988                     sDynamicTypefaceCache.put(key, typeface);
989                     return typeface;
990                 } else {
991                     fontFamily.abortCreation();
992                 }
993             }
994         }
995         throw new RuntimeException("Font asset not found " + path);
996     }
997
998     /**
999      * Creates a unique id for a given font provider and query.
1000      */
1001     private static String createProviderUid(String authority, String query) {
1002         final StringBuilder builder = new StringBuilder();
1003         builder.append("provider:");
1004         builder.append(authority);
1005         builder.append("-");
1006         builder.append(query);
1007         return builder.toString();
1008     }
1009
1010     /**
1011      * Create a new typeface from the specified font file.
1012      *
1013      * @param path The path to the font data.
1014      * @return The new typeface.
1015      */
1016     public static Typeface createFromFile(@Nullable File path) {
1017         // For the compatibility reasons, leaving possible NPE here.
1018         // See android.graphics.cts.TypefaceTest#testCreateFromFileByFileReferenceNull
1019         return createFromFile(path.getAbsolutePath());
1020     }
1021
1022     /**
1023      * Create a new typeface from the specified font file.
1024      *
1025      * @param path The full path to the font data.
1026      * @return The new typeface.
1027      */
1028     public static Typeface createFromFile(@Nullable String path) {
1029         if (sFallbackFonts != null) {
1030             final FontFamily fontFamily = new FontFamily();
1031             if (fontFamily.addFont(path, 0 /* ttcIndex */, null /* axes */,
1032                       RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)) {
1033                 // Due to backward compatibility, even if the font is not supported by our font
1034                 // stack, we need to place the empty font at the first place. The typeface with
1035                 // empty font behaves different from default typeface especially in fallback font
1036                 // selection.
1037                 fontFamily.allowUnsupportedFont();
1038                 fontFamily.freeze();
1039                 FontFamily[] families = { fontFamily };
1040                 return createFromFamiliesWithDefault(families);
1041             } else {
1042                 fontFamily.abortCreation();
1043             }
1044         }
1045         throw new RuntimeException("Font not found " + path);
1046     }
1047
1048     /**
1049      * Create a new typeface from an array of font families.
1050      *
1051      * @param families array of font families
1052      */
1053     private static Typeface createFromFamilies(FontFamily[] families) {
1054         long[] ptrArray = new long[families.length];
1055         for (int i = 0; i < families.length; i++) {
1056             ptrArray[i] = families[i].mNativePtr;
1057         }
1058         return new Typeface(nativeCreateFromArray(ptrArray));
1059     }
1060
1061     /**
1062      * Create a new typeface from an array of font families, including
1063      * also the font families in the fallback list.
1064      *
1065      * @param families array of font families
1066      */
1067     private static Typeface createFromFamiliesWithDefault(FontFamily[] families) {
1068         long[] ptrArray = new long[families.length + sFallbackFonts.length];
1069         for (int i = 0; i < families.length; i++) {
1070             ptrArray[i] = families[i].mNativePtr;
1071         }
1072         for (int i = 0; i < sFallbackFonts.length; i++) {
1073             ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr;
1074         }
1075         return new Typeface(nativeCreateFromArray(ptrArray));
1076     }
1077
1078     // don't allow clients to call this directly
1079     private Typeface(long ni) {
1080         if (ni == 0) {
1081             throw new RuntimeException("native typeface cannot be made");
1082         }
1083
1084         native_instance = ni;
1085         mStyle = nativeGetStyle(ni);
1086         mBaseWeight = nativeGetBaseWeight(ni);
1087     }
1088
1089     private static FontFamily makeFamilyFromParsed(FontConfig.Family family,
1090             Map<String, ByteBuffer> bufferForPath) {
1091         FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
1092         for (FontConfig.Font font : family.getFonts()) {
1093             String fullPathName = "/system/fonts/" + font.getFontName();
1094             ByteBuffer fontBuffer = bufferForPath.get(fullPathName);
1095             if (fontBuffer == null) {
1096                 try (FileInputStream file = new FileInputStream(fullPathName)) {
1097                     FileChannel fileChannel = file.getChannel();
1098                     long fontSize = fileChannel.size();
1099                     fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
1100                     bufferForPath.put(fullPathName, fontBuffer);
1101                 } catch (IOException e) {
1102                     Log.e(TAG, "Error mapping font file " + fullPathName);
1103                     continue;
1104                 }
1105             }
1106             if (!fontFamily.addFontFromBuffer(fontBuffer, font.getTtcIndex(), font.getAxes(),
1107                     font.getWeight(), font.isItalic() ? STYLE_ITALIC : STYLE_NORMAL)) {
1108                 Log.e(TAG, "Error creating font " + fullPathName + "#" + font.getTtcIndex());
1109             }
1110         }
1111         if (!fontFamily.freeze()) {
1112             // Treat as system error since reaching here means that a system pre-installed font
1113             // can't be used by our font stack.
1114             Log.e(TAG, "Unable to load Family: " + family.getName() + ":" + family.getLanguage());
1115             return null;
1116         }
1117         return fontFamily;
1118     }
1119
1120     /*
1121      * (non-Javadoc)
1122      *
1123      * This should only be called once, from the static class initializer block.
1124      */
1125     private static void init() {
1126         // Load font config and initialize Minikin state
1127         File systemFontConfigLocation = getSystemFontConfigLocation();
1128         File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
1129         try {
1130             FileInputStream fontsIn = new FileInputStream(configFilename);
1131             FontConfig fontConfig = FontListParser.parse(fontsIn);
1132
1133             Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>();
1134
1135             List<FontFamily> familyList = new ArrayList<FontFamily>();
1136             // Note that the default typeface is always present in the fallback list;
1137             // this is an enhancement from pre-Minikin behavior.
1138             for (int i = 0; i < fontConfig.getFamilies().length; i++) {
1139                 FontConfig.Family f = fontConfig.getFamilies()[i];
1140                 if (i == 0 || f.getName() == null) {
1141                     FontFamily family = makeFamilyFromParsed(f, bufferForPath);
1142                     if (family != null) {
1143                         familyList.add(family);
1144                     }
1145                 }
1146             }
1147             sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
1148             setDefault(Typeface.createFromFamilies(sFallbackFonts));
1149
1150             Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
1151             for (int i = 0; i < fontConfig.getFamilies().length; i++) {
1152                 Typeface typeface;
1153                 FontConfig.Family f = fontConfig.getFamilies()[i];
1154                 if (f.getName() != null) {
1155                     if (i == 0) {
1156                         // The first entry is the default typeface; no sense in
1157                         // duplicating the corresponding FontFamily.
1158                         typeface = sDefaultTypeface;
1159                     } else {
1160                         FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath);
1161                         if (fontFamily == null) {
1162                             continue;
1163                         }
1164                         FontFamily[] families = { fontFamily };
1165                         typeface = Typeface.createFromFamiliesWithDefault(families);
1166                     }
1167                     systemFonts.put(f.getName(), typeface);
1168                 }
1169             }
1170             for (FontConfig.Alias alias : fontConfig.getAliases()) {
1171                 Typeface base = systemFonts.get(alias.getToName());
1172                 Typeface newFace = base;
1173                 int weight = alias.getWeight();
1174                 if (weight != 400) {
1175                     newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
1176                 }
1177                 systemFonts.put(alias.getName(), newFace);
1178             }
1179             sSystemFontMap = systemFonts;
1180
1181         } catch (RuntimeException e) {
1182             Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
1183             // TODO: normal in non-Minikin case, remove or make error when Minikin-only
1184         } catch (FileNotFoundException e) {
1185             Log.e(TAG, "Error opening " + configFilename, e);
1186         } catch (IOException e) {
1187             Log.e(TAG, "Error reading " + configFilename, e);
1188         } catch (XmlPullParserException e) {
1189             Log.e(TAG, "XML parse exception for " + configFilename, e);
1190         }
1191     }
1192
1193     static {
1194         init();
1195         // Set up defaults and typefaces exposed in public API
1196         DEFAULT         = create((String) null, 0);
1197         DEFAULT_BOLD    = create((String) null, Typeface.BOLD);
1198         SANS_SERIF      = create("sans-serif", 0);
1199         SERIF           = create("serif", 0);
1200         MONOSPACE       = create("monospace", 0);
1201
1202         sDefaults = new Typeface[] {
1203             DEFAULT,
1204             DEFAULT_BOLD,
1205             create((String) null, Typeface.ITALIC),
1206             create((String) null, Typeface.BOLD_ITALIC),
1207         };
1208
1209     }
1210
1211     private static File getSystemFontConfigLocation() {
1212         return new File("/system/etc/");
1213     }
1214
1215     @Override
1216     protected void finalize() throws Throwable {
1217         try {
1218             nativeUnref(native_instance);
1219             native_instance = 0;  // Other finalizers can still call us.
1220         } finally {
1221             super.finalize();
1222         }
1223     }
1224
1225     @Override
1226     public boolean equals(Object o) {
1227         if (this == o) return true;
1228         if (o == null || getClass() != o.getClass()) return false;
1229
1230         Typeface typeface = (Typeface) o;
1231
1232         return mStyle == typeface.mStyle && native_instance == typeface.native_instance;
1233     }
1234
1235     @Override
1236     public int hashCode() {
1237         /*
1238          * Modified method for hashCode with long native_instance derived from
1239          * http://developer.android.com/reference/java/lang/Object.html
1240          */
1241         int result = 17;
1242         result = 31 * result + (int) (native_instance ^ (native_instance >>> 32));
1243         result = 31 * result + mStyle;
1244         return result;
1245     }
1246
1247     /** @hide */
1248     public boolean isSupportedAxes(int axis) {
1249         if (mSupportedAxes == null) {
1250             synchronized (this) {
1251                 if (mSupportedAxes == null) {
1252                     mSupportedAxes = nativeGetSupportedAxes(native_instance);
1253                     if (mSupportedAxes == null) {
1254                         mSupportedAxes = EMPTY_AXES;
1255                     }
1256                 }
1257             }
1258         }
1259         return Arrays.binarySearch(mSupportedAxes, axis) > 0;
1260     }
1261
1262     private static native long nativeCreateFromTypeface(long native_instance, int style);
1263     private static native long nativeCreateFromTypefaceWithExactStyle(
1264             long native_instance, int weight, boolean italic);
1265     // TODO: clean up: change List<FontVariationAxis> to FontVariationAxis[]
1266     private static native long nativeCreateFromTypefaceWithVariation(
1267             long native_instance, List<FontVariationAxis> axes);
1268     private static native long nativeCreateWeightAlias(long native_instance, int weight);
1269     private static native void nativeUnref(long native_instance);
1270     private static native int  nativeGetStyle(long native_instance);
1271     private static native int  nativeGetBaseWeight(long native_instance);
1272     private static native long nativeCreateFromArray(long[] familyArray);
1273     private static native void nativeSetDefault(long native_instance);
1274     private static native int[] nativeGetSupportedAxes(long native_instance);
1275 }