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