Merge "Add Paint methods for cursor positioning"

This commit is contained in:
Raph Levien
2015-04-20 22:13:47 +00:00
committed by Android (Google) Code Review
4 changed files with 239 additions and 13 deletions

View File

@@ -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();

View File

@@ -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();

View File

@@ -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"
@@ -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"
@@ -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[] = {
@@ -1094,36 +1137,43 @@ 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},
(void*) PaintGlue::getTextRunAdvances___CIIIIZ_FI},
{"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F",
(void*) PaintGlue::getTextRunAdvances__StringIIIIZ_FI},
(void*) PaintGlue::getTextRunAdvances__StringIIIIZ_FI},
{"native_getTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
{"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I",
(void*) PaintGlue::getTextRunCursor__String},
{"native_getTextPath","(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
{"native_getTextPath","(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
(void*) PaintGlue::getTextRunCursor__String},
{"native_getTextPath", "(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
{"native_getTextPath", "(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
{"nativeGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V",
(void*) PaintGlue::getStringBounds },
(void*) PaintGlue::getStringBounds },
{"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
(void*) PaintGlue::getCharArrayBounds },
{"native_hasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph },
(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}

View File

@@ -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 {
@@ -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);
}