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