• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libs/android_runtime/android/graphics/Paint.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #define LOG_TAG "Paint"
19 
20 #include <utils/Log.h>
21 
22 #include "jni.h"
23 #include "GraphicsJNI.h"
24 #include <android_runtime/AndroidRuntime.h>
25 
26 #include "SkBlurDrawLooper.h"
27 #include "SkColorFilter.h"
28 #include "SkMaskFilter.h"
29 #include "SkRasterizer.h"
30 #include "SkShader.h"
31 #include "SkTypeface.h"
32 #include "SkXfermode.h"
33 #include "unicode/ushape.h"
34 #include "TextLayout.h"
35 
36 // temporary for debugging
37 #include <Caches.h>
38 #include <utils/Log.h>
39 
40 namespace android {
41 
42 struct JMetricsID {
43     jfieldID    top;
44     jfieldID    ascent;
45     jfieldID    descent;
46     jfieldID    bottom;
47     jfieldID    leading;
48 };
49 
50 static jclass   gFontMetrics_class;
51 static JMetricsID gFontMetrics_fieldID;
52 
53 static jclass   gFontMetricsInt_class;
54 static JMetricsID gFontMetricsInt_fieldID;
55 
defaultSettingsForAndroid(SkPaint * paint)56 static void defaultSettingsForAndroid(SkPaint* paint) {
57     // utf16 is required for java
58     paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
59 }
60 
61 class SkPaintGlue {
62 public:
63     enum MoveOpt {
64         AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
65     };
66 
finalizer(JNIEnv * env,jobject clazz,SkPaint * obj)67     static void finalizer(JNIEnv* env, jobject clazz, SkPaint* obj) {
68         delete obj;
69     }
70 
init(JNIEnv * env,jobject clazz)71     static SkPaint* init(JNIEnv* env, jobject clazz) {
72         SkPaint* obj = new SkPaint();
73         defaultSettingsForAndroid(obj);
74         return obj;
75     }
76 
intiWithPaint(JNIEnv * env,jobject clazz,SkPaint * paint)77     static SkPaint* intiWithPaint(JNIEnv* env, jobject clazz, SkPaint* paint) {
78         SkPaint* obj = new SkPaint(*paint);
79         return obj;
80     }
81 
reset(JNIEnv * env,jobject clazz,SkPaint * obj)82     static void reset(JNIEnv* env, jobject clazz, SkPaint* obj) {
83         obj->reset();
84         defaultSettingsForAndroid(obj);
85     }
86 
assign(JNIEnv * env,jobject clazz,SkPaint * dst,const SkPaint * src)87     static void assign(JNIEnv* env, jobject clazz, SkPaint* dst, const SkPaint* src) {
88         *dst = *src;
89     }
90 
getFlags(JNIEnv * env,jobject paint)91     static jint getFlags(JNIEnv* env, jobject paint) {
92         NPE_CHECK_RETURN_ZERO(env, paint);
93         return GraphicsJNI::getNativePaint(env, paint)->getFlags();
94     }
95 
setFlags(JNIEnv * env,jobject paint,jint flags)96     static void setFlags(JNIEnv* env, jobject paint, jint flags) {
97         NPE_CHECK_RETURN_VOID(env, paint);
98         GraphicsJNI::getNativePaint(env, paint)->setFlags(flags);
99     }
100 
getHinting(JNIEnv * env,jobject paint)101     static jint getHinting(JNIEnv* env, jobject paint) {
102         NPE_CHECK_RETURN_ZERO(env, paint);
103         return GraphicsJNI::getNativePaint(env, paint)->getHinting()
104                 == SkPaint::kNo_Hinting ? 0 : 1;
105     }
106 
setHinting(JNIEnv * env,jobject paint,jint mode)107     static void setHinting(JNIEnv* env, jobject paint, jint mode) {
108         NPE_CHECK_RETURN_VOID(env, paint);
109         GraphicsJNI::getNativePaint(env, paint)->setHinting(
110                 mode == 0 ? SkPaint::kNo_Hinting : SkPaint::kSlight_Hinting);
111     }
112 
setAntiAlias(JNIEnv * env,jobject paint,jboolean aa)113     static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) {
114         NPE_CHECK_RETURN_VOID(env, paint);
115         GraphicsJNI::getNativePaint(env, paint)->setAntiAlias(aa);
116     }
117 
setLinearText(JNIEnv * env,jobject paint,jboolean linearText)118     static void setLinearText(JNIEnv* env, jobject paint, jboolean linearText) {
119         NPE_CHECK_RETURN_VOID(env, paint);
120         GraphicsJNI::getNativePaint(env, paint)->setLinearText(linearText);
121     }
122 
setSubpixelText(JNIEnv * env,jobject paint,jboolean subpixelText)123     static void setSubpixelText(JNIEnv* env, jobject paint, jboolean subpixelText) {
124         NPE_CHECK_RETURN_VOID(env, paint);
125         GraphicsJNI::getNativePaint(env, paint)->setSubpixelText(subpixelText);
126     }
127 
setUnderlineText(JNIEnv * env,jobject paint,jboolean underlineText)128     static void setUnderlineText(JNIEnv* env, jobject paint, jboolean underlineText) {
129         NPE_CHECK_RETURN_VOID(env, paint);
130         GraphicsJNI::getNativePaint(env, paint)->setUnderlineText(underlineText);
131     }
132 
setStrikeThruText(JNIEnv * env,jobject paint,jboolean strikeThruText)133     static void setStrikeThruText(JNIEnv* env, jobject paint, jboolean strikeThruText) {
134         NPE_CHECK_RETURN_VOID(env, paint);
135         GraphicsJNI::getNativePaint(env, paint)->setStrikeThruText(strikeThruText);
136     }
137 
setFakeBoldText(JNIEnv * env,jobject paint,jboolean fakeBoldText)138     static void setFakeBoldText(JNIEnv* env, jobject paint, jboolean fakeBoldText) {
139         NPE_CHECK_RETURN_VOID(env, paint);
140         GraphicsJNI::getNativePaint(env, paint)->setFakeBoldText(fakeBoldText);
141     }
142 
setFilterBitmap(JNIEnv * env,jobject paint,jboolean filterBitmap)143     static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) {
144         NPE_CHECK_RETURN_VOID(env, paint);
145         GraphicsJNI::getNativePaint(env, paint)->setFilterBitmap(filterBitmap);
146     }
147 
setDither(JNIEnv * env,jobject paint,jboolean dither)148     static void setDither(JNIEnv* env, jobject paint, jboolean dither) {
149         NPE_CHECK_RETURN_VOID(env, paint);
150         GraphicsJNI::getNativePaint(env, paint)->setDither(dither);
151     }
152 
getStyle(JNIEnv * env,jobject clazz,SkPaint * obj)153     static jint getStyle(JNIEnv* env, jobject clazz, SkPaint* obj) {
154         return obj->getStyle();
155     }
156 
setStyle(JNIEnv * env,jobject clazz,SkPaint * obj,SkPaint::Style style)157     static void setStyle(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Style style) {
158         obj->setStyle(style);
159     }
160 
getColor(JNIEnv * env,jobject paint)161     static jint getColor(JNIEnv* env, jobject paint) {
162         NPE_CHECK_RETURN_ZERO(env, paint);
163         return GraphicsJNI::getNativePaint(env, paint)->getColor();
164     }
165 
getAlpha(JNIEnv * env,jobject paint)166     static jint getAlpha(JNIEnv* env, jobject paint) {
167         NPE_CHECK_RETURN_ZERO(env, paint);
168         return GraphicsJNI::getNativePaint(env, paint)->getAlpha();
169     }
170 
setColor(JNIEnv * env,jobject paint,jint color)171     static void setColor(JNIEnv* env, jobject paint, jint color) {
172         NPE_CHECK_RETURN_VOID(env, paint);
173         GraphicsJNI::getNativePaint(env, paint)->setColor(color);
174     }
175 
setAlpha(JNIEnv * env,jobject paint,jint a)176     static void setAlpha(JNIEnv* env, jobject paint, jint a) {
177         NPE_CHECK_RETURN_VOID(env, paint);
178         GraphicsJNI::getNativePaint(env, paint)->setAlpha(a);
179     }
180 
getStrokeWidth(JNIEnv * env,jobject paint)181     static jfloat getStrokeWidth(JNIEnv* env, jobject paint) {
182         NPE_CHECK_RETURN_ZERO(env, paint);
183         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeWidth());
184     }
185 
setStrokeWidth(JNIEnv * env,jobject paint,jfloat width)186     static void setStrokeWidth(JNIEnv* env, jobject paint, jfloat width) {
187         NPE_CHECK_RETURN_VOID(env, paint);
188         GraphicsJNI::getNativePaint(env, paint)->setStrokeWidth(SkFloatToScalar(width));
189     }
190 
getStrokeMiter(JNIEnv * env,jobject paint)191     static jfloat getStrokeMiter(JNIEnv* env, jobject paint) {
192         NPE_CHECK_RETURN_ZERO(env, paint);
193         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeMiter());
194     }
195 
setStrokeMiter(JNIEnv * env,jobject paint,jfloat miter)196     static void setStrokeMiter(JNIEnv* env, jobject paint, jfloat miter) {
197         NPE_CHECK_RETURN_VOID(env, paint);
198         GraphicsJNI::getNativePaint(env, paint)->setStrokeMiter(SkFloatToScalar(miter));
199     }
200 
getStrokeCap(JNIEnv * env,jobject clazz,SkPaint * obj)201     static jint getStrokeCap(JNIEnv* env, jobject clazz, SkPaint* obj) {
202         return obj->getStrokeCap();
203     }
204 
setStrokeCap(JNIEnv * env,jobject clazz,SkPaint * obj,SkPaint::Cap cap)205     static void setStrokeCap(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Cap cap) {
206         obj->setStrokeCap(cap);
207     }
208 
getStrokeJoin(JNIEnv * env,jobject clazz,SkPaint * obj)209     static jint getStrokeJoin(JNIEnv* env, jobject clazz, SkPaint* obj) {
210         return obj->getStrokeJoin();
211     }
212 
setStrokeJoin(JNIEnv * env,jobject clazz,SkPaint * obj,SkPaint::Join join)213     static void setStrokeJoin(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Join join) {
214         obj->setStrokeJoin(join);
215     }
216 
getFillPath(JNIEnv * env,jobject clazz,SkPaint * obj,SkPath * src,SkPath * dst)217     static jboolean getFillPath(JNIEnv* env, jobject clazz, SkPaint* obj, SkPath* src, SkPath* dst) {
218         return obj->getFillPath(*src, dst);
219     }
220 
setShader(JNIEnv * env,jobject clazz,SkPaint * obj,SkShader * shader)221     static SkShader* setShader(JNIEnv* env, jobject clazz, SkPaint* obj, SkShader* shader) {
222         return obj->setShader(shader);
223     }
224 
setColorFilter(JNIEnv * env,jobject clazz,SkPaint * obj,SkColorFilter * filter)225     static SkColorFilter* setColorFilter(JNIEnv* env, jobject clazz, SkPaint* obj, SkColorFilter* filter) {
226         return obj->setColorFilter(filter);
227     }
228 
setXfermode(JNIEnv * env,jobject clazz,SkPaint * obj,SkXfermode * xfermode)229     static SkXfermode* setXfermode(JNIEnv* env, jobject clazz, SkPaint* obj, SkXfermode* xfermode) {
230         return obj->setXfermode(xfermode);
231     }
232 
setPathEffect(JNIEnv * env,jobject clazz,SkPaint * obj,SkPathEffect * effect)233     static SkPathEffect* setPathEffect(JNIEnv* env, jobject clazz, SkPaint* obj, SkPathEffect* effect) {
234         return obj->setPathEffect(effect);
235     }
236 
setMaskFilter(JNIEnv * env,jobject clazz,SkPaint * obj,SkMaskFilter * maskfilter)237     static SkMaskFilter* setMaskFilter(JNIEnv* env, jobject clazz, SkPaint* obj, SkMaskFilter* maskfilter) {
238         return obj->setMaskFilter(maskfilter);
239     }
240 
setTypeface(JNIEnv * env,jobject clazz,SkPaint * obj,SkTypeface * typeface)241     static SkTypeface* setTypeface(JNIEnv* env, jobject clazz, SkPaint* obj, SkTypeface* typeface) {
242         return obj->setTypeface(typeface);
243     }
244 
setRasterizer(JNIEnv * env,jobject clazz,SkPaint * obj,SkRasterizer * rasterizer)245     static SkRasterizer* setRasterizer(JNIEnv* env, jobject clazz, SkPaint* obj, SkRasterizer* rasterizer) {
246         return obj->setRasterizer(rasterizer);
247     }
248 
getTextAlign(JNIEnv * env,jobject clazz,SkPaint * obj)249     static jint getTextAlign(JNIEnv* env, jobject clazz, SkPaint* obj) {
250         return obj->getTextAlign();
251     }
252 
setTextAlign(JNIEnv * env,jobject clazz,SkPaint * obj,SkPaint::Align align)253     static void setTextAlign(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Align align) {
254         obj->setTextAlign(align);
255     }
256 
getTextSize(JNIEnv * env,jobject paint)257     static jfloat getTextSize(JNIEnv* env, jobject paint) {
258         NPE_CHECK_RETURN_ZERO(env, paint);
259         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSize());
260     }
261 
setTextSize(JNIEnv * env,jobject paint,jfloat textSize)262     static void setTextSize(JNIEnv* env, jobject paint, jfloat textSize) {
263         NPE_CHECK_RETURN_VOID(env, paint);
264         GraphicsJNI::getNativePaint(env, paint)->setTextSize(SkFloatToScalar(textSize));
265     }
266 
getTextScaleX(JNIEnv * env,jobject paint)267     static jfloat getTextScaleX(JNIEnv* env, jobject paint) {
268         NPE_CHECK_RETURN_ZERO(env, paint);
269         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextScaleX());
270     }
271 
setTextScaleX(JNIEnv * env,jobject paint,jfloat scaleX)272     static void setTextScaleX(JNIEnv* env, jobject paint, jfloat scaleX) {
273         NPE_CHECK_RETURN_VOID(env, paint);
274         GraphicsJNI::getNativePaint(env, paint)->setTextScaleX(SkFloatToScalar(scaleX));
275     }
276 
getTextSkewX(JNIEnv * env,jobject paint)277     static jfloat getTextSkewX(JNIEnv* env, jobject paint) {
278         NPE_CHECK_RETURN_ZERO(env, paint);
279         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSkewX());
280     }
281 
setTextSkewX(JNIEnv * env,jobject paint,jfloat skewX)282     static void setTextSkewX(JNIEnv* env, jobject paint, jfloat skewX) {
283         NPE_CHECK_RETURN_VOID(env, paint);
284         GraphicsJNI::getNativePaint(env, paint)->setTextSkewX(SkFloatToScalar(skewX));
285     }
286 
ascent(JNIEnv * env,jobject paint)287     static jfloat ascent(JNIEnv* env, jobject paint) {
288         NPE_CHECK_RETURN_ZERO(env, paint);
289         SkPaint::FontMetrics    metrics;
290         (void)GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
291         return SkScalarToFloat(metrics.fAscent);
292     }
293 
descent(JNIEnv * env,jobject paint)294     static jfloat descent(JNIEnv* env, jobject paint) {
295         NPE_CHECK_RETURN_ZERO(env, paint);
296         SkPaint::FontMetrics    metrics;
297         (void)GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
298         return SkScalarToFloat(metrics.fDescent);
299     }
300 
getFontMetrics(JNIEnv * env,jobject paint,jobject metricsObj)301     static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) {
302         NPE_CHECK_RETURN_ZERO(env, paint);
303         SkPaint::FontMetrics metrics;
304         SkScalar             spacing = GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
305 
306         if (metricsObj) {
307             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
308             env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
309             env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
310             env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
311             env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
312             env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
313         }
314         return SkScalarToFloat(spacing);
315     }
316 
getFontMetricsInt(JNIEnv * env,jobject paint,jobject metricsObj)317     static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) {
318         NPE_CHECK_RETURN_ZERO(env, paint);
319         SkPaint::FontMetrics metrics;
320 
321         GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
322         int ascent = SkScalarRound(metrics.fAscent);
323         int descent = SkScalarRound(metrics.fDescent);
324         int leading = SkScalarRound(metrics.fLeading);
325 
326         if (metricsObj) {
327             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
328             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloor(metrics.fTop));
329             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
330             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
331             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeil(metrics.fBottom));
332             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
333         }
334         return descent - ascent + leading;
335     }
336 
measureText_CII(JNIEnv * env,jobject jpaint,jcharArray text,int index,int count)337     static jfloat measureText_CII(JNIEnv* env, jobject jpaint, jcharArray text, int index, int count) {
338         NPE_CHECK_RETURN_ZERO(env, jpaint);
339         NPE_CHECK_RETURN_ZERO(env, text);
340 
341         size_t textLength = env->GetArrayLength(text);
342         if ((index | count) < 0 || (size_t)(index + count) > textLength) {
343             doThrowAIOOBE(env);
344             return 0;
345         }
346         if (count == 0) {
347             return 0;
348         }
349 
350         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
351         const jchar* textArray = env->GetCharArrayElements(text, NULL);
352         jfloat result = 0;
353 #if RTL_USE_HARFBUZZ
354         TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
355                 paint->getFlags(), NULL /* dont need all advances */, &result);
356 #else
357         // we double count, since measureText wants a byteLength
358         SkScalar width = paint->measureText(textArray + index, count << 1);
359         result = SkScalarToFloat(width);
360 #endif
361         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
362         return result;
363     }
364 
measureText_StringII(JNIEnv * env,jobject jpaint,jstring text,int start,int end)365     static jfloat measureText_StringII(JNIEnv* env, jobject jpaint, jstring text, int start, int end) {
366         NPE_CHECK_RETURN_ZERO(env, jpaint);
367         NPE_CHECK_RETURN_ZERO(env, text);
368 
369         size_t textLength = env->GetStringLength(text);
370         int count = end - start;
371         if ((start | count) < 0 || (size_t)end > textLength) {
372             doThrowAIOOBE(env);
373             return 0;
374         }
375         if (count == 0) {
376             return 0;
377         }
378 
379         const jchar* textArray = env->GetStringChars(text, NULL);
380         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
381         jfloat width = 0;
382 
383 #if RTL_USE_HARFBUZZ
384         TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
385                 paint->getFlags(), NULL /* dont need all advances */, &width);
386 #else
387 
388         width = SkScalarToFloat(paint->measureText(textArray + start, count << 1));
389 #endif
390         env->ReleaseStringChars(text, textArray);
391         return width;
392     }
393 
measureText_String(JNIEnv * env,jobject jpaint,jstring text)394     static jfloat measureText_String(JNIEnv* env, jobject jpaint, jstring text) {
395         NPE_CHECK_RETURN_ZERO(env, jpaint);
396         NPE_CHECK_RETURN_ZERO(env, text);
397 
398         size_t textLength = env->GetStringLength(text);
399         if (textLength == 0) {
400             return 0;
401         }
402 
403         const jchar* textArray = env->GetStringChars(text, NULL);
404         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
405         jfloat width = 0;
406 
407 #if RTL_USE_HARFBUZZ
408         TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
409                 paint->getFlags(), NULL /* dont need all advances */, &width);
410 #else
411         width = SkScalarToFloat(paint->measureText(textArray, textLength << 1));
412 #endif
413         env->ReleaseStringChars(text, textArray);
414         return width;
415     }
416 
dotextwidths(JNIEnv * env,SkPaint * paint,const jchar text[],int count,jfloatArray widths)417     static int dotextwidths(JNIEnv* env, SkPaint* paint, const jchar text[], int count, jfloatArray widths) {
418         NPE_CHECK_RETURN_ZERO(env, paint);
419         NPE_CHECK_RETURN_ZERO(env, text);
420 
421         if (count < 0 || !widths) {
422             doThrowAIOOBE(env);
423             return 0;
424         }
425         if (count == 0) {
426             return 0;
427         }
428         size_t widthsLength = env->GetArrayLength(widths);
429         if ((size_t)count > widthsLength) {
430             doThrowAIOOBE(env);
431             return 0;
432         }
433 
434         AutoJavaFloatArray autoWidths(env, widths, count);
435         jfloat* widthsArray = autoWidths.ptr();
436 
437 #if RTL_USE_HARFBUZZ
438         TextLayout::getTextRunAdvances(paint, text, 0, count, count,
439                 paint->getFlags(), widthsArray, NULL /* dont need totalAdvance */);
440 #else
441         SkScalar* scalarArray = (SkScalar*)widthsArray;
442 
443         count = paint->getTextWidths(text, count << 1, scalarArray);
444         for (int i = 0; i < count; i++) {
445             widthsArray[i] = SkScalarToFloat(scalarArray[i]);
446         }
447 #endif
448         return count;
449     }
450 
getTextWidths___CII_F(JNIEnv * env,jobject clazz,SkPaint * paint,jcharArray text,int index,int count,jfloatArray widths)451     static int getTextWidths___CII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloatArray widths) {
452         const jchar* textArray = env->GetCharArrayElements(text, NULL);
453         count = dotextwidths(env, paint, textArray + index, count, widths);
454         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
455                                       JNI_ABORT);
456         return count;
457     }
458 
getTextWidths__StringII_F(JNIEnv * env,jobject clazz,SkPaint * paint,jstring text,int start,int end,jfloatArray widths)459     static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
460             int start, int end, jfloatArray widths) {
461         const jchar* textArray = env->GetStringChars(text, NULL);
462         int count = dotextwidths(env, paint, textArray + start, end - start, widths);
463         env->ReleaseStringChars(text, textArray);
464         return count;
465     }
466 
doTextGlyphs(JNIEnv * env,SkPaint * paint,const jchar * text,jint start,jint count,jint contextCount,jint flags,jcharArray glyphs)467     static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count,
468             jint contextCount, jint flags, jcharArray glyphs) {
469         NPE_CHECK_RETURN_ZERO(env, paint);
470         NPE_CHECK_RETURN_ZERO(env, text);
471 
472         if ((start | count | contextCount) < 0 || contextCount < count || !glyphs) {
473             doThrowAIOOBE(env);
474             return 0;
475         }
476         if (count == 0) {
477             return 0;
478         }
479         size_t glypthsLength = env->GetArrayLength(glyphs);
480         if ((size_t)count > glypthsLength) {
481             doThrowAIOOBE(env);
482             return 0;
483         }
484 
485         jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
486 
487         TextLayoutCacheValue value;
488         value.computeValues(paint, text, start, count, contextCount, flags);
489         const jchar* shapedGlyphs = value.getGlyphs();
490         size_t glyphsCount = value.getGlyphsCount();
491         memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount);
492 
493         env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
494         return glyphsCount;
495     }
496 
getTextGlyphs__StringIIIII_C(JNIEnv * env,jobject clazz,SkPaint * paint,jstring text,jint start,jint end,jint contextStart,jint contextEnd,jint flags,jcharArray glyphs)497     static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint,
498             jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
499             jcharArray glyphs) {
500         const jchar* textArray = env->GetStringChars(text, NULL);
501         int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart,
502                 end - start, contextEnd - contextStart, flags, glyphs);
503         env->ReleaseStringChars(text, textArray);
504         return count;
505     }
506 
doTextRunAdvances(JNIEnv * env,SkPaint * paint,const jchar * text,jint start,jint count,jint contextCount,jint flags,jfloatArray advances,jint advancesIndex)507     static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
508                                     jint start, jint count, jint contextCount, jint flags,
509                                     jfloatArray advances, jint advancesIndex) {
510         NPE_CHECK_RETURN_ZERO(env, paint);
511         NPE_CHECK_RETURN_ZERO(env, text);
512 
513         if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
514             doThrowAIOOBE(env);
515             return 0;
516         }
517         if (count == 0) {
518             return 0;
519         }
520         if (advances) {
521             size_t advancesLength = env->GetArrayLength(advances);
522             if ((size_t)count > advancesLength) {
523                 doThrowAIOOBE(env);
524                 return 0;
525             }
526         }
527         jfloat advancesArray[count];
528         jfloat totalAdvance = 0;
529 
530         TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
531                                        advancesArray, &totalAdvance);
532 
533         if (advances != NULL) {
534             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
535         }
536         return totalAdvance;
537     }
538 
doTextRunAdvancesICU(JNIEnv * env,SkPaint * paint,const jchar * text,jint start,jint count,jint contextCount,jint flags,jfloatArray advances,jint advancesIndex)539     static jfloat doTextRunAdvancesICU(JNIEnv *env, SkPaint *paint, const jchar *text,
540                                     jint start, jint count, jint contextCount, jint flags,
541                                     jfloatArray advances, jint advancesIndex) {
542         NPE_CHECK_RETURN_ZERO(env, paint);
543         NPE_CHECK_RETURN_ZERO(env, text);
544 
545         if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
546             doThrowAIOOBE(env);
547             return 0;
548         }
549         if (count == 0) {
550             return 0;
551         }
552         if (advances) {
553             size_t advancesLength = env->GetArrayLength(advances);
554             if ((size_t)count > advancesLength) {
555                 doThrowAIOOBE(env);
556                 return 0;
557             }
558         }
559 
560         jfloat advancesArray[count];
561         jfloat totalAdvance = 0;
562 
563         TextLayout::getTextRunAdvancesICU(paint, text, start, count, contextCount, flags,
564                                        advancesArray, totalAdvance);
565 
566         if (advances != NULL) {
567             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
568         }
569         return totalAdvance;
570     }
571 
getTextRunAdvances___CIIIII_FII(JNIEnv * env,jobject clazz,SkPaint * paint,jcharArray text,jint index,jint count,jint contextIndex,jint contextCount,jint flags,jfloatArray advances,jint advancesIndex,jint reserved)572     static float getTextRunAdvances___CIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
573             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
574             jint flags, jfloatArray advances, jint advancesIndex, jint reserved) {
575         jchar* textArray = env->GetCharArrayElements(text, NULL);
576         jfloat result = (reserved == 0) ?
577                 doTextRunAdvances(env, paint, textArray + contextIndex, index - contextIndex,
578                         count, contextCount, flags, advances, advancesIndex) :
579                 doTextRunAdvancesICU(env, paint, textArray + contextIndex, index - contextIndex,
580                         count, contextCount, flags, advances, advancesIndex);
581         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
582         return result;
583     }
584 
getTextRunAdvances__StringIIIII_FII(JNIEnv * env,jobject clazz,SkPaint * paint,jstring text,jint start,jint end,jint contextStart,jint contextEnd,jint flags,jfloatArray advances,jint advancesIndex,jint reserved)585     static float getTextRunAdvances__StringIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
586             jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
587             jfloatArray advances, jint advancesIndex, jint reserved) {
588         const jchar* textArray = env->GetStringChars(text, NULL);
589         jfloat result = (reserved == 0) ?
590                 doTextRunAdvances(env, paint, textArray + contextStart, start - contextStart,
591                         end - start, contextEnd - contextStart, flags, advances, advancesIndex) :
592                 doTextRunAdvancesICU(env, paint, textArray + contextStart, start - contextStart,
593                         end - start, contextEnd - contextStart, flags, advances, advancesIndex);
594         env->ReleaseStringChars(text, textArray);
595         return result;
596     }
597 
doTextRunCursor(JNIEnv * env,SkPaint * paint,const jchar * text,jint start,jint count,jint flags,jint offset,jint opt)598     static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start,
599             jint count, jint flags, jint offset, jint opt) {
600 #if RTL_USE_HARFBUZZ
601         jfloat scalarArray[count];
602 
603         TextLayout::getTextRunAdvances(paint, text, start, count, count, flags,
604                 scalarArray, NULL /* dont need totalAdvance */);
605 #else
606         SkScalar scalarArray[count];
607         jchar buffer[count];
608 
609         // this is where we'd call harfbuzz
610         // for now we just use ushape.c and widths returned from skia
611 
612         int widths;
613         if (flags & 0x1) { // rtl, call arabic shaping in case
614             UErrorCode status = U_ZERO_ERROR;
615             // Use fixed length since we need to keep start and count valid
616             u_shapeArabic(text + start, count, buffer, count,
617                     U_SHAPE_LENGTH_FIXED_SPACES_NEAR | U_SHAPE_TEXT_DIRECTION_LOGICAL |
618                     U_SHAPE_LETTERS_SHAPE | U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
619             // we shouldn't fail unless there's an out of memory condition,
620             // in which case we're hosed anyway
621             for (int i = 0; i < count; ++i) {
622               if (buffer[i] == 0xffff) {
623                 buffer[i] = 0x200b; // zero-width-space for skia
624               }
625             }
626             widths = paint->getTextWidths(buffer, count << 1, scalarArray);
627         } else {
628             widths = paint->getTextWidths(text + start, count << 1, scalarArray);
629         }
630 
631         if (widths < count) {
632             // Skia operates on code points, not code units, so surrogate pairs return only one
633             // value. Expand the result so we have one value per UTF-16 code unit.
634 
635             // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
636             // leaving the remaining widths zero.  Not nice.
637             const jchar *chars = text + start;
638             for (int i = count, p = widths - 1; --i > p;) {
639                 if (chars[i] >= 0xdc00 && chars[i] < 0xe000 &&
640                         chars[i-1] >= 0xd800 && chars[i-1] < 0xdc00) {
641                     scalarArray[i] = 0;
642                 } else {
643                   scalarArray[i] = scalarArray[--p];
644                 }
645             }
646         }
647 #endif
648         jint pos = offset - start;
649         switch (opt) {
650         case AFTER:
651           if (pos < count) {
652             pos += 1;
653           }
654           // fall through
655         case AT_OR_AFTER:
656           while (pos < count && scalarArray[pos] == 0) {
657             ++pos;
658           }
659           break;
660         case BEFORE:
661           if (pos > 0) {
662             --pos;
663           }
664           // fall through
665         case AT_OR_BEFORE:
666           while (pos > 0 && scalarArray[pos] == 0) {
667             --pos;
668           }
669           break;
670         case AT:
671         default:
672           if (scalarArray[pos] == 0) {
673             pos = -1;
674           }
675           break;
676         }
677 
678         if (pos != -1) {
679           pos += start;
680         }
681 
682         return pos;
683     }
684 
getTextRunCursor___C(JNIEnv * env,jobject clazz,SkPaint * paint,jcharArray text,jint contextStart,jint contextCount,jint flags,jint offset,jint cursorOpt)685     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text,
686             jint contextStart, jint contextCount, jint flags, jint offset, jint cursorOpt) {
687         jchar* textArray = env->GetCharArrayElements(text, NULL);
688         jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, flags,
689                 offset, cursorOpt);
690         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
691         return result;
692     }
693 
getTextRunCursor__String(JNIEnv * env,jobject clazz,SkPaint * paint,jstring text,jint contextStart,jint contextEnd,jint flags,jint offset,jint cursorOpt)694     static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
695             jint contextStart, jint contextEnd, jint flags, jint offset, jint cursorOpt) {
696         const jchar* textArray = env->GetStringChars(text, NULL);
697         jint result = doTextRunCursor(env, paint, textArray, contextStart,
698                 contextEnd - contextStart, flags, offset, cursorOpt);
699         env->ReleaseStringChars(text, textArray);
700         return result;
701     }
702 
getTextPath(JNIEnv * env,SkPaint * paint,const jchar * text,jint count,jint bidiFlags,jfloat x,jfloat y,SkPath * path)703     static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count,
704                             jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
705         TextLayout::getTextPath(paint, text, count, bidiFlags, x, y, path);
706     }
707 
getTextPath___C(JNIEnv * env,jobject clazz,SkPaint * paint,jint bidiFlags,jcharArray text,int index,int count,jfloat x,jfloat y,SkPath * path)708     static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
709             jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
710         const jchar* textArray = env->GetCharArrayElements(text, NULL);
711         getTextPath(env, paint, textArray + index, count, bidiFlags, x, y, path);
712         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
713     }
714 
getTextPath__String(JNIEnv * env,jobject clazz,SkPaint * paint,jint bidiFlags,jstring text,int start,int end,jfloat x,jfloat y,SkPath * path)715     static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
716             jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
717         const jchar* textArray = env->GetStringChars(text, NULL);
718         getTextPath(env, paint, textArray + start, end - start, bidiFlags, x, y, path);
719         env->ReleaseStringChars(text, textArray);
720     }
721 
setShadowLayer(JNIEnv * env,jobject jpaint,jfloat radius,jfloat dx,jfloat dy,int color)722     static void setShadowLayer(JNIEnv* env, jobject jpaint, jfloat radius,
723                                jfloat dx, jfloat dy, int color) {
724         NPE_CHECK_RETURN_VOID(env, jpaint);
725 
726         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
727         if (radius <= 0) {
728             paint->setLooper(NULL);
729         }
730         else {
731             paint->setLooper(new SkBlurDrawLooper(SkFloatToScalar(radius),
732                                                   SkFloatToScalar(dx),
733                                                   SkFloatToScalar(dy),
734                                                   (SkColor)color))->unref();
735         }
736     }
737 
breakText(JNIEnv * env,const SkPaint & paint,const jchar text[],int count,float maxWidth,jfloatArray jmeasured,SkPaint::TextBufferDirection tbd)738     static int breakText(JNIEnv* env, const SkPaint& paint, const jchar text[],
739                          int count, float maxWidth, jfloatArray jmeasured,
740                          SkPaint::TextBufferDirection tbd) {
741         SkASSERT(paint.getTextEncoding() == SkPaint::kUTF16_TextEncoding);
742 
743         SkScalar     measured;
744         size_t       bytes = paint.breakText(text, count << 1,
745                                    SkFloatToScalar(maxWidth), &measured, tbd);
746         SkASSERT((bytes & 1) == 0);
747 
748         if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
749             AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
750             jfloat* array = autoMeasured.ptr();
751             array[0] = SkScalarToFloat(measured);
752         }
753         return bytes >> 1;
754     }
755 
breakTextC(JNIEnv * env,jobject jpaint,jcharArray jtext,int index,int count,float maxWidth,jfloatArray jmeasuredWidth)756     static int breakTextC(JNIEnv* env, jobject jpaint, jcharArray jtext,
757             int index, int count, float maxWidth, jfloatArray jmeasuredWidth) {
758         NPE_CHECK_RETURN_ZERO(env, jpaint);
759         NPE_CHECK_RETURN_ZERO(env, jtext);
760 
761         SkPaint::TextBufferDirection tbd;
762         if (count < 0) {
763             tbd = SkPaint::kBackward_TextBufferDirection;
764             count = -count;
765         }
766         else {
767             tbd = SkPaint::kForward_TextBufferDirection;
768         }
769 
770         if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
771             doThrowAIOOBE(env);
772             return 0;
773         }
774 
775         SkPaint*     paint = GraphicsJNI::getNativePaint(env, jpaint);
776         const jchar* text = env->GetCharArrayElements(jtext, NULL);
777         count = breakText(env, *paint, text + index, count, maxWidth,
778                           jmeasuredWidth, tbd);
779         env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
780                                       JNI_ABORT);
781         return count;
782     }
783 
breakTextS(JNIEnv * env,jobject jpaint,jstring jtext,bool forwards,float maxWidth,jfloatArray jmeasuredWidth)784     static int breakTextS(JNIEnv* env, jobject jpaint, jstring jtext,
785                 bool forwards, float maxWidth, jfloatArray jmeasuredWidth) {
786         NPE_CHECK_RETURN_ZERO(env, jpaint);
787         NPE_CHECK_RETURN_ZERO(env, jtext);
788 
789         SkPaint::TextBufferDirection tbd = forwards ?
790                                         SkPaint::kForward_TextBufferDirection :
791                                         SkPaint::kBackward_TextBufferDirection;
792 
793         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
794         int count = env->GetStringLength(jtext);
795         const jchar* text = env->GetStringChars(jtext, NULL);
796         count = breakText(env, *paint, text, count, maxWidth,
797                           jmeasuredWidth, tbd);
798         env->ReleaseStringChars(jtext, text);
799         return count;
800     }
801 
doTextBounds(JNIEnv * env,const jchar * text,int count,jobject bounds,const SkPaint & paint)802     static void doTextBounds(JNIEnv* env, const jchar* text, int count,
803                              jobject bounds, const SkPaint& paint)
804     {
805         SkRect  r;
806         SkIRect ir;
807 
808         paint.measureText(text, count << 1, &r);
809         r.roundOut(&ir);
810         GraphicsJNI::irect_to_jrect(ir, env, bounds);
811     }
812 
getStringBounds(JNIEnv * env,jobject,const SkPaint * paint,jstring text,int start,int end,jobject bounds)813     static void getStringBounds(JNIEnv* env, jobject, const SkPaint* paint,
814                                 jstring text, int start, int end, jobject bounds)
815     {
816         const jchar* textArray = env->GetStringChars(text, NULL);
817         doTextBounds(env, textArray + start, end - start, bounds, *paint);
818         env->ReleaseStringChars(text, textArray);
819     }
820 
getCharArrayBounds(JNIEnv * env,jobject,const SkPaint * paint,jcharArray text,int index,int count,jobject bounds)821     static void getCharArrayBounds(JNIEnv* env, jobject, const SkPaint* paint,
822                         jcharArray text, int index, int count, jobject bounds)
823     {
824         const jchar* textArray = env->GetCharArrayElements(text, NULL);
825         doTextBounds(env, textArray + index, count, bounds, *paint);
826         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
827                                       JNI_ABORT);
828     }
829 
830 };
831 
832 static JNINativeMethod methods[] = {
833     {"finalizer", "(I)V", (void*) SkPaintGlue::finalizer},
834     {"native_init","()I", (void*) SkPaintGlue::init},
835     {"native_initWithPaint","(I)I", (void*) SkPaintGlue::intiWithPaint},
836     {"native_reset","(I)V", (void*) SkPaintGlue::reset},
837     {"native_set","(II)V", (void*) SkPaintGlue::assign},
838     {"getFlags","()I", (void*) SkPaintGlue::getFlags},
839     {"setFlags","(I)V", (void*) SkPaintGlue::setFlags},
840     {"getHinting","()I", (void*) SkPaintGlue::getHinting},
841     {"setHinting","(I)V", (void*) SkPaintGlue::setHinting},
842     {"setAntiAlias","(Z)V", (void*) SkPaintGlue::setAntiAlias},
843     {"setSubpixelText","(Z)V", (void*) SkPaintGlue::setSubpixelText},
844     {"setLinearText","(Z)V", (void*) SkPaintGlue::setLinearText},
845     {"setUnderlineText","(Z)V", (void*) SkPaintGlue::setUnderlineText},
846     {"setStrikeThruText","(Z)V", (void*) SkPaintGlue::setStrikeThruText},
847     {"setFakeBoldText","(Z)V", (void*) SkPaintGlue::setFakeBoldText},
848     {"setFilterBitmap","(Z)V", (void*) SkPaintGlue::setFilterBitmap},
849     {"setDither","(Z)V", (void*) SkPaintGlue::setDither},
850     {"native_getStyle","(I)I", (void*) SkPaintGlue::getStyle},
851     {"native_setStyle","(II)V", (void*) SkPaintGlue::setStyle},
852     {"getColor","()I", (void*) SkPaintGlue::getColor},
853     {"setColor","(I)V", (void*) SkPaintGlue::setColor},
854     {"getAlpha","()I", (void*) SkPaintGlue::getAlpha},
855     {"setAlpha","(I)V", (void*) SkPaintGlue::setAlpha},
856     {"getStrokeWidth","()F", (void*) SkPaintGlue::getStrokeWidth},
857     {"setStrokeWidth","(F)V", (void*) SkPaintGlue::setStrokeWidth},
858     {"getStrokeMiter","()F", (void*) SkPaintGlue::getStrokeMiter},
859     {"setStrokeMiter","(F)V", (void*) SkPaintGlue::setStrokeMiter},
860     {"native_getStrokeCap","(I)I", (void*) SkPaintGlue::getStrokeCap},
861     {"native_setStrokeCap","(II)V", (void*) SkPaintGlue::setStrokeCap},
862     {"native_getStrokeJoin","(I)I", (void*) SkPaintGlue::getStrokeJoin},
863     {"native_setStrokeJoin","(II)V", (void*) SkPaintGlue::setStrokeJoin},
864     {"native_getFillPath","(III)Z", (void*) SkPaintGlue::getFillPath},
865     {"native_setShader","(II)I", (void*) SkPaintGlue::setShader},
866     {"native_setColorFilter","(II)I", (void*) SkPaintGlue::setColorFilter},
867     {"native_setXfermode","(II)I", (void*) SkPaintGlue::setXfermode},
868     {"native_setPathEffect","(II)I", (void*) SkPaintGlue::setPathEffect},
869     {"native_setMaskFilter","(II)I", (void*) SkPaintGlue::setMaskFilter},
870     {"native_setTypeface","(II)I", (void*) SkPaintGlue::setTypeface},
871     {"native_setRasterizer","(II)I", (void*) SkPaintGlue::setRasterizer},
872     {"native_getTextAlign","(I)I", (void*) SkPaintGlue::getTextAlign},
873     {"native_setTextAlign","(II)V", (void*) SkPaintGlue::setTextAlign},
874     {"getTextSize","()F", (void*) SkPaintGlue::getTextSize},
875     {"setTextSize","(F)V", (void*) SkPaintGlue::setTextSize},
876     {"getTextScaleX","()F", (void*) SkPaintGlue::getTextScaleX},
877     {"setTextScaleX","(F)V", (void*) SkPaintGlue::setTextScaleX},
878     {"getTextSkewX","()F", (void*) SkPaintGlue::getTextSkewX},
879     {"setTextSkewX","(F)V", (void*) SkPaintGlue::setTextSkewX},
880     {"ascent","()F", (void*) SkPaintGlue::ascent},
881     {"descent","()F", (void*) SkPaintGlue::descent},
882     {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)SkPaintGlue::getFontMetrics},
883     {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)SkPaintGlue::getFontMetricsInt},
884     {"native_measureText","([CII)F", (void*) SkPaintGlue::measureText_CII},
885     {"native_measureText","(Ljava/lang/String;)F", (void*) SkPaintGlue::measureText_String},
886     {"native_measureText","(Ljava/lang/String;II)F", (void*) SkPaintGlue::measureText_StringII},
887     {"native_breakText","([CIIF[F)I", (void*) SkPaintGlue::breakTextC},
888     {"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
889     {"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
890     {"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
891     {"native_getTextRunAdvances","(I[CIIIII[FII)F",
892         (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FII},
893     {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FII)F",
894         (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FII},
895 
896 
897     {"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
898         (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
899     {"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
900     {"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I",
901         (void*) SkPaintGlue::getTextRunCursor__String},
902     {"native_getTextPath","(II[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
903     {"native_getTextPath","(IILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
904     {"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
905                                         (void*) SkPaintGlue::getStringBounds },
906     {"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",
907                                     (void*) SkPaintGlue::getCharArrayBounds },
908     {"nSetShadowLayer", "(FFFI)V", (void*)SkPaintGlue::setShadowLayer}
909 };
910 
req_fieldID(jfieldID id)911 static jfieldID req_fieldID(jfieldID id) {
912     SkASSERT(id);
913     return id;
914 }
915 
register_android_graphics_Paint(JNIEnv * env)916 int register_android_graphics_Paint(JNIEnv* env) {
917     gFontMetrics_class = env->FindClass("android/graphics/Paint$FontMetrics");
918     SkASSERT(gFontMetrics_class);
919     gFontMetrics_class = (jclass)env->NewGlobalRef(gFontMetrics_class);
920 
921     gFontMetrics_fieldID.top = req_fieldID(env->GetFieldID(gFontMetrics_class, "top", "F"));
922     gFontMetrics_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetrics_class, "ascent", "F"));
923     gFontMetrics_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetrics_class, "descent", "F"));
924     gFontMetrics_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetrics_class, "bottom", "F"));
925     gFontMetrics_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetrics_class, "leading", "F"));
926 
927     gFontMetricsInt_class = env->FindClass("android/graphics/Paint$FontMetricsInt");
928     SkASSERT(gFontMetricsInt_class);
929     gFontMetricsInt_class = (jclass)env->NewGlobalRef(gFontMetricsInt_class);
930 
931     gFontMetricsInt_fieldID.top = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "top", "I"));
932     gFontMetricsInt_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "ascent", "I"));
933     gFontMetricsInt_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "descent", "I"));
934     gFontMetricsInt_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "bottom", "I"));
935     gFontMetricsInt_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "leading", "I"));
936 
937     int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Paint", methods,
938         sizeof(methods) / sizeof(methods[0]));
939     return result;
940 }
941 
942 }
943