Loading graphics/java/android/graphics/fonts/Font.java +42 −5 Original line number Diff line number Diff line Loading @@ -523,6 +523,9 @@ public final class Font { /** * Returns a font file buffer. * * Duplicate before reading values by {@link ByteBuffer#duplicate()} for avoiding unexpected * reading position sharing. * * @return a font buffer */ public @NonNull ByteBuffer getBuffer() { Loading Loading @@ -628,18 +631,49 @@ public final class Font { if (o == this) { return true; } if (o == null || !(o instanceof Font)) { if (!(o instanceof Font)) { return false; } Font f = (Font) o; return mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex && Arrays.equals(f.mAxes, mAxes) && f.mBuffer.equals(mBuffer) && Objects.equals(f.mLocaleList, mLocaleList); boolean paramEqual = mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex && Arrays.equals(f.mAxes, mAxes) && Objects.equals(f.mLocaleList, mLocaleList) && Objects.equals(mFile, f.mFile); if (!paramEqual) { return false; } // Shortcut for different font buffer check by comparing size. if (mBuffer.capacity() != f.mBuffer.capacity()) { return false; } // ByteBuffer#equals compares all bytes which is not performant for e.g HashMap. Since // 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 (nIsSameBufferAddress(mNativePtr, f.mNativePtr) && mBuffer.position() == f.mBuffer.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(f.mBuffer); } @Override public int hashCode() { return Objects.hash(mFontStyle, mTtcIndex, Arrays.hashCode(mAxes), mBuffer, mLocaleList); return Objects.hash( mFontStyle, mTtcIndex, Arrays.hashCode(mAxes), // 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); } @Override Loading Loading @@ -724,4 +758,7 @@ public final class Font { @CriticalNative private static native long nGetNativeFontPtr(long ptr); @CriticalNative private static native boolean nIsSameBufferAddress(long lFontPtr, long rFontPtr); } libs/hwui/jni/fonts/Font.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -238,6 +238,16 @@ static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) { return reinterpret_cast<jlong>(font->font.get()); } // Critical Native static jboolean Font_isSameBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong lFontHandle, jlong rFontHandle) { FontWrapper* lFont = reinterpret_cast<FontWrapper*>(lFontHandle); FontWrapper* rFont = reinterpret_cast<FontWrapper*>(rFontHandle); const void* lBufferPtr = lFont->font->typeface()->GetFontData(); const void* rBufferPtr = rFont->font->typeface()->GetFontData(); return lBufferPtr == rBufferPtr; } /////////////////////////////////////////////////////////////////////////////// struct FontBufferWrapper { Loading Loading @@ -287,6 +297,7 @@ static const JNINativeMethod gFontMethods[] = { { "nGetAxisInfo", "(JI)J", (void*) Font_getAxisInfo }, { "nGetFontPath", "(J)Ljava/lang/String;", (void*) Font_getFontPath }, { "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr }, { "nIsSameBufferAddress", "(JJ)Z", (void*) Font_isSameBufferAddress }, }; static const JNINativeMethod gFontBufferHelperMethods[] = { Loading Loading
graphics/java/android/graphics/fonts/Font.java +42 −5 Original line number Diff line number Diff line Loading @@ -523,6 +523,9 @@ public final class Font { /** * Returns a font file buffer. * * Duplicate before reading values by {@link ByteBuffer#duplicate()} for avoiding unexpected * reading position sharing. * * @return a font buffer */ public @NonNull ByteBuffer getBuffer() { Loading Loading @@ -628,18 +631,49 @@ public final class Font { if (o == this) { return true; } if (o == null || !(o instanceof Font)) { if (!(o instanceof Font)) { return false; } Font f = (Font) o; return mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex && Arrays.equals(f.mAxes, mAxes) && f.mBuffer.equals(mBuffer) && Objects.equals(f.mLocaleList, mLocaleList); boolean paramEqual = mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex && Arrays.equals(f.mAxes, mAxes) && Objects.equals(f.mLocaleList, mLocaleList) && Objects.equals(mFile, f.mFile); if (!paramEqual) { return false; } // Shortcut for different font buffer check by comparing size. if (mBuffer.capacity() != f.mBuffer.capacity()) { return false; } // ByteBuffer#equals compares all bytes which is not performant for e.g HashMap. Since // 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 (nIsSameBufferAddress(mNativePtr, f.mNativePtr) && mBuffer.position() == f.mBuffer.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(f.mBuffer); } @Override public int hashCode() { return Objects.hash(mFontStyle, mTtcIndex, Arrays.hashCode(mAxes), mBuffer, mLocaleList); return Objects.hash( mFontStyle, mTtcIndex, Arrays.hashCode(mAxes), // 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); } @Override Loading Loading @@ -724,4 +758,7 @@ public final class Font { @CriticalNative private static native long nGetNativeFontPtr(long ptr); @CriticalNative private static native boolean nIsSameBufferAddress(long lFontPtr, long rFontPtr); }
libs/hwui/jni/fonts/Font.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -238,6 +238,16 @@ static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) { return reinterpret_cast<jlong>(font->font.get()); } // Critical Native static jboolean Font_isSameBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong lFontHandle, jlong rFontHandle) { FontWrapper* lFont = reinterpret_cast<FontWrapper*>(lFontHandle); FontWrapper* rFont = reinterpret_cast<FontWrapper*>(rFontHandle); const void* lBufferPtr = lFont->font->typeface()->GetFontData(); const void* rBufferPtr = rFont->font->typeface()->GetFontData(); return lBufferPtr == rBufferPtr; } /////////////////////////////////////////////////////////////////////////////// struct FontBufferWrapper { Loading Loading @@ -287,6 +297,7 @@ static const JNINativeMethod gFontMethods[] = { { "nGetAxisInfo", "(JI)J", (void*) Font_getAxisInfo }, { "nGetFontPath", "(J)Ljava/lang/String;", (void*) Font_getFontPath }, { "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr }, { "nIsSameBufferAddress", "(JJ)Z", (void*) Font_isSameBufferAddress }, }; static const JNINativeMethod gFontBufferHelperMethods[] = { Loading