diff options
| -rw-r--r-- | graphics/java/android/graphics/fonts/Font.java | 274 | ||||
| -rw-r--r-- | graphics/java/android/graphics/fonts/FontFamily.java | 15 | ||||
| -rw-r--r-- | graphics/java/android/graphics/fonts/NativeFont.java | 205 | ||||
| -rw-r--r-- | graphics/java/android/graphics/fonts/NativeFontBufferHelper.java | 62 | ||||
| -rw-r--r-- | graphics/java/android/graphics/text/PositionedGlyphs.java | 6 | ||||
| -rw-r--r-- | libs/hwui/Android.bp | 1 | ||||
| -rw-r--r-- | libs/hwui/apex/jni_runtime.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/jni/fonts/Font.cpp | 131 | ||||
| -rw-r--r-- | libs/hwui/jni/fonts/FontFamily.cpp | 16 | ||||
| -rw-r--r-- | libs/hwui/jni/fonts/NativeFont.cpp | 125 | ||||
| -rw-r--r-- | libs/hwui/jni/text/TextShaper.cpp | 10 |
11 files changed, 283 insertions, 564 deletions
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index 9214ff1eb088..b153c995a7f4 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -26,8 +26,7 @@ import android.graphics.Paint; 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.FileInputStream; 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 @@ public final class Font { 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 @@ public final class Font { * 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 @@ public final class Font { 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 @@ public final class Font { } 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 @@ public final class Font { * @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 @@ public final class Font { * @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 @@ public final class Font { * @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 @@ public final class Font { * @return a TTC index value */ public @IntRange(from = 0) int getTtcIndex() { - return mTtcIndex; + return nGetIndex(mNativePtr); } /** @@ -608,7 +620,23 @@ public final class Font { * @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 @@ public final class Font { * @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 @@ public final class Font { * @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 @@ public final class Font { 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 @@ public final class Font { // 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 @@ public final class Font { 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 @@ public final class Font { @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 @@ public final class Font { @FastNative private static native float nGetFontMetrics(long font, long paint, Paint.FontMetrics metrics); + @FastNative + private static native String nGetFontPath(long fontPtr); + + @FastNative + private static native String nGetLocaleList(long familyPtr); + + @CriticalNative + private static native int nGetPackedStyle(long fontPtr); + + @CriticalNative + private static native int nGetIndex(long fontPtr); + @CriticalNative - private static native long nGetNativeFontPtr(long ptr); + private static native int nGetAxisCount(long fontPtr); @CriticalNative - private static native long nGetFontBufferAddress(long font); + 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 77f86fe726f3..8c13d3e7e51d 100644 --- a/graphics/java/android/graphics/fonts/FontFamily.java +++ b/graphics/java/android/graphics/fonts/FontFamily.java @@ -143,12 +143,10 @@ public final class FontFamily { 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 @@ public final class FontFamily { * @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 @@ public final class FontFamily { * @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 @@ public final class FontFamily { 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 9e9d76a89385..000000000000 --- 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 5655e7fafc1b..000000000000 --- 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 c2de0acebca9..8d20e9cee7d7 100644 --- a/graphics/java/android/graphics/text/PositionedGlyphs.java +++ b/graphics/java/android/graphics/text/PositionedGlyphs.java @@ -184,7 +184,7 @@ public final class PositionedGlyphs { 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 @@ public final class PositionedGlyphs { 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 ce1d96c167d7..f48122858267 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -335,7 +335,6 @@ cc_defaults { "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 0fad2d58cc8a..e1f5abd786bf 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_AnimatedVectorDrawable(JNIEnv* env 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 @@ static const RegJNIRec gRegJNI[] = { 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 b769d40238a4..3392dac02493 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 @@ static jlong Font_Builder_clone(JNIEnv* env, jobject clazz, jlong fontPtr, jlong 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 @@ static jfloat Font_getFontMetrics(JNIEnv* env, jobject, jlong fontHandle, jlong } // 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); +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))); } -/////////////////////////////////////////////////////////////////////////////// - -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; -}; +// Fast Native +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()); +} -static void unrefBuffer(jlong nativePtr) { - FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr); - delete wrapper; +// Critical Native +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 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_getReleaseNativeFontFunc() { + return reinterpret_cast<jlong>(releaseFont); } // 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 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 jlong FontBufferHelper_getReleaseFunc(CRITICAL_JNI_PARAMS) { - return reinterpret_cast<jlong>(unrefBuffer); +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 @@ static const JNINativeMethod gFontBuilderMethods[] = { {"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 @@ int register_android_graphics_fonts_Font(JNIEnv* env) { 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 8fe6da3183f4..80964794efb2 100644 --- a/libs/hwui/jni/fonts/FontFamily.cpp +++ b/libs/hwui/jni/fonts/FontFamily.cpp @@ -100,17 +100,31 @@ static jint FontFamily_getVariant(CRITICAL_JNI_PARAMS_COMMA jlong familyPtr) { 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 c5c5d464ccac..000000000000 --- 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 9785aa537f65..a6fb95832c03 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 @@ static jfloat TextShaper_Result_getY(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i // 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 |