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 "core_jni_helpers.h"
     25 #include <ScopedStringChars.h>
     26 #include <ScopedUtfChars.h>
     27 
     28 #include "SkBlurDrawLooper.h"
     29 #include "SkColorFilter.h"
     30 #include "SkMaskFilter.h"
     31 #include "SkPath.h"
     32 #include "SkPathEffect.h"
     33 #include "SkShader.h"
     34 #include "SkBlendMode.h"
     35 #include "unicode/uloc.h"
     36 #include "unicode/ushape.h"
     37 #include "utils/Blur.h"
     38 
     39 #include <hwui/MinikinSkia.h>
     40 #include <hwui/MinikinUtils.h>
     41 #include <hwui/Paint.h>
     42 #include <hwui/Typeface.h>
     43 #include <minikin/GraphemeBreak.h>
     44 #include <minikin/Measurement.h>
     45 #include <unicode/utf16.h>
     46 
     47 #include <cassert>
     48 #include <cstring>
     49 #include <memory>
     50 #include <vector>
     51 
     52 namespace android {
     53 
     54 struct JMetricsID {
     55     jfieldID    top;
     56     jfieldID    ascent;
     57     jfieldID    descent;
     58     jfieldID    bottom;
     59     jfieldID    leading;
     60 };
     61 
     62 static jclass   gFontMetrics_class;
     63 static JMetricsID gFontMetrics_fieldID;
     64 
     65 static jclass   gFontMetricsInt_class;
     66 static JMetricsID gFontMetricsInt_fieldID;
     67 
     68 static void defaultSettingsForAndroid(Paint* paint) {
     69     // GlyphID encoding is required because we are using Harfbuzz shaping
     70     paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
     71 }
     72 
     73 namespace PaintGlue {
     74     enum MoveOpt {
     75         AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
     76     };
     77 
     78     static void deletePaint(Paint* paint) {
     79         delete paint;
     80     }
     81 
     82     static jlong getNativeFinalizer(JNIEnv*, jobject) {
     83         return static_cast<jlong>(reinterpret_cast<uintptr_t>(&deletePaint));
     84     }
     85 
     86     static jlong init(JNIEnv* env, jobject) {
     87         static_assert(1 <<  0 == SkPaint::kAntiAlias_Flag,             "paint_flags_mismatch");
     88         static_assert(1 <<  2 == SkPaint::kDither_Flag,                "paint_flags_mismatch");
     89         static_assert(1 <<  3 == SkPaint::kUnderlineText_ReserveFlag,  "paint_flags_mismatch");
     90         static_assert(1 <<  4 == SkPaint::kStrikeThruText_ReserveFlag, "paint_flags_mismatch");
     91         static_assert(1 <<  5 == SkPaint::kFakeBoldText_Flag,          "paint_flags_mismatch");
     92         static_assert(1 <<  6 == SkPaint::kLinearText_Flag,            "paint_flags_mismatch");
     93         static_assert(1 <<  7 == SkPaint::kSubpixelText_Flag,          "paint_flags_mismatch");
     94         static_assert(1 <<  8 == SkPaint::kDevKernText_Flag,           "paint_flags_mismatch");
     95         static_assert(1 << 10 == SkPaint::kEmbeddedBitmapText_Flag,    "paint_flags_mismatch");
     96 
     97         Paint* obj = new Paint();
     98         defaultSettingsForAndroid(obj);
     99         return reinterpret_cast<jlong>(obj);
    100     }
    101 
    102     static jlong initWithPaint(JNIEnv* env, jobject clazz, jlong paintHandle) {
    103         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    104         Paint* obj = new Paint(*paint);
    105         return reinterpret_cast<jlong>(obj);
    106     }
    107 
    108     static int breakText(JNIEnv* env, const Paint& paint, Typeface* typeface, const jchar text[],
    109             int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
    110             const bool forwardScan) {
    111         size_t measuredCount = 0;
    112         float measured = 0;
    113 
    114         std::unique_ptr<float[]> advancesArray(new float[count]);
    115         MinikinUtils::measureText(&paint, bidiFlags, typeface, text, 0, count, count,
    116                 advancesArray.get());
    117 
    118         for (int i = 0; i < count; i++) {
    119             // traverse in the given direction
    120             int index = forwardScan ? i : (count - i - 1);
    121             float width = advancesArray[index];
    122             if (measured + width > maxWidth) {
    123                 break;
    124             }
    125             // properly handle clusters when scanning backwards
    126             if (forwardScan || width != 0.0f) {
    127                 measuredCount = i + 1;
    128             }
    129             measured += width;
    130         }
    131 
    132         if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
    133             AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
    134             jfloat* array = autoMeasured.ptr();
    135             array[0] = measured;
    136         }
    137         return measuredCount;
    138     }
    139 
    140     static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle,
    141             jcharArray jtext, jint index, jint count, jfloat maxWidth, jint bidiFlags,
    142             jfloatArray jmeasuredWidth) {
    143         NPE_CHECK_RETURN_ZERO(env, jtext);
    144 
    145         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    146         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    147 
    148         bool forwardTextDirection;
    149         if (count < 0) {
    150             forwardTextDirection = false;
    151             count = -count;
    152         }
    153         else {
    154             forwardTextDirection = true;
    155         }
    156 
    157         if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
    158             doThrowAIOOBE(env);
    159             return 0;
    160         }
    161 
    162         const jchar* text = env->GetCharArrayElements(jtext, nullptr);
    163         count = breakText(env, *paint, typeface, text + index, count, maxWidth,
    164                           bidiFlags, jmeasuredWidth, forwardTextDirection);
    165         env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
    166                                       JNI_ABORT);
    167         return count;
    168     }
    169 
    170     static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
    171                 jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
    172         NPE_CHECK_RETURN_ZERO(env, jtext);
    173 
    174         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    175         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    176 
    177         int count = env->GetStringLength(jtext);
    178         const jchar* text = env->GetStringChars(jtext, nullptr);
    179         count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
    180         env->ReleaseStringChars(jtext, text);
    181         return count;
    182     }
    183 
    184     static jfloat doTextAdvances(JNIEnv *env, Paint *paint, Typeface* typeface,
    185             const jchar *text, jint start, jint count, jint contextCount, jint bidiFlags,
    186             jfloatArray advances, jint advancesIndex) {
    187         NPE_CHECK_RETURN_ZERO(env, text);
    188 
    189         if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
    190             doThrowAIOOBE(env);
    191             return 0;
    192         }
    193         if (count == 0) {
    194             return 0;
    195         }
    196         if (advances) {
    197             size_t advancesLength = env->GetArrayLength(advances);
    198             if ((size_t)(count  + advancesIndex) > advancesLength) {
    199                 doThrowAIOOBE(env);
    200                 return 0;
    201             }
    202         }
    203         std::unique_ptr<jfloat[]> advancesArray;
    204         if (advances) {
    205             advancesArray.reset(new jfloat[count]);
    206         }
    207         const float advance = MinikinUtils::measureText(paint, bidiFlags, typeface, text,
    208                 start, count, contextCount, advancesArray.get());
    209         if (advances) {
    210             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get());
    211         }
    212         return advance;
    213     }
    214 
    215     static jfloat getTextAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
    216             jlong typefaceHandle,
    217             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
    218             jint bidiFlags, jfloatArray advances, jint advancesIndex) {
    219         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    220         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    221         jchar* textArray = env->GetCharArrayElements(text, nullptr);
    222         jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex,
    223                 index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex);
    224         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
    225         return result;
    226     }
    227 
    228     static jfloat getTextAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
    229             jlong typefaceHandle,
    230             jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint bidiFlags,
    231             jfloatArray advances, jint advancesIndex) {
    232         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    233         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    234         const jchar* textArray = env->GetStringChars(text, nullptr);
    235         jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart,
    236                 start - contextStart, end - start, contextEnd - contextStart, bidiFlags,
    237                 advances, advancesIndex);
    238         env->ReleaseStringChars(text, textArray);
    239         return result;
    240     }
    241 
    242     static jint doTextRunCursor(JNIEnv *env, Paint* paint, Typeface* typeface, const jchar *text,
    243             jint start, jint count, jint dir, jint offset, jint opt) {
    244         minikin::GraphemeBreak::MoveOpt moveOpt = minikin::GraphemeBreak::MoveOpt(opt);
    245         int bidiFlags = dir == 1 ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR;
    246         std::unique_ptr<float[]> advancesArray(new float[count]);
    247         MinikinUtils::measureText(paint, bidiFlags, typeface, text, start, count, start + count,
    248                 advancesArray.get());
    249         size_t result = minikin::GraphemeBreak::getTextRunCursor(advancesArray.get(), text,
    250                 start, count, offset, moveOpt);
    251         return static_cast<jint>(result);
    252     }
    253 
    254     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle,
    255             jlong typefaceHandle, jcharArray text, jint contextStart, jint contextCount, jint dir,
    256             jint offset, jint cursorOpt) {
    257         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    258         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    259         jchar* textArray = env->GetCharArrayElements(text, nullptr);
    260         jint result = doTextRunCursor(env, paint, typeface, textArray,
    261                 contextStart, contextCount, dir, offset, cursorOpt);
    262         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
    263         return result;
    264     }
    265 
    266     static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle,
    267             jlong typefaceHandle, jstring text, jint contextStart, jint contextEnd, jint dir,
    268             jint offset, jint cursorOpt) {
    269         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    270         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    271         const jchar* textArray = env->GetStringChars(text, nullptr);
    272         jint result = doTextRunCursor(env, paint, typeface, textArray,
    273                 contextStart, contextEnd - contextStart, dir, offset, cursorOpt);
    274         env->ReleaseStringChars(text, textArray);
    275         return result;
    276     }
    277 
    278     class GetTextFunctor {
    279     public:
    280         GetTextFunctor(const minikin::Layout& layout, SkPath* path, jfloat x, jfloat y,
    281                     Paint* paint, uint16_t* glyphs, SkPoint* pos)
    282                 : layout(layout), path(path), x(x), y(y), paint(paint), glyphs(glyphs), pos(pos) {
    283         }
    284 
    285         void operator()(size_t start, size_t end) {
    286             for (size_t i = start; i < end; i++) {
    287                 glyphs[i] = layout.getGlyphId(i);
    288                 pos[i].fX = x + layout.getX(i);
    289                 pos[i].fY = y + layout.getY(i);
    290             }
    291             if (start == 0) {
    292                 paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, path);
    293             } else {
    294                 paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, &tmpPath);
    295                 path->addPath(tmpPath);
    296             }
    297         }
    298     private:
    299         const minikin::Layout& layout;
    300         SkPath* path;
    301         jfloat x;
    302         jfloat y;
    303         Paint* paint;
    304         uint16_t* glyphs;
    305         SkPoint* pos;
    306         SkPath tmpPath;
    307     };
    308 
    309     static void getTextPath(JNIEnv* env, Paint* paint, Typeface* typeface, const jchar* text,
    310             jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
    311         minikin::Layout layout = MinikinUtils::doLayout(
    312                 paint, bidiFlags, typeface, text, 0, count, count);
    313         size_t nGlyphs = layout.nGlyphs();
    314         uint16_t* glyphs = new uint16_t[nGlyphs];
    315         SkPoint* pos = new SkPoint[nGlyphs];
    316 
    317         x += MinikinUtils::xOffsetForTextAlign(paint, layout);
    318         Paint::Align align = paint->getTextAlign();
    319         paint->setTextAlign(Paint::kLeft_Align);
    320         paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
    321         GetTextFunctor f(layout, path, x, y, paint, glyphs, pos);
    322         MinikinUtils::forFontRun(layout, paint, f);
    323         paint->setTextAlign(align);
    324         delete[] glyphs;
    325         delete[] pos;
    326     }
    327 
    328     static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle,
    329             jlong typefaceHandle, jint bidiFlags,
    330             jcharArray text, jint index, jint count, jfloat x, jfloat y, jlong pathHandle) {
    331         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    332         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    333         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    334         const jchar* textArray = env->GetCharArrayElements(text, nullptr);
    335         getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
    336         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
    337     }
    338 
    339     static void getTextPath__String(JNIEnv* env, jobject clazz, jlong paintHandle,
    340             jlong typefaceHandle, jint bidiFlags,
    341             jstring text, jint start, jint end, jfloat x, jfloat y, jlong pathHandle) {
    342         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    343         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    344         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    345         const jchar* textArray = env->GetStringChars(text, nullptr);
    346         getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
    347         env->ReleaseStringChars(text, textArray);
    348     }
    349 
    350     static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
    351             const Paint& paint, Typeface* typeface, jint bidiFlags) {
    352         SkRect  r;
    353         SkIRect ir;
    354 
    355         minikin::Layout layout = MinikinUtils::doLayout(
    356                 &paint, bidiFlags, typeface, text, 0, count, count);
    357         minikin::MinikinRect rect;
    358         layout.getBounds(&rect);
    359         r.fLeft = rect.mLeft;
    360         r.fTop = rect.mTop;
    361         r.fRight = rect.mRight;
    362         r.fBottom = rect.mBottom;
    363         r.roundOut(&ir);
    364         GraphicsJNI::irect_to_jrect(ir, env, bounds);
    365     }
    366 
    367     static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
    368                                 jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
    369         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    370         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    371         const jchar* textArray = env->GetStringChars(text, nullptr);
    372         doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
    373         env->ReleaseStringChars(text, textArray);
    374     }
    375 
    376     static void getCharArrayBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
    377                         jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) {
    378         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    379         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    380         const jchar* textArray = env->GetCharArrayElements(text, nullptr);
    381         doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags);
    382         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
    383                                       JNI_ABORT);
    384     }
    385 
    386     // Returns true if the given string is exact one pair of regional indicators.
    387     static bool isFlag(const jchar* str, size_t length) {
    388         const jchar RI_LEAD_SURROGATE = 0xD83C;
    389         const jchar RI_TRAIL_SURROGATE_MIN = 0xDDE6;
    390         const jchar RI_TRAIL_SURROGATE_MAX = 0xDDFF;
    391 
    392         if (length != 4) {
    393             return false;
    394         }
    395         if (str[0] != RI_LEAD_SURROGATE || str[2] != RI_LEAD_SURROGATE) {
    396             return false;
    397         }
    398         return RI_TRAIL_SURROGATE_MIN <= str[1] && str[1] <= RI_TRAIL_SURROGATE_MAX &&
    399             RI_TRAIL_SURROGATE_MIN <= str[3] && str[3] <= RI_TRAIL_SURROGATE_MAX;
    400     }
    401 
    402     static jboolean layoutContainsNotdef(const minikin::Layout& layout) {
    403         for (size_t i = 0; i < layout.nGlyphs(); i++) {
    404             if (layout.getGlyphId(i) == 0) {
    405                 return true;
    406             }
    407         }
    408         return false;
    409     }
    410 
    411     // Don't count glyphs that are the recommended "space" glyph and are zero width.
    412     // This logic makes assumptions about HarfBuzz layout, but does correctly handle
    413     // cases where ligatures form and zero width space glyphs are left in as
    414     // placeholders.
    415     static size_t countNonSpaceGlyphs(const minikin::Layout& layout) {
    416         size_t count = 0;
    417         static unsigned int kSpaceGlyphId = 3;
    418         for (size_t i = 0; i < layout.nGlyphs(); i++) {
    419             if (layout.getGlyphId(i) != kSpaceGlyphId || layout.getCharAdvance(i) != 0.0) {
    420                 count++;
    421             }
    422         }
    423         return count;
    424     }
    425 
    426     static jboolean hasGlyph(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle,
    427             jint bidiFlags, jstring string) {
    428         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    429         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    430         ScopedStringChars str(env, string);
    431 
    432         /* Start by rejecting unsupported base code point and variation selector pairs. */
    433         size_t nChars = 0;
    434         const uint32_t kStartOfString = 0xFFFFFFFF;
    435         uint32_t prevCp = kStartOfString;
    436         for (size_t i = 0; i < str.size(); i++) {
    437             jchar cu = str[i];
    438             uint32_t cp = cu;
    439             if (U16_IS_TRAIL(cu)) {
    440                 // invalid UTF-16, unpaired trailing surrogate
    441                 return false;
    442             } else if (U16_IS_LEAD(cu)) {
    443                 if (i + 1 == str.size()) {
    444                     // invalid UTF-16, unpaired leading surrogate at end of string
    445                     return false;
    446                 }
    447                 i++;
    448                 jchar cu2 = str[i];
    449                 if (!U16_IS_TRAIL(cu2)) {
    450                     // invalid UTF-16, unpaired leading surrogate
    451                     return false;
    452                 }
    453                 cp = U16_GET_SUPPLEMENTARY(cu, cu2);
    454             }
    455 
    456             if (prevCp != kStartOfString &&
    457                 ((0xFE00 <= cp && cp <= 0xFE0F) || (0xE0100 <= cp && cp <= 0xE01EF))) {
    458                 bool hasVS = MinikinUtils::hasVariationSelector(typeface, prevCp, cp);
    459                 if (!hasVS) {
    460                     // No font has a glyph for the code point and variation selector pair.
    461                     return false;
    462                 } else if (nChars == 1 && i + 1 == str.size()) {
    463                     // The string is just a codepoint and a VS, we have an authoritative answer
    464                     return true;
    465                 }
    466             }
    467             nChars++;
    468             prevCp = cp;
    469         }
    470         minikin::Layout layout = MinikinUtils::doLayout(
    471                 paint, bidiFlags, typeface, str.get(), 0, str.size(), str.size());
    472         size_t nGlyphs = countNonSpaceGlyphs(layout);
    473         if (nGlyphs != 1 && nChars > 1) {
    474             // multiple-character input, and was not a ligature
    475             // TODO: handle ZWJ/ZWNJ characters specially so we can detect certain ligatures
    476             // in joining scripts, such as Arabic and Mongolian.
    477             return false;
    478         }
    479 
    480         if (nGlyphs == 0 || layoutContainsNotdef(layout)) {
    481             return false;  // The collection doesn't have a glyph.
    482         }
    483 
    484         if (nChars == 2 && isFlag(str.get(), str.size())) {
    485             // Some font may have a special glyph for unsupported regional indicator pairs.
    486             // To return false for this case, need to compare the glyph id with the one of ZZ
    487             // since ZZ is reserved for unknown or invalid territory.
    488             // U+1F1FF (REGIONAL INDICATOR SYMBOL LETTER Z) is \uD83C\uDDFF in UTF16.
    489             static const jchar ZZ_FLAG_STR[] = { 0xD83C, 0xDDFF, 0xD83C, 0xDDFF };
    490             minikin::Layout zzLayout = MinikinUtils::doLayout(
    491                     paint, bidiFlags, typeface, ZZ_FLAG_STR, 0, 4, 4);
    492             if (zzLayout.nGlyphs() != 1 || layoutContainsNotdef(zzLayout)) {
    493                 // The font collection doesn't have a glyph for unknown flag. Just return true.
    494                 return true;
    495             }
    496             return zzLayout.getGlyphId(0) != layout.getGlyphId(0);
    497         }
    498         return true;
    499     }
    500 
    501     static jfloat doRunAdvance(const Paint* paint, Typeface* typeface, const jchar buf[],
    502             jint start, jint count, jint bufSize, jboolean isRtl, jint offset) {
    503         int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR;
    504         if (offset == start + count) {
    505             return MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count,
    506                     bufSize, nullptr);
    507         }
    508         std::unique_ptr<float[]> advancesArray(new float[count]);
    509         MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize,
    510                 advancesArray.get());
    511         return minikin::getRunAdvance(advancesArray.get(), buf, start, count, offset);
    512     }
    513 
    514     static jfloat getRunAdvance___CIIIIZI_F(JNIEnv *env, jclass, jlong paintHandle,
    515             jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart,
    516             jint contextEnd, jboolean isRtl, jint offset) {
    517         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    518         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    519         jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, nullptr);
    520         jfloat result = doRunAdvance(paint, typeface, textArray + contextStart,
    521                 start - contextStart, end - start, contextEnd - contextStart, isRtl,
    522                 offset - contextStart);
    523         env->ReleasePrimitiveArrayCritical(text, textArray, JNI_ABORT);
    524         return result;
    525     }
    526 
    527     static jint doOffsetForAdvance(const Paint* paint, Typeface* typeface, const jchar buf[],
    528             jint start, jint count, jint bufSize, jboolean isRtl, jfloat advance) {
    529         int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR;
    530         std::unique_ptr<float[]> advancesArray(new float[count]);
    531         MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize,
    532                 advancesArray.get());
    533         return minikin::getOffsetForAdvance(advancesArray.get(), buf, start, count, advance);
    534     }
    535 
    536     static jint getOffsetForAdvance___CIIIIZF_I(JNIEnv *env, jclass, jlong paintHandle,
    537             jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart,
    538             jint contextEnd, jboolean isRtl, jfloat advance) {
    539         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    540         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    541         jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, nullptr);
    542         jint result = doOffsetForAdvance(paint, typeface, textArray + contextStart,
    543                 start - contextStart, end - start, contextEnd - contextStart, isRtl, advance);
    544         result += contextStart;
    545         env->ReleasePrimitiveArrayCritical(text, textArray, JNI_ABORT);
    546         return result;
    547     }
    548 
    549     // ------------------ @FastNative ---------------------------
    550 
    551     static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
    552         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    553         ScopedUtfChars localesChars(env, locales);
    554         jint minikinLangListId = minikin::FontStyle::registerLanguageList(localesChars.c_str());
    555         obj->setMinikinLangListId(minikinLangListId);
    556         return minikinLangListId;
    557     }
    558 
    559     static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
    560         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    561         if (!settings) {
    562             paint->setFontFeatureSettings(std::string());
    563         } else {
    564             ScopedUtfChars settingsChars(env, settings);
    565             paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
    566         }
    567     }
    568 
    569     static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle,
    570             Paint::FontMetrics *metrics) {
    571         const int kElegantTop = 2500;
    572         const int kElegantBottom = -1000;
    573         const int kElegantAscent = 1900;
    574         const int kElegantDescent = -500;
    575         const int kElegantLeading = 0;
    576         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    577         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
    578         typeface = Typeface::resolveDefault(typeface);
    579         minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
    580         float saveSkewX = paint->getTextSkewX();
    581         bool savefakeBold = paint->isFakeBoldText();
    582         MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
    583         SkScalar spacing = paint->getFontMetrics(metrics);
    584         // The populateSkPaint call may have changed fake bold / text skew
    585         // because we want to measure with those effects applied, so now
    586         // restore the original settings.
    587         paint->setTextSkewX(saveSkewX);
    588         paint->setFakeBoldText(savefakeBold);
    589         if (paint->getFontVariant() == minikin::VARIANT_ELEGANT) {
    590             SkScalar size = paint->getTextSize();
    591             metrics->fTop = -size * kElegantTop / 2048;
    592             metrics->fBottom = -size * kElegantBottom / 2048;
    593             metrics->fAscent = -size * kElegantAscent / 2048;
    594             metrics->fDescent = -size * kElegantDescent / 2048;
    595             metrics->fLeading = size * kElegantLeading / 2048;
    596             spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
    597         }
    598         return spacing;
    599     }
    600 
    601     static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle,
    602             jlong typefaceHandle, jobject metricsObj) {
    603         Paint::FontMetrics metrics;
    604         SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics);
    605 
    606         if (metricsObj) {
    607             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
    608             env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
    609             env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
    610             env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
    611             env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
    612             env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
    613         }
    614         return SkScalarToFloat(spacing);
    615     }
    616 
    617     static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle,
    618             jlong typefaceHandle, jobject metricsObj) {
    619         Paint::FontMetrics metrics;
    620 
    621         getMetricsInternal(paintHandle, typefaceHandle, &metrics);
    622         int ascent = SkScalarRoundToInt(metrics.fAscent);
    623         int descent = SkScalarRoundToInt(metrics.fDescent);
    624         int leading = SkScalarRoundToInt(metrics.fLeading);
    625 
    626         if (metricsObj) {
    627             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
    628             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
    629             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
    630             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
    631             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
    632             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
    633         }
    634         return descent - ascent + leading;
    635     }
    636 
    637 
    638     // ------------------ @CriticalNative ---------------------------
    639 
    640     static void reset(jlong objHandle) {
    641         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    642         obj->reset();
    643         defaultSettingsForAndroid(obj);
    644     }
    645 
    646     static void assign(jlong dstPaintHandle, jlong srcPaintHandle) {
    647         Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
    648         const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
    649         *dst = *src;
    650     }
    651 
    652     // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
    653     static const uint32_t sFilterBitmapFlag = 0x02;
    654 
    655     static jint getFlags(jlong paintHandle) {
    656         Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
    657         uint32_t result = nativePaint->getFlags();
    658         result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
    659         if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
    660             result |= sFilterBitmapFlag;
    661         }
    662         return static_cast<jint>(result);
    663     }
    664 
    665     static void setFlags(jlong paintHandle, jint flags) {
    666         Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
    667         // Instead of modifying 0x02, change the filter level.
    668         nativePaint->setFilterQuality(flags & sFilterBitmapFlag
    669                 ? kLow_SkFilterQuality
    670                 : kNone_SkFilterQuality);
    671         // Don't pass through filter flag, which is no longer stored in paint's flags.
    672         flags &= ~sFilterBitmapFlag;
    673         // Use the existing value for 0x02.
    674         const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
    675         flags |= existing0x02Flag;
    676         nativePaint->setFlags(flags);
    677     }
    678 
    679     static jint getHinting(jlong paintHandle) {
    680         return reinterpret_cast<Paint*>(paintHandle)->getHinting()
    681                 == Paint::kNo_Hinting ? 0 : 1;
    682     }
    683 
    684     static void setHinting(jlong paintHandle, jint mode) {
    685         reinterpret_cast<Paint*>(paintHandle)->setHinting(
    686                 mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
    687     }
    688 
    689     static void setAntiAlias(jlong paintHandle, jboolean aa) {
    690         reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
    691     }
    692 
    693     static void setLinearText(jlong paintHandle, jboolean linearText) {
    694         reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
    695     }
    696 
    697     static void setSubpixelText(jlong paintHandle, jboolean subpixelText) {
    698         reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
    699     }
    700 
    701     static void setUnderlineText(jlong paintHandle, jboolean underlineText) {
    702         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    703         uint32_t flags = paint->getFlags();
    704         if (underlineText) {
    705             flags |= Paint::kUnderlineText_ReserveFlag;
    706         } else {
    707             flags &= ~Paint::kUnderlineText_ReserveFlag;
    708         }
    709         paint->setFlags(flags);
    710     }
    711 
    712     static void setStrikeThruText(jlong paintHandle, jboolean strikeThruText) {
    713         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    714         uint32_t flags = paint->getFlags();
    715         if (strikeThruText) {
    716             flags |= Paint::kStrikeThruText_ReserveFlag;
    717         } else {
    718             flags &= ~Paint::kStrikeThruText_ReserveFlag;
    719         }
    720         paint->setFlags(flags);
    721     }
    722 
    723     static void setFakeBoldText(jlong paintHandle, jboolean fakeBoldText) {
    724         reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
    725     }
    726 
    727     static void setFilterBitmap(jlong paintHandle, jboolean filterBitmap) {
    728         reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
    729                 filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
    730     }
    731 
    732     static void setDither(jlong paintHandle, jboolean dither) {
    733         reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
    734     }
    735 
    736     static jint getStyle(jlong objHandle) {
    737         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    738         return static_cast<jint>(obj->getStyle());
    739     }
    740 
    741     static void setStyle(jlong objHandle, jint styleHandle) {
    742         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    743         Paint::Style style = static_cast<Paint::Style>(styleHandle);
    744         obj->setStyle(style);
    745     }
    746 
    747     static jint getColor(jlong paintHandle) {
    748         int color;
    749         color = reinterpret_cast<Paint*>(paintHandle)->getColor();
    750         return static_cast<jint>(color);
    751     }
    752 
    753     static jint getAlpha(jlong paintHandle) {
    754         int alpha;
    755         alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
    756         return static_cast<jint>(alpha);
    757     }
    758 
    759     static void setColor(jlong paintHandle, jint color) {
    760         reinterpret_cast<Paint*>(paintHandle)->setColor(color);
    761     }
    762 
    763     static void setAlpha(jlong paintHandle, jint a) {
    764         reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
    765     }
    766 
    767     static jfloat getStrokeWidth(jlong paintHandle) {
    768         return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
    769     }
    770 
    771     static void setStrokeWidth(jlong paintHandle, jfloat width) {
    772         reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
    773     }
    774 
    775     static jfloat getStrokeMiter(jlong paintHandle) {
    776         return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
    777     }
    778 
    779     static void setStrokeMiter(jlong paintHandle, jfloat miter) {
    780         reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
    781     }
    782 
    783     static jint getStrokeCap(jlong objHandle) {
    784         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    785         return static_cast<jint>(obj->getStrokeCap());
    786     }
    787 
    788     static void setStrokeCap(jlong objHandle, jint capHandle) {
    789         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    790         Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
    791         obj->setStrokeCap(cap);
    792     }
    793 
    794     static jint getStrokeJoin(jlong objHandle) {
    795         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    796         return static_cast<jint>(obj->getStrokeJoin());
    797     }
    798 
    799     static void setStrokeJoin(jlong objHandle, jint joinHandle) {
    800         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    801         Paint::Join join = (Paint::Join) joinHandle;
    802         obj->setStrokeJoin(join);
    803     }
    804 
    805     static jboolean getFillPath(jlong objHandle, jlong srcHandle, jlong dstHandle) {
    806         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    807         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
    808         SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
    809         return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
    810     }
    811 
    812     static jlong setShader(jlong objHandle, jlong shaderHandle) {
    813         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    814         SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
    815         obj->setShader(sk_ref_sp(shader));
    816         return reinterpret_cast<jlong>(obj->getShader());
    817     }
    818 
    819     static jlong setColorFilter(jlong objHandle, jlong filterHandle) {
    820         Paint* obj = reinterpret_cast<Paint *>(objHandle);
    821         SkColorFilter* filter  = reinterpret_cast<SkColorFilter *>(filterHandle);
    822         obj->setColorFilter(sk_ref_sp(filter));
    823         return reinterpret_cast<jlong>(obj->getColorFilter());
    824     }
    825 
    826     static void setXfermode(jlong paintHandle, jint xfermodeHandle) {
    827         // validate that the Java enum values match our expectations
    828         static_assert(0 == static_cast<int>(SkBlendMode::kClear), "xfermode_mismatch");
    829         static_assert(1 == static_cast<int>(SkBlendMode::kSrc), "xfermode_mismatch");
    830         static_assert(2 == static_cast<int>(SkBlendMode::kDst), "xfermode_mismatch");
    831         static_assert(3 == static_cast<int>(SkBlendMode::kSrcOver), "xfermode_mismatch");
    832         static_assert(4 == static_cast<int>(SkBlendMode::kDstOver), "xfermode_mismatch");
    833         static_assert(5 == static_cast<int>(SkBlendMode::kSrcIn), "xfermode_mismatch");
    834         static_assert(6 == static_cast<int>(SkBlendMode::kDstIn), "xfermode_mismatch");
    835         static_assert(7 == static_cast<int>(SkBlendMode::kSrcOut), "xfermode_mismatch");
    836         static_assert(8 == static_cast<int>(SkBlendMode::kDstOut), "xfermode_mismatch");
    837         static_assert(9 == static_cast<int>(SkBlendMode::kSrcATop), "xfermode_mismatch");
    838         static_assert(10 == static_cast<int>(SkBlendMode::kDstATop), "xfermode_mismatch");
    839         static_assert(11 == static_cast<int>(SkBlendMode::kXor), "xfermode_mismatch");
    840         static_assert(16 == static_cast<int>(SkBlendMode::kDarken), "xfermode_mismatch");
    841         static_assert(17 == static_cast<int>(SkBlendMode::kLighten), "xfermode_mismatch");
    842         static_assert(13 == static_cast<int>(SkBlendMode::kModulate), "xfermode_mismatch");
    843         static_assert(14 == static_cast<int>(SkBlendMode::kScreen), "xfermode_mismatch");
    844         static_assert(12 == static_cast<int>(SkBlendMode::kPlus), "xfermode_mismatch");
    845         static_assert(15 == static_cast<int>(SkBlendMode::kOverlay), "xfermode_mismatch");
    846 
    847         SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
    848         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    849         paint->setBlendMode(mode);
    850     }
    851 
    852     static jlong setPathEffect(jlong objHandle, jlong effectHandle) {
    853         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    854         SkPathEffect* effect  = reinterpret_cast<SkPathEffect*>(effectHandle);
    855         obj->setPathEffect(sk_ref_sp(effect));
    856         return reinterpret_cast<jlong>(obj->getPathEffect());
    857     }
    858 
    859     static jlong setMaskFilter(jlong objHandle, jlong maskfilterHandle) {
    860         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    861         SkMaskFilter* maskfilter  = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
    862         obj->setMaskFilter(sk_ref_sp(maskfilter));
    863         return reinterpret_cast<jlong>(obj->getMaskFilter());
    864     }
    865 
    866     static jlong setTypeface(jlong objHandle, jlong typefaceHandle) {
    867         // TODO: in Paint refactoring, set typeface on android Paint, not Paint
    868         return 0;
    869     }
    870 
    871     static jint getTextAlign(jlong objHandle) {
    872         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    873         return static_cast<jint>(obj->getTextAlign());
    874     }
    875 
    876     static void setTextAlign(jlong objHandle, jint alignHandle) {
    877         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    878         Paint::Align align = static_cast<Paint::Align>(alignHandle);
    879         obj->setTextAlign(align);
    880     }
    881 
    882     static void setTextLocalesByMinikinLangListId(jlong objHandle,
    883             jint minikinLangListId) {
    884         Paint* obj = reinterpret_cast<Paint*>(objHandle);
    885         obj->setMinikinLangListId(minikinLangListId);
    886     }
    887 
    888     static jboolean isElegantTextHeight(jlong paintHandle) {
    889         Paint* obj = reinterpret_cast<Paint*>(paintHandle);
    890         return obj->getFontVariant() == minikin::VARIANT_ELEGANT;
    891     }
    892 
    893     static void setElegantTextHeight(jlong paintHandle, jboolean aa) {
    894         Paint* obj = reinterpret_cast<Paint*>(paintHandle);
    895         obj->setFontVariant(aa ? minikin::VARIANT_ELEGANT : minikin::VARIANT_DEFAULT);
    896     }
    897 
    898     static jfloat getTextSize(jlong paintHandle) {
    899         return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
    900     }
    901 
    902     static void setTextSize(jlong paintHandle, jfloat textSize) {
    903         reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
    904     }
    905 
    906     static jfloat getTextScaleX(jlong paintHandle) {
    907         return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
    908     }
    909 
    910     static void setTextScaleX(jlong paintHandle, jfloat scaleX) {
    911         reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
    912     }
    913 
    914     static jfloat getTextSkewX(jlong paintHandle) {
    915         return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
    916     }
    917 
    918     static void setTextSkewX(jlong paintHandle, jfloat skewX) {
    919         reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
    920     }
    921 
    922     static jfloat getLetterSpacing(jlong paintHandle) {
    923         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    924         return paint->getLetterSpacing();
    925     }
    926 
    927     static void setLetterSpacing(jlong paintHandle, jfloat letterSpacing) {
    928         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    929         paint->setLetterSpacing(letterSpacing);
    930     }
    931 
    932     static jfloat getWordSpacing(jlong paintHandle) {
    933         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    934         return paint->getWordSpacing();
    935     }
    936 
    937     static void setWordSpacing(jlong paintHandle, jfloat wordSpacing) {
    938         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    939         paint->setWordSpacing(wordSpacing);
    940     }
    941 
    942     static jint getHyphenEdit(jlong paintHandle, jint hyphen) {
    943         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    944         return paint->getHyphenEdit();
    945     }
    946 
    947     static void setHyphenEdit(jlong paintHandle, jint hyphen) {
    948         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    949         paint->setHyphenEdit((uint32_t)hyphen);
    950     }
    951 
    952     static jfloat ascent(jlong paintHandle, jlong typefaceHandle) {
    953         Paint::FontMetrics metrics;
    954         getMetricsInternal(paintHandle, typefaceHandle, &metrics);
    955         return SkScalarToFloat(metrics.fAscent);
    956     }
    957 
    958     static jfloat descent(jlong paintHandle, jlong typefaceHandle) {
    959         Paint::FontMetrics metrics;
    960         getMetricsInternal(paintHandle, typefaceHandle, &metrics);
    961         return SkScalarToFloat(metrics.fDescent);
    962     }
    963 
    964     static void setShadowLayer(jlong paintHandle, jfloat radius,
    965                                jfloat dx, jfloat dy, jint color) {
    966         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    967         if (radius <= 0) {
    968             paint->setLooper(nullptr);
    969         }
    970         else {
    971             SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
    972             paint->setLooper(SkBlurDrawLooper::Make((SkColor)color, sigma, dx, dy));
    973         }
    974     }
    975 
    976     static jboolean hasShadowLayer(jlong paintHandle) {
    977         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    978         return paint->getLooper() && paint->getLooper()->asABlurShadow(nullptr);
    979     }
    980 
    981 }; // namespace PaintGlue
    982 
    983 static const JNINativeMethod methods[] = {
    984     {"nGetNativeFinalizer", "()J", (void*) PaintGlue::getNativeFinalizer},
    985     {"nInit","()J", (void*) PaintGlue::init},
    986     {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
    987     {"nBreakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
    988     {"nBreakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
    989     {"nGetTextAdvances","(JJ[CIIIII[FI)F",
    990             (void*) PaintGlue::getTextAdvances___CIIIII_FI},
    991     {"nGetTextAdvances","(JJLjava/lang/String;IIIII[FI)F",
    992             (void*) PaintGlue::getTextAdvances__StringIIIII_FI},
    993 
    994     {"nGetTextRunCursor", "(JJ[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
    995     {"nGetTextRunCursor", "(JJLjava/lang/String;IIIII)I",
    996             (void*) PaintGlue::getTextRunCursor__String},
    997     {"nGetTextPath", "(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
    998     {"nGetTextPath", "(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
    999     {"nGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V",
   1000             (void*) PaintGlue::getStringBounds },
   1001     {"nGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
   1002             (void*) PaintGlue::getCharArrayBounds },
   1003     {"nHasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph },
   1004     {"nGetRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F},
   1005     {"nGetOffsetForAdvance", "(JJ[CIIIIZF)I",
   1006             (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
   1007 
   1008     // --------------- @FastNative ----------------------
   1009 
   1010     {"nSetTextLocales","(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales},
   1011     {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
   1012                 (void*) PaintGlue::setFontFeatureSettings},
   1013     {"nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F",
   1014                 (void*)PaintGlue::getFontMetrics},
   1015     {"nGetFontMetricsInt", "(JJLandroid/graphics/Paint$FontMetricsInt;)I",
   1016             (void*)PaintGlue::getFontMetricsInt},
   1017 
   1018     // --------------- @CriticalNative ------------------
   1019 
   1020     {"nReset","(J)V", (void*) PaintGlue::reset},
   1021     {"nSet","(JJ)V", (void*) PaintGlue::assign},
   1022     {"nGetFlags","(J)I", (void*) PaintGlue::getFlags},
   1023     {"nSetFlags","(JI)V", (void*) PaintGlue::setFlags},
   1024     {"nGetHinting","(J)I", (void*) PaintGlue::getHinting},
   1025     {"nSetHinting","(JI)V", (void*) PaintGlue::setHinting},
   1026     {"nSetAntiAlias","(JZ)V", (void*) PaintGlue::setAntiAlias},
   1027     {"nSetSubpixelText","(JZ)V", (void*) PaintGlue::setSubpixelText},
   1028     {"nSetLinearText","(JZ)V", (void*) PaintGlue::setLinearText},
   1029     {"nSetUnderlineText","(JZ)V", (void*) PaintGlue::setUnderlineText},
   1030     {"nSetStrikeThruText","(JZ)V", (void*) PaintGlue::setStrikeThruText},
   1031     {"nSetFakeBoldText","(JZ)V", (void*) PaintGlue::setFakeBoldText},
   1032     {"nSetFilterBitmap","(JZ)V", (void*) PaintGlue::setFilterBitmap},
   1033     {"nSetDither","(JZ)V", (void*) PaintGlue::setDither},
   1034     {"nGetStyle","(J)I", (void*) PaintGlue::getStyle},
   1035     {"nSetStyle","(JI)V", (void*) PaintGlue::setStyle},
   1036     {"nGetColor","(J)I", (void*) PaintGlue::getColor},
   1037     {"nSetColor","(JI)V", (void*) PaintGlue::setColor},
   1038     {"nGetAlpha","(J)I", (void*) PaintGlue::getAlpha},
   1039     {"nSetAlpha","(JI)V", (void*) PaintGlue::setAlpha},
   1040     {"nGetStrokeWidth","(J)F", (void*) PaintGlue::getStrokeWidth},
   1041     {"nSetStrokeWidth","(JF)V", (void*) PaintGlue::setStrokeWidth},
   1042     {"nGetStrokeMiter","(J)F", (void*) PaintGlue::getStrokeMiter},
   1043     {"nSetStrokeMiter","(JF)V", (void*) PaintGlue::setStrokeMiter},
   1044     {"nGetStrokeCap","(J)I", (void*) PaintGlue::getStrokeCap},
   1045     {"nSetStrokeCap","(JI)V", (void*) PaintGlue::setStrokeCap},
   1046     {"nGetStrokeJoin","(J)I", (void*) PaintGlue::getStrokeJoin},
   1047     {"nSetStrokeJoin","(JI)V", (void*) PaintGlue::setStrokeJoin},
   1048     {"nGetFillPath","(JJJ)Z", (void*) PaintGlue::getFillPath},
   1049     {"nSetShader","(JJ)J", (void*) PaintGlue::setShader},
   1050     {"nSetColorFilter","(JJ)J", (void*) PaintGlue::setColorFilter},
   1051     {"nSetXfermode","(JI)V", (void*) PaintGlue::setXfermode},
   1052     {"nSetPathEffect","(JJ)J", (void*) PaintGlue::setPathEffect},
   1053     {"nSetMaskFilter","(JJ)J", (void*) PaintGlue::setMaskFilter},
   1054     {"nSetTypeface","(JJ)J", (void*) PaintGlue::setTypeface},
   1055     {"nGetTextAlign","(J)I", (void*) PaintGlue::getTextAlign},
   1056     {"nSetTextAlign","(JI)V", (void*) PaintGlue::setTextAlign},
   1057     {"nSetTextLocalesByMinikinLangListId","(JI)V",
   1058             (void*) PaintGlue::setTextLocalesByMinikinLangListId},
   1059     {"nIsElegantTextHeight","(J)Z", (void*) PaintGlue::isElegantTextHeight},
   1060     {"nSetElegantTextHeight","(JZ)V", (void*) PaintGlue::setElegantTextHeight},
   1061     {"nGetTextSize","(J)F", (void*) PaintGlue::getTextSize},
   1062     {"nSetTextSize","(JF)V", (void*) PaintGlue::setTextSize},
   1063     {"nGetTextScaleX","(J)F", (void*) PaintGlue::getTextScaleX},
   1064     {"nSetTextScaleX","(JF)V", (void*) PaintGlue::setTextScaleX},
   1065     {"nGetTextSkewX","(J)F", (void*) PaintGlue::getTextSkewX},
   1066     {"nSetTextSkewX","(JF)V", (void*) PaintGlue::setTextSkewX},
   1067     {"nGetLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing},
   1068     {"nSetLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing},
   1069     {"nGetWordSpacing","(J)F", (void*) PaintGlue::getWordSpacing},
   1070     {"nSetWordSpacing","(JF)V", (void*) PaintGlue::setWordSpacing},
   1071     {"nGetHyphenEdit", "(J)I", (void*) PaintGlue::getHyphenEdit},
   1072     {"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit},
   1073     {"nAscent","(JJ)F", (void*) PaintGlue::ascent},
   1074     {"nDescent","(JJ)F", (void*) PaintGlue::descent},
   1075     {"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer},
   1076     {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer}
   1077 };
   1078 
   1079 int register_android_graphics_Paint(JNIEnv* env) {
   1080     gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
   1081     gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);
   1082 
   1083     gFontMetrics_fieldID.top = GetFieldIDOrDie(env, gFontMetrics_class, "top", "F");
   1084     gFontMetrics_fieldID.ascent = GetFieldIDOrDie(env, gFontMetrics_class, "ascent", "F");
   1085     gFontMetrics_fieldID.descent = GetFieldIDOrDie(env, gFontMetrics_class, "descent", "F");
   1086     gFontMetrics_fieldID.bottom = GetFieldIDOrDie(env, gFontMetrics_class, "bottom", "F");
   1087     gFontMetrics_fieldID.leading = GetFieldIDOrDie(env, gFontMetrics_class, "leading", "F");
   1088 
   1089     gFontMetricsInt_class = FindClassOrDie(env, "android/graphics/Paint$FontMetricsInt");
   1090     gFontMetricsInt_class = MakeGlobalRefOrDie(env, gFontMetricsInt_class);
   1091 
   1092     gFontMetricsInt_fieldID.top = GetFieldIDOrDie(env, gFontMetricsInt_class, "top", "I");
   1093     gFontMetricsInt_fieldID.ascent = GetFieldIDOrDie(env, gFontMetricsInt_class, "ascent", "I");
   1094     gFontMetricsInt_fieldID.descent = GetFieldIDOrDie(env, gFontMetricsInt_class, "descent", "I");
   1095     gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
   1096     gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");
   1097 
   1098     return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods));
   1099 }
   1100 
   1101 }
   1102