Home | History | Annotate | Download | only in graphics
      1 /* libs/android_runtime/android/graphics/Paint.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #define LOG_TAG "Paint"
     19 
     20 #include <utils/Log.h>
     21 
     22 #include "jni.h"
     23 #include "GraphicsJNI.h"
     24 #include <android_runtime/AndroidRuntime.h>
     25 #include <ScopedUtfChars.h>
     26 
     27 #include "SkBlurDrawLooper.h"
     28 #include "SkColorFilter.h"
     29 #include "SkMaskFilter.h"
     30 #include "SkRasterizer.h"
     31 #include "SkShader.h"
     32 #include "SkTypeface.h"
     33 #include "SkXfermode.h"
     34 #include "unicode/uloc.h"
     35 #include "unicode/ushape.h"
     36 #include "utils/Blur.h"
     37 
     38 #include <minikin/GraphemeBreak.h>
     39 #include "MinikinSkia.h"
     40 #include "MinikinUtils.h"
     41 #include "Paint.h"
     42 #include "TypefaceImpl.h"
     43 
     44 // temporary for debugging
     45 #include <Caches.h>
     46 #include <utils/Log.h>
     47 
     48 namespace android {
     49 
     50 struct JMetricsID {
     51     jfieldID    top;
     52     jfieldID    ascent;
     53     jfieldID    descent;
     54     jfieldID    bottom;
     55     jfieldID    leading;
     56 };
     57 
     58 static jclass   gFontMetrics_class;
     59 static JMetricsID gFontMetrics_fieldID;
     60 
     61 static jclass   gFontMetricsInt_class;
     62 static JMetricsID gFontMetricsInt_fieldID;
     63 
     64 static void defaultSettingsForAndroid(Paint* paint) {
     65     // GlyphID encoding is required because we are using Harfbuzz shaping
     66     paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
     67 }
     68 
     69 class PaintGlue {
     70 public:
     71     enum MoveOpt {
     72         AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
     73     };
     74 
     75     static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
     76         Paint* obj = reinterpret_cast<Paint*>(objHandle);
     77         delete obj;
     78     }
     79 
     80     static jlong init(JNIEnv* env, jobject clazz) {
     81         Paint* obj = new Paint();
     82         defaultSettingsForAndroid(obj);
     83         return reinterpret_cast<jlong>(obj);
     84     }
     85 
     86     static jlong initWithPaint(JNIEnv* env, jobject clazz, jlong paintHandle) {
     87         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
     88         Paint* obj = new Paint(*paint);
     89         return reinterpret_cast<jlong>(obj);
     90     }
     91 
     92     static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
     93         Paint* obj = reinterpret_cast<Paint*>(objHandle);
     94         obj->reset();
     95         defaultSettingsForAndroid(obj);
     96     }
     97 
     98     static void assign(JNIEnv* env, jobject clazz, jlong dstPaintHandle, jlong srcPaintHandle) {
     99         Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
    100         const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
    101         *dst = *src;
    102     }
    103 
    104     // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
    105     static const uint32_t sFilterBitmapFlag = 0x02;
    106 
    107     static jint getFlags(JNIEnv* env, jobject paint) {
    108         NPE_CHECK_RETURN_ZERO(env, paint);
    109         Paint* nativePaint = GraphicsJNI::getNativePaint(env, paint);
    110         uint32_t result = nativePaint->getFlags();
    111         result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
    112         if (nativePaint->getFilterLevel() != Paint::kNone_FilterLevel) {
    113             result |= sFilterBitmapFlag;
    114         }
    115         return static_cast<jint>(result);
    116     }
    117 
    118     static void setFlags(JNIEnv* env, jobject paint, jint flags) {
    119         NPE_CHECK_RETURN_VOID(env, paint);
    120         Paint* nativePaint = GraphicsJNI::getNativePaint(env, paint);
    121         // Instead of modifying 0x02, change the filter level.
    122         nativePaint->setFilterLevel(flags & sFilterBitmapFlag
    123                 ? Paint::kLow_FilterLevel
    124                 : Paint::kNone_FilterLevel);
    125         // Don't pass through filter flag, which is no longer stored in paint's flags.
    126         flags &= ~sFilterBitmapFlag;
    127         // Use the existing value for 0x02.
    128         const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
    129         flags |= existing0x02Flag;
    130         nativePaint->setFlags(flags);
    131     }
    132 
    133     static jint getHinting(JNIEnv* env, jobject paint) {
    134         NPE_CHECK_RETURN_ZERO(env, paint);
    135         return GraphicsJNI::getNativePaint(env, paint)->getHinting()
    136                 == Paint::kNo_Hinting ? 0 : 1;
    137     }
    138 
    139     static void setHinting(JNIEnv* env, jobject paint, jint mode) {
    140         NPE_CHECK_RETURN_VOID(env, paint);
    141         GraphicsJNI::getNativePaint(env, paint)->setHinting(
    142                 mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
    143     }
    144 
    145     static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) {
    146         NPE_CHECK_RETURN_VOID(env, paint);
    147         GraphicsJNI::getNativePaint(env, paint)->setAntiAlias(aa);
    148     }
    149 
    150     static void setLinearText(JNIEnv* env, jobject paint, jboolean linearText) {
    151         NPE_CHECK_RETURN_VOID(env, paint);
    152         GraphicsJNI::getNativePaint(env, paint)->setLinearText(linearText);
    153     }
    154 
    155     static void setSubpixelText(JNIEnv* env, jobject paint, jboolean subpixelText) {
    156         NPE_CHECK_RETURN_VOID(env, paint);
    157         GraphicsJNI::getNativePaint(env, paint)->setSubpixelText(subpixelText);
    158     }
    159 
    160     static void setUnderlineText(JNIEnv* env, jobject paint, jboolean underlineText) {
    161         NPE_CHECK_RETURN_VOID(env, paint);
    162         GraphicsJNI::getNativePaint(env, paint)->setUnderlineText(underlineText);
    163     }
    164 
    165     static void setStrikeThruText(JNIEnv* env, jobject paint, jboolean strikeThruText) {
    166         NPE_CHECK_RETURN_VOID(env, paint);
    167         GraphicsJNI::getNativePaint(env, paint)->setStrikeThruText(strikeThruText);
    168     }
    169 
    170     static void setFakeBoldText(JNIEnv* env, jobject paint, jboolean fakeBoldText) {
    171         NPE_CHECK_RETURN_VOID(env, paint);
    172         GraphicsJNI::getNativePaint(env, paint)->setFakeBoldText(fakeBoldText);
    173     }
    174 
    175     static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) {
    176         NPE_CHECK_RETURN_VOID(env, paint);
    177         GraphicsJNI::getNativePaint(env, paint)->setFilterLevel(
    178                 filterBitmap ? Paint::kLow_FilterLevel : Paint::kNone_FilterLevel);
    179     }
    180 
    181     static void setDither(JNIEnv* env, jobject paint, jboolean dither) {
    182         NPE_CHECK_RETURN_VOID(env, paint);
    183         GraphicsJNI::getNativePaint(env, paint)->setDither(dither);
    184     }
    185 
    186     static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) {
    187         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    188         return static_cast<jint>(obj->getStyle());
    189     }
    190 
    191     static void setStyle(JNIEnv* env, jobject clazz, jlong objHandle, jint styleHandle) {
    192         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    193         Paint::Style style = static_cast<Paint::Style>(styleHandle);
    194         obj->setStyle(style);
    195     }
    196 
    197     static jint getColor(JNIEnv* env, jobject paint) {
    198         NPE_CHECK_RETURN_ZERO(env, paint);
    199         int color;
    200         color = GraphicsJNI::getNativePaint(env, paint)->getColor();
    201         return static_cast<jint>(color);
    202     }
    203 
    204     static jint getAlpha(JNIEnv* env, jobject paint) {
    205         NPE_CHECK_RETURN_ZERO(env, paint);
    206         int alpha;
    207         alpha = GraphicsJNI::getNativePaint(env, paint)->getAlpha();
    208         return static_cast<jint>(alpha);
    209     }
    210 
    211     static void setColor(JNIEnv* env, jobject paint, jint color) {
    212         NPE_CHECK_RETURN_VOID(env, paint);
    213         GraphicsJNI::getNativePaint(env, paint)->setColor(color);
    214     }
    215 
    216     static void setAlpha(JNIEnv* env, jobject paint, jint a) {
    217         NPE_CHECK_RETURN_VOID(env, paint);
    218         GraphicsJNI::getNativePaint(env, paint)->setAlpha(a);
    219     }
    220 
    221     static jfloat getStrokeWidth(JNIEnv* env, jobject paint) {
    222         NPE_CHECK_RETURN_ZERO(env, paint);
    223         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeWidth());
    224     }
    225 
    226     static void setStrokeWidth(JNIEnv* env, jobject paint, jfloat width) {
    227         NPE_CHECK_RETURN_VOID(env, paint);
    228         GraphicsJNI::getNativePaint(env, paint)->setStrokeWidth(width);
    229     }
    230 
    231     static jfloat getStrokeMiter(JNIEnv* env, jobject paint) {
    232         NPE_CHECK_RETURN_ZERO(env, paint);
    233         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeMiter());
    234     }
    235 
    236     static void setStrokeMiter(JNIEnv* env, jobject paint, jfloat miter) {
    237         NPE_CHECK_RETURN_VOID(env, paint);
    238         GraphicsJNI::getNativePaint(env, paint)->setStrokeMiter(miter);
    239     }
    240 
    241     static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) {
    242         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    243         return static_cast<jint>(obj->getStrokeCap());
    244     }
    245 
    246     static void setStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle, jint capHandle) {
    247         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    248         Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
    249         obj->setStrokeCap(cap);
    250     }
    251 
    252     static jint getStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle) {
    253         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    254         return static_cast<jint>(obj->getStrokeJoin());
    255     }
    256 
    257     static void setStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle, jint joinHandle) {
    258         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    259         Paint::Join join = (Paint::Join) joinHandle;
    260         obj->setStrokeJoin(join);
    261     }
    262 
    263     static jboolean getFillPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong dstHandle) {
    264         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    265         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
    266         SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
    267         return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
    268     }
    269 
    270     static jlong setShader(JNIEnv* env, jobject clazz, jlong objHandle, jlong shaderHandle) {
    271         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    272         SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
    273         return reinterpret_cast<jlong>(obj->setShader(shader));
    274     }
    275 
    276     static jlong setColorFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong filterHandle) {
    277         Paint* obj = reinterpret_cast<Paint *>(objHandle);
    278         SkColorFilter* filter  = reinterpret_cast<SkColorFilter *>(filterHandle);
    279         return reinterpret_cast<jlong>(obj->setColorFilter(filter));
    280     }
    281 
    282     static jlong setXfermode(JNIEnv* env, jobject clazz, jlong objHandle, jlong xfermodeHandle) {
    283         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    284         SkXfermode* xfermode = reinterpret_cast<SkXfermode*>(xfermodeHandle);
    285         return reinterpret_cast<jlong>(obj->setXfermode(xfermode));
    286     }
    287 
    288     static jlong setPathEffect(JNIEnv* env, jobject clazz, jlong objHandle, jlong effectHandle) {
    289         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    290         SkPathEffect* effect  = reinterpret_cast<SkPathEffect*>(effectHandle);
    291         return reinterpret_cast<jlong>(obj->setPathEffect(effect));
    292     }
    293 
    294     static jlong setMaskFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong maskfilterHandle) {
    295         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    296         SkMaskFilter* maskfilter  = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
    297         return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter));
    298     }
    299 
    300     static jlong setTypeface(JNIEnv* env, jobject clazz, jlong objHandle, jlong typefaceHandle) {
    301         // TODO: in Paint refactoring, set typeface on android Paint, not Paint
    302         return NULL;
    303     }
    304 
    305     static jlong setRasterizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong rasterizerHandle) {
    306         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    307         SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
    308         return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer));
    309     }
    310 
    311     static jint getTextAlign(JNIEnv* env, jobject clazz, jlong objHandle) {
    312         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    313         return static_cast<jint>(obj->getTextAlign());
    314     }
    315 
    316     static void setTextAlign(JNIEnv* env, jobject clazz, jlong objHandle, jint alignHandle) {
    317         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    318         Paint::Align align = static_cast<Paint::Align>(alignHandle);
    319         obj->setTextAlign(align);
    320     }
    321 
    322     // generate bcp47 identifier for the supplied locale
    323     static void toLanguageTag(char* output, size_t outSize,
    324             const char* locale) {
    325         if (output == NULL || outSize <= 0) {
    326             return;
    327         }
    328         if (locale == NULL) {
    329             output[0] = '\0';
    330             return;
    331         }
    332         char canonicalChars[ULOC_FULLNAME_CAPACITY];
    333         UErrorCode uErr = U_ZERO_ERROR;
    334         uloc_canonicalize(locale, canonicalChars, ULOC_FULLNAME_CAPACITY,
    335                 &uErr);
    336         if (U_SUCCESS(uErr)) {
    337             char likelyChars[ULOC_FULLNAME_CAPACITY];
    338             uErr = U_ZERO_ERROR;
    339             uloc_addLikelySubtags(canonicalChars, likelyChars,
    340                     ULOC_FULLNAME_CAPACITY, &uErr);
    341             if (U_SUCCESS(uErr)) {
    342                 uErr = U_ZERO_ERROR;
    343                 uloc_toLanguageTag(likelyChars, output, outSize, FALSE, &uErr);
    344                 if (U_SUCCESS(uErr)) {
    345                     return;
    346                 } else {
    347                     ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars,
    348                             u_errorName(uErr));
    349                 }
    350             } else {
    351                 ALOGD("uloc_addLikelySubtags(\"%s\") failed: %s",
    352                         canonicalChars, u_errorName(uErr));
    353             }
    354         } else {
    355             ALOGD("uloc_canonicalize(\"%s\") failed: %s", locale,
    356                     u_errorName(uErr));
    357         }
    358         // unable to build a proper language identifier
    359         output[0] = '\0';
    360     }
    361 
    362     static void setTextLocale(JNIEnv* env, jobject clazz, jlong objHandle, jstring locale) {
    363         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    364         ScopedUtfChars localeChars(env, locale);
    365         char langTag[ULOC_FULLNAME_CAPACITY];
    366         toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, localeChars.c_str());
    367 
    368         obj->setTextLocale(langTag);
    369     }
    370 
    371     static jboolean isElegantTextHeight(JNIEnv* env, jobject paint) {
    372         NPE_CHECK_RETURN_ZERO(env, paint);
    373         Paint* obj = GraphicsJNI::getNativePaint(env, paint);
    374         return obj->getFontVariant() == VARIANT_ELEGANT;
    375     }
    376 
    377     static void setElegantTextHeight(JNIEnv* env, jobject paint, jboolean aa) {
    378         NPE_CHECK_RETURN_VOID(env, paint);
    379         Paint* obj = GraphicsJNI::getNativePaint(env, paint);
    380         obj->setFontVariant(aa ? VARIANT_ELEGANT : VARIANT_DEFAULT);
    381     }
    382 
    383     static jfloat getTextSize(JNIEnv* env, jobject paint) {
    384         NPE_CHECK_RETURN_ZERO(env, paint);
    385         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSize());
    386     }
    387 
    388     static void setTextSize(JNIEnv* env, jobject paint, jfloat textSize) {
    389         NPE_CHECK_RETURN_VOID(env, paint);
    390         GraphicsJNI::getNativePaint(env, paint)->setTextSize(textSize);
    391     }
    392 
    393     static jfloat getTextScaleX(JNIEnv* env, jobject paint) {
    394         NPE_CHECK_RETURN_ZERO(env, paint);
    395         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextScaleX());
    396     }
    397 
    398     static void setTextScaleX(JNIEnv* env, jobject paint, jfloat scaleX) {
    399         NPE_CHECK_RETURN_VOID(env, paint);
    400         GraphicsJNI::getNativePaint(env, paint)->setTextScaleX(scaleX);
    401     }
    402 
    403     static jfloat getTextSkewX(JNIEnv* env, jobject paint) {
    404         NPE_CHECK_RETURN_ZERO(env, paint);
    405         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSkewX());
    406     }
    407 
    408     static void setTextSkewX(JNIEnv* env, jobject paint, jfloat skewX) {
    409         NPE_CHECK_RETURN_VOID(env, paint);
    410         GraphicsJNI::getNativePaint(env, paint)->setTextSkewX(skewX);
    411     }
    412 
    413     static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) {
    414         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    415         return paint->getLetterSpacing();
    416     }
    417 
    418     static void setLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat letterSpacing) {
    419         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    420         paint->setLetterSpacing(letterSpacing);
    421     }
    422 
    423     static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
    424         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    425         if (!settings) {
    426             paint->setFontFeatureSettings(std::string());
    427         } else {
    428             ScopedUtfChars settingsChars(env, settings);
    429             paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
    430         }
    431     }
    432 
    433     static SkScalar getMetricsInternal(JNIEnv* env, jobject jpaint, Paint::FontMetrics *metrics) {
    434         const int kElegantTop = 2500;
    435         const int kElegantBottom = -1000;
    436         const int kElegantAscent = 1900;
    437         const int kElegantDescent = -500;
    438         const int kElegantLeading = 0;
    439         Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
    440         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
    441         typeface = TypefaceImpl_resolveDefault(typeface);
    442         FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
    443         float saveSkewX = paint->getTextSkewX();
    444         bool savefakeBold = paint->isFakeBoldText();
    445         MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
    446         SkScalar spacing = paint->getFontMetrics(metrics);
    447         // The populateSkPaint call may have changed fake bold / text skew
    448         // because we want to measure with those effects applied, so now
    449         // restore the original settings.
    450         paint->setTextSkewX(saveSkewX);
    451         paint->setFakeBoldText(savefakeBold);
    452         if (paint->getFontVariant() == VARIANT_ELEGANT) {
    453             SkScalar size = paint->getTextSize();
    454             metrics->fTop = -size * kElegantTop / 2048;
    455             metrics->fBottom = -size * kElegantBottom / 2048;
    456             metrics->fAscent = -size * kElegantAscent / 2048;
    457             metrics->fDescent = -size * kElegantDescent / 2048;
    458             metrics->fLeading = size * kElegantLeading / 2048;
    459             spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
    460         }
    461         return spacing;
    462     }
    463 
    464     static jfloat ascent(JNIEnv* env, jobject paint) {
    465         NPE_CHECK_RETURN_ZERO(env, paint);
    466         Paint::FontMetrics metrics;
    467         getMetricsInternal(env, paint, &metrics);
    468         return SkScalarToFloat(metrics.fAscent);
    469     }
    470 
    471     static jfloat descent(JNIEnv* env, jobject paint) {
    472         NPE_CHECK_RETURN_ZERO(env, paint);
    473         Paint::FontMetrics metrics;
    474         getMetricsInternal(env, paint, &metrics);
    475         return SkScalarToFloat(metrics.fDescent);
    476     }
    477 
    478     static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) {
    479         NPE_CHECK_RETURN_ZERO(env, paint);
    480         Paint::FontMetrics metrics;
    481         SkScalar spacing = getMetricsInternal(env, paint, &metrics);
    482 
    483         if (metricsObj) {
    484             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
    485             env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
    486             env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
    487             env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
    488             env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
    489             env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
    490         }
    491         return SkScalarToFloat(spacing);
    492     }
    493 
    494     static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) {
    495         NPE_CHECK_RETURN_ZERO(env, paint);
    496         Paint::FontMetrics metrics;
    497 
    498         getMetricsInternal(env, paint, &metrics);
    499         int ascent = SkScalarRoundToInt(metrics.fAscent);
    500         int descent = SkScalarRoundToInt(metrics.fDescent);
    501         int leading = SkScalarRoundToInt(metrics.fLeading);
    502 
    503         if (metricsObj) {
    504             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
    505             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
    506             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
    507             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
    508             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
    509             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
    510         }
    511         return descent - ascent + leading;
    512     }
    513 
    514     static jfloat measureText_CIII(JNIEnv* env, jobject jpaint, jcharArray text, jint index, jint count,
    515             jint bidiFlags) {
    516         NPE_CHECK_RETURN_ZERO(env, jpaint);
    517         NPE_CHECK_RETURN_ZERO(env, text);
    518 
    519         size_t textLength = env->GetArrayLength(text);
    520         if ((index | count) < 0 || (size_t)(index + count) > textLength) {
    521             doThrowAIOOBE(env);
    522             return 0;
    523         }
    524         if (count == 0) {
    525             return 0;
    526         }
    527 
    528         Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
    529         const jchar* textArray = env->GetCharArrayElements(text, NULL);
    530         jfloat result = 0;
    531 
    532         Layout layout;
    533         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
    534         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, index, count, textLength);
    535         result = layout.getAdvance();
    536         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
    537         return result;
    538     }
    539 
    540     static jfloat measureText_StringIII(JNIEnv* env, jobject jpaint, jstring text, jint start, jint end,
    541             jint bidiFlags) {
    542         NPE_CHECK_RETURN_ZERO(env, jpaint);
    543         NPE_CHECK_RETURN_ZERO(env, text);
    544 
    545         size_t textLength = env->GetStringLength(text);
    546         int count = end - start;
    547         if ((start | count) < 0 || (size_t)end > textLength) {
    548             doThrowAIOOBE(env);
    549             return 0;
    550         }
    551         if (count == 0) {
    552             return 0;
    553         }
    554 
    555         const jchar* textArray = env->GetStringChars(text, NULL);
    556         Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
    557         jfloat width = 0;
    558 
    559         Layout layout;
    560         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
    561         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, start, count, textLength);
    562         width = layout.getAdvance();
    563 
    564         env->ReleaseStringChars(text, textArray);
    565         return width;
    566     }
    567 
    568     static jfloat measureText_StringI(JNIEnv* env, jobject jpaint, jstring text, jint bidiFlags) {
    569         NPE_CHECK_RETURN_ZERO(env, jpaint);
    570         NPE_CHECK_RETURN_ZERO(env, text);
    571 
    572         size_t textLength = env->GetStringLength(text);
    573         if (textLength == 0) {
    574             return 0;
    575         }
    576 
    577         const jchar* textArray = env->GetStringChars(text, NULL);
    578         Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
    579         jfloat width = 0;
    580 
    581         Layout layout;
    582         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
    583         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, 0, textLength, textLength);
    584         width = layout.getAdvance();
    585 
    586         env->ReleaseStringChars(text, textArray);
    587         return width;
    588     }
    589 
    590     static int dotextwidths(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar text[], int count,
    591             jfloatArray widths, jint bidiFlags) {
    592         NPE_CHECK_RETURN_ZERO(env, paint);
    593         NPE_CHECK_RETURN_ZERO(env, text);
    594 
    595         if (count < 0 || !widths) {
    596             doThrowAIOOBE(env);
    597             return 0;
    598         }
    599         if (count == 0) {
    600             return 0;
    601         }
    602         size_t widthsLength = env->GetArrayLength(widths);
    603         if ((size_t)count > widthsLength) {
    604             doThrowAIOOBE(env);
    605             return 0;
    606         }
    607 
    608         AutoJavaFloatArray autoWidths(env, widths, count);
    609         jfloat* widthsArray = autoWidths.ptr();
    610 
    611         Layout layout;
    612         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
    613         layout.getAdvances(widthsArray);
    614 
    615         return count;
    616     }
    617 
    618     static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text,
    619             jint index, jint count, jint bidiFlags, jfloatArray widths) {
    620         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    621         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
    622         const jchar* textArray = env->GetCharArrayElements(text, NULL);
    623         count = dotextwidths(env, paint, typeface, textArray + index, count, widths, bidiFlags);
    624         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
    625                                       JNI_ABORT);
    626         return count;
    627     }
    628 
    629     static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring text,
    630             jint start, jint end, jint bidiFlags, jfloatArray widths) {
    631         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    632         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
    633         const jchar* textArray = env->GetStringChars(text, NULL);
    634         int count = dotextwidths(env, paint, typeface, textArray + start, end - start, widths, bidiFlags);
    635         env->ReleaseStringChars(text, textArray);
    636         return count;
    637     }
    638 
    639     static jfloat doTextRunAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface, const jchar *text,
    640                                     jint start, jint count, jint contextCount, jboolean isRtl,
    641                                     jfloatArray advances, jint advancesIndex) {
    642         NPE_CHECK_RETURN_ZERO(env, paint);
    643         NPE_CHECK_RETURN_ZERO(env, text);
    644 
    645         if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
    646             doThrowAIOOBE(env);
    647             return 0;
    648         }
    649         if (count == 0) {
    650             return 0;
    651         }
    652         if (advances) {
    653             size_t advancesLength = env->GetArrayLength(advances);
    654             if ((size_t)count > advancesLength) {
    655                 doThrowAIOOBE(env);
    656                 return 0;
    657             }
    658         }
    659         jfloat* advancesArray = new jfloat[count];
    660         jfloat totalAdvance = 0;
    661 
    662         int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
    663 
    664         Layout layout;
    665         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount);
    666         layout.getAdvances(advancesArray);
    667         totalAdvance = layout.getAdvance();
    668 
    669         if (advances != NULL) {
    670             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
    671         }
    672         delete [] advancesArray;
    673         return totalAdvance;
    674     }
    675 
    676     static jfloat getTextRunAdvances___CIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
    677             jlong typefaceHandle,
    678             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
    679             jboolean isRtl, jfloatArray advances, jint advancesIndex) {
    680         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    681         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
    682         jchar* textArray = env->GetCharArrayElements(text, NULL);
    683         jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex,
    684                 index - contextIndex, count, contextCount, isRtl, advances, advancesIndex);
    685         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
    686         return result;
    687     }
    688 
    689     static jfloat getTextRunAdvances__StringIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
    690             jlong typefaceHandle,
    691             jstring text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl,
    692             jfloatArray advances, jint advancesIndex) {
    693         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    694         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
    695         const jchar* textArray = env->GetStringChars(text, NULL);
    696         jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart,
    697                 start - contextStart, end - start, contextEnd - contextStart, isRtl,
    698                 advances, advancesIndex);
    699         env->ReleaseStringChars(text, textArray);
    700         return result;
    701     }
    702 
    703     static jint doTextRunCursor(JNIEnv *env, Paint* paint, const jchar *text, jint start,
    704             jint count, jint flags, jint offset, jint opt) {
    705         GraphemeBreak::MoveOpt moveOpt = GraphemeBreak::MoveOpt(opt);
    706         size_t result = GraphemeBreak::getTextRunCursor(text, start, count, offset, moveOpt);
    707         return static_cast<jint>(result);
    708     }
    709 
    710     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
    711             jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) {
    712         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    713         jchar* textArray = env->GetCharArrayElements(text, NULL);
    714         jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir,
    715                 offset, cursorOpt);
    716         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
    717         return result;
    718     }
    719 
    720     static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
    721             jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) {
    722         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    723         const jchar* textArray = env->GetStringChars(text, NULL);
    724         jint result = doTextRunCursor(env, paint, textArray, contextStart,
    725                 contextEnd - contextStart, dir, offset, cursorOpt);
    726         env->ReleaseStringChars(text, textArray);
    727         return result;
    728     }
    729 
    730     class GetTextFunctor {
    731     public:
    732         GetTextFunctor(const Layout& layout, SkPath* path, jfloat x, jfloat y, Paint* paint,
    733                     uint16_t* glyphs, SkPoint* pos)
    734                 : layout(layout), path(path), x(x), y(y), paint(paint), glyphs(glyphs), pos(pos) {
    735         }
    736 
    737         void operator()(size_t start, size_t end) {
    738             for (size_t i = start; i < end; i++) {
    739                 glyphs[i] = layout.getGlyphId(i);
    740                 pos[i].fX = x + layout.getX(i);
    741                 pos[i].fY = y + layout.getY(i);
    742             }
    743             if (start == 0) {
    744                 paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, path);
    745             } else {
    746                 paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, &tmpPath);
    747                 path->addPath(tmpPath);
    748             }
    749         }
    750     private:
    751         const Layout& layout;
    752         SkPath* path;
    753         jfloat x;
    754         jfloat y;
    755         Paint* paint;
    756         uint16_t* glyphs;
    757         SkPoint* pos;
    758         SkPath tmpPath;
    759     };
    760 
    761     static void getTextPath(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar* text,
    762             jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
    763         Layout layout;
    764         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
    765         size_t nGlyphs = layout.nGlyphs();
    766         uint16_t* glyphs = new uint16_t[nGlyphs];
    767         SkPoint* pos = new SkPoint[nGlyphs];
    768 
    769         x += MinikinUtils::xOffsetForTextAlign(paint, layout);
    770         Paint::Align align = paint->getTextAlign();
    771         paint->setTextAlign(Paint::kLeft_Align);
    772         paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
    773         GetTextFunctor f(layout, path, x, y, paint, glyphs, pos);
    774         MinikinUtils::forFontRun(layout, paint, f);
    775         paint->setTextAlign(align);
    776         delete[] glyphs;
    777         delete[] pos;
    778     }
    779 
    780     static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle,
    781             jlong typefaceHandle, jint bidiFlags,
    782             jcharArray text, jint index, jint count, jfloat x, jfloat y, jlong pathHandle) {
    783         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    784         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
    785         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    786         const jchar* textArray = env->GetCharArrayElements(text, NULL);
    787         getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
    788         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
    789     }
    790 
    791     static void getTextPath__String(JNIEnv* env, jobject clazz, jlong paintHandle,
    792             jlong typefaceHandle, jint bidiFlags,
    793             jstring text, jint start, jint end, jfloat x, jfloat y, jlong pathHandle) {
    794         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    795         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
    796         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    797         const jchar* textArray = env->GetStringChars(text, NULL);
    798         getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
    799         env->ReleaseStringChars(text, textArray);
    800     }
    801 
    802     static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
    803                                jfloat dx, jfloat dy, jint color) {
    804         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    805         if (radius <= 0) {
    806             paint->setLooper(NULL);
    807         }
    808         else {
    809             SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
    810             paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref();
    811         }
    812     }
    813 
    814     static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) {
    815         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    816         return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
    817     }
    818 
    819     static int breakText(JNIEnv* env, const Paint& paint, TypefaceImpl* typeface, const jchar text[],
    820                          int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
    821                          Paint::TextBufferDirection textBufferDirection) {
    822         size_t measuredCount = 0;
    823         float measured = 0;
    824 
    825         Layout layout;
    826         MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
    827         float* advances = new float[count];
    828         layout.getAdvances(advances);
    829         const bool forwardScan = (textBufferDirection == Paint::kForward_TextBufferDirection);
    830         for (int i = 0; i < count; i++) {
    831             // traverse in the given direction
    832             int index = forwardScan ? i : (count - i - 1);
    833             float width = advances[index];
    834             if (measured + width > maxWidth) {
    835                 break;
    836             }
    837             // properly handle clusters when scanning backwards
    838             if (forwardScan || width != 0.0f) {
    839                 measuredCount = i + 1;
    840             }
    841             measured += width;
    842         }
    843         delete[] advances;
    844 
    845         if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
    846             AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
    847             jfloat* array = autoMeasured.ptr();
    848             array[0] = measured;
    849         }
    850         return measuredCount;
    851     }
    852 
    853     static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext,
    854             jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
    855         NPE_CHECK_RETURN_ZERO(env, jtext);
    856 
    857         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    858         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
    859 
    860         Paint::TextBufferDirection tbd;
    861         if (count < 0) {
    862             tbd = Paint::kBackward_TextBufferDirection;
    863             count = -count;
    864         }
    865         else {
    866             tbd = Paint::kForward_TextBufferDirection;
    867         }
    868 
    869         if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
    870             doThrowAIOOBE(env);
    871             return 0;
    872         }
    873 
    874         const jchar* text = env->GetCharArrayElements(jtext, NULL);
    875         count = breakText(env, *paint, typeface, text + index, count, maxWidth,
    876                           bidiFlags, jmeasuredWidth, tbd);
    877         env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
    878                                       JNI_ABORT);
    879         return count;
    880     }
    881 
    882     static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
    883                 jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
    884         NPE_CHECK_RETURN_ZERO(env, jtext);
    885 
    886         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    887         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
    888 
    889         Paint::TextBufferDirection tbd = forwards ?
    890                                         Paint::kForward_TextBufferDirection :
    891                                         Paint::kBackward_TextBufferDirection;
    892 
    893         int count = env->GetStringLength(jtext);
    894         const jchar* text = env->GetStringChars(jtext, NULL);
    895         count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
    896         env->ReleaseStringChars(jtext, text);
    897         return count;
    898     }
    899 
    900     static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
    901             const Paint& paint, TypefaceImpl* typeface, jint bidiFlags) {
    902         SkRect  r;
    903         SkIRect ir;
    904 
    905         Layout layout;
    906         MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
    907         MinikinRect rect;
    908         layout.getBounds(&rect);
    909         r.fLeft = rect.mLeft;
    910         r.fTop = rect.mTop;
    911         r.fRight = rect.mRight;
    912         r.fBottom = rect.mBottom;
    913         r.roundOut(&ir);
    914         GraphicsJNI::irect_to_jrect(ir, env, bounds);
    915     }
    916 
    917     static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
    918                                 jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
    919         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);;
    920         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
    921         const jchar* textArray = env->GetStringChars(text, NULL);
    922         doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
    923         env->ReleaseStringChars(text, textArray);
    924     }
    925 
    926     static void getCharArrayBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
    927                         jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) {
    928         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    929         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
    930         const jchar* textArray = env->GetCharArrayElements(text, NULL);
    931         doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags);
    932         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
    933                                       JNI_ABORT);
    934     }
    935 
    936 };
    937 
    938 static JNINativeMethod methods[] = {
    939     {"finalizer", "(J)V", (void*) PaintGlue::finalizer},
    940     {"native_init","()J", (void*) PaintGlue::init},
    941     {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
    942 
    943     {"native_reset","!(J)V", (void*) PaintGlue::reset},
    944     {"native_set","!(JJ)V", (void*) PaintGlue::assign},
    945     {"getFlags","!()I", (void*) PaintGlue::getFlags},
    946     {"setFlags","!(I)V", (void*) PaintGlue::setFlags},
    947     {"getHinting","!()I", (void*) PaintGlue::getHinting},
    948     {"setHinting","!(I)V", (void*) PaintGlue::setHinting},
    949     {"setAntiAlias","!(Z)V", (void*) PaintGlue::setAntiAlias},
    950     {"setSubpixelText","!(Z)V", (void*) PaintGlue::setSubpixelText},
    951     {"setLinearText","!(Z)V", (void*) PaintGlue::setLinearText},
    952     {"setUnderlineText","!(Z)V", (void*) PaintGlue::setUnderlineText},
    953     {"setStrikeThruText","!(Z)V", (void*) PaintGlue::setStrikeThruText},
    954     {"setFakeBoldText","!(Z)V", (void*) PaintGlue::setFakeBoldText},
    955     {"setFilterBitmap","!(Z)V", (void*) PaintGlue::setFilterBitmap},
    956     {"setDither","!(Z)V", (void*) PaintGlue::setDither},
    957     {"native_getStyle","!(J)I", (void*) PaintGlue::getStyle},
    958     {"native_setStyle","!(JI)V", (void*) PaintGlue::setStyle},
    959     {"getColor","!()I", (void*) PaintGlue::getColor},
    960     {"setColor","!(I)V", (void*) PaintGlue::setColor},
    961     {"getAlpha","!()I", (void*) PaintGlue::getAlpha},
    962     {"setAlpha","!(I)V", (void*) PaintGlue::setAlpha},
    963     {"getStrokeWidth","!()F", (void*) PaintGlue::getStrokeWidth},
    964     {"setStrokeWidth","!(F)V", (void*) PaintGlue::setStrokeWidth},
    965     {"getStrokeMiter","!()F", (void*) PaintGlue::getStrokeMiter},
    966     {"setStrokeMiter","!(F)V", (void*) PaintGlue::setStrokeMiter},
    967     {"native_getStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
    968     {"native_setStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
    969     {"native_getStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
    970     {"native_setStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
    971     {"native_getFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
    972     {"native_setShader","!(JJ)J", (void*) PaintGlue::setShader},
    973     {"native_setColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
    974     {"native_setXfermode","!(JJ)J", (void*) PaintGlue::setXfermode},
    975     {"native_setPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
    976     {"native_setMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
    977     {"native_setTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
    978     {"native_setRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
    979     {"native_getTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
    980     {"native_setTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
    981     {"native_setTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale},
    982     {"isElegantTextHeight","!()Z", (void*) PaintGlue::isElegantTextHeight},
    983     {"setElegantTextHeight","!(Z)V", (void*) PaintGlue::setElegantTextHeight},
    984     {"getTextSize","!()F", (void*) PaintGlue::getTextSize},
    985     {"setTextSize","!(F)V", (void*) PaintGlue::setTextSize},
    986     {"getTextScaleX","!()F", (void*) PaintGlue::getTextScaleX},
    987     {"setTextScaleX","!(F)V", (void*) PaintGlue::setTextScaleX},
    988     {"getTextSkewX","!()F", (void*) PaintGlue::getTextSkewX},
    989     {"setTextSkewX","!(F)V", (void*) PaintGlue::setTextSkewX},
    990     {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
    991     {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
    992     {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings},
    993     {"ascent","!()F", (void*) PaintGlue::ascent},
    994     {"descent","!()F", (void*) PaintGlue::descent},
    995 
    996     {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics},
    997     {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt},
    998     {"native_measureText","([CIII)F", (void*) PaintGlue::measureText_CIII},
    999     {"native_measureText","(Ljava/lang/String;I)F", (void*) PaintGlue::measureText_StringI},
   1000     {"native_measureText","(Ljava/lang/String;III)F", (void*) PaintGlue::measureText_StringIII},
   1001     {"native_breakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
   1002     {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
   1003     {"native_getTextWidths","(JJ[CIII[F)I", (void*) PaintGlue::getTextWidths___CIII_F},
   1004     {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) PaintGlue::getTextWidths__StringIII_F},
   1005     {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F",
   1006         (void*) PaintGlue::getTextRunAdvances___CIIIIZ_FI},
   1007     {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F",
   1008         (void*) PaintGlue::getTextRunAdvances__StringIIIIZ_FI},
   1009 
   1010     {"native_getTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
   1011     {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I",
   1012         (void*) PaintGlue::getTextRunCursor__String},
   1013     {"native_getTextPath","(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
   1014     {"native_getTextPath","(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
   1015     {"nativeGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V",
   1016                                         (void*) PaintGlue::getStringBounds },
   1017     {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
   1018                                     (void*) PaintGlue::getCharArrayBounds },
   1019 
   1020     {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
   1021     {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
   1022 };
   1023 
   1024 static jfieldID req_fieldID(jfieldID id) {
   1025     SkASSERT(id);
   1026     return id;
   1027 }
   1028 
   1029 int register_android_graphics_Paint(JNIEnv* env) {
   1030     gFontMetrics_class = env->FindClass("android/graphics/Paint$FontMetrics");
   1031     SkASSERT(gFontMetrics_class);
   1032     gFontMetrics_class = (jclass)env->NewGlobalRef(gFontMetrics_class);
   1033 
   1034     gFontMetrics_fieldID.top = req_fieldID(env->GetFieldID(gFontMetrics_class, "top", "F"));
   1035     gFontMetrics_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetrics_class, "ascent", "F"));
   1036     gFontMetrics_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetrics_class, "descent", "F"));
   1037     gFontMetrics_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetrics_class, "bottom", "F"));
   1038     gFontMetrics_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetrics_class, "leading", "F"));
   1039 
   1040     gFontMetricsInt_class = env->FindClass("android/graphics/Paint$FontMetricsInt");
   1041     SkASSERT(gFontMetricsInt_class);
   1042     gFontMetricsInt_class = (jclass)env->NewGlobalRef(gFontMetricsInt_class);
   1043 
   1044     gFontMetricsInt_fieldID.top = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "top", "I"));
   1045     gFontMetricsInt_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "ascent", "I"));
   1046     gFontMetricsInt_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "descent", "I"));
   1047     gFontMetricsInt_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "bottom", "I"));
   1048     gFontMetricsInt_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "leading", "I"));
   1049 
   1050     int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Paint", methods,
   1051         sizeof(methods) / sizeof(methods[0]));
   1052     return result;
   1053 }
   1054 
   1055 }
   1056