1 /* 2 * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "jni.h" 27 #include "jni_util.h" 28 #include "jlong.h" 29 #include "sunfontids.h" 30 #include "sun_font_FreetypeFontScaler.h" 31 32 #include <stdlib.h> 33 #if !defined(_WIN32) && !defined(__APPLE_) 34 #include <dlfcn.h> 35 #endif 36 #include <math.h> 37 #include "ft2build.h" 38 #include FT_FREETYPE_H 39 #include FT_GLYPH_H 40 #include FT_BBOX_H 41 #include FT_SIZES_H 42 #include FT_OUTLINE_H 43 #include FT_SYNTHESIS_H 44 #include FT_LCD_FILTER_H 45 #include FT_MODULE_H 46 47 #include "fontscaler.h" 48 49 #define ftFixed1 (FT_Fixed) (1 << 16) 50 #define FloatToFTFixed(f) (FT_Fixed)((f) * (float)(ftFixed1)) 51 #define FTFixedToFloat(x) ((x) / (float)(ftFixed1)) 52 #define FT26Dot6ToFloat(x) ((x) / ((float) (1<<6))) 53 #define FT26Dot6ToInt(x) (((int)(x)) >> 6) 54 55 typedef struct { 56 /* Important note: 57 JNI forbids sharing same env between different threads. 58 We are safe, because pointer is overwritten every time we get into 59 JNI call (see setupFTContext). 60 61 Pointer is used by font data reading callbacks 62 such as ReadTTFontFileFunc. 63 64 NB: We may consider switching to JNI_GetEnv. */ 65 JNIEnv* env; 66 FT_Library library; 67 FT_Face face; 68 FT_Stream faceStream; 69 jobject font2D; 70 jobject directBuffer; 71 72 unsigned char* fontData; 73 unsigned fontDataOffset; 74 unsigned fontDataLength; 75 unsigned fileSize; 76 } FTScalerInfo; 77 78 typedef struct FTScalerContext { 79 FT_Matrix transform; /* glyph transform, including device transform */ 80 jboolean useSbits; /* sbit usage enabled? */ 81 jint aaType; /* antialiasing mode (off/on/grey/lcd) */ 82 jint fmType; /* fractional metrics - on/off */ 83 jboolean doBold; /* perform algorithmic bolding? */ 84 jboolean doItalize; /* perform algorithmic italicizing? */ 85 int renderFlags; /* configuration specific to particular engine */ 86 int pathType; 87 int ptsz; /* size in points */ 88 } FTScalerContext; 89 90 #ifdef DEBUG 91 /* These are referenced in the freetype sources if DEBUG macro is defined. 92 To simplify work with debuging version of freetype we define 93 them here. */ 94 int z_verbose; 95 void z_error(char *s) {} 96 #endif 97 98 /**************** Error handling utilities *****************/ 99 100 static jmethodID invalidateScalerMID; 101 102 JNIEXPORT void JNICALL 103 Java_sun_font_FreetypeFontScaler_initIDs( 104 JNIEnv *env, jobject scaler, jclass FFSClass) { 105 invalidateScalerMID = 106 (*env)->GetMethodID(env, FFSClass, "invalidateScaler", "()V"); 107 } 108 109 static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) { 110 111 if (scalerInfo == NULL) 112 return; 113 114 // FT_Done_Face always closes the stream, but only frees the memory 115 // of the data structure if it was internally allocated by FT. 116 // We hold on to a pointer to the stream structure if we provide it 117 // ourselves, so that we can free it here. 118 FT_Done_Face(scalerInfo->face); 119 FT_Done_FreeType(scalerInfo->library); 120 121 if (scalerInfo->directBuffer != NULL) { 122 (*env)->DeleteGlobalRef(env, scalerInfo->directBuffer); 123 } 124 125 if (scalerInfo->fontData != NULL) { 126 free(scalerInfo->fontData); 127 } 128 129 if (scalerInfo->faceStream != NULL) { 130 free(scalerInfo->faceStream); 131 } 132 free(scalerInfo); 133 } 134 135 /* invalidates state of java scaler object */ 136 static void invalidateJavaScaler(JNIEnv *env, 137 jobject scaler, 138 FTScalerInfo* scalerInfo) { 139 freeNativeResources(env, scalerInfo); 140 (*env)->CallVoidMethod(env, scaler, invalidateScalerMID); 141 } 142 143 /******************* I/O handlers ***************************/ 144 145 #define FILEDATACACHESIZE 1024 146 147 static unsigned long ReadTTFontFileFunc(FT_Stream stream, 148 unsigned long offset, 149 unsigned char* destBuffer, 150 unsigned long numBytes) 151 { 152 FTScalerInfo *scalerInfo = (FTScalerInfo *) stream->pathname.pointer; 153 JNIEnv* env = scalerInfo->env; 154 jobject bBuffer; 155 int bread = 0; 156 157 if (numBytes == 0) return 0; 158 159 /* Large reads will bypass the cache and data copying */ 160 if (numBytes > FILEDATACACHESIZE) { 161 bBuffer = (*env)->NewDirectByteBuffer(env, destBuffer, numBytes); 162 if (bBuffer != NULL) { 163 bread = (*env)->CallIntMethod(env, 164 scalerInfo->font2D, 165 sunFontIDs.ttReadBlockMID, 166 bBuffer, offset, numBytes); 167 return bread; 168 } else { 169 /* We probably hit bug 4845371. For reasons that 170 * are currently unclear, the call stacks after the initial 171 * createScaler call that read large amounts of data seem to 172 * be OK and can create the byte buffer above, but this code 173 * is here just in case. 174 * 4845371 is fixed now so I don't expect this code path to 175 * ever get called but its harmless to leave it here on the 176 * small chance its needed. 177 */ 178 jbyteArray byteArray = (jbyteArray) 179 (*env)->CallObjectMethod(env, scalerInfo->font2D, 180 sunFontIDs.ttReadBytesMID, 181 offset, numBytes); 182 (*env)->GetByteArrayRegion(env, byteArray, 183 0, numBytes, (jbyte*)destBuffer); 184 return numBytes; 185 } 186 } /* Do we have a cache hit? */ 187 else if (scalerInfo->fontDataOffset <= offset && 188 scalerInfo->fontDataOffset + scalerInfo->fontDataLength >= 189 offset + numBytes) 190 { 191 unsigned cacheOffset = offset - scalerInfo->fontDataOffset; 192 193 memcpy(destBuffer, scalerInfo->fontData+(size_t)cacheOffset, numBytes); 194 return numBytes; 195 } else { 196 /* Must fill the cache */ 197 scalerInfo->fontDataOffset = offset; 198 scalerInfo->fontDataLength = 199 (offset + FILEDATACACHESIZE > scalerInfo->fileSize) ? 200 scalerInfo->fileSize - offset : FILEDATACACHESIZE; 201 bBuffer = scalerInfo->directBuffer; 202 bread = (*env)->CallIntMethod(env, scalerInfo->font2D, 203 sunFontIDs.ttReadBlockMID, 204 bBuffer, offset, 205 scalerInfo->fontDataLength); 206 memcpy(destBuffer, scalerInfo->fontData, numBytes); 207 return numBytes; 208 } 209 } 210 211 typedef FT_Error (*FT_Prop_Set_Func)(FT_Library library, 212 const FT_String* module_name, 213 const FT_String* property_name, 214 const void* value ); 215 216 /** 217 * Prefer the older v35 freetype byte code interpreter. 218 */ 219 static void setInterpreterVersion(FT_Library library) { 220 221 char* props = getenv("FREETYPE_PROPERTIES"); 222 int version = 35; 223 const char* module = "truetype"; 224 const char* property = "interpreter-version"; 225 226 /* If some one is setting this, don't override it */ 227 if (props != NULL && strstr(property, props)) { 228 return; 229 } 230 /* 231 * FT_Property_Set was introduced in 2.4.11. 232 * Some older supported Linux OSes may not include it so look 233 * this up dynamically. 234 * And if its not available it doesn't matter, since the reason 235 * we need it dates from 2.7. 236 * On Windows & Mac the library is always bundled so it is safe 237 * to use directly in those cases. 238 */ 239 #if defined(_WIN32) || defined(__APPLE__) 240 FT_Property_Set(library, module, property, (void*)(&version)); 241 #else 242 void *lib = dlopen("libfreetype.so", RTLD_LOCAL|RTLD_LAZY); 243 if (lib == NULL) { 244 lib = dlopen("libfreetype.so.6", RTLD_LOCAL|RTLD_LAZY); 245 if (lib == NULL) { 246 return; 247 } 248 } 249 FT_Prop_Set_Func func = (FT_Prop_Set_Func)dlsym(lib, "FT_Property_Set"); 250 if (func != NULL) { 251 func(library, module, property, (void*)(&version)); 252 } 253 dlclose(lib); 254 #endif 255 } 256 257 /* 258 * Class: sun_font_FreetypeFontScaler 259 * Method: initNativeScaler 260 * Signature: (Lsun/font/Font2D;IIZI)J 261 */ 262 JNIEXPORT jlong JNICALL 263 Java_sun_font_FreetypeFontScaler_initNativeScaler( 264 JNIEnv *env, jobject scaler, jobject font2D, jint type, 265 jint indexInCollection, jboolean supportsCJK, jint filesize) { 266 FTScalerInfo* scalerInfo = NULL; 267 FT_Open_Args ft_open_args; 268 int error; 269 jobject bBuffer; 270 scalerInfo = (FTScalerInfo*) calloc(1, sizeof(FTScalerInfo)); 271 272 if (scalerInfo == NULL) 273 return 0; 274 275 scalerInfo->env = env; 276 scalerInfo->font2D = font2D; 277 scalerInfo->fontDataOffset = 0; 278 scalerInfo->fontDataLength = 0; 279 scalerInfo->fileSize = filesize; 280 281 /* 282 We can consider sharing freetype library between different 283 scalers. However, Freetype docs suggest to use different libraries 284 for different threads. Also, our architecture implies that single 285 FontScaler object is shared for different sizes/transforms/styles 286 of the same font. 287 288 On other hand these methods can not be concurrently executed 289 becaused they are "synchronized" in java. 290 */ 291 error = FT_Init_FreeType(&scalerInfo->library); 292 if (error) { 293 free(scalerInfo); 294 return 0; 295 } 296 setInterpreterVersion(scalerInfo->library); 297 298 #define TYPE1_FROM_JAVA 2 299 300 error = 1; /* triggers memory freeing unless we clear it */ 301 if (type == TYPE1_FROM_JAVA) { /* TYPE1 */ 302 scalerInfo->fontData = (unsigned char*) malloc(filesize); 303 scalerInfo->directBuffer = NULL; 304 scalerInfo->fontDataLength = filesize; 305 306 if (scalerInfo->fontData != NULL) { 307 bBuffer = (*env)->NewDirectByteBuffer(env, 308 scalerInfo->fontData, 309 scalerInfo->fontDataLength); 310 if (bBuffer != NULL) { 311 (*env)->CallVoidMethod(env, font2D, 312 sunFontIDs.readFileMID, bBuffer); 313 314 error = FT_New_Memory_Face(scalerInfo->library, 315 scalerInfo->fontData, 316 scalerInfo->fontDataLength, 317 indexInCollection, 318 &scalerInfo->face); 319 } 320 } 321 } else { /* Truetype */ 322 scalerInfo->fontData = (unsigned char*) malloc(FILEDATACACHESIZE); 323 324 if (scalerInfo->fontData != NULL) { 325 FT_Stream ftstream = (FT_Stream) calloc(1, sizeof(FT_StreamRec)); 326 if (ftstream != NULL) { 327 scalerInfo->directBuffer = (*env)->NewDirectByteBuffer(env, 328 scalerInfo->fontData, 329 FILEDATACACHESIZE); 330 if (scalerInfo->directBuffer != NULL) { 331 scalerInfo->directBuffer = (*env)->NewGlobalRef(env, 332 scalerInfo->directBuffer); 333 ftstream->base = NULL; 334 ftstream->size = filesize; 335 ftstream->pos = 0; 336 ftstream->read = (FT_Stream_IoFunc) ReadTTFontFileFunc; 337 ftstream->close = NULL; 338 ftstream->pathname.pointer = (void *) scalerInfo; 339 340 memset(&ft_open_args, 0, sizeof(FT_Open_Args)); 341 ft_open_args.flags = FT_OPEN_STREAM; 342 ft_open_args.stream = ftstream; 343 344 error = FT_Open_Face(scalerInfo->library, 345 &ft_open_args, 346 indexInCollection, 347 &scalerInfo->face); 348 if (!error) { 349 scalerInfo->faceStream = ftstream; 350 } 351 } 352 if (error || scalerInfo->directBuffer == NULL) { 353 free(ftstream); 354 } 355 } 356 } 357 } 358 359 if (error) { 360 FT_Done_FreeType(scalerInfo->library); 361 if (scalerInfo->directBuffer != NULL) { 362 (*env)->DeleteGlobalRef(env, scalerInfo->directBuffer); 363 } 364 if (scalerInfo->fontData != NULL) 365 free(scalerInfo->fontData); 366 free(scalerInfo); 367 return 0; 368 } 369 370 return ptr_to_jlong(scalerInfo); 371 } 372 373 static double euclidianDistance(double a, double b) { 374 if (a < 0) a=-a; 375 if (b < 0) b=-b; 376 377 if (a == 0) return b; 378 if (b == 0) return a; 379 380 return sqrt(a*a+b*b); 381 } 382 383 JNIEXPORT jlong JNICALL 384 Java_sun_font_FreetypeFontScaler_createScalerContextNative( 385 JNIEnv *env, jobject scaler, jlong pScaler, jdoubleArray matrix, 386 jint aa, jint fm, jfloat boldness, jfloat italic) { 387 double dmat[4], ptsz; 388 FTScalerContext *context = 389 (FTScalerContext*) calloc(1, sizeof(FTScalerContext)); 390 FTScalerInfo *scalerInfo = 391 (FTScalerInfo*) jlong_to_ptr(pScaler); 392 393 if (context == NULL) { 394 invalidateJavaScaler(env, scaler, NULL); 395 return (jlong) 0; 396 } 397 (*env)->GetDoubleArrayRegion(env, matrix, 0, 4, dmat); 398 ptsz = euclidianDistance(dmat[2], dmat[3]); //i.e. y-size 399 if (ptsz < 1.0) { 400 //text can not be smaller than 1 point 401 ptsz = 1.0; 402 } 403 context->ptsz = (int)(ptsz * 64); 404 context->transform.xx = FloatToFTFixed((float)dmat[0]/ptsz); 405 context->transform.yx = -FloatToFTFixed((float)dmat[1]/ptsz); 406 context->transform.xy = -FloatToFTFixed((float)dmat[2]/ptsz); 407 context->transform.yy = FloatToFTFixed((float)dmat[3]/ptsz); 408 context->aaType = aa; 409 context->fmType = fm; 410 411 /* If using algorithmic styling, the base values are 412 * boldness = 1.0, italic = 0.0. 413 */ 414 context->doBold = (boldness != 1.0); 415 context->doItalize = (italic != 0); 416 417 /* freetype is very keen to use embedded bitmaps, even if it knows 418 * there is a rotation or you asked for antialiasing. 419 * In the rendering path we will check useSBits and disable 420 * bitmaps unless it is set. And here we set it only if none 421 * of the conditions invalidate using it. 422 * Note that we allow embedded bitmaps for the LCD case. 423 */ 424 if ((aa != TEXT_AA_ON) && (fm != TEXT_FM_ON) && 425 !context->doBold && !context->doItalize && 426 (context->transform.yx == 0) && (context->transform.xy == 0)) 427 { 428 context->useSbits = 1; 429 } 430 return ptr_to_jlong(context); 431 } 432 433 // values used by FreeType (as of version 2.10.1) for italics transformation matrix in FT_GlyphSlot_Oblique 434 #define FT_MATRIX_ONE 0x10000 435 #define FT_MATRIX_OBLIQUE_XY 0x0366A 436 437 static void setupTransform(FT_Matrix* target, FTScalerContext *context) { 438 FT_Matrix* transform = &context->transform; 439 if (context->doItalize) { 440 // we cannot use FT_GlyphSlot_Oblique as it doesn't work well with arbitrary transforms, 441 // so we add corresponding shear transform to the requested glyph transformation 442 target->xx = FT_MATRIX_ONE; 443 target->xy = FT_MATRIX_OBLIQUE_XY; 444 target->yx = 0; 445 target->yy = FT_MATRIX_ONE; 446 FT_Matrix_Multiply(transform, target); 447 } else { 448 target->xx = transform->xx; 449 target->xy = transform->xy; 450 target->yx = transform->yx; 451 target->yy = transform->yy; 452 } 453 } 454 455 static int setupFTContext(JNIEnv *env, 456 jobject font2D, 457 FTScalerInfo *scalerInfo, 458 FTScalerContext *context) { 459 FT_Matrix matrix; 460 int errCode = 0; 461 462 scalerInfo->env = env; 463 scalerInfo->font2D = font2D; 464 465 if (context != NULL) { 466 setupTransform(&matrix, context); 467 FT_Set_Transform(scalerInfo->face, &matrix, NULL); 468 469 errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72); 470 471 if (errCode == 0) { 472 errCode = FT_Activate_Size(scalerInfo->face->size); 473 } 474 475 FT_Library_SetLcdFilter(scalerInfo->library, FT_LCD_FILTER_DEFAULT); 476 } 477 478 return errCode; 479 } 480 481 // using same values as for the transformation matrix 482 #define OBLIQUE_MODIFIER(y) (context->doItalize ? ((y)*FT_MATRIX_OBLIQUE_XY/FT_MATRIX_ONE) : 0) 483 484 /* FT_GlyphSlot_Embolden (ftsynth.c) uses FT_MulFix(units_per_EM, y_scale) / 24 485 * strength value when glyph format is FT_GLYPH_FORMAT_OUTLINE. This value has 486 * been taken from libfreetype version 2.6 and remain valid at least up to 487 * 2.9.1. */ 488 #define BOLD_MODIFIER(units_per_EM, y_scale) \ 489 (context->doBold ? FT_MulFix(units_per_EM, y_scale) / 24 : 0) 490 491 /* 492 * Class: sun_font_FreetypeFontScaler 493 * Method: getFontMetricsNative 494 * Signature: (Lsun/font/Font2D;J)Lsun/font/StrikeMetrics; 495 */ 496 JNIEXPORT jobject JNICALL 497 Java_sun_font_FreetypeFontScaler_getFontMetricsNative( 498 JNIEnv *env, jobject scaler, jobject font2D, 499 jlong pScalerContext, jlong pScaler) { 500 501 jobject metrics; 502 jfloat ax, ay, dx, dy, bx, by, lx, ly, mx, my; 503 jfloat f0 = 0.0; 504 FTScalerContext *context = 505 (FTScalerContext*) jlong_to_ptr(pScalerContext); 506 FTScalerInfo *scalerInfo = 507 (FTScalerInfo*) jlong_to_ptr(pScaler); 508 509 int errCode; 510 511 if (isNullScalerContext(context) || scalerInfo == NULL) { 512 return (*env)->NewObject(env, 513 sunFontIDs.strikeMetricsClass, 514 sunFontIDs.strikeMetricsCtr, 515 f0, f0, f0, f0, f0, f0, f0, f0, f0, f0); 516 } 517 518 errCode = setupFTContext(env, font2D, scalerInfo, context); 519 520 if (errCode) { 521 metrics = (*env)->NewObject(env, 522 sunFontIDs.strikeMetricsClass, 523 sunFontIDs.strikeMetricsCtr, 524 f0, f0, f0, f0, f0, f0, f0, f0, f0, f0); 525 invalidateJavaScaler(env, scaler, scalerInfo); 526 return metrics; 527 } 528 529 /* This is ugly and has to be reworked. 530 Freetype provide means to add style to glyph but 531 it seems there is no way to adjust metrics accordingly. 532 533 So, we have to do adust them explicitly and stay consistent with what 534 freetype does to outlines. */ 535 536 537 /**** Note: only some metrics are affected by styling ***/ 538 539 /* See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=657854 */ 540 #define FT_MulFixFloatShift6(a, b) (((float) (a)) * ((float) (b)) / 65536.0 / 64.0) 541 542 #define contextAwareMetricsX(x, y) \ 543 (FTFixedToFloat(context->transform.xx) * (x) - \ 544 FTFixedToFloat(context->transform.xy) * (y)) 545 546 #define contextAwareMetricsY(x, y) \ 547 (-FTFixedToFloat(context->transform.yx) * (x) + \ 548 FTFixedToFloat(context->transform.yy) * (y)) 549 550 /* 551 * See FreeType source code: src/base/ftobjs.c ft_recompute_scaled_metrics() 552 * http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1659 553 */ 554 /* ascent */ 555 ax = 0; 556 ay = -(jfloat) (FT_MulFixFloatShift6( 557 ((jlong) scalerInfo->face->ascender), 558 (jlong) scalerInfo->face->size->metrics.y_scale)); 559 /* descent */ 560 dx = 0; 561 dy = -(jfloat) (FT_MulFixFloatShift6( 562 ((jlong) scalerInfo->face->descender), 563 (jlong) scalerInfo->face->size->metrics.y_scale)); 564 /* baseline */ 565 bx = by = 0; 566 567 /* leading */ 568 lx = 0; 569 ly = (jfloat) (FT_MulFixFloatShift6( 570 (jlong) scalerInfo->face->height, 571 (jlong) scalerInfo->face->size->metrics.y_scale)) 572 + ay - dy; 573 /* max advance */ 574 mx = (jfloat) FT26Dot6ToFloat( 575 scalerInfo->face->size->metrics.max_advance + 576 OBLIQUE_MODIFIER(scalerInfo->face->size->metrics.height) + 577 BOLD_MODIFIER(scalerInfo->face->units_per_EM, 578 scalerInfo->face->size->metrics.y_scale)); 579 my = 0; 580 581 metrics = (*env)->NewObject(env, 582 sunFontIDs.strikeMetricsClass, 583 sunFontIDs.strikeMetricsCtr, 584 contextAwareMetricsX(ax, ay), contextAwareMetricsY(ax, ay), 585 contextAwareMetricsX(dx, dy), contextAwareMetricsY(dx, dy), 586 bx, by, 587 contextAwareMetricsX(lx, ly), contextAwareMetricsY(lx, ly), 588 contextAwareMetricsX(mx, my), contextAwareMetricsY(mx, my)); 589 590 return metrics; 591 } 592 593 /* 594 * Class: sun_font_FreetypeFontScaler 595 * Method: getGlyphAdvanceNative 596 * Signature: (Lsun/font/Font2D;JI)F 597 */ 598 JNIEXPORT jfloat JNICALL 599 Java_sun_font_FreetypeFontScaler_getGlyphAdvanceNative( 600 JNIEnv *env, jobject scaler, jobject font2D, 601 jlong pScalerContext, jlong pScaler, jint glyphCode) { 602 603 /* This method is rarely used because requests for metrics are usually 604 coupled with request for bitmap and to large extend work can be reused 605 (to find out metrics we need to hint glyph). 606 So, we typically go through getGlyphImage code path. 607 608 For initial freetype implementation we delegate 609 all work to getGlyphImage but drop result image. 610 This is waste of work related to scan conversion and conversion from 611 freetype format to our format but for now this seems to be ok. 612 613 NB: investigate performance benefits of refactoring code 614 to avoid unnecesary work with bitmaps. */ 615 616 GlyphInfo *info; 617 jfloat advance; 618 jlong image; 619 620 image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative( 621 env, scaler, font2D, pScalerContext, pScaler, glyphCode); 622 info = (GlyphInfo*) jlong_to_ptr(image); 623 624 advance = info->advanceX; 625 626 free(info); 627 628 return advance; 629 } 630 631 /* 632 * Class: sun_font_FreetypeFontScaler 633 * Method: getGlyphMetricsNative 634 * Signature: (Lsun/font/Font2D;JILjava/awt/geom/Point2D/Float;)V 635 */ 636 JNIEXPORT void JNICALL 637 Java_sun_font_FreetypeFontScaler_getGlyphMetricsNative( 638 JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext, 639 jlong pScaler, jint glyphCode, jobject metrics) { 640 641 /* As initial implementation we delegate all work to getGlyphImage 642 but drop result image. This is clearly waste of resorces. 643 644 TODO: investigate performance benefits of refactoring code 645 by avoiding bitmap generation and conversion from FT 646 bitmap format. */ 647 GlyphInfo *info; 648 649 jlong image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative( 650 env, scaler, font2D, 651 pScalerContext, pScaler, glyphCode); 652 info = (GlyphInfo*) jlong_to_ptr(image); 653 654 (*env)->SetFloatField(env, metrics, sunFontIDs.xFID, info->advanceX); 655 (*env)->SetFloatField(env, metrics, sunFontIDs.yFID, info->advanceY); 656 657 free(info); 658 } 659 660 661 static GlyphInfo* getNullGlyphImage() { 662 GlyphInfo *glyphInfo = (GlyphInfo*) calloc(1, sizeof(GlyphInfo)); 663 return glyphInfo; 664 } 665 666 static void CopyBW2Grey8(const void* srcImage, int srcRowBytes, 667 void* dstImage, int dstRowBytes, 668 int width, int height) { 669 const UInt8* srcRow = (UInt8*)srcImage; 670 UInt8* dstRow = (UInt8*)dstImage; 671 int wholeByteCount = width >> 3; 672 int remainingBitsCount = width & 7; 673 int i, j; 674 675 while (height--) { 676 const UInt8* src8 = srcRow; 677 UInt8* dstByte = dstRow; 678 unsigned srcValue; 679 680 srcRow += srcRowBytes; 681 dstRow += dstRowBytes; 682 683 for (i = 0; i < wholeByteCount; i++) { 684 srcValue = *src8++; 685 for (j = 0; j < 8; j++) { 686 *dstByte++ = (srcValue & 0x80) ? 0xFF : 0; 687 srcValue <<= 1; 688 } 689 } 690 if (remainingBitsCount) { 691 srcValue = *src8; 692 for (j = 0; j < remainingBitsCount; j++) { 693 *dstByte++ = (srcValue & 0x80) ? 0xFF : 0; 694 srcValue <<= 1; 695 } 696 } 697 } 698 } 699 700 #define Grey4ToAlpha255(value) (((value) << 4) + ((value) >> 3)) 701 702 static void CopyGrey4ToGrey8(const void* srcImage, int srcRowBytes, 703 void* dstImage, int dstRowBytes, int width, int height) { 704 const UInt8* srcRow = (UInt8*) srcImage; 705 UInt8* dstRow = (UInt8*) dstImage; 706 int i; 707 708 while (height--) { 709 const UInt8* src8 = srcRow; 710 UInt8* dstByte = dstRow; 711 unsigned srcValue; 712 713 srcRow += srcRowBytes; 714 dstRow += dstRowBytes; 715 716 for (i = 0; i < width; i++) { 717 srcValue = *src8++; 718 *dstByte++ = Grey4ToAlpha255(srcValue & 0x0f); 719 *dstByte++ = Grey4ToAlpha255(srcValue >> 4); 720 } 721 } 722 } 723 724 /* We need it because FT rows are often padded to 4 byte boundaries 725 and our internal format is not padded */ 726 static void CopyFTSubpixelToSubpixel(const void* srcImage, int srcRowBytes, 727 void* dstImage, int dstRowBytes, 728 int width, int height) { 729 unsigned char *srcRow = (unsigned char *) srcImage; 730 unsigned char *dstRow = (unsigned char *) dstImage; 731 732 while (height--) { 733 memcpy(dstRow, srcRow, width); 734 srcRow += srcRowBytes; 735 dstRow += dstRowBytes; 736 } 737 } 738 739 /* We need it because FT rows are often padded to 4 byte boundaries 740 and our internal format is not padded */ 741 static void CopyFTSubpixelVToSubpixel(const void* srcImage, int srcRowBytes, 742 void* dstImage, int dstRowBytes, 743 int width, int height) { 744 unsigned char *srcRow = (unsigned char *) srcImage, *srcByte; 745 unsigned char *dstRow = (unsigned char *) dstImage, *dstByte; 746 int i; 747 748 while (height > 0) { 749 srcByte = srcRow; 750 dstByte = dstRow; 751 for (i = 0; i < width; i++) { 752 *dstByte++ = *srcByte; 753 *dstByte++ = *(srcByte + srcRowBytes); 754 *dstByte++ = *(srcByte + 2*srcRowBytes); 755 srcByte++; 756 } 757 srcRow += 3*srcRowBytes; 758 dstRow += dstRowBytes; 759 height -= 3; 760 } 761 } 762 763 764 /* 765 * Class: sun_font_FreetypeFontScaler 766 * Method: getGlyphImageNative 767 * Signature: (Lsun/font/Font2D;JI)J 768 */ 769 JNIEXPORT jlong JNICALL 770 Java_sun_font_FreetypeFontScaler_getGlyphImageNative( 771 JNIEnv *env, jobject scaler, jobject font2D, 772 jlong pScalerContext, jlong pScaler, jint glyphCode) { 773 774 int error, imageSize; 775 UInt16 width, height; 776 GlyphInfo *glyphInfo; 777 int renderFlags = FT_LOAD_DEFAULT, target; 778 FT_GlyphSlot ftglyph; 779 780 FTScalerContext* context = 781 (FTScalerContext*) jlong_to_ptr(pScalerContext); 782 FTScalerInfo *scalerInfo = 783 (FTScalerInfo*) jlong_to_ptr(pScaler); 784 785 if (isNullScalerContext(context) || scalerInfo == NULL) { 786 return ptr_to_jlong(getNullGlyphImage()); 787 } 788 789 error = setupFTContext(env, font2D, scalerInfo, context); 790 if (error) { 791 invalidateJavaScaler(env, scaler, scalerInfo); 792 return ptr_to_jlong(getNullGlyphImage()); 793 } 794 795 if (!context->useSbits) { 796 renderFlags |= FT_LOAD_NO_BITMAP; 797 } 798 799 /* NB: in case of non identity transform 800 we might also prefer to disable transform before hinting, 801 and apply it explicitly after hinting is performed. 802 Or we can disable hinting. */ 803 804 /* select appropriate hinting mode */ 805 if (context->aaType == TEXT_AA_OFF) { 806 target = FT_LOAD_TARGET_MONO; 807 } else if (context->aaType == TEXT_AA_ON) { 808 target = FT_LOAD_TARGET_NORMAL; 809 } else if (context->aaType == TEXT_AA_LCD_HRGB || 810 context->aaType == TEXT_AA_LCD_HBGR) { 811 target = FT_LOAD_TARGET_LCD; 812 } else { 813 target = FT_LOAD_TARGET_LCD_V; 814 } 815 renderFlags |= target; 816 817 error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags); 818 if (error) { 819 //do not destroy scaler yet. 820 //this can be problem of particular context (e.g. with bad transform) 821 return ptr_to_jlong(getNullGlyphImage()); 822 } 823 824 ftglyph = scalerInfo->face->glyph; 825 826 /* apply styles */ 827 if (context->doBold) { /* if bold style */ 828 FT_GlyphSlot_Embolden(ftglyph); 829 } 830 831 /* generate bitmap if it is not done yet 832 e.g. if algorithmic styling is performed and style was added to outline */ 833 if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) { 834 error = FT_Render_Glyph(ftglyph, FT_LOAD_TARGET_MODE(target)); 835 if (error != 0) { 836 return ptr_to_jlong(getNullGlyphImage()); 837 } 838 } 839 840 width = (UInt16) ftglyph->bitmap.width; 841 height = (UInt16) ftglyph->bitmap.rows; 842 843 imageSize = width*height; 844 glyphInfo = (GlyphInfo*) malloc(sizeof(GlyphInfo) + imageSize); 845 if (glyphInfo == NULL) { 846 glyphInfo = getNullGlyphImage(); 847 return ptr_to_jlong(glyphInfo); 848 } 849 glyphInfo->cellInfo = NULL; 850 glyphInfo->managed = UNMANAGED_GLYPH; 851 glyphInfo->rowBytes = width; 852 glyphInfo->width = width; 853 glyphInfo->height = height; 854 glyphInfo->topLeftX = (float) ftglyph->bitmap_left; 855 glyphInfo->topLeftY = (float) -ftglyph->bitmap_top; 856 857 if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) { 858 glyphInfo->width = width/3; 859 } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) { 860 glyphInfo->height = glyphInfo->height/3; 861 } 862 863 if (context->fmType == TEXT_FM_ON) { 864 double advh = FTFixedToFloat(ftglyph->linearHoriAdvance); 865 glyphInfo->advanceX = 866 (float) (advh * FTFixedToFloat(context->transform.xx)); 867 glyphInfo->advanceY = 868 (float) (advh * FTFixedToFloat(context->transform.xy)); 869 } else { 870 if (!ftglyph->advance.y) { 871 glyphInfo->advanceX = 872 (float) FT26Dot6ToInt(ftglyph->advance.x); 873 glyphInfo->advanceY = 0; 874 } else if (!ftglyph->advance.x) { 875 glyphInfo->advanceX = 0; 876 glyphInfo->advanceY = 877 (float) FT26Dot6ToInt(-ftglyph->advance.y); 878 } else { 879 glyphInfo->advanceX = FT26Dot6ToFloat(ftglyph->advance.x); 880 glyphInfo->advanceY = FT26Dot6ToFloat(-ftglyph->advance.y); 881 } 882 } 883 884 if (imageSize == 0) { 885 glyphInfo->image = NULL; 886 } else { 887 glyphInfo->image = (unsigned char*) glyphInfo + sizeof(GlyphInfo); 888 //convert result to output format 889 //output format is either 3 bytes per pixel (for subpixel modes) 890 // or 1 byte per pixel for AA and B&W 891 if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { 892 /* convert from 8 pixels per byte to 1 byte per pixel */ 893 CopyBW2Grey8(ftglyph->bitmap.buffer, 894 ftglyph->bitmap.pitch, 895 (void *) glyphInfo->image, 896 width, 897 width, 898 height); 899 } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { 900 /* byte per pixel to byte per pixel => just copy */ 901 memcpy(glyphInfo->image, ftglyph->bitmap.buffer, imageSize); 902 } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY4) { 903 /* 4 bits per pixel to byte per pixel */ 904 CopyGrey4ToGrey8(ftglyph->bitmap.buffer, 905 ftglyph->bitmap.pitch, 906 (void *) glyphInfo->image, 907 width, 908 width, 909 height); 910 } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) { 911 /* 3 bytes per pixel to 3 bytes per pixel */ 912 CopyFTSubpixelToSubpixel(ftglyph->bitmap.buffer, 913 ftglyph->bitmap.pitch, 914 (void *) glyphInfo->image, 915 width, 916 width, 917 height); 918 } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) { 919 /* 3 bytes per pixel to 3 bytes per pixel */ 920 CopyFTSubpixelVToSubpixel(ftglyph->bitmap.buffer, 921 ftglyph->bitmap.pitch, 922 (void *) glyphInfo->image, 923 width*3, 924 width, 925 height); 926 glyphInfo->rowBytes *=3; 927 } else { 928 free(glyphInfo); 929 glyphInfo = getNullGlyphImage(); 930 } 931 } 932 933 return ptr_to_jlong(glyphInfo); 934 } 935 936 /* 937 * Class: sun_font_FreetypeFontScaler 938 * Method: disposeNativeScaler 939 * Signature: (J)V 940 */ 941 JNIEXPORT void JNICALL 942 Java_sun_font_FreetypeFontScaler_disposeNativeScaler( 943 JNIEnv *env, jobject scaler, jobject font2D, jlong pScaler) { 944 FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler); 945 946 /* Freetype functions *may* cause callback to java 947 that can use cached values. Make sure our cache is up to date. 948 NB: scaler context is not important at this point, can use NULL. */ 949 int errCode = setupFTContext(env, font2D, scalerInfo, NULL); 950 if (errCode) { 951 return; 952 } 953 954 freeNativeResources(env, scalerInfo); 955 } 956 957 /* 958 * Class: sun_font_FreetypeFontScaler 959 * Method: getNumGlyphsNative 960 * Signature: ()I 961 */ 962 JNIEXPORT jint JNICALL 963 Java_sun_font_FreetypeFontScaler_getNumGlyphsNative( 964 JNIEnv *env, jobject scaler, jlong pScaler) { 965 FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler); 966 967 if (scalerInfo == NULL || scalerInfo->face == NULL) { /* bad/null scaler */ 968 /* null scaler can render 1 glyph - "missing glyph" with code 0 969 (all glyph codes requested by user are mapped to code 0 at 970 validation step) */ 971 invalidateJavaScaler(env, scaler, scalerInfo); 972 return (jint) 1; 973 } 974 975 return (jint) scalerInfo->face->num_glyphs; 976 } 977 978 /* 979 * Class: sun_font_FreetypeFontScaler 980 * Method: getMissingGlyphCodeNative 981 * Signature: ()I 982 */ 983 JNIEXPORT jint JNICALL 984 Java_sun_font_FreetypeFontScaler_getMissingGlyphCodeNative( 985 JNIEnv *env, jobject scaler, jlong pScaler) { 986 987 /* Is it always 0 for freetype? */ 988 return 0; 989 } 990 991 /* 992 * Class: sun_font_FreetypeFontScaler 993 * Method: getGlyphCodeNative 994 * Signature: (C)I 995 */ 996 JNIEXPORT jint JNICALL 997 Java_sun_font_FreetypeFontScaler_getGlyphCodeNative( 998 JNIEnv *env, jobject scaler, 999 jobject font2D, jlong pScaler, jchar charCode) { 1000 1001 FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler); 1002 int errCode; 1003 1004 if (scaler == NULL || scalerInfo->face == NULL) { /* bad/null scaler */ 1005 invalidateJavaScaler(env, scaler, scalerInfo); 1006 return 0; 1007 } 1008 1009 /* Freetype functions *may* cause callback to java 1010 that can use cached values. Make sure our cache is up to date. 1011 Scaler context is not important here, can use NULL. */ 1012 errCode = setupFTContext(env, font2D, scalerInfo, NULL); 1013 if (errCode) { 1014 return 0; 1015 } 1016 1017 return FT_Get_Char_Index(scalerInfo->face, charCode); 1018 } 1019 1020 1021 #define FloatToF26Dot6(x) ((unsigned int) ((x)*64)) 1022 1023 static FT_Outline* getFTOutline(JNIEnv* env, jobject font2D, 1024 FTScalerContext *context, FTScalerInfo* scalerInfo, 1025 jint glyphCode, jfloat xpos, jfloat ypos) { 1026 int renderFlags; 1027 FT_Error error; 1028 FT_GlyphSlot ftglyph; 1029 1030 if (glyphCode >= INVISIBLE_GLYPHS || 1031 isNullScalerContext(context) || scalerInfo == NULL) { 1032 return NULL; 1033 } 1034 1035 error = setupFTContext(env, font2D, scalerInfo, context); 1036 if (error) { 1037 return NULL; 1038 } 1039 1040 renderFlags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; 1041 1042 error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags); 1043 if (error) { 1044 return NULL; 1045 } 1046 1047 ftglyph = scalerInfo->face->glyph; 1048 1049 /* apply styles */ 1050 if (context->doBold) { /* if bold style */ 1051 FT_GlyphSlot_Embolden(ftglyph); 1052 } 1053 1054 FT_Outline_Translate(&ftglyph->outline, 1055 FloatToF26Dot6(xpos), 1056 -FloatToF26Dot6(ypos)); 1057 1058 return &ftglyph->outline; 1059 } 1060 1061 #define F26Dot6ToFloat(n) (((float)(n))/((float) 64)) 1062 1063 /* Types of GeneralPath segments. 1064 TODO: pull constants from other place? */ 1065 1066 #define SEG_UNKNOWN -1 1067 #define SEG_MOVETO 0 1068 #define SEG_LINETO 1 1069 #define SEG_QUADTO 2 1070 #define SEG_CUBICTO 3 1071 #define SEG_CLOSE 4 1072 1073 #define WIND_NON_ZERO 0 1074 #define WIND_EVEN_ODD 1 1075 1076 /* Placeholder to accumulate GeneralPath data */ 1077 typedef struct { 1078 jint numTypes; 1079 jint numCoords; 1080 jint lenTypes; 1081 jint lenCoords; 1082 jint wr; 1083 jbyte* pointTypes; 1084 jfloat* pointCoords; 1085 } GPData; 1086 1087 /* returns 0 on failure */ 1088 static int allocateSpaceForGP(GPData* gpdata, int npoints, int ncontours) { 1089 int maxTypes, maxCoords; 1090 1091 /* we may have up to N intermediate points per contour 1092 (and for each point can actually cause new curve to be generated) 1093 In addition we can also have 2 extra point per outline. 1094 */ 1095 maxTypes = 2*npoints + 2*ncontours; 1096 maxCoords = 4*(npoints + 2*ncontours); //we may need to insert 1097 //up to n-1 intermediate points 1098 1099 /* first usage - allocate space and intialize all fields */ 1100 if (gpdata->pointTypes == NULL || gpdata->pointCoords == NULL) { 1101 gpdata->lenTypes = maxTypes; 1102 gpdata->lenCoords = maxCoords; 1103 gpdata->pointTypes = (jbyte*) 1104 malloc(gpdata->lenTypes*sizeof(jbyte)); 1105 gpdata->pointCoords = (jfloat*) 1106 malloc(gpdata->lenCoords*sizeof(jfloat)); 1107 gpdata->numTypes = 0; 1108 gpdata->numCoords = 0; 1109 gpdata->wr = WIND_NON_ZERO; /* By default, outlines are filled 1110 using the non-zero winding rule. */ 1111 } else { 1112 /* do we have enough space? */ 1113 if (gpdata->lenTypes - gpdata->numTypes < maxTypes) { 1114 gpdata->lenTypes += maxTypes; 1115 gpdata->pointTypes = (jbyte*) 1116 realloc(gpdata->pointTypes, gpdata->lenTypes*sizeof(jbyte)); 1117 } 1118 1119 if (gpdata->lenCoords - gpdata->numCoords < maxCoords) { 1120 gpdata->lenCoords += maxCoords; 1121 gpdata->pointCoords = (jfloat*) 1122 realloc(gpdata->pointCoords, gpdata->lenCoords*sizeof(jfloat)); 1123 } 1124 } 1125 1126 /* failure if any of mallocs failed */ 1127 if (gpdata->pointTypes == NULL || gpdata->pointCoords == NULL) 1128 return 0; 1129 else 1130 return 1; 1131 } 1132 1133 static void addSeg(GPData *gp, jbyte type) { 1134 gp->pointTypes[gp->numTypes++] = type; 1135 } 1136 1137 static void addCoords(GPData *gp, FT_Vector *p) { 1138 gp->pointCoords[gp->numCoords++] = F26Dot6ToFloat(p->x); 1139 gp->pointCoords[gp->numCoords++] = -F26Dot6ToFloat(p->y); 1140 } 1141 1142 static int moveTo(FT_Vector *to, GPData *gp) { 1143 if (gp->numCoords) 1144 addSeg(gp, SEG_CLOSE); 1145 addCoords(gp, to); 1146 addSeg(gp, SEG_MOVETO); 1147 return FT_Err_Ok; 1148 } 1149 1150 static int lineTo(FT_Vector *to, GPData *gp) { 1151 addCoords(gp, to); 1152 addSeg(gp, SEG_LINETO); 1153 return FT_Err_Ok; 1154 } 1155 1156 static int conicTo(FT_Vector *control, FT_Vector *to, GPData *gp) { 1157 addCoords(gp, control); 1158 addCoords(gp, to); 1159 addSeg(gp, SEG_QUADTO); 1160 return FT_Err_Ok; 1161 } 1162 1163 static int cubicTo(FT_Vector *control1, 1164 FT_Vector *control2, 1165 FT_Vector *to, 1166 GPData *gp) { 1167 addCoords(gp, control1); 1168 addCoords(gp, control2); 1169 addCoords(gp, to); 1170 addSeg(gp, SEG_CUBICTO); 1171 return FT_Err_Ok; 1172 } 1173 1174 static void addToGP(GPData* gpdata, FT_Outline*outline) { 1175 static const FT_Outline_Funcs outline_funcs = { 1176 (FT_Outline_MoveToFunc) moveTo, 1177 (FT_Outline_LineToFunc) lineTo, 1178 (FT_Outline_ConicToFunc) conicTo, 1179 (FT_Outline_CubicToFunc) cubicTo, 1180 0, /* shift */ 1181 0, /* delta */ 1182 }; 1183 1184 FT_Outline_Decompose(outline, &outline_funcs, gpdata); 1185 if (gpdata->numCoords) 1186 addSeg(gpdata, SEG_CLOSE); 1187 1188 /* If set to 1, the outline will be filled using the even-odd fill rule */ 1189 if (outline->flags & FT_OUTLINE_EVEN_ODD_FILL) { 1190 gpdata->wr = WIND_EVEN_ODD; 1191 } 1192 } 1193 1194 static void freeGP(GPData* gpdata) { 1195 if (gpdata->pointCoords != NULL) { 1196 free(gpdata->pointCoords); 1197 gpdata->pointCoords = NULL; 1198 gpdata->numCoords = 0; 1199 gpdata->lenCoords = 0; 1200 } 1201 if (gpdata->pointTypes != NULL) { 1202 free(gpdata->pointTypes); 1203 gpdata->pointTypes = NULL; 1204 gpdata->numTypes = 0; 1205 gpdata->lenTypes = 0; 1206 } 1207 } 1208 1209 static jobject getGlyphGeneralPath(JNIEnv* env, jobject font2D, 1210 FTScalerContext *context, FTScalerInfo *scalerInfo, 1211 jint glyphCode, jfloat xpos, jfloat ypos) { 1212 1213 FT_Outline* outline; 1214 jobject gp = NULL; 1215 jbyteArray types; 1216 jfloatArray coords; 1217 GPData gpdata; 1218 1219 outline = getFTOutline(env, font2D, context, scalerInfo, 1220 glyphCode, xpos, ypos); 1221 1222 if (outline == NULL || outline->n_points == 0) { 1223 return gp; 1224 } 1225 1226 gpdata.pointTypes = NULL; 1227 gpdata.pointCoords = NULL; 1228 if (!allocateSpaceForGP(&gpdata, outline->n_points, outline->n_contours)) { 1229 return gp; 1230 } 1231 1232 addToGP(&gpdata, outline); 1233 1234 types = (*env)->NewByteArray(env, gpdata.numTypes); 1235 coords = (*env)->NewFloatArray(env, gpdata.numCoords); 1236 1237 if (types && coords) { 1238 (*env)->SetByteArrayRegion(env, types, 0, 1239 gpdata.numTypes, 1240 gpdata.pointTypes); 1241 (*env)->SetFloatArrayRegion(env, coords, 0, 1242 gpdata.numCoords, 1243 gpdata.pointCoords); 1244 gp = (*env)->NewObject(env, 1245 sunFontIDs.gpClass, 1246 sunFontIDs.gpCtr, 1247 gpdata.wr, 1248 types, 1249 gpdata.numTypes, 1250 coords, 1251 gpdata.numCoords); 1252 } 1253 1254 freeGP(&gpdata); 1255 1256 return gp; 1257 } 1258 1259 /* 1260 * Class: sun_font_FreetypeFontScaler 1261 * Method: getGlyphOutlineNative 1262 * Signature: (Lsun/font/Font2D;JIFF)Ljava/awt/geom/GeneralPath; 1263 */ 1264 JNIEXPORT jobject JNICALL 1265 Java_sun_font_FreetypeFontScaler_getGlyphOutlineNative( 1266 JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext, 1267 jlong pScaler, jint glyphCode, jfloat xpos, jfloat ypos) { 1268 1269 FTScalerContext *context = 1270 (FTScalerContext*) jlong_to_ptr(pScalerContext); 1271 FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler); 1272 1273 jobject gp = getGlyphGeneralPath(env, 1274 font2D, 1275 context, 1276 scalerInfo, 1277 glyphCode, 1278 xpos, 1279 ypos); 1280 if (gp == NULL) { /* can be legal */ 1281 gp = (*env)->NewObject(env, 1282 sunFontIDs.gpClass, 1283 sunFontIDs.gpCtrEmpty); 1284 } 1285 return gp; 1286 } 1287 1288 /* 1289 * Class: sun_font_FreetypeFontScaler 1290 * Method: getGlyphOutlineBoundsNative 1291 * Signature: (Lsun/font/Font2D;JI)Ljava/awt/geom/Rectangle2D/Float; 1292 */ 1293 JNIEXPORT jobject JNICALL 1294 Java_sun_font_FreetypeFontScaler_getGlyphOutlineBoundsNative( 1295 JNIEnv *env, jobject scaler, jobject font2D, 1296 jlong pScalerContext, jlong pScaler, jint glyphCode) { 1297 1298 FT_Outline *outline; 1299 FT_BBox bbox; 1300 int error; 1301 jobject bounds; 1302 1303 FTScalerContext *context = 1304 (FTScalerContext*) jlong_to_ptr(pScalerContext); 1305 FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler); 1306 1307 outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0); 1308 if (outline == NULL || outline->n_points == 0) { 1309 /* it is legal case, e.g. invisible glyph */ 1310 bounds = (*env)->NewObject(env, 1311 sunFontIDs.rect2DFloatClass, 1312 sunFontIDs.rect2DFloatCtr); 1313 return bounds; 1314 } 1315 1316 error = FT_Outline_Get_BBox(outline, &bbox); 1317 1318 //convert bbox 1319 if (error || bbox.xMin >= bbox.xMax || bbox.yMin >= bbox.yMax) { 1320 bounds = (*env)->NewObject(env, 1321 sunFontIDs.rect2DFloatClass, 1322 sunFontIDs.rect2DFloatCtr); 1323 } else { 1324 bounds = (*env)->NewObject(env, 1325 sunFontIDs.rect2DFloatClass, 1326 sunFontIDs.rect2DFloatCtr4, 1327 F26Dot6ToFloat(bbox.xMin), 1328 F26Dot6ToFloat(-bbox.yMax), 1329 F26Dot6ToFloat(bbox.xMax-bbox.xMin), 1330 F26Dot6ToFloat(bbox.yMax-bbox.yMin)); 1331 } 1332 1333 return bounds; 1334 } 1335 1336 /* 1337 * Class: sun_font_FreetypeFontScaler 1338 * Method: getGlyphVectorOutlineNative 1339 * Signature: (Lsun/font/Font2D;J[IIFF)Ljava/awt/geom/GeneralPath; 1340 */ 1341 JNIEXPORT jobject 1342 JNICALL 1343 Java_sun_font_FreetypeFontScaler_getGlyphVectorOutlineNative( 1344 JNIEnv *env, jobject scaler, jobject font2D, 1345 jlong pScalerContext, jlong pScaler, 1346 jintArray glyphArray, jint numGlyphs, jfloat xpos, jfloat ypos) { 1347 1348 FT_Outline* outline; 1349 jobject gp = NULL; 1350 jbyteArray types; 1351 jfloatArray coords; 1352 GPData gpdata; 1353 int i; 1354 jint *glyphs; 1355 1356 FTScalerContext *context = 1357 (FTScalerContext*) jlong_to_ptr(pScalerContext); 1358 FTScalerInfo *scalerInfo = 1359 (FTScalerInfo*) jlong_to_ptr(pScaler); 1360 1361 glyphs = NULL; 1362 if (numGlyphs > 0 && 0xffffffffu / sizeof(jint) >= numGlyphs) { 1363 glyphs = (jint*) malloc(numGlyphs*sizeof(jint)); 1364 } 1365 if (glyphs == NULL) { 1366 // We reach here if: 1367 // 1. numGlyphs <= 0, 1368 // 2. overflow check failed, or 1369 // 3. malloc failed. 1370 gp = (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty); 1371 return gp; 1372 } 1373 1374 (*env)->GetIntArrayRegion(env, glyphArray, 0, numGlyphs, glyphs); 1375 1376 gpdata.numCoords = 0; 1377 for (i=0; i<numGlyphs;i++) { 1378 if (glyphs[i] >= INVISIBLE_GLYPHS) { 1379 continue; 1380 } 1381 outline = getFTOutline(env, 1382 font2D, 1383 context, 1384 scalerInfo, 1385 glyphs[i], 1386 xpos, ypos); 1387 1388 if (outline == NULL || outline->n_points == 0) { 1389 continue; 1390 } 1391 1392 gpdata.pointTypes = NULL; 1393 gpdata.pointCoords = NULL; 1394 if (!allocateSpaceForGP(&gpdata, outline->n_points, 1395 outline->n_contours)) { 1396 break; 1397 } 1398 1399 addToGP(&gpdata, outline); 1400 } 1401 free(glyphs); 1402 1403 if (gpdata.numCoords != 0) { 1404 types = (*env)->NewByteArray(env, gpdata.numTypes); 1405 coords = (*env)->NewFloatArray(env, gpdata.numCoords); 1406 1407 if (types && coords) { 1408 (*env)->SetByteArrayRegion(env, types, 0, 1409 gpdata.numTypes, gpdata.pointTypes); 1410 (*env)->SetFloatArrayRegion(env, coords, 0, 1411 gpdata.numCoords, gpdata.pointCoords); 1412 1413 gp=(*env)->NewObject(env, 1414 sunFontIDs.gpClass, 1415 sunFontIDs.gpCtr, 1416 gpdata.wr, 1417 types, 1418 gpdata.numTypes, 1419 coords, 1420 gpdata.numCoords); 1421 return gp; 1422 } 1423 } 1424 return (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty); 1425 } 1426 1427 JNIEXPORT jlong JNICALL 1428 Java_sun_font_FreetypeFontScaler_getUnitsPerEMNative( 1429 JNIEnv *env, jobject scaler, jlong pScaler) { 1430 1431 FTScalerInfo *s = (FTScalerInfo* ) jlong_to_ptr(pScaler); 1432 1433 /* Freetype doc says: 1434 The number of font units per EM square for this face. 1435 This is typically 2048 for TrueType fonts, and 1000 for Type 1 fonts. 1436 Only relevant for scalable formats. 1437 However, layout engine might be not tested with anything but 2048. 1438 1439 NB: test it! */ 1440 if (s != NULL) { 1441 return s->face->units_per_EM; 1442 } 1443 return 2048; 1444 } 1445 1446 /* This native method is called by the OpenType layout engine. */ 1447 JNIEXPORT jobject JNICALL 1448 Java_sun_font_FreetypeFontScaler_getGlyphPointNative( 1449 JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext, 1450 jlong pScaler, jint glyphCode, jint pointNumber) { 1451 1452 FT_Outline* outline; 1453 jobject point = NULL; 1454 jfloat x=0, y=0; 1455 FTScalerContext *context = 1456 (FTScalerContext*) jlong_to_ptr(pScalerContext); 1457 FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler); 1458 1459 outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0); 1460 1461 if (outline != NULL && outline->n_points > pointNumber) { 1462 x = F26Dot6ToFloat(outline->points[pointNumber].x); 1463 y = -F26Dot6ToFloat(outline->points[pointNumber].y); 1464 } 1465 1466 return (*env)->NewObject(env, sunFontIDs.pt2DFloatClass, 1467 sunFontIDs.pt2DFloatCtr, x, y); 1468 }