blob: b769d40238a4909eb58f0eee500b345664dfbba4 [file] [log] [blame]
Seigo Nonakaa1c21c02018-07-20 15:57:39 -07001/*
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
Derek Sollenberger5368eda2019-10-25 11:20:03 -040017#undef LOG_TAG
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070018#define LOG_TAG "Minikin"
19
Kohsuke Yatoh1ca390e2020-11-06 16:21:30 -080020#include "Font.h"
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070021#include "SkData.h"
Seigo Nonaka1ed4f642020-09-10 17:19:34 -070022#include "SkFont.h"
23#include "SkFontMetrics.h"
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070024#include "SkFontMgr.h"
25#include "SkRefCnt.h"
26#include "SkTypeface.h"
27#include "GraphicsJNI.h"
28#include <nativehelper/ScopedUtfChars.h>
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070029#include "Utils.h"
30#include "FontUtils.h"
31
32#include <hwui/MinikinSkia.h>
Seigo Nonaka1ed4f642020-09-10 17:19:34 -070033#include <hwui/Paint.h>
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070034#include <hwui/Typeface.h>
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070035#include <minikin/FontFamily.h>
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -080036#include <minikin/FontFileParser.h>
Jagadeesh Pakaravoorb624af32020-05-01 00:01:40 +000037#include <ui/FatVector.h>
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070038
39#include <memory>
40
41namespace android {
42
43struct NativeFontBuilder {
44 std::vector<minikin::FontVariation> axes;
45};
46
47static inline NativeFontBuilder* toBuilder(jlong ptr) {
48 return reinterpret_cast<NativeFontBuilder*>(ptr);
49}
50
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070051static void releaseFont(jlong font) {
52 delete reinterpret_cast<FontWrapper*>(font);
53}
54
55static void release_global_ref(const void* /*data*/, void* context) {
Derek Sollenbergerc5882c42019-10-25 11:11:32 -040056 JNIEnv* env = GraphicsJNI::getJNIEnv();
57 bool needToAttach = (env == nullptr);
58 if (needToAttach) {
59 env = GraphicsJNI::attachJNIEnv("release_font_data");
60 if (env == nullptr) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070061 ALOGE("failed to attach to thread to release global ref.");
62 return;
63 }
64 }
65
66 jobject obj = reinterpret_cast<jobject>(context);
67 env->DeleteGlobalRef(obj);
68}
69
70// Regular JNI
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070071static jlong Font_Builder_initBuilder(JNIEnv*, jobject) {
72 return reinterpret_cast<jlong>(new NativeFontBuilder());
73}
74
75// Critical Native
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010076static void Font_Builder_addAxis(CRITICAL_JNI_PARAMS_COMMA jlong builderPtr, jint tag, jfloat value) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070077 toBuilder(builderPtr)->axes.emplace_back(static_cast<minikin::AxisTag>(tag), value);
78}
79
80// Regular JNI
81static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jobject buffer,
Seigo Nonaka99c07562021-02-03 21:37:57 -080082 jstring filePath, jstring langTags, jint weight, jboolean italic,
83 jint ttcIndex) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070084 NPE_CHECK_RETURN_ZERO(env, buffer);
85 std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
86 const void* fontPtr = env->GetDirectBufferAddress(buffer);
87 if (fontPtr == nullptr) {
88 jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
89 return 0;
90 }
91 jlong fontSize = env->GetDirectBufferCapacity(buffer);
92 if (fontSize <= 0) {
93 jniThrowException(env, "java/lang/IllegalArgumentException",
94 "buffer size must not be zero or negative");
95 return 0;
96 }
Seigo Nonaka54c6a272018-10-25 15:44:32 -070097 ScopedUtfChars fontPath(env, filePath);
Seigo Nonaka99c07562021-02-03 21:37:57 -080098 ScopedUtfChars langTagStr(env, langTags);
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070099 jobject fontRef = MakeGlobalRefOrDie(env, buffer);
100 sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
101 release_global_ref, reinterpret_cast<void*>(fontRef)));
Kohsuke Yatoh1ca390e2020-11-06 16:21:30 -0800102 std::shared_ptr<minikin::MinikinFont> minikinFont = fonts::createMinikinFontSkia(
103 std::move(data), std::string_view(fontPath.c_str(), fontPath.size()),
104 fontPtr, fontSize, ttcIndex, builder->axes);
105 if (minikinFont == nullptr) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700106 jniThrowException(env, "java/lang/IllegalArgumentException",
107 "Failed to create internal object. maybe invalid font data.");
108 return 0;
109 }
Seigo Nonaka99c07562021-02-03 21:37:57 -0800110 uint32_t localeListId = minikin::registerLocaleList(langTagStr.c_str());
111 std::shared_ptr<minikin::Font> font =
112 minikin::Font::Builder(minikinFont)
113 .setWeight(weight)
114 .setSlant(static_cast<minikin::FontStyle::Slant>(italic))
115 .setLocaleListId(localeListId)
116 .build();
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700117 return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
118}
119
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700120// Fast Native
121static jlong Font_Builder_clone(JNIEnv* env, jobject clazz, jlong fontPtr, jlong builderPtr,
122 jint weight, jboolean italic, jint ttcIndex) {
123 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700124 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700125 std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
126
127 // Reconstruct SkTypeface with different arguments from existing SkTypeface.
128 FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
129 for (const auto& axis : builder->axes) {
130 skVariation.push_back({axis.axisTag, axis.value});
131 }
132 SkFontArguments args;
133 args.setCollectionIndex(ttcIndex);
134 args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
135
136 sk_sp<SkTypeface> newTypeface = minikinSkia->GetSkTypeface()->makeClone(args);
137
138 std::shared_ptr<minikin::MinikinFont> newMinikinFont = std::make_shared<MinikinFontSkia>(
139 std::move(newTypeface),
140 minikinSkia->GetFontData(),
141 minikinSkia->GetFontSize(),
142 minikinSkia->getFilePath(),
143 minikinSkia->GetFontIndex(),
144 builder->axes);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700145 std::shared_ptr<minikin::Font> newFont = minikin::Font::Builder(newMinikinFont)
146 .setWeight(weight)
147 .setSlant(static_cast<minikin::FontStyle::Slant>(italic))
148 .build();
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700149 return reinterpret_cast<jlong>(new FontWrapper(std::move(newFont)));
150}
151
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700152// Critical Native
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100153static jlong Font_Builder_getReleaseNativeFont(CRITICAL_JNI_PARAMS) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700154 return reinterpret_cast<jlong>(releaseFont);
155}
156
157///////////////////////////////////////////////////////////////////////////////
158
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700159// Fast Native
160static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint glyphId,
161 jlong paintHandle, jobject rect) {
162 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700163 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700164 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
165
166 SkFont* skFont = &paint->getSkFont();
167 // We don't use populateSkFont since it is designed to be used for layout result with addressing
168 // auto fake-bolding.
169 skFont->setTypeface(minikinSkia->RefSkTypeface());
170
171 uint16_t glyph16 = glyphId;
172 SkRect skBounds;
173 SkScalar skWidth;
174 skFont->getWidthsBounds(&glyph16, 1, &skWidth, &skBounds, nullptr);
175 GraphicsJNI::rect_to_jrectf(skBounds, env, rect);
176 return SkScalarToFloat(skWidth);
177}
178
179// Fast Native
180static jfloat Font_getFontMetrics(JNIEnv* env, jobject, jlong fontHandle, jlong paintHandle,
181 jobject metricsObj) {
182 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700183 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700184 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
185
186 SkFont* skFont = &paint->getSkFont();
187 // We don't use populateSkFont since it is designed to be used for layout result with addressing
188 // auto fake-bolding.
189 skFont->setTypeface(minikinSkia->RefSkTypeface());
190
191 SkFontMetrics metrics;
192 SkScalar spacing = skFont->getMetrics(&metrics);
193 GraphicsJNI::set_metrics(env, metricsObj, metrics);
194 return spacing;
195}
196
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700197// Critical Native
Seigo Nonaka760d3512020-10-01 12:29:03 -0700198static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
199 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
200 return reinterpret_cast<jlong>(font->font.get());
201}
202
Seigo Nonaka31bf8602020-10-14 15:04:01 -0700203// Critical Native
Seigo Nonakabb684032020-11-03 21:47:25 -0800204static jlong Font_GetBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
205 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
206 const void* bufferPtr = font->font->typeface()->GetFontData();
207 return reinterpret_cast<jlong>(bufferPtr);
Seigo Nonaka31bf8602020-10-14 15:04:01 -0700208}
209
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700210///////////////////////////////////////////////////////////////////////////////
211
212struct FontBufferWrapper {
213 FontBufferWrapper(const std::shared_ptr<minikin::MinikinFont>& font) : minikinFont(font) {}
214 // MinikinFont holds a shared pointer of SkTypeface which has reference to font data.
215 std::shared_ptr<minikin::MinikinFont> minikinFont;
216};
217
218static void unrefBuffer(jlong nativePtr) {
219 FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
220 delete wrapper;
221}
222
223// Critical Native
224static jlong FontBufferHelper_refFontBuffer(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
Seigo Nonaka760d3512020-10-01 12:29:03 -0700225 const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
226 return reinterpret_cast<jlong>(new FontBufferWrapper(font->typeface()));
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700227}
228
229// Fast Native
230static jobject FontBufferHelper_wrapByteBuffer(JNIEnv* env, jobject, jlong nativePtr) {
231 FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
232 return env->NewDirectByteBuffer(
233 const_cast<void*>(wrapper->minikinFont->GetFontData()),
234 wrapper->minikinFont->GetFontSize());
235}
236
237// Critical Native
238static jlong FontBufferHelper_getReleaseFunc(CRITICAL_JNI_PARAMS) {
239 return reinterpret_cast<jlong>(unrefBuffer);
240}
241
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700242///////////////////////////////////////////////////////////////////////////////
243
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -0800244// Fast Native
245static jlong FontFileUtil_getFontRevision(JNIEnv* env, jobject, jobject buffer, jint index) {
246 NPE_CHECK_RETURN_ZERO(env, buffer);
247 const void* fontPtr = env->GetDirectBufferAddress(buffer);
248 if (fontPtr == nullptr) {
249 jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
250 return 0;
251 }
252 jlong fontSize = env->GetDirectBufferCapacity(buffer);
253 if (fontSize <= 0) {
254 jniThrowException(env, "java/lang/IllegalArgumentException",
255 "buffer size must not be zero or negative");
256 return 0;
257 }
258 minikin::FontFileParser parser(fontPtr, fontSize, index);
259 std::optional<uint32_t> revision = parser.getFontRevision();
260 if (!revision.has_value()) {
261 return -1L;
262 }
263 return revision.value();
264}
265
266static jstring FontFileUtil_getFontPostScriptName(JNIEnv* env, jobject, jobject buffer,
267 jint index) {
268 NPE_CHECK_RETURN_ZERO(env, buffer);
269 const void* fontPtr = env->GetDirectBufferAddress(buffer);
270 if (fontPtr == nullptr) {
271 jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
272 return nullptr;
273 }
274 jlong fontSize = env->GetDirectBufferCapacity(buffer);
275 if (fontSize <= 0) {
276 jniThrowException(env, "java/lang/IllegalArgumentException",
277 "buffer size must not be zero or negative");
278 return nullptr;
279 }
280 minikin::FontFileParser parser(fontPtr, fontSize, index);
281 std::optional<std::string> psName = parser.getPostScriptName();
282 if (!psName.has_value()) {
283 return nullptr; // null
284 }
285 return env->NewStringUTF(psName->c_str());
286}
Seigo Nonaka9d5ab7e2021-01-20 22:50:09 -0800287
288static jint FontFileUtil_isPostScriptType1Font(JNIEnv* env, jobject, jobject buffer, jint index) {
289 NPE_CHECK_RETURN_ZERO(env, buffer);
290 const void* fontPtr = env->GetDirectBufferAddress(buffer);
291 if (fontPtr == nullptr) {
292 jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
293 return -1;
294 }
295 jlong fontSize = env->GetDirectBufferCapacity(buffer);
296 if (fontSize <= 0) {
297 jniThrowException(env, "java/lang/IllegalArgumentException",
298 "buffer size must not be zero or negative");
299 return -1;
300 }
301 minikin::FontFileParser parser(fontPtr, fontSize, index);
302 std::optional<bool> isType1 = parser.isPostScriptType1Font();
303 if (!isType1.has_value()) {
304 return -1; // not an OpenType font. HarfBuzz failed to parse it.
305 }
306 return isType1.value();
307}
308
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -0800309///////////////////////////////////////////////////////////////////////////////
310
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700311static const JNINativeMethod gFontBuilderMethods[] = {
Seigo Nonaka99c07562021-02-03 21:37:57 -0800312 {"nInitBuilder", "()J", (void*)Font_Builder_initBuilder},
313 {"nAddAxis", "(JIF)V", (void*)Font_Builder_addAxis},
314 {"nBuild", "(JLjava/nio/ByteBuffer;Ljava/lang/String;Ljava/lang/String;IZI)J",
315 (void*)Font_Builder_build},
316 {"nClone", "(JJIZI)J", (void*)Font_Builder_clone},
317 {"nGetReleaseNativeFont", "()J", (void*)Font_Builder_getReleaseNativeFont},
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700318};
319
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700320static const JNINativeMethod gFontMethods[] = {
321 { "nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*) Font_getGlyphBounds },
322 { "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
Seigo Nonaka760d3512020-10-01 12:29:03 -0700323 { "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr },
Seigo Nonakabb684032020-11-03 21:47:25 -0800324 { "nGetFontBufferAddress", "(J)J", (void*) Font_GetBufferAddress },
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700325};
326
327static const JNINativeMethod gFontBufferHelperMethods[] = {
328 { "nRefFontBuffer", "(J)J", (void*) FontBufferHelper_refFontBuffer },
329 { "nWrapByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*) FontBufferHelper_wrapByteBuffer },
330 { "nGetReleaseFunc", "()J", (void*) FontBufferHelper_getReleaseFunc },
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700331};
332
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -0800333static const JNINativeMethod gFontFileUtilMethods[] = {
334 { "nGetFontRevision", "(Ljava/nio/ByteBuffer;I)J", (void*) FontFileUtil_getFontRevision },
335 { "nGetFontPostScriptName", "(Ljava/nio/ByteBuffer;I)Ljava/lang/String;",
336 (void*) FontFileUtil_getFontPostScriptName },
Seigo Nonaka9d5ab7e2021-01-20 22:50:09 -0800337 { "nIsPostScriptType1Font", "(Ljava/nio/ByteBuffer;I)I",
338 (void*) FontFileUtil_isPostScriptType1Font },
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -0800339};
340
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700341int register_android_graphics_fonts_Font(JNIEnv* env) {
342 return RegisterMethodsOrDie(env, "android/graphics/fonts/Font$Builder", gFontBuilderMethods,
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700343 NELEM(gFontBuilderMethods)) +
344 RegisterMethodsOrDie(env, "android/graphics/fonts/Font", gFontMethods,
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700345 NELEM(gFontMethods)) +
346 RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFontBufferHelper",
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -0800347 gFontBufferHelperMethods, NELEM(gFontBufferHelperMethods)) +
348 RegisterMethodsOrDie(env, "android/graphics/fonts/FontFileUtil", gFontFileUtilMethods,
349 NELEM(gFontFileUtilMethods));
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700350}
351
Kohsuke Yatoh1ca390e2020-11-06 16:21:30 -0800352namespace fonts {
353
354std::shared_ptr<minikin::MinikinFont> createMinikinFontSkia(
355 sk_sp<SkData>&& data, std::string_view fontPath, const void *fontPtr, size_t fontSize,
356 int ttcIndex, const std::vector<minikin::FontVariation>& axes) {
357 FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
358 for (const auto& axis : axes) {
359 skVariation.push_back({axis.axisTag, axis.value});
360 }
361
362 std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
363
364 SkFontArguments args;
365 args.setCollectionIndex(ttcIndex);
366 args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
367
368 sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
369 sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
370 if (face == nullptr) {
371 return nullptr;
372 }
373 return std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize,
374 fontPath, ttcIndex, axes);
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700375}
Kohsuke Yatoh1ca390e2020-11-06 16:21:30 -0800376
377} // namespace fonts
378
379} // namespace android