Loading core/tests/coretests/src/android/graphics/TypefaceTest.java +27 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.graphics; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.content.Context; Loading @@ -34,6 +35,9 @@ import com.android.frameworks.coretests.R; import org.junit.Test; import org.junit.runner.RunWith; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.List; import java.util.Random; @RunWith(AndroidJUnit4.class) Loading Loading @@ -171,4 +175,27 @@ public class TypefaceTest { } @SmallTest @Test public void testSerialize() throws Exception { int size = Typeface.writeTypefaces(null, Arrays.asList(mFaces)); ByteBuffer buffer = ByteBuffer.allocateDirect(size); Typeface.writeTypefaces(buffer, Arrays.asList(mFaces)); List<Typeface> copiedTypefaces = Typeface.readTypefaces(buffer); assertNotNull(copiedTypefaces); assertEquals(mFaces.length, copiedTypefaces.size()); for (int i = 0; i < mFaces.length; i++) { Typeface original = mFaces[i]; Typeface copied = copiedTypefaces.get(i); assertEquals(original.getStyle(), copied.getStyle()); assertEquals(original.getWeight(), copied.getWeight()); assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6); } } private static float measureText(Typeface typeface, String text) { Paint paint = new Paint(); paint.setTypeface(typeface); return paint.measureText(text); } } graphics/java/android/graphics/Typeface.java +36 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; Loading Loading @@ -1209,6 +1210,36 @@ public class Typeface { return Arrays.binarySearch(mSupportedAxes, axis) >= 0; } /** * Writes Typeface instances to the ByteBuffer and returns the number of bytes written. * * <p>If {@code buffer} is null, this method returns the number of bytes required to serialize * the typefaces, without writing anything. * @hide */ public static int writeTypefaces( @Nullable ByteBuffer buffer, @NonNull List<Typeface> typefaces) { long[] nativePtrs = new long[typefaces.size()]; for (int i = 0; i < nativePtrs.length; i++) { nativePtrs[i] = typefaces.get(i).native_instance; } return nativeWriteTypefaces(buffer, nativePtrs); } /** * Reads serialized Typeface instances from the ByteBuffer. Returns null on errors. * @hide */ public static @Nullable List<Typeface> readTypefaces(@NonNull ByteBuffer buffer) { long[] nativePtrs = nativeReadTypefaces(buffer); if (nativePtrs == null) return null; List<Typeface> typefaces = new ArrayList<>(nativePtrs.length); for (long nativePtr : nativePtrs) { typefaces.add(new Typeface(nativePtr)); } return typefaces; } private static native long nativeCreateFromTypeface(long native_instance, int style); private static native long nativeCreateFromTypefaceWithExactStyle( long native_instance, int weight, boolean italic); Loading @@ -1234,4 +1265,9 @@ public class Typeface { private static native long nativeGetReleaseFunc(); private static native void nativeRegisterGenericFamily(String str, long nativePtr); private static native int nativeWriteTypefaces( @Nullable ByteBuffer buffer, @NonNull long[] nativePtrs); private static native @Nullable long[] nativeReadTypefaces(@NonNull ByteBuffer buffer); } libs/hwui/hwui/Typeface.h +3 −4 Original line number Diff line number Diff line Loading @@ -41,6 +41,9 @@ public: 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 Loading Loading @@ -81,10 +84,6 @@ public: // Sets roboto font as the default typeface for testing purpose. static void setRobotoTypefaceForTest(); private: // base weight in CSS-style units, 1..1000 int fBaseWeight; }; } Loading libs/hwui/jni/Typeface.cpp +87 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -132,6 +135,88 @@ static void Typeface_registerGenericFamily(JNIEnv *env, jobject, jstring familyN 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[] = { Loading @@ -150,6 +235,8 @@ static const JNINativeMethod gTypefaceMethods[] = { { "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) Loading libs/hwui/jni/fonts/Font.cpp +32 −19 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #undef LOG_TAG #define LOG_TAG "Minikin" #include "Font.h" #include "SkData.h" #include "SkFont.h" #include "SkFontMetrics.h" Loading Loading @@ -95,29 +96,14 @@ static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jo 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))); Loading Loading @@ -312,4 +298,31 @@ int register_android_graphics_fonts_Font(JNIEnv* env) { 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 Loading
core/tests/coretests/src/android/graphics/TypefaceTest.java +27 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.graphics; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.content.Context; Loading @@ -34,6 +35,9 @@ import com.android.frameworks.coretests.R; import org.junit.Test; import org.junit.runner.RunWith; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.List; import java.util.Random; @RunWith(AndroidJUnit4.class) Loading Loading @@ -171,4 +175,27 @@ public class TypefaceTest { } @SmallTest @Test public void testSerialize() throws Exception { int size = Typeface.writeTypefaces(null, Arrays.asList(mFaces)); ByteBuffer buffer = ByteBuffer.allocateDirect(size); Typeface.writeTypefaces(buffer, Arrays.asList(mFaces)); List<Typeface> copiedTypefaces = Typeface.readTypefaces(buffer); assertNotNull(copiedTypefaces); assertEquals(mFaces.length, copiedTypefaces.size()); for (int i = 0; i < mFaces.length; i++) { Typeface original = mFaces[i]; Typeface copied = copiedTypefaces.get(i); assertEquals(original.getStyle(), copied.getStyle()); assertEquals(original.getWeight(), copied.getWeight()); assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6); } } private static float measureText(Typeface typeface, String text) { Paint paint = new Paint(); paint.setTypeface(typeface); return paint.measureText(text); } }
graphics/java/android/graphics/Typeface.java +36 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; Loading Loading @@ -1209,6 +1210,36 @@ public class Typeface { return Arrays.binarySearch(mSupportedAxes, axis) >= 0; } /** * Writes Typeface instances to the ByteBuffer and returns the number of bytes written. * * <p>If {@code buffer} is null, this method returns the number of bytes required to serialize * the typefaces, without writing anything. * @hide */ public static int writeTypefaces( @Nullable ByteBuffer buffer, @NonNull List<Typeface> typefaces) { long[] nativePtrs = new long[typefaces.size()]; for (int i = 0; i < nativePtrs.length; i++) { nativePtrs[i] = typefaces.get(i).native_instance; } return nativeWriteTypefaces(buffer, nativePtrs); } /** * Reads serialized Typeface instances from the ByteBuffer. Returns null on errors. * @hide */ public static @Nullable List<Typeface> readTypefaces(@NonNull ByteBuffer buffer) { long[] nativePtrs = nativeReadTypefaces(buffer); if (nativePtrs == null) return null; List<Typeface> typefaces = new ArrayList<>(nativePtrs.length); for (long nativePtr : nativePtrs) { typefaces.add(new Typeface(nativePtr)); } return typefaces; } private static native long nativeCreateFromTypeface(long native_instance, int style); private static native long nativeCreateFromTypefaceWithExactStyle( long native_instance, int weight, boolean italic); Loading @@ -1234,4 +1265,9 @@ public class Typeface { private static native long nativeGetReleaseFunc(); private static native void nativeRegisterGenericFamily(String str, long nativePtr); private static native int nativeWriteTypefaces( @Nullable ByteBuffer buffer, @NonNull long[] nativePtrs); private static native @Nullable long[] nativeReadTypefaces(@NonNull ByteBuffer buffer); }
libs/hwui/hwui/Typeface.h +3 −4 Original line number Diff line number Diff line Loading @@ -41,6 +41,9 @@ public: 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 Loading Loading @@ -81,10 +84,6 @@ public: // Sets roboto font as the default typeface for testing purpose. static void setRobotoTypefaceForTest(); private: // base weight in CSS-style units, 1..1000 int fBaseWeight; }; } Loading
libs/hwui/jni/Typeface.cpp +87 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -132,6 +135,88 @@ static void Typeface_registerGenericFamily(JNIEnv *env, jobject, jstring familyN 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[] = { Loading @@ -150,6 +235,8 @@ static const JNINativeMethod gTypefaceMethods[] = { { "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) Loading
libs/hwui/jni/fonts/Font.cpp +32 −19 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #undef LOG_TAG #define LOG_TAG "Minikin" #include "Font.h" #include "SkData.h" #include "SkFont.h" #include "SkFontMetrics.h" Loading Loading @@ -95,29 +96,14 @@ static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jo 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))); Loading Loading @@ -312,4 +298,31 @@ int register_android_graphics_fonts_Font(JNIEnv* env) { 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