1 /*
2 * Copyright (C) 2014 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 #include "utils/misc.h"
18 #include "utils/Log.h"
19 #include "graphics_jni_helpers.h"
20 #include <nativehelper/ScopedStringChars.h>
21 #include <nativehelper/ScopedPrimitiveArray.h>
22 #include "scoped_nullable_primitive_array.h"
23 #include <cstdint>
24 #include <vector>
25 #include <list>
26 #include <algorithm>
27
28 #include "SkPaint.h"
29 #include "SkTypeface.h"
30 #include <hwui/MinikinSkia.h>
31 #include <hwui/MinikinUtils.h>
32 #include <hwui/Paint.h>
33 #include <minikin/FontCollection.h>
34 #include <minikin/AndroidLineBreakerHelper.h>
35 #include <minikin/MinikinFont.h>
36
37 namespace android {
38
jintArrayToFloatVector(JNIEnv * env,jintArray javaArray)39 static inline std::vector<float> jintArrayToFloatVector(JNIEnv* env, jintArray javaArray) {
40 if (javaArray == nullptr) {
41 return std::vector<float>();
42 } else {
43 ScopedIntArrayRO intArr(env, javaArray);
44 return std::vector<float>(intArr.get(), intArr.get() + intArr.size());
45 }
46 }
47
toNative(jlong ptr)48 static inline minikin::android::StaticLayoutNative* toNative(jlong ptr) {
49 return reinterpret_cast<minikin::android::StaticLayoutNative*>(ptr);
50 }
51
52 // set text and set a number of parameters for creating a layout (width, tabstops, strategy,
53 // hyphenFrequency)
nInit(JNIEnv * env,jclass,jint breakStrategy,jint hyphenationFrequency,jboolean isJustified,jintArray indents,jboolean useBoundsForWidth)54 static jlong nInit(JNIEnv* env, jclass /* unused */, jint breakStrategy, jint hyphenationFrequency,
55 jboolean isJustified, jintArray indents, jboolean useBoundsForWidth) {
56 return reinterpret_cast<jlong>(new minikin::android::StaticLayoutNative(
57 static_cast<minikin::BreakStrategy>(breakStrategy),
58 static_cast<minikin::HyphenationFrequency>(hyphenationFrequency), isJustified,
59 jintArrayToFloatVector(env, indents), useBoundsForWidth));
60 }
61
nFinish(jlong nativePtr)62 static void nFinish(jlong nativePtr) {
63 delete toNative(nativePtr);
64 }
65
66 // CriticalNative
nGetReleaseFunc(CRITICAL_JNI_PARAMS)67 static jlong nGetReleaseFunc(CRITICAL_JNI_PARAMS) {
68 return reinterpret_cast<jlong>(nFinish);
69 }
70
nComputeLineBreaks(JNIEnv * env,jclass,jlong nativePtr,jcharArray javaText,jlong measuredTextPtr,jint length,jfloat firstWidth,jint firstWidthLineCount,jfloat restWidth,jfloatArray variableTabStops,jfloat defaultTabStop,jint indentsOffset)71 static jlong nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
72 // Inputs
73 jcharArray javaText,
74 jlong measuredTextPtr,
75 jint length,
76 jfloat firstWidth,
77 jint firstWidthLineCount,
78 jfloat restWidth,
79 jfloatArray variableTabStops,
80 jfloat defaultTabStop,
81 jint indentsOffset) {
82 minikin::android::StaticLayoutNative* builder = toNative(nativePtr);
83
84 ScopedCharArrayRO text(env, javaText);
85 ScopedNullableFloatArrayRO tabStops(env, variableTabStops);
86
87 minikin::U16StringPiece u16Text(text.get(), length);
88 minikin::MeasuredText* measuredText = reinterpret_cast<minikin::MeasuredText*>(measuredTextPtr);
89
90 std::unique_ptr<minikin::LineBreakResult> result =
91 std::make_unique<minikin::LineBreakResult>(builder->computeBreaks(
92 u16Text, *measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset,
93 tabStops.get(), tabStops.size(), defaultTabStop));
94 return reinterpret_cast<jlong>(result.release());
95 }
96
nGetLineCount(CRITICAL_JNI_PARAMS_COMMA jlong ptr)97 static jint nGetLineCount(CRITICAL_JNI_PARAMS_COMMA jlong ptr) {
98 return reinterpret_cast<minikin::LineBreakResult*>(ptr)->breakPoints.size();
99 }
100
nGetLineBreakOffset(CRITICAL_JNI_PARAMS_COMMA jlong ptr,jint i)101 static jint nGetLineBreakOffset(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
102 return reinterpret_cast<minikin::LineBreakResult*>(ptr)->breakPoints[i];
103 }
104
nGetLineWidth(CRITICAL_JNI_PARAMS_COMMA jlong ptr,jint i)105 static jfloat nGetLineWidth(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
106 return reinterpret_cast<minikin::LineBreakResult*>(ptr)->widths[i];
107 }
108
nGetLineAscent(CRITICAL_JNI_PARAMS_COMMA jlong ptr,jint i)109 static jfloat nGetLineAscent(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
110 return reinterpret_cast<minikin::LineBreakResult*>(ptr)->ascents[i];
111 }
112
nGetLineDescent(CRITICAL_JNI_PARAMS_COMMA jlong ptr,jint i)113 static jfloat nGetLineDescent(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
114 return reinterpret_cast<minikin::LineBreakResult*>(ptr)->descents[i];
115 }
116
nGetLineFlag(CRITICAL_JNI_PARAMS_COMMA jlong ptr,jint i)117 static jint nGetLineFlag(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
118 return reinterpret_cast<minikin::LineBreakResult*>(ptr)->flags[i];
119 }
120
nReleaseResult(jlong ptr)121 static void nReleaseResult(jlong ptr) {
122 delete reinterpret_cast<minikin::LineBreakResult*>(ptr);
123 }
124
nGetReleaseResultFunc(CRITICAL_JNI_PARAMS)125 static jlong nGetReleaseResultFunc(CRITICAL_JNI_PARAMS) {
126 return reinterpret_cast<jlong>(nReleaseResult);
127 }
128
129 static const JNINativeMethod gMethods[] = {
130 // Fast Natives
131 {"nInit",
132 "("
133 "I" // breakStrategy
134 "I" // hyphenationFrequency
135 "Z" // isJustified
136 "[I" // indents
137 "Z" // useBoundsForWidth
138 ")J",
139 (void*)nInit},
140
141 // Critical Natives
142 {"nGetReleaseFunc", "()J", (void*)nGetReleaseFunc},
143
144 // Regular JNI
145 {"nComputeLineBreaks",
146 "("
147 "J" // nativePtr
148 "[C" // text
149 "J" // MeasuredParagraph ptr.
150 "I" // length
151 "F" // firstWidth
152 "I" // firstWidthLineCount
153 "F" // restWidth
154 "[F" // variableTabStops
155 "F" // defaultTabStop
156 "I" // indentsOffset
157 ")J",
158 (void*)nComputeLineBreaks},
159
160 // Result accessors, CriticalNatives
161 {"nGetLineCount", "(J)I", (void*)nGetLineCount},
162 {"nGetLineBreakOffset", "(JI)I", (void*)nGetLineBreakOffset},
163 {"nGetLineWidth", "(JI)F", (void*)nGetLineWidth},
164 {"nGetLineAscent", "(JI)F", (void*)nGetLineAscent},
165 {"nGetLineDescent", "(JI)F", (void*)nGetLineDescent},
166 {"nGetLineFlag", "(JI)I", (void*)nGetLineFlag},
167 {"nGetReleaseResultFunc", "()J", (void*)nGetReleaseResultFunc},
168 };
169
register_android_graphics_text_LineBreaker(JNIEnv * env)170 int register_android_graphics_text_LineBreaker(JNIEnv* env) {
171 return RegisterMethodsOrDie(env, "android/graphics/text/LineBreaker", gMethods,
172 NELEM(gMethods));
173 }
174
175 }
176