Loading core/jni/android_text_StaticLayout.cpp +17 −29 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <nativehelper/ScopedPrimitiveArray.h> #include <nativehelper/JNIHelp.h> #include "core_jni_helpers.h" #include "scoped_nullable_primitive_array.h" #include <cstdint> #include <vector> #include <list> Loading Loading @@ -87,9 +88,8 @@ static void nFinish(jlong nativePtr) { static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks, jfloatArray recycleWidths, jfloatArray recycleAscents, jfloatArray recycleDescents, jintArray recycleFlags, jint recycleLength, size_t nBreaks, const jint* breaks, const jfloat* widths, const jfloat* ascents, const jfloat* descents, const jint* flags) { jint recycleLength, const minikin::LineBreakResult& result) { const size_t nBreaks = result.breakPoints.size(); if ((size_t)recycleLength < nBreaks) { // have to reallocate buffers recycleBreaks = env->NewIntArray(nBreaks); Loading @@ -105,11 +105,11 @@ static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks, env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags); } // copy data env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, breaks); env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, widths); env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, ascents); env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, descents); env->SetIntArrayRegion(recycleFlags, 0, nBreaks, flags); env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, result.breakPoints.data()); env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, result.widths.data()); env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, result.ascents.data()); env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, result.descents.data()); env->SetIntArrayRegion(recycleFlags, 0, nBreaks, result.flags.data()); } static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr, Loading @@ -136,34 +136,22 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr, minikin::android::StaticLayoutNative* builder = toNative(nativePtr); ScopedCharArrayRO text(env, javaText); ScopedNullableIntArrayRO tabStops(env, variableTabStops); // TODO: Reorganize minikin APIs. minikin::LineBreaker b(minikin::U16StringPiece(text.get(), length)); if (variableTabStops == nullptr) { b.setTabStops(nullptr, 0, defaultTabStop); } else { ScopedIntArrayRO stops(env, variableTabStops); b.setTabStops(stops.get(), stops.size(), defaultTabStop); } b.setStrategy(builder->getStrategy()); b.setHyphenationFrequency(builder->getFrequency()); b.setJustified(builder->isJustified()); b.setLineWidthDelegate(builder->buildLineWidthDelegate( firstWidth, firstWidthLineCount, restWidth, indentsOffset)); builder->addRuns(&b); size_t nBreaks = b.computeBreaks(); minikin::U16StringPiece u16Text(text.get(), length); minikin::MeasuredText measuredText = builder->measureText(u16Text); minikin::LineBreakResult result = builder->computeBreaks( u16Text, measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset, tabStops.get(), tabStops.size(), defaultTabStop); recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleAscents, recycleDescents, recycleFlags, recycleLength, nBreaks, b.getBreaks(), b.getWidths(), b.getAscents(), b.getDescents(), b.getFlags()); recycleFlags, recycleLength, result); env->SetFloatArrayRegion(charWidths, 0, b.size(), b.charWidths()); env->SetFloatArrayRegion(charWidths, 0, measuredText.widths.size(), measuredText.widths.data()); builder->clearRuns(); return static_cast<jint>(nBreaks); return static_cast<jint>(result.breakPoints.size()); } // Basically similar to Paint.getTextRunAdvances but with C++ interface Loading core/jni/scoped_nullable_primitive_array.h 0 → 100644 +103 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SCOPED_NULLABLE_PRIMITIVE_ARRAY_H #define SCOPED_NULLABLE_PRIMITIVE_ARRAY_H #include <jni.h> namespace android { #define ARRAY_TRAITS(ARRAY_TYPE, POINTER_TYPE, NAME) \ class NAME ## ArrayTraits { \ public: \ static constexpr void getArrayRegion(JNIEnv* env, ARRAY_TYPE array, size_t start, \ size_t len, POINTER_TYPE out) { \ env->Get ## NAME ## ArrayRegion(array, start, len, out); \ } \ \ static constexpr POINTER_TYPE getArrayElements(JNIEnv* env, ARRAY_TYPE array) { \ return env->Get ## NAME ## ArrayElements(array, nullptr); \ } \ \ static constexpr void releaseArrayElements(JNIEnv* env, ARRAY_TYPE array, \ POINTER_TYPE buffer, jint mode) { \ env->Release ## NAME ## ArrayElements(array, buffer, mode); \ } \ }; \ ARRAY_TRAITS(jbooleanArray, jboolean*, Boolean) ARRAY_TRAITS(jbyteArray, jbyte*, Byte) ARRAY_TRAITS(jcharArray, jchar*, Char) ARRAY_TRAITS(jdoubleArray, jdouble*, Double) ARRAY_TRAITS(jfloatArray, jfloat*, Float) ARRAY_TRAITS(jintArray, jint*, Int) ARRAY_TRAITS(jlongArray, jlong*, Long) ARRAY_TRAITS(jshortArray, jshort*, Short) #undef ARRAY_TRAITS template<typename JavaArrayType, typename PrimitiveType, class Traits, size_t preallocSize = 10> class ScopedArrayRO { public: ScopedArrayRO(JNIEnv* env, JavaArrayType javaArray) : mEnv(env), mJavaArray(javaArray) { if (mJavaArray == nullptr) { mSize = 0; mRawArray = nullptr; } else { mSize = mEnv->GetArrayLength(mJavaArray); if (mSize <= preallocSize) { Traits::getArrayRegion(mEnv, mJavaArray, 0, mSize, mBuffer); mRawArray = mBuffer; } else { mRawArray = Traits::getArrayElements(mEnv, mJavaArray); } } } ~ScopedArrayRO() { if (mRawArray != nullptr && mRawArray != mBuffer) { Traits::releaseArrayElements(mEnv, mJavaArray, mRawArray, JNI_ABORT); } } const PrimitiveType* get() const { return mRawArray; } const PrimitiveType& operator[](size_t n) const { return mRawArray[n]; } size_t size() const { return mSize; } private: JNIEnv* const mEnv; JavaArrayType mJavaArray; PrimitiveType* mRawArray; size_t mSize; PrimitiveType mBuffer[preallocSize]; DISALLOW_COPY_AND_ASSIGN(ScopedArrayRO); }; // ScopedNullable***ArrayRO provide convenient read-only access to Java array from JNI code. // These accept nullptr. In that case, get() returns nullptr and size() returns 0. using ScopedNullableBooleanArrayRO = ScopedArrayRO<jbooleanArray, jboolean, BooleanArrayTraits>; using ScopedNullableByteArrayRO = ScopedArrayRO<jbyteArray, jbyte, ByteArrayTraits>; using ScopedNullableCharArrayRO = ScopedArrayRO<jcharArray, jchar, CharArrayTraits>; using ScopedNullableDoubleArrayRO = ScopedArrayRO<jdoubleArray, jdouble, DoubleArrayTraits>; using ScopedNullableFloatArrayRO = ScopedArrayRO<jfloatArray, jfloat, FloatArrayTraits>; using ScopedNullableIntArrayRO = ScopedArrayRO<jintArray, jint, IntArrayTraits>; using ScopedNullableLongArrayRO = ScopedArrayRO<jlongArray, jlong, LongArrayTraits>; using ScopedNullableShortArrayRO = ScopedArrayRO<jshortArray, jshort, ShortArrayTraits>; } // namespace android #endif // SCOPED_NULLABLE_PRIMITIVE_ARRAY_H Loading
core/jni/android_text_StaticLayout.cpp +17 −29 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <nativehelper/ScopedPrimitiveArray.h> #include <nativehelper/JNIHelp.h> #include "core_jni_helpers.h" #include "scoped_nullable_primitive_array.h" #include <cstdint> #include <vector> #include <list> Loading Loading @@ -87,9 +88,8 @@ static void nFinish(jlong nativePtr) { static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks, jfloatArray recycleWidths, jfloatArray recycleAscents, jfloatArray recycleDescents, jintArray recycleFlags, jint recycleLength, size_t nBreaks, const jint* breaks, const jfloat* widths, const jfloat* ascents, const jfloat* descents, const jint* flags) { jint recycleLength, const minikin::LineBreakResult& result) { const size_t nBreaks = result.breakPoints.size(); if ((size_t)recycleLength < nBreaks) { // have to reallocate buffers recycleBreaks = env->NewIntArray(nBreaks); Loading @@ -105,11 +105,11 @@ static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks, env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags); } // copy data env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, breaks); env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, widths); env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, ascents); env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, descents); env->SetIntArrayRegion(recycleFlags, 0, nBreaks, flags); env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, result.breakPoints.data()); env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, result.widths.data()); env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, result.ascents.data()); env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, result.descents.data()); env->SetIntArrayRegion(recycleFlags, 0, nBreaks, result.flags.data()); } static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr, Loading @@ -136,34 +136,22 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr, minikin::android::StaticLayoutNative* builder = toNative(nativePtr); ScopedCharArrayRO text(env, javaText); ScopedNullableIntArrayRO tabStops(env, variableTabStops); // TODO: Reorganize minikin APIs. minikin::LineBreaker b(minikin::U16StringPiece(text.get(), length)); if (variableTabStops == nullptr) { b.setTabStops(nullptr, 0, defaultTabStop); } else { ScopedIntArrayRO stops(env, variableTabStops); b.setTabStops(stops.get(), stops.size(), defaultTabStop); } b.setStrategy(builder->getStrategy()); b.setHyphenationFrequency(builder->getFrequency()); b.setJustified(builder->isJustified()); b.setLineWidthDelegate(builder->buildLineWidthDelegate( firstWidth, firstWidthLineCount, restWidth, indentsOffset)); builder->addRuns(&b); size_t nBreaks = b.computeBreaks(); minikin::U16StringPiece u16Text(text.get(), length); minikin::MeasuredText measuredText = builder->measureText(u16Text); minikin::LineBreakResult result = builder->computeBreaks( u16Text, measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset, tabStops.get(), tabStops.size(), defaultTabStop); recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleAscents, recycleDescents, recycleFlags, recycleLength, nBreaks, b.getBreaks(), b.getWidths(), b.getAscents(), b.getDescents(), b.getFlags()); recycleFlags, recycleLength, result); env->SetFloatArrayRegion(charWidths, 0, b.size(), b.charWidths()); env->SetFloatArrayRegion(charWidths, 0, measuredText.widths.size(), measuredText.widths.data()); builder->clearRuns(); return static_cast<jint>(nBreaks); return static_cast<jint>(result.breakPoints.size()); } // Basically similar to Paint.getTextRunAdvances but with C++ interface Loading
core/jni/scoped_nullable_primitive_array.h 0 → 100644 +103 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SCOPED_NULLABLE_PRIMITIVE_ARRAY_H #define SCOPED_NULLABLE_PRIMITIVE_ARRAY_H #include <jni.h> namespace android { #define ARRAY_TRAITS(ARRAY_TYPE, POINTER_TYPE, NAME) \ class NAME ## ArrayTraits { \ public: \ static constexpr void getArrayRegion(JNIEnv* env, ARRAY_TYPE array, size_t start, \ size_t len, POINTER_TYPE out) { \ env->Get ## NAME ## ArrayRegion(array, start, len, out); \ } \ \ static constexpr POINTER_TYPE getArrayElements(JNIEnv* env, ARRAY_TYPE array) { \ return env->Get ## NAME ## ArrayElements(array, nullptr); \ } \ \ static constexpr void releaseArrayElements(JNIEnv* env, ARRAY_TYPE array, \ POINTER_TYPE buffer, jint mode) { \ env->Release ## NAME ## ArrayElements(array, buffer, mode); \ } \ }; \ ARRAY_TRAITS(jbooleanArray, jboolean*, Boolean) ARRAY_TRAITS(jbyteArray, jbyte*, Byte) ARRAY_TRAITS(jcharArray, jchar*, Char) ARRAY_TRAITS(jdoubleArray, jdouble*, Double) ARRAY_TRAITS(jfloatArray, jfloat*, Float) ARRAY_TRAITS(jintArray, jint*, Int) ARRAY_TRAITS(jlongArray, jlong*, Long) ARRAY_TRAITS(jshortArray, jshort*, Short) #undef ARRAY_TRAITS template<typename JavaArrayType, typename PrimitiveType, class Traits, size_t preallocSize = 10> class ScopedArrayRO { public: ScopedArrayRO(JNIEnv* env, JavaArrayType javaArray) : mEnv(env), mJavaArray(javaArray) { if (mJavaArray == nullptr) { mSize = 0; mRawArray = nullptr; } else { mSize = mEnv->GetArrayLength(mJavaArray); if (mSize <= preallocSize) { Traits::getArrayRegion(mEnv, mJavaArray, 0, mSize, mBuffer); mRawArray = mBuffer; } else { mRawArray = Traits::getArrayElements(mEnv, mJavaArray); } } } ~ScopedArrayRO() { if (mRawArray != nullptr && mRawArray != mBuffer) { Traits::releaseArrayElements(mEnv, mJavaArray, mRawArray, JNI_ABORT); } } const PrimitiveType* get() const { return mRawArray; } const PrimitiveType& operator[](size_t n) const { return mRawArray[n]; } size_t size() const { return mSize; } private: JNIEnv* const mEnv; JavaArrayType mJavaArray; PrimitiveType* mRawArray; size_t mSize; PrimitiveType mBuffer[preallocSize]; DISALLOW_COPY_AND_ASSIGN(ScopedArrayRO); }; // ScopedNullable***ArrayRO provide convenient read-only access to Java array from JNI code. // These accept nullptr. In that case, get() returns nullptr and size() returns 0. using ScopedNullableBooleanArrayRO = ScopedArrayRO<jbooleanArray, jboolean, BooleanArrayTraits>; using ScopedNullableByteArrayRO = ScopedArrayRO<jbyteArray, jbyte, ByteArrayTraits>; using ScopedNullableCharArrayRO = ScopedArrayRO<jcharArray, jchar, CharArrayTraits>; using ScopedNullableDoubleArrayRO = ScopedArrayRO<jdoubleArray, jdouble, DoubleArrayTraits>; using ScopedNullableFloatArrayRO = ScopedArrayRO<jfloatArray, jfloat, FloatArrayTraits>; using ScopedNullableIntArrayRO = ScopedArrayRO<jintArray, jint, IntArrayTraits>; using ScopedNullableLongArrayRO = ScopedArrayRO<jlongArray, jlong, LongArrayTraits>; using ScopedNullableShortArrayRO = ScopedArrayRO<jshortArray, jshort, ShortArrayTraits>; } // namespace android #endif // SCOPED_NULLABLE_PRIMITIVE_ARRAY_H