Add new API useful for determining text height for empty text field
Bug: 303326708
Test: atest Paint_FontMetricsForLocaleTest
Change-Id: I4395c778a8de459ffdddba0c0d4dc2ba050e50ac
diff --git a/core/api/current.txt b/core/api/current.txt
index d037c31..d53e6d47 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -16086,10 +16086,12 @@
method public String getFontFeatureSettings();
method public float getFontMetrics(android.graphics.Paint.FontMetrics);
method public android.graphics.Paint.FontMetrics getFontMetrics();
+ method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") public void getFontMetricsForLocale(@NonNull android.graphics.Paint.FontMetrics);
method public void getFontMetricsInt(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, boolean, @NonNull android.graphics.Paint.FontMetricsInt);
method public void getFontMetricsInt(@NonNull char[], @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, boolean, @NonNull android.graphics.Paint.FontMetricsInt);
method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
+ method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") public void getFontMetricsIntForLocale(@NonNull android.graphics.Paint.FontMetricsInt);
method public float getFontSpacing();
method public String getFontVariationSettings();
method public int getHinting();
diff --git a/core/java/android/text/flags/fix_line_height_for_locale.aconfig b/core/java/android/text/flags/fix_line_height_for_locale.aconfig
new file mode 100644
index 0000000..8696bfa
--- /dev/null
+++ b/core/java/android/text/flags/fix_line_height_for_locale.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.text.flags"
+
+flag {
+ name: "fix_line_height_for_locale"
+ namespace: "text"
+ description: "Feature flag that preserve the line height of the TextView and EditText even if the the locale is different from Latin"
+ bug: "303326708"
+}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 9d32272..db1cc44 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -16,8 +16,11 @@
package android.graphics;
+import static com.android.text.flags.Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE;
+
import android.annotation.ColorInt;
import android.annotation.ColorLong;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -2125,7 +2128,7 @@
* @return the font's recommended interline spacing.
*/
public float getFontMetrics(FontMetrics metrics) {
- return nGetFontMetrics(mNativePaint, metrics);
+ return nGetFontMetrics(mNativePaint, metrics, false);
}
/**
@@ -2139,6 +2142,32 @@
}
/**
+ * Get the font metrics used for the locale
+ *
+ * Obtain the metrics of the font that is used for the specified locale by
+ * {@link #setTextLocales(LocaleList)}. If multiple locales are specified, the minimum ascent
+ * and maximum descent will be set.
+ *
+ * This API is useful for determining the default line height of the empty text field, e.g.
+ * {@link android.widget.EditText}.
+ *
+ * Note, if the {@link android.graphics.Typeface} is created from the custom font files, its
+ * metrics are reserved, i.e. the ascent will be the custom font's ascent or smaller, the
+ * descent will be the custom font's descent or larger.
+ *
+ * Note, if the {@link android.graphics.Typeface} is a system fallback, e.g.
+ * {@link android.graphics.Typeface#SERIF}, the default font's metrics are reserved, i.e. the
+ * ascent will be the serif font's ascent or smaller, the descent will be the serif font's
+ * descent or larger.
+ *
+ * @param metrics an output parameter. All members will be set by calling this function.
+ */
+ @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+ public void getFontMetricsForLocale(@NonNull FontMetrics metrics) {
+ nGetFontMetrics(mNativePaint, metrics, true);
+ }
+
+ /**
* Returns the font metrics value for the given text.
*
* If the text is rendered with multiple font files, this function returns the large ascent and
@@ -2318,7 +2347,7 @@
* @return the font's interline spacing.
*/
public int getFontMetricsInt(FontMetricsInt fmi) {
- return nGetFontMetricsInt(mNativePaint, fmi);
+ return nGetFontMetricsInt(mNativePaint, fmi, false);
}
public FontMetricsInt getFontMetricsInt() {
@@ -2328,6 +2357,32 @@
}
/**
+ * Get the font metrics used for the locale
+ *
+ * Obtain the metrics of the font that is used for the specified locale by
+ * {@link #setTextLocales(LocaleList)}. If multiple locales are specified, the minimum ascent
+ * and maximum descent will be set.
+ *
+ * This API is useful for determining the default line height of the empty text field, e.g.
+ * {@link android.widget.EditText}.
+ *
+ * Note, if the {@link android.graphics.Typeface} is created from the custom font files, its
+ * metrics are reserved, i.e. the ascent will be the custom font's ascent or smaller, the
+ * descent will be the custom font's descent or larger.
+ *
+ * Note, if the {@link android.graphics.Typeface} is a system fallback, e.g.
+ * {@link android.graphics.Typeface#SERIF}, the default font's metrics are reserved, i.e. the
+ * ascent will be the serif font's ascent or smaller, the descent will be the serif font's
+ * descent or larger.
+ *
+ * @param metrics an output parameter. All members will be set by calling this function.
+ */
+ @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+ public void getFontMetricsIntForLocale(@NonNull FontMetricsInt metrics) {
+ nGetFontMetricsInt(mNativePaint, metrics, true);
+ }
+
+ /**
* Return the recommend line spacing based on the current typeface and
* text size.
*
@@ -3446,9 +3501,11 @@
@FastNative
private static native void nSetFontFeatureSettings(long paintPtr, String settings);
@FastNative
- private static native float nGetFontMetrics(long paintPtr, FontMetrics metrics);
+ private static native float nGetFontMetrics(long paintPtr, FontMetrics metrics,
+ boolean useLocale);
@FastNative
- private static native int nGetFontMetricsInt(long paintPtr, FontMetricsInt fmi);
+ private static native int nGetFontMetricsInt(long paintPtr, FontMetricsInt fmi,
+ boolean useLocale);
// ---------------- @CriticalNative ------------------------
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index 7aef7a5..1463945 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -593,7 +593,7 @@
return result;
}
- static SkScalar getMetricsInternal(jlong paintHandle, SkFontMetrics *metrics) {
+ static SkScalar getMetricsInternal(jlong paintHandle, SkFontMetrics* metrics, bool useLocale) {
const int kElegantTop = 2500;
const int kElegantBottom = -1000;
const int kElegantAscent = 1900;
@@ -622,6 +622,17 @@
metrics->fLeading = size * kElegantLeading / 2048;
spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
}
+
+ if (useLocale) {
+ minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface);
+ minikin::MinikinExtent extent =
+ typeface->fFontCollection->getReferenceExtentForLocale(minikinPaint);
+ metrics->fAscent = std::min(extent.ascent, metrics->fAscent);
+ metrics->fDescent = std::max(extent.descent, metrics->fDescent);
+ metrics->fTop = std::min(metrics->fAscent, metrics->fTop);
+ metrics->fBottom = std::max(metrics->fDescent, metrics->fBottom);
+ }
+
return spacing;
}
@@ -634,7 +645,7 @@
MinikinUtils::getFontExtent(paint, bidiFlags, typeface, buf, start, count, bufSize);
SkFontMetrics metrics;
- getMetricsInternal(paintHandle, &metrics);
+ getMetricsInternal(paintHandle, &metrics, false /* useLocale */);
metrics.fAscent = extent.ascent;
metrics.fDescent = extent.descent;
@@ -686,20 +697,21 @@
}
}
- static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
+ static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj,
+ jboolean useLocale) {
SkFontMetrics metrics;
- SkScalar spacing = getMetricsInternal(paintHandle, &metrics);
+ SkScalar spacing = getMetricsInternal(paintHandle, &metrics, useLocale);
GraphicsJNI::set_metrics(env, metricsObj, metrics);
return SkScalarToFloat(spacing);
}
- static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
+ static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj,
+ jboolean useLocale) {
SkFontMetrics metrics;
- getMetricsInternal(paintHandle, &metrics);
+ getMetricsInternal(paintHandle, &metrics, useLocale);
return GraphicsJNI::set_metrics_int(env, metricsObj, metrics);
}
-
// ------------------ @CriticalNative ---------------------------
static void reset(CRITICAL_JNI_PARAMS_COMMA jlong objHandle) {
@@ -1002,19 +1014,19 @@
static jfloat ascent(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle) {
SkFontMetrics metrics;
- getMetricsInternal(paintHandle, &metrics);
+ getMetricsInternal(paintHandle, &metrics, false /* useLocale */);
return SkScalarToFloat(metrics.fAscent);
}
static jfloat descent(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle) {
SkFontMetrics metrics;
- getMetricsInternal(paintHandle, &metrics);
+ getMetricsInternal(paintHandle, &metrics, false /* useLocale */);
return SkScalarToFloat(metrics.fDescent);
}
static jfloat getUnderlinePosition(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle) {
SkFontMetrics metrics;
- getMetricsInternal(paintHandle, &metrics);
+ getMetricsInternal(paintHandle, &metrics, false /* useLocale */);
SkScalar position;
if (metrics.hasUnderlinePosition(&position)) {
return SkScalarToFloat(position);
@@ -1026,7 +1038,7 @@
static jfloat getUnderlineThickness(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle) {
SkFontMetrics metrics;
- getMetricsInternal(paintHandle, &metrics);
+ getMetricsInternal(paintHandle, &metrics, false /* useLocale */);
SkScalar thickness;
if (metrics.hasUnderlineThickness(&thickness)) {
return SkScalarToFloat(thickness);
@@ -1121,9 +1133,9 @@
{"nSetTextLocales", "(JLjava/lang/String;)I", (void*)PaintGlue::setTextLocales},
{"nSetFontFeatureSettings", "(JLjava/lang/String;)V",
(void*)PaintGlue::setFontFeatureSettings},
- {"nGetFontMetrics", "(JLandroid/graphics/Paint$FontMetrics;)F",
+ {"nGetFontMetrics", "(JLandroid/graphics/Paint$FontMetrics;Z)F",
(void*)PaintGlue::getFontMetrics},
- {"nGetFontMetricsInt", "(JLandroid/graphics/Paint$FontMetricsInt;)I",
+ {"nGetFontMetricsInt", "(JLandroid/graphics/Paint$FontMetricsInt;Z)I",
(void*)PaintGlue::getFontMetricsInt},
// --------------- @CriticalNative ------------------