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
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index f826b24..69cd8bd 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -801,6 +801,15 @@
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 @@
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 0da2b51..8d69d44 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -39,6 +39,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -46,7 +47,6 @@
*/
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 @@
private static final Object LOCK = new Object();
private static @GuardedBy("sLock") Set<Font> sAvailableFonts;
- private static @GuardedBy("sLock") Map<String, FontFamily[]> 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 static @NonNull Set<Font> getAvailableFonts() {
synchronized (LOCK) {
if (sAvailableFonts == null) {
- Set<Font> set = new ArraySet<>();
+ Set<SystemFontHashWrapper> set = new ArraySet<>();
for (Typeface tf : Typeface.getSystemFontMap().values()) {
List<FontFamily> 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<Font> 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<Font> result = new ArraySet(set.size());
+ for (SystemFontHashWrapper wrapper : set) {
+ result.add(wrapper.mFont);
+ }
+ sAvailableFonts = Collections.unmodifiableSet(result);
}
return sAvailableFonts;
}