summaryrefslogtreecommitdiffstats
path: root/core/java/android/text
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/text')
-rw-r--r--core/java/android/text/DynamicLayout.java19
-rw-r--r--core/java/android/text/Hyphenator.java76
-rw-r--r--core/java/android/text/Layout.java32
-rw-r--r--core/java/android/text/StaticLayout.java43
-rw-r--r--core/java/android/text/TextLine.java4
5 files changed, 145 insertions, 29 deletions
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 1bdaef0..7d2e1ef 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -356,6 +356,8 @@ public class DynamicLayout extends Layout
ints[DESCENT] = desc;
objects[0] = reflowed.getLineDirections(i);
+ ints[HYPHEN] = reflowed.getHyphen(i);
+
if (mEllipsize) {
ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i);
ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i);
@@ -631,6 +633,14 @@ public class DynamicLayout extends Layout
return mBottomPadding;
}
+ /**
+ * @hide
+ */
+ @Override
+ public int getHyphen(int line) {
+ return mInts.getValue(line, HYPHEN);
+ }
+
@Override
public int getEllipsizedWidth() {
return mEllipsizedWidth;
@@ -739,11 +749,12 @@ public class DynamicLayout extends Layout
private static final int TAB = START;
private static final int TOP = 1;
private static final int DESCENT = 2;
- private static final int COLUMNS_NORMAL = 3;
+ private static final int HYPHEN = 3;
+ private static final int COLUMNS_NORMAL = 4;
- private static final int ELLIPSIS_START = 3;
- private static final int ELLIPSIS_COUNT = 4;
- private static final int COLUMNS_ELLIPSIZE = 5;
+ private static final int ELLIPSIS_START = 4;
+ private static final int ELLIPSIS_COUNT = 5;
+ private static final int COLUMNS_ELLIPSIZE = 6;
private static final int START_MASK = 0x1FFFFFFF;
private static final int DIR_SHIFT = 30;
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
new file mode 100644
index 0000000..f4dff9b
--- /dev/null
+++ b/core/java/android/text/Hyphenator.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package android.text;
+
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.HashMap;
+import java.util.Locale;
+
+/**
+ * Hyphenator is a wrapper class for a native implementation of automatic hyphenation,
+ * in essence finding valid hyphenation opportunities in a word.
+ *
+ * @hide
+ */
+/* package */ class Hyphenator {
+ // This class has deliberately simple lifetime management (no finalizer) because in
+ // the common case a process will use a very small number of locales.
+
+ private static String TAG = "Hyphenator";
+
+ static HashMap<Locale, Hyphenator> sMap = new HashMap<Locale, Hyphenator>();
+
+ private long mNativePtr;
+
+ private Hyphenator(long nativePtr) {
+ mNativePtr = nativePtr;
+ }
+
+ public static long get(Locale locale) {
+ synchronized (sMap) {
+ Hyphenator result = sMap.get(locale);
+ if (result == null) {
+ result = loadHyphenator(locale);
+ sMap.put(locale, result);
+ }
+ return result == null ? 0 : result.mNativePtr;
+ }
+ }
+
+ private static Hyphenator loadHyphenator(Locale locale) {
+ // TODO: find pattern dictionary (from system location) that best matches locale
+ if (Locale.US.equals(locale)) {
+ File f = new File("/data/local/tmp/hyph-en-us.pat.txt");
+ try {
+ RandomAccessFile rf = new RandomAccessFile(f, "r");
+ byte[] buf = new byte[(int)rf.length()];
+ rf.read(buf);
+ rf.close();
+ String patternData = new String(buf);
+ long nativePtr = StaticLayout.nLoadHyphenator(patternData);
+ return new Hyphenator(nativePtr);
+ } catch (IOException e) {
+ Log.e(TAG, "error loading hyphenation " + f);
+ }
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 928bf16..22abb18 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -225,17 +225,17 @@ public abstract class Layout {
// Draw the lines, one at a time.
// The baseline is the top of the following line minus the current line's descent.
- for (int i = firstLine; i <= lastLine; i++) {
+ for (int lineNum = firstLine; lineNum <= lastLine; lineNum++) {
int start = previousLineEnd;
- previousLineEnd = getLineStart(i + 1);
- int end = getLineVisibleEnd(i, start, previousLineEnd);
+ previousLineEnd = getLineStart(lineNum + 1);
+ int end = getLineVisibleEnd(lineNum, start, previousLineEnd);
int ltop = previousLineBottom;
- int lbottom = getLineTop(i+1);
+ int lbottom = getLineTop(lineNum + 1);
previousLineBottom = lbottom;
- int lbaseline = lbottom - getLineDescent(i);
+ int lbaseline = lbottom - getLineDescent(lineNum);
- int dir = getParagraphDirection(i);
+ int dir = getParagraphDirection(lineNum);
int left = 0;
int right = mWidth;
@@ -254,7 +254,7 @@ public abstract class Layout {
// just collect the ones present at the start of the paragraph.
// If spanEnd is before the end of the paragraph, that's not
// our problem.
- if (start >= spanEnd && (i == firstLine || isFirstParaLine)) {
+ if (start >= spanEnd && (lineNum == firstLine || isFirstParaLine)) {
spanEnd = sp.nextSpanTransition(start, textLength,
ParagraphStyle.class);
spans = getParagraphSpans(sp, start, spanEnd, ParagraphStyle.class);
@@ -280,7 +280,7 @@ public abstract class Layout {
int startLine = getLineForOffset(sp.getSpanStart(spans[n]));
// if there is more than one LeadingMarginSpan2, use
// the count that is greatest
- if (i < startLine + count) {
+ if (lineNum < startLine + count) {
useFirstLineMargin = true;
break;
}
@@ -304,7 +304,7 @@ public abstract class Layout {
}
}
- boolean hasTabOrEmoji = getLineContainsTab(i);
+ boolean hasTabOrEmoji = getLineContainsTab(lineNum);
// Can't tell if we have tabs for sure, currently
if (hasTabOrEmoji && !tabStopsIsInitialized) {
if (tabStops == null) {
@@ -333,7 +333,7 @@ public abstract class Layout {
x = right;
}
} else {
- int max = (int)getLineExtent(i, tabStops, false);
+ int max = (int)getLineExtent(lineNum, tabStops, false);
if (align == Alignment.ALIGN_OPPOSITE) {
if (dir == DIR_LEFT_TO_RIGHT) {
x = right - max;
@@ -346,7 +346,8 @@ public abstract class Layout {
}
}
- Directions directions = getLineDirections(i);
+ paint.setHyphenEdit(getHyphen(lineNum));
+ Directions directions = getLineDirections(lineNum);
if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTabOrEmoji) {
// XXX: assumes there's nothing additional to be done
canvas.drawText(buf, start, end, x, lbaseline, paint);
@@ -677,6 +678,15 @@ public abstract class Layout {
*/
public abstract int getBottomPadding();
+ /**
+ * Returns the hyphen edit for a line.
+ *
+ * @hide
+ */
+ public int getHyphen(int line) {
+ return 0;
+ }
+
/**
* Returns true if the character at offset and the preceding character
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index b47418f..4174df0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -170,7 +170,8 @@ public class StaticLayout extends Layout {
* Measurement and break iteration is done in native code. The protocol for using
* the native code is as follows.
*
- * For each paragraph, do a nSetText of the paragraph text. Also do nSetLineWidth.
+ * For each paragraph, do a nSetupParagraph, which sets paragraph text, line width, tab
+ * stops, break strategy (and possibly other parameters in the future).
*
* Then, for each run within the paragraph:
* - setLocale (this must be done at least for the first run, optional afterwards)
@@ -187,7 +188,7 @@ public class StaticLayout extends Layout {
private void setLocale(Locale locale) {
if (!locale.equals(mLocale)) {
- nSetLocale(mNativePtr, locale.toLanguageTag());
+ nSetLocale(mNativePtr, locale.toLanguageTag(), Hyphenator.get(locale));
mLocale = locale;
}
}
@@ -531,7 +532,7 @@ public class StaticLayout extends Layout {
int[] breaks = lineBreaks.breaks;
float[] lineWidths = lineBreaks.widths;
- boolean[] flags = lineBreaks.flags;
+ int[] flags = lineBreaks.flags;
// here is the offset of the starting character of the line we are currently measuring
int here = paraStart;
@@ -617,7 +618,7 @@ public class StaticLayout extends Layout {
fm.top, fm.bottom,
v,
spacingmult, spacingadd, null,
- null, fm, false,
+ null, fm, 0,
needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd,
includepad, trackpad, null,
null, bufStart, ellipsize,
@@ -629,7 +630,7 @@ public class StaticLayout extends Layout {
int above, int below, int top, int bottom, int v,
float spacingmult, float spacingadd,
LineHeightSpan[] chooseHt, int[] chooseHtv,
- Paint.FontMetricsInt fm, boolean hasTabOrEmoji,
+ Paint.FontMetricsInt fm, int flags,
boolean needMultiply, byte[] chdirs, int dir,
boolean easy, int bufEnd, boolean includePad,
boolean trackPad, char[] chs,
@@ -722,8 +723,10 @@ public class StaticLayout extends Layout {
lines[off + mColumns + START] = end;
lines[off + mColumns + TOP] = v;
- if (hasTabOrEmoji)
- lines[off + TAB] |= TAB_MASK;
+ // TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining
+ // one bit for start field
+ lines[off + TAB] |= flags & TAB_MASK;
+ lines[off + HYPHEN] = flags;
lines[off + DIR] |= dir << DIR_SHIFT;
Directions linedirs = DIRS_ALL_LEFT_TO_RIGHT;
@@ -942,6 +945,14 @@ public class StaticLayout extends Layout {
return mBottomPadding;
}
+ /**
+ * @hide
+ */
+ @Override
+ public int getHyphen(int line) {
+ return mLines[mColumns * line + HYPHEN] & 0xff;
+ }
+
@Override
public int getEllipsisCount(int line) {
if (mColumns < COLUMNS_ELLIPSIZE) {
@@ -968,7 +979,10 @@ public class StaticLayout extends Layout {
private static native long nNewBuilder();
private static native void nFreeBuilder(long nativePtr);
private static native void nFinishBuilder(long nativePtr);
- private static native void nSetLocale(long nativePtr, String locale);
+
+ /* package */ static native long nLoadHyphenator(String patternData);
+
+ private static native void nSetLocale(long nativePtr, String locale, long nativeHyphenator);
// Set up paragraph text and settings; done as one big method to minimize jni crossings
private static native void nSetupParagraph(long nativePtr, char[] text, int length,
@@ -991,22 +1005,23 @@ public class StaticLayout extends Layout {
// to reduce the number of JNI calls in the common case where the
// arrays do not have to be resized
private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle,
- int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength);
+ int[] recycleBreaks, float[] recycleWidths, int[] recycleFlags, int recycleLength);
private int mLineCount;
private int mTopPadding, mBottomPadding;
private int mColumns;
private int mEllipsizedWidth;
- private static final int COLUMNS_NORMAL = 3;
- private static final int COLUMNS_ELLIPSIZE = 5;
+ private static final int COLUMNS_NORMAL = 4;
+ private static final int COLUMNS_ELLIPSIZE = 6;
private static final int START = 0;
private static final int DIR = START;
private static final int TAB = START;
private static final int TOP = 1;
private static final int DESCENT = 2;
- private static final int ELLIPSIS_START = 3;
- private static final int ELLIPSIS_COUNT = 4;
+ private static final int HYPHEN = 3;
+ private static final int ELLIPSIS_START = 4;
+ private static final int ELLIPSIS_COUNT = 5;
private int[] mLines;
private Directions[] mLineDirections;
@@ -1028,7 +1043,7 @@ public class StaticLayout extends Layout {
private static final int INITIAL_SIZE = 16;
public int[] breaks = new int[INITIAL_SIZE];
public float[] widths = new float[INITIAL_SIZE];
- public boolean[] flags = new boolean[INITIAL_SIZE]; // hasTabOrEmoji
+ public int[] flags = new int[INITIAL_SIZE]; // hasTabOrEmoji
// breaks, widths, and flags should all have the same length
}
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 4725581..479242c 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -955,6 +955,10 @@ class TextLine {
span.updateDrawState(wp);
}
+ // Only draw hyphen on last run in line
+ if (jnext < mLen) {
+ wp.setHyphenEdit(0);
+ }
x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x,
top, y, bottom, fmi, needWidth || jnext < measureLimit);
}