Add elegantTextHeight text appearance attribute

This patch adds an elegantTextHeight text appearance attribute and
plumbs it through to the paint. This attribute selects the elegant
variant of fonts (when appropriate, which is typically Arabic and indic
scripts), and also specifies larger vertical metrics, to avoid clipping.

The intent is for this to be the default for quantum themes, but this
patch doesn't change any default behavior, just adds the attribute.

The larger vertical metrics are applied to top and bottom, but should
not affect line spacing in the common case. Also, with the setting,
metrics are no longer dependent on the font, so setting a custom font
will preserve layout and spacing.

Change-Id: If3b7d41f141deff50ca078f479ca90c2aa07829a
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index f77a389..08a88d1 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -357,6 +357,24 @@
         obj->setPaintOptionsAndroid(paintOpts);
     }
 
+    static jboolean isElegantTextHeight(JNIEnv* env, jobject paint) {
+        NPE_CHECK_RETURN_ZERO(env, paint);
+        SkPaint* obj = GraphicsJNI::getNativePaint(env, paint);
+        SkPaintOptionsAndroid paintOpts = obj->getPaintOptionsAndroid();
+        return paintOpts.getFontVariant() == SkPaintOptionsAndroid::kElegant_Variant;
+    }
+
+    static void setElegantTextHeight(JNIEnv* env, jobject paint, jboolean aa) {
+        NPE_CHECK_RETURN_VOID(env, paint);
+        SkPaint* obj = GraphicsJNI::getNativePaint(env, paint);
+        SkPaintOptionsAndroid::FontVariant variant =
+            aa ? SkPaintOptionsAndroid::kElegant_Variant :
+            SkPaintOptionsAndroid::kDefault_Variant;
+        SkPaintOptionsAndroid paintOpts = obj->getPaintOptionsAndroid();
+        paintOpts.setFontVariant(variant);
+        obj->setPaintOptionsAndroid(paintOpts);
+    }
+
     static jfloat getTextSize(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSize());
@@ -401,10 +419,30 @@
         return SkScalarToFloat(metrics.fDescent);
     }
 
+    static SkScalar getMetricsInternal(SkPaint *paint, SkPaint::FontMetrics *metrics) {
+        const int kElegantTop = 2500;
+        const int kElegantBottom = -1000;
+        const int kElegantAscent = 1946;
+        const int kElegantDescent = -512;
+        const int kElegantLeading = 0;
+        SkScalar spacing = paint->getFontMetrics(metrics);
+        SkPaintOptionsAndroid paintOpts = paint->getPaintOptionsAndroid();
+        if (paintOpts.getFontVariant() == SkPaintOptionsAndroid::kElegant_Variant) {
+            SkScalar size = paint->getTextSize();
+            metrics->fTop = -size * kElegantTop / 2048;
+            metrics->fBottom = -size * kElegantBottom / 2048;
+            metrics->fAscent = -size * kElegantAscent / 2048;
+            metrics->fDescent = -size * kElegantDescent / 2048;
+            metrics->fLeading = size * kElegantLeading / 2048;
+            spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
+        }
+        return spacing;
+    }
+
     static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         SkPaint::FontMetrics metrics;
-        SkScalar             spacing = GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
+        SkScalar spacing = getMetricsInternal(GraphicsJNI::getNativePaint(env, paint), &metrics);
 
         if (metricsObj) {
             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
@@ -421,7 +459,7 @@
         NPE_CHECK_RETURN_ZERO(env, paint);
         SkPaint::FontMetrics metrics;
 
-        GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
+        getMetricsInternal(GraphicsJNI::getNativePaint(env, paint), &metrics);
         int ascent = SkScalarRoundToInt(metrics.fAscent);
         int descent = SkScalarRoundToInt(metrics.fDescent);
         int leading = SkScalarRoundToInt(metrics.fLeading);
@@ -894,6 +932,8 @@
     {"native_getTextAlign","(J)I", (void*) SkPaintGlue::getTextAlign},
     {"native_setTextAlign","(JI)V", (void*) SkPaintGlue::setTextAlign},
     {"native_setTextLocale","(JLjava/lang/String;)V", (void*) SkPaintGlue::setTextLocale},
+    {"isElegantTextHeight","()Z", (void*) SkPaintGlue::isElegantTextHeight},
+    {"setElegantTextHeight","(Z)V", (void*) SkPaintGlue::setElegantTextHeight},
     {"getTextSize","()F", (void*) SkPaintGlue::getTextSize},
     {"setTextSize","(F)V", (void*) SkPaintGlue::setTextSize},
     {"getTextScaleX","()F", (void*) SkPaintGlue::getTextScaleX},