blob: f0c77930cbe3a099aded7862d9baab9c9784fbc7 [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>
Jagadeesh Pakaravoorb624af32020-05-01 00:01:40 +000036#include <ui/FatVector.h>
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070037
38#include <memory>
39
40namespace android {
41
42struct NativeFontBuilder {
43 std::vector<minikin::FontVariation> axes;
44};
45
46static inline NativeFontBuilder* toBuilder(jlong ptr) {
47 return reinterpret_cast<NativeFontBuilder*>(ptr);
48}
49
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070050static void releaseFont(jlong font) {
51 delete reinterpret_cast<FontWrapper*>(font);
52}
53
54static void release_global_ref(const void* /*data*/, void* context) {
Derek Sollenbergerc5882c42019-10-25 11:11:32 -040055 JNIEnv* env = GraphicsJNI::getJNIEnv();
56 bool needToAttach = (env == nullptr);
57 if (needToAttach) {
58 env = GraphicsJNI::attachJNIEnv("release_font_data");
59 if (env == nullptr) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070060 ALOGE("failed to attach to thread to release global ref.");
61 return;
62 }
63 }
64
65 jobject obj = reinterpret_cast<jobject>(context);
66 env->DeleteGlobalRef(obj);
67}
68
69// Regular JNI
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070070static jlong Font_Builder_initBuilder(JNIEnv*, jobject) {
71 return reinterpret_cast<jlong>(new NativeFontBuilder());
72}
73
74// Critical Native
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010075static void Font_Builder_addAxis(CRITICAL_JNI_PARAMS_COMMA jlong builderPtr, jint tag, jfloat value) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070076 toBuilder(builderPtr)->axes.emplace_back(static_cast<minikin::AxisTag>(tag), value);
77}
78
79// Regular JNI
80static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jobject buffer,
Seigo Nonaka54c6a272018-10-25 15:44:32 -070081 jstring filePath, jint weight, jboolean italic, jint ttcIndex) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070082 NPE_CHECK_RETURN_ZERO(env, buffer);
83 std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
84 const void* fontPtr = env->GetDirectBufferAddress(buffer);
85 if (fontPtr == nullptr) {
86 jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
87 return 0;
88 }
89 jlong fontSize = env->GetDirectBufferCapacity(buffer);
90 if (fontSize <= 0) {
91 jniThrowException(env, "java/lang/IllegalArgumentException",
92 "buffer size must not be zero or negative");
93 return 0;
94 }
Seigo Nonaka54c6a272018-10-25 15:44:32 -070095 ScopedUtfChars fontPath(env, filePath);
Seigo Nonakaa1c21c02018-07-20 15:57:39 -070096 jobject fontRef = MakeGlobalRefOrDie(env, buffer);
97 sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
98 release_global_ref, reinterpret_cast<void*>(fontRef)));
Kohsuke Yatoh1ca390e2020-11-06 16:21:30 -080099 std::shared_ptr<minikin::MinikinFont> minikinFont = fonts::createMinikinFontSkia(
100 std::move(data), std::string_view(fontPath.c_str(), fontPath.size()),
101 fontPtr, fontSize, ttcIndex, builder->axes);
102 if (minikinFont == nullptr) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700103 jniThrowException(env, "java/lang/IllegalArgumentException",
104 "Failed to create internal object. maybe invalid font data.");
105 return 0;
106 }
Seigo Nonaka760d3512020-10-01 12:29:03 -0700107 std::shared_ptr<minikin::Font> font = minikin::Font::Builder(minikinFont).setWeight(weight)
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700108 .setSlant(static_cast<minikin::FontStyle::Slant>(italic)).build();
109 return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
110}
111
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700112// Fast Native
113static jlong Font_Builder_clone(JNIEnv* env, jobject clazz, jlong fontPtr, jlong builderPtr,
114 jint weight, jboolean italic, jint ttcIndex) {
115 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700116 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700117 std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
118
119 // Reconstruct SkTypeface with different arguments from existing SkTypeface.
120 FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
121 for (const auto& axis : builder->axes) {
122 skVariation.push_back({axis.axisTag, axis.value});
123 }
124 SkFontArguments args;
125 args.setCollectionIndex(ttcIndex);
126 args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
127
128 sk_sp<SkTypeface> newTypeface = minikinSkia->GetSkTypeface()->makeClone(args);
129
130 std::shared_ptr<minikin::MinikinFont> newMinikinFont = std::make_shared<MinikinFontSkia>(
131 std::move(newTypeface),
132 minikinSkia->GetFontData(),
133 minikinSkia->GetFontSize(),
134 minikinSkia->getFilePath(),
135 minikinSkia->GetFontIndex(),
136 builder->axes);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700137 std::shared_ptr<minikin::Font> newFont = minikin::Font::Builder(newMinikinFont)
138 .setWeight(weight)
139 .setSlant(static_cast<minikin::FontStyle::Slant>(italic))
140 .build();
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700141 return reinterpret_cast<jlong>(new FontWrapper(std::move(newFont)));
142}
143
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700144// Critical Native
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100145static jlong Font_Builder_getReleaseNativeFont(CRITICAL_JNI_PARAMS) {
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700146 return reinterpret_cast<jlong>(releaseFont);
147}
148
149///////////////////////////////////////////////////////////////////////////////
150
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700151// Fast Native
152static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint glyphId,
153 jlong paintHandle, jobject rect) {
154 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700155 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700156 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
157
158 SkFont* skFont = &paint->getSkFont();
159 // We don't use populateSkFont since it is designed to be used for layout result with addressing
160 // auto fake-bolding.
161 skFont->setTypeface(minikinSkia->RefSkTypeface());
162
163 uint16_t glyph16 = glyphId;
164 SkRect skBounds;
165 SkScalar skWidth;
166 skFont->getWidthsBounds(&glyph16, 1, &skWidth, &skBounds, nullptr);
167 GraphicsJNI::rect_to_jrectf(skBounds, env, rect);
168 return SkScalarToFloat(skWidth);
169}
170
171// Fast Native
172static jfloat Font_getFontMetrics(JNIEnv* env, jobject, jlong fontHandle, jlong paintHandle,
173 jobject metricsObj) {
174 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
Seigo Nonaka760d3512020-10-01 12:29:03 -0700175 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700176 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
177
178 SkFont* skFont = &paint->getSkFont();
179 // We don't use populateSkFont since it is designed to be used for layout result with addressing
180 // auto fake-bolding.
181 skFont->setTypeface(minikinSkia->RefSkTypeface());
182
183 SkFontMetrics metrics;
184 SkScalar spacing = skFont->getMetrics(&metrics);
185 GraphicsJNI::set_metrics(env, metricsObj, metrics);
186 return spacing;
187}
188
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700189// Critical Native
190static jlong Font_getFontInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
Seigo Nonaka760d3512020-10-01 12:29:03 -0700191 const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
192 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700193
Seigo Nonaka760d3512020-10-01 12:29:03 -0700194 uint64_t result = font->style().weight();
195 result |= font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 0x10000 : 0x00000;
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700196 result |= ((static_cast<uint64_t>(minikinSkia->GetFontIndex())) << 32);
197 result |= ((static_cast<uint64_t>(minikinSkia->GetAxes().size())) << 48);
198 return result;
199}
200
201// Critical Native
202static jlong Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle, jint index) {
Seigo Nonaka760d3512020-10-01 12:29:03 -0700203 const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
204 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700205 const minikin::FontVariation& var = minikinSkia->GetAxes().at(index);
206 uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
207 return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
208}
209
Seigo Nonakac519ed82020-10-09 12:00:07 -0700210// FastNative
211static jstring Font_getFontPath(JNIEnv* env, jobject, jlong fontHandle) {
212 const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
213 MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
214 const std::string& filePath = minikinSkia->getFilePath();
215 if (filePath.empty()) {
216 return nullptr;
217 }
218 return env->NewStringUTF(filePath.c_str());
219}
220
Seigo Nonaka760d3512020-10-01 12:29:03 -0700221// Critical Native
222static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
223 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
224 return reinterpret_cast<jlong>(font->font.get());
225}
226
Seigo Nonaka31bf8602020-10-14 15:04:01 -0700227// Critical Native
Seigo Nonakabb684032020-11-03 21:47:25 -0800228static jlong Font_GetBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
229 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
230 const void* bufferPtr = font->font->typeface()->GetFontData();
231 return reinterpret_cast<jlong>(bufferPtr);
Seigo Nonaka31bf8602020-10-14 15:04:01 -0700232}
233
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700234///////////////////////////////////////////////////////////////////////////////
235
236struct FontBufferWrapper {
237 FontBufferWrapper(const std::shared_ptr<minikin::MinikinFont>& font) : minikinFont(font) {}
238 // MinikinFont holds a shared pointer of SkTypeface which has reference to font data.
239 std::shared_ptr<minikin::MinikinFont> minikinFont;
240};
241
242static void unrefBuffer(jlong nativePtr) {
243 FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
244 delete wrapper;
245}
246
247// Critical Native
248static jlong FontBufferHelper_refFontBuffer(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
Seigo Nonaka760d3512020-10-01 12:29:03 -0700249 const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
250 return reinterpret_cast<jlong>(new FontBufferWrapper(font->typeface()));
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700251}
252
253// Fast Native
254static jobject FontBufferHelper_wrapByteBuffer(JNIEnv* env, jobject, jlong nativePtr) {
255 FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
256 return env->NewDirectByteBuffer(
257 const_cast<void*>(wrapper->minikinFont->GetFontData()),
258 wrapper->minikinFont->GetFontSize());
259}
260
261// Critical Native
262static jlong FontBufferHelper_getReleaseFunc(CRITICAL_JNI_PARAMS) {
263 return reinterpret_cast<jlong>(unrefBuffer);
264}
265
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700266///////////////////////////////////////////////////////////////////////////////
267
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700268static const JNINativeMethod gFontBuilderMethods[] = {
269 { "nInitBuilder", "()J", (void*) Font_Builder_initBuilder },
270 { "nAddAxis", "(JIF)V", (void*) Font_Builder_addAxis },
Seigo Nonaka54c6a272018-10-25 15:44:32 -0700271 { "nBuild", "(JLjava/nio/ByteBuffer;Ljava/lang/String;IZI)J", (void*) Font_Builder_build },
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700272 { "nClone", "(JJIZI)J", (void*) Font_Builder_clone },
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700273 { "nGetReleaseNativeFont", "()J", (void*) Font_Builder_getReleaseNativeFont },
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700274};
275
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700276static const JNINativeMethod gFontMethods[] = {
277 { "nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*) Font_getGlyphBounds },
278 { "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700279 { "nGetFontInfo", "(J)J", (void*) Font_getFontInfo },
280 { "nGetAxisInfo", "(JI)J", (void*) Font_getAxisInfo },
Seigo Nonakac519ed82020-10-09 12:00:07 -0700281 { "nGetFontPath", "(J)Ljava/lang/String;", (void*) Font_getFontPath },
Seigo Nonaka760d3512020-10-01 12:29:03 -0700282 { "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr },
Seigo Nonakabb684032020-11-03 21:47:25 -0800283 { "nGetFontBufferAddress", "(J)J", (void*) Font_GetBufferAddress },
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700284};
285
286static const JNINativeMethod gFontBufferHelperMethods[] = {
287 { "nRefFontBuffer", "(J)J", (void*) FontBufferHelper_refFontBuffer },
288 { "nWrapByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*) FontBufferHelper_wrapByteBuffer },
289 { "nGetReleaseFunc", "()J", (void*) FontBufferHelper_getReleaseFunc },
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700290};
291
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700292int register_android_graphics_fonts_Font(JNIEnv* env) {
293 return RegisterMethodsOrDie(env, "android/graphics/fonts/Font$Builder", gFontBuilderMethods,
Seigo Nonaka1ed4f642020-09-10 17:19:34 -0700294 NELEM(gFontBuilderMethods)) +
295 RegisterMethodsOrDie(env, "android/graphics/fonts/Font", gFontMethods,
Seigo Nonakaf3a19152020-09-14 15:29:42 -0700296 NELEM(gFontMethods)) +
297 RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFontBufferHelper",
298 gFontBufferHelperMethods, NELEM(gFontBufferHelperMethods));
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700299}
300
Kohsuke Yatoh1ca390e2020-11-06 16:21:30 -0800301namespace fonts {
302
303std::shared_ptr<minikin::MinikinFont> createMinikinFontSkia(
304 sk_sp<SkData>&& data, std::string_view fontPath, const void *fontPtr, size_t fontSize,
305 int ttcIndex, const std::vector<minikin::FontVariation>& axes) {
306 FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
307 for (const auto& axis : axes) {
308 skVariation.push_back({axis.axisTag, axis.value});
309 }
310
311 std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
312
313 SkFontArguments args;
314 args.setCollectionIndex(ttcIndex);
315 args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
316
317 sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
318 sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
319 if (face == nullptr) {
320 return nullptr;
321 }
322 return std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize,
323 fontPath, ttcIndex, axes);
Seigo Nonakaa1c21c02018-07-20 15:57:39 -0700324}
Kohsuke Yatoh1ca390e2020-11-06 16:21:30 -0800325
326} // namespace fonts
327
328} // namespace android