summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Raph Levien <raph@google.com> 2015-07-01 14:39:31 -0700
committer Raph Levien <raph@google.com> 2015-07-01 15:53:23 -0700
commit2ea5290ffb9efe0a7c187fb1177ef8ecd089803c (patch)
tree867c693c303249bac0d7805622d497bbe5386b49
parentf22e2e3998db9bcfdac5d1c524b0c02e7da7f86d (diff)
Fix problems with StaticLayout indentation
The implementation of indendataion had two issues. First, the indent pattern would restart on a new paragraph, which created problems when a multi-paragraph text would flow into a shape. Second, the indents didn't affect drawing position, which is ok for centered text but not most of the other alignments. This patch fixes both. Bug: 21904268 Change-Id: I53a3eb1c192fc0f8f0beace304832eed61b38497
-rw-r--r--core/java/android/text/Layout.java29
-rw-r--r--core/java/android/text/StaticLayout.java61
2 files changed, 79 insertions, 11 deletions
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index f7027f9e20b8..d82213857ac0 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -385,21 +385,22 @@ public abstract class Layout {
int x;
if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_LEFT_TO_RIGHT) {
- x = left;
+ x = left + getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
} else {
- x = right;
+ x = right + getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
}
} else {
int max = (int)getLineExtent(lineNum, tabStops, false);
if (align == Alignment.ALIGN_OPPOSITE) {
if (dir == DIR_LEFT_TO_RIGHT) {
- x = right - max;
+ x = right - max + getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
} else {
- x = left - max;
+ x = left - max + getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
}
} else { // Alignment.ALIGN_CENTER
max = max & ~1;
- x = (right + left - max) >> 1;
+ x = ((right + left - max) >> 1) +
+ getIndentAdjust(lineNum, Alignment.ALIGN_CENTER);
}
}
@@ -545,9 +546,9 @@ public abstract class Layout {
int x;
if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_LEFT_TO_RIGHT) {
- x = left;
+ x = left + getIndentAdjust(line, Alignment.ALIGN_LEFT);
} else {
- x = right;
+ x = right + getIndentAdjust(line, Alignment.ALIGN_RIGHT);
}
} else {
TabStops tabStops = null;
@@ -565,14 +566,14 @@ public abstract class Layout {
int max = (int)getLineExtent(line, tabStops, false);
if (align == Alignment.ALIGN_OPPOSITE) {
if (dir == DIR_LEFT_TO_RIGHT) {
- x = right - max;
+ x = right - max + getIndentAdjust(line, Alignment.ALIGN_RIGHT);
} else {
// max is negative here
- x = left - max;
+ x = left - max + getIndentAdjust(line, Alignment.ALIGN_LEFT);
}
} else { // Alignment.ALIGN_CENTER
max = max & ~1;
- x = (left + right - max) >> 1;
+ x = (left + right - max) >> 1 + getIndentAdjust(line, Alignment.ALIGN_CENTER);
}
}
return x;
@@ -745,6 +746,14 @@ public abstract class Layout {
return 0;
}
+ /**
+ * Returns the left indent for a line.
+ *
+ * @hide
+ */
+ public int getIndentAdjust(int line, Alignment alignment) {
+ 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 b6fa4e4cf9e8..cdff395a3fa9 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -103,6 +103,8 @@ public class StaticLayout extends Layout {
b.mText = null;
MeasuredText.recycle(b.mMeasuredText);
b.mMeasuredText = null;
+ b.mLeftIndents = null;
+ b.mRightIndents = null;
nFinishBuilder(b.mNativePtr);
sPool.release(b);
}
@@ -296,9 +298,10 @@ public class StaticLayout extends Layout {
* @param leftIndents array of indent values for left margin, in pixels
* @param rightIndents array of indent values for right margin, in pixels
* @return this builder, useful for chaining
- * @see android.widget.TextView#setIndents
*/
public Builder setIndents(int[] leftIndents, int[] rightIndents) {
+ mLeftIndents = leftIndents;
+ mRightIndents = rightIndents;
int leftLen = leftIndents == null ? 0 : leftIndents.length;
int rightLen = rightIndents == null ? 0 : rightIndents.length;
int[] indents = new int[Math.max(leftLen, rightLen)];
@@ -393,6 +396,8 @@ public class StaticLayout extends Layout {
int mMaxLines;
int mBreakStrategy;
int mHyphenationFrequency;
+ int[] mLeftIndents;
+ int[] mRightIndents;
Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
@@ -544,6 +549,9 @@ public class StaticLayout extends Layout {
mLines = new int[mLineDirections.length];
mMaximumVisibleLineCount = b.mMaxLines;
+ mLeftIndents = b.mLeftIndents;
+ mRightIndents = b.mRightIndents;
+
generate(b, b.mIncludePad, b.mIncludePad);
}
@@ -661,6 +669,23 @@ public class StaticLayout extends Layout {
nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
firstWidth, firstWidthLineCount, restWidth,
variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency);
+ if (mLeftIndents != null || mRightIndents != null) {
+ // TODO(raph) performance: it would be better to do this once per layout rather
+ // than once per paragraph, but that would require a change to the native
+ // interface.
+ int leftLen = mLeftIndents == null ? 0 : mLeftIndents.length;
+ int rightLen = mRightIndents == null ? 0 : mRightIndents.length;
+ int indentsLen = Math.max(1, Math.min(leftLen, rightLen) - mLineCount);
+ int[] indents = new int[indentsLen];
+ for (int i = 0; i < indentsLen; i++) {
+ int leftMargin = mLeftIndents == null ? 0 :
+ mLeftIndents[Math.min(i + mLineCount, leftLen - 1)];
+ int rightMargin = mRightIndents == null ? 0 :
+ mRightIndents[Math.min(i + mLineCount, rightLen - 1)];
+ indents[i] = leftMargin + rightMargin;
+ }
+ nSetIndents(b.mNativePtr, indents);
+ }
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
@@ -1154,6 +1179,38 @@ public class StaticLayout extends Layout {
return mLines[mColumns * line + HYPHEN] & 0xff;
}
+ /**
+ * @hide
+ */
+ @Override
+ public int getIndentAdjust(int line, Alignment align) {
+ if (align == Alignment.ALIGN_LEFT) {
+ if (mLeftIndents == null) {
+ return 0;
+ } else {
+ return mLeftIndents[Math.min(line, mLeftIndents.length - 1)];
+ }
+ } else if (align == Alignment.ALIGN_RIGHT) {
+ if (mRightIndents == null) {
+ return 0;
+ } else {
+ return -mRightIndents[Math.min(line, mRightIndents.length - 1)];
+ }
+ } else if (align == Alignment.ALIGN_CENTER) {
+ int left = 0;
+ if (mLeftIndents != null) {
+ left = mLeftIndents[Math.min(line, mLeftIndents.length - 1)];
+ }
+ int right = 0;
+ if (mRightIndents != null) {
+ right = mRightIndents[Math.min(line, mRightIndents.length - 1)];
+ }
+ return (left - right) >> 1;
+ } else {
+ throw new AssertionError("unhandled alignment " + align);
+ }
+ }
+
@Override
public int getEllipsisCount(int line) {
if (mColumns < COLUMNS_ELLIPSIZE) {
@@ -1250,4 +1307,6 @@ public class StaticLayout extends Layout {
// breaks, widths, and flags should all have the same length
}
+ private int[] mLeftIndents;
+ private int[] mRightIndents;
}