blob: 98d7fce0106092cdda5bdcd75442346f36bd7c62 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* libs/android_runtime/android/graphics/Paint.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
Elliott Hughes8451b252011-04-07 19:17:57 -07005** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008**
Elliott Hughes8451b252011-04-07 19:17:57 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010**
Elliott Hughes8451b252011-04-07 19:17:57 -070011** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080015** limitations under the License.
16*/
17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018#include "jni.h"
19#include "GraphicsJNI.h"
20#include <android_runtime/AndroidRuntime.h>
21
22#include "SkBlurDrawLooper.h"
23#include "SkColorFilter.h"
24#include "SkMaskFilter.h"
25#include "SkRasterizer.h"
26#include "SkShader.h"
27#include "SkTypeface.h"
28#include "SkXfermode.h"
Doug Felt0c702b82010-05-14 10:55:42 -070029#include "unicode/ushape.h"
Doug Feltf7cb1f72010-07-01 16:20:43 -070030#include "TextLayout.h"
Doug Felt0c702b82010-05-14 10:55:42 -070031
32// temporary for debugging
Chet Haase5c13d892010-10-08 08:37:55 -070033#include <Caches.h>
Doug Felt0c702b82010-05-14 10:55:42 -070034#include <utils/Log.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035
36namespace android {
37
38struct JMetricsID {
39 jfieldID top;
40 jfieldID ascent;
41 jfieldID descent;
42 jfieldID bottom;
43 jfieldID leading;
44};
45
46static jclass gFontMetrics_class;
47static JMetricsID gFontMetrics_fieldID;
48
49static jclass gFontMetricsInt_class;
50static JMetricsID gFontMetricsInt_fieldID;
51
Mike Reed3d63e012009-07-27 09:50:31 -040052static void defaultSettingsForAndroid(SkPaint* paint) {
53 // looks best we decided
54 paint->setHinting(SkPaint::kSlight_Hinting);
55 // utf16 is required for java
56 paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
57}
58
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059class SkPaintGlue {
60public:
Doug Felt0c702b82010-05-14 10:55:42 -070061 enum MoveOpt {
62 AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
63 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
65 static void finalizer(JNIEnv* env, jobject clazz, SkPaint* obj) {
66 delete obj;
67 }
68
69 static SkPaint* init(JNIEnv* env, jobject clazz) {
70 SkPaint* obj = new SkPaint();
Mike Reed3d63e012009-07-27 09:50:31 -040071 defaultSettingsForAndroid(obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 return obj;
73 }
74
75 static SkPaint* intiWithPaint(JNIEnv* env, jobject clazz, SkPaint* paint) {
76 SkPaint* obj = new SkPaint(*paint);
77 return obj;
78 }
Elliott Hughes8451b252011-04-07 19:17:57 -070079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 static void reset(JNIEnv* env, jobject clazz, SkPaint* obj) {
81 obj->reset();
Mike Reed3d63e012009-07-27 09:50:31 -040082 defaultSettingsForAndroid(obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 }
Elliott Hughes8451b252011-04-07 19:17:57 -070084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 static void assign(JNIEnv* env, jobject clazz, SkPaint* dst, const SkPaint* src) {
86 *dst = *src;
87 }
Elliott Hughes8451b252011-04-07 19:17:57 -070088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 static jint getFlags(JNIEnv* env, jobject paint) {
90 NPE_CHECK_RETURN_ZERO(env, paint);
91 return GraphicsJNI::getNativePaint(env, paint)->getFlags();
92 }
Elliott Hughes8451b252011-04-07 19:17:57 -070093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 static void setFlags(JNIEnv* env, jobject paint, jint flags) {
95 NPE_CHECK_RETURN_VOID(env, paint);
96 GraphicsJNI::getNativePaint(env, paint)->setFlags(flags);
97 }
Elliott Hughes8451b252011-04-07 19:17:57 -070098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) {
100 NPE_CHECK_RETURN_VOID(env, paint);
101 GraphicsJNI::getNativePaint(env, paint)->setAntiAlias(aa);
102 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 static void setLinearText(JNIEnv* env, jobject paint, jboolean linearText) {
105 NPE_CHECK_RETURN_VOID(env, paint);
106 GraphicsJNI::getNativePaint(env, paint)->setLinearText(linearText);
107 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 static void setSubpixelText(JNIEnv* env, jobject paint, jboolean subpixelText) {
110 NPE_CHECK_RETURN_VOID(env, paint);
111 GraphicsJNI::getNativePaint(env, paint)->setSubpixelText(subpixelText);
112 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 static void setUnderlineText(JNIEnv* env, jobject paint, jboolean underlineText) {
115 NPE_CHECK_RETURN_VOID(env, paint);
116 GraphicsJNI::getNativePaint(env, paint)->setUnderlineText(underlineText);
117 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 static void setStrikeThruText(JNIEnv* env, jobject paint, jboolean strikeThruText) {
120 NPE_CHECK_RETURN_VOID(env, paint);
121 GraphicsJNI::getNativePaint(env, paint)->setStrikeThruText(strikeThruText);
122 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 static void setFakeBoldText(JNIEnv* env, jobject paint, jboolean fakeBoldText) {
125 NPE_CHECK_RETURN_VOID(env, paint);
126 GraphicsJNI::getNativePaint(env, paint)->setFakeBoldText(fakeBoldText);
127 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) {
130 NPE_CHECK_RETURN_VOID(env, paint);
131 GraphicsJNI::getNativePaint(env, paint)->setFilterBitmap(filterBitmap);
132 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 static void setDither(JNIEnv* env, jobject paint, jboolean dither) {
135 NPE_CHECK_RETURN_VOID(env, paint);
136 GraphicsJNI::getNativePaint(env, paint)->setDither(dither);
137 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 static jint getStyle(JNIEnv* env, jobject clazz, SkPaint* obj) {
140 return obj->getStyle();
141 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 static void setStyle(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Style style) {
144 obj->setStyle(style);
145 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 static jint getColor(JNIEnv* env, jobject paint) {
148 NPE_CHECK_RETURN_ZERO(env, paint);
149 return GraphicsJNI::getNativePaint(env, paint)->getColor();
150 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 static jint getAlpha(JNIEnv* env, jobject paint) {
153 NPE_CHECK_RETURN_ZERO(env, paint);
154 return GraphicsJNI::getNativePaint(env, paint)->getAlpha();
155 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 static void setColor(JNIEnv* env, jobject paint, jint color) {
158 NPE_CHECK_RETURN_VOID(env, paint);
159 GraphicsJNI::getNativePaint(env, paint)->setColor(color);
160 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 static void setAlpha(JNIEnv* env, jobject paint, jint a) {
163 NPE_CHECK_RETURN_VOID(env, paint);
164 GraphicsJNI::getNativePaint(env, paint)->setAlpha(a);
165 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 static jfloat getStrokeWidth(JNIEnv* env, jobject paint) {
168 NPE_CHECK_RETURN_ZERO(env, paint);
169 return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeWidth());
170 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 static void setStrokeWidth(JNIEnv* env, jobject paint, jfloat width) {
173 NPE_CHECK_RETURN_VOID(env, paint);
174 GraphicsJNI::getNativePaint(env, paint)->setStrokeWidth(SkFloatToScalar(width));
175 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 static jfloat getStrokeMiter(JNIEnv* env, jobject paint) {
178 NPE_CHECK_RETURN_ZERO(env, paint);
179 return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeMiter());
180 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 static void setStrokeMiter(JNIEnv* env, jobject paint, jfloat miter) {
183 NPE_CHECK_RETURN_VOID(env, paint);
184 GraphicsJNI::getNativePaint(env, paint)->setStrokeMiter(SkFloatToScalar(miter));
185 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 static jint getStrokeCap(JNIEnv* env, jobject clazz, SkPaint* obj) {
188 return obj->getStrokeCap();
189 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 static void setStrokeCap(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Cap cap) {
192 obj->setStrokeCap(cap);
193 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 static jint getStrokeJoin(JNIEnv* env, jobject clazz, SkPaint* obj) {
196 return obj->getStrokeJoin();
197 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 static void setStrokeJoin(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Join join) {
200 obj->setStrokeJoin(join);
201 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 static jboolean getFillPath(JNIEnv* env, jobject clazz, SkPaint* obj, SkPath* src, SkPath* dst) {
204 return obj->getFillPath(*src, dst);
205 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 static SkShader* setShader(JNIEnv* env, jobject clazz, SkPaint* obj, SkShader* shader) {
208 return obj->setShader(shader);
209 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 static SkColorFilter* setColorFilter(JNIEnv* env, jobject clazz, SkPaint* obj, SkColorFilter* filter) {
212 return obj->setColorFilter(filter);
213 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 static SkXfermode* setXfermode(JNIEnv* env, jobject clazz, SkPaint* obj, SkXfermode* xfermode) {
216 return obj->setXfermode(xfermode);
217 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 static SkPathEffect* setPathEffect(JNIEnv* env, jobject clazz, SkPaint* obj, SkPathEffect* effect) {
220 return obj->setPathEffect(effect);
221 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 static SkMaskFilter* setMaskFilter(JNIEnv* env, jobject clazz, SkPaint* obj, SkMaskFilter* maskfilter) {
224 return obj->setMaskFilter(maskfilter);
225 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 static SkTypeface* setTypeface(JNIEnv* env, jobject clazz, SkPaint* obj, SkTypeface* typeface) {
228 return obj->setTypeface(typeface);
229 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 static SkRasterizer* setRasterizer(JNIEnv* env, jobject clazz, SkPaint* obj, SkRasterizer* rasterizer) {
232 return obj->setRasterizer(rasterizer);
233 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 static jint getTextAlign(JNIEnv* env, jobject clazz, SkPaint* obj) {
236 return obj->getTextAlign();
237 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 static void setTextAlign(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Align align) {
240 obj->setTextAlign(align);
241 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 static jfloat getTextSize(JNIEnv* env, jobject paint) {
244 NPE_CHECK_RETURN_ZERO(env, paint);
245 return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSize());
246 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 static void setTextSize(JNIEnv* env, jobject paint, jfloat textSize) {
249 NPE_CHECK_RETURN_VOID(env, paint);
250 GraphicsJNI::getNativePaint(env, paint)->setTextSize(SkFloatToScalar(textSize));
251 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 static jfloat getTextScaleX(JNIEnv* env, jobject paint) {
254 NPE_CHECK_RETURN_ZERO(env, paint);
255 return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextScaleX());
256 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 static void setTextScaleX(JNIEnv* env, jobject paint, jfloat scaleX) {
259 NPE_CHECK_RETURN_VOID(env, paint);
260 GraphicsJNI::getNativePaint(env, paint)->setTextScaleX(SkFloatToScalar(scaleX));
261 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 static jfloat getTextSkewX(JNIEnv* env, jobject paint) {
264 NPE_CHECK_RETURN_ZERO(env, paint);
265 return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSkewX());
266 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 static void setTextSkewX(JNIEnv* env, jobject paint, jfloat skewX) {
269 NPE_CHECK_RETURN_VOID(env, paint);
270 GraphicsJNI::getNativePaint(env, paint)->setTextSkewX(SkFloatToScalar(skewX));
271 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 static jfloat ascent(JNIEnv* env, jobject paint) {
274 NPE_CHECK_RETURN_ZERO(env, paint);
275 SkPaint::FontMetrics metrics;
276 (void)GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
277 return SkScalarToFloat(metrics.fAscent);
278 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 static jfloat descent(JNIEnv* env, jobject paint) {
281 NPE_CHECK_RETURN_ZERO(env, paint);
282 SkPaint::FontMetrics metrics;
283 (void)GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
284 return SkScalarToFloat(metrics.fDescent);
285 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) {
288 NPE_CHECK_RETURN_ZERO(env, paint);
289 SkPaint::FontMetrics metrics;
290 SkScalar spacing = GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
291
292 if (metricsObj) {
293 SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
294 env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
295 env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
296 env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
297 env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
298 env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
299 }
300 return SkScalarToFloat(spacing);
301 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) {
304 NPE_CHECK_RETURN_ZERO(env, paint);
305 SkPaint::FontMetrics metrics;
Elliott Hughes8451b252011-04-07 19:17:57 -0700306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
308 int ascent = SkScalarRound(metrics.fAscent);
309 int descent = SkScalarRound(metrics.fDescent);
310 int leading = SkScalarRound(metrics.fLeading);
311
312 if (metricsObj) {
313 SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
314 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloor(metrics.fTop));
315 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
316 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
317 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeil(metrics.fBottom));
318 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
319 }
320 return descent - ascent + leading;
321 }
322
323 static jfloat measureText_CII(JNIEnv* env, jobject jpaint, jcharArray text, int index, int count) {
324 NPE_CHECK_RETURN_ZERO(env, jpaint);
325 NPE_CHECK_RETURN_ZERO(env, text);
326
327 size_t textLength = env->GetArrayLength(text);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 if ((index | count) < 0 || (size_t)(index + count) > textLength) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700329 doThrowAIOOBE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 return 0;
331 }
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700332 if (count == 0) {
333 return 0;
334 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700336 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 const jchar* textArray = env->GetCharArrayElements(text, NULL);
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700338 jfloat result = 0;
339#if RTL_USE_HARFBUZZ
Fabrice Di Meglio8fb50712011-05-13 18:51:21 -0700340 TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
341 paint->getFlags(), NULL /* dont need all advances */, result);
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700342#else
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 // we double count, since measureText wants a byteLength
344 SkScalar width = paint->measureText(textArray + index, count << 1);
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700345 result = SkScalarToFloat(width);
346#endif
347 env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
348 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 static jfloat measureText_StringII(JNIEnv* env, jobject jpaint, jstring text, int start, int end) {
352 NPE_CHECK_RETURN_ZERO(env, jpaint);
353 NPE_CHECK_RETURN_ZERO(env, text);
Elliott Hughes8451b252011-04-07 19:17:57 -0700354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 int count = end - start;
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700356 if ((start | count) < 0) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700357 doThrowAIOOBE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 return 0;
359 }
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700360 if (count == 0) {
361 return 0;
362 }
363 size_t textLength = env->GetStringLength(text);
364 if ((size_t)count > textLength) {
365 doThrowAIOOBE(env);
366 return 0;
367 }
368
369 const jchar* textArray = env->GetStringChars(text, NULL);
370 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700371 jfloat width = 0;
Elliott Hughes8451b252011-04-07 19:17:57 -0700372
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700373#if RTL_USE_HARFBUZZ
Fabrice Di Meglio8fb50712011-05-13 18:51:21 -0700374 TextLayout::getTextRunAdvances(paint, textArray, start, count, end,
375 paint->getFlags(), NULL /* dont need all advances */, width);
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700376#else
377
378 width = SkScalarToFloat(paint->measureText(textArray + start, count << 1));
379#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 env->ReleaseStringChars(text, textArray);
381 return width;
382 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 static jfloat measureText_String(JNIEnv* env, jobject jpaint, jstring text) {
385 NPE_CHECK_RETURN_ZERO(env, jpaint);
386 NPE_CHECK_RETURN_ZERO(env, text);
Elliott Hughes8451b252011-04-07 19:17:57 -0700387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 size_t textLength = env->GetStringLength(text);
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700389 if (textLength == 0) {
390 return 0;
391 }
392
393 const jchar* textArray = env->GetStringChars(text, NULL);
394 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700395 jfloat width = 0;
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700396
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700397#if RTL_USE_HARFBUZZ
Fabrice Di Meglio8fb50712011-05-13 18:51:21 -0700398 TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
399 paint->getFlags(), NULL /* dont need all advances */, width);
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700400#else
401 width = SkScalarToFloat(paint->measureText(textArray, textLength << 1));
402#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 env->ReleaseStringChars(text, textArray);
404 return width;
405 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 static int dotextwidths(JNIEnv* env, SkPaint* paint, const jchar text[], int count, jfloatArray widths) {
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700408 NPE_CHECK_RETURN_ZERO(env, paint);
409 NPE_CHECK_RETURN_ZERO(env, text);
410
411 if (count < 0 || !widths) {
412 doThrowAIOOBE(env);
413 return 0;
414 }
415 if (count == 0) {
416 return 0;
417 }
418 size_t widthsLength = env->GetArrayLength(widths);
419 if ((size_t)count > widthsLength) {
420 doThrowAIOOBE(env);
421 return 0;
422 }
423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 AutoJavaFloatArray autoWidths(env, widths, count);
425 jfloat* widthsArray = autoWidths.ptr();
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700426
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700427#if RTL_USE_HARFBUZZ
428 jfloat totalAdvance;
429
Fabrice Di Meglio8fb50712011-05-13 18:51:21 -0700430 TextLayout::getTextRunAdvances(paint, text, 0, count, count,
431 paint->getFlags(), widthsArray, totalAdvance);
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700432#else
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 SkScalar* scalarArray = (SkScalar*)widthsArray;
434
Elliott Hughes8451b252011-04-07 19:17:57 -0700435 count = paint->getTextWidths(text, count << 1, scalarArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 for (int i = 0; i < count; i++) {
437 widthsArray[i] = SkScalarToFloat(scalarArray[i]);
438 }
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700439#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 return count;
441 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 static int getTextWidths___CII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloatArray widths) {
444 const jchar* textArray = env->GetCharArrayElements(text, NULL);
445 count = dotextwidths(env, paint, textArray + index, count, widths);
446 env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
Elliott Hughes8451b252011-04-07 19:17:57 -0700447 JNI_ABORT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 return count;
449 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700450
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800451 static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
452 int start, int end, jfloatArray widths) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 const jchar* textArray = env->GetStringChars(text, NULL);
454 int count = dotextwidths(env, paint, textArray + start, end - start, widths);
455 env->ReleaseStringChars(text, textArray);
456 return count;
457 }
Doug Felt0c702b82010-05-14 10:55:42 -0700458
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800459 static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count,
460 jint contextCount, jint flags, jcharArray glyphs) {
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700461 NPE_CHECK_RETURN_ZERO(env, paint);
462 NPE_CHECK_RETURN_ZERO(env, text);
463
464 if ((start | count | contextCount) < 0 || contextCount < count || !glyphs) {
465 doThrowAIOOBE(env);
466 return 0;
467 }
468 if (count == 0) {
469 return 0;
470 }
471 size_t glypthsLength = env->GetArrayLength(glyphs);
472 if ((size_t)count > glypthsLength) {
473 doThrowAIOOBE(env);
474 return 0;
475 }
476
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800477 jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
478 HB_ShaperItem shaperItem;
479 HB_FontRec font;
480 FontData fontData;
Fabrice Di Meglio1de9e7a2011-04-05 13:43:18 -0700481 TextLayoutCacheValue::shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, text,
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800482 start, count, contextCount, flags);
483
484 int glyphCount = shaperItem.num_glyphs;
485 for (int i = 0; i < glyphCount; i++) {
486 glyphsArray[i] = (jchar) shaperItem.glyphs[i];
487 }
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700488 env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800489 return glyphCount;
490 }
491
492 static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint,
493 jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
494 jcharArray glyphs) {
495 const jchar* textArray = env->GetStringChars(text, NULL);
496 int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart,
497 end - start, contextEnd - contextStart, flags, glyphs);
498 env->ReleaseStringChars(text, textArray);
499 return count;
500 }
501
Doug Feltf7cb1f72010-07-01 16:20:43 -0700502 static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
503 jint start, jint count, jint contextCount, jint flags,
Doug Felt0c702b82010-05-14 10:55:42 -0700504 jfloatArray advances, jint advancesIndex) {
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700505 NPE_CHECK_RETURN_ZERO(env, paint);
506 NPE_CHECK_RETURN_ZERO(env, text);
507
508 if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
509 doThrowAIOOBE(env);
510 return 0;
511 }
512 if (count == 0) {
513 return 0;
514 }
515 if (advances) {
516 size_t advancesLength = env->GetArrayLength(advances);
517 if ((size_t)count > advancesLength) {
518 doThrowAIOOBE(env);
519 return 0;
520 }
521 }
Doug Felt0c702b82010-05-14 10:55:42 -0700522 jfloat advancesArray[count];
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700523 jfloat totalAdvance = 0;
Doug Felt0c702b82010-05-14 10:55:42 -0700524
Doug Feltf7cb1f72010-07-01 16:20:43 -0700525 TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
526 advancesArray, totalAdvance);
Doug Felt0c702b82010-05-14 10:55:42 -0700527
528 if (advances != NULL) {
529 env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
530 }
531 return totalAdvance;
532 }
533
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700534 static jfloat doTextRunAdvancesICU(JNIEnv *env, SkPaint *paint, const jchar *text,
535 jint start, jint count, jint contextCount, jint flags,
536 jfloatArray advances, jint advancesIndex) {
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700537 NPE_CHECK_RETURN_ZERO(env, paint);
538 NPE_CHECK_RETURN_ZERO(env, text);
539
540 if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
541 doThrowAIOOBE(env);
542 return 0;
543 }
544 if (count == 0) {
545 return 0;
546 }
547 if (advances) {
548 size_t advancesLength = env->GetArrayLength(advances);
549 if ((size_t)count > advancesLength) {
550 doThrowAIOOBE(env);
551 return 0;
552 }
553 }
554
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700555 jfloat advancesArray[count];
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700556 jfloat totalAdvance = 0;
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700557
558 TextLayout::getTextRunAdvancesICU(paint, text, start, count, contextCount, flags,
559 advancesArray, totalAdvance);
560
561 if (advances != NULL) {
562 env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
563 }
564 return totalAdvance;
565 }
566
Fabrice Di Meglio0a1413e2011-04-21 17:36:26 -0700567 static float getTextRunAdvances___CIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
Doug Felt0c702b82010-05-14 10:55:42 -0700568 jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
Fabrice Di Meglio0a1413e2011-04-21 17:36:26 -0700569 jint flags, jfloatArray advances, jint advancesIndex, jint reserved) {
Doug Felt0c702b82010-05-14 10:55:42 -0700570 jchar* textArray = env->GetCharArrayElements(text, NULL);
Fabrice Di Meglio0a1413e2011-04-21 17:36:26 -0700571 jfloat result = (reserved == 0) ?
572 doTextRunAdvances(env, paint, textArray + contextIndex, index - contextIndex,
573 count, contextCount, flags, advances, advancesIndex) :
574 doTextRunAdvancesICU(env, paint, textArray + contextIndex, index - contextIndex,
575 count, contextCount, flags, advances, advancesIndex);
Doug Felt0c702b82010-05-14 10:55:42 -0700576 env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
577 return result;
578 }
579
Fabrice Di Meglio0a1413e2011-04-21 17:36:26 -0700580 static float getTextRunAdvances__StringIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
Doug Felt0c702b82010-05-14 10:55:42 -0700581 jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
Fabrice Di Meglio0a1413e2011-04-21 17:36:26 -0700582 jfloatArray advances, jint advancesIndex, jint reserved) {
Doug Felt0c702b82010-05-14 10:55:42 -0700583 const jchar* textArray = env->GetStringChars(text, NULL);
Fabrice Di Meglio0a1413e2011-04-21 17:36:26 -0700584 jfloat result = (reserved == 0) ?
585 doTextRunAdvances(env, paint, textArray + contextStart, start - contextStart,
586 end - start, contextEnd - contextStart, flags, advances, advancesIndex) :
587 doTextRunAdvancesICU(env, paint, textArray + contextStart, start - contextStart,
588 end - start, contextEnd - contextStart, flags, advances, advancesIndex);
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700589 env->ReleaseStringChars(text, textArray);
590 return result;
591 }
592
Doug Felt0c702b82010-05-14 10:55:42 -0700593 static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start,
594 jint count, jint flags, jint offset, jint opt) {
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700595#if RTL_USE_HARFBUZZ
596 jfloat scalarArray[count];
Fabrice Di Meglio6ab90ed2011-08-08 16:19:38 -0700597 jfloat totalAdvance = 0;
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700598
599 TextLayout::getTextRunAdvances(paint, text, start, count, count, flags,
600 scalarArray, totalAdvance);
601#else
Doug Felt0c702b82010-05-14 10:55:42 -0700602 SkScalar scalarArray[count];
603 jchar buffer[count];
604
605 // this is where we'd call harfbuzz
606 // for now we just use ushape.c and widths returned from skia
607
608 int widths;
609 if (flags & 0x1) { // rtl, call arabic shaping in case
610 UErrorCode status = U_ZERO_ERROR;
611 // Use fixed length since we need to keep start and count valid
612 u_shapeArabic(text + start, count, buffer, count,
613 U_SHAPE_LENGTH_FIXED_SPACES_NEAR | U_SHAPE_TEXT_DIRECTION_LOGICAL |
614 U_SHAPE_LETTERS_SHAPE | U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
615 // we shouldn't fail unless there's an out of memory condition,
616 // in which case we're hosed anyway
617 for (int i = 0; i < count; ++i) {
618 if (buffer[i] == 0xffff) {
619 buffer[i] = 0x200b; // zero-width-space for skia
620 }
621 }
622 widths = paint->getTextWidths(buffer, count << 1, scalarArray);
623 } else {
624 widths = paint->getTextWidths(text + start, count << 1, scalarArray);
625 }
626
627 if (widths < count) {
628 // Skia operates on code points, not code units, so surrogate pairs return only one
629 // value. Expand the result so we have one value per UTF-16 code unit.
630
631 // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
632 // leaving the remaining widths zero. Not nice.
633 const jchar *chars = text + start;
634 for (int i = count, p = widths - 1; --i > p;) {
635 if (chars[i] >= 0xdc00 && chars[i] < 0xe000 &&
636 chars[i-1] >= 0xd800 && chars[i-1] < 0xdc00) {
637 scalarArray[i] = 0;
638 } else {
639 scalarArray[i] = scalarArray[--p];
640 }
641 }
642 }
Fabrice Di Meglio4f810c82011-04-19 14:53:58 -0700643#endif
Doug Felt0c702b82010-05-14 10:55:42 -0700644 jint pos = offset - start;
645 switch (opt) {
646 case AFTER:
647 if (pos < count) {
648 pos += 1;
649 }
650 // fall through
651 case AT_OR_AFTER:
652 while (pos < count && scalarArray[pos] == 0) {
653 ++pos;
654 }
655 break;
656 case BEFORE:
657 if (pos > 0) {
658 --pos;
659 }
660 // fall through
661 case AT_OR_BEFORE:
662 while (pos > 0 && scalarArray[pos] == 0) {
663 --pos;
664 }
665 break;
666 case AT:
667 default:
668 if (scalarArray[pos] == 0) {
669 pos = -1;
670 }
671 break;
672 }
673
674 if (pos != -1) {
675 pos += start;
676 }
677
678 return pos;
679 }
680
681 static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text,
682 jint contextStart, jint contextCount, jint flags, jint offset, jint cursorOpt) {
683 jchar* textArray = env->GetCharArrayElements(text, NULL);
684 jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, flags,
685 offset, cursorOpt);
686 env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
687 return result;
688 }
689
690 static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
691 jint contextStart, jint contextEnd, jint flags, jint offset, jint cursorOpt) {
692 const jchar* textArray = env->GetStringChars(text, NULL);
693 jint result = doTextRunCursor(env, paint, textArray, contextStart,
694 contextEnd - contextStart, flags, offset, cursorOpt);
695 env->ReleaseStringChars(text, textArray);
696 return result;
697 }
698
Doug Feltf7cb1f72010-07-01 16:20:43 -0700699 static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count,
700 jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
701 TextLayout::getTextPath(paint, text, count, bidiFlags, x, y, path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 }
Doug Feltf7cb1f72010-07-01 16:20:43 -0700703
704 static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
705 jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
706 const jchar* textArray = env->GetCharArrayElements(text, NULL);
707 getTextPath(env, paint, textArray + index, count, bidiFlags, x, y, path);
708 env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
709 }
710
711 static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
712 jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 const jchar* textArray = env->GetStringChars(text, NULL);
Doug Feltf7cb1f72010-07-01 16:20:43 -0700714 getTextPath(env, paint, textArray + start, end - start, bidiFlags, x, y, path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 env->ReleaseStringChars(text, textArray);
716 }
Doug Feltf7cb1f72010-07-01 16:20:43 -0700717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 static void setShadowLayer(JNIEnv* env, jobject jpaint, jfloat radius,
719 jfloat dx, jfloat dy, int color) {
720 NPE_CHECK_RETURN_VOID(env, jpaint);
Elliott Hughes8451b252011-04-07 19:17:57 -0700721
722 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 if (radius <= 0) {
724 paint->setLooper(NULL);
725 }
726 else {
727 paint->setLooper(new SkBlurDrawLooper(SkFloatToScalar(radius),
728 SkFloatToScalar(dx),
729 SkFloatToScalar(dy),
730 (SkColor)color))->unref();
731 }
732 }
733
734 static int breakText(JNIEnv* env, const SkPaint& paint, const jchar text[],
735 int count, float maxWidth, jfloatArray jmeasured,
736 SkPaint::TextBufferDirection tbd) {
737 SkASSERT(paint.getTextEncoding() == SkPaint::kUTF16_TextEncoding);
738
739 SkScalar measured;
740 size_t bytes = paint.breakText(text, count << 1,
741 SkFloatToScalar(maxWidth), &measured, tbd);
742 SkASSERT((bytes & 1) == 0);
743
744 if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
745 AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
746 jfloat* array = autoMeasured.ptr();
747 array[0] = SkScalarToFloat(measured);
748 }
749 return bytes >> 1;
750 }
751
752 static int breakTextC(JNIEnv* env, jobject jpaint, jcharArray jtext,
753 int index, int count, float maxWidth, jfloatArray jmeasuredWidth) {
754 NPE_CHECK_RETURN_ZERO(env, jpaint);
755 NPE_CHECK_RETURN_ZERO(env, jtext);
756
757 SkPaint::TextBufferDirection tbd;
758 if (count < 0) {
759 tbd = SkPaint::kBackward_TextBufferDirection;
760 count = -count;
761 }
762 else {
763 tbd = SkPaint::kForward_TextBufferDirection;
764 }
765
766 if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700767 doThrowAIOOBE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 return 0;
769 }
770
771 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
772 const jchar* text = env->GetCharArrayElements(jtext, NULL);
773 count = breakText(env, *paint, text + index, count, maxWidth,
774 jmeasuredWidth, tbd);
775 env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
776 JNI_ABORT);
777 return count;
778 }
779
780 static int breakTextS(JNIEnv* env, jobject jpaint, jstring jtext,
781 bool forwards, float maxWidth, jfloatArray jmeasuredWidth) {
782 NPE_CHECK_RETURN_ZERO(env, jpaint);
783 NPE_CHECK_RETURN_ZERO(env, jtext);
784
785 SkPaint::TextBufferDirection tbd = forwards ?
786 SkPaint::kForward_TextBufferDirection :
787 SkPaint::kBackward_TextBufferDirection;
788
789 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
790 int count = env->GetStringLength(jtext);
791 const jchar* text = env->GetStringChars(jtext, NULL);
792 count = breakText(env, *paint, text, count, maxWidth,
793 jmeasuredWidth, tbd);
794 env->ReleaseStringChars(jtext, text);
795 return count;
796 }
797
798 static void doTextBounds(JNIEnv* env, const jchar* text, int count,
799 jobject bounds, const SkPaint& paint)
800 {
801 SkRect r;
802 SkIRect ir;
Elliott Hughes8451b252011-04-07 19:17:57 -0700803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 paint.measureText(text, count << 1, &r);
805 r.roundOut(&ir);
806 GraphicsJNI::irect_to_jrect(ir, env, bounds);
807 }
808
809 static void getStringBounds(JNIEnv* env, jobject, const SkPaint* paint,
810 jstring text, int start, int end, jobject bounds)
811 {
812 const jchar* textArray = env->GetStringChars(text, NULL);
813 doTextBounds(env, textArray + start, end - start, bounds, *paint);
814 env->ReleaseStringChars(text, textArray);
815 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 static void getCharArrayBounds(JNIEnv* env, jobject, const SkPaint* paint,
818 jcharArray text, int index, int count, jobject bounds)
819 {
820 const jchar* textArray = env->GetCharArrayElements(text, NULL);
821 doTextBounds(env, textArray + index, count, bounds, *paint);
822 env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
823 JNI_ABORT);
824 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826};
827
828static JNINativeMethod methods[] = {
829 {"finalizer", "(I)V", (void*) SkPaintGlue::finalizer},
830 {"native_init","()I", (void*) SkPaintGlue::init},
831 {"native_initWithPaint","(I)I", (void*) SkPaintGlue::intiWithPaint},
832 {"native_reset","(I)V", (void*) SkPaintGlue::reset},
833 {"native_set","(II)V", (void*) SkPaintGlue::assign},
834 {"getFlags","()I", (void*) SkPaintGlue::getFlags},
835 {"setFlags","(I)V", (void*) SkPaintGlue::setFlags},
836 {"setAntiAlias","(Z)V", (void*) SkPaintGlue::setAntiAlias},
837 {"setSubpixelText","(Z)V", (void*) SkPaintGlue::setSubpixelText},
838 {"setLinearText","(Z)V", (void*) SkPaintGlue::setLinearText},
839 {"setUnderlineText","(Z)V", (void*) SkPaintGlue::setUnderlineText},
840 {"setStrikeThruText","(Z)V", (void*) SkPaintGlue::setStrikeThruText},
841 {"setFakeBoldText","(Z)V", (void*) SkPaintGlue::setFakeBoldText},
842 {"setFilterBitmap","(Z)V", (void*) SkPaintGlue::setFilterBitmap},
843 {"setDither","(Z)V", (void*) SkPaintGlue::setDither},
844 {"native_getStyle","(I)I", (void*) SkPaintGlue::getStyle},
845 {"native_setStyle","(II)V", (void*) SkPaintGlue::setStyle},
846 {"getColor","()I", (void*) SkPaintGlue::getColor},
847 {"setColor","(I)V", (void*) SkPaintGlue::setColor},
848 {"getAlpha","()I", (void*) SkPaintGlue::getAlpha},
849 {"setAlpha","(I)V", (void*) SkPaintGlue::setAlpha},
850 {"getStrokeWidth","()F", (void*) SkPaintGlue::getStrokeWidth},
851 {"setStrokeWidth","(F)V", (void*) SkPaintGlue::setStrokeWidth},
852 {"getStrokeMiter","()F", (void*) SkPaintGlue::getStrokeMiter},
853 {"setStrokeMiter","(F)V", (void*) SkPaintGlue::setStrokeMiter},
854 {"native_getStrokeCap","(I)I", (void*) SkPaintGlue::getStrokeCap},
855 {"native_setStrokeCap","(II)V", (void*) SkPaintGlue::setStrokeCap},
856 {"native_getStrokeJoin","(I)I", (void*) SkPaintGlue::getStrokeJoin},
857 {"native_setStrokeJoin","(II)V", (void*) SkPaintGlue::setStrokeJoin},
858 {"native_getFillPath","(III)Z", (void*) SkPaintGlue::getFillPath},
859 {"native_setShader","(II)I", (void*) SkPaintGlue::setShader},
860 {"native_setColorFilter","(II)I", (void*) SkPaintGlue::setColorFilter},
861 {"native_setXfermode","(II)I", (void*) SkPaintGlue::setXfermode},
862 {"native_setPathEffect","(II)I", (void*) SkPaintGlue::setPathEffect},
863 {"native_setMaskFilter","(II)I", (void*) SkPaintGlue::setMaskFilter},
864 {"native_setTypeface","(II)I", (void*) SkPaintGlue::setTypeface},
865 {"native_setRasterizer","(II)I", (void*) SkPaintGlue::setRasterizer},
866 {"native_getTextAlign","(I)I", (void*) SkPaintGlue::getTextAlign},
867 {"native_setTextAlign","(II)V", (void*) SkPaintGlue::setTextAlign},
868 {"getTextSize","()F", (void*) SkPaintGlue::getTextSize},
869 {"setTextSize","(F)V", (void*) SkPaintGlue::setTextSize},
870 {"getTextScaleX","()F", (void*) SkPaintGlue::getTextScaleX},
871 {"setTextScaleX","(F)V", (void*) SkPaintGlue::setTextScaleX},
872 {"getTextSkewX","()F", (void*) SkPaintGlue::getTextSkewX},
873 {"setTextSkewX","(F)V", (void*) SkPaintGlue::setTextSkewX},
874 {"ascent","()F", (void*) SkPaintGlue::ascent},
875 {"descent","()F", (void*) SkPaintGlue::descent},
876 {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)SkPaintGlue::getFontMetrics},
877 {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)SkPaintGlue::getFontMetricsInt},
Dianne Hackbornafa78962009-09-28 17:33:54 -0700878 {"native_measureText","([CII)F", (void*) SkPaintGlue::measureText_CII},
879 {"native_measureText","(Ljava/lang/String;)F", (void*) SkPaintGlue::measureText_String},
880 {"native_measureText","(Ljava/lang/String;II)F", (void*) SkPaintGlue::measureText_StringII},
881 {"native_breakText","([CIIF[F)I", (void*) SkPaintGlue::breakTextC},
882 {"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 {"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
884 {"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
Fabrice Di Meglio0a1413e2011-04-21 17:36:26 -0700885 {"native_getTextRunAdvances","(I[CIIIII[FII)F",
886 (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FII},
887 {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FII)F",
888 (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FII},
889
890
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800891 {"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
892 (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
Doug Felt0c702b82010-05-14 10:55:42 -0700893 {"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
894 {"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I",
895 (void*) SkPaintGlue::getTextRunCursor__String},
Doug Feltf7cb1f72010-07-01 16:20:43 -0700896 {"native_getTextPath","(II[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
897 {"native_getTextPath","(IILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 {"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
899 (void*) SkPaintGlue::getStringBounds },
900 {"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",
901 (void*) SkPaintGlue::getCharArrayBounds },
Romain Guy1e45aae2010-08-13 19:39:53 -0700902 {"nSetShadowLayer", "(FFFI)V", (void*)SkPaintGlue::setShadowLayer}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903};
904
905static jfieldID req_fieldID(jfieldID id) {
906 SkASSERT(id);
907 return id;
908}
909
910int register_android_graphics_Paint(JNIEnv* env) {
911 gFontMetrics_class = env->FindClass("android/graphics/Paint$FontMetrics");
912 SkASSERT(gFontMetrics_class);
913 gFontMetrics_class = (jclass)env->NewGlobalRef(gFontMetrics_class);
914
915 gFontMetrics_fieldID.top = req_fieldID(env->GetFieldID(gFontMetrics_class, "top", "F"));
916 gFontMetrics_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetrics_class, "ascent", "F"));
917 gFontMetrics_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetrics_class, "descent", "F"));
918 gFontMetrics_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetrics_class, "bottom", "F"));
919 gFontMetrics_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetrics_class, "leading", "F"));
920
921 gFontMetricsInt_class = env->FindClass("android/graphics/Paint$FontMetricsInt");
922 SkASSERT(gFontMetricsInt_class);
923 gFontMetricsInt_class = (jclass)env->NewGlobalRef(gFontMetricsInt_class);
924
925 gFontMetricsInt_fieldID.top = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "top", "I"));
926 gFontMetricsInt_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "ascent", "I"));
927 gFontMetricsInt_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "descent", "I"));
928 gFontMetricsInt_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "bottom", "I"));
929 gFontMetricsInt_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "leading", "I"));
930
931 int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Paint", methods,
932 sizeof(methods) / sizeof(methods[0]));
933 return result;
934}
935
936}