diff options
author | Seigo Nonaka <nona@google.com> | 2021-04-14 19:15:16 -0700 |
---|---|---|
committer | Seigo Nonaka <nona@google.com> | 2021-04-15 11:03:37 -0700 |
commit | b950a1f746c9e130c78eafefc9bfd7ec87da730f (patch) | |
tree | d16d7f3c1481d82227edcfb3cef1679ceb230db5 | |
parent | 9e2adae46b250980d3b5f4ece7f6e4bfc363a8b5 (diff) |
Update native font API to read updated font files.
Bug: 184974821
Test: atest NativeSystemFontTest
Change-Id: Ia7fdf6155e07445d7f16edb88fd2a7293e63080c
-rw-r--r-- | apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java | 4 | ||||
-rw-r--r-- | core/api/test-current.txt | 2 | ||||
-rw-r--r-- | core/tests/coretests/src/android/graphics/TypefaceTest.java | 6 | ||||
-rw-r--r-- | graphics/java/android/graphics/Typeface.java | 21 | ||||
-rw-r--r-- | libs/hwui/jni/Typeface.cpp | 7 | ||||
-rw-r--r-- | native/android/system_fonts.cpp | 102 |
6 files changed, 118 insertions, 24 deletions
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java index 547369055e95..d27250719c6d 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java @@ -20,6 +20,7 @@ import android.graphics.Typeface; import android.os.SharedMemory; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; +import android.util.ArrayMap; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; @@ -55,9 +56,10 @@ public class TypefaceSerializationPerfTest { ByteBuffer buffer = memory.mapReadOnly().order(ByteOrder.BIG_ENDIAN); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + ArrayMap<String, Typeface> out = new ArrayMap<>(); while (state.keepRunning()) { buffer.position(0); - Typeface.deserializeFontMap(buffer); + Typeface.deserializeFontMap(buffer, out); } } diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 04dd04cf03d2..23d0e787bf3a 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -995,7 +995,7 @@ package android.graphics { } public class Typeface { - method @NonNull public static java.util.Map<java.lang.String,android.graphics.Typeface> deserializeFontMap(@NonNull java.nio.ByteBuffer) throws java.io.IOException; + method @NonNull public static long[] deserializeFontMap(@NonNull java.nio.ByteBuffer, @NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws java.io.IOException; method @Nullable public static android.os.SharedMemory getSystemFontMapSharedMemory(); method @NonNull public static android.os.SharedMemory serializeFontMap(@NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws android.system.ErrnoException, java.io.IOException; } diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java index d12f495055e1..6defe9113132 100644 --- a/core/tests/coretests/src/android/graphics/TypefaceTest.java +++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java @@ -27,6 +27,7 @@ import android.graphics.fonts.FontFamily; import android.graphics.fonts.SystemFonts; import android.os.SharedMemory; import android.text.FontConfig; +import android.util.ArrayMap; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; @@ -200,8 +201,9 @@ public class TypefaceTest { Map<String, Typeface> systemFontMap = SystemFonts.buildSystemTypefaces(fontConfig, fallbackMap); SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap); - Map<String, Typeface> copiedFontMap = - Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN)); + Map<String, Typeface> copiedFontMap = new ArrayMap<>(); + Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN), + copiedFontMap); assertEquals(systemFontMap.size(), copiedFontMap.size()); for (String key : systemFontMap.keySet()) { assertTrue(copiedFontMap.containsKey(key)); diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index c48fd8b8b6ae..b88751a610dd 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -1259,20 +1259,21 @@ public class Typeface { * @hide */ @TestApi - public static @NonNull Map<String, Typeface> deserializeFontMap(@NonNull ByteBuffer buffer) + public static @NonNull long[] deserializeFontMap( + @NonNull ByteBuffer buffer, @NonNull Map<String, Typeface> out) throws IOException { - Map<String, Typeface> fontMap = new ArrayMap<>(); int typefacesBytesCount = buffer.getInt(); long[] nativePtrs = nativeReadTypefaces(buffer.slice()); if (nativePtrs == null) { throw new IOException("Could not read typefaces"); } + out.clear(); buffer.position(buffer.position() + typefacesBytesCount); for (long nativePtr : nativePtrs) { String name = readString(buffer); - fontMap.put(name, new Typeface(nativePtr)); + out.put(name, new Typeface(nativePtr)); } - return fontMap; + return nativePtrs; } private static String readString(ByteBuffer buffer) { @@ -1330,7 +1331,14 @@ public class Typeface { return; } sSystemFontMapBuffer = sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN); - Map<String, Typeface> systemFontMap = deserializeFontMap(sSystemFontMapBuffer); + Map<String, Typeface> systemFontMap = new ArrayMap<>(); + long[] nativePtrs = deserializeFontMap(sSystemFontMapBuffer, systemFontMap); + + // Initialize native font APIs. The native font API will read fonts.xml by itself if + // Typeface is initialized with loadPreinstalledSystemFontMap. + for (long ptr : nativePtrs) { + nativeAddFontCollections(ptr); + } setSystemFontMap(systemFontMap); } finally { Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); @@ -1528,5 +1536,8 @@ public class Typeface { private static native void nativeForceSetStaticFinalField(String fieldName, Typeface typeface); + @CriticalNative + private static native void nativeAddFontCollections(long nativePtr); + private static native void nativeWarmUpCache(String fileName); } diff --git a/libs/hwui/jni/Typeface.cpp b/libs/hwui/jni/Typeface.cpp index 251323d34422..f928baa27863 100644 --- a/libs/hwui/jni/Typeface.cpp +++ b/libs/hwui/jni/Typeface.cpp @@ -373,6 +373,12 @@ static void Typeface_warmUpCache(JNIEnv* env, jobject, jstring jFilePath) { makeSkDataCached(filePath.c_str(), false /* fs verity */); } +// Critical Native +static void Typeface_addFontCollection(CRITICAL_JNI_PARAMS_COMMA jlong faceHandle) { + std::shared_ptr<minikin::FontCollection> collection = toTypeface(faceHandle)->fFontCollection; + minikin::SystemFonts::addFontMap(std::move(collection)); +} + /////////////////////////////////////////////////////////////////////////////// static const JNINativeMethod gTypefaceMethods[] = { @@ -397,6 +403,7 @@ static const JNINativeMethod gTypefaceMethods[] = { {"nativeGetFamilySize", "(J)I", (void*)Typeface_getFamilySize}, {"nativeGetFamily", "(JI)J", (void*)Typeface_getFamily}, {"nativeWarmUpCache", "(Ljava/lang/String;)V", (void*)Typeface_warmUpCache}, + {"nativeAddFontCollections", "(J)V", (void*)Typeface_addFontCollection}, }; int register_android_graphics_Typeface(JNIEnv* env) diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp index 48d738039696..60b0f1eeaf72 100644 --- a/native/android/system_fonts.cpp +++ b/native/android/system_fonts.cpp @@ -54,21 +54,51 @@ struct ParserState { XmlCharUniquePtr mLocale; }; -struct ASystemFontIterator { - XmlDocUniquePtr mXmlDoc; - ParserState state; - - // The OEM customization XML. - XmlDocUniquePtr mCustomizationXmlDoc; -}; - struct AFont { std::string mFilePath; - std::unique_ptr<std::string> mLocale; + std::optional<std::string> mLocale; uint16_t mWeight; bool mItalic; uint32_t mCollectionIndex; std::vector<std::pair<uint32_t, float>> mAxes; + + bool operator==(const AFont& o) const { + return mFilePath == o.mFilePath && mLocale == o.mLocale && mWeight == o.mWeight && + mItalic == o.mItalic && mCollectionIndex == o.mCollectionIndex && mAxes == o.mAxes; + } + + AFont() = default; + AFont(const AFont&) = default; +}; + +struct FontHasher { + std::size_t operator()(const AFont& font) const { + std::size_t r = std::hash<std::string>{}(font.mFilePath); + if (font.mLocale) { + r = combine(r, std::hash<std::string>{}(*font.mLocale)); + } + r = combine(r, std::hash<uint16_t>{}(font.mWeight)); + r = combine(r, std::hash<uint32_t>{}(font.mCollectionIndex)); + for (const auto& [tag, value] : font.mAxes) { + r = combine(r, std::hash<uint32_t>{}(tag)); + r = combine(r, std::hash<float>{}(value)); + } + return r; + } + + std::size_t combine(std::size_t l, std::size_t r) const { return l ^ (r << 1); } +}; + +struct ASystemFontIterator { + std::vector<AFont> fonts; + uint32_t index; + + XmlDocUniquePtr mXmlDoc; + + ParserState state; + + // The OEM customization XML. + XmlDocUniquePtr mCustomizationXmlDoc; }; struct AFontMatcher { @@ -147,10 +177,9 @@ void copyFont(const XmlDocUniquePtr& xmlDoc, const ParserState& state, AFont* ou out->mCollectionIndex = indexStr ? strtol(reinterpret_cast<const char*>(indexStr.get()), nullptr, 10) : 0; - out->mLocale.reset( - state.mLocale ? - new std::string(reinterpret_cast<const char*>(state.mLocale.get())) - : nullptr); + if (state.mLocale) { + out->mLocale.emplace(reinterpret_cast<const char*>(state.mLocale.get())); + } const xmlChar* TAG_ATTR_NAME = BAD_CAST("tag"); const xmlChar* STYLEVALUE_ATTR_NAME = BAD_CAST("stylevalue"); @@ -214,8 +243,44 @@ bool findFirstFontNode(const XmlDocUniquePtr& doc, ParserState* state) { ASystemFontIterator* ASystemFontIterator_open() { std::unique_ptr<ASystemFontIterator> ite(new ASystemFontIterator()); - ite->mXmlDoc.reset(xmlReadFile("/system/etc/fonts.xml", nullptr, 0)); - ite->mCustomizationXmlDoc.reset(xmlReadFile("/product/etc/fonts_customization.xml", nullptr, 0)); + + std::unordered_set<AFont, FontHasher> fonts; + minikin::SystemFonts::getFontMap( + [&fonts](const std::vector<std::shared_ptr<minikin::FontCollection>>& collections) { + for (const auto& fc : collections) { + for (const auto& family : fc->getFamilies()) { + for (uint32_t i = 0; i < family->getNumFonts(); ++i) { + const minikin::Font* font = family->getFont(i); + + std::optional<std::string> locale; + uint32_t localeId = font->getLocaleListId(); + if (localeId != minikin::kEmptyLocaleListId) { + locale.emplace(minikin::getLocaleString(localeId)); + } + std::vector<std::pair<uint32_t, float>> axes; + for (const auto& [tag, value] : font->typeface()->GetAxes()) { + axes.push_back(std::make_pair(tag, value)); + } + + fonts.insert( + {font->typeface()->GetFontPath(), std::move(locale), + font->style().weight(), + font->style().slant() == minikin::FontStyle::Slant::ITALIC, + static_cast<uint32_t>(font->typeface()->GetFontIndex()), + axes}); + } + } + } + }); + + if (fonts.empty()) { + ite->mXmlDoc.reset(xmlReadFile("/system/etc/fonts.xml", nullptr, 0)); + ite->mCustomizationXmlDoc.reset( + xmlReadFile("/product/etc/fonts_customization.xml", nullptr, 0)); + } else { + ite->index = 0; + ite->fonts.assign(fonts.begin(), fonts.end()); + } return ite.release(); } @@ -308,6 +373,13 @@ bool findNextFontNode(const XmlDocUniquePtr& xmlDoc, ParserState* state) { AFont* ASystemFontIterator_next(ASystemFontIterator* ite) { LOG_ALWAYS_FATAL_IF(ite == nullptr, "nullptr has passed as iterator argument"); + if (!ite->fonts.empty()) { + if (ite->index >= ite->fonts.size()) { + return nullptr; + } + return new AFont(ite->fonts[ite->index++]); + } + if (ite->mXmlDoc) { if (!findNextFontNode(ite->mXmlDoc, &ite->state)) { // Reached end of the XML file. Continue OEM customization. |