Extract native methods into isolated classes
StaticLayout/MeasuredParagraph uses native methods which is a pain point
of porting TextView to JetPack.
To make minimize the dependency to the native methods, extract native
methods and put them into a thin wrapper class.
The performance impact is limited:
android.text.StaticLayoutPerfTest:
PrecomputedText Balanced Hyphenation : 602 -> 644: ( +42, +7.0%)
PrecomputedText Balanced NoHyphenation: 457 -> 476: ( +19, +4.2%)
PrecomputedText Greedy Hyphenation : 397 -> 412: ( +15, +3.8%)
PrecomputedText Greedy NoHyphenation : 397 -> 411: ( +14, +3.5%)
RandomText Balanced Hyphenation : 17,594 -> 17,715: (+121, +0.7%)
RandomText Balanced NoHyphenation : 7,146 -> 7,236: ( +90, +1.3%)
RandomText Greedy Hyphenation : 7,125 -> 7,196: ( +71, +1.0%)
RandomText Greedy NoHyphenation : 7,099 -> 7,187: ( +88, +1.2%)
draw
PrecomputedText NoStyle : 614 -> 628: ( +14, +2.3%)
PrecomputedText Style : 778 -> 826: ( +48, +6.2%)
RandomText NoStyle : 537 -> 540: ( +3, +0.6%)
RandomText Style : 786 -> 759: ( -27, -3.4%)
Bug: N/A
Test: atest CtsWidgetTestCases:EditTextTest
CtsWidgetTestCases:TextViewFadingEdgeTest
FrameworksCoreTests:TextViewFallbackLineSpacingTest
FrameworksCoreTests:TextViewTest FrameworksCoreTests:TypefaceTest
CtsGraphicsTestCases:TypefaceTest CtsWidgetTestCases:TextViewTest
CtsTextTestCases FrameworksCoreTests:android.text
CtsWidgetTestCases:TextViewPrecomputedTextTest
Change-Id: I976df4db63be241af395dd30dd94182f76bdae53
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 4b78aa2..6dad238 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Paint;
-import android.text.AutoGrowArray.FloatArray;
import android.text.style.LeadingMarginSpan;
import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
import android.text.style.LineHeightSpan;
@@ -32,9 +31,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import dalvik.annotation.optimization.CriticalNative;
-import dalvik.annotation.optimization.FastNative;
-
import java.util.Arrays;
/**
@@ -57,7 +53,7 @@
*
* - Create MeasuredParagraph by MeasuredParagraph.buildForStaticLayout which measures in
* native.
- * - Run nComputeLineBreaks() to obtain line breaks for the paragraph.
+ * - Run NativeLineBreaker.computeLineBreaks() to obtain line breaks for the paragraph.
*
* After all paragraphs, call finish() to release expensive buffers.
*/
@@ -586,8 +582,7 @@
float ellipsizedWidth = b.mEllipsizedWidth;
TextUtils.TruncateAt ellipsize = b.mEllipsize;
final boolean addLastLineSpacing = b.mAddLastLineLineSpacing;
- LineBreaks lineBreaks = new LineBreaks(); // TODO: move to builder to avoid allocation costs
- FloatArray widths = new FloatArray();
+ NativeLineBreaker.LineBreaks lineBreaks = new NativeLineBreaker.LineBreaks();
mLineCount = 0;
mEllipsized = false;
@@ -615,7 +610,7 @@
indents = null;
}
- final long nativePtr = nInit(
+ final NativeLineBreaker lineBreaker = new NativeLineBreaker(
b.mBreakStrategy, b.mHyphenationFrequency,
// TODO: Support more justification mode, e.g. letter spacing, stretching.
b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE,
@@ -639,243 +634,219 @@
bufEnd, false /* computeLayout */);
}
- try {
- for (int paraIndex = 0; paraIndex < paragraphInfo.length; paraIndex++) {
- final int paraStart = paraIndex == 0
- ? bufStart : paragraphInfo[paraIndex - 1].paragraphEnd;
- final int paraEnd = paragraphInfo[paraIndex].paragraphEnd;
+ for (int paraIndex = 0; paraIndex < paragraphInfo.length; paraIndex++) {
+ final int paraStart = paraIndex == 0
+ ? bufStart : paragraphInfo[paraIndex - 1].paragraphEnd;
+ final int paraEnd = paragraphInfo[paraIndex].paragraphEnd;
- int firstWidthLineCount = 1;
- int firstWidth = outerWidth;
- int restWidth = outerWidth;
+ int firstWidthLineCount = 1;
+ int firstWidth = outerWidth;
+ int restWidth = outerWidth;
- LineHeightSpan[] chooseHt = null;
+ LineHeightSpan[] chooseHt = null;
+ if (spanned != null) {
+ LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd,
+ LeadingMarginSpan.class);
+ for (int i = 0; i < sp.length; i++) {
+ LeadingMarginSpan lms = sp[i];
+ firstWidth -= sp[i].getLeadingMargin(true);
+ restWidth -= sp[i].getLeadingMargin(false);
- if (spanned != null) {
- LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd,
- LeadingMarginSpan.class);
- for (int i = 0; i < sp.length; i++) {
- LeadingMarginSpan lms = sp[i];
- firstWidth -= sp[i].getLeadingMargin(true);
- restWidth -= sp[i].getLeadingMargin(false);
+ // LeadingMarginSpan2 is odd. The count affects all
+ // leading margin spans, not just this particular one
+ if (lms instanceof LeadingMarginSpan2) {
+ LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
+ firstWidthLineCount = Math.max(firstWidthLineCount,
+ lms2.getLeadingMarginLineCount());
+ }
+ }
- // LeadingMarginSpan2 is odd. The count affects all
- // leading margin spans, not just this particular one
- if (lms instanceof LeadingMarginSpan2) {
- LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
- firstWidthLineCount = Math.max(firstWidthLineCount,
- lms2.getLeadingMarginLineCount());
- }
+ chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
+
+ if (chooseHt.length == 0) {
+ chooseHt = null; // So that out() would not assume it has any contents
+ } else {
+ if (chooseHtv == null || chooseHtv.length < chooseHt.length) {
+ chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
}
- chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
+ for (int i = 0; i < chooseHt.length; i++) {
+ int o = spanned.getSpanStart(chooseHt[i]);
- if (chooseHt.length == 0) {
- chooseHt = null; // So that out() would not assume it has any contents
+ if (o < paraStart) {
+ // starts in this layout, before the
+ // current paragraph
+
+ chooseHtv[i] = getLineTop(getLineForOffset(o));
+ } else {
+ // starts in this paragraph
+
+ chooseHtv[i] = v;
+ }
+ }
+ }
+ }
+ // tab stop locations
+ int[] variableTabStops = null;
+ if (spanned != null) {
+ TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
+ paraEnd, TabStopSpan.class);
+ if (spans.length > 0) {
+ int[] stops = new int[spans.length];
+ for (int i = 0; i < spans.length; i++) {
+ stops[i] = spans[i].getTabStop();
+ }
+ Arrays.sort(stops, 0, stops.length);
+ variableTabStops = stops;
+ }
+ }
+
+ final MeasuredParagraph measuredPara = paragraphInfo[paraIndex].measured;
+ final char[] chs = measuredPara.getChars();
+ final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray();
+ final int[] fmCache = measuredPara.getFontMetrics().getRawArray();
+ int breakCount = lineBreaker.computeLineBreaks(
+ measuredPara.getChars(),
+ measuredPara.getNativeMeasuredParagraph(),
+ paraEnd - paraStart,
+ firstWidth,
+ firstWidthLineCount,
+ restWidth,
+ variableTabStops,
+ TAB_INCREMENT,
+ mLineCount,
+ lineBreaks);
+
+ final int[] breaks = lineBreaks.breaks;
+ final float[] lineWidths = lineBreaks.widths;
+ final float[] ascents = lineBreaks.ascents;
+ final float[] descents = lineBreaks.descents;
+ final int[] flags = lineBreaks.flags;
+
+ final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
+ final boolean ellipsisMayBeApplied = ellipsize != null
+ && (ellipsize == TextUtils.TruncateAt.END
+ || (mMaximumVisibleLineCount == 1
+ && ellipsize != TextUtils.TruncateAt.MARQUEE));
+ if (0 < remainingLineCount && remainingLineCount < breakCount
+ && ellipsisMayBeApplied) {
+ // Calculate width
+ float width = 0;
+ int flag = 0; // XXX May need to also have starting hyphen edit
+ for (int i = remainingLineCount - 1; i < breakCount; i++) {
+ if (i == breakCount - 1) {
+ width += lineWidths[i];
} else {
- if (chooseHtv == null || chooseHtv.length < chooseHt.length) {
- chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
- }
-
- for (int i = 0; i < chooseHt.length; i++) {
- int o = spanned.getSpanStart(chooseHt[i]);
-
- if (o < paraStart) {
- // starts in this layout, before the
- // current paragraph
-
- chooseHtv[i] = getLineTop(getLineForOffset(o));
- } else {
- // starts in this paragraph
-
- chooseHtv[i] = v;
- }
+ for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
+ width += measuredPara.getCharWidthAt(j - paraStart);
}
}
+ flag |= flags[i] & TAB_MASK;
+ }
+ // Treat the last line and overflowed lines as a single line.
+ breaks[remainingLineCount - 1] = breaks[breakCount - 1];
+ lineWidths[remainingLineCount - 1] = width;
+ flags[remainingLineCount - 1] = flag;
+
+ breakCount = remainingLineCount;
+ }
+
+ // here is the offset of the starting character of the line we are currently
+ // measuring
+ int here = paraStart;
+
+ int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0;
+ int fmCacheIndex = 0;
+ int spanEndCacheIndex = 0;
+ int breakIndex = 0;
+ for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
+ // retrieve end of span
+ spanEnd = spanEndCache[spanEndCacheIndex++];
+
+ // retrieve cached metrics, order matches above
+ fm.top = fmCache[fmCacheIndex * 4 + 0];
+ fm.bottom = fmCache[fmCacheIndex * 4 + 1];
+ fm.ascent = fmCache[fmCacheIndex * 4 + 2];
+ fm.descent = fmCache[fmCacheIndex * 4 + 3];
+ fmCacheIndex++;
+
+ if (fm.top < fmTop) {
+ fmTop = fm.top;
+ }
+ if (fm.ascent < fmAscent) {
+ fmAscent = fm.ascent;
+ }
+ if (fm.descent > fmDescent) {
+ fmDescent = fm.descent;
+ }
+ if (fm.bottom > fmBottom) {
+ fmBottom = fm.bottom;
}
- // tab stop locations
- int[] variableTabStops = null;
- if (spanned != null) {
- TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
- paraEnd, TabStopSpan.class);
- if (spans.length > 0) {
- int[] stops = new int[spans.length];
- for (int i = 0; i < spans.length; i++) {
- stops[i] = spans[i].getTabStop();
- }
- Arrays.sort(stops, 0, stops.length);
- variableTabStops = stops;
- }
+ // skip breaks ending before current span range
+ while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
+ breakIndex++;
}
- final MeasuredParagraph measuredPara = paragraphInfo[paraIndex].measured;
- final char[] chs = measuredPara.getChars();
- final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray();
- final int[] fmCache = measuredPara.getFontMetrics().getRawArray();
- // TODO: Stop keeping duplicated width copy in native and Java.
- widths.resize(chs.length);
+ while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
+ int endPos = paraStart + breaks[breakIndex];
- // measurement has to be done before performing line breaking
- // but we don't want to recompute fontmetrics or span ranges the
- // second time, so we cache those and then use those stored values
+ boolean moreChars = (endPos < bufEnd);
- int breakCount = nComputeLineBreaks(
- nativePtr,
+ final int ascent = fallbackLineSpacing
+ ? Math.min(fmAscent, Math.round(ascents[breakIndex]))
+ : fmAscent;
+ final int descent = fallbackLineSpacing
+ ? Math.max(fmDescent, Math.round(descents[breakIndex]))
+ : fmDescent;
- // Inputs
- chs,
- measuredPara.getNativePtr(),
- paraEnd - paraStart,
- firstWidth,
- firstWidthLineCount,
- restWidth,
- variableTabStops,
- TAB_INCREMENT,
- mLineCount,
+ v = out(source, here, endPos,
+ ascent, descent, fmTop, fmBottom,
+ v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
+ flags[breakIndex], needMultiply, measuredPara, bufEnd,
+ includepad, trackpad, addLastLineSpacing, chs,
+ paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],
+ paint, moreChars);
- // Outputs
- lineBreaks,
- lineBreaks.breaks.length,
- lineBreaks.breaks,
- lineBreaks.widths,
- lineBreaks.ascents,
- lineBreaks.descents,
- lineBreaks.flags,
- widths.getRawArray());
-
- final int[] breaks = lineBreaks.breaks;
- final float[] lineWidths = lineBreaks.widths;
- final float[] ascents = lineBreaks.ascents;
- final float[] descents = lineBreaks.descents;
- final int[] flags = lineBreaks.flags;
-
- final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
- final boolean ellipsisMayBeApplied = ellipsize != null
- && (ellipsize == TextUtils.TruncateAt.END
- || (mMaximumVisibleLineCount == 1
- && ellipsize != TextUtils.TruncateAt.MARQUEE));
- if (0 < remainingLineCount && remainingLineCount < breakCount
- && ellipsisMayBeApplied) {
- // Calculate width and flag.
- float width = 0;
- int flag = 0; // XXX May need to also have starting hyphen edit
- for (int i = remainingLineCount - 1; i < breakCount; i++) {
- if (i == breakCount - 1) {
- width += lineWidths[i];
- } else {
- for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
- width += widths.get(j);
- }
- }
- flag |= flags[i] & TAB_MASK;
- }
- // Treat the last line and overflowed lines as a single line.
- breaks[remainingLineCount - 1] = breaks[breakCount - 1];
- lineWidths[remainingLineCount - 1] = width;
- flags[remainingLineCount - 1] = flag;
-
- breakCount = remainingLineCount;
- }
-
- // here is the offset of the starting character of the line we are currently
- // measuring
- int here = paraStart;
-
- int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0;
- int fmCacheIndex = 0;
- int spanEndCacheIndex = 0;
- int breakIndex = 0;
- for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
- // retrieve end of span
- spanEnd = spanEndCache[spanEndCacheIndex++];
-
- // retrieve cached metrics, order matches above
- fm.top = fmCache[fmCacheIndex * 4 + 0];
- fm.bottom = fmCache[fmCacheIndex * 4 + 1];
- fm.ascent = fmCache[fmCacheIndex * 4 + 2];
- fm.descent = fmCache[fmCacheIndex * 4 + 3];
- fmCacheIndex++;
-
- if (fm.top < fmTop) {
+ if (endPos < spanEnd) {
+ // preserve metrics for current span
fmTop = fm.top;
- }
- if (fm.ascent < fmAscent) {
- fmAscent = fm.ascent;
- }
- if (fm.descent > fmDescent) {
- fmDescent = fm.descent;
- }
- if (fm.bottom > fmBottom) {
fmBottom = fm.bottom;
+ fmAscent = fm.ascent;
+ fmDescent = fm.descent;
+ } else {
+ fmTop = fmBottom = fmAscent = fmDescent = 0;
}
- // skip breaks ending before current span range
- while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
- breakIndex++;
+ here = endPos;
+ breakIndex++;
+
+ if (mLineCount >= mMaximumVisibleLineCount && mEllipsized) {
+ return;
}
-
- while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
- int endPos = paraStart + breaks[breakIndex];
-
- boolean moreChars = (endPos < bufEnd);
-
- final int ascent = fallbackLineSpacing
- ? Math.min(fmAscent, Math.round(ascents[breakIndex]))
- : fmAscent;
- final int descent = fallbackLineSpacing
- ? Math.max(fmDescent, Math.round(descents[breakIndex]))
- : fmDescent;
- v = out(source, here, endPos,
- ascent, descent, fmTop, fmBottom,
- v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
- flags[breakIndex], needMultiply, measuredPara, bufEnd,
- includepad, trackpad, addLastLineSpacing, chs, widths.getRawArray(),
- paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],
- paint, moreChars);
-
- if (endPos < spanEnd) {
- // preserve metrics for current span
- fmTop = fm.top;
- fmBottom = fm.bottom;
- fmAscent = fm.ascent;
- fmDescent = fm.descent;
- } else {
- fmTop = fmBottom = fmAscent = fmDescent = 0;
- }
-
- here = endPos;
- breakIndex++;
-
- if (mLineCount >= mMaximumVisibleLineCount && mEllipsized) {
- return;
- }
- }
- }
-
- if (paraEnd == bufEnd) {
- break;
}
}
- if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE)
- && mLineCount < mMaximumVisibleLineCount) {
- final MeasuredParagraph measuredPara =
- MeasuredParagraph.buildForBidi(source, bufEnd, bufEnd, textDir, null);
- paint.getFontMetricsInt(fm);
- v = out(source,
- bufEnd, bufEnd, fm.ascent, fm.descent,
- fm.top, fm.bottom,
- v,
- spacingmult, spacingadd, null,
- null, fm, 0,
- needMultiply, measuredPara, bufEnd,
- includepad, trackpad, addLastLineSpacing, null,
- null, bufStart, ellipsize,
- ellipsizedWidth, 0, paint, false);
+ if (paraEnd == bufEnd) {
+ break;
}
- } finally {
- nFinish(nativePtr);
+ }
+
+ if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE)
+ && mLineCount < mMaximumVisibleLineCount) {
+ final MeasuredParagraph measuredPara =
+ MeasuredParagraph.buildForBidi(source, bufEnd, bufEnd, textDir, null);
+ paint.getFontMetricsInt(fm);
+ v = out(source,
+ bufEnd, bufEnd, fm.ascent, fm.descent,
+ fm.top, fm.bottom,
+ v,
+ spacingmult, spacingadd, null,
+ null, fm, 0,
+ needMultiply, measuredPara, bufEnd,
+ includepad, trackpad, addLastLineSpacing, null,
+ bufStart, ellipsize,
+ ellipsizedWidth, 0, paint, false);
}
}
@@ -884,7 +855,7 @@
final LineHeightSpan[] chooseHt, final int[] chooseHtv, final Paint.FontMetricsInt fm,
final int flags, final boolean needMultiply, @NonNull final MeasuredParagraph measured,
final int bufEnd, final boolean includePad, final boolean trackPad,
- final boolean addLastLineLineSpacing, final char[] chs, final float[] widths,
+ final boolean addLastLineLineSpacing, final char[] chs,
final int widthStart, final TextUtils.TruncateAt ellipsize, final float ellipsisWidth,
final float textWidth, final TextPaint paint, final boolean moreChars) {
final int j = mLineCount;
@@ -942,7 +913,7 @@
(!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) &&
ellipsize == TextUtils.TruncateAt.END);
if (doEllipsis) {
- calculateEllipsis(start, end, widths, widthStart,
+ calculateEllipsis(start, end, measured, widthStart,
ellipsisWidth, ellipsize, j,
textWidth, paint, forceEllipsis);
}
@@ -1026,7 +997,7 @@
}
private void calculateEllipsis(int lineStart, int lineEnd,
- float[] widths, int widthStart,
+ MeasuredParagraph measured, int widthStart,
float avail, TextUtils.TruncateAt where,
int line, float textWidth, TextPaint paint,
boolean forceEllipsis) {
@@ -1050,9 +1021,10 @@
int i;
for (i = len; i > 0; i--) {
- float w = widths[i - 1 + lineStart - widthStart];
+ float w = measured.getCharWidthAt(i - 1 + lineStart - widthStart);
if (w + sum + ellipsisWidth > avail) {
- while (i < len && widths[i + lineStart - widthStart] == 0.0f) {
+ while (i < len
+ && measured.getCharWidthAt(i + lineStart - widthStart) == 0.0f) {
i++;
}
break;
@@ -1074,7 +1046,7 @@
int i;
for (i = 0; i < len; i++) {
- float w = widths[i + lineStart - widthStart];
+ float w = measured.getCharWidthAt(i + lineStart - widthStart);
if (w + sum + ellipsisWidth > avail) {
break;
@@ -1097,10 +1069,12 @@
float ravail = (avail - ellipsisWidth) / 2;
for (right = len; right > 0; right--) {
- float w = widths[right - 1 + lineStart - widthStart];
+ float w = measured.getCharWidthAt(right - 1 + lineStart - widthStart);
if (w + rsum > ravail) {
- while (right < len && widths[right + lineStart - widthStart] == 0.0f) {
+ while (right < len
+ && measured.getCharWidthAt(right + lineStart - widthStart)
+ == 0.0f) {
right++;
}
break;
@@ -1110,7 +1084,7 @@
float lavail = avail - ellipsisWidth - rsum;
for (left = 0; left < right; left++) {
- float w = widths[left + lineStart - widthStart];
+ float w = measured.getCharWidthAt(left + lineStart - widthStart);
if (w + lsum > lavail) {
break;
@@ -1306,47 +1280,6 @@
? mMaxLineHeight : super.getHeight();
}
- @FastNative
- private static native long nInit(
- @BreakStrategy int breakStrategy,
- @HyphenationFrequency int hyphenationFrequency,
- boolean isJustified,
- @Nullable int[] indents);
-
- @CriticalNative
- private static native void nFinish(long nativePtr);
-
- // populates LineBreaks and returns the number of breaks found
- //
- // the arrays inside the LineBreaks objects are passed in as well
- // to reduce the number of JNI calls in the common case where the
- // arrays do not have to be resized
- // The individual character widths will be returned in charWidths. The length of charWidths must
- // be at least the length of the text.
- private static native int nComputeLineBreaks(
- /* non zero */ long nativePtr,
-
- // Inputs
- @NonNull char[] text,
- /* Non Zero */ long measuredTextPtr,
- @IntRange(from = 0) int length,
- @FloatRange(from = 0.0f) float firstWidth,
- @IntRange(from = 0) int firstWidthLineCount,
- @FloatRange(from = 0.0f) float restWidth,
- @Nullable int[] variableTabStops,
- int defaultTabStop,
- @IntRange(from = 0) int indentsOffset,
-
- // Outputs
- @NonNull LineBreaks recycle,
- @IntRange(from = 0) int recycleLength,
- @NonNull int[] recycleBreaks,
- @NonNull float[] recycleWidths,
- @NonNull float[] recycleAscents,
- @NonNull float[] recycleDescents,
- @NonNull int[] recycleFlags,
- @NonNull float[] charWidths);
-
private int mLineCount;
private int mTopPadding, mBottomPadding;
private int mColumns;
@@ -1396,8 +1329,7 @@
private static final int DEFAULT_MAX_LINE_HEIGHT = -1;
- // This is used to return three arrays from a single JNI call when
- // performing line breaking
+ // Unused, here because of gray list private API accesses.
/*package*/ static class LineBreaks {
private static final int INITIAL_SIZE = 16;
public int[] breaks = new int[INITIAL_SIZE];