summaryrefslogtreecommitdiffstats
path: root/core/jni/android_text_StaticLayout.cpp
diff options
context:
space:
mode:
authorRaph Levien <raph@google.com>2015-03-02 16:29:23 -0800
committerRaph Levien <raph@google.com>2015-03-05 10:07:33 -0800
commit4c1f12efcf24e404df40f19075eb95a148a9d6a1 (patch)
treeceea0bfa44ab8d9ca188325bcf42487d867c6e1f /core/jni/android_text_StaticLayout.cpp
parentd3ab692d28018825578ff05832644cfad60233fb (diff)
downloadframeworks_base-4c1f12efcf24e404df40f19075eb95a148a9d6a1.zip
frameworks_base-4c1f12efcf24e404df40f19075eb95a148a9d6a1.tar.gz
frameworks_base-4c1f12efcf24e404df40f19075eb95a148a9d6a1.tar.bz2
Add JNI StaticLayout.Builder
This patch adds a native C++ Builder object for StaticLayout to complement the Java one introduced in a previous patch. The Builder object contains state used in constructing a layout, as well as temporary buffers, to avoid having to allocate such. In particular, it holds a break iterator, so avoids the cost of constructing that in the common case of a single locale. Change-Id: I1125103b7ccf00b8674c1586c3ea8d5d915fdd5b
Diffstat (limited to 'core/jni/android_text_StaticLayout.cpp')
-rw-r--r--core/jni/android_text_StaticLayout.cpp142
1 files changed, 91 insertions, 51 deletions
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index db73e69..a6f19b1 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -29,6 +29,7 @@
#include <list>
#include <algorithm>
+
namespace android {
struct JLineBreaksID {
@@ -40,6 +41,53 @@ struct JLineBreaksID {
static jclass gLineBreaks_class;
static JLineBreaksID gLineBreaks_fieldID;
+class Builder {
+ public:
+ ~Builder() {
+ utext_close(&mUText);
+ delete mBreakIterator;
+ }
+
+ void setLocale(const Locale& locale) {
+ delete mBreakIterator;
+ UErrorCode status = U_ZERO_ERROR;
+ mBreakIterator = BreakIterator::createLineInstance(locale, status);
+ // TODO: check status
+ }
+
+ void resize(size_t size) {
+ mTextBuf.resize(size);
+ }
+
+ uint16_t* buffer() {
+ return mTextBuf.data();
+ }
+
+ // set text to current contents of buffer
+ void setText() {
+ UErrorCode status = U_ZERO_ERROR;
+ utext_openUChars(&mUText, mTextBuf.data(), mTextBuf.size(), &status);
+ mBreakIterator->setText(&mUText, status);
+ }
+
+ void finish() {
+ if (mTextBuf.size() > MAX_TEXT_BUF_RETAIN) {
+ mTextBuf.clear();
+ mTextBuf.shrink_to_fit();
+ }
+ }
+
+ BreakIterator* breakIterator() const {
+ return mBreakIterator;
+ }
+
+ private:
+ const size_t MAX_TEXT_BUF_RETAIN = 32678;
+ BreakIterator* mBreakIterator = nullptr;
+ UText mUText = UTEXT_INITIALIZER;
+ std::vector<uint16_t>mTextBuf;
+};
+
static const int CHAR_SPACE = 0x20;
static const int CHAR_TAB = 0x09;
static const int CHAR_NEWLINE = 0x0a;
@@ -50,7 +98,7 @@ class TabStops {
// specified stops must be a sorted array (allowed to be null)
TabStops(JNIEnv* env, jintArray stops, jint defaultTabWidth) :
mStops(env), mTabWidth(defaultTabWidth) {
- if (stops != NULL) {
+ if (stops != nullptr) {
mStops.reset(stops);
mNumStops = mStops.size();
} else {
@@ -430,37 +478,6 @@ class GreedyLineBreaker : public LineBreaker {
}
};
-class ScopedBreakIterator {
- public:
- ScopedBreakIterator(JNIEnv* env, BreakIterator* breakIterator, const jchar* inputText,
- jint length) : mBreakIterator(breakIterator), mChars(inputText) {
- UErrorCode status = U_ZERO_ERROR;
- mUText = utext_openUChars(NULL, mChars, length, &status);
- if (mUText == NULL) {
- return;
- }
-
- mBreakIterator->setText(mUText, status);
- }
-
- inline BreakIterator* operator->() {
- return mBreakIterator;
- }
-
- ~ScopedBreakIterator() {
- utext_close(mUText);
- delete mBreakIterator;
- }
- private:
- BreakIterator* mBreakIterator;
- const jchar* mChars;
- UText* mUText;
-
- // disable copying and assignment
- ScopedBreakIterator(const ScopedBreakIterator&);
- void operator=(const ScopedBreakIterator&);
-};
-
static jint recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
jfloatArray recycleWidths, jbooleanArray recycleFlags,
jint recycleLength, const std::vector<jint>& breaks,
@@ -526,7 +543,7 @@ void computePrimitives(const jchar* textArr, const jfloat* widthsArr, jint lengt
primitives->push_back(p);
}
-static jint nComputeLineBreaks(JNIEnv* env, jclass, jstring javaLocaleName,
+static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
jcharArray inputText, jfloatArray widths, jint length,
jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
jintArray variableTabStops, jint defaultTabStop, jboolean optimize,
@@ -535,29 +552,24 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jstring javaLocaleName,
jint recycleLength) {
std::vector<int> breaks;
- ScopedCharArrayRO textScopedArr(env, inputText);
+ Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ b->resize(length);
+ env->GetCharArrayRegion(inputText, 0, length, b->buffer());
+ b->setText();
+
+ // TODO: this array access is pretty inefficient, but we'll replace it anyway
ScopedFloatArrayRO widthsScopedArr(env, widths);
- ScopedIcuLocale icuLocale(env, javaLocaleName);
- if (icuLocale.valid()) {
- UErrorCode status = U_ZERO_ERROR;
- BreakIterator* it = BreakIterator::createLineInstance(icuLocale.locale(), status);
- if (!U_SUCCESS(status) || it == NULL) {
- if (it) {
- delete it;
- }
- } else {
- ScopedBreakIterator breakIterator(env, it, textScopedArr.get(), length);
- int loc = breakIterator->first();
- while ((loc = breakIterator->next()) != BreakIterator::DONE) {
- breaks.push_back(loc);
- }
- }
+ BreakIterator* breakIterator = b->breakIterator();
+ int loc = breakIterator->first();
+ while ((loc = breakIterator->next()) != BreakIterator::DONE) {
+ breaks.push_back(loc);
}
+ // TODO: all these allocations can be moved into the builder
std::vector<Primitive> primitives;
TabStops tabStops(env, variableTabStops, defaultTabStop);
- computePrimitives(textScopedArr.get(), widthsScopedArr.get(), length, breaks, tabStops, &primitives);
+ computePrimitives(b->buffer(), widthsScopedArr.get(), length, breaks, tabStops, &primitives);
LineWidth lineWidth(firstWidth, firstWidthLineLimit, restWidth);
std::vector<int> computedBreaks;
@@ -571,13 +583,41 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jstring javaLocaleName,
GreedyLineBreaker breaker(primitives, lineWidth);
breaker.computeBreaks(&computedBreaks, &computedWidths, &computedFlags);
}
+ b->finish();
return recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleFlags, recycleLength,
computedBreaks, computedWidths, computedFlags);
}
+static jlong nNewBuilder(JNIEnv*, jclass) {
+ return reinterpret_cast<jlong>(new Builder);
+}
+
+static void nFreeBuilder(JNIEnv*, jclass, jlong nativePtr) {
+ delete reinterpret_cast<Builder*>(nativePtr);
+}
+
+static void nFinishBuilder(JNIEnv*, jclass, jlong nativePtr) {
+ Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ b->finish();
+}
+
+static void nBuilderSetLocale(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleName) {
+ ScopedIcuLocale icuLocale(env, javaLocaleName);
+ Builder* b = reinterpret_cast<Builder*>(nativePtr);
+
+ if (icuLocale.valid()) {
+ b->setLocale(icuLocale.locale());
+ }
+}
+
static JNINativeMethod gMethods[] = {
- {"nComputeLineBreaks", "(Ljava/lang/String;[C[FIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I", (void*) nComputeLineBreaks}
+ {"nNewBuilder", "()J", (void*) nNewBuilder},
+ {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
+ {"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
+ {"nBuilderSetLocale", "(JLjava/lang/String;)V", (void*) nBuilderSetLocale},
+ {"nComputeLineBreaks", "(J[C[FIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I",
+ (void*) nComputeLineBreaks}
};
int register_android_text_StaticLayout(JNIEnv* env)