Merge "Skip buffer equality check for SystemFonts" into sc-dev

This commit is contained in:
Seigo Nonaka
2021-05-21 05:03:38 +00:00
committed by Android (Google) Code Review
2 changed files with 52 additions and 12 deletions

View File

@@ -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;
}

View File

@@ -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<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 final class SystemFonts {
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;
}