• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #undef LOG_TAG
18 #define LOG_TAG "Minikin"
19 
20 #include "Font.h"
21 #include "SkData.h"
22 #include "SkFont.h"
23 #include "SkFontMetrics.h"
24 #include "SkFontMgr.h"
25 #include "SkRefCnt.h"
26 #include "SkTypeface.h"
27 #include "GraphicsJNI.h"
28 #include <nativehelper/ScopedUtfChars.h>
29 #include "Utils.h"
30 #include "FontUtils.h"
31 
32 #include <hwui/MinikinSkia.h>
33 #include <hwui/Paint.h>
34 #include <hwui/Typeface.h>
35 #include <minikin/FontFamily.h>
36 #include <minikin/FontFileParser.h>
37 #include <minikin/LocaleList.h>
38 #include <minikin/SystemFonts.h>
39 #include <ui/FatVector.h>
40 
41 #include <memory>
42 
43 namespace android {
44 
45 struct NativeFontBuilder {
46     std::vector<minikin::FontVariation> axes;
47 };
48 
toBuilder(jlong ptr)49 static inline NativeFontBuilder* toBuilder(jlong ptr) {
50     return reinterpret_cast<NativeFontBuilder*>(ptr);
51 }
52 
releaseFont(jlong font)53 static void releaseFont(jlong font) {
54     delete reinterpret_cast<FontWrapper*>(font);
55 }
56 
release_global_ref(const void *,void * context)57 static void release_global_ref(const void* /*data*/, void* context) {
58     JNIEnv* env = GraphicsJNI::getJNIEnv();
59     bool needToAttach = (env == nullptr);
60     if (needToAttach) {
61         env = GraphicsJNI::attachJNIEnv("release_font_data");
62         if (env == nullptr) {
63             ALOGE("failed to attach to thread to release global ref.");
64             return;
65         }
66     }
67 
68     jobject obj = reinterpret_cast<jobject>(context);
69     env->DeleteGlobalRef(obj);
70 }
71 
72 // Regular JNI
Font_Builder_initBuilder(JNIEnv *,jobject)73 static jlong Font_Builder_initBuilder(JNIEnv*, jobject) {
74     return reinterpret_cast<jlong>(new NativeFontBuilder());
75 }
76 
77 // Critical Native
Font_Builder_addAxis(CRITICAL_JNI_PARAMS_COMMA jlong builderPtr,jint tag,jfloat value)78 static void Font_Builder_addAxis(CRITICAL_JNI_PARAMS_COMMA jlong builderPtr, jint tag, jfloat value) {
79     toBuilder(builderPtr)->axes.emplace_back(static_cast<minikin::AxisTag>(tag), value);
80 }
81 
82 // Regular JNI
Font_Builder_build(JNIEnv * env,jobject clazz,jlong builderPtr,jobject buffer,jstring filePath,jstring langTags,jint weight,jboolean italic,jint ttcIndex)83 static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jobject buffer,
84                                 jstring filePath, jstring langTags, jint weight, jboolean italic,
85                                 jint ttcIndex) {
86     NPE_CHECK_RETURN_ZERO(env, buffer);
87     std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
88     const void* fontPtr = env->GetDirectBufferAddress(buffer);
89     if (fontPtr == nullptr) {
90         jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
91         return 0;
92     }
93     jlong fontSize = env->GetDirectBufferCapacity(buffer);
94     if (fontSize <= 0) {
95         jniThrowException(env, "java/lang/IllegalArgumentException",
96                           "buffer size must not be zero or negative");
97         return 0;
98     }
99     ScopedUtfChars fontPath(env, filePath);
100     ScopedUtfChars langTagStr(env, langTags);
101     jobject fontRef = MakeGlobalRefOrDie(env, buffer);
102     sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
103             release_global_ref, reinterpret_cast<void*>(fontRef)));
104     std::shared_ptr<minikin::MinikinFont> minikinFont = fonts::createMinikinFontSkia(
105         std::move(data), std::string_view(fontPath.c_str(), fontPath.size()),
106         fontPtr, fontSize, ttcIndex, builder->axes);
107     if (minikinFont == nullptr) {
108         jniThrowException(env, "java/lang/IllegalArgumentException",
109                           "Failed to create internal object. maybe invalid font data.");
110         return 0;
111     }
112     uint32_t localeListId = minikin::registerLocaleList(langTagStr.c_str());
113     std::shared_ptr<minikin::Font> font =
114             minikin::Font::Builder(minikinFont)
115                     .setWeight(weight)
116                     .setSlant(static_cast<minikin::FontStyle::Slant>(italic))
117                     .setLocaleListId(localeListId)
118                     .build();
119     return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
120 }
121 
122 // Fast Native
Font_Builder_clone(JNIEnv * env,jobject clazz,jlong fontPtr,jlong builderPtr,jint weight,jboolean italic,jint ttcIndex)123 static jlong Font_Builder_clone(JNIEnv* env, jobject clazz, jlong fontPtr, jlong builderPtr,
124                                 jint weight, jboolean italic, jint ttcIndex) {
125     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
126     MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
127     std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
128 
129     // Reconstruct SkTypeface with different arguments from existing SkTypeface.
130     FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
131     for (const auto& axis : builder->axes) {
132         skVariation.push_back({axis.axisTag, axis.value});
133     }
134     SkFontArguments args;
135     args.setCollectionIndex(ttcIndex);
136     args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
137 
138     sk_sp<SkTypeface> newTypeface = minikinSkia->GetSkTypeface()->makeClone(args);
139 
140     std::shared_ptr<minikin::MinikinFont> newMinikinFont = std::make_shared<MinikinFontSkia>(
141             std::move(newTypeface), minikinSkia->GetSourceId(), minikinSkia->GetFontData(),
142             minikinSkia->GetFontSize(), minikinSkia->getFilePath(), minikinSkia->GetFontIndex(),
143             builder->axes);
144     std::shared_ptr<minikin::Font> newFont = minikin::Font::Builder(newMinikinFont)
145               .setWeight(weight)
146               .setSlant(static_cast<minikin::FontStyle::Slant>(italic))
147               .build();
148     return reinterpret_cast<jlong>(new FontWrapper(std::move(newFont)));
149 }
150 
151 ///////////////////////////////////////////////////////////////////////////////
152 // Font JNI functions
153 
154 // Fast Native
Font_getGlyphBounds(JNIEnv * env,jobject,jlong fontHandle,jint glyphId,jlong paintHandle,jobject rect)155 static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint glyphId,
156                                   jlong paintHandle, jobject rect) {
157     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
158     MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
159     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
160 
161     SkFont* skFont = &paint->getSkFont();
162     // We don't use populateSkFont since it is designed to be used for layout result with addressing
163     // auto fake-bolding.
164     skFont->setTypeface(minikinSkia->RefSkTypeface());
165 
166     uint16_t glyph16 = glyphId;
167     SkRect skBounds;
168     SkScalar skWidth;
169     skFont->getWidthsBounds(&glyph16, 1, &skWidth, &skBounds, nullptr);
170     GraphicsJNI::rect_to_jrectf(skBounds, env, rect);
171     return SkScalarToFloat(skWidth);
172 }
173 
174 // Fast Native
Font_getFontMetrics(JNIEnv * env,jobject,jlong fontHandle,jlong paintHandle,jobject metricsObj)175 static jfloat Font_getFontMetrics(JNIEnv* env, jobject, jlong fontHandle, jlong paintHandle,
176                                   jobject metricsObj) {
177     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
178     MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
179     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
180 
181     SkFont* skFont = &paint->getSkFont();
182     // We don't use populateSkFont since it is designed to be used for layout result with addressing
183     // auto fake-bolding.
184     skFont->setTypeface(minikinSkia->RefSkTypeface());
185 
186     SkFontMetrics metrics;
187     SkScalar spacing = skFont->getMetrics(&metrics);
188     GraphicsJNI::set_metrics(env, metricsObj, metrics);
189     return spacing;
190 }
191 
192 // Critical Native
Font_getMinikinFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr)193 static jlong Font_getMinikinFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
194     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
195     return reinterpret_cast<jlong>(font->font.get());
196 }
197 
198 // Critical Native
Font_cloneFont(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr)199 static jlong Font_cloneFont(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
200     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
201     std::shared_ptr<minikin::Font> ref = font->font;
202     return reinterpret_cast<jlong>(new FontWrapper(std::move(ref)));
203 }
204 
205 // Fast Native
Font_newByteBuffer(JNIEnv * env,jobject,jlong fontPtr)206 static jobject Font_newByteBuffer(JNIEnv* env, jobject, jlong fontPtr) {
207     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
208     const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
209     return env->NewDirectByteBuffer(const_cast<void*>(minikinFont->GetFontData()),
210                                     minikinFont->GetFontSize());
211 }
212 
213 // Critical Native
Font_getBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr)214 static jlong Font_getBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
215     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
216     return reinterpret_cast<jlong>(font->font->typeface()->GetFontData());
217 }
218 
219 // Critical Native
Font_getReleaseNativeFontFunc(CRITICAL_JNI_PARAMS)220 static jlong Font_getReleaseNativeFontFunc(CRITICAL_JNI_PARAMS) {
221     return reinterpret_cast<jlong>(releaseFont);
222 }
223 
224 // Fast Native
Font_getFontPath(JNIEnv * env,jobject,jlong fontPtr)225 static jstring Font_getFontPath(JNIEnv* env, jobject, jlong fontPtr) {
226     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
227     minikin::BufferReader reader = font->font->typefaceMetadataReader();
228     if (reader.data() != nullptr) {
229         std::string path = std::string(reader.readString());
230         if (path.empty()) {
231             return nullptr;
232         }
233         return env->NewStringUTF(path.c_str());
234     } else {
235         const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
236         const std::string& path = minikinFont->GetFontPath();
237         if (path.empty()) {
238             return nullptr;
239         }
240         return env->NewStringUTF(path.c_str());
241     }
242 }
243 
244 // Fast Native
Font_getLocaleList(JNIEnv * env,jobject,jlong fontPtr)245 static jstring Font_getLocaleList(JNIEnv* env, jobject, jlong fontPtr) {
246     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
247     uint32_t localeListId = font->font->getLocaleListId();
248     if (localeListId == 0) {
249         return nullptr;
250     }
251     std::string langTags = minikin::getLocaleString(localeListId);
252     if (langTags.empty()) {
253         return nullptr;
254     }
255     return env->NewStringUTF(langTags.c_str());
256 }
257 
258 // Critical Native
Font_getPackedStyle(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr)259 static jint Font_getPackedStyle(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
260     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
261     uint32_t weight = font->font->style().weight();
262     uint32_t isItalic = font->font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 1 : 0;
263     return (isItalic << 16) | weight;
264 }
265 
266 // Critical Native
Font_getIndex(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr)267 static jint Font_getIndex(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
268     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
269     minikin::BufferReader reader = font->font->typefaceMetadataReader();
270     if (reader.data() != nullptr) {
271         reader.skipString();  // fontPath
272         return reader.read<int>();
273     } else {
274         const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
275         return minikinFont->GetFontIndex();
276     }
277 }
278 
279 // Critical Native
Font_getAxisCount(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr)280 static jint Font_getAxisCount(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
281     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
282     minikin::BufferReader reader = font->font->typefaceMetadataReader();
283     if (reader.data() != nullptr) {
284         reader.skipString();  // fontPath
285         reader.skip<int>();   // fontIndex
286         return reader.readArray<minikin::FontVariation>().second;
287     } else {
288         const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
289         return minikinFont->GetAxes().size();
290     }
291 }
292 
293 // Critical Native
Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr,jint index)294 static jlong Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr, jint index) {
295     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
296     minikin::BufferReader reader = font->font->typefaceMetadataReader();
297     minikin::FontVariation var;
298     if (reader.data() != nullptr) {
299         reader.skipString();  // fontPath
300         reader.skip<int>();   // fontIndex
301         var = reader.readArray<minikin::FontVariation>().first[index];
302     } else {
303         const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
304         var = minikinFont->GetAxes().at(index);
305     }
306     uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
307     return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
308 }
309 
310 // Critical Native
Font_getSourceId(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr)311 static jint Font_getSourceId(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
312     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
313     return font->font->typeface()->GetSourceId();
314 }
315 
Font_getAvailableFontSet(JNIEnv * env,jobject)316 static jlongArray Font_getAvailableFontSet(JNIEnv* env, jobject) {
317     std::vector<jlong> refArray;
318     minikin::SystemFonts::getFontSet(
319             [&refArray](const std::vector<std::shared_ptr<minikin::Font>>& fontSet) {
320                 refArray.reserve(fontSet.size());
321                 for (const auto& font : fontSet) {
322                     std::shared_ptr<minikin::Font> fontRef = font;
323                     refArray.push_back(
324                             reinterpret_cast<jlong>(new FontWrapper(std::move(fontRef))));
325                 }
326             });
327     jlongArray r = env->NewLongArray(refArray.size());
328     env->SetLongArrayRegion(r, 0, refArray.size(), refArray.data());
329     return r;
330 }
331 
332 // Fast Native
FontFileUtil_getFontRevision(JNIEnv * env,jobject,jobject buffer,jint index)333 static jlong FontFileUtil_getFontRevision(JNIEnv* env, jobject, jobject buffer, jint index) {
334     NPE_CHECK_RETURN_ZERO(env, buffer);
335     const void* fontPtr = env->GetDirectBufferAddress(buffer);
336     if (fontPtr == nullptr) {
337         jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
338         return 0;
339     }
340     jlong fontSize = env->GetDirectBufferCapacity(buffer);
341     if (fontSize <= 0) {
342         jniThrowException(env, "java/lang/IllegalArgumentException",
343                           "buffer size must not be zero or negative");
344         return 0;
345     }
346     minikin::FontFileParser parser(fontPtr, fontSize, index);
347     std::optional<uint32_t> revision = parser.getFontRevision();
348     if (!revision.has_value()) {
349         return -1L;
350     }
351     return revision.value();
352 }
353 
FontFileUtil_getFontPostScriptName(JNIEnv * env,jobject,jobject buffer,jint index)354 static jstring FontFileUtil_getFontPostScriptName(JNIEnv* env, jobject, jobject buffer,
355                                                   jint index) {
356     NPE_CHECK_RETURN_ZERO(env, buffer);
357     const void* fontPtr = env->GetDirectBufferAddress(buffer);
358     if (fontPtr == nullptr) {
359         jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
360         return nullptr;
361     }
362     jlong fontSize = env->GetDirectBufferCapacity(buffer);
363     if (fontSize <= 0) {
364         jniThrowException(env, "java/lang/IllegalArgumentException",
365                           "buffer size must not be zero or negative");
366         return nullptr;
367     }
368     minikin::FontFileParser parser(fontPtr, fontSize, index);
369     std::optional<std::string> psName = parser.getPostScriptName();
370     if (!psName.has_value()) {
371         return nullptr;  // null
372     }
373     return env->NewStringUTF(psName->c_str());
374 }
375 
FontFileUtil_isPostScriptType1Font(JNIEnv * env,jobject,jobject buffer,jint index)376 static jint FontFileUtil_isPostScriptType1Font(JNIEnv* env, jobject, jobject buffer, jint index) {
377     NPE_CHECK_RETURN_ZERO(env, buffer);
378     const void* fontPtr = env->GetDirectBufferAddress(buffer);
379     if (fontPtr == nullptr) {
380         jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
381         return -1;
382     }
383     jlong fontSize = env->GetDirectBufferCapacity(buffer);
384     if (fontSize <= 0) {
385         jniThrowException(env, "java/lang/IllegalArgumentException",
386                           "buffer size must not be zero or negative");
387         return -1;
388     }
389     minikin::FontFileParser parser(fontPtr, fontSize, index);
390     std::optional<bool> isType1 = parser.isPostScriptType1Font();
391     if (!isType1.has_value()) {
392         return -1;  // not an OpenType font. HarfBuzz failed to parse it.
393     }
394     return isType1.value();
395 }
396 
397 ///////////////////////////////////////////////////////////////////////////////
398 
399 static const JNINativeMethod gFontBuilderMethods[] = {
400         {"nInitBuilder", "()J", (void*)Font_Builder_initBuilder},
401         {"nAddAxis", "(JIF)V", (void*)Font_Builder_addAxis},
402         {"nBuild", "(JLjava/nio/ByteBuffer;Ljava/lang/String;Ljava/lang/String;IZI)J",
403          (void*)Font_Builder_build},
404         {"nClone", "(JJIZI)J", (void*)Font_Builder_clone},
405 };
406 
407 static const JNINativeMethod gFontMethods[] = {
408         {"nGetMinikinFontPtr", "(J)J", (void*)Font_getMinikinFontPtr},
409         {"nCloneFont", "(J)J", (void*)Font_cloneFont},
410         {"nNewByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*)Font_newByteBuffer},
411         {"nGetBufferAddress", "(J)J", (void*)Font_getBufferAddress},
412         {"nGetReleaseNativeFont", "()J", (void*)Font_getReleaseNativeFontFunc},
413         {"nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*)Font_getGlyphBounds},
414         {"nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F",
415          (void*)Font_getFontMetrics},
416         {"nGetFontPath", "(J)Ljava/lang/String;", (void*)Font_getFontPath},
417         {"nGetLocaleList", "(J)Ljava/lang/String;", (void*)Font_getLocaleList},
418         {"nGetPackedStyle", "(J)I", (void*)Font_getPackedStyle},
419         {"nGetIndex", "(J)I", (void*)Font_getIndex},
420         {"nGetAxisCount", "(J)I", (void*)Font_getAxisCount},
421         {"nGetAxisInfo", "(JI)J", (void*)Font_getAxisInfo},
422         {"nGetSourceId", "(J)I", (void*)Font_getSourceId},
423 
424         // System font accessors
425         {"nGetAvailableFontSet", "()[J", (void*)Font_getAvailableFontSet},
426 };
427 
428 static const JNINativeMethod gFontFileUtilMethods[] = {
429     { "nGetFontRevision", "(Ljava/nio/ByteBuffer;I)J", (void*) FontFileUtil_getFontRevision },
430     { "nGetFontPostScriptName", "(Ljava/nio/ByteBuffer;I)Ljava/lang/String;",
431         (void*) FontFileUtil_getFontPostScriptName },
432     { "nIsPostScriptType1Font", "(Ljava/nio/ByteBuffer;I)I",
433         (void*) FontFileUtil_isPostScriptType1Font },
434 };
435 
register_android_graphics_fonts_Font(JNIEnv * env)436 int register_android_graphics_fonts_Font(JNIEnv* env) {
437     return RegisterMethodsOrDie(env, "android/graphics/fonts/Font$Builder", gFontBuilderMethods,
438             NELEM(gFontBuilderMethods)) +
439             RegisterMethodsOrDie(env, "android/graphics/fonts/Font", gFontMethods,
440             NELEM(gFontMethods)) +
441             RegisterMethodsOrDie(env, "android/graphics/fonts/FontFileUtil", gFontFileUtilMethods,
442             NELEM(gFontFileUtilMethods));
443 }
444 
445 namespace fonts {
446 
createMinikinFontSkia(sk_sp<SkData> && data,std::string_view fontPath,const void * fontPtr,size_t fontSize,int ttcIndex,const std::vector<minikin::FontVariation> & axes)447 std::shared_ptr<minikin::MinikinFont> createMinikinFontSkia(
448         sk_sp<SkData>&& data, std::string_view fontPath, const void *fontPtr, size_t fontSize,
449         int ttcIndex, const std::vector<minikin::FontVariation>& axes) {
450     FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
451     for (const auto& axis : axes) {
452         skVariation.push_back({axis.axisTag, axis.value});
453     }
454 
455     std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
456 
457     SkFontArguments args;
458     args.setCollectionIndex(ttcIndex);
459     args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
460 
461     sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
462     sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
463     if (face == nullptr) {
464         return nullptr;
465     }
466     return std::make_shared<MinikinFontSkia>(std::move(face), getNewSourceId(), fontPtr, fontSize,
467                                              fontPath, ttcIndex, axes);
468 }
469 
getNewSourceId()470 int getNewSourceId() {
471     static std::atomic<int> sSourceId = {0};
472     return sSourceId++;
473 }
474 
475 }  // namespace fonts
476 
477 }  // namespace android
478