Loading api/current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -11524,8 +11524,12 @@ package android.graphics { method public int getHinting(); method public float getLetterSpacing(); method public android.graphics.MaskFilter getMaskFilter(); method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float); method public int getOffsetForAdvance(java.lang.CharSequence, int, int, int, int, boolean, float); method public android.graphics.PathEffect getPathEffect(); method public deprecated android.graphics.Rasterizer getRasterizer(); method public float getRunAdvance(char[], int, int, int, int, boolean, int); method public float getRunAdvance(java.lang.CharSequence, int, int, int, int, boolean, int); method public android.graphics.Shader getShader(); method public android.graphics.Paint.Cap getStrokeCap(); method public android.graphics.Paint.Join getStrokeJoin(); api/system-current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -11818,8 +11818,12 @@ package android.graphics { method public int getHinting(); method public float getLetterSpacing(); method public android.graphics.MaskFilter getMaskFilter(); method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float); method public int getOffsetForAdvance(java.lang.CharSequence, int, int, int, int, boolean, float); method public android.graphics.PathEffect getPathEffect(); method public deprecated android.graphics.Rasterizer getRasterizer(); method public float getRunAdvance(char[], int, int, int, int, boolean, int); method public float getRunAdvance(java.lang.CharSequence, int, int, int, int, boolean, int); method public android.graphics.Shader getShader(); method public android.graphics.Paint.Cap getStrokeCap(); method public android.graphics.Paint.Join getStrokeJoin(); core/jni/android/graphics/Paint.cpp +63 −13 Original line number Diff line number Diff line Loading @@ -22,8 +22,8 @@ #include "jni.h" #include "GraphicsJNI.h" #include "core_jni_helpers.h" #include <ScopedUtfChars.h> #include <ScopedStringChars.h> #include <ScopedUtfChars.h> #include "SkBlurDrawLooper.h" #include "SkColorFilter.h" Loading @@ -37,6 +37,7 @@ #include "utils/Blur.h" #include <minikin/GraphemeBreak.h> #include <minikin/Measurement.h> #include "MinikinSkia.h" #include "MinikinUtils.h" #include "Paint.h" Loading Loading @@ -1038,6 +1039,48 @@ public: return nGlyphs > 0 && !layoutContainsNotdef(layout); } static jfloat doRunAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[], jint start, jint count, jint bufSize, jboolean isRtl, jint offset) { Layout layout; int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, buf, start, count, bufSize); return getRunAdvance(layout, buf, start, count, offset); } static jfloat getRunAdvance___CIIIIZI_F(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl, jint offset) { const Paint* paint = reinterpret_cast<Paint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); // TODO performance: optimize JNI array access jchar* textArray = env->GetCharArrayElements(text, NULL); jfloat result = doRunAdvance(paint, typeface, textArray + contextStart, start - contextStart, end - start, contextEnd - contextStart, isRtl, offset); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); return result; } static jint doOffsetForAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[], jint start, jint count, jint bufSize, jboolean isRtl, jfloat advance) { Layout layout; int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, buf, start, count, bufSize); return getOffsetForAdvance(layout, buf, start, count, advance); } static jint getOffsetForAdvance___CIIIIZF_I(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl, jfloat advance) { const Paint* paint = reinterpret_cast<Paint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); // TODO performance: optimize JNI array access jchar* textArray = env->GetCharArrayElements(text, NULL); jint result = doOffsetForAdvance(paint, typeface, textArray + contextStart, start - contextStart, end - start, contextEnd - contextStart, isRtl, advance); result += contextStart; env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); return result; } }; static JNINativeMethod methods[] = { Loading Loading @@ -1094,21 +1137,25 @@ static JNINativeMethod methods[] = { {"setTextSkewX","!(F)V", (void*) PaintGlue::setTextSkewX}, {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing}, {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing}, {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings}, {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings}, {"native_getHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit}, {"native_setHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit}, {"ascent","!()F", (void*) PaintGlue::ascent}, {"descent","!()F", (void*) PaintGlue::descent}, {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics}, {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt}, {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics}, {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt}, {"native_measureText","([CIII)F", (void*) PaintGlue::measureText_CIII}, {"native_measureText","(Ljava/lang/String;I)F", (void*) PaintGlue::measureText_StringI}, {"native_measureText","(Ljava/lang/String;III)F", (void*) PaintGlue::measureText_StringIII}, {"native_breakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC}, {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS}, {"native_getTextWidths","(JJ[CIII[F)I", (void*) PaintGlue::getTextWidths___CIII_F}, {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) PaintGlue::getTextWidths__StringIII_F}, {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) PaintGlue::getTextWidths__StringIII_F}, {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F", (void*) PaintGlue::getTextRunAdvances___CIIIIZ_FI}, {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F", Loading @@ -1124,6 +1171,9 @@ static JNINativeMethod methods[] = { {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V", (void*) PaintGlue::getCharArrayBounds }, {"native_hasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph }, {"native_getRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F}, {"native_getOffsetForAdvance", "(JJ[CIIIIZF)I", (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I}, {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer}, {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer} Loading graphics/java/android/graphics/Paint.java +168 −0 Original line number Diff line number Diff line Loading @@ -2269,6 +2269,168 @@ public class Paint { return native_hasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string); } /** * Measure cursor position within a run of text. * * <p>The run of text includes the characters from {@code start} to {@code end} in the text. In * addition, the range {@code contextStart} to {@code contextEnd} is used as context for the * purpose of complex text shaping, such as Arabic text potentially shaped differently based on * the text next to it. * * All text outside the range {@code contextStart..contextEnd} is ignored. The text between * {@code start} and {@code end} will be laid out to be measured. * * The returned width measurement is the advance from {@code start} to {@code offset}. It is * generally a positive value, no matter the direction of the run. If {@code offset == end}, * the return value is simply the width of the whole run from {@code start} to {@code end}. * * Ligatures are formed for characters in the range {@code start..end} (but not for * {@code start..contextStart} or {@code end..contextEnd}). If {@code offset} points to a * character in the middle of such a formed ligature, but at a grapheme cluster boundary, the * return value will also reflect an advance in the middle of the ligature. See * {@link #getOffsetForAdvance} for more discussion of grapheme cluster boundaries. * * The direction of the run is explicitly specified by {@code isRtl}. Thus, this method is * suitable only for runs of a single direction. * * <p>All indices are relative to the start of {@code text}. Further, {@code 0 <= contextStart * <= start <= offset <= end <= contextEnd <= text.length} must hold on entry. * * @param text the text to measure. Cannot be null. * @param start the index of the start of the range to measure * @param end the index + 1 of the end of the range to measure * @param contextStart the index of the start of the shaping context * @param contextEnd the index + 1 of the end of the range to measure * @param isRtl whether the run is in RTL direction * @param offset index of caret position * @return width measurement between start and offset */ public float getRunAdvance(char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } if ((contextStart | start | offset | end | contextEnd | start - contextStart | offset - start | end - offset | contextEnd - end | text.length - contextEnd) < 0) { throw new IndexOutOfBoundsException(); } if (end == start) { return 0.0f; } // TODO: take mCompatScaling into account (or eliminate compat scaling)? return native_getRunAdvance(mNativePaint, mNativeTypeface, text, start, end, contextStart, contextEnd, isRtl, offset); } /** * @see #getRunAdvance(char[], int, int, int, int, boolean, int) * * @param text the text to measure. Cannot be null. * @param start the index of the start of the range to measure * @param end the index + 1 of the end of the range to measure * @param contextStart the index of the start of the shaping context * @param contextEnd the index + 1 of the end of the range to measure * @param isRtl whether the run is in RTL direction * @param offset index of caret position * @return width measurement between start and offset */ public float getRunAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } if ((contextStart | start | offset | end | contextEnd | start - contextStart | offset - start | end - offset | contextEnd - end | text.length() - contextEnd) < 0) { throw new IndexOutOfBoundsException(); } if (end == start) { return 0.0f; } // TODO performance: specialized alternatives to avoid buffer copy, if win is significant char[] buf = TemporaryBuffer.obtain(contextEnd - contextStart); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); float result = getRunAdvance(buf, start - contextStart, end - contextStart, 0, contextEnd - contextStart, isRtl, offset - contextStart); TemporaryBuffer.recycle(buf); return result; } /** * Get the character offset within the string whose position is closest to the specified * horizontal position. * * <p>The returned value is generally the value of {@code offset} for which * {@link #getRunAdvance} yields a result most closely approximating {@code advance}, * and which is also on a grapheme cluster boundary. As such, it is the preferred method * for positioning a cursor in response to a touch or pointer event. The grapheme cluster * boundaries are based on * <a href="http://unicode.org/reports/tr29/">Unicode Standard Annex #29</a> but with some * tailoring for better user experience. * * <p>Note that {@code advance} is a (generally positive) width measurement relative to the start * of the run. Thus, for RTL runs it the distance from the point to the right edge. * * <p>All indices are relative to the start of {@code text}. Further, {@code 0 <= contextStart * <= start <= end <= contextEnd <= text.length} must hold on entry, and {@code start <= result * <= end} will hold on return. * * @param text the text to measure. Cannot be null. * @param start the index of the start of the range to measure * @param end the index + 1 of the end of the range to measure * @param contextStart the index of the start of the shaping context * @param contextEnd the index + 1 of the end of the range to measure * @param isRtl whether the run is in RTL direction * @param advance width relative to start of run * @return index of offset */ public int getOffsetForAdvance(char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } if ((contextStart | start | end | contextEnd | start - contextStart | end - start | contextEnd - end | text.length - contextEnd) < 0) { throw new IndexOutOfBoundsException(); } // TODO: take mCompatScaling into account (or eliminate compat scaling)? return native_getOffsetForAdvance(mNativePaint, mNativeTypeface, text, start, end, contextStart, contextEnd, isRtl, advance); } /** * @see #getOffsetForAdvance(char[], int, int, int, int, boolean, float) * * @param text the text to measure. Cannot be null. * @param start the index of the start of the range to measure * @param end the index + 1 of the end of the range to measure * @param contextStart the index of the start of the shaping context * @param contextEnd the index + 1 of the end of the range to measure * @param isRtl whether the run is in RTL direction * @param advance width relative to start of run * @return index of offset */ public int getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } if ((contextStart | start | end | contextEnd | start - contextStart | end - start | contextEnd - end | text.length() - contextEnd) < 0) { throw new IndexOutOfBoundsException(); } // TODO performance: specialized alternatives to avoid buffer copy, if win is significant char[] buf = TemporaryBuffer.obtain(contextEnd - contextStart); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); int result = getOffsetForAdvance(buf, start - contextStart, end - contextStart, 0, contextEnd - contextStart, isRtl, advance) + contextStart; TemporaryBuffer.recycle(buf); return result; } @Override protected void finalize() throws Throwable { try { Loading Loading @@ -2356,4 +2518,10 @@ public class Paint { private static native void native_setHyphenEdit(long native_object, int hyphen); private static native boolean native_hasGlyph(long native_object, long native_typeface, int bidiFlags, String string); private static native float native_getRunAdvance(long native_object, long native_typeface, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset); private static native int native_getOffsetForAdvance(long native_object, long native_typeface, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance); } Loading
api/current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -11524,8 +11524,12 @@ package android.graphics { method public int getHinting(); method public float getLetterSpacing(); method public android.graphics.MaskFilter getMaskFilter(); method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float); method public int getOffsetForAdvance(java.lang.CharSequence, int, int, int, int, boolean, float); method public android.graphics.PathEffect getPathEffect(); method public deprecated android.graphics.Rasterizer getRasterizer(); method public float getRunAdvance(char[], int, int, int, int, boolean, int); method public float getRunAdvance(java.lang.CharSequence, int, int, int, int, boolean, int); method public android.graphics.Shader getShader(); method public android.graphics.Paint.Cap getStrokeCap(); method public android.graphics.Paint.Join getStrokeJoin();
api/system-current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -11818,8 +11818,12 @@ package android.graphics { method public int getHinting(); method public float getLetterSpacing(); method public android.graphics.MaskFilter getMaskFilter(); method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float); method public int getOffsetForAdvance(java.lang.CharSequence, int, int, int, int, boolean, float); method public android.graphics.PathEffect getPathEffect(); method public deprecated android.graphics.Rasterizer getRasterizer(); method public float getRunAdvance(char[], int, int, int, int, boolean, int); method public float getRunAdvance(java.lang.CharSequence, int, int, int, int, boolean, int); method public android.graphics.Shader getShader(); method public android.graphics.Paint.Cap getStrokeCap(); method public android.graphics.Paint.Join getStrokeJoin();
core/jni/android/graphics/Paint.cpp +63 −13 Original line number Diff line number Diff line Loading @@ -22,8 +22,8 @@ #include "jni.h" #include "GraphicsJNI.h" #include "core_jni_helpers.h" #include <ScopedUtfChars.h> #include <ScopedStringChars.h> #include <ScopedUtfChars.h> #include "SkBlurDrawLooper.h" #include "SkColorFilter.h" Loading @@ -37,6 +37,7 @@ #include "utils/Blur.h" #include <minikin/GraphemeBreak.h> #include <minikin/Measurement.h> #include "MinikinSkia.h" #include "MinikinUtils.h" #include "Paint.h" Loading Loading @@ -1038,6 +1039,48 @@ public: return nGlyphs > 0 && !layoutContainsNotdef(layout); } static jfloat doRunAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[], jint start, jint count, jint bufSize, jboolean isRtl, jint offset) { Layout layout; int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, buf, start, count, bufSize); return getRunAdvance(layout, buf, start, count, offset); } static jfloat getRunAdvance___CIIIIZI_F(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl, jint offset) { const Paint* paint = reinterpret_cast<Paint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); // TODO performance: optimize JNI array access jchar* textArray = env->GetCharArrayElements(text, NULL); jfloat result = doRunAdvance(paint, typeface, textArray + contextStart, start - contextStart, end - start, contextEnd - contextStart, isRtl, offset); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); return result; } static jint doOffsetForAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[], jint start, jint count, jint bufSize, jboolean isRtl, jfloat advance) { Layout layout; int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, buf, start, count, bufSize); return getOffsetForAdvance(layout, buf, start, count, advance); } static jint getOffsetForAdvance___CIIIIZF_I(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl, jfloat advance) { const Paint* paint = reinterpret_cast<Paint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); // TODO performance: optimize JNI array access jchar* textArray = env->GetCharArrayElements(text, NULL); jint result = doOffsetForAdvance(paint, typeface, textArray + contextStart, start - contextStart, end - start, contextEnd - contextStart, isRtl, advance); result += contextStart; env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); return result; } }; static JNINativeMethod methods[] = { Loading Loading @@ -1094,21 +1137,25 @@ static JNINativeMethod methods[] = { {"setTextSkewX","!(F)V", (void*) PaintGlue::setTextSkewX}, {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing}, {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing}, {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings}, {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings}, {"native_getHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit}, {"native_setHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit}, {"ascent","!()F", (void*) PaintGlue::ascent}, {"descent","!()F", (void*) PaintGlue::descent}, {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics}, {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt}, {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics}, {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt}, {"native_measureText","([CIII)F", (void*) PaintGlue::measureText_CIII}, {"native_measureText","(Ljava/lang/String;I)F", (void*) PaintGlue::measureText_StringI}, {"native_measureText","(Ljava/lang/String;III)F", (void*) PaintGlue::measureText_StringIII}, {"native_breakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC}, {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS}, {"native_getTextWidths","(JJ[CIII[F)I", (void*) PaintGlue::getTextWidths___CIII_F}, {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) PaintGlue::getTextWidths__StringIII_F}, {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) PaintGlue::getTextWidths__StringIII_F}, {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F", (void*) PaintGlue::getTextRunAdvances___CIIIIZ_FI}, {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F", Loading @@ -1124,6 +1171,9 @@ static JNINativeMethod methods[] = { {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V", (void*) PaintGlue::getCharArrayBounds }, {"native_hasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph }, {"native_getRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F}, {"native_getOffsetForAdvance", "(JJ[CIIIIZF)I", (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I}, {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer}, {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer} Loading
graphics/java/android/graphics/Paint.java +168 −0 Original line number Diff line number Diff line Loading @@ -2269,6 +2269,168 @@ public class Paint { return native_hasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string); } /** * Measure cursor position within a run of text. * * <p>The run of text includes the characters from {@code start} to {@code end} in the text. In * addition, the range {@code contextStart} to {@code contextEnd} is used as context for the * purpose of complex text shaping, such as Arabic text potentially shaped differently based on * the text next to it. * * All text outside the range {@code contextStart..contextEnd} is ignored. The text between * {@code start} and {@code end} will be laid out to be measured. * * The returned width measurement is the advance from {@code start} to {@code offset}. It is * generally a positive value, no matter the direction of the run. If {@code offset == end}, * the return value is simply the width of the whole run from {@code start} to {@code end}. * * Ligatures are formed for characters in the range {@code start..end} (but not for * {@code start..contextStart} or {@code end..contextEnd}). If {@code offset} points to a * character in the middle of such a formed ligature, but at a grapheme cluster boundary, the * return value will also reflect an advance in the middle of the ligature. See * {@link #getOffsetForAdvance} for more discussion of grapheme cluster boundaries. * * The direction of the run is explicitly specified by {@code isRtl}. Thus, this method is * suitable only for runs of a single direction. * * <p>All indices are relative to the start of {@code text}. Further, {@code 0 <= contextStart * <= start <= offset <= end <= contextEnd <= text.length} must hold on entry. * * @param text the text to measure. Cannot be null. * @param start the index of the start of the range to measure * @param end the index + 1 of the end of the range to measure * @param contextStart the index of the start of the shaping context * @param contextEnd the index + 1 of the end of the range to measure * @param isRtl whether the run is in RTL direction * @param offset index of caret position * @return width measurement between start and offset */ public float getRunAdvance(char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } if ((contextStart | start | offset | end | contextEnd | start - contextStart | offset - start | end - offset | contextEnd - end | text.length - contextEnd) < 0) { throw new IndexOutOfBoundsException(); } if (end == start) { return 0.0f; } // TODO: take mCompatScaling into account (or eliminate compat scaling)? return native_getRunAdvance(mNativePaint, mNativeTypeface, text, start, end, contextStart, contextEnd, isRtl, offset); } /** * @see #getRunAdvance(char[], int, int, int, int, boolean, int) * * @param text the text to measure. Cannot be null. * @param start the index of the start of the range to measure * @param end the index + 1 of the end of the range to measure * @param contextStart the index of the start of the shaping context * @param contextEnd the index + 1 of the end of the range to measure * @param isRtl whether the run is in RTL direction * @param offset index of caret position * @return width measurement between start and offset */ public float getRunAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } if ((contextStart | start | offset | end | contextEnd | start - contextStart | offset - start | end - offset | contextEnd - end | text.length() - contextEnd) < 0) { throw new IndexOutOfBoundsException(); } if (end == start) { return 0.0f; } // TODO performance: specialized alternatives to avoid buffer copy, if win is significant char[] buf = TemporaryBuffer.obtain(contextEnd - contextStart); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); float result = getRunAdvance(buf, start - contextStart, end - contextStart, 0, contextEnd - contextStart, isRtl, offset - contextStart); TemporaryBuffer.recycle(buf); return result; } /** * Get the character offset within the string whose position is closest to the specified * horizontal position. * * <p>The returned value is generally the value of {@code offset} for which * {@link #getRunAdvance} yields a result most closely approximating {@code advance}, * and which is also on a grapheme cluster boundary. As such, it is the preferred method * for positioning a cursor in response to a touch or pointer event. The grapheme cluster * boundaries are based on * <a href="http://unicode.org/reports/tr29/">Unicode Standard Annex #29</a> but with some * tailoring for better user experience. * * <p>Note that {@code advance} is a (generally positive) width measurement relative to the start * of the run. Thus, for RTL runs it the distance from the point to the right edge. * * <p>All indices are relative to the start of {@code text}. Further, {@code 0 <= contextStart * <= start <= end <= contextEnd <= text.length} must hold on entry, and {@code start <= result * <= end} will hold on return. * * @param text the text to measure. Cannot be null. * @param start the index of the start of the range to measure * @param end the index + 1 of the end of the range to measure * @param contextStart the index of the start of the shaping context * @param contextEnd the index + 1 of the end of the range to measure * @param isRtl whether the run is in RTL direction * @param advance width relative to start of run * @return index of offset */ public int getOffsetForAdvance(char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } if ((contextStart | start | end | contextEnd | start - contextStart | end - start | contextEnd - end | text.length - contextEnd) < 0) { throw new IndexOutOfBoundsException(); } // TODO: take mCompatScaling into account (or eliminate compat scaling)? return native_getOffsetForAdvance(mNativePaint, mNativeTypeface, text, start, end, contextStart, contextEnd, isRtl, advance); } /** * @see #getOffsetForAdvance(char[], int, int, int, int, boolean, float) * * @param text the text to measure. Cannot be null. * @param start the index of the start of the range to measure * @param end the index + 1 of the end of the range to measure * @param contextStart the index of the start of the shaping context * @param contextEnd the index + 1 of the end of the range to measure * @param isRtl whether the run is in RTL direction * @param advance width relative to start of run * @return index of offset */ public int getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } if ((contextStart | start | end | contextEnd | start - contextStart | end - start | contextEnd - end | text.length() - contextEnd) < 0) { throw new IndexOutOfBoundsException(); } // TODO performance: specialized alternatives to avoid buffer copy, if win is significant char[] buf = TemporaryBuffer.obtain(contextEnd - contextStart); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); int result = getOffsetForAdvance(buf, start - contextStart, end - contextStart, 0, contextEnd - contextStart, isRtl, advance) + contextStart; TemporaryBuffer.recycle(buf); return result; } @Override protected void finalize() throws Throwable { try { Loading Loading @@ -2356,4 +2518,10 @@ public class Paint { private static native void native_setHyphenEdit(long native_object, int hyphen); private static native boolean native_hasGlyph(long native_object, long native_typeface, int bidiFlags, String string); private static native float native_getRunAdvance(long native_object, long native_typeface, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset); private static native int native_getOffsetForAdvance(long native_object, long native_typeface, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance); }