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