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