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