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