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     /*
 465      * See FreeType source code: src/base/ftobjs.c ft_recompute_scaled_metrics()
 466      * http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1659
 467      */
 468     /* ascent */
 469     ax = 0;
 470     ay = -(jfloat) (FT_MulFixFloatShift6(
 471                        ((jlong) scalerInfo->face->ascender),
 472                        (jlong) scalerInfo->face->size->metrics.y_scale));
 473     /* descent */
 474     dx = 0;
 475     dy = -(jfloat) (FT_MulFixFloatShift6(
 476                        ((jlong) scalerInfo->face->descender),
 477                        (jlong) scalerInfo->face->size->metrics.y_scale));
 478     /* baseline */
 479     bx = by = 0;
 480 
 481     /* leading */
 482     lx = 0;
 483     ly = (jfloat) (FT_MulFixFloatShift6(
 484                       (jlong) scalerInfo->face->height,
 485                       (jlong) scalerInfo->face->size->metrics.y_scale))
 486                   + ay - dy;
 487     /* max advance */
 488     mx = (jfloat) FT26Dot6ToFloat(
 489                      scalerInfo->face->size->metrics.max_advance +
 490                      OBLIQUE_MODIFIER(scalerInfo->face->size->metrics.height));
 491     my = 0;
 492 
 493     metrics = (*env)->NewObject(env,
 494                                 sunFontIDs.strikeMetricsClass,
 495                                 sunFontIDs.strikeMetricsCtr,
 496                                 ax, ay, dx, dy, bx, by, lx, ly, mx, my);
 497 
 498     return metrics;
 499 }
 500 
 501 /*
 502  * Class:     sun_font_FreetypeFontScaler
 503  * Method:    getGlyphAdvanceNative
 504  * Signature: (Lsun/font/Font2D;JI)F
 505  */
 506 JNIEXPORT jfloat JNICALL
 507 Java_sun_font_FreetypeFontScaler_getGlyphAdvanceNative(
 508         JNIEnv *env, jobject scaler, jobject font2D,
 509         jlong pScalerContext, jlong pScaler, jint glyphCode) {
 510 
 511    /* This method is rarely used because requests for metrics are usually
 512       coupled with request for bitmap and to large extend work can be reused
 513       (to find out metrics we need to hint glyph).
 514       So, we typically go through getGlyphImage code path.
 515 
 516       For initial freetype implementation we delegate
 517       all work to getGlyphImage but drop result image.
 518       This is waste of work related to scan conversion and conversion from
 519       freetype format to our format but for now this seems to be ok.
 520 
 521       NB: investigate performance benefits of refactoring code
 522       to avoid unnecesary work with bitmaps. */
 523 
 524     GlyphInfo *info;
 525     jfloat advance;
 526     jlong image;
 527 
 528     image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
 529                  env, scaler, font2D, pScalerContext, pScaler, glyphCode);
 530     info = (GlyphInfo*) jlong_to_ptr(image);
 531 
 532     advance = info->advanceX;
 533 
 534     free(info);
 535 
 536     return advance;
 537 }
 538 
 539 /*
 540  * Class:     sun_font_FreetypeFontScaler
 541  * Method:    getGlyphMetricsNative
 542  * Signature: (Lsun/font/Font2D;JILjava/awt/geom/Point2D/Float;)V
 543  */
 544 JNIEXPORT void JNICALL
 545 Java_sun_font_FreetypeFontScaler_getGlyphMetricsNative(
 546         JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
 547         jlong pScaler, jint glyphCode, jobject metrics) {
 548 
 549      /* As initial implementation we delegate all work to getGlyphImage
 550         but drop result image. This is clearly waste of resorces.
 551 
 552         TODO: investigate performance benefits of refactoring code
 553               by avoiding bitmap generation and conversion from FT
 554               bitmap format. */
 555      GlyphInfo *info;
 556 
 557      jlong image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
 558                                  env, scaler, font2D,
 559                                  pScalerContext, pScaler, glyphCode);
 560      info = (GlyphInfo*) jlong_to_ptr(image);
 561 
 562      (*env)->SetFloatField(env, metrics, sunFontIDs.xFID, info->advanceX);
 563      (*env)->SetFloatField(env, metrics, sunFontIDs.yFID, info->advanceY);
 564 
 565      free(info);
 566 }
 567 
 568 
 569 static GlyphInfo* getNullGlyphImage() {
 570     GlyphInfo *glyphInfo =  (GlyphInfo*) calloc(1, sizeof(GlyphInfo));
 571     return glyphInfo;
 572 }
 573 
 574 static void CopyBW2Grey8(const void* srcImage, int srcRowBytes,
 575                          void* dstImage, int dstRowBytes,
 576                          int width, int height) {
 577     const UInt8* srcRow = (UInt8*)srcImage;
 578     UInt8* dstRow = (UInt8*)dstImage;
 579     int wholeByteCount = width >> 3;
 580     int remainingBitsCount = width & 7;
 581     int i, j;
 582 
 583     while (height--) {
 584         const UInt8* src8 = srcRow;
 585         UInt8* dstByte = dstRow;
 586         unsigned srcValue;
 587 
 588         srcRow += srcRowBytes;
 589         dstRow += dstRowBytes;
 590 
 591         for (i = 0; i < wholeByteCount; i++) {
 592             srcValue = *src8++;
 593             for (j = 0; j < 8; j++) {
 594                 *dstByte++ = (srcValue & 0x80) ? 0xFF : 0;
 595                 srcValue <<= 1;
 596             }
 597         }
 598         if (remainingBitsCount) {
 599             srcValue = *src8;
 600             for (j = 0; j < remainingBitsCount; j++) {
 601                 *dstByte++ = (srcValue & 0x80) ? 0xFF : 0;
 602                 srcValue <<= 1;
 603             }
 604         }
 605     }
 606 }
 607 
 608 #define Grey4ToAlpha255(value) (((value) << 4) + ((value) >> 3))
 609 
 610 static void CopyGrey4ToGrey8(const void* srcImage, int srcRowBytes,
 611                 void* dstImage, int dstRowBytes, int width, int height) {
 612      const UInt8* srcRow = (UInt8*) srcImage;
 613      UInt8* dstRow = (UInt8*) dstImage;
 614      int i;
 615 
 616      while (height--) {
 617          const UInt8* src8 = srcRow;
 618          UInt8* dstByte = dstRow;
 619          unsigned srcValue;
 620 
 621          srcRow += srcRowBytes;
 622          dstRow += dstRowBytes;
 623 
 624          for (i = 0; i < width; i++) {
 625              srcValue = *src8++;
 626              *dstByte++ = Grey4ToAlpha255(srcValue & 0x0f);
 627              *dstByte++ = Grey4ToAlpha255(srcValue >> 4);
 628          }
 629      }
 630 }
 631 
 632 /* We need it because FT rows are often padded to 4 byte boundaries
 633     and our internal format is not padded */
 634 static void CopyFTSubpixelToSubpixel(const void* srcImage, int srcRowBytes,
 635                                      void* dstImage, int dstRowBytes,
 636                                      int width, int height) {
 637     unsigned char *srcRow = (unsigned char *) srcImage;
 638     unsigned char *dstRow = (unsigned char *) dstImage;
 639 
 640     while (height--) {
 641         memcpy(dstRow, srcRow, width);
 642         srcRow += srcRowBytes;
 643         dstRow += dstRowBytes;
 644     }
 645 }
 646 
 647 /* We need it because FT rows are often padded to 4 byte boundaries
 648    and our internal format is not padded */
 649 static void CopyFTSubpixelVToSubpixel(const void* srcImage, int srcRowBytes,
 650                                       void* dstImage, int dstRowBytes,
 651                                       int width, int height) {
 652     unsigned char *srcRow = (unsigned char *) srcImage, *srcByte;
 653     unsigned char *dstRow = (unsigned char *) dstImage, *dstByte;
 654     int i;
 655 
 656     while (height > 0) {
 657         srcByte = srcRow;
 658         dstByte = dstRow;
 659         for (i = 0; i < width; i++) {
 660             *dstByte++ = *srcByte;
 661             *dstByte++ = *(srcByte + srcRowBytes);
 662             *dstByte++ = *(srcByte + 2*srcRowBytes);
 663             srcByte++;
 664         }
 665         srcRow += 3*srcRowBytes;
 666         dstRow += dstRowBytes;
 667         height -= 3;
 668     }
 669 }
 670 
 671 
 672 /*
 673  * Class:     sun_font_FreetypeFontScaler
 674  * Method:    getGlyphImageNative
 675  * Signature: (Lsun/font/Font2D;JI)J
 676  */
 677 JNIEXPORT jlong JNICALL
 678 Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
 679         JNIEnv *env, jobject scaler, jobject font2D,
 680         jlong pScalerContext, jlong pScaler, jint glyphCode) {
 681 
 682     int error, imageSize;
 683     UInt16 width, height;
 684     GlyphInfo *glyphInfo;
 685     int renderFlags = FT_LOAD_RENDER, target;
 686     FT_GlyphSlot ftglyph;
 687 
 688     FTScalerContext* context =
 689         (FTScalerContext*) jlong_to_ptr(pScalerContext);
 690     FTScalerInfo *scalerInfo =
 691              (FTScalerInfo*) jlong_to_ptr(pScaler);
 692 
 693     if (isNullScalerContext(context) || scalerInfo == NULL) {
 694         return ptr_to_jlong(getNullGlyphImage());
 695     }
 696 
 697     error = setupFTContext(env, font2D, scalerInfo, context);
 698     if (error) {
 699         invalidateJavaScaler(env, scaler, scalerInfo);
 700         return ptr_to_jlong(getNullGlyphImage());
 701     }
 702 
 703     if (!context->useSbits) {
 704         renderFlags |= FT_LOAD_NO_BITMAP;
 705         if (context->doBold || context->doItalize) {
 706             renderFlags &= ~FT_LOAD_RENDER;
 707         }
 708     }
 709 
 710     /* NB: in case of non identity transform
 711      we might also prefer to disable transform before hinting,
 712      and apply it explicitly after hinting is performed.
 713      Or we can disable hinting. */
 714 
 715     /* select appropriate hinting mode */
 716     if (context->aaType == TEXT_AA_OFF) {
 717         target = FT_LOAD_TARGET_MONO;
 718     } else if (context->aaType == TEXT_AA_ON) {
 719         target = FT_LOAD_TARGET_NORMAL;
 720     } else if (context->aaType == TEXT_AA_LCD_HRGB ||
 721                context->aaType == TEXT_AA_LCD_HBGR) {
 722         target = FT_LOAD_TARGET_LCD;
 723     } else {
 724         target = FT_LOAD_TARGET_LCD_V;
 725     }
 726     renderFlags |= target;
 727 
 728     error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags);
 729     if (error) {
 730         //do not destroy scaler yet.
 731         //this can be problem of particular context (e.g. with bad transform)
 732         return ptr_to_jlong(getNullGlyphImage());
 733     }
 734 
 735     ftglyph = scalerInfo->face->glyph;
 736 
 737     /* apply styles */
 738     if (context->doBold) { /* if bold style */
 739         FT_GlyphSlot_Embolden(ftglyph);
 740     }
 741     if (context->doItalize) { /* if oblique */
 742         FT_GlyphSlot_Oblique(ftglyph);
 743     }
 744 
 745     /* generate bitmap if it is not done yet
 746      e.g. if algorithmic styling is performed and style was added to outline */
 747     if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) {
 748         FT_Render_Glyph(ftglyph, FT_LOAD_TARGET_MODE(target));
 749     }
 750 
 751     width  = (UInt16) ftglyph->bitmap.width;
 752     height = (UInt16) ftglyph->bitmap.rows;
 753 
 754     imageSize = width*height;
 755     glyphInfo = (GlyphInfo*) malloc(sizeof(GlyphInfo) + imageSize);
 756     if (glyphInfo == NULL) {
 757         glyphInfo = getNullGlyphImage();
 758         return ptr_to_jlong(glyphInfo);
 759     }
 760     glyphInfo->cellInfo  = NULL;
 761     glyphInfo->managed   = UNMANAGED_GLYPH;
 762     glyphInfo->rowBytes  = width;
 763     glyphInfo->width     = width;
 764     glyphInfo->height    = height;
 765     glyphInfo->topLeftX  = (float)  ftglyph->bitmap_left;
 766     glyphInfo->topLeftY  = (float) -ftglyph->bitmap_top;
 767 
 768     if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD) {
 769         glyphInfo->width = width/3;
 770     } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD_V) {
 771         glyphInfo->height = glyphInfo->height/3;
 772     }
 773 
 774     if (context->fmType == TEXT_FM_ON) {
 775         double advh = FTFixedToFloat(ftglyph->linearHoriAdvance);
 776         glyphInfo->advanceX =
 777             (float) (advh * FTFixedToFloat(context->transform.xx));
 778         glyphInfo->advanceY =
 779             (float) (advh * FTFixedToFloat(context->transform.xy));
 780     } else {
 781         if (!ftglyph->advance.y) {
 782             glyphInfo->advanceX =
 783                 (float) FT26Dot6ToInt(ftglyph->advance.x);
 784             glyphInfo->advanceY = 0;
 785         } else if (!ftglyph->advance.x) {
 786             glyphInfo->advanceX = 0;
 787             glyphInfo->advanceY =
 788                 (float) FT26Dot6ToInt(-ftglyph->advance.y);
 789         } else {
 790             glyphInfo->advanceX = FT26Dot6ToFloat(ftglyph->advance.x);
 791             glyphInfo->advanceY = FT26Dot6ToFloat(-ftglyph->advance.y);
 792         }
 793     }
 794 
 795     if (imageSize == 0) {
 796         glyphInfo->image = NULL;
 797     } else {
 798         glyphInfo->image = (unsigned char*) glyphInfo + sizeof(GlyphInfo);
 799         //convert result to output format
 800         //output format is either 3 bytes per pixel (for subpixel modes)
 801         // or 1 byte per pixel for AA and B&W
 802         if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_MONO) {
 803             /* convert from 8 pixels per byte to 1 byte per pixel */
 804             CopyBW2Grey8(ftglyph->bitmap.buffer,
 805                          ftglyph->bitmap.pitch,
 806                          (void *) glyphInfo->image,
 807                          width,
 808                          width,
 809                          height);
 810         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_GRAY) {
 811             /* byte per pixel to byte per pixel => just copy */
 812             memcpy(glyphInfo->image, ftglyph->bitmap.buffer, imageSize);
 813         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_GRAY4) {
 814             /* 4 bits per pixel to byte per pixel */
 815             CopyGrey4ToGrey8(ftglyph->bitmap.buffer,
 816                              ftglyph->bitmap.pitch,
 817                              (void *) glyphInfo->image,
 818                              width,
 819                              width,
 820                              height);
 821         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD) {
 822             /* 3 bytes per pixel to 3 bytes per pixel */
 823             CopyFTSubpixelToSubpixel(ftglyph->bitmap.buffer,
 824                                      ftglyph->bitmap.pitch,
 825                                      (void *) glyphInfo->image,
 826                                      width,
 827                                      width,
 828                                      height);
 829         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD_V) {
 830             /* 3 bytes per pixel to 3 bytes per pixel */
 831             CopyFTSubpixelVToSubpixel(ftglyph->bitmap.buffer,
 832                                       ftglyph->bitmap.pitch,
 833                                       (void *) glyphInfo->image,
 834                                       width*3,
 835                                       width,
 836                                       height);
 837             glyphInfo->rowBytes *=3;
 838         } else {
 839             free(glyphInfo);
 840             glyphInfo = getNullGlyphImage();
 841         }
 842     }
 843 
 844     return ptr_to_jlong(glyphInfo);
 845 }
 846 
 847 
 848 /*
 849  * Class:     sun_font_FreetypeFontScaler
 850  * Method:    getLayoutTableCacheNative
 851  * Signature: (J)J
 852  */
 853 JNIEXPORT jlong JNICALL
 854 Java_sun_font_FreetypeFontScaler_getLayoutTableCacheNative(
 855         JNIEnv *env, jobject scaler, jlong pScaler) {
 856     FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
 857 
 858     if (scalerInfo == NULL) {
 859         invalidateJavaScaler(env, scaler, scalerInfo);
 860         return 0L;
 861     }
 862 
 863     // init layout table cache in font
 864     // we're assuming the font is a file font and moreover it is Truetype font
 865     // otherwise we shouldn't be able to get here...
 866     if (scalerInfo->layoutTables == NULL) {
 867         scalerInfo->layoutTables = newLayoutTableCache();
 868     }
 869 
 870     return ptr_to_jlong(scalerInfo->layoutTables);
 871 }
 872 
 873 /*
 874  * Class:     sun_font_FreetypeFontScaler
 875  * Method:    disposeNativeScaler
 876  * Signature: (J)V
 877  */
 878 JNIEXPORT void JNICALL
 879 Java_sun_font_FreetypeFontScaler_disposeNativeScaler(
 880         JNIEnv *env, jobject scaler, jobject font2D, jlong pScaler) {
 881     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 882 
 883     /* Freetype functions *may* cause callback to java
 884        that can use cached values. Make sure our cache is up to date.
 885        NB: scaler context is not important at this point, can use NULL. */
 886     int errCode = setupFTContext(env, font2D, scalerInfo, NULL);
 887     if (errCode) {
 888         return;
 889     }
 890 
 891     freeNativeResources(env, scalerInfo);
 892 }
 893 
 894 /*
 895  * Class:     sun_font_FreetypeFontScaler
 896  * Method:    getNumGlyphsNative
 897  * Signature: ()I
 898  */
 899 JNIEXPORT jint JNICALL
 900 Java_sun_font_FreetypeFontScaler_getNumGlyphsNative(
 901         JNIEnv *env, jobject scaler, jlong pScaler) {
 902     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 903 
 904     if (scalerInfo == NULL || scalerInfo->face == NULL) { /* bad/null scaler */
 905         /* null scaler can render 1 glyph - "missing glyph" with code 0
 906            (all glyph codes requested by user are mapped to code 0 at
 907            validation step) */
 908         invalidateJavaScaler(env, scaler, scalerInfo);
 909         return (jint) 1;
 910     }
 911 
 912     return (jint) scalerInfo->face->num_glyphs;
 913 }
 914 
 915 /*
 916  * Class:     sun_font_FreetypeFontScaler
 917  * Method:    getMissingGlyphCodeNative
 918  * Signature: ()I
 919  */
 920 JNIEXPORT jint JNICALL
 921 Java_sun_font_FreetypeFontScaler_getMissingGlyphCodeNative(
 922         JNIEnv *env, jobject scaler, jlong pScaler) {
 923 
 924     /* Is it always 0 for freetype? */
 925     return 0;
 926 }
 927 
 928 /*
 929  * Class:     sun_font_FreetypeFontScaler
 930  * Method:    getGlyphCodeNative
 931  * Signature: (C)I
 932  */
 933 JNIEXPORT jint JNICALL
 934 Java_sun_font_FreetypeFontScaler_getGlyphCodeNative(
 935         JNIEnv *env, jobject scaler,
 936         jobject font2D, jlong pScaler, jchar charCode) {
 937 
 938     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 939     int errCode;
 940 
 941     if (scaler == NULL || scalerInfo->face == NULL) { /* bad/null scaler */
 942         invalidateJavaScaler(env, scaler, scalerInfo);
 943         return 0;
 944     }
 945 
 946     /* Freetype functions *may* cause callback to java
 947        that can use cached values. Make sure our cache is up to date.
 948        Scaler context is not important here, can use NULL. */
 949     errCode = setupFTContext(env, font2D, scalerInfo, NULL);
 950     if (errCode) {
 951         return 0;
 952     }
 953 
 954     return FT_Get_Char_Index(scalerInfo->face, charCode);
 955 }
 956 
 957 
 958 #define FloatToF26Dot6(x) ((unsigned int) ((x)*64))
 959 
 960 static FT_Outline* getFTOutline(JNIEnv* env, jobject font2D,
 961         FTScalerContext *context, FTScalerInfo* scalerInfo,
 962         jint glyphCode, jfloat xpos, jfloat ypos) {
 963     int renderFlags;
 964     FT_Error error;
 965     FT_GlyphSlot ftglyph;
 966 
 967     if (glyphCode >= INVISIBLE_GLYPHS ||
 968             isNullScalerContext(context) || scalerInfo == NULL) {
 969         return NULL;
 970     }
 971 
 972     error = setupFTContext(env, font2D, scalerInfo, context);
 973     if (error) {
 974         return NULL;
 975     }
 976 
 977     renderFlags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
 978 
 979     error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags);
 980     if (error) {
 981         return NULL;
 982     }
 983 
 984     ftglyph = scalerInfo->face->glyph;
 985 
 986     /* apply styles */
 987     if (context->doBold) { /* if bold style */
 988         FT_GlyphSlot_Embolden(ftglyph);
 989     }
 990     if (context->doItalize) { /* if oblique */
 991         FT_GlyphSlot_Oblique(ftglyph);
 992     }
 993 
 994     FT_Outline_Translate(&ftglyph->outline,
 995                          FloatToF26Dot6(xpos),
 996                          -FloatToF26Dot6(ypos));
 997 
 998     return &ftglyph->outline;
 999 }
1000 
1001 #define F26Dot6ToFloat(n) (((float)(n))/((float) 64))
1002 
1003 /* Types of GeneralPath segments.
1004    TODO: pull constants from other place? */
1005 
1006 #define SEG_UNKNOWN -1
1007 #define SEG_MOVETO   0
1008 #define SEG_LINETO   1
1009 #define SEG_QUADTO   2
1010 #define SEG_CUBICTO  3
1011 #define SEG_CLOSE    4
1012 
1013 #define WIND_NON_ZERO 0
1014 #define WIND_EVEN_ODD 1
1015 
1016 /* Placeholder to accumulate GeneralPath data */
1017 typedef struct {
1018     jint numTypes;
1019     jint numCoords;
1020     jint lenTypes;
1021     jint lenCoords;
1022     jint wr;
1023     jbyte* pointTypes;
1024     jfloat* pointCoords;
1025 } GPData;
1026 
1027 /* returns 0 on failure */
1028 static int allocateSpaceForGP(GPData* gpdata, int npoints, int ncontours) {
1029     int maxTypes, maxCoords;
1030 
1031     /* we may have up to N intermediate points per contour
1032        (and for each point can actually cause new curve to be generated)
1033        In addition we can also have 2 extra point per outline.
1034      */
1035     maxTypes  = 2*npoints  + 2*ncontours;
1036     maxCoords = 4*(npoints + 2*ncontours); //we may need to insert
1037                                            //up to n-1 intermediate points
1038 
1039     /* first usage - allocate space and intialize all fields */
1040     if (gpdata->pointTypes == NULL || gpdata->pointCoords == NULL) {
1041         gpdata->lenTypes  = maxTypes;
1042         gpdata->lenCoords = maxCoords;
1043         gpdata->pointTypes  = (jbyte*)
1044              malloc(gpdata->lenTypes*sizeof(jbyte));
1045         gpdata->pointCoords = (jfloat*)
1046              malloc(gpdata->lenCoords*sizeof(jfloat));
1047         gpdata->numTypes = 0;
1048         gpdata->numCoords = 0;
1049         gpdata->wr = WIND_NON_ZERO; /* By default, outlines are filled
1050                                        using the non-zero winding rule. */
1051     } else {
1052         /* do we have enough space? */
1053         if (gpdata->lenTypes - gpdata->numTypes < maxTypes) {
1054             gpdata->lenTypes  += maxTypes;
1055             gpdata->pointTypes  = (jbyte*)
1056               realloc(gpdata->pointTypes, gpdata->lenTypes*sizeof(jbyte));
1057         }
1058 
1059         if (gpdata->lenCoords - gpdata->numCoords < maxCoords) {
1060             gpdata->lenCoords += maxCoords;
1061             gpdata->pointCoords = (jfloat*)
1062               realloc(gpdata->pointCoords, gpdata->lenCoords*sizeof(jfloat));
1063         }
1064     }
1065 
1066     /* failure if any of mallocs failed */
1067     if (gpdata->pointTypes == NULL ||  gpdata->pointCoords == NULL)
1068         return 0;
1069     else
1070         return 1;
1071 }
1072 
1073 static void addSeg(GPData *gp, jbyte type) {
1074     gp->pointTypes[gp->numTypes++] = type;
1075 }
1076 
1077 static void addCoords(GPData *gp, FT_Vector *p) {
1078     gp->pointCoords[gp->numCoords++] =  F26Dot6ToFloat(p->x);
1079     gp->pointCoords[gp->numCoords++] = -F26Dot6ToFloat(p->y);
1080 }
1081 
1082 static int moveTo(FT_Vector *to, GPData *gp) {
1083     if (gp->numCoords)
1084         addSeg(gp, SEG_CLOSE);
1085     addCoords(gp, to);
1086     addSeg(gp, SEG_MOVETO);
1087     return FT_Err_Ok;
1088 }
1089 
1090 static int lineTo(FT_Vector *to, GPData *gp) {
1091     addCoords(gp, to);
1092     addSeg(gp, SEG_LINETO);
1093     return FT_Err_Ok;
1094 }
1095 
1096 static int conicTo(FT_Vector *control, FT_Vector *to, GPData *gp) {
1097     addCoords(gp, control);
1098     addCoords(gp, to);
1099     addSeg(gp, SEG_QUADTO);
1100     return FT_Err_Ok;
1101 }
1102 
1103 static int cubicTo(FT_Vector *control1,
1104                    FT_Vector *control2,
1105                    FT_Vector *to,
1106                    GPData    *gp) {
1107     addCoords(gp, control1);
1108     addCoords(gp, control2);
1109     addCoords(gp, to);
1110     addSeg(gp, SEG_CUBICTO);
1111     return FT_Err_Ok;
1112 }
1113 
1114 static void addToGP(GPData* gpdata, FT_Outline*outline) {
1115     static const FT_Outline_Funcs outline_funcs = {
1116         (FT_Outline_MoveToFunc) moveTo,
1117         (FT_Outline_LineToFunc) lineTo,
1118         (FT_Outline_ConicToFunc) conicTo,
1119         (FT_Outline_CubicToFunc) cubicTo,
1120         0, /* shift */
1121         0, /* delta */
1122     };
1123 
1124     FT_Outline_Decompose(outline, &outline_funcs, gpdata);
1125     if (gpdata->numCoords)
1126         addSeg(gpdata, SEG_CLOSE);
1127 
1128     /* If set to 1, the outline will be filled using the even-odd fill rule */
1129     if (outline->flags & FT_OUTLINE_EVEN_ODD_FILL) {
1130         gpdata->wr = WIND_EVEN_ODD;
1131     }
1132 }
1133 
1134 static void freeGP(GPData* gpdata) {
1135     if (gpdata->pointCoords != NULL) {
1136         free(gpdata->pointCoords);
1137         gpdata->pointCoords = NULL;
1138         gpdata->numCoords = 0;
1139         gpdata->lenCoords = 0;
1140     }
1141     if (gpdata->pointTypes != NULL) {
1142         free(gpdata->pointTypes);
1143         gpdata->pointTypes = NULL;
1144         gpdata->numTypes = 0;
1145         gpdata->lenTypes = 0;
1146     }
1147 }
1148 
1149 static jobject getGlyphGeneralPath(JNIEnv* env, jobject font2D,
1150         FTScalerContext *context, FTScalerInfo *scalerInfo,
1151         jint glyphCode, jfloat xpos, jfloat ypos) {
1152 
1153     FT_Outline* outline;
1154     jobject gp = NULL;
1155     jbyteArray types;
1156     jfloatArray coords;
1157     GPData gpdata;
1158 
1159     outline = getFTOutline(env, font2D, context, scalerInfo,
1160                            glyphCode, xpos, ypos);
1161 
1162     if (outline == NULL || outline->n_points == 0) {
1163         return gp;
1164     }
1165 
1166     gpdata.pointTypes  = NULL;
1167     gpdata.pointCoords = NULL;
1168     if (!allocateSpaceForGP(&gpdata, outline->n_points, outline->n_contours)) {
1169         return gp;
1170     }
1171 
1172     addToGP(&gpdata, outline);
1173 
1174     types  = (*env)->NewByteArray(env, gpdata.numTypes);
1175     coords = (*env)->NewFloatArray(env, gpdata.numCoords);
1176 
1177     if (types && coords) {
1178         (*env)->SetByteArrayRegion(env, types, 0,
1179                                    gpdata.numTypes,
1180                                    gpdata.pointTypes);
1181         (*env)->SetFloatArrayRegion(env, coords, 0,
1182                                     gpdata.numCoords,
1183                                     gpdata.pointCoords);
1184         gp = (*env)->NewObject(env,
1185                                sunFontIDs.gpClass,
1186                                sunFontIDs.gpCtr,
1187                                gpdata.wr,
1188                                types,
1189                                gpdata.numTypes,
1190                                coords,
1191                                gpdata.numCoords);
1192     }
1193 
1194     freeGP(&gpdata);
1195 
1196     return gp;
1197 }
1198 
1199 /*
1200  * Class:     sun_font_FreetypeFontScaler
1201  * Method:    getGlyphOutlineNative
1202  * Signature: (Lsun/font/Font2D;JIFF)Ljava/awt/geom/GeneralPath;
1203  */
1204 JNIEXPORT jobject JNICALL
1205 Java_sun_font_FreetypeFontScaler_getGlyphOutlineNative(
1206       JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
1207       jlong pScaler, jint glyphCode, jfloat xpos, jfloat ypos) {
1208 
1209     FTScalerContext *context =
1210          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1211     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1212 
1213     jobject gp = getGlyphGeneralPath(env,
1214                                font2D,
1215                                context,
1216                                scalerInfo,
1217                                glyphCode,
1218                                xpos,
1219                                ypos);
1220     if (gp == NULL) { /* can be legal */
1221         gp = (*env)->NewObject(env,
1222                                sunFontIDs.gpClass,
1223                                sunFontIDs.gpCtrEmpty);
1224     }
1225     return gp;
1226 }
1227 
1228 /*
1229  * Class:     sun_font_FreetypeFontScaler
1230  * Method:    getGlyphOutlineBoundsNative
1231  * Signature: (Lsun/font/Font2D;JI)Ljava/awt/geom/Rectangle2D/Float;
1232  */
1233 JNIEXPORT jobject JNICALL
1234 Java_sun_font_FreetypeFontScaler_getGlyphOutlineBoundsNative(
1235         JNIEnv *env, jobject scaler, jobject font2D,
1236         jlong pScalerContext, jlong pScaler, jint glyphCode) {
1237 
1238     FT_Outline *outline;
1239     FT_BBox bbox;
1240     int error;
1241     jobject bounds;
1242 
1243     FTScalerContext *context =
1244          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1245     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1246 
1247     outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0);
1248     if (outline == NULL || outline->n_points == 0) {
1249         /* it is legal case, e.g. invisible glyph */
1250         bounds = (*env)->NewObject(env,
1251                                  sunFontIDs.rect2DFloatClass,
1252                                  sunFontIDs.rect2DFloatCtr);
1253         return bounds;
1254     }
1255 
1256     error = FT_Outline_Get_BBox(outline, &bbox);
1257 
1258     //convert bbox
1259     if (error || bbox.xMin >= bbox.xMax || bbox.yMin >= bbox.yMax) {
1260         bounds = (*env)->NewObject(env,
1261                                    sunFontIDs.rect2DFloatClass,
1262                                    sunFontIDs.rect2DFloatCtr);
1263     } else {
1264         bounds = (*env)->NewObject(env,
1265                                    sunFontIDs.rect2DFloatClass,
1266                                    sunFontIDs.rect2DFloatCtr4,
1267                                    F26Dot6ToFloat(bbox.xMin),
1268                                    F26Dot6ToFloat(-bbox.yMax),
1269                                    F26Dot6ToFloat(bbox.xMax-bbox.xMin),
1270                                    F26Dot6ToFloat(bbox.yMax-bbox.yMin));
1271     }
1272 
1273     return bounds;
1274 }
1275 
1276 /*
1277  * Class:     sun_font_FreetypeFontScaler
1278  * Method:    getGlyphVectorOutlineNative
1279  * Signature: (Lsun/font/Font2D;J[IIFF)Ljava/awt/geom/GeneralPath;
1280  */
1281 JNIEXPORT jobject
1282 JNICALL
1283 Java_sun_font_FreetypeFontScaler_getGlyphVectorOutlineNative(
1284         JNIEnv *env, jobject scaler, jobject font2D,
1285         jlong pScalerContext, jlong pScaler,
1286         jintArray glyphArray, jint numGlyphs, jfloat xpos, jfloat ypos) {
1287 
1288     FT_Outline* outline;
1289     jobject gp = NULL;
1290     jbyteArray types;
1291     jfloatArray coords;
1292     GPData gpdata;
1293     int i;
1294     jint *glyphs;
1295 
1296     FTScalerContext *context =
1297          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1298     FTScalerInfo *scalerInfo =
1299              (FTScalerInfo*) jlong_to_ptr(pScaler);
1300 
1301     glyphs = NULL;
1302     if (numGlyphs > 0 && 0xffffffffu / sizeof(jint) >= numGlyphs) {
1303         glyphs = (jint*) malloc(numGlyphs*sizeof(jint));
1304     }
1305     if (glyphs == NULL) {
1306         // We reach here if:
1307         // 1. numGlyphs <= 0,
1308         // 2. overflow check failed, or
1309         // 3. malloc failed.
1310         gp = (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty);
1311         return gp;
1312     }
1313 
1314     (*env)->GetIntArrayRegion(env, glyphArray, 0, numGlyphs, glyphs);
1315 
1316     gpdata.numCoords = 0;
1317     for (i=0; i<numGlyphs;i++) {
1318         if (glyphs[i] >= INVISIBLE_GLYPHS) {
1319             continue;
1320         }
1321         outline = getFTOutline(env,
1322                                font2D,
1323                                context,
1324                                scalerInfo,
1325                                glyphs[i],
1326                                xpos, ypos);
1327 
1328         if (outline == NULL || outline->n_points == 0) {
1329             continue;
1330         }
1331 
1332         gpdata.pointTypes  = NULL;
1333         gpdata.pointCoords = NULL;
1334         if (!allocateSpaceForGP(&gpdata, outline->n_points,
1335                                 outline->n_contours)) {
1336             break;
1337         }
1338 
1339         addToGP(&gpdata, outline);
1340     }
1341     free(glyphs);
1342 
1343     if (gpdata.numCoords != 0) {
1344       types = (*env)->NewByteArray(env, gpdata.numTypes);
1345       coords = (*env)->NewFloatArray(env, gpdata.numCoords);
1346 
1347       if (types && coords) {
1348         (*env)->SetByteArrayRegion(env, types, 0,
1349                                    gpdata.numTypes, gpdata.pointTypes);
1350         (*env)->SetFloatArrayRegion(env, coords, 0,
1351                                     gpdata.numCoords, gpdata.pointCoords);
1352 
1353         gp=(*env)->NewObject(env,
1354                              sunFontIDs.gpClass,
1355                              sunFontIDs.gpCtr,
1356                              gpdata.wr,
1357                              types,
1358                              gpdata.numTypes,
1359                              coords,
1360                              gpdata.numCoords);
1361         return gp;
1362       }
1363     }
1364     return (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty);
1365 }
1366 
1367 JNIEXPORT jlong JNICALL
1368 Java_sun_font_FreetypeFontScaler_getUnitsPerEMNative(
1369         JNIEnv *env, jobject scaler, jlong pScaler) {
1370 
1371     FTScalerInfo *s = (FTScalerInfo* ) jlong_to_ptr(pScaler);
1372 
1373     /* Freetype doc says:
1374      The number of font units per EM square for this face.
1375      This is typically 2048 for TrueType fonts, and 1000 for Type 1 fonts.
1376      Only relevant for scalable formats.
1377      However, layout engine might be not tested with anything but 2048.
1378 
1379      NB: test it! */
1380     if (s != NULL) {
1381         return s->face->units_per_EM;
1382     }
1383     return 2048;
1384 }
1385 
1386 /* This native method is called by the OpenType layout engine. */
1387 JNIEXPORT jobject JNICALL
1388 Java_sun_font_FreetypeFontScaler_getGlyphPointNative(
1389         JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
1390         jlong pScaler, jint glyphCode, jint pointNumber) {
1391 
1392     FT_Outline* outline;
1393     jobject point = NULL;
1394     jfloat x=0, y=0;
1395     FTScalerContext *context =
1396          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1397     FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
1398 
1399     outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0);
1400 
1401     if (outline != NULL && outline->n_points > pointNumber) {
1402         x =  F26Dot6ToFloat(outline->points[pointNumber].x);
1403         y = -F26Dot6ToFloat(outline->points[pointNumber].y);
1404     }
1405 
1406     return (*env)->NewObject(env, sunFontIDs.pt2DFloatClass,
1407                              sunFontIDs.pt2DFloatCtr, x, y);
1408 }