diff options
| author | 2015-07-01 14:39:31 -0700 | |
|---|---|---|
| committer | 2015-07-01 15:53:23 -0700 | |
| commit | 2ea5290ffb9efe0a7c187fb1177ef8ecd089803c (patch) | |
| tree | 867c693c303249bac0d7805622d497bbe5386b49 | |
| parent | f22e2e3998db9bcfdac5d1c524b0c02e7da7f86d (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.java | 29 | ||||
| -rw-r--r-- | core/java/android/text/StaticLayout.java | 61 |
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; } |