blob: b944310d88222e27859ec5672dad578641579219 [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 Nonaka54c6a272018-10-25 15:44:32 -070082 jstring filePath, jint weight, jboolean italic, jint ttcIndex) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070083 NPE_CHECK_RETURN_ZERO(env, buffer);
84 std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
85 const void* fontPtr = env->GetDirectBufferAddress(buffer);
86 if (fontPtr == nullptr) {
87 jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
88 return 0;
89 }
90 jlong fontSize = env->GetDirectBufferCapacity(buffer);
91 if (fontSize <= 0) {
92 jniThrowException(env, "java/lang/IllegalArgumentException",
93 "buffer size must not be zero or negative");
94 return 0;
95 }
Seigo Nonaka54c6a272018-10-25 15:44:32 -070096 ScopedUtfChars fontPath(env, filePath);
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070097 jobject fontRef = MakeGlobalRefOrDie(env, buffer);
98 sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
99 release_global_ref, reinterpret_cast<void*>(fontRef)));
Kohsuke Yatoh1ca390e2020-11-06 16:21:30 -0800100 std::shared_ptr<minikin::MinikinFont> minikinFont = fonts::createMinikinFontSkia(
101 std::move(data), std::string_view(fontPath.c_str(), fontPath.size()),
102 fontPtr, fontSize, ttcIndex, builder->axes);
103 if (minikinFont == nullptr) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700104 jniThrowException(env, "java/lang/IllegalArgumentException",
105 "Failed to create internal object. maybe invalid font data.");
106 return 0;
107 }
Seigo Nonaka760d3512020-10-01 12:29:03 -0700108 std::shared_ptr<minikin::Font> font = minikin::Font::Builder(minikinFont).setWeight(weight)
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700109 .setSlant(static_cast<minikin::FontStyle::Slant>(italic)).build();
110 return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
111}
112
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700113// Fast Native
114static jlong Font_Builder_clone(JNIEnv* env, jobject clazz, jlong fontPtr, jlong builderPtr,
115 jint weight, jboolean italic, jint ttcIndex) {
116 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700117 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700118 std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
119
120 // Reconstruct SkTypeface with different arguments from existing SkTypeface.
121 FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
122 for (const auto& axis : builder->axes) {
123 skVariation.push_back({axis.axisTag, axis.value});
124 }
125 SkFontArguments args;
126 args.setCollectionIndex(ttcIndex);
127 args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
128
129 sk_sp<SkTypeface> newTypeface = minikinSkia->GetSkTypeface()->makeClone(args);
130
131 std::shared_ptr<minikin::MinikinFont> newMinikinFont = std::make_shared<MinikinFontSkia>(
132 std::move(newTypeface),
133 minikinSkia->GetFontData(),
134 minikinSkia->GetFontSize(),
135 minikinSkia->getFilePath(),
136 minikinSkia->GetFontIndex(),
137 builder->axes);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700138 std::shared_ptr<minikin::Font> newFont = minikin::Font::Builder(newMinikinFont)
139 .setWeight(weight)
140 .setSlant(static_cast<minikin::FontStyle::Slant>(italic))
141 .build();
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700142 return reinterpret_cast<jlong>(new FontWrapper(std::move(newFont)));
143}
144
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700145// Critical Native
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100146static jlong Font_Builder_getReleaseNativeFont(CRITICAL_JNI_PARAMS) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700147 return reinterpret_cast<jlong>(releaseFont);
148}
149
150///////////////////////////////////////////////////////////////////////////////
151
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700152// Fast Native
153static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint glyphId,
154 jlong paintHandle, jobject rect) {
155 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700156 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700157 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
158
159 SkFont* skFont = &paint->getSkFont();
160 // We don't use populateSkFont since it is designed to be used for layout result with addressing
161 // auto fake-bolding.
162 skFont->setTypeface(minikinSkia->RefSkTypeface());
163
164 uint16_t glyph16 = glyphId;
165 SkRect skBounds;
166 SkScalar skWidth;
167 skFont->getWidthsBounds(&glyph16, 1, &skWidth, &skBounds, nullptr);
168 GraphicsJNI::rect_to_jrectf(skBounds, env, rect);
169 return SkScalarToFloat(skWidth);
170}
171
172// Fast Native
173static jfloat Font_getFontMetrics(JNIEnv* env, jobject, jlong fontHandle, jlong paintHandle,
174 jobject metricsObj) {
175 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700176 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700177 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
178
179 SkFont* skFont = &paint->getSkFont();
180 // We don't use populateSkFont since it is designed to be used for layout result with addressing
181 // auto fake-bolding.
182 skFont->setTypeface(minikinSkia->RefSkTypeface());
183
184 SkFontMetrics metrics;
185 SkScalar spacing = skFont->getMetrics(&metrics);
186 GraphicsJNI::set_metrics(env, metricsObj, metrics);
187 return spacing;
188}
189
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700190// Critical Native
Seigo Nonaka760d3512020-10-01 12:29:03 -0700191static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
192 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
193 return reinterpret_cast<jlong>(font->font.get());
194}
195
Seigo Nonaka31bf8602020-10-14 15:04:01 -0700196// Critical Native
Seigo Nonakabb684032020-11-03 21:47:25 -0800197static jlong Font_GetBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
198 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
199 const void* bufferPtr = font->font->typeface()->GetFontData();
200 return reinterpret_cast<jlong>(bufferPtr);
Seigo Nonaka31bf8602020-10-14 15:04:01 -0700201}
202
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700203///////////////////////////////////////////////////////////////////////////////
204
205struct FontBufferWrapper {
206 FontBufferWrapper(const std::shared_ptr<minikin::MinikinFont>& font) : minikinFont(font) {}
207 // MinikinFont holds a shared pointer of SkTypeface which has reference to font data.
208 std::shared_ptr<minikin::MinikinFont> minikinFont;
209};
210
211static void unrefBuffer(jlong nativePtr) {
212 FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
213 delete wrapper;
214}
215
216// Critical Native
217static jlong FontBufferHelper_refFontBuffer(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
Seigo Nonaka760d3512020-10-01 12:29:03 -0700218 const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
219 return reinterpret_cast<jlong>(new FontBufferWrapper(font->typeface()));
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700220}
221
222// Fast Native
223static jobject FontBufferHelper_wrapByteBuffer(JNIEnv* env, jobject, jlong nativePtr) {
224 FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
225 return env->NewDirectByteBuffer(
226 const_cast<void*>(wrapper->minikinFont->GetFontData()),
227 wrapper->minikinFont->GetFontSize());
228}
229
230// Critical Native
231static jlong FontBufferHelper_getReleaseFunc(CRITICAL_JNI_PARAMS) {
232 return reinterpret_cast<jlong>(unrefBuffer);
233}
234
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700235///////////////////////////////////////////////////////////////////////////////
236
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -0800237// Fast Native
238static jlong FontFileUtil_getFontRevision(JNIEnv* env, jobject, jobject buffer, jint index) {
239 NPE_CHECK_RETURN_ZERO(env, buffer);
240 const void* fontPtr = env->GetDirectBufferAddress(buffer);
241 if (fontPtr == nullptr) {
242 jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
243 return 0;
244 }
245 jlong fontSize = env->GetDirectBufferCapacity(buffer);
246 if (fontSize <= 0) {
247 jniThrowException(env, "java/lang/IllegalArgumentException",
248 "buffer size must not be zero or negative");
249 return 0;
250 }
251 minikin::FontFileParser parser(fontPtr, fontSize, index);
252 std::optional<uint32_t> revision = parser.getFontRevision();
253 if (!revision.has_value()) {
254 return -1L;
255 }
256 return revision.value();
257}
258
259static jstring FontFileUtil_getFontPostScriptName(JNIEnv* env, jobject, jobject buffer,
260 jint index) {
261 NPE_CHECK_RETURN_ZERO(env, buffer);
262 const void* fontPtr = env->GetDirectBufferAddress(buffer);
263 if (fontPtr == nullptr) {
264 jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
265 return nullptr;
266 }
267 jlong fontSize = env->GetDirectBufferCapacity(buffer);
268 if (fontSize <= 0) {
269 jniThrowException(env, "java/lang/IllegalArgumentException",
270 "buffer size must not be zero or negative");
271 return nullptr;
272 }
273 minikin::FontFileParser parser(fontPtr, fontSize, index);
274 std::optional<std::string> psName = parser.getPostScriptName();
275 if (!psName.has_value()) {
276 return nullptr; // null
277 }
278 return env->NewStringUTF(psName->c_str());
279}
Seigo Nonaka9d5ab7e2021-01-20 22:50:09 -0800280
281static jint FontFileUtil_isPostScriptType1Font(JNIEnv* env, jobject, jobject buffer, jint index) {
282 NPE_CHECK_RETURN_ZERO(env, buffer);
283 const void* fontPtr = env->GetDirectBufferAddress(buffer);
284 if (fontPtr == nullptr) {
285 jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
286 return -1;
287 }
288 jlong fontSize = env->GetDirectBufferCapacity(buffer);
289 if (fontSize <= 0) {
290 jniThrowException(env, "java/lang/IllegalArgumentException",
291 "buffer size must not be zero or negative");
292 return -1;
293 }
294 minikin::FontFileParser parser(fontPtr, fontSize, index);
295 std::optional<bool> isType1 = parser.isPostScriptType1Font();
296 if (!isType1.has_value()) {
297 return -1; // not an OpenType font. HarfBuzz failed to parse it.
298 }
299 return isType1.value();
300}
301
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -0800302///////////////////////////////////////////////////////////////////////////////
303
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700304static const JNINativeMethod gFontBuilderMethods[] = {
305 { "nInitBuilder", "()J", (void*) Font_Builder_initBuilder },
306 { "nAddAxis", "(JIF)V", (void*) Font_Builder_addAxis },
Seigo Nonaka54c6a272018-10-25 15:44:32 -0700307 { "nBuild", "(JLjava/nio/ByteBuffer;Ljava/lang/String;IZI)J", (void*) Font_Builder_build },
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700308 { "nClone", "(JJIZI)J", (void*) Font_Builder_clone },
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700309 { "nGetReleaseNativeFont", "()J", (void*) Font_Builder_getReleaseNativeFont },
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700310};
311
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700312static const JNINativeMethod gFontMethods[] = {
313 { "nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*) Font_getGlyphBounds },
314 { "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
Seigo Nonaka760d3512020-10-01 12:29:03 -0700315 { "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr },
Seigo Nonakabb684032020-11-03 21:47:25 -0800316 { "nGetFontBufferAddress", "(J)J", (void*) Font_GetBufferAddress },
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700317};
318
319static const JNINativeMethod gFontBufferHelperMethods[] = {
320 { "nRefFontBuffer", "(J)J", (void*) FontBufferHelper_refFontBuffer },
321 { "nWrapByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*) FontBufferHelper_wrapByteBuffer },
322 { "nGetReleaseFunc", "()J", (void*) FontBufferHelper_getReleaseFunc },
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700323};
324
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -0800325static const JNINativeMethod gFontFileUtilMethods[] = {
326 { "nGetFontRevision", "(Ljava/nio/ByteBuffer;I)J", (void*) FontFileUtil_getFontRevision },
327 { "nGetFontPostScriptName", "(Ljava/nio/ByteBuffer;I)Ljava/lang/String;",
328 (void*) FontFileUtil_getFontPostScriptName },
Seigo Nonaka9d5ab7e2021-01-20 22:50:09 -0800329 { "nIsPostScriptType1Font", "(Ljava/nio/ByteBuffer;I)I",
330 (void*) FontFileUtil_isPostScriptType1Font },
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -0800331};
332
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700333int register_android_graphics_fonts_Font(JNIEnv* env) {
334 return RegisterMethodsOrDie(env, "android/graphics/fonts/Font$Builder", gFontBuilderMethods,
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700335 NELEM(gFontBuilderMethods)) +
336 RegisterMethodsOrDie(env, "android/graphics/fonts/Font", gFontMethods,
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700337 NELEM(gFontMethods)) +
338 RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFontBufferHelper",
Seigo Nonaka47b6c1b2021-01-13 15:02:47 -0800339 gFontBufferHelperMethods, NELEM(gFontBufferHelperMethods)) +
340 RegisterMethodsOrDie(env, "android/graphics/fonts/FontFileUtil", gFontFileUtilMethods,
341 NELEM(gFontFileUtilMethods));
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700342}
343
Kohsuke Yatoh1ca390e2020-11-06 16:21:30 -0800344namespace fonts {
345
346std::shared_ptr<minikin::MinikinFont> createMinikinFontSkia(
347 sk_sp<SkData>&& data, std::string_view fontPath, const void *fontPtr, size_t fontSize,
348 int ttcIndex, const std::vector<minikin::FontVariation>& axes) {
349 FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
350 for (const auto& axis : axes) {
351 skVariation.push_back({axis.axisTag, axis.value});
352 }
353
354 std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
355
356 SkFontArguments args;
357 args.setCollectionIndex(ttcIndex);
358 args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
359
360 sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
361 sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
362 if (face == nullptr) {
363 return nullptr;
364 }
365 return std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize,
366 fontPath, ttcIndex, axes);
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700367}
Kohsuke Yatoh1ca390e2020-11-06 16:21:30 -0800368
369} // namespace fonts
370
371} // namespace android