1/* 2 * Copyright (C) 2017 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#define LOG_TAG "MeasuredParagraph" 18 19#include "GraphicsJNI.h" 20#include "ScopedIcuLocale.h" 21#include "unicode/locid.h" 22#include "unicode/brkiter.h" 23#include "utils/misc.h" 24#include "utils/Log.h" 25#include <nativehelper/ScopedStringChars.h> 26#include <nativehelper/ScopedPrimitiveArray.h> 27#include <nativehelper/JNIHelp.h> 28#include "core_jni_helpers.h" 29#include <cstdint> 30#include <vector> 31#include <list> 32#include <algorithm> 33 34#include "SkPaint.h" 35#include "SkTypeface.h" 36#include <hwui/MinikinSkia.h> 37#include <hwui/MinikinUtils.h> 38#include <hwui/Paint.h> 39#include <minikin/FontCollection.h> 40#include <minikin/AndroidLineBreakerHelper.h> 41#include <minikin/MinikinFont.h> 42 43namespace android { 44 45static inline minikin::MeasuredTextBuilder* toBuilder(jlong ptr) { 46 return reinterpret_cast<minikin::MeasuredTextBuilder*>(ptr); 47} 48 49static inline Paint* toPaint(jlong ptr) { 50 return reinterpret_cast<Paint*>(ptr); 51} 52 53static inline minikin::MeasuredText* toMeasuredParagraph(jlong ptr) { 54 return reinterpret_cast<minikin::MeasuredText*>(ptr); 55} 56 57template<typename Ptr> static inline jlong toJLong(Ptr ptr) { 58 return reinterpret_cast<jlong>(ptr); 59} 60 61static void releaseMeasuredParagraph(jlong measuredTextPtr) { 62 delete toMeasuredParagraph(measuredTextPtr); 63} 64 65// Regular JNI 66static jlong nInitBuilder() { 67 return toJLong(new minikin::MeasuredTextBuilder()); 68} 69 70// Regular JNI 71static void nAddStyleRun(JNIEnv* /* unused */, jclass /* unused */, jlong builderPtr, 72 jlong paintPtr, jint start, jint end, jboolean isRtl) { 73 Paint* paint = toPaint(paintPtr); 74 const Typeface* typeface = Typeface::resolveDefault(paint->getAndroidTypeface()); 75 minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface); 76 toBuilder(builderPtr)->addStyleRun(start, end, std::move(minikinPaint), isRtl); 77} 78 79// Regular JNI 80static void nAddReplacementRun(JNIEnv* /* unused */, jclass /* unused */, jlong builderPtr, 81 jlong paintPtr, jint start, jint end, jfloat width) { 82 toBuilder(builderPtr)->addReplacementRun(start, end, width, 83 toPaint(paintPtr)->getMinikinLocaleListId()); 84} 85 86// Regular JNI 87static jlong nBuildNativeMeasuredParagraph(JNIEnv* env, jclass /* unused */, jlong builderPtr, 88 jcharArray javaText, jboolean computeHyphenation, 89 jboolean computeLayout) { 90 ScopedCharArrayRO text(env, javaText); 91 const minikin::U16StringPiece textBuffer(text.get(), text.size()); 92 93 // Pass the ownership to Java. 94 return toJLong(toBuilder(builderPtr)->build(textBuffer, computeHyphenation, 95 computeLayout).release()); 96} 97 98// Regular JNI 99static void nFreeBuilder(JNIEnv* env, jclass /* unused */, jlong builderPtr) { 100 delete toBuilder(builderPtr); 101} 102 103// CriticalNative 104static jfloat nGetWidth(jlong ptr, jint start, jint end) { 105 minikin::MeasuredText* mt = toMeasuredParagraph(ptr); 106 float r = 0.0f; 107 for (int i = start; i < end; ++i) { 108 r += mt->widths[i]; 109 } 110 return r; 111} 112 113// Regular JNI 114static void nGetBounds(JNIEnv* env, jobject, jlong ptr, jcharArray javaText, jint start, jint end, 115 jobject bounds) { 116 ScopedCharArrayRO text(env, javaText); 117 const minikin::U16StringPiece textBuffer(text.get(), text.size()); 118 const minikin::Range range(start, end); 119 120 minikin::MinikinRect rect = toMeasuredParagraph(ptr)->getBounds(textBuffer, range); 121 122 SkRect r; 123 r.fLeft = rect.mLeft; 124 r.fTop = rect.mTop; 125 r.fRight = rect.mRight; 126 r.fBottom = rect.mBottom; 127 128 SkIRect ir; 129 r.roundOut(&ir); 130 GraphicsJNI::irect_to_jrect(ir, env, bounds); 131} 132 133// CriticalNative 134static jlong nGetReleaseFunc() { 135 return toJLong(&releaseMeasuredParagraph); 136} 137 138static jint nGetMemoryUsage(jlong ptr) { 139 return static_cast<jint>(toMeasuredParagraph(ptr)->getMemoryUsage()); 140} 141 142static const JNINativeMethod gMethods[] = { 143 // MeasuredParagraphBuilder native functions. 144 {"nInitBuilder", "()J", (void*) nInitBuilder}, 145 {"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun}, 146 {"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun}, 147 {"nBuildNativeMeasuredParagraph", "(J[CZZ)J", (void*) nBuildNativeMeasuredParagraph}, 148 {"nFreeBuilder", "(J)V", (void*) nFreeBuilder}, 149 150 // MeasuredParagraph native functions. 151 {"nGetWidth", "(JII)F", (void*) nGetWidth}, // Critical Natives 152 {"nGetBounds", "(J[CIILandroid/graphics/Rect;)V", (void*) nGetBounds}, // Regular JNI 153 {"nGetReleaseFunc", "()J", (void*) nGetReleaseFunc}, // Critical Natives 154 {"nGetMemoryUsage", "(J)I", (void*) nGetMemoryUsage}, // Critical Native 155}; 156 157int register_android_text_MeasuredParagraph(JNIEnv* env) { 158 return RegisterMethodsOrDie(env, "android/text/MeasuredParagraph", gMethods, NELEM(gMethods)); 159} 160 161} 162