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