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