Paint.cpp revision 2a1ce8a4e5258b6599cb8e86864eb816d24d69b4
1/* libs/android_runtime/android/graphics/Paint.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "Paint"
19
20#include <utils/Log.h>
21
22#include "jni.h"
23#include "GraphicsJNI.h"
24#include "core_jni_helpers.h"
25#include <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->getFilterQuality() != kNone_SkFilterQuality) {
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->setFilterQuality(flags & sFilterBitmapFlag
146                ? kLow_SkFilterQuality
147                : kNone_SkFilterQuality);
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)->setFilterQuality(
201                filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
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 jint getHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
457        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
458        return paint->getHyphenEdit();
459    }
460
461    static void setHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
462        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
463        paint->setHyphenEdit((uint32_t)hyphen);
464    }
465
466    static SkScalar getMetricsInternal(JNIEnv* env, jobject jpaint, Paint::FontMetrics *metrics) {
467        const int kElegantTop = 2500;
468        const int kElegantBottom = -1000;
469        const int kElegantAscent = 1900;
470        const int kElegantDescent = -500;
471        const int kElegantLeading = 0;
472        Paint* paint = getNativePaint(env, jpaint);
473        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
474        typeface = TypefaceImpl_resolveDefault(typeface);
475        FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
476        float saveSkewX = paint->getTextSkewX();
477        bool savefakeBold = paint->isFakeBoldText();
478        MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
479        SkScalar spacing = paint->getFontMetrics(metrics);
480        // The populateSkPaint call may have changed fake bold / text skew
481        // because we want to measure with those effects applied, so now
482        // restore the original settings.
483        paint->setTextSkewX(saveSkewX);
484        paint->setFakeBoldText(savefakeBold);
485        if (paint->getFontVariant() == VARIANT_ELEGANT) {
486            SkScalar size = paint->getTextSize();
487            metrics->fTop = -size * kElegantTop / 2048;
488            metrics->fBottom = -size * kElegantBottom / 2048;
489            metrics->fAscent = -size * kElegantAscent / 2048;
490            metrics->fDescent = -size * kElegantDescent / 2048;
491            metrics->fLeading = size * kElegantLeading / 2048;
492            spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
493        }
494        return spacing;
495    }
496
497    static jfloat ascent(JNIEnv* env, jobject paint) {
498        NPE_CHECK_RETURN_ZERO(env, paint);
499        Paint::FontMetrics metrics;
500        getMetricsInternal(env, paint, &metrics);
501        return SkScalarToFloat(metrics.fAscent);
502    }
503
504    static jfloat descent(JNIEnv* env, jobject paint) {
505        NPE_CHECK_RETURN_ZERO(env, paint);
506        Paint::FontMetrics metrics;
507        getMetricsInternal(env, paint, &metrics);
508        return SkScalarToFloat(metrics.fDescent);
509    }
510
511    static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) {
512        NPE_CHECK_RETURN_ZERO(env, paint);
513        Paint::FontMetrics metrics;
514        SkScalar spacing = getMetricsInternal(env, paint, &metrics);
515
516        if (metricsObj) {
517            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
518            env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
519            env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
520            env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
521            env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
522            env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
523        }
524        return SkScalarToFloat(spacing);
525    }
526
527    static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) {
528        NPE_CHECK_RETURN_ZERO(env, paint);
529        Paint::FontMetrics metrics;
530
531        getMetricsInternal(env, paint, &metrics);
532        int ascent = SkScalarRoundToInt(metrics.fAscent);
533        int descent = SkScalarRoundToInt(metrics.fDescent);
534        int leading = SkScalarRoundToInt(metrics.fLeading);
535
536        if (metricsObj) {
537            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
538            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
539            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
540            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
541            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
542            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
543        }
544        return descent - ascent + leading;
545    }
546
547    static jfloat measureText_CIII(JNIEnv* env, jobject jpaint, jcharArray text, jint index, jint count,
548            jint bidiFlags) {
549        NPE_CHECK_RETURN_ZERO(env, jpaint);
550        NPE_CHECK_RETURN_ZERO(env, text);
551
552        size_t textLength = env->GetArrayLength(text);
553        if ((index | count) < 0 || (size_t)(index + count) > textLength) {
554            doThrowAIOOBE(env);
555            return 0;
556        }
557        if (count == 0) {
558            return 0;
559        }
560
561        Paint* paint = getNativePaint(env, jpaint);
562        const jchar* textArray = env->GetCharArrayElements(text, NULL);
563        jfloat result = 0;
564
565        Layout layout;
566        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
567        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, index, count, textLength);
568        result = layout.getAdvance();
569        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
570        return result;
571    }
572
573    static jfloat measureText_StringIII(JNIEnv* env, jobject jpaint, jstring text, jint start, jint end,
574            jint bidiFlags) {
575        NPE_CHECK_RETURN_ZERO(env, jpaint);
576        NPE_CHECK_RETURN_ZERO(env, text);
577
578        size_t textLength = env->GetStringLength(text);
579        int count = end - start;
580        if ((start | count) < 0 || (size_t)end > textLength) {
581            doThrowAIOOBE(env);
582            return 0;
583        }
584        if (count == 0) {
585            return 0;
586        }
587
588        const jchar* textArray = env->GetStringChars(text, NULL);
589        Paint* paint = getNativePaint(env, jpaint);
590        jfloat width = 0;
591
592        Layout layout;
593        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
594        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, start, count, textLength);
595        width = layout.getAdvance();
596
597        env->ReleaseStringChars(text, textArray);
598        return width;
599    }
600
601    static jfloat measureText_StringI(JNIEnv* env, jobject jpaint, jstring text, jint bidiFlags) {
602        NPE_CHECK_RETURN_ZERO(env, jpaint);
603        NPE_CHECK_RETURN_ZERO(env, text);
604
605        size_t textLength = env->GetStringLength(text);
606        if (textLength == 0) {
607            return 0;
608        }
609
610        const jchar* textArray = env->GetStringChars(text, NULL);
611        Paint* paint = getNativePaint(env, jpaint);
612        jfloat width = 0;
613
614        Layout layout;
615        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
616        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, 0, textLength, textLength);
617        width = layout.getAdvance();
618
619        env->ReleaseStringChars(text, textArray);
620        return width;
621    }
622
623    static int dotextwidths(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar text[], int count,
624            jfloatArray widths, jint bidiFlags) {
625        NPE_CHECK_RETURN_ZERO(env, paint);
626        NPE_CHECK_RETURN_ZERO(env, text);
627
628        if (count < 0 || !widths) {
629            doThrowAIOOBE(env);
630            return 0;
631        }
632        if (count == 0) {
633            return 0;
634        }
635        size_t widthsLength = env->GetArrayLength(widths);
636        if ((size_t)count > widthsLength) {
637            doThrowAIOOBE(env);
638            return 0;
639        }
640
641        AutoJavaFloatArray autoWidths(env, widths, count);
642        jfloat* widthsArray = autoWidths.ptr();
643
644        Layout layout;
645        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
646        layout.getAdvances(widthsArray);
647
648        return count;
649    }
650
651    static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text,
652            jint index, jint count, jint bidiFlags, jfloatArray widths) {
653        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
654        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
655        const jchar* textArray = env->GetCharArrayElements(text, NULL);
656        count = dotextwidths(env, paint, typeface, textArray + index, count, widths, bidiFlags);
657        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
658                                      JNI_ABORT);
659        return count;
660    }
661
662    static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring text,
663            jint start, jint end, jint bidiFlags, jfloatArray widths) {
664        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
665        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
666        const jchar* textArray = env->GetStringChars(text, NULL);
667        int count = dotextwidths(env, paint, typeface, textArray + start, end - start, widths, bidiFlags);
668        env->ReleaseStringChars(text, textArray);
669        return count;
670    }
671
672    static jfloat doTextRunAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface, const jchar *text,
673                                    jint start, jint count, jint contextCount, jboolean isRtl,
674                                    jfloatArray advances, jint advancesIndex) {
675        NPE_CHECK_RETURN_ZERO(env, paint);
676        NPE_CHECK_RETURN_ZERO(env, text);
677
678        if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
679            doThrowAIOOBE(env);
680            return 0;
681        }
682        if (count == 0) {
683            return 0;
684        }
685        if (advances) {
686            size_t advancesLength = env->GetArrayLength(advances);
687            if ((size_t)count > advancesLength) {
688                doThrowAIOOBE(env);
689                return 0;
690            }
691        }
692        jfloat* advancesArray = new jfloat[count];
693        jfloat totalAdvance = 0;
694
695        int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
696
697        Layout layout;
698        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount);
699        layout.getAdvances(advancesArray);
700        totalAdvance = layout.getAdvance();
701
702        if (advances != NULL) {
703            env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
704        }
705        delete [] advancesArray;
706        return totalAdvance;
707    }
708
709    static jfloat getTextRunAdvances___CIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
710            jlong typefaceHandle,
711            jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
712            jboolean isRtl, jfloatArray advances, jint advancesIndex) {
713        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
714        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
715        jchar* textArray = env->GetCharArrayElements(text, NULL);
716        jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex,
717                index - contextIndex, count, contextCount, isRtl, advances, advancesIndex);
718        env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
719        return result;
720    }
721
722    static jfloat getTextRunAdvances__StringIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
723            jlong typefaceHandle,
724            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl,
725            jfloatArray advances, jint advancesIndex) {
726        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
727        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
728        const jchar* textArray = env->GetStringChars(text, NULL);
729        jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart,
730                start - contextStart, end - start, contextEnd - contextStart, isRtl,
731                advances, advancesIndex);
732        env->ReleaseStringChars(text, textArray);
733        return result;
734    }
735
736    static jint doTextRunCursor(JNIEnv *env, Paint* paint, const jchar *text, jint start,
737            jint count, jint flags, jint offset, jint opt) {
738        GraphemeBreak::MoveOpt moveOpt = GraphemeBreak::MoveOpt(opt);
739        size_t result = GraphemeBreak::getTextRunCursor(text, start, count, offset, moveOpt);
740        return static_cast<jint>(result);
741    }
742
743    static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
744            jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) {
745        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
746        jchar* textArray = env->GetCharArrayElements(text, NULL);
747        jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir,
748                offset, cursorOpt);
749        env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
750        return result;
751    }
752
753    static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
754            jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) {
755        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
756        const jchar* textArray = env->GetStringChars(text, NULL);
757        jint result = doTextRunCursor(env, paint, textArray, contextStart,
758                contextEnd - contextStart, dir, offset, cursorOpt);
759        env->ReleaseStringChars(text, textArray);
760        return result;
761    }
762
763    class GetTextFunctor {
764    public:
765        GetTextFunctor(const Layout& layout, SkPath* path, jfloat x, jfloat y, Paint* paint,
766                    uint16_t* glyphs, SkPoint* pos)
767                : layout(layout), path(path), x(x), y(y), paint(paint), glyphs(glyphs), pos(pos) {
768        }
769
770        void operator()(size_t start, size_t end) {
771            for (size_t i = start; i < end; i++) {
772                glyphs[i] = layout.getGlyphId(i);
773                pos[i].fX = x + layout.getX(i);
774                pos[i].fY = y + layout.getY(i);
775            }
776            if (start == 0) {
777                paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, path);
778            } else {
779                paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, &tmpPath);
780                path->addPath(tmpPath);
781            }
782        }
783    private:
784        const Layout& layout;
785        SkPath* path;
786        jfloat x;
787        jfloat y;
788        Paint* paint;
789        uint16_t* glyphs;
790        SkPoint* pos;
791        SkPath tmpPath;
792    };
793
794    static void getTextPath(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar* text,
795            jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
796        Layout layout;
797        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
798        size_t nGlyphs = layout.nGlyphs();
799        uint16_t* glyphs = new uint16_t[nGlyphs];
800        SkPoint* pos = new SkPoint[nGlyphs];
801
802        x += MinikinUtils::xOffsetForTextAlign(paint, layout);
803        Paint::Align align = paint->getTextAlign();
804        paint->setTextAlign(Paint::kLeft_Align);
805        paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
806        GetTextFunctor f(layout, path, x, y, paint, glyphs, pos);
807        MinikinUtils::forFontRun(layout, paint, f);
808        paint->setTextAlign(align);
809        delete[] glyphs;
810        delete[] pos;
811    }
812
813    static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle,
814            jlong typefaceHandle, jint bidiFlags,
815            jcharArray text, jint index, jint count, jfloat x, jfloat y, jlong pathHandle) {
816        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
817        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
818        SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
819        const jchar* textArray = env->GetCharArrayElements(text, NULL);
820        getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
821        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
822    }
823
824    static void getTextPath__String(JNIEnv* env, jobject clazz, jlong paintHandle,
825            jlong typefaceHandle, jint bidiFlags,
826            jstring text, jint start, jint end, jfloat x, jfloat y, jlong pathHandle) {
827        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
828        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
829        SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
830        const jchar* textArray = env->GetStringChars(text, NULL);
831        getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
832        env->ReleaseStringChars(text, textArray);
833    }
834
835    static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
836                               jfloat dx, jfloat dy, jint color) {
837        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
838        if (radius <= 0) {
839            paint->setLooper(NULL);
840        }
841        else {
842            SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
843            paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref();
844        }
845    }
846
847    static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) {
848        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
849        return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
850    }
851
852    static int breakText(JNIEnv* env, const Paint& paint, TypefaceImpl* typeface, const jchar text[],
853                         int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
854                         const bool forwardScan) {
855        size_t measuredCount = 0;
856        float measured = 0;
857
858        Layout layout;
859        MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
860        float* advances = new float[count];
861        layout.getAdvances(advances);
862
863        for (int i = 0; i < count; i++) {
864            // traverse in the given direction
865            int index = forwardScan ? i : (count - i - 1);
866            float width = advances[index];
867            if (measured + width > maxWidth) {
868                break;
869            }
870            // properly handle clusters when scanning backwards
871            if (forwardScan || width != 0.0f) {
872                measuredCount = i + 1;
873            }
874            measured += width;
875        }
876        delete[] advances;
877
878        if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
879            AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
880            jfloat* array = autoMeasured.ptr();
881            array[0] = measured;
882        }
883        return measuredCount;
884    }
885
886    static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext,
887            jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
888        NPE_CHECK_RETURN_ZERO(env, jtext);
889
890        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
891        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
892
893        bool forwardTextDirection;
894        if (count < 0) {
895            forwardTextDirection = false;
896            count = -count;
897        }
898        else {
899            forwardTextDirection = true;
900        }
901
902        if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
903            doThrowAIOOBE(env);
904            return 0;
905        }
906
907        const jchar* text = env->GetCharArrayElements(jtext, NULL);
908        count = breakText(env, *paint, typeface, text + index, count, maxWidth,
909                          bidiFlags, jmeasuredWidth, forwardTextDirection);
910        env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
911                                      JNI_ABORT);
912        return count;
913    }
914
915    static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
916                jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
917        NPE_CHECK_RETURN_ZERO(env, jtext);
918
919        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
920        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
921
922        int count = env->GetStringLength(jtext);
923        const jchar* text = env->GetStringChars(jtext, NULL);
924        count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
925        env->ReleaseStringChars(jtext, text);
926        return count;
927    }
928
929    static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
930            const Paint& paint, TypefaceImpl* typeface, jint bidiFlags) {
931        SkRect  r;
932        SkIRect ir;
933
934        Layout layout;
935        MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
936        MinikinRect rect;
937        layout.getBounds(&rect);
938        r.fLeft = rect.mLeft;
939        r.fTop = rect.mTop;
940        r.fRight = rect.mRight;
941        r.fBottom = rect.mBottom;
942        r.roundOut(&ir);
943        GraphicsJNI::irect_to_jrect(ir, env, bounds);
944    }
945
946    static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
947                                jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
948        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);;
949        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
950        const jchar* textArray = env->GetStringChars(text, NULL);
951        doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
952        env->ReleaseStringChars(text, textArray);
953    }
954
955    static void getCharArrayBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
956                        jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) {
957        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
958        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
959        const jchar* textArray = env->GetCharArrayElements(text, NULL);
960        doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags);
961        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
962                                      JNI_ABORT);
963    }
964
965};
966
967static JNINativeMethod methods[] = {
968    {"finalizer", "(J)V", (void*) PaintGlue::finalizer},
969    {"native_init","()J", (void*) PaintGlue::init},
970    {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
971
972    {"native_reset","!(J)V", (void*) PaintGlue::reset},
973    {"native_set","!(JJ)V", (void*) PaintGlue::assign},
974    {"getFlags","!()I", (void*) PaintGlue::getFlags},
975    {"setFlags","!(I)V", (void*) PaintGlue::setFlags},
976    {"getHinting","!()I", (void*) PaintGlue::getHinting},
977    {"setHinting","!(I)V", (void*) PaintGlue::setHinting},
978    {"setAntiAlias","!(Z)V", (void*) PaintGlue::setAntiAlias},
979    {"setSubpixelText","!(Z)V", (void*) PaintGlue::setSubpixelText},
980    {"setLinearText","!(Z)V", (void*) PaintGlue::setLinearText},
981    {"setUnderlineText","!(Z)V", (void*) PaintGlue::setUnderlineText},
982    {"setStrikeThruText","!(Z)V", (void*) PaintGlue::setStrikeThruText},
983    {"setFakeBoldText","!(Z)V", (void*) PaintGlue::setFakeBoldText},
984    {"setFilterBitmap","!(Z)V", (void*) PaintGlue::setFilterBitmap},
985    {"setDither","!(Z)V", (void*) PaintGlue::setDither},
986    {"native_getStyle","!(J)I", (void*) PaintGlue::getStyle},
987    {"native_setStyle","!(JI)V", (void*) PaintGlue::setStyle},
988    {"getColor","!()I", (void*) PaintGlue::getColor},
989    {"setColor","!(I)V", (void*) PaintGlue::setColor},
990    {"getAlpha","!()I", (void*) PaintGlue::getAlpha},
991    {"setAlpha","!(I)V", (void*) PaintGlue::setAlpha},
992    {"getStrokeWidth","!()F", (void*) PaintGlue::getStrokeWidth},
993    {"setStrokeWidth","!(F)V", (void*) PaintGlue::setStrokeWidth},
994    {"getStrokeMiter","!()F", (void*) PaintGlue::getStrokeMiter},
995    {"setStrokeMiter","!(F)V", (void*) PaintGlue::setStrokeMiter},
996    {"native_getStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
997    {"native_setStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
998    {"native_getStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
999    {"native_setStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
1000    {"native_getFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
1001    {"native_setShader","!(JJ)J", (void*) PaintGlue::setShader},
1002    {"native_setColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
1003    {"native_setXfermode","!(JJ)J", (void*) PaintGlue::setXfermode},
1004    {"native_setPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
1005    {"native_setMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
1006    {"native_setTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
1007    {"native_setRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
1008    {"native_getTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
1009    {"native_setTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
1010    {"native_setTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale},
1011    {"isElegantTextHeight","!()Z", (void*) PaintGlue::isElegantTextHeight},
1012    {"setElegantTextHeight","!(Z)V", (void*) PaintGlue::setElegantTextHeight},
1013    {"getTextSize","!()F", (void*) PaintGlue::getTextSize},
1014    {"setTextSize","!(F)V", (void*) PaintGlue::setTextSize},
1015    {"getTextScaleX","!()F", (void*) PaintGlue::getTextScaleX},
1016    {"setTextScaleX","!(F)V", (void*) PaintGlue::setTextScaleX},
1017    {"getTextSkewX","!()F", (void*) PaintGlue::getTextSkewX},
1018    {"setTextSkewX","!(F)V", (void*) PaintGlue::setTextSkewX},
1019    {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
1020    {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
1021    {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings},
1022    {"native_getHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit},
1023    {"native_setHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit},
1024    {"ascent","!()F", (void*) PaintGlue::ascent},
1025    {"descent","!()F", (void*) PaintGlue::descent},
1026
1027    {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics},
1028    {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt},
1029    {"native_measureText","([CIII)F", (void*) PaintGlue::measureText_CIII},
1030    {"native_measureText","(Ljava/lang/String;I)F", (void*) PaintGlue::measureText_StringI},
1031    {"native_measureText","(Ljava/lang/String;III)F", (void*) PaintGlue::measureText_StringIII},
1032    {"native_breakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
1033    {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
1034    {"native_getTextWidths","(JJ[CIII[F)I", (void*) PaintGlue::getTextWidths___CIII_F},
1035    {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) PaintGlue::getTextWidths__StringIII_F},
1036    {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F",
1037        (void*) PaintGlue::getTextRunAdvances___CIIIIZ_FI},
1038    {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F",
1039        (void*) PaintGlue::getTextRunAdvances__StringIIIIZ_FI},
1040
1041    {"native_getTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
1042    {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I",
1043        (void*) PaintGlue::getTextRunCursor__String},
1044    {"native_getTextPath","(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
1045    {"native_getTextPath","(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
1046    {"nativeGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V",
1047                                        (void*) PaintGlue::getStringBounds },
1048    {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
1049                                    (void*) PaintGlue::getCharArrayBounds },
1050
1051    {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
1052    {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
1053};
1054
1055int register_android_graphics_Paint(JNIEnv* env) {
1056    gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
1057    gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);
1058
1059    gFontMetrics_fieldID.top = GetFieldIDOrDie(env, gFontMetrics_class, "top", "F");
1060    gFontMetrics_fieldID.ascent = GetFieldIDOrDie(env, gFontMetrics_class, "ascent", "F");
1061    gFontMetrics_fieldID.descent = GetFieldIDOrDie(env, gFontMetrics_class, "descent", "F");
1062    gFontMetrics_fieldID.bottom = GetFieldIDOrDie(env, gFontMetrics_class, "bottom", "F");
1063    gFontMetrics_fieldID.leading = GetFieldIDOrDie(env, gFontMetrics_class, "leading", "F");
1064
1065    gFontMetricsInt_class = FindClassOrDie(env, "android/graphics/Paint$FontMetricsInt");
1066    gFontMetricsInt_class = MakeGlobalRefOrDie(env, gFontMetricsInt_class);
1067
1068    gFontMetricsInt_fieldID.top = GetFieldIDOrDie(env, gFontMetricsInt_class, "top", "I");
1069    gFontMetricsInt_fieldID.ascent = GetFieldIDOrDie(env, gFontMetricsInt_class, "ascent", "I");
1070    gFontMetricsInt_fieldID.descent = GetFieldIDOrDie(env, gFontMetricsInt_class, "descent", "I");
1071    gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
1072    gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");
1073
1074    gPaint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Paint"));
1075    gPaint_nativeInstanceID = GetFieldIDOrDie(env, gPaint_class, "mNativePaint", "J");
1076    gPaint_nativeTypefaceID = GetFieldIDOrDie(env, gPaint_class, "mNativeTypeface", "J");
1077
1078    return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods));
1079}
1080
1081}
1082