Paint conversion to @FastNative/@CriticalNative

Test: Refactor, device still boots

Change-Id: Ibf106607070860958c4317d6013d14ecf236f35a
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 315dd6b..4b1530a 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -105,392 +105,80 @@
         return reinterpret_cast<jlong>(obj);
     }
 
-    static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        obj->reset();
-        defaultSettingsForAndroid(obj);
-    }
+    static int breakText(JNIEnv* env, const Paint& paint, Typeface* typeface, const jchar text[],
+            int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
+            const bool forwardScan) {
+        size_t measuredCount = 0;
+        float measured = 0;
 
-    static void assign(JNIEnv* env, jobject clazz, jlong dstPaintHandle, jlong srcPaintHandle) {
-        Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
-        const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
-        *dst = *src;
-    }
+        std::unique_ptr<float[]> advancesArray(new float[count]);
+        MinikinUtils::measureText(&paint, bidiFlags, typeface, text, 0, count, count,
+                advancesArray.get());
 
-    // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
-    static const uint32_t sFilterBitmapFlag = 0x02;
-
-    static jint getFlags(JNIEnv* env, jobject, jlong paintHandle) {
-        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
-        uint32_t result = nativePaint->getFlags();
-        result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
-        if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
-            result |= sFilterBitmapFlag;
+        for (int i = 0; i < count; i++) {
+            // traverse in the given direction
+            int index = forwardScan ? i : (count - i - 1);
+            float width = advancesArray[index];
+            if (measured + width > maxWidth) {
+                break;
+            }
+            // properly handle clusters when scanning backwards
+            if (forwardScan || width != 0.0f) {
+                measuredCount = i + 1;
+            }
+            measured += width;
         }
-        return static_cast<jint>(result);
-    }
 
-    static void setFlags(JNIEnv* env, jobject, jlong paintHandle, jint flags) {
-        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
-        // Instead of modifying 0x02, change the filter level.
-        nativePaint->setFilterQuality(flags & sFilterBitmapFlag
-                ? kLow_SkFilterQuality
-                : kNone_SkFilterQuality);
-        // Don't pass through filter flag, which is no longer stored in paint's flags.
-        flags &= ~sFilterBitmapFlag;
-        // Use the existing value for 0x02.
-        const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
-        flags |= existing0x02Flag;
-        nativePaint->setFlags(flags);
-    }
-
-    static jint getHinting(JNIEnv* env, jobject, jlong paintHandle) {
-        return reinterpret_cast<Paint*>(paintHandle)->getHinting()
-                == Paint::kNo_Hinting ? 0 : 1;
-    }
-
-    static void setHinting(JNIEnv* env, jobject, jlong paintHandle, jint mode) {
-        reinterpret_cast<Paint*>(paintHandle)->setHinting(
-                mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
-    }
-
-    static void setAntiAlias(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
-        reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
-    }
-
-    static void setLinearText(JNIEnv* env, jobject, jlong paintHandle, jboolean linearText) {
-        reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
-    }
-
-    static void setSubpixelText(JNIEnv* env, jobject, jlong paintHandle, jboolean subpixelText) {
-        reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
-    }
-
-    static void setUnderlineText(JNIEnv* env, jobject, jlong paintHandle, jboolean underlineText) {
-        reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText);
-    }
-
-    static void setStrikeThruText(JNIEnv* env, jobject, jlong paintHandle, jboolean strikeThruText) {
-        reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText);
-    }
-
-    static void setFakeBoldText(JNIEnv* env, jobject, jlong paintHandle, jboolean fakeBoldText) {
-        reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
-    }
-
-    static void setFilterBitmap(JNIEnv* env, jobject, jlong paintHandle, jboolean filterBitmap) {
-        reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
-                filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
-    }
-
-    static void setDither(JNIEnv* env, jobject, jlong paintHandle, jboolean dither) {
-        reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
-    }
-
-    static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        return static_cast<jint>(obj->getStyle());
-    }
-
-    static void setStyle(JNIEnv* env, jobject clazz, jlong objHandle, jint styleHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        Paint::Style style = static_cast<Paint::Style>(styleHandle);
-        obj->setStyle(style);
-    }
-
-    static jint getColor(JNIEnv* env, jobject, jlong paintHandle) {
-        int color;
-        color = reinterpret_cast<Paint*>(paintHandle)->getColor();
-        return static_cast<jint>(color);
-    }
-
-    static jint getAlpha(JNIEnv* env, jobject, jlong paintHandle) {
-        int alpha;
-        alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
-        return static_cast<jint>(alpha);
-    }
-
-    static void setColor(JNIEnv* env, jobject, jlong paintHandle, jint color) {
-        reinterpret_cast<Paint*>(paintHandle)->setColor(color);
-    }
-
-    static void setAlpha(JNIEnv* env, jobject, jlong paintHandle, jint a) {
-        reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
-    }
-
-    static jfloat getStrokeWidth(JNIEnv* env, jobject, jlong paintHandle) {
-        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
-    }
-
-    static void setStrokeWidth(JNIEnv* env, jobject, jlong paintHandle, jfloat width) {
-        reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
-    }
-
-    static jfloat getStrokeMiter(JNIEnv* env, jobject, jlong paintHandle) {
-        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
-    }
-
-    static void setStrokeMiter(JNIEnv* env, jobject, jlong paintHandle, jfloat miter) {
-        reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
-    }
-
-    static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        return static_cast<jint>(obj->getStrokeCap());
-    }
-
-    static void setStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle, jint capHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
-        obj->setStrokeCap(cap);
-    }
-
-    static jint getStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        return static_cast<jint>(obj->getStrokeJoin());
-    }
-
-    static void setStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle, jint joinHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        Paint::Join join = (Paint::Join) joinHandle;
-        obj->setStrokeJoin(join);
-    }
-
-    static jboolean getFillPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong dstHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
-        SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
-        return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
-    }
-
-    static jlong setShader(JNIEnv* env, jobject clazz, jlong objHandle, jlong shaderHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
-        return reinterpret_cast<jlong>(obj->setShader(shader));
-    }
-
-    static jlong setColorFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong filterHandle) {
-        Paint* obj = reinterpret_cast<Paint *>(objHandle);
-        SkColorFilter* filter  = reinterpret_cast<SkColorFilter *>(filterHandle);
-        return reinterpret_cast<jlong>(obj->setColorFilter(filter));
-    }
-
-    static void setXfermode(JNIEnv* env, jobject clazz, jlong paintHandle, jint xfermodeHandle) {
-        // validate that the Java enum values match our expectations
-        static_assert(0 == SkXfermode::kClear_Mode, "xfermode_mismatch");
-        static_assert(1 == SkXfermode::kSrc_Mode, "xfermode_mismatch");
-        static_assert(2 == SkXfermode::kDst_Mode, "xfermode_mismatch");
-        static_assert(3 == SkXfermode::kSrcOver_Mode, "xfermode_mismatch");
-        static_assert(4 == SkXfermode::kDstOver_Mode, "xfermode_mismatch");
-        static_assert(5 == SkXfermode::kSrcIn_Mode, "xfermode_mismatch");
-        static_assert(6 == SkXfermode::kDstIn_Mode, "xfermode_mismatch");
-        static_assert(7 == SkXfermode::kSrcOut_Mode, "xfermode_mismatch");
-        static_assert(8 == SkXfermode::kDstOut_Mode, "xfermode_mismatch");
-        static_assert(9 == SkXfermode::kSrcATop_Mode, "xfermode_mismatch");
-        static_assert(10 == SkXfermode::kDstATop_Mode, "xfermode_mismatch");
-        static_assert(11 == SkXfermode::kXor_Mode, "xfermode_mismatch");
-        static_assert(16 == SkXfermode::kDarken_Mode, "xfermode_mismatch");
-        static_assert(17 == SkXfermode::kLighten_Mode, "xfermode_mismatch");
-        static_assert(13 == SkXfermode::kModulate_Mode, "xfermode_mismatch");
-        static_assert(14 == SkXfermode::kScreen_Mode, "xfermode_mismatch");
-        static_assert(12 == SkXfermode::kPlus_Mode, "xfermode_mismatch");
-        static_assert(15 == SkXfermode::kOverlay_Mode, "xfermode_mismatch");
-
-        SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        paint->setXfermodeMode(mode);
-    }
-
-    static jlong setPathEffect(JNIEnv* env, jobject clazz, jlong objHandle, jlong effectHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkPathEffect* effect  = reinterpret_cast<SkPathEffect*>(effectHandle);
-        return reinterpret_cast<jlong>(obj->setPathEffect(effect));
-    }
-
-    static jlong setMaskFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong maskfilterHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkMaskFilter* maskfilter  = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
-        return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter));
-    }
-
-    static jlong setTypeface(JNIEnv* env, jobject clazz, jlong objHandle, jlong typefaceHandle) {
-        // TODO: in Paint refactoring, set typeface on android Paint, not Paint
-        return NULL;
-    }
-
-    static jlong setRasterizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong rasterizerHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
-        return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer));
-    }
-
-    static jint getTextAlign(JNIEnv* env, jobject clazz, jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        return static_cast<jint>(obj->getTextAlign());
-    }
-
-    static void setTextAlign(JNIEnv* env, jobject clazz, jlong objHandle, jint alignHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        Paint::Align align = static_cast<Paint::Align>(alignHandle);
-        obj->setTextAlign(align);
-    }
-
-    static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        ScopedUtfChars localesChars(env, locales);
-        jint minikinLangListId = minikin::FontStyle::registerLanguageList(localesChars.c_str());
-        obj->setMinikinLangListId(minikinLangListId);
-        return minikinLangListId;
-    }
-
-    static void setTextLocalesByMinikinLangListId(JNIEnv* env, jobject clazz, jlong objHandle,
-            jint minikinLangListId) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        obj->setMinikinLangListId(minikinLangListId);
-    }
-
-    static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
-        return obj->getFontVariant() == minikin::VARIANT_ELEGANT;
-    }
-
-    static void setElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
-        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
-        obj->setFontVariant(aa ? minikin::VARIANT_ELEGANT : minikin::VARIANT_DEFAULT);
-    }
-
-    static jfloat getTextSize(JNIEnv* env, jobject, jlong paintHandle) {
-        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
-    }
-
-    static void setTextSize(JNIEnv* env, jobject, jlong paintHandle, jfloat textSize) {
-        reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
-    }
-
-    static jfloat getTextScaleX(JNIEnv* env, jobject, jlong paintHandle) {
-        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
-    }
-
-    static void setTextScaleX(JNIEnv* env, jobject, jlong paintHandle, jfloat scaleX) {
-        reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
-    }
-
-    static jfloat getTextSkewX(JNIEnv* env, jobject, jlong paintHandle) {
-        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
-    }
-
-    static void setTextSkewX(JNIEnv* env, jobject, jlong paintHandle, jfloat skewX) {
-        reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
-    }
-
-    static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        return paint->getLetterSpacing();
-    }
-
-    static void setLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat letterSpacing) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        paint->setLetterSpacing(letterSpacing);
-    }
-
-    static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        if (!settings) {
-            paint->setFontFeatureSettings(std::string());
-        } else {
-            ScopedUtfChars settingsChars(env, settings);
-            paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
+        if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
+            AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
+            jfloat* array = autoMeasured.ptr();
+            array[0] = measured;
         }
+        return measuredCount;
     }
 
-    static jint getHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        return paint->getHyphenEdit();
-    }
+    static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle,
+            jcharArray jtext, jint index, jint count, jfloat maxWidth, jint bidiFlags,
+            jfloatArray jmeasuredWidth) {
+        NPE_CHECK_RETURN_ZERO(env, jtext);
 
-    static void setHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        paint->setHyphenEdit((uint32_t)hyphen);
-    }
-
-    static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle,
-            Paint::FontMetrics *metrics) {
-        const int kElegantTop = 2500;
-        const int kElegantBottom = -1000;
-        const int kElegantAscent = 1900;
-        const int kElegantDescent = -500;
-        const int kElegantLeading = 0;
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        typeface = Typeface::resolveDefault(typeface);
-        minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
-        float saveSkewX = paint->getTextSkewX();
-        bool savefakeBold = paint->isFakeBoldText();
-        MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
-        SkScalar spacing = paint->getFontMetrics(metrics);
-        // The populateSkPaint call may have changed fake bold / text skew
-        // because we want to measure with those effects applied, so now
-        // restore the original settings.
-        paint->setTextSkewX(saveSkewX);
-        paint->setFakeBoldText(savefakeBold);
-        if (paint->getFontVariant() == minikin::VARIANT_ELEGANT) {
-            SkScalar size = paint->getTextSize();
-            metrics->fTop = -size * kElegantTop / 2048;
-            metrics->fBottom = -size * kElegantBottom / 2048;
-            metrics->fAscent = -size * kElegantAscent / 2048;
-            metrics->fDescent = -size * kElegantDescent / 2048;
-            metrics->fLeading = size * kElegantLeading / 2048;
-            spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
+
+        bool forwardTextDirection;
+        if (count < 0) {
+            forwardTextDirection = false;
+            count = -count;
         }
-        return spacing;
-    }
-
-    static jfloat ascent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
-        Paint::FontMetrics metrics;
-        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
-        return SkScalarToFloat(metrics.fAscent);
-    }
-
-    static jfloat descent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
-        Paint::FontMetrics metrics;
-        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
-        return SkScalarToFloat(metrics.fDescent);
-    }
-
-    static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle,
-            jlong typefaceHandle, jobject metricsObj) {
-        Paint::FontMetrics metrics;
-        SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics);
-
-        if (metricsObj) {
-            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
+        else {
+            forwardTextDirection = true;
         }
-        return SkScalarToFloat(spacing);
+
+        if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
+            doThrowAIOOBE(env);
+            return 0;
+        }
+
+        const jchar* text = env->GetCharArrayElements(jtext, nullptr);
+        count = breakText(env, *paint, typeface, text + index, count, maxWidth,
+                          bidiFlags, jmeasuredWidth, forwardTextDirection);
+        env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
+                                      JNI_ABORT);
+        return count;
     }
 
-    static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle,
-            jlong typefaceHandle, jobject metricsObj) {
-        Paint::FontMetrics metrics;
+    static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
+                jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
+        NPE_CHECK_RETURN_ZERO(env, jtext);
 
-        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
-        int ascent = SkScalarRoundToInt(metrics.fAscent);
-        int descent = SkScalarRoundToInt(metrics.fDescent);
-        int leading = SkScalarRoundToInt(metrics.fLeading);
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
 
-        if (metricsObj) {
-            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
-        }
-        return descent - ascent + leading;
+        int count = env->GetStringLength(jtext);
+        const jchar* text = env->GetStringChars(jtext, nullptr);
+        count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
+        env->ReleaseStringChars(jtext, text);
+        return count;
     }
 
     static jfloat doTextAdvances(JNIEnv *env, Paint *paint, Typeface* typeface,
@@ -530,7 +218,7 @@
             jint bidiFlags, jfloatArray advances, jint advancesIndex) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        jchar* textArray = env->GetCharArrayElements(text, NULL);
+        jchar* textArray = env->GetCharArrayElements(text, nullptr);
         jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex,
                 index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
@@ -543,7 +231,7 @@
             jfloatArray advances, jint advancesIndex) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        const jchar* textArray = env->GetStringChars(text, NULL);
+        const jchar* textArray = env->GetStringChars(text, nullptr);
         jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart,
                 start - contextStart, end - start, contextEnd - contextStart, bidiFlags,
                 advances, advancesIndex);
@@ -562,7 +250,7 @@
     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
             jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        jchar* textArray = env->GetCharArrayElements(text, NULL);
+        jchar* textArray = env->GetCharArrayElements(text, nullptr);
         jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir,
                 offset, cursorOpt);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
@@ -572,7 +260,7 @@
     static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
             jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        const jchar* textArray = env->GetStringChars(text, NULL);
+        const jchar* textArray = env->GetStringChars(text, nullptr);
         jint result = doTextRunCursor(env, paint, textArray, contextStart,
                 contextEnd - contextStart, dir, offset, cursorOpt);
         env->ReleaseStringChars(text, textArray);
@@ -635,7 +323,7 @@
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
-        const jchar* textArray = env->GetCharArrayElements(text, NULL);
+        const jchar* textArray = env->GetCharArrayElements(text, nullptr);
         getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
     }
@@ -646,103 +334,11 @@
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
-        const jchar* textArray = env->GetStringChars(text, NULL);
+        const jchar* textArray = env->GetStringChars(text, nullptr);
         getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
         env->ReleaseStringChars(text, textArray);
     }
 
-    static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
-                               jfloat dx, jfloat dy, jint color) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        if (radius <= 0) {
-            paint->setLooper(NULL);
-        }
-        else {
-            SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
-            paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref();
-        }
-    }
-
-    static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
-    }
-
-    static int breakText(JNIEnv* env, const Paint& paint, Typeface* typeface, const jchar text[],
-                         int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
-                         const bool forwardScan) {
-        size_t measuredCount = 0;
-        float measured = 0;
-
-        std::unique_ptr<float[]> advancesArray(new float[count]);
-        MinikinUtils::measureText(&paint, bidiFlags, typeface, text, 0, count, count,
-                advancesArray.get());
-
-        for (int i = 0; i < count; i++) {
-            // traverse in the given direction
-            int index = forwardScan ? i : (count - i - 1);
-            float width = advancesArray[index];
-            if (measured + width > maxWidth) {
-                break;
-            }
-            // properly handle clusters when scanning backwards
-            if (forwardScan || width != 0.0f) {
-                measuredCount = i + 1;
-            }
-            measured += width;
-        }
-
-        if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
-            AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
-            jfloat* array = autoMeasured.ptr();
-            array[0] = measured;
-        }
-        return measuredCount;
-    }
-
-    static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext,
-            jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
-        NPE_CHECK_RETURN_ZERO(env, jtext);
-
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-
-        bool forwardTextDirection;
-        if (count < 0) {
-            forwardTextDirection = false;
-            count = -count;
-        }
-        else {
-            forwardTextDirection = true;
-        }
-
-        if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-
-        const jchar* text = env->GetCharArrayElements(jtext, NULL);
-        count = breakText(env, *paint, typeface, text + index, count, maxWidth,
-                          bidiFlags, jmeasuredWidth, forwardTextDirection);
-        env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
-                                      JNI_ABORT);
-        return count;
-    }
-
-    static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
-                jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
-        NPE_CHECK_RETURN_ZERO(env, jtext);
-
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-
-        int count = env->GetStringLength(jtext);
-        const jchar* text = env->GetStringChars(jtext, NULL);
-        count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
-        env->ReleaseStringChars(jtext, text);
-        return count;
-    }
-
     static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
             const Paint& paint, Typeface* typeface, jint bidiFlags) {
         SkRect  r;
@@ -764,7 +360,7 @@
                                 jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        const jchar* textArray = env->GetStringChars(text, NULL);
+        const jchar* textArray = env->GetStringChars(text, nullptr);
         doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
         env->ReleaseStringChars(text, textArray);
     }
@@ -773,12 +369,28 @@
                         jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        const jchar* textArray = env->GetCharArrayElements(text, NULL);
+        const jchar* textArray = env->GetCharArrayElements(text, nullptr);
         doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
                                       JNI_ABORT);
     }
 
+    // Returns true if the given string is exact one pair of regional indicators.
+    static bool isFlag(const jchar* str, size_t length) {
+        const jchar RI_LEAD_SURROGATE = 0xD83C;
+        const jchar RI_TRAIL_SURROGATE_MIN = 0xDDE6;
+        const jchar RI_TRAIL_SURROGATE_MAX = 0xDDFF;
+
+        if (length != 4) {
+            return false;
+        }
+        if (str[0] != RI_LEAD_SURROGATE || str[2] != RI_LEAD_SURROGATE) {
+            return false;
+        }
+        return RI_TRAIL_SURROGATE_MIN <= str[1] && str[1] <= RI_TRAIL_SURROGATE_MAX &&
+            RI_TRAIL_SURROGATE_MIN <= str[3] && str[3] <= RI_TRAIL_SURROGATE_MAX;
+    }
+
     static jboolean layoutContainsNotdef(const minikin::Layout& layout) {
         for (size_t i = 0; i < layout.nGlyphs(); i++) {
             if (layout.getGlyphId(i) == 0) {
@@ -803,22 +415,6 @@
         return count;
     }
 
-    // Returns true if the given string is exact one pair of regional indicators.
-    static bool isFlag(const jchar* str, size_t length) {
-        const jchar RI_LEAD_SURROGATE = 0xD83C;
-        const jchar RI_TRAIL_SURROGATE_MIN = 0xDDE6;
-        const jchar RI_TRAIL_SURROGATE_MAX = 0xDDFF;
-
-        if (length != 4) {
-            return false;
-        }
-        if (str[0] != RI_LEAD_SURROGATE || str[2] != RI_LEAD_SURROGATE) {
-            return false;
-        }
-        return RI_TRAIL_SURROGATE_MIN <= str[1] && str[1] <= RI_TRAIL_SURROGATE_MAX &&
-            RI_TRAIL_SURROGATE_MIN <= str[3] && str[3] <= RI_TRAIL_SURROGATE_MAX;
-    }
-
     static jboolean hasGlyph(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle,
             jint bidiFlags, jstring string) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
@@ -913,7 +509,7 @@
             jint contextEnd, jboolean isRtl, jint offset) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL);
+        jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, nullptr);
         jfloat result = doRunAdvance(paint, typeface, textArray + contextStart,
                 start - contextStart, end - start, contextEnd - contextStart, isRtl,
                 offset - contextStart);
@@ -935,7 +531,7 @@
             jint contextEnd, jboolean isRtl, jfloat advance) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL);
+        jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, nullptr);
         jint result = doOffsetForAdvance(paint, typeface, textArray + contextStart,
                 start - contextStart, end - start, contextEnd - contextStart, isRtl, advance);
         result += contextStart;
@@ -943,76 +539,422 @@
         return result;
     }
 
+    // ------------------ @FastNative ---------------------------
+
+    static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        ScopedUtfChars localesChars(env, locales);
+        jint minikinLangListId = minikin::FontStyle::registerLanguageList(localesChars.c_str());
+        obj->setMinikinLangListId(minikinLangListId);
+        return minikinLangListId;
+    }
+
+    static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        if (!settings) {
+            paint->setFontFeatureSettings(std::string());
+        } else {
+            ScopedUtfChars settingsChars(env, settings);
+            paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
+        }
+    }
+
+    static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle,
+            Paint::FontMetrics *metrics) {
+        const int kElegantTop = 2500;
+        const int kElegantBottom = -1000;
+        const int kElegantAscent = 1900;
+        const int kElegantDescent = -500;
+        const int kElegantLeading = 0;
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
+        typeface = Typeface::resolveDefault(typeface);
+        minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
+        float saveSkewX = paint->getTextSkewX();
+        bool savefakeBold = paint->isFakeBoldText();
+        MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
+        SkScalar spacing = paint->getFontMetrics(metrics);
+        // The populateSkPaint call may have changed fake bold / text skew
+        // because we want to measure with those effects applied, so now
+        // restore the original settings.
+        paint->setTextSkewX(saveSkewX);
+        paint->setFakeBoldText(savefakeBold);
+        if (paint->getFontVariant() == minikin::VARIANT_ELEGANT) {
+            SkScalar size = paint->getTextSize();
+            metrics->fTop = -size * kElegantTop / 2048;
+            metrics->fBottom = -size * kElegantBottom / 2048;
+            metrics->fAscent = -size * kElegantAscent / 2048;
+            metrics->fDescent = -size * kElegantDescent / 2048;
+            metrics->fLeading = size * kElegantLeading / 2048;
+            spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
+        }
+        return spacing;
+    }
+
+    static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle,
+            jlong typefaceHandle, jobject metricsObj) {
+        Paint::FontMetrics metrics;
+        SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+
+        if (metricsObj) {
+            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
+            env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
+            env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
+            env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
+            env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
+            env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
+        }
+        return SkScalarToFloat(spacing);
+    }
+
+    static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle,
+            jlong typefaceHandle, jobject metricsObj) {
+        Paint::FontMetrics metrics;
+
+        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+        int ascent = SkScalarRoundToInt(metrics.fAscent);
+        int descent = SkScalarRoundToInt(metrics.fDescent);
+        int leading = SkScalarRoundToInt(metrics.fLeading);
+
+        if (metricsObj) {
+            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
+        }
+        return descent - ascent + leading;
+    }
+
+
+    // ------------------ @CriticalNative ---------------------------
+
+    static void reset(jlong objHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        obj->reset();
+        defaultSettingsForAndroid(obj);
+    }
+
+    static void assign(jlong dstPaintHandle, jlong srcPaintHandle) {
+        Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
+        const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
+        *dst = *src;
+    }
+
+    // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
+    static const uint32_t sFilterBitmapFlag = 0x02;
+
+    static jint getFlags(jlong paintHandle) {
+        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
+        uint32_t result = nativePaint->getFlags();
+        result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
+        if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
+            result |= sFilterBitmapFlag;
+        }
+        return static_cast<jint>(result);
+    }
+
+    static void setFlags(jlong paintHandle, jint flags) {
+        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
+        // Instead of modifying 0x02, change the filter level.
+        nativePaint->setFilterQuality(flags & sFilterBitmapFlag
+                ? kLow_SkFilterQuality
+                : kNone_SkFilterQuality);
+        // Don't pass through filter flag, which is no longer stored in paint's flags.
+        flags &= ~sFilterBitmapFlag;
+        // Use the existing value for 0x02.
+        const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
+        flags |= existing0x02Flag;
+        nativePaint->setFlags(flags);
+    }
+
+    static jint getHinting(jlong paintHandle) {
+        return reinterpret_cast<Paint*>(paintHandle)->getHinting()
+                == Paint::kNo_Hinting ? 0 : 1;
+    }
+
+    static void setHinting(jlong paintHandle, jint mode) {
+        reinterpret_cast<Paint*>(paintHandle)->setHinting(
+                mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
+    }
+
+    static void setAntiAlias(jlong paintHandle, jboolean aa) {
+        reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
+    }
+
+    static void setLinearText(jlong paintHandle, jboolean linearText) {
+        reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
+    }
+
+    static void setSubpixelText(jlong paintHandle, jboolean subpixelText) {
+        reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
+    }
+
+    static void setUnderlineText(jlong paintHandle, jboolean underlineText) {
+        reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText);
+    }
+
+    static void setStrikeThruText(jlong paintHandle, jboolean strikeThruText) {
+        reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText);
+    }
+
+    static void setFakeBoldText(jlong paintHandle, jboolean fakeBoldText) {
+        reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
+    }
+
+    static void setFilterBitmap(jlong paintHandle, jboolean filterBitmap) {
+        reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
+                filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
+    }
+
+    static void setDither(jlong paintHandle, jboolean dither) {
+        reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
+    }
+
+    static jint getStyle(jlong objHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        return static_cast<jint>(obj->getStyle());
+    }
+
+    static void setStyle(jlong objHandle, jint styleHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        Paint::Style style = static_cast<Paint::Style>(styleHandle);
+        obj->setStyle(style);
+    }
+
+    static jint getColor(jlong paintHandle) {
+        int color;
+        color = reinterpret_cast<Paint*>(paintHandle)->getColor();
+        return static_cast<jint>(color);
+    }
+
+    static jint getAlpha(jlong paintHandle) {
+        int alpha;
+        alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
+        return static_cast<jint>(alpha);
+    }
+
+    static void setColor(jlong paintHandle, jint color) {
+        reinterpret_cast<Paint*>(paintHandle)->setColor(color);
+    }
+
+    static void setAlpha(jlong paintHandle, jint a) {
+        reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
+    }
+
+    static jfloat getStrokeWidth(jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
+    }
+
+    static void setStrokeWidth(jlong paintHandle, jfloat width) {
+        reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
+    }
+
+    static jfloat getStrokeMiter(jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
+    }
+
+    static void setStrokeMiter(jlong paintHandle, jfloat miter) {
+        reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
+    }
+
+    static jint getStrokeCap(jlong objHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        return static_cast<jint>(obj->getStrokeCap());
+    }
+
+    static void setStrokeCap(jlong objHandle, jint capHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
+        obj->setStrokeCap(cap);
+    }
+
+    static jint getStrokeJoin(jlong objHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        return static_cast<jint>(obj->getStrokeJoin());
+    }
+
+    static void setStrokeJoin(jlong objHandle, jint joinHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        Paint::Join join = (Paint::Join) joinHandle;
+        obj->setStrokeJoin(join);
+    }
+
+    static jboolean getFillPath(jlong objHandle, jlong srcHandle, jlong dstHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
+        SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
+        return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
+    }
+
+    static jlong setShader(jlong objHandle, jlong shaderHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
+        return reinterpret_cast<jlong>(obj->setShader(shader));
+    }
+
+    static jlong setColorFilter(jlong objHandle, jlong filterHandle) {
+        Paint* obj = reinterpret_cast<Paint *>(objHandle);
+        SkColorFilter* filter  = reinterpret_cast<SkColorFilter *>(filterHandle);
+        return reinterpret_cast<jlong>(obj->setColorFilter(filter));
+    }
+
+    static void setXfermode(jlong paintHandle, jint xfermodeHandle) {
+        // validate that the Java enum values match our expectations
+        static_assert(0 == SkXfermode::kClear_Mode, "xfermode_mismatch");
+        static_assert(1 == SkXfermode::kSrc_Mode, "xfermode_mismatch");
+        static_assert(2 == SkXfermode::kDst_Mode, "xfermode_mismatch");
+        static_assert(3 == SkXfermode::kSrcOver_Mode, "xfermode_mismatch");
+        static_assert(4 == SkXfermode::kDstOver_Mode, "xfermode_mismatch");
+        static_assert(5 == SkXfermode::kSrcIn_Mode, "xfermode_mismatch");
+        static_assert(6 == SkXfermode::kDstIn_Mode, "xfermode_mismatch");
+        static_assert(7 == SkXfermode::kSrcOut_Mode, "xfermode_mismatch");
+        static_assert(8 == SkXfermode::kDstOut_Mode, "xfermode_mismatch");
+        static_assert(9 == SkXfermode::kSrcATop_Mode, "xfermode_mismatch");
+        static_assert(10 == SkXfermode::kDstATop_Mode, "xfermode_mismatch");
+        static_assert(11 == SkXfermode::kXor_Mode, "xfermode_mismatch");
+        static_assert(16 == SkXfermode::kDarken_Mode, "xfermode_mismatch");
+        static_assert(17 == SkXfermode::kLighten_Mode, "xfermode_mismatch");
+        static_assert(13 == SkXfermode::kModulate_Mode, "xfermode_mismatch");
+        static_assert(14 == SkXfermode::kScreen_Mode, "xfermode_mismatch");
+        static_assert(12 == SkXfermode::kPlus_Mode, "xfermode_mismatch");
+        static_assert(15 == SkXfermode::kOverlay_Mode, "xfermode_mismatch");
+
+        SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        paint->setXfermodeMode(mode);
+    }
+
+    static jlong setPathEffect(jlong objHandle, jlong effectHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        SkPathEffect* effect  = reinterpret_cast<SkPathEffect*>(effectHandle);
+        return reinterpret_cast<jlong>(obj->setPathEffect(effect));
+    }
+
+    static jlong setMaskFilter(jlong objHandle, jlong maskfilterHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        SkMaskFilter* maskfilter  = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
+        return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter));
+    }
+
+    static jlong setTypeface(jlong objHandle, jlong typefaceHandle) {
+        // TODO: in Paint refactoring, set typeface on android Paint, not Paint
+        return 0;
+    }
+
+    static jlong setRasterizer(jlong objHandle, jlong rasterizerHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
+        return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer));
+    }
+
+    static jint getTextAlign(jlong objHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        return static_cast<jint>(obj->getTextAlign());
+    }
+
+    static void setTextAlign(jlong objHandle, jint alignHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        Paint::Align align = static_cast<Paint::Align>(alignHandle);
+        obj->setTextAlign(align);
+    }
+
+    static void setTextLocalesByMinikinLangListId(jlong objHandle,
+            jint minikinLangListId) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        obj->setMinikinLangListId(minikinLangListId);
+    }
+
+    static jboolean isElegantTextHeight(jlong paintHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
+        return obj->getFontVariant() == minikin::VARIANT_ELEGANT;
+    }
+
+    static void setElegantTextHeight(jlong paintHandle, jboolean aa) {
+        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
+        obj->setFontVariant(aa ? minikin::VARIANT_ELEGANT : minikin::VARIANT_DEFAULT);
+    }
+
+    static jfloat getTextSize(jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
+    }
+
+    static void setTextSize(jlong paintHandle, jfloat textSize) {
+        reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
+    }
+
+    static jfloat getTextScaleX(jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
+    }
+
+    static void setTextScaleX(jlong paintHandle, jfloat scaleX) {
+        reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
+    }
+
+    static jfloat getTextSkewX(jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
+    }
+
+    static void setTextSkewX(jlong paintHandle, jfloat skewX) {
+        reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
+    }
+
+    static jfloat getLetterSpacing(jlong paintHandle) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        return paint->getLetterSpacing();
+    }
+
+    static void setLetterSpacing(jlong paintHandle, jfloat letterSpacing) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        paint->setLetterSpacing(letterSpacing);
+    }
+
+    static jint getHyphenEdit(jlong paintHandle, jint hyphen) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        return paint->getHyphenEdit();
+    }
+
+    static void setHyphenEdit(jlong paintHandle, jint hyphen) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        paint->setHyphenEdit((uint32_t)hyphen);
+    }
+
+    static jfloat ascent(jlong paintHandle, jlong typefaceHandle) {
+        Paint::FontMetrics metrics;
+        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+        return SkScalarToFloat(metrics.fAscent);
+    }
+
+    static jfloat descent(jlong paintHandle, jlong typefaceHandle) {
+        Paint::FontMetrics metrics;
+        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+        return SkScalarToFloat(metrics.fDescent);
+    }
+
+    static void setShadowLayer(jlong paintHandle, jfloat radius,
+                               jfloat dx, jfloat dy, jint color) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        if (radius <= 0) {
+            paint->setLooper(nullptr);
+        }
+        else {
+            SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
+            paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref();
+        }
+    }
+
+    static jboolean hasShadowLayer(jlong paintHandle) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        return paint->getLooper() && paint->getLooper()->asABlurShadow(nullptr);
+    }
+
 }; // namespace PaintGlue
 
 static const JNINativeMethod methods[] = {
     {"nGetNativeFinalizer", "()J", (void*) PaintGlue::getNativeFinalizer},
     {"nInit","()J", (void*) PaintGlue::init},
     {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
-
-    {"nReset","!(J)V", (void*) PaintGlue::reset},
-    {"nSet","!(JJ)V", (void*) PaintGlue::assign},
-    {"nGetFlags","!(J)I", (void*) PaintGlue::getFlags},
-    {"nSetFlags","!(JI)V", (void*) PaintGlue::setFlags},
-    {"nGetHinting","!(J)I", (void*) PaintGlue::getHinting},
-    {"nSetHinting","!(JI)V", (void*) PaintGlue::setHinting},
-    {"nSetAntiAlias","!(JZ)V", (void*) PaintGlue::setAntiAlias},
-    {"nSetSubpixelText","!(JZ)V", (void*) PaintGlue::setSubpixelText},
-    {"nSetLinearText","!(JZ)V", (void*) PaintGlue::setLinearText},
-    {"nSetUnderlineText","!(JZ)V", (void*) PaintGlue::setUnderlineText},
-    {"nSetStrikeThruText","!(JZ)V", (void*) PaintGlue::setStrikeThruText},
-    {"nSetFakeBoldText","!(JZ)V", (void*) PaintGlue::setFakeBoldText},
-    {"nSetFilterBitmap","!(JZ)V", (void*) PaintGlue::setFilterBitmap},
-    {"nSetDither","!(JZ)V", (void*) PaintGlue::setDither},
-    {"nGetStyle","!(J)I", (void*) PaintGlue::getStyle},
-    {"nSetStyle","!(JI)V", (void*) PaintGlue::setStyle},
-    {"nGetColor","!(J)I", (void*) PaintGlue::getColor},
-    {"nSetColor","!(JI)V", (void*) PaintGlue::setColor},
-    {"nGetAlpha","!(J)I", (void*) PaintGlue::getAlpha},
-    {"nSetAlpha","!(JI)V", (void*) PaintGlue::setAlpha},
-    {"nGetStrokeWidth","!(J)F", (void*) PaintGlue::getStrokeWidth},
-    {"nSetStrokeWidth","!(JF)V", (void*) PaintGlue::setStrokeWidth},
-    {"nGetStrokeMiter","!(J)F", (void*) PaintGlue::getStrokeMiter},
-    {"nSetStrokeMiter","!(JF)V", (void*) PaintGlue::setStrokeMiter},
-    {"nGetStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
-    {"nSetStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
-    {"nGetStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
-    {"nSetStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
-    {"nGetFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
-    {"nSetShader","!(JJ)J", (void*) PaintGlue::setShader},
-    {"nSetColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
-    {"nSetXfermode","!(JI)V", (void*) PaintGlue::setXfermode},
-    {"nSetPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
-    {"nSetMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
-    {"nSetTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
-    {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
-    {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
-    {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
-    {"nSetTextLocales","!(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales},
-    {"nSetTextLocalesByMinikinLangListId","!(JI)V",
-            (void*) PaintGlue::setTextLocalesByMinikinLangListId},
-    {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight},
-    {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight},
-    {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize},
-    {"nSetTextSize","!(JF)V", (void*) PaintGlue::setTextSize},
-    {"nGetTextScaleX","!(J)F", (void*) PaintGlue::getTextScaleX},
-    {"nSetTextScaleX","!(JF)V", (void*) PaintGlue::setTextScaleX},
-    {"nGetTextSkewX","!(J)F", (void*) PaintGlue::getTextSkewX},
-    {"nSetTextSkewX","!(JF)V", (void*) PaintGlue::setTextSkewX},
-    {"nGetLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
-    {"nSetLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
-    {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
-            (void*) PaintGlue::setFontFeatureSettings},
-    {"nGetHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit},
-    {"nSetHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit},
-    {"nAscent","!(JJ)F", (void*) PaintGlue::ascent},
-    {"nDescent","!(JJ)F", (void*) PaintGlue::descent},
-
-    {"nGetFontMetrics", "!(JJLandroid/graphics/Paint$FontMetrics;)F",
-            (void*)PaintGlue::getFontMetrics},
-    {"nGetFontMetricsInt", "!(JJLandroid/graphics/Paint$FontMetricsInt;)I",
-            (void*)PaintGlue::getFontMetricsInt},
-
     {"nBreakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
     {"nBreakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
     {"nGetTextAdvances","(JJ[CIIIII[FI)F",
@@ -1034,8 +976,74 @@
     {"nGetOffsetForAdvance", "(JJ[CIIIIZF)I",
             (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
 
-    {"nSetShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
-    {"nHasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
+    // --------------- @FastNative ----------------------
+
+    {"nSetTextLocales","(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales},
+    {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
+                (void*) PaintGlue::setFontFeatureSettings},
+    {"nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F",
+                (void*)PaintGlue::getFontMetrics},
+    {"nGetFontMetricsInt", "(JJLandroid/graphics/Paint$FontMetricsInt;)I",
+            (void*)PaintGlue::getFontMetricsInt},
+
+    // --------------- @CriticalNative ------------------
+
+    {"nReset","(J)V", (void*) PaintGlue::reset},
+    {"nSet","(JJ)V", (void*) PaintGlue::assign},
+    {"nGetFlags","(J)I", (void*) PaintGlue::getFlags},
+    {"nSetFlags","(JI)V", (void*) PaintGlue::setFlags},
+    {"nGetHinting","(J)I", (void*) PaintGlue::getHinting},
+    {"nSetHinting","(JI)V", (void*) PaintGlue::setHinting},
+    {"nSetAntiAlias","(JZ)V", (void*) PaintGlue::setAntiAlias},
+    {"nSetSubpixelText","(JZ)V", (void*) PaintGlue::setSubpixelText},
+    {"nSetLinearText","(JZ)V", (void*) PaintGlue::setLinearText},
+    {"nSetUnderlineText","(JZ)V", (void*) PaintGlue::setUnderlineText},
+    {"nSetStrikeThruText","(JZ)V", (void*) PaintGlue::setStrikeThruText},
+    {"nSetFakeBoldText","(JZ)V", (void*) PaintGlue::setFakeBoldText},
+    {"nSetFilterBitmap","(JZ)V", (void*) PaintGlue::setFilterBitmap},
+    {"nSetDither","(JZ)V", (void*) PaintGlue::setDither},
+    {"nGetStyle","(J)I", (void*) PaintGlue::getStyle},
+    {"nSetStyle","(JI)V", (void*) PaintGlue::setStyle},
+    {"nGetColor","(J)I", (void*) PaintGlue::getColor},
+    {"nSetColor","(JI)V", (void*) PaintGlue::setColor},
+    {"nGetAlpha","(J)I", (void*) PaintGlue::getAlpha},
+    {"nSetAlpha","(JI)V", (void*) PaintGlue::setAlpha},
+    {"nGetStrokeWidth","(J)F", (void*) PaintGlue::getStrokeWidth},
+    {"nSetStrokeWidth","(JF)V", (void*) PaintGlue::setStrokeWidth},
+    {"nGetStrokeMiter","(J)F", (void*) PaintGlue::getStrokeMiter},
+    {"nSetStrokeMiter","(JF)V", (void*) PaintGlue::setStrokeMiter},
+    {"nGetStrokeCap","(J)I", (void*) PaintGlue::getStrokeCap},
+    {"nSetStrokeCap","(JI)V", (void*) PaintGlue::setStrokeCap},
+    {"nGetStrokeJoin","(J)I", (void*) PaintGlue::getStrokeJoin},
+    {"nSetStrokeJoin","(JI)V", (void*) PaintGlue::setStrokeJoin},
+    {"nGetFillPath","(JJJ)Z", (void*) PaintGlue::getFillPath},
+    {"nSetShader","(JJ)J", (void*) PaintGlue::setShader},
+    {"nSetColorFilter","(JJ)J", (void*) PaintGlue::setColorFilter},
+    {"nSetXfermode","(JI)V", (void*) PaintGlue::setXfermode},
+    {"nSetPathEffect","(JJ)J", (void*) PaintGlue::setPathEffect},
+    {"nSetMaskFilter","(JJ)J", (void*) PaintGlue::setMaskFilter},
+    {"nSetTypeface","(JJ)J", (void*) PaintGlue::setTypeface},
+    {"nSetRasterizer","(JJ)J", (void*) PaintGlue::setRasterizer},
+    {"nGetTextAlign","(J)I", (void*) PaintGlue::getTextAlign},
+    {"nSetTextAlign","(JI)V", (void*) PaintGlue::setTextAlign},
+    {"nSetTextLocalesByMinikinLangListId","(JI)V",
+            (void*) PaintGlue::setTextLocalesByMinikinLangListId},
+    {"nIsElegantTextHeight","(J)Z", (void*) PaintGlue::isElegantTextHeight},
+    {"nSetElegantTextHeight","(JZ)V", (void*) PaintGlue::setElegantTextHeight},
+    {"nGetTextSize","(J)F", (void*) PaintGlue::getTextSize},
+    {"nSetTextSize","(JF)V", (void*) PaintGlue::setTextSize},
+    {"nGetTextScaleX","(J)F", (void*) PaintGlue::getTextScaleX},
+    {"nSetTextScaleX","(JF)V", (void*) PaintGlue::setTextScaleX},
+    {"nGetTextSkewX","(J)F", (void*) PaintGlue::getTextSkewX},
+    {"nSetTextSkewX","(JF)V", (void*) PaintGlue::setTextSkewX},
+    {"nGetLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing},
+    {"nSetLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing},
+    {"nGetHyphenEdit", "(J)I", (void*) PaintGlue::getHyphenEdit},
+    {"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit},
+    {"nAscent","(JJ)F", (void*) PaintGlue::ascent},
+    {"nDescent","(JJ)F", (void*) PaintGlue::descent},
+    {"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer},
+    {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer}
 };
 
 int register_android_graphics_Paint(JNIEnv* env) {