Typeface.java revision ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7f
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
17package android.graphics;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.content.res.AssetManager;
23import android.graphics.fonts.FontRequest;
24import android.graphics.fonts.FontResult;
25import android.os.Bundle;
26import android.os.Handler;
27import android.os.ParcelFileDescriptor;
28import android.os.ResultReceiver;
29import android.provider.FontsContract;
30import android.text.FontConfig;
31import android.util.Log;
32import android.util.LongSparseArray;
33import android.util.LruCache;
34import android.util.SparseArray;
35
36import com.android.internal.annotations.GuardedBy;
37
38import libcore.io.IoUtils;
39
40import org.xmlpull.v1.XmlPullParserException;
41
42import java.io.File;
43import java.io.FileInputStream;
44import java.io.FileNotFoundException;
45import java.io.IOException;
46import java.lang.annotation.Retention;
47import java.lang.annotation.RetentionPolicy;
48import java.nio.ByteBuffer;
49import java.nio.channels.FileChannel;
50import java.util.ArrayList;
51import java.util.HashMap;
52import java.util.List;
53import java.util.Map;
54
55/**
56 * The Typeface class specifies the typeface and intrinsic style of a font.
57 * This is used in the paint, along with optionally Paint settings like
58 * textSize, textSkewX, textScaleX to specify
59 * how text appears when drawn (and measured).
60 */
61public class Typeface {
62
63    private static String TAG = "Typeface";
64
65    /** The default NORMAL typeface object */
66    public static final Typeface DEFAULT;
67    /**
68     * The default BOLD typeface object. Note: this may be not actually be
69     * bold, depending on what fonts are installed. Call getStyle() to know
70     * for sure.
71     */
72    public static final Typeface DEFAULT_BOLD;
73    /** The NORMAL style of the default sans serif typeface. */
74    public static final Typeface SANS_SERIF;
75    /** The NORMAL style of the default serif typeface. */
76    public static final Typeface SERIF;
77    /** The NORMAL style of the default monospace typeface. */
78    public static final Typeface MONOSPACE;
79
80    static Typeface[] sDefaults;
81    private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache =
82            new LongSparseArray<>(3);
83    @GuardedBy("sLock")
84    private static FontsContract sFontsContract;
85    @GuardedBy("sLock")
86    private static Handler mHandler;
87
88    /**
89     * Cache for Typeface objects dynamically loaded from assets. Currently max size is 16.
90     */
91    private static final LruCache<String, Typeface> sDynamicTypefaceCache = new LruCache<>(16);
92
93    static Typeface sDefaultTypeface;
94    static Map<String, Typeface> sSystemFontMap;
95    static FontFamily[] sFallbackFonts;
96    private static final Object sLock = new Object();
97
98    static final String FONTS_CONFIG = "fonts.xml";
99
100    /**
101     * @hide
102     */
103    public long native_instance;
104
105    // Style
106    public static final int NORMAL = 0;
107    public static final int BOLD = 1;
108    public static final int ITALIC = 2;
109    public static final int BOLD_ITALIC = 3;
110
111    private int mStyle = 0;
112
113    private static void setDefault(Typeface t) {
114        sDefaultTypeface = t;
115        nativeSetDefault(t.native_instance);
116    }
117
118    /** Returns the typeface's intrinsic style attributes */
119    public int getStyle() {
120        return mStyle;
121    }
122
123    /** Returns true if getStyle() has the BOLD bit set. */
124    public final boolean isBold() {
125        return (mStyle & BOLD) != 0;
126    }
127
128    /** Returns true if getStyle() has the ITALIC bit set. */
129    public final boolean isItalic() {
130        return (mStyle & ITALIC) != 0;
131    }
132
133    /**
134     * @hide
135     * Used by Resources to load a font resource of type font file.
136     */
137    @Nullable
138    public static Typeface createFromResources(AssetManager mgr, String path, int cookie) {
139        if (sFallbackFonts != null) {
140            synchronized (sDynamicTypefaceCache) {
141                final String key = createAssetUid(mgr, path);
142                Typeface typeface = sDynamicTypefaceCache.get(key);
143                if (typeface != null) return typeface;
144
145                FontFamily fontFamily = new FontFamily();
146                if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */)) {
147                    fontFamily.freeze();
148                    FontFamily[] families = {fontFamily};
149                    typeface = createFromFamiliesWithDefault(families);
150                    sDynamicTypefaceCache.put(key, typeface);
151                    return typeface;
152                }
153            }
154        }
155        return null;
156    }
157
158    /**
159     * @hide
160     * Used by Resources to load a font resource of type xml.
161     */
162    @Nullable
163    public static Typeface createFromResources(FontConfig config, AssetManager mgr, String path) {
164        if (sFallbackFonts != null) {
165            synchronized (sDynamicTypefaceCache) {
166                final String key = createAssetUid(mgr, path);
167                Typeface typeface = sDynamicTypefaceCache.get(key);
168                if (typeface != null) return typeface;
169
170                List<FontConfig.Family> families = config.getFamilies();
171                if (families == null || families.isEmpty()) {
172                    throw new RuntimeException("Font resource contained no fonts.");
173                }
174                if (families.size() > 1) {
175                    throw new RuntimeException("Font resource contained more than one family.");
176                }
177                FontConfig.Family family = families.get(0);
178
179                FontFamily fontFamily = new FontFamily();
180                List<FontConfig.Font> fonts = family.getFonts();
181                for (int i = 0; i < fonts.size(); i++) {
182                    FontConfig.Font font = fonts.get(i);
183                    // TODO: Use style and weight info
184                    if (!fontFamily.addFontFromAssetManager(mgr, font.getFontName(),
185                            0 /* resourceCookie */, false /* isAsset */)) {
186                        return null;
187                    }
188                }
189                fontFamily.freeze();
190                FontFamily[] familyChain = { fontFamily };
191                typeface = createFromFamiliesWithDefault(familyChain);
192                sDynamicTypefaceCache.put(key, typeface);
193                return typeface;
194            }
195        }
196        return null;
197    }
198
199    /**
200     * @hide
201     */
202    public static Typeface createFromCache(AssetManager mgr, String path) {
203        synchronized (sDynamicTypefaceCache) {
204            final String key = createAssetUid(mgr, path);
205            Typeface typeface = sDynamicTypefaceCache.get(key);
206            if (typeface != null) {
207                return typeface;
208            }
209        }
210        return null;
211    }
212
213    /**
214     * Create a typeface object given a font request. The font will be asynchronously fetched,
215     * therefore the result is delivered to the given callback. See {@link FontRequest}.
216     * Only one of the methods in callback will be invoked, depending on whether the request
217     * succeeds or fails. These calls will happen on the main thread.
218     * @param request A {@link FontRequest} object that identifies the provider and query for the
219     *                request. May not be null.
220     * @param callback A callback that will be triggered when results are obtained. May not be null.
221     */
222    public static void create(@NonNull FontRequest request, @NonNull FontRequestCallback callback) {
223        synchronized (sLock) {
224            if (sFontsContract == null) {
225                sFontsContract = new FontsContract();
226                mHandler = new Handler();
227            }
228            final ResultReceiver receiver = new ResultReceiver(null) {
229                @Override
230                public void onReceiveResult(int resultCode, Bundle resultData) {
231                    mHandler.post(new Runnable() {
232                        @Override
233                        public void run() {
234                            receiveResult(request, callback, resultCode, resultData);
235                        }
236                    });
237                }
238            };
239            sFontsContract.getFont(request, receiver);
240        }
241    }
242
243    private static void receiveResult(FontRequest request, FontRequestCallback callback,
244            int resultCode, Bundle resultData) {
245        if (resultCode == FontsContract.RESULT_CODE_PROVIDER_NOT_FOUND) {
246            callback.onTypefaceRequestFailed(
247                    FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND);
248            return;
249        }
250        if (resultCode == FontsContract.RESULT_CODE_FONT_NOT_FOUND
251                || resultData == null) {
252            callback.onTypefaceRequestFailed(
253                    FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND);
254            return;
255        }
256        List<FontResult> resultList =
257                resultData.getParcelableArrayList(FontsContract.PARCEL_FONT_RESULTS);
258        if (resultList == null || resultList.isEmpty()) {
259            callback.onTypefaceRequestFailed(
260                    FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND);
261            return;
262        }
263        FontFamily fontFamily = new FontFamily();
264        for (int i = 0; i < resultList.size(); ++i) {
265            FontResult result = resultList.get(i);
266            ParcelFileDescriptor fd = result.getFileDescriptor();
267            if (fd == null) {
268                callback.onTypefaceRequestFailed(
269                        FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
270                return;
271            }
272            try (FileInputStream is = new FileInputStream(fd.getFileDescriptor())) {
273                FileChannel fileChannel = is.getChannel();
274                long fontSize = fileChannel.size();
275                ByteBuffer fontBuffer = fileChannel.map(
276                        FileChannel.MapMode.READ_ONLY, 0, fontSize);
277                int style = result.getStyle();
278                int weight = (style & BOLD) != 0 ? 700 : 400;
279                // TODO: this method should be
280                // create(fd, ttcIndex, fontVariationSettings, style).
281                if (!fontFamily.addFontWeightStyle(fontBuffer, result.getTtcIndex(),
282                                null, weight, (style & ITALIC) != 0)) {
283                    Log.e(TAG, "Error creating font " + request.getQuery());
284                    callback.onTypefaceRequestFailed(
285                            FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
286                    return;
287                }
288            } catch (IOException e) {
289                Log.e(TAG, "Error reading font " + request.getQuery(), e);
290                callback.onTypefaceRequestFailed(
291                        FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
292                return;
293            } finally {
294                IoUtils.closeQuietly(fd);
295            }
296        }
297        callback.onTypefaceRetrieved(Typeface.createFromFamiliesWithDefault(
298                new FontFamily[] {fontFamily}));
299    }
300
301    /**
302     * Interface used to receive asynchronously fetched typefaces.
303     */
304    public interface FontRequestCallback {
305        /**
306         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
307         * provider was not found on the device.
308         */
309        int FAIL_REASON_PROVIDER_NOT_FOUND = 0;
310        /**
311         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
312         * returned by the provider was not loaded properly.
313         */
314        int FAIL_REASON_FONT_LOAD_ERROR = 1;
315        /**
316         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
317         * provider did not return any results for the given query.
318         */
319        int FAIL_REASON_FONT_NOT_FOUND = 2;
320
321        /** @hide */
322        @IntDef({FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
323                FAIL_REASON_FONT_NOT_FOUND})
324        @Retention(RetentionPolicy.SOURCE)
325        @interface FontRequestFailReason {}
326
327        /**
328         * Called then a Typeface request done via {@link Typeface#create(FontRequest,
329         * FontRequestCallback)} is complete. Note that this method will not be called if
330         * {@link #onTypefaceRequestFailed(int)} is called instead.
331         * @param typeface  The Typeface object retrieved.
332         */
333        void onTypefaceRetrieved(Typeface typeface);
334
335        /**
336         * Called when a Typeface request done via {@link Typeface#create(FontRequest,
337         * FontRequestCallback)} fails.
338         * @param reason One of {@link #FAIL_REASON_PROVIDER_NOT_FOUND},
339         *               {@link #FAIL_REASON_FONT_NOT_FOUND} or
340         *               {@link #FAIL_REASON_FONT_LOAD_ERROR}.
341         */
342        void onTypefaceRequestFailed(@FontRequestFailReason int reason);
343    }
344
345    /**
346     * Create a typeface object given a family name, and option style information.
347     * If null is passed for the name, then the "default" font will be chosen.
348     * The resulting typeface object can be queried (getStyle()) to discover what
349     * its "real" style characteristics are.
350     *
351     * @param familyName May be null. The name of the font family.
352     * @param style  The style (normal, bold, italic) of the typeface.
353     *               e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
354     * @return The best matching typeface.
355     */
356    public static Typeface create(String familyName, int style) {
357        if (sSystemFontMap != null) {
358            return create(sSystemFontMap.get(familyName), style);
359        }
360        return null;
361    }
362
363    /**
364     * Create a typeface object that best matches the specified existing
365     * typeface and the specified Style. Use this call if you want to pick a new
366     * style from the same family of an existing typeface object. If family is
367     * null, this selects from the default font's family.
368     *
369     * @param family May be null. The name of the existing type face.
370     * @param style  The style (normal, bold, italic) of the typeface.
371     *               e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
372     * @return The best matching typeface.
373     */
374    public static Typeface create(Typeface family, int style) {
375        if (style < 0 || style > 3) {
376            style = 0;
377        }
378        long ni = 0;
379        if (family != null) {
380            // Return early if we're asked for the same face/style
381            if (family.mStyle == style) {
382                return family;
383            }
384
385            ni = family.native_instance;
386        }
387
388        Typeface typeface;
389        SparseArray<Typeface> styles = sTypefaceCache.get(ni);
390
391        if (styles != null) {
392            typeface = styles.get(style);
393            if (typeface != null) {
394                return typeface;
395            }
396        }
397
398        typeface = new Typeface(nativeCreateFromTypeface(ni, style));
399        if (styles == null) {
400            styles = new SparseArray<Typeface>(4);
401            sTypefaceCache.put(ni, styles);
402        }
403        styles.put(style, typeface);
404
405        return typeface;
406    }
407
408    /**
409     * Returns one of the default typeface objects, based on the specified style
410     *
411     * @return the default typeface that corresponds to the style
412     */
413    public static Typeface defaultFromStyle(int style) {
414        return sDefaults[style];
415    }
416
417    /**
418     * Create a new typeface from the specified font data.
419     *
420     * @param mgr  The application's asset manager
421     * @param path The file name of the font data in the assets directory
422     * @return The new typeface.
423     */
424    public static Typeface createFromAsset(AssetManager mgr, String path) {
425        if (sFallbackFonts != null) {
426            synchronized (sDynamicTypefaceCache) {
427                final String key = createAssetUid(mgr, path);
428                Typeface typeface = sDynamicTypefaceCache.get(key);
429                if (typeface != null) return typeface;
430
431                FontFamily fontFamily = new FontFamily();
432                if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */)) {
433                    fontFamily.freeze();
434                    FontFamily[] families = { fontFamily };
435                    typeface = createFromFamiliesWithDefault(families);
436                    sDynamicTypefaceCache.put(key, typeface);
437                    return typeface;
438                } else {
439                    fontFamily.abortCreation();
440                }
441            }
442        }
443        throw new RuntimeException("Font asset not found " + path);
444    }
445
446    /**
447     * Creates a unique id for a given AssetManager and asset path.
448     *
449     * @param mgr  AssetManager instance
450     * @param path The path for the asset.
451     * @return Unique id for a given AssetManager and asset path.
452     */
453    private static String createAssetUid(final AssetManager mgr, String path) {
454        final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers();
455        final StringBuilder builder = new StringBuilder();
456        final int size = pkgs.size();
457        for (int i = 0; i < size; i++) {
458            builder.append(pkgs.valueAt(i));
459            builder.append("-");
460        }
461        builder.append(path);
462        return builder.toString();
463    }
464
465    /**
466     * Create a new typeface from the specified font file.
467     *
468     * @param path The path to the font data.
469     * @return The new typeface.
470     */
471    public static Typeface createFromFile(File path) {
472        return createFromFile(path.getAbsolutePath());
473    }
474
475    /**
476     * Create a new typeface from the specified font file.
477     *
478     * @param path The full path to the font data.
479     * @return The new typeface.
480     */
481    public static Typeface createFromFile(String path) {
482        if (sFallbackFonts != null) {
483            FontFamily fontFamily = new FontFamily();
484            if (fontFamily.addFont(path, 0 /* ttcIndex */)) {
485                fontFamily.freeze();
486                FontFamily[] families = { fontFamily };
487                return createFromFamiliesWithDefault(families);
488            } else {
489                fontFamily.abortCreation();
490            }
491        }
492        throw new RuntimeException("Font not found " + path);
493    }
494
495    /**
496     * Create a new typeface from an array of font families.
497     *
498     * @param families array of font families
499     * @hide
500     */
501    public static Typeface createFromFamilies(FontFamily[] families) {
502        long[] ptrArray = new long[families.length];
503        for (int i = 0; i < families.length; i++) {
504            ptrArray[i] = families[i].mNativePtr;
505        }
506        return new Typeface(nativeCreateFromArray(ptrArray));
507    }
508
509    /**
510     * Create a new typeface from an array of font families, including
511     * also the font families in the fallback list.
512     *
513     * @param families array of font families
514     * @hide
515     */
516    public static Typeface createFromFamiliesWithDefault(FontFamily[] families) {
517        long[] ptrArray = new long[families.length + sFallbackFonts.length];
518        for (int i = 0; i < families.length; i++) {
519            ptrArray[i] = families[i].mNativePtr;
520        }
521        for (int i = 0; i < sFallbackFonts.length; i++) {
522            ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr;
523        }
524        return new Typeface(nativeCreateFromArray(ptrArray));
525    }
526
527    // don't allow clients to call this directly
528    private Typeface(long ni) {
529        if (ni == 0) {
530            throw new RuntimeException("native typeface cannot be made");
531        }
532
533        native_instance = ni;
534        mStyle = nativeGetStyle(ni);
535    }
536
537    private static FontFamily makeFamilyFromParsed(FontConfig.Family family,
538            Map<String, ByteBuffer> bufferForPath) {
539        FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
540        for (FontConfig.Font font : family.getFonts()) {
541            ByteBuffer fontBuffer = bufferForPath.get(font.getFontName());
542            if (fontBuffer == null) {
543                try (FileInputStream file = new FileInputStream(font.getFontName())) {
544                    FileChannel fileChannel = file.getChannel();
545                    long fontSize = fileChannel.size();
546                    fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
547                    bufferForPath.put(font.getFontName(), fontBuffer);
548                } catch (IOException e) {
549                    Log.e(TAG, "Error mapping font file " + font.getFontName());
550                    continue;
551                }
552            }
553            if (!fontFamily.addFontWeightStyle(fontBuffer, font.getTtcIndex(), font.getAxes(),
554                    font.getWeight(), font.isItalic())) {
555                Log.e(TAG, "Error creating font " + font.getFontName() + "#" + font.getTtcIndex());
556            }
557        }
558        fontFamily.freeze();
559        return fontFamily;
560    }
561
562    /*
563     * (non-Javadoc)
564     *
565     * This should only be called once, from the static class initializer block.
566     */
567    private static void init() {
568        // Load font config and initialize Minikin state
569        File systemFontConfigLocation = getSystemFontConfigLocation();
570        File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
571        try {
572            FileInputStream fontsIn = new FileInputStream(configFilename);
573            FontConfig fontConfig = FontListParser.parse(fontsIn);
574
575            Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>();
576
577            List<FontFamily> familyList = new ArrayList<FontFamily>();
578            // Note that the default typeface is always present in the fallback list;
579            // this is an enhancement from pre-Minikin behavior.
580            for (int i = 0; i < fontConfig.getFamilies().size(); i++) {
581                FontConfig.Family f = fontConfig.getFamilies().get(i);
582                if (i == 0 || f.getName() == null) {
583                    familyList.add(makeFamilyFromParsed(f, bufferForPath));
584                }
585            }
586            sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
587            setDefault(Typeface.createFromFamilies(sFallbackFonts));
588
589            Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
590            for (int i = 0; i < fontConfig.getFamilies().size(); i++) {
591                Typeface typeface;
592                FontConfig.Family f = fontConfig.getFamilies().get(i);
593                if (f.getName() != null) {
594                    if (i == 0) {
595                        // The first entry is the default typeface; no sense in
596                        // duplicating the corresponding FontFamily.
597                        typeface = sDefaultTypeface;
598                    } else {
599                        FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath);
600                        FontFamily[] families = { fontFamily };
601                        typeface = Typeface.createFromFamiliesWithDefault(families);
602                    }
603                    systemFonts.put(f.getName(), typeface);
604                }
605            }
606            for (FontConfig.Alias alias : fontConfig.getAliases()) {
607                Typeface base = systemFonts.get(alias.getToName());
608                Typeface newFace = base;
609                int weight = alias.getWeight();
610                if (weight != 400) {
611                    newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
612                }
613                systemFonts.put(alias.getName(), newFace);
614            }
615            sSystemFontMap = systemFonts;
616
617        } catch (RuntimeException e) {
618            Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
619            // TODO: normal in non-Minikin case, remove or make error when Minikin-only
620        } catch (FileNotFoundException e) {
621            Log.e(TAG, "Error opening " + configFilename, e);
622        } catch (IOException e) {
623            Log.e(TAG, "Error reading " + configFilename, e);
624        } catch (XmlPullParserException e) {
625            Log.e(TAG, "XML parse exception for " + configFilename, e);
626        }
627    }
628
629    static {
630        init();
631        // Set up defaults and typefaces exposed in public API
632        DEFAULT         = create((String) null, 0);
633        DEFAULT_BOLD    = create((String) null, Typeface.BOLD);
634        SANS_SERIF      = create("sans-serif", 0);
635        SERIF           = create("serif", 0);
636        MONOSPACE       = create("monospace", 0);
637
638        sDefaults = new Typeface[] {
639            DEFAULT,
640            DEFAULT_BOLD,
641            create((String) null, Typeface.ITALIC),
642            create((String) null, Typeface.BOLD_ITALIC),
643        };
644
645    }
646
647    private static File getSystemFontConfigLocation() {
648        return new File("/system/etc/");
649    }
650
651    @Override
652    protected void finalize() throws Throwable {
653        try {
654            nativeUnref(native_instance);
655            native_instance = 0;  // Other finalizers can still call us.
656        } finally {
657            super.finalize();
658        }
659    }
660
661    @Override
662    public boolean equals(Object o) {
663        if (this == o) return true;
664        if (o == null || getClass() != o.getClass()) return false;
665
666        Typeface typeface = (Typeface) o;
667
668        return mStyle == typeface.mStyle && native_instance == typeface.native_instance;
669    }
670
671    @Override
672    public int hashCode() {
673        /*
674         * Modified method for hashCode with long native_instance derived from
675         * http://developer.android.com/reference/java/lang/Object.html
676         */
677        int result = 17;
678        result = 31 * result + (int) (native_instance ^ (native_instance >>> 32));
679        result = 31 * result + mStyle;
680        return result;
681    }
682
683    private static native long nativeCreateFromTypeface(long native_instance, int style);
684    private static native long nativeCreateWeightAlias(long native_instance, int weight);
685    private static native void nativeUnref(long native_instance);
686    private static native int  nativeGetStyle(long native_instance);
687    private static native long nativeCreateFromArray(long[] familyArray);
688    private static native void nativeSetDefault(long native_instance);
689}
690