Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d2ec907 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Measure the text before doing line break"

parents 577e4009 beb16403
Loading
Loading
Loading
Loading
+17 −29
Original line number Diff line number Diff line
@@ -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>
@@ -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);
@@ -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,
@@ -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
+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