Revert "DO NOT MERGE Implement line breaking using ICU break iterator"

This reverts commit 0c87dfd25d.

Change-Id: Ibc300bb945776594099b69965cabe7220d10de2f
This commit is contained in:
Alan Lau
2014-07-28 19:50:14 +00:00
parent 40b0d4d751
commit 77d6f36bbc
4 changed files with 106 additions and 130 deletions

View File

@ -161,9 +161,6 @@ public class StaticLayout extends Layout {
float spacingadd, boolean includepad, float spacingadd, boolean includepad,
boolean trackpad, float ellipsizedWidth, boolean trackpad, float ellipsizedWidth,
TextUtils.TruncateAt ellipsize) { TextUtils.TruncateAt ellipsize) {
int[] breakOpp = null;
final String localeLanguageTag = paint.getTextLocale().toLanguageTag();
mLineCount = 0; mLineCount = 0;
int v = 0; int v = 0;
@ -178,6 +175,8 @@ public class StaticLayout extends Layout {
if (source instanceof Spanned) if (source instanceof Spanned)
spanned = (Spanned) source; spanned = (Spanned) source;
int DEFAULT_DIR = DIR_LEFT_TO_RIGHT; // XXX
int paraEnd; int paraEnd;
for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) { for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) {
paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd); paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd);
@ -244,9 +243,6 @@ public class StaticLayout extends Layout {
int dir = measured.mDir; int dir = measured.mDir;
boolean easy = measured.mEasy; boolean easy = measured.mEasy;
breakOpp = nLineBreakOpportunities(localeLanguageTag, chs, paraEnd - paraStart, breakOpp);
int breakOppIndex = 0;
int width = firstWidth; int width = firstWidth;
float w = 0; float w = 0;
@ -359,12 +355,15 @@ public class StaticLayout extends Layout {
if (fmBottom > fitBottom) if (fmBottom > fitBottom)
fitBottom = fmBottom; fitBottom = fmBottom;
while (breakOpp[breakOppIndex] != -1 // From the Unicode Line Breaking Algorithm (at least approximately)
&& breakOpp[breakOppIndex] < j - paraStart + 1) { boolean isLineBreak = isSpaceOrTab ||
breakOppIndex++; // / is class SY and - is class HY, except when followed by a digit
} ((c == CHAR_SLASH || c == CHAR_HYPHEN) &&
boolean isLineBreak = breakOppIndex < breakOpp.length && (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
breakOpp[breakOppIndex] == j - paraStart + 1; // Ideographs are class ID: breakpoints when adjacent, except for NS
// (non-starters), which can be broken after but not before
(c >= CHAR_FIRST_CJK && isIdeographic(c, true) &&
j + 1 < spanEnd && isIdeographic(chs[j + 1 - paraStart], false));
if (isLineBreak) { if (isLineBreak) {
okWidth = w; okWidth = w;
@ -492,6 +491,97 @@ public class StaticLayout extends Layout {
} }
} }
/**
* Returns true if the specified character is one of those specified
* as being Ideographic (class ID) by the Unicode Line Breaking Algorithm
* (http://www.unicode.org/unicode/reports/tr14/), and is therefore OK
* to break between a pair of.
*
* @param includeNonStarters also return true for category NS
* (non-starters), which can be broken
* after but not before.
*/
private static final boolean isIdeographic(char c, boolean includeNonStarters) {
if (c >= '\u2E80' && c <= '\u2FFF') {
return true; // CJK, KANGXI RADICALS, DESCRIPTION SYMBOLS
}
if (c == '\u3000') {
return true; // IDEOGRAPHIC SPACE
}
if (c >= '\u3040' && c <= '\u309F') {
if (!includeNonStarters) {
switch (c) {
case '\u3041': // # HIRAGANA LETTER SMALL A
case '\u3043': // # HIRAGANA LETTER SMALL I
case '\u3045': // # HIRAGANA LETTER SMALL U
case '\u3047': // # HIRAGANA LETTER SMALL E
case '\u3049': // # HIRAGANA LETTER SMALL O
case '\u3063': // # HIRAGANA LETTER SMALL TU
case '\u3083': // # HIRAGANA LETTER SMALL YA
case '\u3085': // # HIRAGANA LETTER SMALL YU
case '\u3087': // # HIRAGANA LETTER SMALL YO
case '\u308E': // # HIRAGANA LETTER SMALL WA
case '\u3095': // # HIRAGANA LETTER SMALL KA
case '\u3096': // # HIRAGANA LETTER SMALL KE
case '\u309B': // # KATAKANA-HIRAGANA VOICED SOUND MARK
case '\u309C': // # KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
case '\u309D': // # HIRAGANA ITERATION MARK
case '\u309E': // # HIRAGANA VOICED ITERATION MARK
return false;
}
}
return true; // Hiragana (except small characters)
}
if (c >= '\u30A0' && c <= '\u30FF') {
if (!includeNonStarters) {
switch (c) {
case '\u30A0': // # KATAKANA-HIRAGANA DOUBLE HYPHEN
case '\u30A1': // # KATAKANA LETTER SMALL A
case '\u30A3': // # KATAKANA LETTER SMALL I
case '\u30A5': // # KATAKANA LETTER SMALL U
case '\u30A7': // # KATAKANA LETTER SMALL E
case '\u30A9': // # KATAKANA LETTER SMALL O
case '\u30C3': // # KATAKANA LETTER SMALL TU
case '\u30E3': // # KATAKANA LETTER SMALL YA
case '\u30E5': // # KATAKANA LETTER SMALL YU
case '\u30E7': // # KATAKANA LETTER SMALL YO
case '\u30EE': // # KATAKANA LETTER SMALL WA
case '\u30F5': // # KATAKANA LETTER SMALL KA
case '\u30F6': // # KATAKANA LETTER SMALL KE
case '\u30FB': // # KATAKANA MIDDLE DOT
case '\u30FC': // # KATAKANA-HIRAGANA PROLONGED SOUND MARK
case '\u30FD': // # KATAKANA ITERATION MARK
case '\u30FE': // # KATAKANA VOICED ITERATION MARK
return false;
}
}
return true; // Katakana (except small characters)
}
if (c >= '\u3400' && c <= '\u4DB5') {
return true; // CJK UNIFIED IDEOGRAPHS EXTENSION A
}
if (c >= '\u4E00' && c <= '\u9FBB') {
return true; // CJK UNIFIED IDEOGRAPHS
}
if (c >= '\uF900' && c <= '\uFAD9') {
return true; // CJK COMPATIBILITY IDEOGRAPHS
}
if (c >= '\uA000' && c <= '\uA48F') {
return true; // YI SYLLABLES
}
if (c >= '\uA490' && c <= '\uA4CF') {
return true; // YI RADICALS
}
if (c >= '\uFE62' && c <= '\uFE66') {
return true; // SMALL PLUS SIGN to SMALL EQUALS SIGN
}
if (c >= '\uFF10' && c <= '\uFF19') {
return true; // WIDE DIGITS
}
return false;
}
private int out(CharSequence text, int start, int end, private int out(CharSequence text, int start, int end,
int above, int below, int top, int bottom, int v, int above, int below, int top, int bottom, int v,
float spacingmult, float spacingadd, float spacingmult, float spacingadd,
@ -840,11 +930,6 @@ public class StaticLayout extends Layout {
mMeasured = MeasuredText.recycle(mMeasured); mMeasured = MeasuredText.recycle(mMeasured);
} }
// returns an array with terminal sentinel value -1 to indicate end
// this is so that arrays can be recycled instead of allocating new arrays
// every time
private static native int[] nLineBreakOpportunities(String locale, char[] text, int length, int[] recycle);
private int mLineCount; private int mLineCount;
private int mTopPadding, mBottomPadding; private int mTopPadding, mBottomPadding;
private int mColumns; private int mColumns;
@ -870,9 +955,13 @@ public class StaticLayout extends Layout {
private static final int TAB_INCREMENT = 20; // same as Layout, but that's private private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
private static final char CHAR_FIRST_CJK = '\u2E80';
private static final char CHAR_NEW_LINE = '\n'; private static final char CHAR_NEW_LINE = '\n';
private static final char CHAR_TAB = '\t'; private static final char CHAR_TAB = '\t';
private static final char CHAR_SPACE = ' '; private static final char CHAR_SPACE = ' ';
private static final char CHAR_SLASH = '/';
private static final char CHAR_HYPHEN = '-';
private static final char CHAR_ZWSP = '\u200B'; private static final char CHAR_ZWSP = '\u200B';
private static final double EXTRA_ROUNDING = 0.5; private static final double EXTRA_ROUNDING = 0.5;

View File

@ -62,7 +62,6 @@ LOCAL_SRC_FILES:= \
android_view_VelocityTracker.cpp \ android_view_VelocityTracker.cpp \
android_text_AndroidCharacter.cpp \ android_text_AndroidCharacter.cpp \
android_text_AndroidBidi.cpp \ android_text_AndroidBidi.cpp \
android_text_StaticLayout.cpp \
android_os_Debug.cpp \ android_os_Debug.cpp \
android_os_MemoryFile.cpp \ android_os_MemoryFile.cpp \
android_os_MessageQueue.cpp \ android_os_MessageQueue.cpp \

View File

@ -149,7 +149,6 @@ extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_net_TrafficStats(JNIEnv* env); extern int register_android_net_TrafficStats(JNIEnv* env);
extern int register_android_net_wifi_WifiNative(JNIEnv* env); extern int register_android_net_wifi_WifiNative(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv *env); extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_StaticLayout(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env); extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env); extern int register_android_opengl_classes(JNIEnv *env);
extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env); extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
@ -1106,7 +1105,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_content_XmlBlock), REG_JNI(register_android_content_XmlBlock),
REG_JNI(register_android_emoji_EmojiFactory), REG_JNI(register_android_emoji_EmojiFactory),
REG_JNI(register_android_text_AndroidCharacter), REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_StaticLayout),
REG_JNI(register_android_text_AndroidBidi), REG_JNI(register_android_text_AndroidBidi),
REG_JNI(register_android_view_InputDevice), REG_JNI(register_android_view_InputDevice),
REG_JNI(register_android_view_KeyCharacterMap), REG_JNI(register_android_view_KeyCharacterMap),

View File

@ -1,110 +0,0 @@
/*
* Copyright (C) 2014 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.
*/
#define LOG_TAG "StaticLayout"
#include "ScopedIcuLocale.h"
#include "unicode/locid.h"
#include "unicode/brkiter.h"
#include "utils/misc.h"
#include "utils/Log.h"
#include "ScopedPrimitiveArray.h"
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <vector>
namespace android {
class ScopedBreakIterator {
public:
ScopedBreakIterator(JNIEnv* env, BreakIterator* breakIterator, jcharArray inputText,
jint length) : mBreakIterator(breakIterator), mChars(env, inputText) {
UErrorCode status = U_ZERO_ERROR;
mUText = utext_openUChars(NULL, mChars.get(), length, &status);
if (mUText == NULL) {
return;
}
mBreakIterator->setText(mUText, status);
}
inline BreakIterator* operator->() {
return mBreakIterator;
}
~ScopedBreakIterator() {
utext_close(mUText);
delete mBreakIterator;
}
private:
BreakIterator* mBreakIterator;
ScopedCharArrayRO mChars;
UText* mUText;
// disable copying and assignment
ScopedBreakIterator(const ScopedBreakIterator&);
void operator=(const ScopedBreakIterator&);
};
static jintArray nLineBreakOpportunities(JNIEnv* env, jclass, jstring javaLocaleName,
jcharArray inputText, jint length,
jintArray recycle) {
jintArray ret;
std::vector<jint> breaks(16);
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, inputText, length);
for (int loc = breakIterator->first(); loc != BreakIterator::DONE;
loc = breakIterator->next()) {
breaks.push_back(loc);
}
}
}
breaks.push_back(-1); // sentinel terminal value
if (recycle != NULL && env->GetArrayLength(recycle) >= breaks.size()) {
ret = recycle;
} else {
ret = env->NewIntArray(breaks.size());
}
if (ret != NULL) {
env->SetIntArrayRegion(ret, 0, breaks.size(), &breaks.front());
}
return ret;
}
static JNINativeMethod gMethods[] = {
{"nLineBreakOpportunities", "(Ljava/lang/String;[CI[I)[I", (void*) nLineBreakOpportunities}
};
int register_android_text_StaticLayout(JNIEnv* env)
{
return AndroidRuntime::registerNativeMethods(env, "android/text/StaticLayout",
gMethods, NELEM(gMethods));
}
}