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