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