Calculate set of available fonts in native
The previous attempt[1] of improving SystemFonts API is not good enough
for users. To further improve the performance, calculate font uniqueness
in native code. From Android S, the system font information is stored
in native code and has more information for skipping duplication check.
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
Test: minikin_tests
Change-Id: Ib375dcda0f278c93ec8dd21636d7a22b4174f214
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 69cd8bd..cd7936d 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -46,7 +46,10 @@
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.IdentityHashMap;
import java.util.Objects;
+import java.util.Set;
/**
* A font class can be used for creating FontFamily.
@@ -859,6 +862,18 @@
+ "}";
}
+ /** @hide */
+ public static Set<Font> getAvailableFonts() {
+ // The font uniqueness is already calculated in the native code. So use IdentityHashMap
+ // for avoiding hash/equals calculation.
+ IdentityHashMap<Font, Font> map = new IdentityHashMap<>();
+ for (long nativePtr : nGetAvailableFontSet()) {
+ Font font = new Font(nativePtr);
+ map.put(font, font);
+ }
+ return Collections.unmodifiableSet(map.keySet());
+ }
+
@CriticalNative
private static native long nGetMinikinFontPtr(long font);
@@ -900,4 +915,7 @@
@CriticalNative
private static native long nGetAxisInfo(long fontPtr, int i);
+
+ @FastNative
+ private static native long[] nGetAvailableFontSet();
}
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 8d69d44..6278c0e 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -22,7 +22,6 @@
import android.graphics.Typeface;
import android.text.FontConfig;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -39,7 +38,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
/**
@@ -61,36 +59,6 @@
private static @GuardedBy("sLock") Set<Font> sAvailableFonts;
/**
- * 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.
*
* @return a set of system fonts
@@ -98,25 +66,7 @@
public static @NonNull Set<Font> getAvailableFonts() {
synchronized (LOCK) {
if (sAvailableFonts == null) {
- 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(new SystemFontHashWrapper(family.getFont(j)));
- }
- }
- }
-
- // 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);
+ sAvailableFonts = Font.getAvailableFonts();
}
return sAvailableFonts;
}
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 5a972f5..bd3b7c9 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -35,6 +35,7 @@
#include <minikin/FontFamily.h>
#include <minikin/FontFileParser.h>
#include <minikin/LocaleList.h>
+#include <minikin/SystemFonts.h>
#include <ui/FatVector.h>
#include <memory>
@@ -282,6 +283,22 @@
return font->font->typeface()->GetSourceId();
}
+static jlongArray Font_getAvailableFontSet(JNIEnv* env, jobject) {
+ std::vector<jlong> refArray;
+ minikin::SystemFonts::getFontSet(
+ [&refArray](const std::vector<std::shared_ptr<minikin::Font>>& fontSet) {
+ refArray.reserve(fontSet.size());
+ for (const auto& font : fontSet) {
+ std::shared_ptr<minikin::Font> fontRef = font;
+ refArray.push_back(
+ reinterpret_cast<jlong>(new FontWrapper(std::move(fontRef))));
+ }
+ });
+ jlongArray r = env->NewLongArray(refArray.size());
+ env->SetLongArrayRegion(r, 0, refArray.size(), refArray.data());
+ return r;
+}
+
// Fast Native
static jlong FontFileUtil_getFontRevision(JNIEnv* env, jobject, jobject buffer, jint index) {
NPE_CHECK_RETURN_ZERO(env, buffer);
@@ -373,6 +390,9 @@
{"nGetAxisCount", "(J)I", (void*)Font_getAxisCount},
{"nGetAxisInfo", "(JI)J", (void*)Font_getAxisInfo},
{"nGetSourceId", "(J)I", (void*)Font_getSourceId},
+
+ // System font accessors
+ {"nGetAvailableFontSet", "()[J", (void*)Font_getAvailableFontSet},
};
static const JNINativeMethod gFontFileUtilMethods[] = {