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_ */