diff --git a/api/current.txt b/api/current.txt index 878e2e8a3851b..29f14a748038e 100755 --- a/api/current.txt +++ b/api/current.txt @@ -15468,8 +15468,8 @@ package android.graphics.text { public static class MeasuredText.Builder { ctor public MeasuredText.Builder(char[]); - method public android.graphics.text.MeasuredText.Builder addReplacementRun(android.graphics.Paint, int, int, float); - method public android.graphics.text.MeasuredText.Builder addStyleRun(android.graphics.Paint, int, int, boolean); + method public android.graphics.text.MeasuredText.Builder appendReplacementRun(android.graphics.Paint, int, float); + method public android.graphics.text.MeasuredText.Builder appendStyleRun(android.graphics.Paint, int, boolean); method public android.graphics.text.MeasuredText build(); method public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean); method public android.graphics.text.MeasuredText.Builder setComputeLayout(boolean); diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java index 0a2d65c9ebffa..f9370a8aa6af0 100644 --- a/core/java/android/text/MeasuredParagraph.java +++ b/core/java/android/text/MeasuredParagraph.java @@ -505,7 +505,7 @@ public class MeasuredParagraph { } mWholeWidth += width; } else { - builder.addReplacementRun(mCachedPaint, start, end, width); + builder.appendReplacementRun(mCachedPaint, end - start, width); } } @@ -520,7 +520,7 @@ public class MeasuredParagraph { mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */, mWidths.getRawArray(), start); } else { - builder.addStyleRun(mCachedPaint, start, end, false /* isRtl */); + builder.appendStyleRun(mCachedPaint, end - start, false /* isRtl */); } } else { // If there is multiple bidi levels, split into individual bidi level and apply style. @@ -536,7 +536,7 @@ public class MeasuredParagraph { mCopiedBuffer, levelStart, levelLength, levelStart, levelLength, isRtl, mWidths.getRawArray(), levelStart); } else { - builder.addStyleRun(mCachedPaint, levelStart, levelEnd, isRtl); + builder.appendStyleRun(mCachedPaint, levelEnd - levelStart, isRtl); } if (levelEnd == end) { break; diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java index 8d38f961f4029..16479095a63ad 100644 --- a/graphics/java/android/graphics/text/LineBreaker.java +++ b/graphics/java/android/graphics/text/LineBreaker.java @@ -38,11 +38,14 @@ import java.lang.annotation.RetentionPolicy; *
  * 
  * Paint paint = new Paint();
+ * Paint bigPaint = new Paint();
+ * bigPaint.setTextSize(paint.getTextSize() * 2.0);
  * String text = "Hello, Android.";
  *
  * // Prepare the measured text
  * MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
- *     .addStyleRun(paint, 0, text.length(), false)  // Use paint for whole paragraph.
+ *     .appendStyleRun(paint, 7, false)  // Use paint for "Hello, "
+ *     .appednStyleRun(bigPaint, 8, false)  // Use bigPaint for "Hello, "
  *     .build();
  *
  * LineBreaker lb = new LineBreaker.Builder()
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index 852e66e174ca2..3efe655b25654 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -31,6 +31,21 @@ import libcore.util.NativeAllocationRegistry;
 
 /**
  * Result of text shaping of the single paragraph string.
+ *
+ * 

+ *

+ * 
+ * Paint paint = new Paint();
+ * Paint bigPaint = new Paint();
+ * bigPaint.setTextSize(paint.getTextSize() * 2.0);
+ * String text = "Hello, Android.";
+ * MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
+ *      .appendStyleRun(paint, 7, false)  // Use paint for "Hello, "
+ *      .appendStyleRun(bigPaint, 8, false)  // Use bigPaint for "Hello, "
+ *      .build();
+ * 
+ * 
+ *

*/ public class MeasuredText { private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( @@ -136,6 +151,19 @@ public class MeasuredText { /** * Helper class for creating a {@link MeasuredText}. + *

+ *

+     * 
+     * Paint paint = new Paint();
+     * String text = "Hello, Android.";
+     * MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
+     *      .appendStyleRun(paint, text.length, false)
+     *      .build();
+     * 
+     * 
+ *

+ * + * Note: The appendStyle and appendReplacementRun should be called to cover the text length. */ public static class Builder { private long mNativePtr; @@ -143,6 +171,7 @@ public class MeasuredText { private final @NonNull char[] mText; private boolean mComputeHyphenation = false; private boolean mComputeLayout = true; + private int mCurrentOffset = 0; /** * Construct a builder. @@ -159,35 +188,50 @@ public class MeasuredText { } /** - * Apply styles to the given range. + * Apply styles to the given length. + * + * Keeps an internal offset which increases at every append. The initial value for this + * offset is zero. After the style is applied the internal offset is moved to {@code offset + * + length}, and next call will start from this new position. * * @param paint a paint - * @param start an inclusive start index of the range - * @param end an exclusive end index of the range + * @param length a length to be applied with a given paint, can not exceed the length of the + * text * @param isRtl true if the text is in RTL context, otherwise false. */ - public Builder addStyleRun(@NonNull Paint paint, - @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean isRtl) { + public Builder appendStyleRun(@NonNull Paint paint, @IntRange(from = 0) int length, + boolean isRtl) { Preconditions.checkNotNull(paint); - nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl); + Preconditions.checkArgument(length > 0, "length can not be negative"); + final int end = mCurrentOffset + length; + Preconditions.checkArgument(end <= mText.length, "Style exceeds the text length"); + nAddStyleRun(mNativePtr, paint.getNativeInstance(), mCurrentOffset, end, isRtl); + mCurrentOffset = end; return this; } /** - * Used to inform the text layout that the given range is replaced with the object of given + * Used to inform the text layout that the given length is replaced with the object of given * width. * - * Informs the layout engine that the given range should not be processed, instead the + * Keeps an internal offset which increases at every append. The initial value for this + * offset is zero. After the style is applied the internal offset is moved to {@code offset + * + length}, and next call will start from this new position. + * + * Informs the layout engine that the given length should not be processed, instead the * provided width should be used for calculating the width of that range. * - * @param start an inclusive start index of the range - * @param end an exclusive end index of the range + * @param length a length to be replaced with the object, can not exceed the length of the + * text * @param width a replacement width of the range */ - public Builder addReplacementRun(@NonNull Paint paint, - @IntRange(from = 0) int start, @IntRange(from = 0) int end, - @FloatRange(from = 0) float width) { - nAddReplacementRun(mNativePtr, paint.getNativeInstance(), start, end, width); + public Builder appendReplacementRun(@NonNull Paint paint, + @IntRange(from = 0) int length, @FloatRange(from = 0) float width) { + Preconditions.checkArgument(length > 0, "length can not be negative"); + final int end = mCurrentOffset + length; + Preconditions.checkArgument(end <= mText.length, "Replacement exceeds the text length"); + nAddReplacementRun(mNativePtr, paint.getNativeInstance(), mCurrentOffset, end, width); + mCurrentOffset = end; return this; } @@ -230,9 +274,14 @@ public class MeasuredText { * * Once you called build() method, you can't reuse the Builder class again. * @throws IllegalStateException if this Builder is reused. + * @throws IllegalStateException if the whole text is not covered by one or more runs (style + * or replacement) */ public MeasuredText build() { ensureNativePtrNoReuse(); + if (mCurrentOffset != mText.length) { + throw new IllegalStateException("Style info has not been provided for all text."); + } try { long ptr = nBuildMeasuredText(mNativePtr, mText, mComputeHyphenation, mComputeLayout);