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