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