Support serializing Java Typeface.

Bug: 169871852
Test: atest FrameworksCoreTests:TypefaceTest
Change-Id: I3b4315440e2ef6d45f0f9bf526b1980a974d9807
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index ef8d8f4..0c3ef01 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -41,6 +41,9 @@
     enum Style : uint8_t { kNormal = 0, kBold = 0x01, kItalic = 0x02, kBoldItalic = 0x03 };
     Style fAPIStyle;
 
+    // base weight in CSS-style units, 1..1000
+    int fBaseWeight;
+
     static const Typeface* resolveDefault(const Typeface* src);
 
     // The following three functions create new Typeface from an existing Typeface with a different
@@ -81,10 +84,6 @@
 
     // Sets roboto font as the default typeface for testing purpose.
     static void setRobotoTypefaceForTest();
-
-private:
-    // base weight in CSS-style units, 1..1000
-    int fBaseWeight;
 };
 }
 
diff --git a/libs/hwui/jni/Typeface.cpp b/libs/hwui/jni/Typeface.cpp
index 2a5f402..dc066da 100644
--- a/libs/hwui/jni/Typeface.cpp
+++ b/libs/hwui/jni/Typeface.cpp
@@ -16,10 +16,13 @@
 
 #include "FontUtils.h"
 #include "GraphicsJNI.h"
+#include "fonts/Font.h"
 #include <nativehelper/ScopedPrimitiveArray.h>
 #include <nativehelper/ScopedUtfChars.h>
+#include "SkData.h"
 #include "SkTypeface.h"
 #include <hwui/Typeface.h>
+#include <minikin/FontCollection.h>
 #include <minikin/FontFamily.h>
 #include <minikin/SystemFonts.h>
 
@@ -132,6 +135,88 @@
                                            toTypeface(ptr)->fFontCollection);
 }
 
+static std::function<std::shared_ptr<minikin::MinikinFont>()> readMinikinFontSkia(
+        minikin::BufferReader* reader) {
+    std::string_view fontPath = reader->readString();
+    int fontIndex = reader->read<int>();
+    const minikin::FontVariation* axesPtr;
+    uint32_t axesCount;
+    std::tie(axesPtr, axesCount) = reader->readArray<minikin::FontVariation>();
+    return [fontPath, fontIndex, axesPtr, axesCount]() -> std::shared_ptr<minikin::MinikinFont> {
+        std::string path(fontPath.data(), fontPath.size());
+        sk_sp<SkData> data = SkData::MakeFromFileName(path.c_str());
+        const void* fontPtr = data->data();
+        size_t fontSize = data->size();
+        std::vector<minikin::FontVariation> axes(axesPtr, axesPtr + axesCount);
+        std::shared_ptr<minikin::MinikinFont> minikinFont =
+                fonts::createMinikinFontSkia(std::move(data), fontPath, fontPtr, fontSize,
+                                             fontIndex, axes);
+        if (minikinFont == nullptr) {
+            ALOGE("Failed to create MinikinFontSkia: %s", path.c_str());
+            return nullptr;
+        }
+        return minikinFont;
+    };
+}
+
+static void writeMinikinFontSkia(minikin::BufferWriter* writer,
+        const minikin::MinikinFont* typeface) {
+    writer->writeString(typeface->GetFontPath());
+    writer->write<int>(typeface->GetFontIndex());
+    const std::vector<minikin::FontVariation>& axes = typeface->GetAxes();
+    writer->writeArray<minikin::FontVariation>(axes.data(), axes.size());
+}
+
+static jint Typeface_writeTypefaces(JNIEnv *env, jobject, jobject buffer, jlongArray faceHandles) {
+    ScopedLongArrayRO faces(env, faceHandles);
+    std::vector<Typeface*> typefaces;
+    typefaces.reserve(faces.size());
+    for (size_t i = 0; i < faces.size(); i++) {
+        typefaces.push_back(toTypeface(faces[i]));
+    }
+    void* addr = buffer == nullptr ? nullptr : env->GetDirectBufferAddress(buffer);
+    minikin::BufferWriter writer(addr);
+    std::vector<std::shared_ptr<minikin::FontCollection>> fontCollections;
+    std::unordered_map<std::shared_ptr<minikin::FontCollection>, size_t> fcToIndex;
+    for (Typeface* typeface : typefaces) {
+        bool inserted = fcToIndex.emplace(typeface->fFontCollection, fontCollections.size()).second;
+        if (inserted) {
+            fontCollections.push_back(typeface->fFontCollection);
+        }
+    }
+    minikin::FontCollection::writeVector<writeMinikinFontSkia>(&writer, fontCollections);
+    writer.write<uint32_t>(typefaces.size());
+    for (Typeface* typeface : typefaces) {
+      writer.write<uint32_t>(fcToIndex.find(typeface->fFontCollection)->second);
+      typeface->fStyle.writeTo(&writer);
+      writer.write<Typeface::Style>(typeface->fAPIStyle);
+      writer.write<int>(typeface->fBaseWeight);
+    }
+    return static_cast<jint>(writer.size());
+}
+
+static jlongArray Typeface_readTypefaces(JNIEnv *env, jobject, jobject buffer) {
+    void* addr = buffer == nullptr ? nullptr : env->GetDirectBufferAddress(buffer);
+    if (addr == nullptr) return nullptr;
+    minikin::BufferReader reader(addr);
+    std::vector<std::shared_ptr<minikin::FontCollection>> fontCollections =
+            minikin::FontCollection::readVector<readMinikinFontSkia>(&reader);
+    uint32_t typefaceCount = reader.read<uint32_t>();
+    std::vector<jlong> faceHandles;
+    faceHandles.reserve(typefaceCount);
+    for (uint32_t i = 0; i < typefaceCount; i++) {
+        Typeface* typeface = new Typeface;
+        typeface->fFontCollection = fontCollections[reader.read<uint32_t>()];
+        typeface->fStyle = minikin::FontStyle(&reader);
+        typeface->fAPIStyle = reader.read<Typeface::Style>();
+        typeface->fBaseWeight = reader.read<int>();
+        faceHandles.push_back(toJLong(typeface));
+    }
+    const jlongArray result = env->NewLongArray(typefaceCount);
+    env->SetLongArrayRegion(result, 0, typefaceCount, faceHandles.data());
+    return result;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gTypefaceMethods[] = {
@@ -150,6 +235,8 @@
     { "nativeGetSupportedAxes",   "(J)[I",  (void*)Typeface_getSupportedAxes },
     { "nativeRegisterGenericFamily", "(Ljava/lang/String;J)V",
           (void*)Typeface_registerGenericFamily },
+    { "nativeWriteTypefaces", "(Ljava/nio/ByteBuffer;[J)I", (void*)Typeface_writeTypefaces},
+    { "nativeReadTypefaces", "(Ljava/nio/ByteBuffer;)[J", (void*)Typeface_readTypefaces},
 };
 
 int register_android_graphics_Typeface(JNIEnv* env)
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 21fcd2f..f0c7793 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "Minikin"
 
+#include "Font.h"
 #include "SkData.h"
 #include "SkFont.h"
 #include "SkFontMetrics.h"
@@ -95,29 +96,14 @@
     jobject fontRef = MakeGlobalRefOrDie(env, buffer);
     sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
             release_global_ref, reinterpret_cast<void*>(fontRef)));
-
-    FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
-    for (const auto& axis : builder->axes) {
-        skVariation.push_back({axis.axisTag, axis.value});
-    }
-
-    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
-
-    SkFontArguments args;
-    args.setCollectionIndex(ttcIndex);
-    args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
-
-    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
-    sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
-    if (face == nullptr) {
+    std::shared_ptr<minikin::MinikinFont> minikinFont = fonts::createMinikinFontSkia(
+        std::move(data), std::string_view(fontPath.c_str(), fontPath.size()),
+        fontPtr, fontSize, ttcIndex, builder->axes);
+    if (minikinFont == nullptr) {
         jniThrowException(env, "java/lang/IllegalArgumentException",
                           "Failed to create internal object. maybe invalid font data.");
         return 0;
     }
-    std::shared_ptr<minikin::MinikinFont> minikinFont =
-            std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize,
-                                              std::string_view(fontPath.c_str(), fontPath.size()),
-                                              ttcIndex, builder->axes);
     std::shared_ptr<minikin::Font> font = minikin::Font::Builder(minikinFont).setWeight(weight)
                     .setSlant(static_cast<minikin::FontStyle::Slant>(italic)).build();
     return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
@@ -312,4 +298,31 @@
             gFontBufferHelperMethods, NELEM(gFontBufferHelperMethods));
 }
 
+namespace fonts {
+
+std::shared_ptr<minikin::MinikinFont> createMinikinFontSkia(
+        sk_sp<SkData>&& data, std::string_view fontPath, const void *fontPtr, size_t fontSize,
+        int ttcIndex, const std::vector<minikin::FontVariation>& axes) {
+    FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
+    for (const auto& axis : axes) {
+        skVariation.push_back({axis.axisTag, axis.value});
+    }
+
+    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
+
+    SkFontArguments args;
+    args.setCollectionIndex(ttcIndex);
+    args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
+
+    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
+    sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
+    if (face == nullptr) {
+        return nullptr;
+    }
+    return std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize,
+                                             fontPath, ttcIndex, axes);
 }
+
+}  // namespace fonts
+
+}  // namespace android
diff --git a/libs/hwui/jni/fonts/Font.h b/libs/hwui/jni/fonts/Font.h
new file mode 100644
index 0000000..b5d20bf
--- /dev/null
+++ b/libs/hwui/jni/fonts/Font.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef FONTS_FONT_H_
+#define FONTS_FONT_H_
+
+#include <minikin/FontVariation.h>
+#include <minikin/MinikinFont.h>
+#include <SkRefCnt.h>
+
+#include <string_view>
+#include <vector>
+
+class SkData;
+
+namespace android {
+
+namespace fonts {
+
+std::shared_ptr<minikin::MinikinFont> createMinikinFontSkia(
+        sk_sp<SkData>&& data, std::string_view fontPath, const void *fontPtr, size_t fontSize,
+        int ttcIndex, const std::vector<minikin::FontVariation>& axes);
+
+} // namespace fonts
+
+} // namespace android
+
+#endif /* FONTS_FONT_H_ */