Make Font class being able to create from native instance

This CL refactors followings:
- Use infomation stored in native instance as the source-of-truth.
- Being able to create Font instance from native instance.
- Use ByteBuffer as a wrapper of the native byte buffer.

Bug: 179113771
Test: atest CtsTextTestCases CtsGraphicsTestCases
Test: atest android.graphics.fonts.NativeSystemFontTest
Test: atest android.graphics.fonts.SystemFontsTest
Test: atest FrameworksCoreTests:android.text
Test: atest FrameworksCoreTests:android.graphics
Change-Id: Icc1df1c76ba78d4f8800984444439fd03970e179
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 9214ff1..b153c99 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -26,8 +26,7 @@
 import android.graphics.RectF;
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
-import android.util.Log;
-import android.util.LongSparseArray;
+import android.text.TextUtils;
 import android.util.LongSparseLongArray;
 import android.util.TypedValue;
 
@@ -44,7 +43,6 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.lang.ref.WeakReference;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.channels.FileChannel;
@@ -61,14 +59,9 @@
     private static final int STYLE_ITALIC = 1;
     private static final int STYLE_NORMAL = 0;
 
-    private static final Object MAP_LOCK = new Object();
-    // We need to have mapping from native ptr to Font object for later accessing from TextShape
-    // result since Typeface doesn't have reference to Font object and it is not always created from
-    // Font object. Sometimes Typeface is created in native layer only and there might not be Font
-    // object in Java layer. So, if not found in this cache, create new Font object for API user.
-    @GuardedBy("MAP_LOCK")
-    private static final LongSparseArray<WeakReference<Font>> FONT_PTR_MAP =
-            new LongSparseArray<>();
+    private static final NativeAllocationRegistry BUFFER_REGISTRY =
+            NativeAllocationRegistry.createMalloced(
+                    ByteBuffer.class.getClassLoader(), nGetReleaseNativeFont());
 
     private static final Object SOURCE_ID_LOCK = new Object();
     @GuardedBy("SOURCE_ID_LOCK")
@@ -79,9 +72,7 @@
      * A builder class for creating new Font.
      */
     public static final class Builder {
-        private static final NativeAllocationRegistry sFontRegistry =
-                NativeAllocationRegistry.createMalloced(Font.class.getClassLoader(),
-                    nGetReleaseNativeFont());
+
 
         private @Nullable ByteBuffer mBuffer;
         private @Nullable File mFile;
@@ -484,26 +475,15 @@
             final String filePath = mFile == null ? "" : mFile.getAbsolutePath();
 
             long ptr;
-            int fontIdentifier;
+            final Font font;
             if (mFont == null) {
                 ptr = nBuild(builderPtr, readonlyBuffer, filePath, mLocaleList, mWeight, italic,
                         mTtcIndex);
-                long fontBufferPtr = nGetFontBufferAddress(ptr);
-                synchronized (SOURCE_ID_LOCK) {
-                    long id = FONT_SOURCE_ID_MAP.get(fontBufferPtr, -1);
-                    if (id == -1) {
-                        id = FONT_SOURCE_ID_MAP.size();
-                        FONT_SOURCE_ID_MAP.put(fontBufferPtr, id);
-                    }
-                    fontIdentifier = (int) id;
-                }
+                font = new Font(ptr);
             } else {
                 ptr = nClone(mFont.getNativePtr(), builderPtr, mWeight, italic, mTtcIndex);
-                fontIdentifier = mFont.mSourceIdentifier;
+                font = new Font(ptr);
             }
-            final Font font = new Font(ptr, readonlyBuffer, mFile,
-                    new FontStyle(mWeight, slant), mTtcIndex, mAxes, mLocaleList, fontIdentifier);
-            sFontRegistry.registerNativeAllocation(font, ptr);
             return font;
         }
 
@@ -525,33 +505,32 @@
     }
 
     private final long mNativePtr;  // address of the shared ptr of minikin::Font
-    private final @NonNull ByteBuffer mBuffer;
-    private final @Nullable File mFile;
-    private final FontStyle mFontStyle;
-    private final @IntRange(from = 0) int mTtcIndex;
-    private final @Nullable FontVariationAxis[] mAxes;
-    private final @NonNull String mLocaleList;
-    private final int mSourceIdentifier;  // An identifier of font source data.
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private @NonNull ByteBuffer mBuffer = null;
+    @GuardedBy("mLock")
+    private boolean mIsFileInitialized = false;
+    @GuardedBy("mLock")
+    private @Nullable File mFile = null;
+    @GuardedBy("mLock")
+    private FontStyle mFontStyle = null;
+    @GuardedBy("mLock")
+    private @Nullable FontVariationAxis[] mAxes = null;
+    @GuardedBy("mLock")
+    private @NonNull LocaleList mLocaleList = null;
+    @GuardedBy("mLock")
+    private int mSourceIdentifier = -1;
 
     /**
      * Use Builder instead
+     *
+     * Caller must increment underlying minikin::Font ref count.
+     *
+     * @hide
      */
-    private Font(long nativePtr, @NonNull ByteBuffer buffer, @Nullable File file,
-            @NonNull FontStyle fontStyle, @IntRange(from = 0) int ttcIndex,
-            @Nullable FontVariationAxis[] axes, @NonNull String localeList,
-            int sourceIdentifier) {
-        mBuffer = buffer;
-        mFile = file;
-        mFontStyle = fontStyle;
+    public Font(long nativePtr) {
         mNativePtr = nativePtr;
-        mTtcIndex = ttcIndex;
-        mAxes = axes;
-        mLocaleList = localeList;
-        mSourceIdentifier = sourceIdentifier;
-
-        synchronized (MAP_LOCK) {
-            FONT_PTR_MAP.append(nGetNativeFontPtr(mNativePtr), new WeakReference<>(this));
-        }
     }
 
     /**
@@ -563,7 +542,22 @@
      * @return a font buffer
      */
     public @NonNull ByteBuffer getBuffer() {
-        return mBuffer;
+        synchronized (mLock) {
+            if (mBuffer == null) {
+                // Create new instance of native FontWrapper, i.e. incrementing ref count of
+                // minikin Font instance for keeping buffer fo ByteBuffer reference which may live
+                // longer than this object.
+                long ref = nCloneFont(mNativePtr);
+                ByteBuffer fromNative = nNewByteBuffer(mNativePtr);
+
+                // Bind ByteBuffer's lifecycle with underlying font object.
+                BUFFER_REGISTRY.registerNativeAllocation(fromNative, ref);
+
+                // JNI NewDirectBuffer creates writable ByteBuffer even if it is mmaped readonly.
+                mBuffer = fromNative.asReadOnlyBuffer();
+            }
+            return mBuffer;
+        }
     }
 
     /**
@@ -574,7 +568,16 @@
      * @return a file path of the font
      */
     public @Nullable File getFile() {
-        return mFile;
+        synchronized (mLock) {
+            if (!mIsFileInitialized) {
+                String path = nGetFontPath(mNativePtr);
+                if (!TextUtils.isEmpty(path)) {
+                    mFile = new File(path);
+                }
+                mIsFileInitialized = true;
+            }
+            return mFile;
+        }
     }
 
     /**
@@ -585,7 +588,16 @@
      * @return a font style
      */
     public @NonNull FontStyle getStyle() {
-        return mFontStyle;
+        synchronized (mLock) {
+            if (mFontStyle == null) {
+                int packedStyle = nGetPackedStyle(mNativePtr);
+                mFontStyle = new FontStyle(
+                        FontFileUtil.unpackWeight(packedStyle),
+                        FontFileUtil.unpackItalic(packedStyle)
+                                ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);
+            }
+            return mFontStyle;
+        }
     }
 
     /**
@@ -597,7 +609,7 @@
      * @return a TTC index value
      */
     public @IntRange(from = 0) int getTtcIndex() {
-        return mTtcIndex;
+        return nGetIndex(mNativePtr);
     }
 
     /**
@@ -608,7 +620,23 @@
      * @return font variation settings
      */
     public @Nullable FontVariationAxis[] getAxes() {
-        return mAxes == null ? null : mAxes.clone();
+        synchronized (mLock) {
+            if (mAxes == null) {
+                int axisCount = nGetAxisCount(mNativePtr);
+                mAxes = new FontVariationAxis[axisCount];
+                char[] charBuffer = new char[4];
+                for (int i = 0; i < axisCount; ++i) {
+                    long packedAxis = nGetAxisInfo(mNativePtr, i);
+                    float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
+                    charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >>> 56);
+                    charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >>> 48);
+                    charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >>> 40);
+                    charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >>> 32);
+                    mAxes[i] = new FontVariationAxis(new String(charBuffer), value);
+                }
+            }
+        }
+        return mAxes;
     }
 
     /**
@@ -618,7 +646,17 @@
      * @return a locale list
      */
     public @NonNull LocaleList getLocaleList() {
-        return LocaleList.forLanguageTags(mLocaleList);
+        synchronized (mLock) {
+            if (mLocaleList == null) {
+                String langTags = nGetLocaleList(mNativePtr);
+                if (TextUtils.isEmpty(langTags)) {
+                    mLocaleList = LocaleList.getEmptyLocaleList();
+                } else {
+                    mLocaleList = LocaleList.forLanguageTags(langTags);
+                }
+            }
+            return mLocaleList;
+        }
     }
 
     /**
@@ -713,7 +751,20 @@
      * @return an unique identifier for the font source data.
      */
     public int getSourceIdentifier() {
-        return mSourceIdentifier;
+        synchronized (mLock) {
+            if (mSourceIdentifier == -1) {
+                long bufferAddress = nGetBufferAddress(mNativePtr);
+                synchronized (SOURCE_ID_LOCK) {
+                    long id = FONT_SOURCE_ID_MAP.get(bufferAddress, -1);
+                    if (id == -1) {
+                        id = FONT_SOURCE_ID_MAP.size();
+                        FONT_SOURCE_ID_MAP.append(bufferAddress, id);
+                    }
+                    mSourceIdentifier = (int) id;
+                }
+            }
+            return mSourceIdentifier;
+        }
     }
 
     /**
@@ -736,13 +787,16 @@
     private boolean isSameSource(@NonNull Font other) {
         Objects.requireNonNull(other);
 
+        ByteBuffer myBuffer = getBuffer();
+        ByteBuffer otherBuffer = other.getBuffer();
+
         // Shortcut for the same instance.
-        if (mBuffer == other.mBuffer) {
+        if (myBuffer == otherBuffer) {
             return true;
         }
 
         // Shortcut for different font buffer check by comparing size.
-        if (mBuffer.capacity() != other.mBuffer.capacity()) {
+        if (myBuffer.capacity() != otherBuffer.capacity()) {
             return false;
         }
 
@@ -750,15 +804,15 @@
         // underlying native font object holds buffer address, check if this buffer points exactly
         // the same address as a shortcut of equality. For being compatible with of API30 or before,
         // check buffer position even if the buffer points the same address.
-        if (mSourceIdentifier == other.mSourceIdentifier
-                && mBuffer.position() == other.mBuffer.position()) {
+        if (getSourceIdentifier() == other.getSourceIdentifier()
+                && myBuffer.position() == otherBuffer.position()) {
             return true;
         }
 
         // Unfortunately, need to compare bytes one-by-one since the buffer may be different font
         // file but has the same file size, or two font has same content but they are allocated
         // differently. For being compatible with API30 ore before, compare with ByteBuffer#equals.
-        return mBuffer.equals(other.mBuffer);
+        return myBuffer.equals(otherBuffer);
     }
 
     @Override
@@ -769,10 +823,20 @@
         if (!(o instanceof Font)) {
             return false;
         }
+
         Font f = (Font) o;
-        boolean paramEqual = mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex
-                && Arrays.equals(f.mAxes, mAxes) && Objects.equals(f.mLocaleList, mLocaleList)
-                && Objects.equals(mFile, f.mFile);
+
+        // The underlying minikin::Font object is the source of the truth of font information. Thus,
+        // Pointer equality is the object equality.
+        if (nGetMinikinFontPtr(mNativePtr) == nGetMinikinFontPtr(f.mNativePtr)) {
+            return true;
+        }
+
+        boolean paramEqual = f.getStyle().equals(getStyle())
+                && f.getTtcIndex() == getTtcIndex()
+                && Arrays.equals(f.getAxes(), getAxes())
+                && Objects.equals(f.getLocaleList(), getLocaleList())
+                && Objects.equals(getFile(), f.getFile());
 
         if (!paramEqual) {
             return false;
@@ -784,64 +848,42 @@
     @Override
     public int hashCode() {
         return Objects.hash(
-                mFontStyle,
-                mTtcIndex,
-                Arrays.hashCode(mAxes),
+                getStyle(),
+                getTtcIndex(),
+                Arrays.hashCode(getAxes()),
                 // Use Buffer size instead of ByteBuffer#hashCode since ByteBuffer#hashCode traverse
                 // data which is not performant e.g. for HashMap. The hash collision are less likely
                 // happens because it is unlikely happens the different font files has exactly the
                 // same size.
-                mLocaleList);
+                getLocaleList());
     }
 
     @Override
     public String toString() {
         return "Font {"
-            + "path=" + mFile
-            + ", style=" + mFontStyle
-            + ", ttcIndex=" + mTtcIndex
-            + ", axes=" + FontVariationAxis.toFontVariationSettings(mAxes)
-            + ", localeList=" + mLocaleList
-            + ", buffer=" + mBuffer
+            + "path=" + getFile()
+            + ", style=" + getStyle()
+            + ", ttcIndex=" + getTtcIndex()
+            + ", axes=" + FontVariationAxis.toFontVariationSettings(getAxes())
+            + ", localeList=" + getLocaleList()
+            + ", buffer=" + getBuffer()
             + "}";
     }
 
-    /**
-     * Lookup Font object from native pointer or create new one if not found.
-     * @hide
-     */
-    public static Font findOrCreateFontFromNativePtr(long ptr) {
-        // First, lookup from known mapps.
-        synchronized (MAP_LOCK) {
-            WeakReference<Font> fontRef = FONT_PTR_MAP.get(ptr);
-            if (fontRef != null) {
-                Font font = fontRef.get();
-                if (font != null) {
-                    return font;
-                }
-            }
+    @CriticalNative
+    private static native long nGetMinikinFontPtr(long font);
 
-            // If not found, create Font object from native object for Java API users.
-            ByteBuffer buffer = NativeFontBufferHelper.refByteBuffer(ptr);
-            NativeFont.Font font = NativeFont.readNativeFont(ptr);
+    @CriticalNative
+    private static native long nCloneFont(long font);
 
-            Font.Builder builder = new Font.Builder(buffer, font.getFile(), "")
-                    .setWeight(font.getStyle().getWeight())
-                    .setSlant(font.getStyle().getSlant())
-                    .setTtcIndex(font.getIndex())
-                    .setFontVariationSettings(font.getAxes());
+    @FastNative
+    private static native ByteBuffer nNewByteBuffer(long font);
 
-            Font newFont = null;
-            try {
-                newFont = builder.build();
-                FONT_PTR_MAP.append(ptr, new WeakReference<>(newFont));
-            } catch (IOException e) {
-                // This must not happen since the buffer was already created once.
-                Log.e("Font", "Failed to create font object from existing buffer.", e);
-            }
-            return newFont;
-        }
-    }
+    @CriticalNative
+    private static native long nGetBufferAddress(long font);
+
+    @CriticalNative
+    private static native long nGetReleaseNativeFont();
 
     @FastNative
     private static native float nGetGlyphBounds(long font, int glyphId, long paint, RectF rect);
@@ -849,9 +891,21 @@
     @FastNative
     private static native float nGetFontMetrics(long font, long paint, Paint.FontMetrics metrics);
 
-    @CriticalNative
-    private static native long nGetNativeFontPtr(long ptr);
+    @FastNative
+    private static native String nGetFontPath(long fontPtr);
+
+    @FastNative
+    private static native String nGetLocaleList(long familyPtr);
 
     @CriticalNative
-    private static native long nGetFontBufferAddress(long font);
+    private static native int nGetPackedStyle(long fontPtr);
+
+    @CriticalNative
+    private static native int nGetIndex(long fontPtr);
+
+    @CriticalNative
+    private static native int nGetAxisCount(long fontPtr);
+
+    @CriticalNative
+    private static native long nGetAxisInfo(long fontPtr, int i);
 }
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index 77f86fe..8c13d3e 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -143,12 +143,10 @@
         private static native long nGetReleaseNativeFamily();
     }
 
-    private final ArrayList<Font> mFonts;
     private final long mNativePtr;
 
     // Use Builder instead.
     private FontFamily(@NonNull ArrayList<Font> fonts, long ptr) {
-        mFonts = fonts;
         mNativePtr = ptr;
     }
 
@@ -176,7 +174,10 @@
      * @return a registered font
      */
     public @NonNull Font getFont(@IntRange(from = 0) int index) {
-        return mFonts.get(index);
+        if (index < 0 || getSize() <= index) {
+            throw new IndexOutOfBoundsException();
+        }
+        return new Font(nGetFont(mNativePtr, index));
     }
 
     /**
@@ -185,7 +186,7 @@
      * @return the number of fonts registered in this family.
      */
     public @IntRange(from = 1) int getSize() {
-        return mFonts.size();
+        return nGetFontSize(mNativePtr);
     }
 
     /** @hide */
@@ -193,6 +194,12 @@
         return mNativePtr;
     }
 
+    @CriticalNative
+    private static native int nGetFontSize(long family);
+
+    @CriticalNative
+    private static native long nGetFont(long family, int i);
+
     @FastNative
     private static native String nGetLangTags(long family);
 
diff --git a/graphics/java/android/graphics/fonts/NativeFont.java b/graphics/java/android/graphics/fonts/NativeFont.java
deleted file mode 100644
index 9e9d76a..0000000
--- a/graphics/java/android/graphics/fonts/NativeFont.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics.fonts;
-
-import android.graphics.Typeface;
-
-import dalvik.annotation.optimization.CriticalNative;
-import dalvik.annotation.optimization.FastNative;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Read native font objects.
- *
- * @hide
- */
-public class NativeFont {
-
-    /**
-     * Represents native font object.
-     */
-    public static final class Font {
-        private final File mFile;
-        private final int mIndex;
-        private final FontVariationAxis[] mAxes;
-        private final FontStyle mStyle;
-
-        public Font(File file, int index, FontVariationAxis[] axes, FontStyle style) {
-            mFile = file;
-            mIndex = index;
-            mAxes = axes;
-            mStyle = style;
-        }
-
-        public File getFile() {
-            return mFile;
-        }
-
-        public FontVariationAxis[] getAxes() {
-            return mAxes;
-        }
-
-        public FontStyle getStyle() {
-            return mStyle;
-        }
-
-        public int getIndex() {
-            return mIndex;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-            Font font = (Font) o;
-            return mIndex == font.mIndex && mFile.equals(font.mFile)
-                    && Arrays.equals(mAxes, font.mAxes) && mStyle.equals(font.mStyle);
-        }
-
-        @Override
-        public int hashCode() {
-            int result = Objects.hash(mFile, mIndex, mStyle);
-            result = 31 * result + Arrays.hashCode(mAxes);
-            return result;
-        }
-    }
-
-    /**
-     * Represents native font family object.
-     */
-    public static final class Family {
-        private final List<Font> mFonts;
-        private final String mLocale;
-
-        public Family(List<Font> fonts, String locale) {
-            mFonts = fonts;
-            mLocale = locale;
-        }
-
-        public List<Font> getFonts() {
-            return mFonts;
-        }
-
-        public String getLocale() {
-            return mLocale;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-            Family family = (Family) o;
-            return mFonts.equals(family.mFonts) && mLocale.equals(family.mLocale);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(mFonts, mLocale);
-        }
-    }
-
-    /**
-     * Get underlying font families from Typeface
-     *
-     * @param typeface a typeface
-     * @return list of family
-     */
-    public static List<Family> readTypeface(Typeface typeface) {
-        int familyCount = nGetFamilyCount(typeface.native_instance);
-        List<Family> result = new ArrayList<>(familyCount);
-        for (int i = 0; i < familyCount; ++i) {
-            result.add(readNativeFamily(nGetFamily(typeface.native_instance, i)));
-        }
-        return result;
-    }
-
-    /**
-     * Read family object from native pointer
-     *
-     * @param familyPtr a font family pointer
-     * @return a family
-     */
-    public static Family readNativeFamily(long familyPtr) {
-        int fontCount = nGetFontCount(familyPtr);
-        List<Font> result = new ArrayList<>(fontCount);
-        for (int i = 0; i < fontCount; ++i) {
-            result.add(readNativeFont(nGetFont(familyPtr, i)));
-        }
-        String localeList = nGetLocaleList(familyPtr);
-        return new Family(result, localeList);
-    }
-
-    /**
-     * Read font object from native pointer.
-     *
-     * @param ptr a font pointer
-     * @return a font
-     */
-    public static Font readNativeFont(long ptr) {
-        long packed = nGetFontInfo(ptr);
-        int weight = (int) (packed & 0x0000_0000_0000_FFFFL);
-        boolean italic = (packed & 0x0000_0000_0001_0000L) != 0;
-        int ttcIndex = (int) ((packed & 0x0000_FFFF_0000_0000L) >> 32);
-        int axisCount = (int) ((packed & 0xFFFF_0000_0000_0000L) >> 48);
-        FontVariationAxis[] axes = new FontVariationAxis[axisCount];
-        char[] charBuffer = new char[4];
-        for (int i = 0; i < axisCount; ++i) {
-            long packedAxis = nGetAxisInfo(ptr, i);
-            float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
-            charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >> 56);
-            charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >> 48);
-            charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >> 40);
-            charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >> 32);
-            axes[i] = new FontVariationAxis(new String(charBuffer), value);
-        }
-        String path = nGetFontPath(ptr);
-        File file = (path == null) ? null : new File(path);
-        FontStyle style = new FontStyle(weight,
-                italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);
-
-        return new Font(file, ttcIndex, axes, style);
-    }
-
-    @CriticalNative
-    private static native int nGetFamilyCount(long ptr);
-
-    @CriticalNative
-    private static native long nGetFamily(long ptr, int index);
-
-    @FastNative
-    private static native String nGetLocaleList(long familyPtr);
-
-    @CriticalNative
-    private static native long nGetFont(long familyPtr, int fontIndex);
-
-    @CriticalNative
-    private static native int nGetFontCount(long familyPtr);
-
-    @CriticalNative
-    private static native long nGetFontInfo(long fontPtr);
-
-    @CriticalNative
-    private static native long nGetAxisInfo(long fontPtr, int i);
-
-    @FastNative
-    private static native String nGetFontPath(long fontPtr);
-}
diff --git a/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java b/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java
deleted file mode 100644
index 5655e7f..0000000
--- a/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics.fonts;
-
-import android.annotation.NonNull;
-
-import dalvik.annotation.optimization.CriticalNative;
-import dalvik.annotation.optimization.FastNative;
-
-import libcore.util.NativeAllocationRegistry;
-
-import java.nio.ByteBuffer;
-
-/**
- * This is a helper class for showing native allocated buffer in Java API.
- *
- * @hide
- */
-public class NativeFontBufferHelper {
-    private NativeFontBufferHelper() {}
-
-    private static final NativeAllocationRegistry REGISTRY =
-            NativeAllocationRegistry.createMalloced(
-                    ByteBuffer.class.getClassLoader(), nGetReleaseFunc());
-
-    /**
-     * Wrap native buffer with ByteBuffer with adding reference to it.
-     */
-    public static @NonNull ByteBuffer refByteBuffer(long fontPtr) {
-        long refPtr = nRefFontBuffer(fontPtr);
-        ByteBuffer buffer = nWrapByteBuffer(refPtr);
-
-        // Releasing native object so that decreasing shared pointer ref count when the byte buffer
-        // is GCed.
-        REGISTRY.registerNativeAllocation(buffer, refPtr);
-
-        return buffer;
-    }
-
-    @CriticalNative
-    private static native long nRefFontBuffer(long fontPtr);
-
-    @FastNative
-    private static native ByteBuffer nWrapByteBuffer(long refPtr);
-
-    @CriticalNative
-    private static native long nGetReleaseFunc();
-}
diff --git a/graphics/java/android/graphics/text/PositionedGlyphs.java b/graphics/java/android/graphics/text/PositionedGlyphs.java
index c2de0ac..8d20e9c 100644
--- a/graphics/java/android/graphics/text/PositionedGlyphs.java
+++ b/graphics/java/android/graphics/text/PositionedGlyphs.java
@@ -184,7 +184,7 @@
             long ptr = nGetFont(layoutPtr, i);
             if (prevPtr != ptr) {
                 prevPtr = ptr;
-                prevFont = Font.findOrCreateFontFromNativePtr(ptr);
+                prevFont = new Font(ptr);
             }
             mFonts.add(prevFont);
         }
@@ -224,9 +224,7 @@
             if (getGlyphId(i) != that.getGlyphId(i)) return false;
             if (getGlyphX(i) != that.getGlyphX(i)) return false;
             if (getGlyphY(i) != that.getGlyphY(i)) return false;
-            // Intentionally using reference equality since font equality is heavy due to buffer
-            // compare.
-            if (getFont(i) != that.getFont(i)) return false;
+            if (!getFont(i).equals(that.getFont(i))) return false;
         }
 
         return true;
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index ce1d96c..f481228 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -335,7 +335,6 @@
         "jni/YuvToJpegEncoder.cpp",
         "jni/fonts/Font.cpp",
         "jni/fonts/FontFamily.cpp",
-        "jni/fonts/NativeFont.cpp",
         "jni/text/LineBreaker.cpp",
         "jni/text/MeasuredText.cpp",
         "jni/text/TextShaper.cpp",
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index 0fad2d5..e1f5abd7 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -69,7 +69,6 @@
 extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
 extern int register_android_graphics_fonts_Font(JNIEnv* env);
 extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
-extern int register_android_graphics_fonts_NativeFont(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
@@ -136,7 +135,6 @@
     REG_JNI(register_android_graphics_drawable_VectorDrawable),
     REG_JNI(register_android_graphics_fonts_Font),
     REG_JNI(register_android_graphics_fonts_FontFamily),
-    REG_JNI(register_android_graphics_fonts_NativeFont),
     REG_JNI(register_android_graphics_pdf_PdfDocument),
     REG_JNI(register_android_graphics_pdf_PdfEditor),
     REG_JNI(register_android_graphics_pdf_PdfRenderer),
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index b769d40..3392dac 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -34,6 +34,7 @@
 #include <hwui/Typeface.h>
 #include <minikin/FontFamily.h>
 #include <minikin/FontFileParser.h>
+#include <minikin/LocaleList.h>
 #include <ui/FatVector.h>
 
 #include <memory>
@@ -149,12 +150,8 @@
     return reinterpret_cast<jlong>(new FontWrapper(std::move(newFont)));
 }
 
-// Critical Native
-static jlong Font_Builder_getReleaseNativeFont(CRITICAL_JNI_PARAMS) {
-    return reinterpret_cast<jlong>(releaseFont);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
+// Font JNI functions
 
 // Fast Native
 static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint glyphId,
@@ -195,51 +192,92 @@
 }
 
 // Critical Native
-static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
-    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
-    return reinterpret_cast<jlong>(font->font.get());
+static jlong Font_getMinikinFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    return reinterpret_cast<jlong>(font->font->typeface().get());
 }
 
 // Critical Native
-static jlong Font_GetBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
-    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
-    const void* bufferPtr = font->font->typeface()->GetFontData();
-    return reinterpret_cast<jlong>(bufferPtr);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-struct FontBufferWrapper {
-    FontBufferWrapper(const std::shared_ptr<minikin::MinikinFont>& font) : minikinFont(font) {}
-    // MinikinFont holds a shared pointer of SkTypeface which has reference to font data.
-    std::shared_ptr<minikin::MinikinFont> minikinFont;
-};
-
-static void unrefBuffer(jlong nativePtr) {
-    FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
-    delete wrapper;
-}
-
-// Critical Native
-static jlong FontBufferHelper_refFontBuffer(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
-    const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
-    return reinterpret_cast<jlong>(new FontBufferWrapper(font->typeface()));
+static jlong Font_cloneFont(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    std::shared_ptr<minikin::Font> ref = font->font;
+    return reinterpret_cast<jlong>(new FontWrapper(std::move(ref)));
 }
 
 // Fast Native
-static jobject FontBufferHelper_wrapByteBuffer(JNIEnv* env, jobject, jlong nativePtr) {
-    FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
-    return env->NewDirectByteBuffer(
-        const_cast<void*>(wrapper->minikinFont->GetFontData()),
-        wrapper->minikinFont->GetFontSize());
+static jobject Font_newByteBuffer(JNIEnv* env, jobject, jlong fontPtr) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+    return env->NewDirectByteBuffer(const_cast<void*>(minikinFont->GetFontData()),
+                                    minikinFont->GetFontSize());
 }
 
 // Critical Native
-static jlong FontBufferHelper_getReleaseFunc(CRITICAL_JNI_PARAMS) {
-    return reinterpret_cast<jlong>(unrefBuffer);
+static jlong Font_getBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    return reinterpret_cast<jlong>(font->font->typeface()->GetFontData());
 }
 
-///////////////////////////////////////////////////////////////////////////////
+// Critical Native
+static jlong Font_getReleaseNativeFontFunc() {
+    return reinterpret_cast<jlong>(releaseFont);
+}
+
+// Fast Native
+static jstring Font_getFontPath(JNIEnv* env, jobject, jlong fontPtr) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+    const std::string& path = minikinFont->GetFontPath();
+    if (path.empty()) {
+        return nullptr;
+    }
+    return env->NewStringUTF(path.c_str());
+}
+
+// Fast Native
+static jstring Font_getLocaleList(JNIEnv* env, jobject, jlong fontPtr) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    uint32_t localeListId = font->font->getLocaleListId();
+    if (localeListId == 0) {
+        return nullptr;
+    }
+    std::string langTags = minikin::getLocaleString(localeListId);
+    if (langTags.empty()) {
+        return nullptr;
+    }
+    return env->NewStringUTF(langTags.c_str());
+}
+
+// Critical Native
+static jint Font_getPackedStyle(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    uint32_t weight = font->font->style().weight();
+    uint32_t isItalic = font->font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 1 : 0;
+    return (isItalic << 16) | weight;
+}
+
+// Critical Native
+static jint Font_getIndex(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+    return minikinFont->GetFontIndex();
+}
+
+// Critical Native
+static jint Font_getAxisCount(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+    return minikinFont->GetAxes().size();
+}
+
+// Critical Native
+static jlong Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr, jint index) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+    minikin::FontVariation var = minikinFont->GetAxes().at(index);
+    uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
+    return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
+}
 
 // Fast Native
 static jlong FontFileUtil_getFontRevision(JNIEnv* env, jobject, jobject buffer, jint index) {
@@ -314,20 +352,23 @@
         {"nBuild", "(JLjava/nio/ByteBuffer;Ljava/lang/String;Ljava/lang/String;IZI)J",
          (void*)Font_Builder_build},
         {"nClone", "(JJIZI)J", (void*)Font_Builder_clone},
-        {"nGetReleaseNativeFont", "()J", (void*)Font_Builder_getReleaseNativeFont},
 };
 
 static const JNINativeMethod gFontMethods[] = {
-    { "nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*) Font_getGlyphBounds },
-    { "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
-    { "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr },
-    { "nGetFontBufferAddress", "(J)J", (void*) Font_GetBufferAddress },
-};
-
-static const JNINativeMethod gFontBufferHelperMethods[] = {
-    { "nRefFontBuffer", "(J)J", (void*) FontBufferHelper_refFontBuffer },
-    { "nWrapByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*) FontBufferHelper_wrapByteBuffer },
-    { "nGetReleaseFunc", "()J", (void*) FontBufferHelper_getReleaseFunc },
+        {"nGetMinikinFontPtr", "(J)J", (void*)Font_getMinikinFontPtr},
+        {"nCloneFont", "(J)J", (void*)Font_cloneFont},
+        {"nNewByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*)Font_newByteBuffer},
+        {"nGetBufferAddress", "(J)J", (void*)Font_getBufferAddress},
+        {"nGetReleaseNativeFont", "()J", (void*)Font_getReleaseNativeFontFunc},
+        {"nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*)Font_getGlyphBounds},
+        {"nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F",
+         (void*)Font_getFontMetrics},
+        {"nGetFontPath", "(J)Ljava/lang/String;", (void*)Font_getFontPath},
+        {"nGetLocaleList", "(J)Ljava/lang/String;", (void*)Font_getLocaleList},
+        {"nGetPackedStyle", "(J)I", (void*)Font_getPackedStyle},
+        {"nGetIndex", "(J)I", (void*)Font_getIndex},
+        {"nGetAxisCount", "(J)I", (void*)Font_getAxisCount},
+        {"nGetAxisInfo", "(JI)J", (void*)Font_getAxisInfo},
 };
 
 static const JNINativeMethod gFontFileUtilMethods[] = {
@@ -343,8 +384,6 @@
             NELEM(gFontBuilderMethods)) +
             RegisterMethodsOrDie(env, "android/graphics/fonts/Font", gFontMethods,
             NELEM(gFontMethods)) +
-            RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFontBufferHelper",
-            gFontBufferHelperMethods, NELEM(gFontBufferHelperMethods)) +
             RegisterMethodsOrDie(env, "android/graphics/fonts/FontFileUtil", gFontFileUtilMethods,
             NELEM(gFontFileUtilMethods));
 }
diff --git a/libs/hwui/jni/fonts/FontFamily.cpp b/libs/hwui/jni/fonts/FontFamily.cpp
index a07723f..c40594d 100644
--- a/libs/hwui/jni/fonts/FontFamily.cpp
+++ b/libs/hwui/jni/fonts/FontFamily.cpp
@@ -100,17 +100,31 @@
     return static_cast<jint>(family->family->variant());
 }
 
+// CriticalNative
+static jint FontFamily_getFontSize(jlong familyPtr) {
+    FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
+    return family->family->getNumFonts();
+}
+
+// CriticalNative
+static jlong FontFamily_getFont(jlong familyPtr, jint index) {
+    FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
+    std::shared_ptr<minikin::Font> font = family->family->getFontRef(index);
+    return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gFontFamilyBuilderMethods[] = {
     { "nInitBuilder", "()J", (void*) FontFamily_Builder_initBuilder },
     { "nAddFont", "(JJ)V", (void*) FontFamily_Builder_addFont },
     { "nBuild", "(JLjava/lang/String;IZ)J", (void*) FontFamily_Builder_build },
-
     { "nGetReleaseNativeFamily", "()J", (void*) FontFamily_Builder_GetReleaseFunc },
 };
 
 static const JNINativeMethod gFontFamilyMethods[] = {
+        {"nGetFontSize", "(J)I", (void*)FontFamily_getFontSize},
+        {"nGetFont", "(JI)J", (void*)FontFamily_getFont},
         {"nGetLangTags", "(J)Ljava/lang/String;", (void*)FontFamily_getLangTags},
         {"nGetVariant", "(J)I", (void*)FontFamily_getVariant},
 };
diff --git a/libs/hwui/jni/fonts/NativeFont.cpp b/libs/hwui/jni/fonts/NativeFont.cpp
deleted file mode 100644
index c5c5d46..0000000
--- a/libs/hwui/jni/fonts/NativeFont.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "Minikin"
-
-#include "Font.h"
-#include "SkData.h"
-#include "SkFont.h"
-#include "SkFontMetrics.h"
-#include "SkFontMgr.h"
-#include "SkRefCnt.h"
-#include "SkTypeface.h"
-#include "GraphicsJNI.h"
-#include <nativehelper/ScopedUtfChars.h>
-#include "Utils.h"
-#include "FontUtils.h"
-
-#include <hwui/MinikinSkia.h>
-#include <hwui/Paint.h>
-#include <hwui/Typeface.h>
-#include <minikin/FontFamily.h>
-#include <minikin/LocaleList.h>
-#include <ui/FatVector.h>
-
-#include <memory>
-
-namespace android {
-
-// Critical Native
-static jint NativeFont_getFamilyCount(CRITICAL_JNI_PARAMS_COMMA jlong typefaceHandle) {
-    Typeface* tf = reinterpret_cast<Typeface*>(typefaceHandle);
-    return tf->fFontCollection->getFamilies().size();
-}
-
-// Critical Native
-static jlong NativeFont_getFamily(CRITICAL_JNI_PARAMS_COMMA jlong typefaceHandle, jint index) {
-    Typeface* tf = reinterpret_cast<Typeface*>(typefaceHandle);
-    return reinterpret_cast<jlong>(tf->fFontCollection->getFamilies()[index].get());
-
-}
-
-// Fast Native
-static jstring NativeFont_getLocaleList(JNIEnv* env, jobject, jlong familyHandle) {
-    minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
-    uint32_t localeListId = family->localeListId();
-    return env->NewStringUTF(minikin::getLocaleString(localeListId).c_str());
-}
-
-// Critical Native
-static jint NativeFont_getFontCount(CRITICAL_JNI_PARAMS_COMMA jlong familyHandle) {
-    minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
-    return family->getNumFonts();
-}
-
-// Critical Native
-static jlong NativeFont_getFont(CRITICAL_JNI_PARAMS_COMMA jlong familyHandle, jint index) {
-    minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
-    return reinterpret_cast<jlong>(family->getFont(index));
-}
-
-// Critical Native
-static jlong NativeFont_getFontInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
-    const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
-    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
-
-    uint64_t result = font->style().weight();
-    result |= font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 0x10000 : 0x00000;
-    result |= ((static_cast<uint64_t>(minikinSkia->GetFontIndex())) << 32);
-    result |= ((static_cast<uint64_t>(minikinSkia->GetAxes().size())) << 48);
-    return result;
-}
-
-// Critical Native
-static jlong NativeFont_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle, jint index) {
-    const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
-    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
-    const minikin::FontVariation& var = minikinSkia->GetAxes().at(index);
-    uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
-    return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
-}
-
-// FastNative
-static jstring NativeFont_getFontPath(JNIEnv* env, jobject, jlong fontHandle) {
-    const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
-    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
-    const std::string& filePath = minikinSkia->getFilePath();
-    if (filePath.empty()) {
-        return nullptr;
-    }
-    return env->NewStringUTF(filePath.c_str());
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static const JNINativeMethod gNativeFontMethods[] = {
-    { "nGetFamilyCount", "(J)I", (void*) NativeFont_getFamilyCount },
-    { "nGetFamily", "(JI)J", (void*) NativeFont_getFamily },
-    { "nGetLocaleList", "(J)Ljava/lang/String;", (void*) NativeFont_getLocaleList },
-    { "nGetFontCount", "(J)I", (void*) NativeFont_getFontCount },
-    { "nGetFont", "(JI)J", (void*) NativeFont_getFont },
-    { "nGetFontInfo", "(J)J", (void*) NativeFont_getFontInfo },
-    { "nGetAxisInfo", "(JI)J", (void*) NativeFont_getAxisInfo },
-    { "nGetFontPath", "(J)Ljava/lang/String;", (void*) NativeFont_getFontPath },
-};
-
-int register_android_graphics_fonts_NativeFont(JNIEnv* env) {
-    return RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFont", gNativeFontMethods,
-            NELEM(gNativeFontMethods));
-}
-
-}  // namespace android
diff --git a/libs/hwui/jni/text/TextShaper.cpp b/libs/hwui/jni/text/TextShaper.cpp
index 9785aa5..a6fb958 100644
--- a/libs/hwui/jni/text/TextShaper.cpp
+++ b/libs/hwui/jni/text/TextShaper.cpp
@@ -23,13 +23,14 @@
 #include <set>
 #include <algorithm>
 
-#include "SkPaint.h"
-#include "SkTypeface.h"
 #include <hwui/MinikinSkia.h>
 #include <hwui/MinikinUtils.h>
 #include <hwui/Paint.h>
-#include <minikin/MinikinPaint.h>
 #include <minikin/MinikinFont.h>
+#include <minikin/MinikinPaint.h>
+#include "FontUtils.h"
+#include "SkPaint.h"
+#include "SkTypeface.h"
 
 namespace android {
 
@@ -149,7 +150,8 @@
 // CriticalNative
 static jlong TextShaper_Result_getFont(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
     const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
-    return reinterpret_cast<jlong>(layout->layout.getFont(i));
+    std::shared_ptr<minikin::Font> fontRef = layout->layout.getFontRef(i);
+    return reinterpret_cast<jlong>(new FontWrapper(std::move(fontRef)));
 }
 
 // CriticalNative