Paint.cpp revision 5d31a293ad0a832c7b8b445c1a67fb1800e5da32
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 "core_jni_helpers.h" 25#include <ScopedStringChars.h> 26#include <ScopedUtfChars.h> 27 28#include "SkBlurDrawLooper.h" 29#include "SkColorFilter.h" 30#include "SkMaskFilter.h" 31#include "SkPath.h" 32#include "SkRasterizer.h" 33#include "SkShader.h" 34#include "SkXfermode.h" 35#include "unicode/uloc.h" 36#include "unicode/ushape.h" 37#include "utils/Blur.h" 38 39#include <hwui/MinikinSkia.h> 40#include <hwui/MinikinUtils.h> 41#include <hwui/Paint.h> 42#include <hwui/Typeface.h> 43#include <minikin/GraphemeBreak.h> 44#include <minikin/Measurement.h> 45#include <unicode/utf16.h> 46 47#include <cassert> 48#include <cstring> 49#include <memory> 50#include <vector> 51 52namespace android { 53 54struct JMetricsID { 55 jfieldID top; 56 jfieldID ascent; 57 jfieldID descent; 58 jfieldID bottom; 59 jfieldID leading; 60}; 61 62static jclass gFontMetrics_class; 63static JMetricsID gFontMetrics_fieldID; 64 65static jclass gFontMetricsInt_class; 66static JMetricsID gFontMetricsInt_fieldID; 67 68static void defaultSettingsForAndroid(Paint* paint) { 69 // GlyphID encoding is required because we are using Harfbuzz shaping 70 paint->setTextEncoding(Paint::kGlyphID_TextEncoding); 71} 72 73namespace PaintGlue { 74 enum MoveOpt { 75 AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT 76 }; 77 78 static void deletePaint(Paint* paint) { 79 delete paint; 80 } 81 82 static jlong getNativeFinalizer(JNIEnv*, jobject) { 83 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&deletePaint)); 84 } 85 86 static jlong init(JNIEnv* env, jobject) { 87 static_assert(1 << 0 == SkPaint::kAntiAlias_Flag, "paint_flags_mismatch"); 88 static_assert(1 << 2 == SkPaint::kDither_Flag, "paint_flags_mismatch"); 89 static_assert(1 << 3 == SkPaint::kUnderlineText_Flag, "paint_flags_mismatch"); 90 static_assert(1 << 4 == SkPaint::kStrikeThruText_Flag, "paint_flags_mismatch"); 91 static_assert(1 << 5 == SkPaint::kFakeBoldText_Flag, "paint_flags_mismatch"); 92 static_assert(1 << 6 == SkPaint::kLinearText_Flag, "paint_flags_mismatch"); 93 static_assert(1 << 7 == SkPaint::kSubpixelText_Flag, "paint_flags_mismatch"); 94 static_assert(1 << 8 == SkPaint::kDevKernText_Flag, "paint_flags_mismatch"); 95 static_assert(1 << 10 == SkPaint::kEmbeddedBitmapText_Flag, "paint_flags_mismatch"); 96 97 Paint* obj = new Paint(); 98 defaultSettingsForAndroid(obj); 99 return reinterpret_cast<jlong>(obj); 100 } 101 102 static jlong initWithPaint(JNIEnv* env, jobject clazz, jlong paintHandle) { 103 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 104 Paint* obj = new Paint(*paint); 105 return reinterpret_cast<jlong>(obj); 106 } 107 108 static void reset(JNIEnv* env, jobject clazz, jlong objHandle) { 109 Paint* obj = reinterpret_cast<Paint*>(objHandle); 110 obj->reset(); 111 defaultSettingsForAndroid(obj); 112 } 113 114 static void assign(JNIEnv* env, jobject clazz, jlong dstPaintHandle, jlong srcPaintHandle) { 115 Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle); 116 const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle); 117 *dst = *src; 118 } 119 120 // Equivalent to the Java Paint's FILTER_BITMAP_FLAG. 121 static const uint32_t sFilterBitmapFlag = 0x02; 122 123 static jint getFlags(JNIEnv* env, jobject, jlong paintHandle) { 124 Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle); 125 uint32_t result = nativePaint->getFlags(); 126 result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away. 127 if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) { 128 result |= sFilterBitmapFlag; 129 } 130 return static_cast<jint>(result); 131 } 132 133 static void setFlags(JNIEnv* env, jobject, jlong paintHandle, jint flags) { 134 Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle); 135 // Instead of modifying 0x02, change the filter level. 136 nativePaint->setFilterQuality(flags & sFilterBitmapFlag 137 ? kLow_SkFilterQuality 138 : kNone_SkFilterQuality); 139 // Don't pass through filter flag, which is no longer stored in paint's flags. 140 flags &= ~sFilterBitmapFlag; 141 // Use the existing value for 0x02. 142 const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag; 143 flags |= existing0x02Flag; 144 nativePaint->setFlags(flags); 145 } 146 147 static jint getHinting(JNIEnv* env, jobject, jlong paintHandle) { 148 return reinterpret_cast<Paint*>(paintHandle)->getHinting() 149 == Paint::kNo_Hinting ? 0 : 1; 150 } 151 152 static void setHinting(JNIEnv* env, jobject, jlong paintHandle, jint mode) { 153 reinterpret_cast<Paint*>(paintHandle)->setHinting( 154 mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting); 155 } 156 157 static void setAntiAlias(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) { 158 reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa); 159 } 160 161 static void setLinearText(JNIEnv* env, jobject, jlong paintHandle, jboolean linearText) { 162 reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText); 163 } 164 165 static void setSubpixelText(JNIEnv* env, jobject, jlong paintHandle, jboolean subpixelText) { 166 reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText); 167 } 168 169 static void setUnderlineText(JNIEnv* env, jobject, jlong paintHandle, jboolean underlineText) { 170 reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText); 171 } 172 173 static void setStrikeThruText(JNIEnv* env, jobject, jlong paintHandle, jboolean strikeThruText) { 174 reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText); 175 } 176 177 static void setFakeBoldText(JNIEnv* env, jobject, jlong paintHandle, jboolean fakeBoldText) { 178 reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText); 179 } 180 181 static void setFilterBitmap(JNIEnv* env, jobject, jlong paintHandle, jboolean filterBitmap) { 182 reinterpret_cast<Paint*>(paintHandle)->setFilterQuality( 183 filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality); 184 } 185 186 static void setDither(JNIEnv* env, jobject, jlong paintHandle, jboolean dither) { 187 reinterpret_cast<Paint*>(paintHandle)->setDither(dither); 188 } 189 190 static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) { 191 Paint* obj = reinterpret_cast<Paint*>(objHandle); 192 return static_cast<jint>(obj->getStyle()); 193 } 194 195 static void setStyle(JNIEnv* env, jobject clazz, jlong objHandle, jint styleHandle) { 196 Paint* obj = reinterpret_cast<Paint*>(objHandle); 197 Paint::Style style = static_cast<Paint::Style>(styleHandle); 198 obj->setStyle(style); 199 } 200 201 static jint getColor(JNIEnv* env, jobject, jlong paintHandle) { 202 int color; 203 color = reinterpret_cast<Paint*>(paintHandle)->getColor(); 204 return static_cast<jint>(color); 205 } 206 207 static jint getAlpha(JNIEnv* env, jobject, jlong paintHandle) { 208 int alpha; 209 alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha(); 210 return static_cast<jint>(alpha); 211 } 212 213 static void setColor(JNIEnv* env, jobject, jlong paintHandle, jint color) { 214 reinterpret_cast<Paint*>(paintHandle)->setColor(color); 215 } 216 217 static void setAlpha(JNIEnv* env, jobject, jlong paintHandle, jint a) { 218 reinterpret_cast<Paint*>(paintHandle)->setAlpha(a); 219 } 220 221 static jfloat getStrokeWidth(JNIEnv* env, jobject, jlong paintHandle) { 222 return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth()); 223 } 224 225 static void setStrokeWidth(JNIEnv* env, jobject, jlong paintHandle, jfloat width) { 226 reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width); 227 } 228 229 static jfloat getStrokeMiter(JNIEnv* env, jobject, jlong paintHandle) { 230 return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter()); 231 } 232 233 static void setStrokeMiter(JNIEnv* env, jobject, jlong paintHandle, jfloat miter) { 234 reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter); 235 } 236 237 static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) { 238 Paint* obj = reinterpret_cast<Paint*>(objHandle); 239 return static_cast<jint>(obj->getStrokeCap()); 240 } 241 242 static void setStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle, jint capHandle) { 243 Paint* obj = reinterpret_cast<Paint*>(objHandle); 244 Paint::Cap cap = static_cast<Paint::Cap>(capHandle); 245 obj->setStrokeCap(cap); 246 } 247 248 static jint getStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle) { 249 Paint* obj = reinterpret_cast<Paint*>(objHandle); 250 return static_cast<jint>(obj->getStrokeJoin()); 251 } 252 253 static void setStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle, jint joinHandle) { 254 Paint* obj = reinterpret_cast<Paint*>(objHandle); 255 Paint::Join join = (Paint::Join) joinHandle; 256 obj->setStrokeJoin(join); 257 } 258 259 static jboolean getFillPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong dstHandle) { 260 Paint* obj = reinterpret_cast<Paint*>(objHandle); 261 SkPath* src = reinterpret_cast<SkPath*>(srcHandle); 262 SkPath* dst = reinterpret_cast<SkPath*>(dstHandle); 263 return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE; 264 } 265 266 static jlong setShader(JNIEnv* env, jobject clazz, jlong objHandle, jlong shaderHandle) { 267 Paint* obj = reinterpret_cast<Paint*>(objHandle); 268 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); 269 return reinterpret_cast<jlong>(obj->setShader(shader)); 270 } 271 272 static jlong setColorFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong filterHandle) { 273 Paint* obj = reinterpret_cast<Paint *>(objHandle); 274 SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(filterHandle); 275 return reinterpret_cast<jlong>(obj->setColorFilter(filter)); 276 } 277 278 static void setXfermode(JNIEnv* env, jobject clazz, jlong paintHandle, jint xfermodeHandle) { 279 // validate that the Java enum values match our expectations 280 static_assert(0 == SkXfermode::kClear_Mode, "xfermode_mismatch"); 281 static_assert(1 == SkXfermode::kSrc_Mode, "xfermode_mismatch"); 282 static_assert(2 == SkXfermode::kDst_Mode, "xfermode_mismatch"); 283 static_assert(3 == SkXfermode::kSrcOver_Mode, "xfermode_mismatch"); 284 static_assert(4 == SkXfermode::kDstOver_Mode, "xfermode_mismatch"); 285 static_assert(5 == SkXfermode::kSrcIn_Mode, "xfermode_mismatch"); 286 static_assert(6 == SkXfermode::kDstIn_Mode, "xfermode_mismatch"); 287 static_assert(7 == SkXfermode::kSrcOut_Mode, "xfermode_mismatch"); 288 static_assert(8 == SkXfermode::kDstOut_Mode, "xfermode_mismatch"); 289 static_assert(9 == SkXfermode::kSrcATop_Mode, "xfermode_mismatch"); 290 static_assert(10 == SkXfermode::kDstATop_Mode, "xfermode_mismatch"); 291 static_assert(11 == SkXfermode::kXor_Mode, "xfermode_mismatch"); 292 static_assert(16 == SkXfermode::kDarken_Mode, "xfermode_mismatch"); 293 static_assert(17 == SkXfermode::kLighten_Mode, "xfermode_mismatch"); 294 static_assert(13 == SkXfermode::kModulate_Mode, "xfermode_mismatch"); 295 static_assert(14 == SkXfermode::kScreen_Mode, "xfermode_mismatch"); 296 static_assert(12 == SkXfermode::kPlus_Mode, "xfermode_mismatch"); 297 static_assert(15 == SkXfermode::kOverlay_Mode, "xfermode_mismatch"); 298 299 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle); 300 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 301 paint->setXfermodeMode(mode); 302 } 303 304 static jlong setPathEffect(JNIEnv* env, jobject clazz, jlong objHandle, jlong effectHandle) { 305 Paint* obj = reinterpret_cast<Paint*>(objHandle); 306 SkPathEffect* effect = reinterpret_cast<SkPathEffect*>(effectHandle); 307 return reinterpret_cast<jlong>(obj->setPathEffect(effect)); 308 } 309 310 static jlong setMaskFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong maskfilterHandle) { 311 Paint* obj = reinterpret_cast<Paint*>(objHandle); 312 SkMaskFilter* maskfilter = reinterpret_cast<SkMaskFilter*>(maskfilterHandle); 313 return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter)); 314 } 315 316 static jlong setTypeface(JNIEnv* env, jobject clazz, jlong objHandle, jlong typefaceHandle) { 317 // TODO: in Paint refactoring, set typeface on android Paint, not Paint 318 return NULL; 319 } 320 321 static jlong setRasterizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong rasterizerHandle) { 322 Paint* obj = reinterpret_cast<Paint*>(objHandle); 323 SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle)); 324 return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer)); 325 } 326 327 static jint getTextAlign(JNIEnv* env, jobject clazz, jlong objHandle) { 328 Paint* obj = reinterpret_cast<Paint*>(objHandle); 329 return static_cast<jint>(obj->getTextAlign()); 330 } 331 332 static void setTextAlign(JNIEnv* env, jobject clazz, jlong objHandle, jint alignHandle) { 333 Paint* obj = reinterpret_cast<Paint*>(objHandle); 334 Paint::Align align = static_cast<Paint::Align>(alignHandle); 335 obj->setTextAlign(align); 336 } 337 338 static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) { 339 Paint* obj = reinterpret_cast<Paint*>(objHandle); 340 ScopedUtfChars localesChars(env, locales); 341 jint minikinLangListId = minikin::FontStyle::registerLanguageList(localesChars.c_str()); 342 obj->setMinikinLangListId(minikinLangListId); 343 return minikinLangListId; 344 } 345 346 static void setTextLocalesByMinikinLangListId(JNIEnv* env, jobject clazz, jlong objHandle, 347 jint minikinLangListId) { 348 Paint* obj = reinterpret_cast<Paint*>(objHandle); 349 obj->setMinikinLangListId(minikinLangListId); 350 } 351 352 static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) { 353 Paint* obj = reinterpret_cast<Paint*>(paintHandle); 354 return obj->getFontVariant() == minikin::VARIANT_ELEGANT; 355 } 356 357 static void setElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) { 358 Paint* obj = reinterpret_cast<Paint*>(paintHandle); 359 obj->setFontVariant(aa ? minikin::VARIANT_ELEGANT : minikin::VARIANT_DEFAULT); 360 } 361 362 static jfloat getTextSize(JNIEnv* env, jobject, jlong paintHandle) { 363 return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize()); 364 } 365 366 static void setTextSize(JNIEnv* env, jobject, jlong paintHandle, jfloat textSize) { 367 reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize); 368 } 369 370 static jfloat getTextScaleX(JNIEnv* env, jobject, jlong paintHandle) { 371 return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX()); 372 } 373 374 static void setTextScaleX(JNIEnv* env, jobject, jlong paintHandle, jfloat scaleX) { 375 reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX); 376 } 377 378 static jfloat getTextSkewX(JNIEnv* env, jobject, jlong paintHandle) { 379 return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX()); 380 } 381 382 static void setTextSkewX(JNIEnv* env, jobject, jlong paintHandle, jfloat skewX) { 383 reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX); 384 } 385 386 static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) { 387 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 388 return paint->getLetterSpacing(); 389 } 390 391 static void setLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat letterSpacing) { 392 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 393 paint->setLetterSpacing(letterSpacing); 394 } 395 396 static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) { 397 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 398 if (!settings) { 399 paint->setFontFeatureSettings(std::string()); 400 } else { 401 ScopedUtfChars settingsChars(env, settings); 402 paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size())); 403 } 404 } 405 406 static jint getHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) { 407 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 408 return paint->getHyphenEdit(); 409 } 410 411 static void setHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) { 412 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 413 paint->setHyphenEdit((uint32_t)hyphen); 414 } 415 416 static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle, 417 Paint::FontMetrics *metrics) { 418 const int kElegantTop = 2500; 419 const int kElegantBottom = -1000; 420 const int kElegantAscent = 1900; 421 const int kElegantDescent = -500; 422 const int kElegantLeading = 0; 423 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 424 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 425 typeface = Typeface::resolveDefault(typeface); 426 minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle); 427 float saveSkewX = paint->getTextSkewX(); 428 bool savefakeBold = paint->isFakeBoldText(); 429 MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery); 430 SkScalar spacing = paint->getFontMetrics(metrics); 431 // The populateSkPaint call may have changed fake bold / text skew 432 // because we want to measure with those effects applied, so now 433 // restore the original settings. 434 paint->setTextSkewX(saveSkewX); 435 paint->setFakeBoldText(savefakeBold); 436 if (paint->getFontVariant() == minikin::VARIANT_ELEGANT) { 437 SkScalar size = paint->getTextSize(); 438 metrics->fTop = -size * kElegantTop / 2048; 439 metrics->fBottom = -size * kElegantBottom / 2048; 440 metrics->fAscent = -size * kElegantAscent / 2048; 441 metrics->fDescent = -size * kElegantDescent / 2048; 442 metrics->fLeading = size * kElegantLeading / 2048; 443 spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading; 444 } 445 return spacing; 446 } 447 448 static jfloat ascent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) { 449 Paint::FontMetrics metrics; 450 getMetricsInternal(paintHandle, typefaceHandle, &metrics); 451 return SkScalarToFloat(metrics.fAscent); 452 } 453 454 static jfloat descent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) { 455 Paint::FontMetrics metrics; 456 getMetricsInternal(paintHandle, typefaceHandle, &metrics); 457 return SkScalarToFloat(metrics.fDescent); 458 } 459 460 static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle, 461 jlong typefaceHandle, jobject metricsObj) { 462 Paint::FontMetrics metrics; 463 SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics); 464 465 if (metricsObj) { 466 SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class)); 467 env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop)); 468 env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent)); 469 env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent)); 470 env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom)); 471 env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading)); 472 } 473 return SkScalarToFloat(spacing); 474 } 475 476 static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle, 477 jlong typefaceHandle, jobject metricsObj) { 478 Paint::FontMetrics metrics; 479 480 getMetricsInternal(paintHandle, typefaceHandle, &metrics); 481 int ascent = SkScalarRoundToInt(metrics.fAscent); 482 int descent = SkScalarRoundToInt(metrics.fDescent); 483 int leading = SkScalarRoundToInt(metrics.fLeading); 484 485 if (metricsObj) { 486 SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class)); 487 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop)); 488 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent); 489 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent); 490 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom)); 491 env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading); 492 } 493 return descent - ascent + leading; 494 } 495 496 static jfloat doTextAdvances(JNIEnv *env, Paint *paint, Typeface* typeface, 497 const jchar *text, jint start, jint count, jint contextCount, jint bidiFlags, 498 jfloatArray advances, jint advancesIndex) { 499 NPE_CHECK_RETURN_ZERO(env, text); 500 501 if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) { 502 doThrowAIOOBE(env); 503 return 0; 504 } 505 if (count == 0) { 506 return 0; 507 } 508 if (advances) { 509 size_t advancesLength = env->GetArrayLength(advances); 510 if ((size_t)(count + advancesIndex) > advancesLength) { 511 doThrowAIOOBE(env); 512 return 0; 513 } 514 } 515 std::unique_ptr<jfloat[]> advancesArray; 516 if (advances) { 517 advancesArray.reset(new jfloat[count]); 518 } 519 const float advance = MinikinUtils::measureText(paint, bidiFlags, typeface, text, 520 start, count, contextCount, advancesArray.get()); 521 if (advances) { 522 env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get()); 523 } 524 return advance; 525 } 526 527 static jfloat getTextAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, 528 jlong typefaceHandle, 529 jcharArray text, jint index, jint count, jint contextIndex, jint contextCount, 530 jint bidiFlags, jfloatArray advances, jint advancesIndex) { 531 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 532 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 533 jchar* textArray = env->GetCharArrayElements(text, NULL); 534 jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex, 535 index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex); 536 env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); 537 return result; 538 } 539 540 static jfloat getTextAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, 541 jlong typefaceHandle, 542 jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint bidiFlags, 543 jfloatArray advances, jint advancesIndex) { 544 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 545 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 546 const jchar* textArray = env->GetStringChars(text, NULL); 547 jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart, 548 start - contextStart, end - start, contextEnd - contextStart, bidiFlags, 549 advances, advancesIndex); 550 env->ReleaseStringChars(text, textArray); 551 return result; 552 } 553 554 static jint doTextRunCursor(JNIEnv *env, Paint* paint, const jchar *text, jint start, 555 jint count, jint flags, jint offset, jint opt) { 556 minikin::GraphemeBreak::MoveOpt moveOpt = minikin::GraphemeBreak::MoveOpt(opt); 557 size_t result = minikin::GraphemeBreak::getTextRunCursor(text, start, count, offset, 558 moveOpt); 559 return static_cast<jint>(result); 560 } 561 562 static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text, 563 jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) { 564 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 565 jchar* textArray = env->GetCharArrayElements(text, NULL); 566 jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir, 567 offset, cursorOpt); 568 env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); 569 return result; 570 } 571 572 static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text, 573 jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) { 574 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 575 const jchar* textArray = env->GetStringChars(text, NULL); 576 jint result = doTextRunCursor(env, paint, textArray, contextStart, 577 contextEnd - contextStart, dir, offset, cursorOpt); 578 env->ReleaseStringChars(text, textArray); 579 return result; 580 } 581 582 class GetTextFunctor { 583 public: 584 GetTextFunctor(const minikin::Layout& layout, SkPath* path, jfloat x, jfloat y, 585 Paint* paint, uint16_t* glyphs, SkPoint* pos) 586 : layout(layout), path(path), x(x), y(y), paint(paint), glyphs(glyphs), pos(pos) { 587 } 588 589 void operator()(size_t start, size_t end) { 590 for (size_t i = start; i < end; i++) { 591 glyphs[i] = layout.getGlyphId(i); 592 pos[i].fX = x + layout.getX(i); 593 pos[i].fY = y + layout.getY(i); 594 } 595 if (start == 0) { 596 paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, path); 597 } else { 598 paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, &tmpPath); 599 path->addPath(tmpPath); 600 } 601 } 602 private: 603 const minikin::Layout& layout; 604 SkPath* path; 605 jfloat x; 606 jfloat y; 607 Paint* paint; 608 uint16_t* glyphs; 609 SkPoint* pos; 610 SkPath tmpPath; 611 }; 612 613 static void getTextPath(JNIEnv* env, Paint* paint, Typeface* typeface, const jchar* text, 614 jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) { 615 minikin::Layout layout; 616 MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count); 617 size_t nGlyphs = layout.nGlyphs(); 618 uint16_t* glyphs = new uint16_t[nGlyphs]; 619 SkPoint* pos = new SkPoint[nGlyphs]; 620 621 x += MinikinUtils::xOffsetForTextAlign(paint, layout); 622 Paint::Align align = paint->getTextAlign(); 623 paint->setTextAlign(Paint::kLeft_Align); 624 paint->setTextEncoding(Paint::kGlyphID_TextEncoding); 625 GetTextFunctor f(layout, path, x, y, paint, glyphs, pos); 626 MinikinUtils::forFontRun(layout, paint, f); 627 paint->setTextAlign(align); 628 delete[] glyphs; 629 delete[] pos; 630 } 631 632 static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle, 633 jlong typefaceHandle, jint bidiFlags, 634 jcharArray text, jint index, jint count, jfloat x, jfloat y, jlong pathHandle) { 635 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 636 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 637 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 638 const jchar* textArray = env->GetCharArrayElements(text, NULL); 639 getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path); 640 env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT); 641 } 642 643 static void getTextPath__String(JNIEnv* env, jobject clazz, jlong paintHandle, 644 jlong typefaceHandle, jint bidiFlags, 645 jstring text, jint start, jint end, jfloat x, jfloat y, jlong pathHandle) { 646 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 647 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 648 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 649 const jchar* textArray = env->GetStringChars(text, NULL); 650 getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path); 651 env->ReleaseStringChars(text, textArray); 652 } 653 654 static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius, 655 jfloat dx, jfloat dy, jint color) { 656 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 657 if (radius <= 0) { 658 paint->setLooper(NULL); 659 } 660 else { 661 SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius); 662 paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref(); 663 } 664 } 665 666 static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) { 667 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 668 return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL); 669 } 670 671 static int breakText(JNIEnv* env, const Paint& paint, Typeface* typeface, const jchar text[], 672 int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured, 673 const bool forwardScan) { 674 size_t measuredCount = 0; 675 float measured = 0; 676 677 std::unique_ptr<float[]> advancesArray(new float[count]); 678 MinikinUtils::measureText(&paint, bidiFlags, typeface, text, 0, count, count, 679 advancesArray.get()); 680 681 for (int i = 0; i < count; i++) { 682 // traverse in the given direction 683 int index = forwardScan ? i : (count - i - 1); 684 float width = advancesArray[index]; 685 if (measured + width > maxWidth) { 686 break; 687 } 688 // properly handle clusters when scanning backwards 689 if (forwardScan || width != 0.0f) { 690 measuredCount = i + 1; 691 } 692 measured += width; 693 } 694 695 if (jmeasured && env->GetArrayLength(jmeasured) > 0) { 696 AutoJavaFloatArray autoMeasured(env, jmeasured, 1); 697 jfloat* array = autoMeasured.ptr(); 698 array[0] = measured; 699 } 700 return measuredCount; 701 } 702 703 static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext, 704 jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) { 705 NPE_CHECK_RETURN_ZERO(env, jtext); 706 707 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 708 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 709 710 bool forwardTextDirection; 711 if (count < 0) { 712 forwardTextDirection = false; 713 count = -count; 714 } 715 else { 716 forwardTextDirection = true; 717 } 718 719 if ((index < 0) || (index + count > env->GetArrayLength(jtext))) { 720 doThrowAIOOBE(env); 721 return 0; 722 } 723 724 const jchar* text = env->GetCharArrayElements(jtext, NULL); 725 count = breakText(env, *paint, typeface, text + index, count, maxWidth, 726 bidiFlags, jmeasuredWidth, forwardTextDirection); 727 env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text), 728 JNI_ABORT); 729 return count; 730 } 731 732 static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext, 733 jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) { 734 NPE_CHECK_RETURN_ZERO(env, jtext); 735 736 Paint* paint = reinterpret_cast<Paint*>(paintHandle); 737 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 738 739 int count = env->GetStringLength(jtext); 740 const jchar* text = env->GetStringChars(jtext, NULL); 741 count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards); 742 env->ReleaseStringChars(jtext, text); 743 return count; 744 } 745 746 static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds, 747 const Paint& paint, Typeface* typeface, jint bidiFlags) { 748 SkRect r; 749 SkIRect ir; 750 751 minikin::Layout layout; 752 MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count); 753 minikin::MinikinRect rect; 754 layout.getBounds(&rect); 755 r.fLeft = rect.mLeft; 756 r.fTop = rect.mTop; 757 r.fRight = rect.mRight; 758 r.fBottom = rect.mBottom; 759 r.roundOut(&ir); 760 GraphicsJNI::irect_to_jrect(ir, env, bounds); 761 } 762 763 static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle, 764 jstring text, jint start, jint end, jint bidiFlags, jobject bounds) { 765 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 766 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 767 const jchar* textArray = env->GetStringChars(text, NULL); 768 doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags); 769 env->ReleaseStringChars(text, textArray); 770 } 771 772 static void getCharArrayBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle, 773 jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) { 774 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 775 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 776 const jchar* textArray = env->GetCharArrayElements(text, NULL); 777 doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags); 778 env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), 779 JNI_ABORT); 780 } 781 782 static jboolean layoutContainsNotdef(const minikin::Layout& layout) { 783 for (size_t i = 0; i < layout.nGlyphs(); i++) { 784 if (layout.getGlyphId(i) == 0) { 785 return true; 786 } 787 } 788 return false; 789 } 790 791 // Don't count glyphs that are the recommended "space" glyph and are zero width. 792 // This logic makes assumptions about HarfBuzz layout, but does correctly handle 793 // cases where ligatures form and zero width space glyphs are left in as 794 // placeholders. 795 static size_t countNonSpaceGlyphs(const minikin::Layout& layout) { 796 size_t count = 0; 797 static unsigned int kSpaceGlyphId = 3; 798 for (size_t i = 0; i < layout.nGlyphs(); i++) { 799 if (layout.getGlyphId(i) != kSpaceGlyphId || layout.getCharAdvance(i) != 0.0) { 800 count++; 801 } 802 } 803 return count; 804 } 805 806 // Returns true if the given string is exact one pair of regional indicators. 807 static bool isFlag(const jchar* str, size_t length) { 808 const jchar RI_LEAD_SURROGATE = 0xD83C; 809 const jchar RI_TRAIL_SURROGATE_MIN = 0xDDE6; 810 const jchar RI_TRAIL_SURROGATE_MAX = 0xDDFF; 811 812 if (length != 4) { 813 return false; 814 } 815 if (str[0] != RI_LEAD_SURROGATE || str[2] != RI_LEAD_SURROGATE) { 816 return false; 817 } 818 return RI_TRAIL_SURROGATE_MIN <= str[1] && str[1] <= RI_TRAIL_SURROGATE_MAX && 819 RI_TRAIL_SURROGATE_MIN <= str[3] && str[3] <= RI_TRAIL_SURROGATE_MAX; 820 } 821 822 static jboolean hasGlyph(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle, 823 jint bidiFlags, jstring string) { 824 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 825 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 826 ScopedStringChars str(env, string); 827 828 /* Start by rejecting unsupported base code point and variation selector pairs. */ 829 size_t nChars = 0; 830 const uint32_t kStartOfString = 0xFFFFFFFF; 831 uint32_t prevCp = kStartOfString; 832 for (size_t i = 0; i < str.size(); i++) { 833 jchar cu = str[i]; 834 uint32_t cp = cu; 835 if (U16_IS_TRAIL(cu)) { 836 // invalid UTF-16, unpaired trailing surrogate 837 return false; 838 } else if (U16_IS_LEAD(cu)) { 839 if (i + 1 == str.size()) { 840 // invalid UTF-16, unpaired leading surrogate at end of string 841 return false; 842 } 843 i++; 844 jchar cu2 = str[i]; 845 if (!U16_IS_TRAIL(cu2)) { 846 // invalid UTF-16, unpaired leading surrogate 847 return false; 848 } 849 cp = U16_GET_SUPPLEMENTARY(cu, cu2); 850 } 851 852 if (prevCp != kStartOfString && 853 ((0xFE00 <= cp && cp <= 0xFE0F) || (0xE0100 <= cp && cp <= 0xE01EF))) { 854 bool hasVS = MinikinUtils::hasVariationSelector(typeface, prevCp, cp); 855 if (!hasVS) { 856 // No font has a glyph for the code point and variation selector pair. 857 return false; 858 } else if (nChars == 1 && i + 1 == str.size()) { 859 // The string is just a codepoint and a VS, we have an authoritative answer 860 return true; 861 } 862 } 863 nChars++; 864 prevCp = cp; 865 } 866 minikin::Layout layout; 867 MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, str.get(), 0, str.size(), 868 str.size()); 869 size_t nGlyphs = countNonSpaceGlyphs(layout); 870 if (nGlyphs != 1 && nChars > 1) { 871 // multiple-character input, and was not a ligature 872 // TODO: handle ZWJ/ZWNJ characters specially so we can detect certain ligatures 873 // in joining scripts, such as Arabic and Mongolian. 874 return false; 875 } 876 877 if (nGlyphs == 0 || layoutContainsNotdef(layout)) { 878 return false; // The collection doesn't have a glyph. 879 } 880 881 if (nChars == 2 && isFlag(str.get(), str.size())) { 882 // Some font may have a special glyph for unsupported regional indicator pairs. 883 // To return false for this case, need to compare the glyph id with the one of ZZ 884 // since ZZ is reserved for unknown or invalid territory. 885 // U+1F1FF (REGIONAL INDICATOR SYMBOL LETTER Z) is \uD83C\uDDFF in UTF16. 886 static const jchar ZZ_FLAG_STR[] = { 0xD83C, 0xDDFF, 0xD83C, 0xDDFF }; 887 minikin::Layout zzLayout; 888 MinikinUtils::doLayout(&zzLayout, paint, bidiFlags, typeface, ZZ_FLAG_STR, 0, 4, 4); 889 if (zzLayout.nGlyphs() != 1 || layoutContainsNotdef(zzLayout)) { 890 // The font collection doesn't have a glyph for unknown flag. Just return true. 891 return true; 892 } 893 return zzLayout.getGlyphId(0) != layout.getGlyphId(0); 894 } 895 return true; 896 } 897 898 static jfloat doRunAdvance(const Paint* paint, Typeface* typeface, const jchar buf[], 899 jint start, jint count, jint bufSize, jboolean isRtl, jint offset) { 900 int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR; 901 if (offset == start + count) { 902 return MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, 903 bufSize, nullptr); 904 } 905 std::unique_ptr<float[]> advancesArray(new float[count]); 906 MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize, 907 advancesArray.get()); 908 return minikin::getRunAdvance(advancesArray.get(), buf, start, count, offset); 909 } 910 911 static jfloat getRunAdvance___CIIIIZI_F(JNIEnv *env, jclass, jlong paintHandle, 912 jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart, 913 jint contextEnd, jboolean isRtl, jint offset) { 914 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 915 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 916 jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL); 917 jfloat result = doRunAdvance(paint, typeface, textArray + contextStart, 918 start - contextStart, end - start, contextEnd - contextStart, isRtl, 919 offset - contextStart); 920 env->ReleasePrimitiveArrayCritical(text, textArray, JNI_ABORT); 921 return result; 922 } 923 924 static jint doOffsetForAdvance(const Paint* paint, Typeface* typeface, const jchar buf[], 925 jint start, jint count, jint bufSize, jboolean isRtl, jfloat advance) { 926 int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR; 927 std::unique_ptr<float[]> advancesArray(new float[count]); 928 MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize, 929 advancesArray.get()); 930 return minikin::getOffsetForAdvance(advancesArray.get(), buf, start, count, advance); 931 } 932 933 static jint getOffsetForAdvance___CIIIIZF_I(JNIEnv *env, jclass, jlong paintHandle, 934 jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart, 935 jint contextEnd, jboolean isRtl, jfloat advance) { 936 const Paint* paint = reinterpret_cast<Paint*>(paintHandle); 937 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle); 938 jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL); 939 jint result = doOffsetForAdvance(paint, typeface, textArray + contextStart, 940 start - contextStart, end - start, contextEnd - contextStart, isRtl, advance); 941 result += contextStart; 942 env->ReleasePrimitiveArrayCritical(text, textArray, JNI_ABORT); 943 return result; 944 } 945 946}; // namespace PaintGlue 947 948static const JNINativeMethod methods[] = { 949 {"nGetNativeFinalizer", "()J", (void*) PaintGlue::getNativeFinalizer}, 950 {"nInit","()J", (void*) PaintGlue::init}, 951 {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint}, 952 953 {"nReset","!(J)V", (void*) PaintGlue::reset}, 954 {"nSet","!(JJ)V", (void*) PaintGlue::assign}, 955 {"nGetFlags","!(J)I", (void*) PaintGlue::getFlags}, 956 {"nSetFlags","!(JI)V", (void*) PaintGlue::setFlags}, 957 {"nGetHinting","!(J)I", (void*) PaintGlue::getHinting}, 958 {"nSetHinting","!(JI)V", (void*) PaintGlue::setHinting}, 959 {"nSetAntiAlias","!(JZ)V", (void*) PaintGlue::setAntiAlias}, 960 {"nSetSubpixelText","!(JZ)V", (void*) PaintGlue::setSubpixelText}, 961 {"nSetLinearText","!(JZ)V", (void*) PaintGlue::setLinearText}, 962 {"nSetUnderlineText","!(JZ)V", (void*) PaintGlue::setUnderlineText}, 963 {"nSetStrikeThruText","!(JZ)V", (void*) PaintGlue::setStrikeThruText}, 964 {"nSetFakeBoldText","!(JZ)V", (void*) PaintGlue::setFakeBoldText}, 965 {"nSetFilterBitmap","!(JZ)V", (void*) PaintGlue::setFilterBitmap}, 966 {"nSetDither","!(JZ)V", (void*) PaintGlue::setDither}, 967 {"nGetStyle","!(J)I", (void*) PaintGlue::getStyle}, 968 {"nSetStyle","!(JI)V", (void*) PaintGlue::setStyle}, 969 {"nGetColor","!(J)I", (void*) PaintGlue::getColor}, 970 {"nSetColor","!(JI)V", (void*) PaintGlue::setColor}, 971 {"nGetAlpha","!(J)I", (void*) PaintGlue::getAlpha}, 972 {"nSetAlpha","!(JI)V", (void*) PaintGlue::setAlpha}, 973 {"nGetStrokeWidth","!(J)F", (void*) PaintGlue::getStrokeWidth}, 974 {"nSetStrokeWidth","!(JF)V", (void*) PaintGlue::setStrokeWidth}, 975 {"nGetStrokeMiter","!(J)F", (void*) PaintGlue::getStrokeMiter}, 976 {"nSetStrokeMiter","!(JF)V", (void*) PaintGlue::setStrokeMiter}, 977 {"nGetStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap}, 978 {"nSetStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap}, 979 {"nGetStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin}, 980 {"nSetStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin}, 981 {"nGetFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath}, 982 {"nSetShader","!(JJ)J", (void*) PaintGlue::setShader}, 983 {"nSetColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter}, 984 {"nSetXfermode","!(JI)V", (void*) PaintGlue::setXfermode}, 985 {"nSetPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect}, 986 {"nSetMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter}, 987 {"nSetTypeface","!(JJ)J", (void*) PaintGlue::setTypeface}, 988 {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer}, 989 {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign}, 990 {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign}, 991 {"nSetTextLocales","!(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales}, 992 {"nSetTextLocalesByMinikinLangListId","!(JI)V", 993 (void*) PaintGlue::setTextLocalesByMinikinLangListId}, 994 {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight}, 995 {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight}, 996 {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize}, 997 {"nSetTextSize","!(JF)V", (void*) PaintGlue::setTextSize}, 998 {"nGetTextScaleX","!(J)F", (void*) PaintGlue::getTextScaleX}, 999 {"nSetTextScaleX","!(JF)V", (void*) PaintGlue::setTextScaleX}, 1000 {"nGetTextSkewX","!(J)F", (void*) PaintGlue::getTextSkewX}, 1001 {"nSetTextSkewX","!(JF)V", (void*) PaintGlue::setTextSkewX}, 1002 {"nGetLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing}, 1003 {"nSetLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing}, 1004 {"nSetFontFeatureSettings","(JLjava/lang/String;)V", 1005 (void*) PaintGlue::setFontFeatureSettings}, 1006 {"nGetHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit}, 1007 {"nSetHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit}, 1008 {"nAscent","!(JJ)F", (void*) PaintGlue::ascent}, 1009 {"nDescent","!(JJ)F", (void*) PaintGlue::descent}, 1010 1011 {"nGetFontMetrics", "!(JJLandroid/graphics/Paint$FontMetrics;)F", 1012 (void*)PaintGlue::getFontMetrics}, 1013 {"nGetFontMetricsInt", "!(JJLandroid/graphics/Paint$FontMetricsInt;)I", 1014 (void*)PaintGlue::getFontMetricsInt}, 1015 1016 {"nBreakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC}, 1017 {"nBreakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS}, 1018 {"nGetTextAdvances","(JJ[CIIIII[FI)F", 1019 (void*) PaintGlue::getTextAdvances___CIIIII_FI}, 1020 {"nGetTextAdvances","(JJLjava/lang/String;IIIII[FI)F", 1021 (void*) PaintGlue::getTextAdvances__StringIIIII_FI}, 1022 1023 {"nGetTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C}, 1024 {"nGetTextRunCursor", "(JLjava/lang/String;IIIII)I", 1025 (void*) PaintGlue::getTextRunCursor__String}, 1026 {"nGetTextPath", "(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C}, 1027 {"nGetTextPath", "(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String}, 1028 {"nGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V", 1029 (void*) PaintGlue::getStringBounds }, 1030 {"nGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V", 1031 (void*) PaintGlue::getCharArrayBounds }, 1032 {"nHasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph }, 1033 {"nGetRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F}, 1034 {"nGetOffsetForAdvance", "(JJ[CIIIIZF)I", 1035 (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I}, 1036 1037 {"nSetShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer}, 1038 {"nHasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer} 1039}; 1040 1041int register_android_graphics_Paint(JNIEnv* env) { 1042 gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics"); 1043 gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class); 1044 1045 gFontMetrics_fieldID.top = GetFieldIDOrDie(env, gFontMetrics_class, "top", "F"); 1046 gFontMetrics_fieldID.ascent = GetFieldIDOrDie(env, gFontMetrics_class, "ascent", "F"); 1047 gFontMetrics_fieldID.descent = GetFieldIDOrDie(env, gFontMetrics_class, "descent", "F"); 1048 gFontMetrics_fieldID.bottom = GetFieldIDOrDie(env, gFontMetrics_class, "bottom", "F"); 1049 gFontMetrics_fieldID.leading = GetFieldIDOrDie(env, gFontMetrics_class, "leading", "F"); 1050 1051 gFontMetricsInt_class = FindClassOrDie(env, "android/graphics/Paint$FontMetricsInt"); 1052 gFontMetricsInt_class = MakeGlobalRefOrDie(env, gFontMetricsInt_class); 1053 1054 gFontMetricsInt_fieldID.top = GetFieldIDOrDie(env, gFontMetricsInt_class, "top", "I"); 1055 gFontMetricsInt_fieldID.ascent = GetFieldIDOrDie(env, gFontMetricsInt_class, "ascent", "I"); 1056 gFontMetricsInt_fieldID.descent = GetFieldIDOrDie(env, gFontMetricsInt_class, "descent", "I"); 1057 gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I"); 1058 gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I"); 1059 1060 return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods)); 1061} 1062 1063} 1064