From 5abd5dfd9dd6b3311f99b3923e574500c3e92f23 Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Mon, 17 May 2021 14:38:58 -0700 Subject: [PATCH] Skip buffer equality check for SystemFonts All system font files are file backed and stored in the unique place, so no need to compare the buffers during creating sets of system fonts. Bug: 188201287 Test: atest FontFamilyUpdateRequestTest Test: atest FontListParserTest Test: atest FontManagerTest Test: atest NativeSystemFontTest Test: atest PersistentSystemFontConfigTest Test: atest SystemFontsTest Test: atest SystemFontsUniqueNameTest Test: atest UpdatableFontDirTest Test: atest UpdatableSystemFontTest Change-Id: I4a4680937988c013aaa4e4fa729e61ac8514c513 --- .../java/android/graphics/fonts/Font.java | 17 ++++--- .../android/graphics/fonts/SystemFonts.java | 47 +++++++++++++++++-- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index f826b24b2df2f..69cd8bdb3e700 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -801,6 +801,15 @@ public final class Font { return myBuffer.equals(otherBuffer); } + /** @hide */ + public boolean paramEquals(@NonNull Font f) { + return f.getStyle().equals(getStyle()) + && f.getTtcIndex() == getTtcIndex() + && Arrays.equals(f.getAxes(), getAxes()) + && Objects.equals(f.getLocaleList(), getLocaleList()) + && Objects.equals(getFile(), f.getFile()); + } + @Override public boolean equals(@Nullable Object o) { if (o == this) { @@ -818,13 +827,7 @@ public final class Font { 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) { + if (!paramEquals(f)) { return false; } diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index 0da2b5146fb55..8d69d447f4e0c 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; /** @@ -46,7 +47,6 @@ import java.util.Set; */ public final class SystemFonts { private static final String TAG = "SystemFonts"; - private static final String DEFAULT_FAMILY = "sans-serif"; private static final String FONTS_XML = "/system/etc/fonts.xml"; /** @hide */ @@ -59,7 +59,36 @@ public final class SystemFonts { private static final Object LOCK = new Object(); private static @GuardedBy("sLock") Set sAvailableFonts; - private static @GuardedBy("sLock") Map sFamilyMap; + + /** + * Helper wrapper class for skipping buffer equality check of Font#equals. + * + * Due to historical reasons, the Font#equals checks the byte-by-byte buffer equality which + * requires heavy IO work in getAvailableFonts. Since the fonts came from system are all regular + * file backed font instance and stored in the unique place, just comparing file path should be + * good enough for this case. + */ + private static final class SystemFontHashWrapper { + private final Font mFont; + SystemFontHashWrapper(Font font) { + mFont = font; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + // All system fonts are regular-file backed font instance, so no need to + // compare buffers. + return mFont.paramEquals(((SystemFontHashWrapper) o).mFont); + } + + @Override + public int hashCode() { + return Objects.hash(mFont); + } + } /** * Returns all available font files in the system. @@ -69,17 +98,25 @@ public final class SystemFonts { public static @NonNull Set getAvailableFonts() { synchronized (LOCK) { if (sAvailableFonts == null) { - Set set = new ArraySet<>(); + Set set = new ArraySet<>(); for (Typeface tf : Typeface.getSystemFontMap().values()) { List families = tf.getFallback(); for (int i = 0; i < families.size(); ++i) { FontFamily family = families.get(i); for (int j = 0; j < family.getSize(); ++j) { - set.add(family.getFont(j)); + set.add(new SystemFontHashWrapper(family.getFont(j))); } } } - sAvailableFonts = Collections.unmodifiableSet(set); + + // Unwrapping font instance for Set interface. The ArraySet#add won't call + // Font#equals function if none of two objects has the same hash, so following + // unwrapping won't cause bad performance due to byte-by-byte equality check. + ArraySet result = new ArraySet(set.size()); + for (SystemFontHashWrapper wrapper : set) { + result.add(wrapper.mFont); + } + sAvailableFonts = Collections.unmodifiableSet(result); } return sAvailableFonts; }