Improve BoringLayout#isBoring for PrecomputedText
Bug: 216736786 Test: atest PrecomputedTextTest Test: perf score becomes 758,071 -> 110,755 Change-Id: I57d3eb9d1e896ed1c847733c4e96ac52dd97d2c4
This commit is contained in:
@@ -16412,6 +16412,7 @@ package android.graphics.text {
|
||||
public class MeasuredText {
|
||||
method public void getBounds(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Rect);
|
||||
method @FloatRange(from=0.0f) @Px public float getCharWidthAt(@IntRange(from=0) int);
|
||||
method public void getFontMetricsInt(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Paint.FontMetricsInt);
|
||||
method @FloatRange(from=0.0) @Px public float getWidth(@IntRange(from=0) int, @IntRange(from=0) int);
|
||||
}
|
||||
|
||||
@@ -44939,6 +44940,7 @@ package android.text {
|
||||
method public char charAt(int);
|
||||
method public static android.text.PrecomputedText create(@NonNull CharSequence, @NonNull android.text.PrecomputedText.Params);
|
||||
method public void getBounds(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Rect);
|
||||
method public void getFontMetricsInt(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Paint.FontMetricsInt);
|
||||
method @IntRange(from=0) public int getParagraphCount();
|
||||
method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
|
||||
method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
|
||||
|
||||
@@ -286,6 +286,16 @@ public class MeasuredParagraph {
|
||||
mMeasuredText.getBounds(start, end, bounds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the font metrics for the given range.
|
||||
*
|
||||
* This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
|
||||
*/
|
||||
public void getFontMetricsInt(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
|
||||
@NonNull Paint.FontMetricsInt fmi) {
|
||||
mMeasuredText.getFontMetricsInt(start, end, fmi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a width of the character at the offset.
|
||||
*
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.annotation.IntDef;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.text.LineBreakConfig;
|
||||
import android.graphics.text.MeasuredText;
|
||||
@@ -696,6 +697,38 @@ public class PrecomputedText implements Spannable {
|
||||
getMeasuredParagraph(paraIndex).getBounds(start - paraStart, end - paraStart, bounds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the text font metrics for the given range.
|
||||
* Both {@code start} and {@code end} offset need to be in the same paragraph, otherwise
|
||||
* IllegalArgumentException will be thrown.
|
||||
*
|
||||
* @param start the inclusive start offset in the text
|
||||
* @param end the exclusive end offset in the text
|
||||
* @param outMetrics the output font metrics
|
||||
* @throws IllegalArgumentException if start and end offset are in the different paragraph.
|
||||
*/
|
||||
public void getFontMetricsInt(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
|
||||
@NonNull Paint.FontMetricsInt outMetrics) {
|
||||
Preconditions.checkArgument(0 <= start && start <= mText.length(), "invalid start offset");
|
||||
Preconditions.checkArgument(0 <= end && end <= mText.length(), "invalid end offset");
|
||||
Preconditions.checkArgument(start <= end, "start offset can not be larger than end offset");
|
||||
Objects.requireNonNull(outMetrics);
|
||||
if (start == end) {
|
||||
mParams.getTextPaint().getFontMetricsInt(outMetrics);
|
||||
return;
|
||||
}
|
||||
final int paraIndex = findParaIndex(start);
|
||||
final int paraStart = getParagraphStart(paraIndex);
|
||||
final int paraEnd = getParagraphEnd(paraIndex);
|
||||
if (start < paraStart || paraEnd < end) {
|
||||
throw new IllegalArgumentException("Cannot measured across the paragraph:"
|
||||
+ "para: (" + paraStart + ", " + paraEnd + "), "
|
||||
+ "request: (" + start + ", " + end + ")");
|
||||
}
|
||||
getMeasuredParagraph(paraIndex).getFontMetricsInt(start - paraStart,
|
||||
end - paraStart, outMetrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a width of a character at offset
|
||||
*
|
||||
|
||||
@@ -866,8 +866,12 @@ public class TextLine {
|
||||
wp.getFontMetricsInt(mChars, start, count, contextStart, contextCount, runIsRtl,
|
||||
fmi);
|
||||
} else {
|
||||
wp.getFontMetricsInt(mText, mStart + start, count, mStart + contextStart, contextCount,
|
||||
runIsRtl, fmi);
|
||||
if (mComputed == null) {
|
||||
wp.getFontMetricsInt(mText, mStart + start, count, mStart + contextStart,
|
||||
contextCount, runIsRtl, fmi);
|
||||
} else {
|
||||
mComputed.getFontMetricsInt(mStart + start, mStart + end, fmi);
|
||||
}
|
||||
}
|
||||
|
||||
updateMetrics(fmi, previousTop, previousAscent, previousDescent, previousBottom,
|
||||
|
||||
@@ -34,6 +34,7 @@ import libcore.util.NativeAllocationRegistry;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Result of text shaping of the single paragraph string.
|
||||
@@ -56,18 +57,22 @@ import java.lang.annotation.RetentionPolicy;
|
||||
public class MeasuredText {
|
||||
private static final String TAG = "MeasuredText";
|
||||
|
||||
private long mNativePtr;
|
||||
private boolean mComputeHyphenation;
|
||||
private boolean mComputeLayout;
|
||||
private @NonNull char[] mChars;
|
||||
private final long mNativePtr;
|
||||
private final boolean mComputeHyphenation;
|
||||
private final boolean mComputeLayout;
|
||||
@NonNull private final char[] mChars;
|
||||
private final int mTop;
|
||||
private final int mBottom;
|
||||
|
||||
// Use builder instead.
|
||||
private MeasuredText(long ptr, @NonNull char[] chars, boolean computeHyphenation,
|
||||
boolean computeLayout) {
|
||||
boolean computeLayout, int top, int bottom) {
|
||||
mNativePtr = ptr;
|
||||
mChars = chars;
|
||||
mComputeHyphenation = computeHyphenation;
|
||||
mComputeLayout = computeLayout;
|
||||
mTop = top;
|
||||
mBottom = bottom;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,6 +128,30 @@ public class MeasuredText {
|
||||
nGetBounds(mNativePtr, mChars, start, end, rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the font metrics of the given range
|
||||
*
|
||||
* @param start an inclusive start index of the range
|
||||
* @param end an exclusive end index of the range
|
||||
* @param outMetrics an output metrics object
|
||||
*/
|
||||
public void getFontMetricsInt(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
|
||||
@NonNull Paint.FontMetricsInt outMetrics) {
|
||||
Preconditions.checkArgument(0 <= start && start <= mChars.length,
|
||||
"start(%d) must be 0 <= start <= %d", start, mChars.length);
|
||||
Preconditions.checkArgument(0 <= end && end <= mChars.length,
|
||||
"end(%d) must be 0 <= end <= %d", end, mChars.length);
|
||||
Preconditions.checkArgument(start <= end,
|
||||
"start(%d) is larger than end(%d)", start, end);
|
||||
Objects.requireNonNull(outMetrics);
|
||||
|
||||
long packed = nGetExtent(mNativePtr, mChars, start, end);
|
||||
outMetrics.ascent = (int) (packed >> 32);
|
||||
outMetrics.descent = (int) (packed & 0xFFFFFFFF);
|
||||
outMetrics.top = Math.min(outMetrics.ascent, mTop);
|
||||
outMetrics.bottom = Math.max(outMetrics.descent, mBottom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the width of the character at the given offset.
|
||||
*
|
||||
@@ -160,6 +189,8 @@ public class MeasuredText {
|
||||
@CriticalNative
|
||||
private static native float nGetCharWidthAt(long nativePtr, int offset);
|
||||
|
||||
private static native long nGetExtent(long nativePtr, char[] buf, int start, int end);
|
||||
|
||||
/**
|
||||
* Helper class for creating a {@link MeasuredText}.
|
||||
* <p>
|
||||
@@ -189,6 +220,9 @@ public class MeasuredText {
|
||||
private boolean mFastHyphenation = false;
|
||||
private int mCurrentOffset = 0;
|
||||
private @Nullable MeasuredText mHintMt = null;
|
||||
private int mTop = 0;
|
||||
private int mBottom = 0;
|
||||
private Paint.FontMetricsInt mCachedMetrics = new Paint.FontMetricsInt();
|
||||
|
||||
/**
|
||||
* Construct a builder.
|
||||
@@ -269,6 +303,10 @@ public class MeasuredText {
|
||||
nAddStyleRun(mNativePtr, paint.getNativeInstance(), lbStyle, lbWordStyle,
|
||||
mCurrentOffset, end, isRtl);
|
||||
mCurrentOffset = end;
|
||||
|
||||
paint.getFontMetricsInt(mCachedMetrics);
|
||||
mTop = Math.min(mTop, mCachedMetrics.top);
|
||||
mBottom = Math.max(mBottom, mCachedMetrics.bottom);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -419,7 +457,7 @@ public class MeasuredText {
|
||||
long ptr = nBuildMeasuredText(mNativePtr, hintPtr, mText, mComputeHyphenation,
|
||||
mComputeLayout, mFastHyphenation);
|
||||
final MeasuredText res = new MeasuredText(ptr, mText, mComputeHyphenation,
|
||||
mComputeLayout);
|
||||
mComputeLayout, mTop, mBottom);
|
||||
sRegistry.registerNativeAllocation(res, ptr);
|
||||
return res;
|
||||
} finally {
|
||||
|
||||
@@ -134,6 +134,21 @@ static void nGetBounds(JNIEnv* env, jobject, jlong ptr, jcharArray javaText, jin
|
||||
GraphicsJNI::irect_to_jrect(ir, env, bounds);
|
||||
}
|
||||
|
||||
// Regular JNI
|
||||
static jlong nGetExtent(JNIEnv* env, jobject, jlong ptr, jcharArray javaText, jint start,
|
||||
jint end) {
|
||||
ScopedCharArrayRO text(env, javaText);
|
||||
const minikin::U16StringPiece textBuffer(text.get(), text.size());
|
||||
const minikin::Range range(start, end);
|
||||
|
||||
minikin::MinikinExtent extent = toMeasuredParagraph(ptr)->getExtent(textBuffer, range);
|
||||
|
||||
int32_t ascent = SkScalarRoundToInt(extent.ascent);
|
||||
int32_t descent = SkScalarRoundToInt(extent.descent);
|
||||
|
||||
return (((jlong)(ascent)) << 32) | ((jlong)descent);
|
||||
}
|
||||
|
||||
// CriticalNative
|
||||
static jlong nGetReleaseFunc(CRITICAL_JNI_PARAMS) {
|
||||
return toJLong(&releaseMeasuredParagraph);
|
||||
@@ -153,12 +168,13 @@ static const JNINativeMethod gMTBuilderMethods[] = {
|
||||
};
|
||||
|
||||
static const JNINativeMethod gMTMethods[] = {
|
||||
// MeasuredParagraph native functions.
|
||||
{"nGetWidth", "(JII)F", (void*) nGetWidth}, // Critical Natives
|
||||
{"nGetBounds", "(J[CIILandroid/graphics/Rect;)V", (void*) nGetBounds}, // Regular JNI
|
||||
{"nGetReleaseFunc", "()J", (void*) nGetReleaseFunc}, // Critical Natives
|
||||
{"nGetMemoryUsage", "(J)I", (void*) nGetMemoryUsage}, // Critical Native
|
||||
{"nGetCharWidthAt", "(JI)F", (void*) nGetCharWidthAt}, // Critical Native
|
||||
// MeasuredParagraph native functions.
|
||||
{"nGetWidth", "(JII)F", (void*)nGetWidth}, // Critical Natives
|
||||
{"nGetBounds", "(J[CIILandroid/graphics/Rect;)V", (void*)nGetBounds}, // Regular JNI
|
||||
{"nGetExtent", "(J[CII)J", (void*)nGetExtent}, // Regular JNI
|
||||
{"nGetReleaseFunc", "()J", (void*)nGetReleaseFunc}, // Critical Natives
|
||||
{"nGetMemoryUsage", "(J)I", (void*)nGetMemoryUsage}, // Critical Native
|
||||
{"nGetCharWidthAt", "(JI)F", (void*)nGetCharWidthAt}, // Critical Native
|
||||
};
|
||||
|
||||
int register_android_graphics_text_MeasuredText(JNIEnv* env) {
|
||||
|
||||
Reference in New Issue
Block a user