Paint.cpp revision a0398430fcf365fba6e42ad0bdca2fbf45ed6fe0
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#include <ScopedUtfChars.h> 26 27#include "SkBlurDrawLooper.h" 28#include "SkColorFilter.h" 29#include "SkMaskFilter.h" 30#include "SkRasterizer.h" 31#include "SkShader.h" 32#include "SkTypeface.h" 33#include "SkXfermode.h" 34#include "unicode/uloc.h" 35#include "unicode/ushape.h" 36#include "TextLayout.h" 37 38// temporary for debugging 39#include <Caches.h> 40#include <utils/Log.h> 41 42namespace android { 43 44struct JMetricsID { 45 jfieldID top; 46 jfieldID ascent; 47 jfieldID descent; 48 jfieldID bottom; 49 jfieldID leading; 50}; 51 52static jclass gFontMetrics_class; 53static JMetricsID gFontMetrics_fieldID; 54 55static jclass gFontMetricsInt_class; 56static JMetricsID gFontMetricsInt_fieldID; 57 58static void defaultSettingsForAndroid(SkPaint* paint) { 59 // GlyphID encoding is required because we are using Harfbuzz shaping 60 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 61 62 SkPaintOptionsAndroid paintOpts = paint->getPaintOptionsAndroid(); 63 paintOpts.setUseFontFallbacks(true); 64 paint->setPaintOptionsAndroid(paintOpts); 65} 66 67class SkPaintGlue { 68public: 69 enum MoveOpt { 70 AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT 71 }; 72 73 static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) { 74 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 75 delete obj; 76 } 77 78 static jlong init(JNIEnv* env, jobject clazz) { 79 SkPaint* obj = new SkPaint(); 80 defaultSettingsForAndroid(obj); 81 return reinterpret_cast<jlong>(obj); 82 } 83 84 static jlong initWithPaint(JNIEnv* env, jobject clazz, jlong paintHandle) { 85 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 86 SkPaint* obj = new SkPaint(*paint); 87 return reinterpret_cast<jlong>(obj); 88 } 89 90 static void reset(JNIEnv* env, jobject clazz, jlong objHandle) { 91 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 92 obj->reset(); 93 defaultSettingsForAndroid(obj); 94 } 95 96 static void assign(JNIEnv* env, jobject clazz, jlong dstPaintHandle, jlong srcPaintHandle) { 97 SkPaint* dst = reinterpret_cast<SkPaint*>(dstPaintHandle); 98 const SkPaint* src = reinterpret_cast<SkPaint*>(srcPaintHandle); 99 *dst = *src; 100 } 101 102 static jint getFlags(JNIEnv* env, jobject paint) { 103 NPE_CHECK_RETURN_ZERO(env, paint); 104 int result; 105 result = GraphicsJNI::getNativePaint(env, paint)->getFlags(); 106 return static_cast<jint>(result); 107 } 108 109 static void setFlags(JNIEnv* env, jobject paint, jint flags) { 110 NPE_CHECK_RETURN_VOID(env, paint); 111 GraphicsJNI::getNativePaint(env, paint)->setFlags(flags); 112 } 113 114 static jint getHinting(JNIEnv* env, jobject paint) { 115 NPE_CHECK_RETURN_ZERO(env, paint); 116 return GraphicsJNI::getNativePaint(env, paint)->getHinting() 117 == SkPaint::kNo_Hinting ? 0 : 1; 118 } 119 120 static void setHinting(JNIEnv* env, jobject paint, jint mode) { 121 NPE_CHECK_RETURN_VOID(env, paint); 122 GraphicsJNI::getNativePaint(env, paint)->setHinting( 123 mode == 0 ? SkPaint::kNo_Hinting : SkPaint::kNormal_Hinting); 124 } 125 126 static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) { 127 NPE_CHECK_RETURN_VOID(env, paint); 128 GraphicsJNI::getNativePaint(env, paint)->setAntiAlias(aa); 129 } 130 131 static void setLinearText(JNIEnv* env, jobject paint, jboolean linearText) { 132 NPE_CHECK_RETURN_VOID(env, paint); 133 GraphicsJNI::getNativePaint(env, paint)->setLinearText(linearText); 134 } 135 136 static void setSubpixelText(JNIEnv* env, jobject paint, jboolean subpixelText) { 137 NPE_CHECK_RETURN_VOID(env, paint); 138 GraphicsJNI::getNativePaint(env, paint)->setSubpixelText(subpixelText); 139 } 140 141 static void setUnderlineText(JNIEnv* env, jobject paint, jboolean underlineText) { 142 NPE_CHECK_RETURN_VOID(env, paint); 143 GraphicsJNI::getNativePaint(env, paint)->setUnderlineText(underlineText); 144 } 145 146 static void setStrikeThruText(JNIEnv* env, jobject paint, jboolean strikeThruText) { 147 NPE_CHECK_RETURN_VOID(env, paint); 148 GraphicsJNI::getNativePaint(env, paint)->setStrikeThruText(strikeThruText); 149 } 150 151 static void setFakeBoldText(JNIEnv* env, jobject paint, jboolean fakeBoldText) { 152 NPE_CHECK_RETURN_VOID(env, paint); 153 GraphicsJNI::getNativePaint(env, paint)->setFakeBoldText(fakeBoldText); 154 } 155 156 static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) { 157 NPE_CHECK_RETURN_VOID(env, paint); 158 GraphicsJNI::getNativePaint(env, paint)->setFilterBitmap(filterBitmap); 159 } 160 161 static void setDither(JNIEnv* env, jobject paint, jboolean dither) { 162 NPE_CHECK_RETURN_VOID(env, paint); 163 GraphicsJNI::getNativePaint(env, paint)->setDither(dither); 164 } 165 166 static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) { 167 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 168 return static_cast<jint>(obj->getStyle()); 169 } 170 171 static void setStyle(JNIEnv* env, jobject clazz, jlong objHandle, jint styleHandle) { 172 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 173 SkPaint::Style style = static_cast<SkPaint::Style>(styleHandle); 174 obj->setStyle(style); 175 } 176 177 static jint getColor(JNIEnv* env, jobject paint) { 178 NPE_CHECK_RETURN_ZERO(env, paint); 179 int color; 180 color = GraphicsJNI::getNativePaint(env, paint)->getColor(); 181 return static_cast<jint>(color); 182 } 183 184 static jint getAlpha(JNIEnv* env, jobject paint) { 185 NPE_CHECK_RETURN_ZERO(env, paint); 186 int alpha; 187 alpha = GraphicsJNI::getNativePaint(env, paint)->getAlpha(); 188 return static_cast<jint>(alpha); 189 } 190 191 static void setColor(JNIEnv* env, jobject paint, jint color) { 192 NPE_CHECK_RETURN_VOID(env, paint); 193 GraphicsJNI::getNativePaint(env, paint)->setColor(color); 194 } 195 196 static void setAlpha(JNIEnv* env, jobject paint, jint a) { 197 NPE_CHECK_RETURN_VOID(env, paint); 198 GraphicsJNI::getNativePaint(env, paint)->setAlpha(a); 199 } 200 201 static jfloat getStrokeWidth(JNIEnv* env, jobject paint) { 202 NPE_CHECK_RETURN_ZERO(env, paint); 203 return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeWidth()); 204 } 205 206 static void setStrokeWidth(JNIEnv* env, jobject paint, jfloat width) { 207 NPE_CHECK_RETURN_VOID(env, paint); 208 GraphicsJNI::getNativePaint(env, paint)->setStrokeWidth(SkFloatToScalar(width)); 209 } 210 211 static jfloat getStrokeMiter(JNIEnv* env, jobject paint) { 212 NPE_CHECK_RETURN_ZERO(env, paint); 213 return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeMiter()); 214 } 215 216 static void setStrokeMiter(JNIEnv* env, jobject paint, jfloat miter) { 217 NPE_CHECK_RETURN_VOID(env, paint); 218 GraphicsJNI::getNativePaint(env, paint)->setStrokeMiter(SkFloatToScalar(miter)); 219 } 220 221 static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) { 222 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 223 return static_cast<jint>(obj->getStrokeCap()); 224 } 225 226 static void setStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle, jint capHandle) { 227 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 228 SkPaint::Cap cap = static_cast<SkPaint::Cap>(capHandle); 229 obj->setStrokeCap(cap); 230 } 231 232 static jint getStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle) { 233 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 234 return static_cast<jint>(obj->getStrokeJoin()); 235 } 236 237 static void setStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle, jint joinHandle) { 238 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 239 SkPaint::Join join = (SkPaint::Join) joinHandle; 240 obj->setStrokeJoin(join); 241 } 242 243 static jboolean getFillPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong dstHandle) { 244 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 245 SkPath* src = reinterpret_cast<SkPath*>(srcHandle); 246 SkPath* dst = reinterpret_cast<SkPath*>(dstHandle); 247 return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE; 248 } 249 250 static jlong setShader(JNIEnv* env, jobject clazz, jlong objHandle, jlong shaderHandle) { 251 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 252 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); 253 return reinterpret_cast<jlong>(obj->setShader(shader)); 254 } 255 256 static jlong setColorFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong filterHandle) { 257 SkPaint* obj = reinterpret_cast<SkPaint *>(objHandle); 258 SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(filterHandle); 259 return reinterpret_cast<jlong>(obj->setColorFilter(filter)); 260 } 261 262 static jlong setXfermode(JNIEnv* env, jobject clazz, jlong objHandle, jlong xfermodeHandle) { 263 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 264 SkXfermode* xfermode = reinterpret_cast<SkXfermode*>(xfermodeHandle); 265 return reinterpret_cast<jlong>(obj->setXfermode(xfermode)); 266 } 267 268 static jlong setPathEffect(JNIEnv* env, jobject clazz, jlong objHandle, jlong effectHandle) { 269 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 270 SkPathEffect* effect = reinterpret_cast<SkPathEffect*>(effectHandle); 271 return reinterpret_cast<jlong>(obj->setPathEffect(effect)); 272 } 273 274 static jlong setMaskFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong maskfilterHandle) { 275 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 276 SkMaskFilter* maskfilter = reinterpret_cast<SkMaskFilter*>(maskfilterHandle); 277 return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter)); 278 } 279 280 static jlong setTypeface(JNIEnv* env, jobject clazz, jlong objHandle, jlong typefaceHandle) { 281 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 282 SkTypeface* typeface = reinterpret_cast<SkTypeface*>(typefaceHandle); 283 return reinterpret_cast<jlong>(obj->setTypeface(typeface)); 284 } 285 286 static jlong setRasterizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong rasterizerHandle) { 287 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 288 SkRasterizer* rasterizer = reinterpret_cast<SkRasterizer*>(rasterizerHandle); 289 return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer)); 290 } 291 292 static jint getTextAlign(JNIEnv* env, jobject clazz, jlong objHandle) { 293 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 294 return static_cast<jint>(obj->getTextAlign()); 295 } 296 297 static void setTextAlign(JNIEnv* env, jobject clazz, jlong objHandle, jint alignHandle) { 298 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 299 SkPaint::Align align = static_cast<SkPaint::Align>(alignHandle); 300 obj->setTextAlign(align); 301 } 302 303 // generate bcp47 identifier for the supplied locale 304 static void toLanguageTag(char* output, size_t outSize, 305 const char* locale) { 306 if (output == NULL || outSize <= 0) { 307 return; 308 } 309 if (locale == NULL) { 310 output[0] = '\0'; 311 return; 312 } 313 char canonicalChars[ULOC_FULLNAME_CAPACITY]; 314 UErrorCode uErr = U_ZERO_ERROR; 315 uloc_canonicalize(locale, canonicalChars, ULOC_FULLNAME_CAPACITY, 316 &uErr); 317 if (U_SUCCESS(uErr)) { 318 char likelyChars[ULOC_FULLNAME_CAPACITY]; 319 uErr = U_ZERO_ERROR; 320 uloc_addLikelySubtags(canonicalChars, likelyChars, 321 ULOC_FULLNAME_CAPACITY, &uErr); 322 if (U_SUCCESS(uErr)) { 323 uErr = U_ZERO_ERROR; 324 uloc_toLanguageTag(likelyChars, output, outSize, FALSE, &uErr); 325 if (U_SUCCESS(uErr)) { 326 return; 327 } else { 328 ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars, 329 u_errorName(uErr)); 330 } 331 } else { 332 ALOGD("uloc_addLikelySubtags(\"%s\") failed: %s", 333 canonicalChars, u_errorName(uErr)); 334 } 335 } else { 336 ALOGD("uloc_canonicalize(\"%s\") failed: %s", locale, 337 u_errorName(uErr)); 338 } 339 // unable to build a proper language identifier 340 output[0] = '\0'; 341 } 342 343 static void setTextLocale(JNIEnv* env, jobject clazz, jlong objHandle, jstring locale) { 344 SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle); 345 ScopedUtfChars localeChars(env, locale); 346 char langTag[ULOC_FULLNAME_CAPACITY]; 347 toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, localeChars.c_str()); 348 349 SkPaintOptionsAndroid paintOpts = obj->getPaintOptionsAndroid(); 350 paintOpts.setLanguage(langTag); 351 obj->setPaintOptionsAndroid(paintOpts); 352 } 353 354 static jfloat getTextSize(JNIEnv* env, jobject paint) { 355 NPE_CHECK_RETURN_ZERO(env, paint); 356 return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSize()); 357 } 358 359 static void setTextSize(JNIEnv* env, jobject paint, jfloat textSize) { 360 NPE_CHECK_RETURN_VOID(env, paint); 361 GraphicsJNI::getNativePaint(env, paint)->setTextSize(SkFloatToScalar(textSize)); 362 } 363 364 static jfloat getTextScaleX(JNIEnv* env, jobject paint) { 365 NPE_CHECK_RETURN_ZERO(env, paint); 366 return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextScaleX()); 367 } 368 369 static void setTextScaleX(JNIEnv* env, jobject paint, jfloat scaleX) { 370 NPE_CHECK_RETURN_VOID(env, paint); 371 GraphicsJNI::getNativePaint(env, paint)->setTextScaleX(SkFloatToScalar(scaleX)); 372 } 373 374 static jfloat getTextSkewX(JNIEnv* env, jobject paint) { 375 NPE_CHECK_RETURN_ZERO(env, paint); 376 return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSkewX()); 377 } 378 379 static void setTextSkewX(JNIEnv* env, jobject paint, jfloat skewX) { 380 NPE_CHECK_RETURN_VOID(env, paint); 381 GraphicsJNI::getNativePaint(env, paint)->setTextSkewX(SkFloatToScalar(skewX)); 382 } 383 384 static jfloat ascent(JNIEnv* env, jobject paint) { 385 NPE_CHECK_RETURN_ZERO(env, paint); 386 SkPaint::FontMetrics metrics; 387 (void)GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics); 388 return SkScalarToFloat(metrics.fAscent); 389 } 390 391 static jfloat descent(JNIEnv* env, jobject paint) { 392 NPE_CHECK_RETURN_ZERO(env, paint); 393 SkPaint::FontMetrics metrics; 394 (void)GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics); 395 return SkScalarToFloat(metrics.fDescent); 396 } 397 398 static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) { 399 NPE_CHECK_RETURN_ZERO(env, paint); 400 SkPaint::FontMetrics metrics; 401 SkScalar spacing = GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics); 402 403 if (metricsObj) { 404 SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class)); 405 env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop)); 406 env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent)); 407 env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent)); 408 env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom)); 409 env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading)); 410 } 411 return SkScalarToFloat(spacing); 412 } 413 414 static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) { 415 NPE_CHECK_RETURN_ZERO(env, paint); 416 SkPaint::FontMetrics metrics; 417 418 GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics); 419 int ascent = SkScalarRound(metrics.fAscent); 420 int descent = SkScalarRound(metrics.fDescent); 421 int leading = SkScalarRound(metrics.fLeading); 422 423 if (metricsObj) { 424 SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class)); 425 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloor(metrics.fTop)); 426 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent); 427 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent); 428 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeil(metrics.fBottom)); 429 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading); 430 } 431 return descent - ascent + leading; 432 } 433 434 static jfloat measureText_CIII(JNIEnv* env, jobject jpaint, jcharArray text, jint index, jint count, 435 jint bidiFlags) { 436 NPE_CHECK_RETURN_ZERO(env, jpaint); 437 NPE_CHECK_RETURN_ZERO(env, text); 438 439 size_t textLength = env->GetArrayLength(text); 440 if ((index | count) < 0 || (size_t)(index + count) > textLength) { 441 doThrowAIOOBE(env); 442 return 0; 443 } 444 if (count == 0) { 445 return 0; 446 } 447 448 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); 449 const jchar* textArray = env->GetCharArrayElements(text, NULL); 450 jfloat result = 0; 451 452 TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength, 453 bidiFlags, NULL /* dont need all advances */, &result); 454 455 env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT); 456 return result; 457 } 458 459 static jfloat measureText_StringIII(JNIEnv* env, jobject jpaint, jstring text, jint start, jint end, 460 jint bidiFlags) { 461 NPE_CHECK_RETURN_ZERO(env, jpaint); 462 NPE_CHECK_RETURN_ZERO(env, text); 463 464 size_t textLength = env->GetStringLength(text); 465 int count = end - start; 466 if ((start | count) < 0 || (size_t)end > textLength) { 467 doThrowAIOOBE(env); 468 return 0; 469 } 470 if (count == 0) { 471 return 0; 472 } 473 474 const jchar* textArray = env->GetStringChars(text, NULL); 475 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); 476 jfloat width = 0; 477 478 TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength, 479 bidiFlags, NULL /* dont need all advances */, &width); 480 481 env->ReleaseStringChars(text, textArray); 482 return width; 483 } 484 485 static jfloat measureText_StringI(JNIEnv* env, jobject jpaint, jstring text, jint bidiFlags) { 486 NPE_CHECK_RETURN_ZERO(env, jpaint); 487 NPE_CHECK_RETURN_ZERO(env, text); 488 489 size_t textLength = env->GetStringLength(text); 490 if (textLength == 0) { 491 return 0; 492 } 493 494 const jchar* textArray = env->GetStringChars(text, NULL); 495 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); 496 jfloat width = 0; 497 498 TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength, 499 bidiFlags, NULL /* dont need all advances */, &width); 500 501 env->ReleaseStringChars(text, textArray); 502 return width; 503 } 504 505 static int dotextwidths(JNIEnv* env, SkPaint* paint, const jchar text[], int count, jfloatArray widths, 506 jint bidiFlags) { 507 NPE_CHECK_RETURN_ZERO(env, paint); 508 NPE_CHECK_RETURN_ZERO(env, text); 509 510 if (count < 0 || !widths) { 511 doThrowAIOOBE(env); 512 return 0; 513 } 514 if (count == 0) { 515 return 0; 516 } 517 size_t widthsLength = env->GetArrayLength(widths); 518 if ((size_t)count > widthsLength) { 519 doThrowAIOOBE(env); 520 return 0; 521 } 522 523 AutoJavaFloatArray autoWidths(env, widths, count); 524 jfloat* widthsArray = autoWidths.ptr(); 525 526 TextLayout::getTextRunAdvances(paint, text, 0, count, count, 527 bidiFlags, widthsArray, NULL /* dont need totalAdvance */); 528 529 return count; 530 } 531 532 static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text, 533 jint index, jint count, jint bidiFlags, jfloatArray widths) { 534 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 535 const jchar* textArray = env->GetCharArrayElements(text, NULL); 536 count = dotextwidths(env, paint, textArray + index, count, widths, bidiFlags); 537 env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), 538 JNI_ABORT); 539 return count; 540 } 541 542 static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text, 543 jint start, jint end, jint bidiFlags, jfloatArray widths) { 544 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 545 const jchar* textArray = env->GetStringChars(text, NULL); 546 int count = dotextwidths(env, paint, textArray + start, end - start, widths, bidiFlags); 547 env->ReleaseStringChars(text, textArray); 548 return count; 549 } 550 551 static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count, 552 jint contextCount, jint flags, jcharArray glyphs) { 553 NPE_CHECK_RETURN_ZERO(env, paint); 554 NPE_CHECK_RETURN_ZERO(env, text); 555 556 if ((start | count | contextCount) < 0 || contextCount < count || !glyphs) { 557 doThrowAIOOBE(env); 558 return 0; 559 } 560 if (count == 0) { 561 return 0; 562 } 563 size_t glypthsLength = env->GetArrayLength(glyphs); 564 if ((size_t)count > glypthsLength) { 565 doThrowAIOOBE(env); 566 return 0; 567 } 568 569 jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL); 570 571 sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, 572 text, start, count, contextCount, flags); 573 const jchar* shapedGlyphs = value->getGlyphs(); 574 size_t glyphsCount = value->getGlyphsCount(); 575 memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount); 576 577 env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT); 578 return glyphsCount; 579 } 580 581 static jint getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, jlong paintHandle, 582 jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags, 583 jcharArray glyphs) { 584 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 585 const jchar* textArray = env->GetStringChars(text, NULL); 586 int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart, 587 end - start, contextEnd - contextStart, flags, glyphs); 588 env->ReleaseStringChars(text, textArray); 589 return count; 590 } 591 592 static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text, 593 jint start, jint count, jint contextCount, jint flags, 594 jfloatArray advances, jint advancesIndex) { 595 NPE_CHECK_RETURN_ZERO(env, paint); 596 NPE_CHECK_RETURN_ZERO(env, text); 597 598 if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) { 599 doThrowAIOOBE(env); 600 return 0; 601 } 602 if (count == 0) { 603 return 0; 604 } 605 if (advances) { 606 size_t advancesLength = env->GetArrayLength(advances); 607 if ((size_t)count > advancesLength) { 608 doThrowAIOOBE(env); 609 return 0; 610 } 611 } 612 jfloat advancesArray[count]; 613 jfloat totalAdvance = 0; 614 615 TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags, 616 advancesArray, &totalAdvance); 617 618 if (advances != NULL) { 619 env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray); 620 } 621 return totalAdvance; 622 } 623 624 static jfloat getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, 625 jcharArray text, jint index, jint count, jint contextIndex, jint contextCount, 626 jint flags, jfloatArray advances, jint advancesIndex) { 627 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 628 jchar* textArray = env->GetCharArrayElements(text, NULL); 629 jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex, 630 index - contextIndex, count, contextCount, flags, advances, advancesIndex); 631 env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); 632 return result; 633 } 634 635 static jfloat getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, 636 jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags, 637 jfloatArray advances, jint advancesIndex) { 638 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 639 const jchar* textArray = env->GetStringChars(text, NULL); 640 jfloat result = doTextRunAdvances(env, paint, textArray + contextStart, 641 start - contextStart, end - start, contextEnd - contextStart, flags, 642 advances, advancesIndex); 643 env->ReleaseStringChars(text, textArray); 644 return result; 645 } 646 647 static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start, 648 jint count, jint flags, jint offset, jint opt) { 649 jfloat scalarArray[count]; 650 651 TextLayout::getTextRunAdvances(paint, text, start, count, start + count, flags, 652 scalarArray, NULL /* dont need totalAdvance */); 653 654 jint pos = offset - start; 655 switch (opt) { 656 case AFTER: 657 if (pos < count) { 658 pos += 1; 659 } 660 // fall through 661 case AT_OR_AFTER: 662 while (pos < count && scalarArray[pos] == 0) { 663 ++pos; 664 } 665 break; 666 case BEFORE: 667 if (pos > 0) { 668 --pos; 669 } 670 // fall through 671 case AT_OR_BEFORE: 672 while (pos > 0 && scalarArray[pos] == 0) { 673 --pos; 674 } 675 break; 676 case AT: 677 default: 678 if (scalarArray[pos] == 0) { 679 pos = -1; 680 } 681 break; 682 } 683 684 if (pos != -1) { 685 pos += start; 686 } 687 688 return pos; 689 } 690 691 static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text, 692 jint contextStart, jint contextCount, jint flags, jint offset, jint cursorOpt) { 693 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 694 jchar* textArray = env->GetCharArrayElements(text, NULL); 695 jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, flags, 696 offset, cursorOpt); 697 env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); 698 return result; 699 } 700 701 static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text, 702 jint contextStart, jint contextEnd, jint flags, jint offset, jint cursorOpt) { 703 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 704 const jchar* textArray = env->GetStringChars(text, NULL); 705 jint result = doTextRunCursor(env, paint, textArray, contextStart, 706 contextEnd - contextStart, flags, offset, cursorOpt); 707 env->ReleaseStringChars(text, textArray); 708 return result; 709 } 710 711 static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count, 712 jint bidiFlags, jfloat x, jfloat y, SkPath *path) { 713 TextLayout::getTextPath(paint, text, count, bidiFlags, x, y, path); 714 } 715 716 static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle, jint bidiFlags, 717 jcharArray text, jint index, jint count, jfloat x, jfloat y, jlong pathHandle) { 718 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 719 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 720 const jchar* textArray = env->GetCharArrayElements(text, NULL); 721 getTextPath(env, paint, textArray + index, count, bidiFlags, x, y, path); 722 env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT); 723 } 724 725 static void getTextPath__String(JNIEnv* env, jobject clazz, jlong paintHandle, jint bidiFlags, 726 jstring text, jint start, jint end, jfloat x, jfloat y, jlong pathHandle) { 727 SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 728 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 729 const jchar* textArray = env->GetStringChars(text, NULL); 730 getTextPath(env, paint, textArray + start, end - start, bidiFlags, x, y, path); 731 env->ReleaseStringChars(text, textArray); 732 } 733 734 static void setShadowLayer(JNIEnv* env, jobject jpaint, jfloat radius, 735 jfloat dx, jfloat dy, jint color) { 736 NPE_CHECK_RETURN_VOID(env, jpaint); 737 738 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); 739 if (radius <= 0) { 740 paint->setLooper(NULL); 741 } 742 else { 743 paint->setLooper(new SkBlurDrawLooper(SkFloatToScalar(radius), 744 SkFloatToScalar(dx), 745 SkFloatToScalar(dy), 746 (SkColor)color))->unref(); 747 } 748 } 749 750 static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[], 751 int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured, 752 SkPaint::TextBufferDirection tbd) { 753 sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint, 754 text, 0, count, count, bidiFlags); 755 if (value == NULL) { 756 return 0; 757 } 758 SkScalar measured; 759 size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1, 760 SkFloatToScalar(maxWidth), &measured, tbd); 761 SkASSERT((bytes & 1) == 0); 762 763 if (jmeasured && env->GetArrayLength(jmeasured) > 0) { 764 AutoJavaFloatArray autoMeasured(env, jmeasured, 1); 765 jfloat* array = autoMeasured.ptr(); 766 array[0] = SkScalarToFloat(measured); 767 } 768 return bytes >> 1; 769 } 770 771 static jint breakTextC(JNIEnv* env, jobject jpaint, jcharArray jtext, 772 jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) { 773 NPE_CHECK_RETURN_ZERO(env, jpaint); 774 NPE_CHECK_RETURN_ZERO(env, jtext); 775 776 SkPaint::TextBufferDirection tbd; 777 if (count < 0) { 778 tbd = SkPaint::kBackward_TextBufferDirection; 779 count = -count; 780 } 781 else { 782 tbd = SkPaint::kForward_TextBufferDirection; 783 } 784 785 if ((index < 0) || (index + count > env->GetArrayLength(jtext))) { 786 doThrowAIOOBE(env); 787 return 0; 788 } 789 790 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); 791 const jchar* text = env->GetCharArrayElements(jtext, NULL); 792 count = breakText(env, *paint, text + index, count, maxWidth, 793 bidiFlags, jmeasuredWidth, tbd); 794 env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text), 795 JNI_ABORT); 796 return count; 797 } 798 799 static jint breakTextS(JNIEnv* env, jobject jpaint, jstring jtext, 800 jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) { 801 NPE_CHECK_RETURN_ZERO(env, jpaint); 802 NPE_CHECK_RETURN_ZERO(env, jtext); 803 804 SkPaint::TextBufferDirection tbd = forwards ? 805 SkPaint::kForward_TextBufferDirection : 806 SkPaint::kBackward_TextBufferDirection; 807 808 SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); 809 int count = env->GetStringLength(jtext); 810 const jchar* text = env->GetStringChars(jtext, NULL); 811 count = breakText(env, *paint, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd); 812 env->ReleaseStringChars(jtext, text); 813 return count; 814 } 815 816 static void doTextBounds(JNIEnv* env, const jchar* text, int count, 817 jobject bounds, const SkPaint& paint, jint bidiFlags) { 818 SkRect r; 819 SkIRect ir; 820 821 sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint, 822 text, 0, count, count, bidiFlags); 823 if (value == NULL) { 824 return; 825 } 826 paint.measureText(value->getGlyphs(), value->getGlyphsCount() << 1, &r); 827 r.roundOut(&ir); 828 GraphicsJNI::irect_to_jrect(ir, env, bounds); 829 } 830 831 static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, 832 jstring text, jint start, jint end, jint bidiFlags, jobject bounds) { 833 const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);; 834 const jchar* textArray = env->GetStringChars(text, NULL); 835 doTextBounds(env, textArray + start, end - start, bounds, *paint, bidiFlags); 836 env->ReleaseStringChars(text, textArray); 837 } 838 839 static void getCharArrayBounds(JNIEnv* env, jobject, jlong paintHandle, 840 jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) { 841 const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); 842 const jchar* textArray = env->GetCharArrayElements(text, NULL); 843 doTextBounds(env, textArray + index, count, bounds, *paint, bidiFlags); 844 env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), 845 JNI_ABORT); 846 } 847 848}; 849 850static JNINativeMethod methods[] = { 851 {"finalizer", "(J)V", (void*) SkPaintGlue::finalizer}, 852 {"native_init","()J", (void*) SkPaintGlue::init}, 853 {"native_initWithPaint","(J)J", (void*) SkPaintGlue::initWithPaint}, 854 {"native_reset","(J)V", (void*) SkPaintGlue::reset}, 855 {"native_set","(JJ)V", (void*) SkPaintGlue::assign}, 856 {"getFlags","()I", (void*) SkPaintGlue::getFlags}, 857 {"setFlags","(I)V", (void*) SkPaintGlue::setFlags}, 858 {"getHinting","()I", (void*) SkPaintGlue::getHinting}, 859 {"setHinting","(I)V", (void*) SkPaintGlue::setHinting}, 860 {"setAntiAlias","(Z)V", (void*) SkPaintGlue::setAntiAlias}, 861 {"setSubpixelText","(Z)V", (void*) SkPaintGlue::setSubpixelText}, 862 {"setLinearText","(Z)V", (void*) SkPaintGlue::setLinearText}, 863 {"setUnderlineText","(Z)V", (void*) SkPaintGlue::setUnderlineText}, 864 {"setStrikeThruText","(Z)V", (void*) SkPaintGlue::setStrikeThruText}, 865 {"setFakeBoldText","(Z)V", (void*) SkPaintGlue::setFakeBoldText}, 866 {"setFilterBitmap","(Z)V", (void*) SkPaintGlue::setFilterBitmap}, 867 {"setDither","(Z)V", (void*) SkPaintGlue::setDither}, 868 {"native_getStyle","(J)I", (void*) SkPaintGlue::getStyle}, 869 {"native_setStyle","(JI)V", (void*) SkPaintGlue::setStyle}, 870 {"getColor","()I", (void*) SkPaintGlue::getColor}, 871 {"setColor","(I)V", (void*) SkPaintGlue::setColor}, 872 {"getAlpha","()I", (void*) SkPaintGlue::getAlpha}, 873 {"setAlpha","(I)V", (void*) SkPaintGlue::setAlpha}, 874 {"getStrokeWidth","()F", (void*) SkPaintGlue::getStrokeWidth}, 875 {"setStrokeWidth","(F)V", (void*) SkPaintGlue::setStrokeWidth}, 876 {"getStrokeMiter","()F", (void*) SkPaintGlue::getStrokeMiter}, 877 {"setStrokeMiter","(F)V", (void*) SkPaintGlue::setStrokeMiter}, 878 {"native_getStrokeCap","(J)I", (void*) SkPaintGlue::getStrokeCap}, 879 {"native_setStrokeCap","(JI)V", (void*) SkPaintGlue::setStrokeCap}, 880 {"native_getStrokeJoin","(J)I", (void*) SkPaintGlue::getStrokeJoin}, 881 {"native_setStrokeJoin","(JI)V", (void*) SkPaintGlue::setStrokeJoin}, 882 {"native_getFillPath","(JJJ)Z", (void*) SkPaintGlue::getFillPath}, 883 {"native_setShader","(JJ)J", (void*) SkPaintGlue::setShader}, 884 {"native_setColorFilter","(JJ)J", (void*) SkPaintGlue::setColorFilter}, 885 {"native_setXfermode","(JJ)J", (void*) SkPaintGlue::setXfermode}, 886 {"native_setPathEffect","(JJ)J", (void*) SkPaintGlue::setPathEffect}, 887 {"native_setMaskFilter","(JJ)J", (void*) SkPaintGlue::setMaskFilter}, 888 {"native_setTypeface","(JJ)J", (void*) SkPaintGlue::setTypeface}, 889 {"native_setRasterizer","(JJ)J", (void*) SkPaintGlue::setRasterizer}, 890 {"native_getTextAlign","(J)I", (void*) SkPaintGlue::getTextAlign}, 891 {"native_setTextAlign","(JI)V", (void*) SkPaintGlue::setTextAlign}, 892 {"native_setTextLocale","(JLjava/lang/String;)V", (void*) SkPaintGlue::setTextLocale}, 893 {"getTextSize","()F", (void*) SkPaintGlue::getTextSize}, 894 {"setTextSize","(F)V", (void*) SkPaintGlue::setTextSize}, 895 {"getTextScaleX","()F", (void*) SkPaintGlue::getTextScaleX}, 896 {"setTextScaleX","(F)V", (void*) SkPaintGlue::setTextScaleX}, 897 {"getTextSkewX","()F", (void*) SkPaintGlue::getTextSkewX}, 898 {"setTextSkewX","(F)V", (void*) SkPaintGlue::setTextSkewX}, 899 {"ascent","()F", (void*) SkPaintGlue::ascent}, 900 {"descent","()F", (void*) SkPaintGlue::descent}, 901 {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)SkPaintGlue::getFontMetrics}, 902 {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)SkPaintGlue::getFontMetricsInt}, 903 {"native_measureText","([CIII)F", (void*) SkPaintGlue::measureText_CIII}, 904 {"native_measureText","(Ljava/lang/String;I)F", (void*) SkPaintGlue::measureText_StringI}, 905 {"native_measureText","(Ljava/lang/String;III)F", (void*) SkPaintGlue::measureText_StringIII}, 906 {"native_breakText","([CIIFI[F)I", (void*) SkPaintGlue::breakTextC}, 907 {"native_breakText","(Ljava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS}, 908 {"native_getTextWidths","(J[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F}, 909 {"native_getTextWidths","(JLjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F}, 910 {"native_getTextRunAdvances","(J[CIIIII[FI)F", 911 (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI}, 912 {"native_getTextRunAdvances","(JLjava/lang/String;IIIII[FI)F", 913 (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI}, 914 915 916 {"native_getTextGlyphs","(JLjava/lang/String;IIIII[C)I", 917 (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C}, 918 {"native_getTextRunCursor", "(J[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C}, 919 {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I", 920 (void*) SkPaintGlue::getTextRunCursor__String}, 921 {"native_getTextPath","(JI[CIIFFJ)V", (void*) SkPaintGlue::getTextPath___C}, 922 {"native_getTextPath","(JILjava/lang/String;IIFFJ)V", (void*) SkPaintGlue::getTextPath__String}, 923 {"nativeGetStringBounds", "(JLjava/lang/String;IIILandroid/graphics/Rect;)V", 924 (void*) SkPaintGlue::getStringBounds }, 925 {"nativeGetCharArrayBounds", "(J[CIIILandroid/graphics/Rect;)V", 926 (void*) SkPaintGlue::getCharArrayBounds }, 927 {"nSetShadowLayer", "(FFFI)V", (void*)SkPaintGlue::setShadowLayer} 928}; 929 930static jfieldID req_fieldID(jfieldID id) { 931 SkASSERT(id); 932 return id; 933} 934 935int register_android_graphics_Paint(JNIEnv* env) { 936 gFontMetrics_class = env->FindClass("android/graphics/Paint$FontMetrics"); 937 SkASSERT(gFontMetrics_class); 938 gFontMetrics_class = (jclass)env->NewGlobalRef(gFontMetrics_class); 939 940 gFontMetrics_fieldID.top = req_fieldID(env->GetFieldID(gFontMetrics_class, "top", "F")); 941 gFontMetrics_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetrics_class, "ascent", "F")); 942 gFontMetrics_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetrics_class, "descent", "F")); 943 gFontMetrics_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetrics_class, "bottom", "F")); 944 gFontMetrics_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetrics_class, "leading", "F")); 945 946 gFontMetricsInt_class = env->FindClass("android/graphics/Paint$FontMetricsInt"); 947 SkASSERT(gFontMetricsInt_class); 948 gFontMetricsInt_class = (jclass)env->NewGlobalRef(gFontMetricsInt_class); 949 950 gFontMetricsInt_fieldID.top = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "top", "I")); 951 gFontMetricsInt_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "ascent", "I")); 952 gFontMetricsInt_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "descent", "I")); 953 gFontMetricsInt_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "bottom", "I")); 954 gFontMetricsInt_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "leading", "I")); 955 956 int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Paint", methods, 957 sizeof(methods) / sizeof(methods[0])); 958 return result; 959} 960 961} 962