1 /*
   2  * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "jni.h"
  27 #include "jni_util.h"
  28 #include "jlong.h"
  29 #include "sunfontids.h"
  30 #include "sun_font_FreetypeFontScaler.h"
  31 
  32 #include<stdlib.h>
  33 #include <math.h>
  34 #include "ft2build.h"
  35 #include FT_FREETYPE_H
  36 #include FT_GLYPH_H
  37 #include FT_BBOX_H
  38 #include FT_SIZES_H
  39 #include FT_OUTLINE_H
  40 #include FT_SYNTHESIS_H
  41 
  42 #include "fontscaler.h"
  43 
  44 #define  ftFixed1  (FT_Fixed) (1 << 16)
  45 #define  FloatToFTFixed(f) (FT_Fixed)((f) * (float)(ftFixed1))
  46 #define  FTFixedToFloat(x) ((x) / (float)(ftFixed1))
  47 #define  FT26Dot6ToFloat(x)  ((x) / ((float) (1<<6)))
  48 #define  ROUND(x) ((int) (x+0.5))
  49 
  50 typedef struct {
  51     /* Important note:
  52          JNI forbids sharing same env between different threads.
  53          We are safe, because pointer is overwritten every time we get into
  54          JNI call (see setupFTContext).
  55 
  56          Pointer is used by font data reading callbacks
  57          such as ReadTTFontFileFunc.
  58 
  59          NB: We may consider switching to JNI_GetEnv. */
  60     JNIEnv* env;
  61     FT_Library library;
  62     FT_Face face;
  63     FT_Stream faceStream;
  64     jobject font2D;
  65     jobject directBuffer;
  66 
  67     unsigned char* fontData;
  68     unsigned fontDataOffset;
  69     unsigned fontDataLength;
  70     unsigned fileSize;
  71     TTLayoutTableCache* layoutTables;
  72 } FTScalerInfo;
  73 
  74 typedef struct FTScalerContext {
  75     FT_Matrix  transform;     /* glyph transform, including device transform */
  76     jboolean   useSbits;      /* sbit usage enabled? */
  77     jint       aaType;        /* antialiasing mode (off/on/grey/lcd) */
  78     jint       fmType;        /* fractional metrics - on/off */
  79     jboolean   doBold;        /* perform algorithmic bolding? */
  80     jboolean   doItalize;     /* perform algorithmic italicizing? */
  81     int        renderFlags;   /* configuration specific to particular engine */
  82     int        pathType;
  83     int        ptsz;          /* size in points */
  84 } FTScalerContext;
  85 
  86 #ifdef DEBUG
  87 /* These are referenced in the freetype sources if DEBUG macro is defined.
  88    To simplify work with debuging version of freetype we define
  89    them here. */
  90 int z_verbose;
  91 void z_error(char *s) {}
  92 #endif
  93 
  94 /**************** Error handling utilities *****************/
  95 
  96 static jmethodID invalidateScalerMID;
  97 
  98 JNIEXPORT void JNICALL
  99 Java_sun_font_FreetypeFontScaler_initIDs(
 100         JNIEnv *env, jobject scaler, jclass FFSClass) {
 101     invalidateScalerMID =
 102         (*env)->GetMethodID(env, FFSClass, "invalidateScaler", "()V");
 103 }
 104 
 105 static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) {
 106     void *stream;
 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)->CallObjectMethod(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     return ptr_to_jlong(context);
 369 }
 370 
 371 static int setupFTContext(JNIEnv *env,
 372                           jobject font2D,
 373                           FTScalerInfo *scalerInfo,
 374                           FTScalerContext *context) {
 375     int errCode = 0;
 376 
 377     scalerInfo->env = env;
 378     scalerInfo->font2D = font2D;
 379 
 380     if (context != NULL) {
 381         FT_Set_Transform(scalerInfo->face, &context->transform, NULL);
 382 
 383         errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72);
 384 
 385         if (errCode == 0) {
 386             errCode = FT_Activate_Size(scalerInfo->face->size);
 387         }
 388     }
 389 
 390     return errCode;
 391 }
 392 
 393 /* ftsynth.c uses (0x10000, 0x06000, 0x0, 0x10000) matrix to get oblique
 394    outline.  Therefore x coordinate will change by 0x06000*y.
 395    Note that y coordinate does not change. */
 396 #define OBLIQUE_MODIFIER(y)  (context->doItalize ? ((y)*6/16) : 0)
 397 
 398 /*
 399  * Class:     sun_font_FreetypeFontScaler
 400  * Method:    getFontMetricsNative
 401  * Signature: (Lsun/font/Font2D;J)Lsun/font/StrikeMetrics;
 402  */
 403 JNIEXPORT jobject JNICALL
 404 Java_sun_font_FreetypeFontScaler_getFontMetricsNative(
 405         JNIEnv *env, jobject scaler, jobject font2D,
 406         jlong pScalerContext, jlong pScaler) {
 407 
 408     jobject metrics;
 409     jfloat ax, ay, dx, dy, bx, by, lx, ly, mx, my;
 410     jfloat f0 = 0.0;
 411     FTScalerContext *context =
 412         (FTScalerContext*) jlong_to_ptr(pScalerContext);
 413     FTScalerInfo *scalerInfo =
 414              (FTScalerInfo*) jlong_to_ptr(pScaler);
 415 
 416     int errCode;
 417 
 418     if (isNullScalerContext(context) || scalerInfo == NULL) {
 419         return (*env)->NewObject(env,
 420                                  sunFontIDs.strikeMetricsClass,
 421                                  sunFontIDs.strikeMetricsCtr,
 422                                  f0, f0, f0, f0, f0, f0, f0, f0, f0, f0);
 423     }
 424 
 425     errCode = setupFTContext(env, font2D, scalerInfo, context);
 426 
 427     if (errCode) {
 428         metrics = (*env)->NewObject(env,
 429                                  sunFontIDs.strikeMetricsClass,
 430                                  sunFontIDs.strikeMetricsCtr,
 431                                  f0, f0, f0, f0, f0, f0, f0, f0, f0, f0);
 432         invalidateJavaScaler(env, scaler, scalerInfo);
 433         return metrics;
 434     }
 435 
 436     /* This is ugly and has to be reworked.
 437        Freetype provide means to add style to glyph but
 438        it seems there is no way to adjust metrics accordingly.
 439 
 440        So, we have to do adust them explicitly and stay consistent with what
 441        freetype does to outlines. */
 442 
 443 
 444     /**** Note: only some metrics are affected by styling ***/
 445 
 446     /* See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=657854 */
 447 #define FT_MulFixFloatShift6(a, b) (((float) (a)) * ((float) (b)) / 65536.0 / 64.0)
 448 
 449     /*
 450      * See FreeType source code: src/base/ftobjs.c ft_recompute_scaled_metrics()
 451      * http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1659
 452      */
 453     /* ascent */
 454     ax = 0;
 455     ay = -(jfloat) (FT_MulFixFloatShift6(
 456                        ((jlong) scalerInfo->face->ascender),
 457                        (jlong) scalerInfo->face->size->metrics.y_scale));
 458     /* descent */
 459     dx = 0;
 460     dy = -(jfloat) (FT_MulFixFloatShift6(
 461                        ((jlong) scalerInfo->face->descender),
 462                        (jlong) scalerInfo->face->size->metrics.y_scale));
 463     /* baseline */
 464     bx = by = 0;
 465 
 466     /* leading */
 467     lx = 0;
 468     ly = (jfloat) (FT_MulFixFloatShift6(
 469                       (jlong) scalerInfo->face->height,
 470                       (jlong) scalerInfo->face->size->metrics.y_scale))
 471                   + ay - dy;
 472     /* max advance */
 473     mx = (jfloat) FT26Dot6ToFloat(
 474                      scalerInfo->face->size->metrics.max_advance +
 475                      OBLIQUE_MODIFIER(scalerInfo->face->size->metrics.height));
 476     my = 0;
 477 
 478     metrics = (*env)->NewObject(env,
 479                                 sunFontIDs.strikeMetricsClass,
 480                                 sunFontIDs.strikeMetricsCtr,
 481                                 ax, ay, dx, dy, bx, by, lx, ly, mx, my);
 482 
 483     return metrics;
 484 }
 485 
 486 /*
 487  * Class:     sun_font_FreetypeFontScaler
 488  * Method:    getGlyphAdvanceNative
 489  * Signature: (Lsun/font/Font2D;JI)F
 490  */
 491 JNIEXPORT jfloat JNICALL
 492 Java_sun_font_FreetypeFontScaler_getGlyphAdvanceNative(
 493         JNIEnv *env, jobject scaler, jobject font2D,
 494         jlong pScalerContext, jlong pScaler, jint glyphCode) {
 495 
 496    /* This method is rarely used because requests for metrics are usually
 497       coupled with request for bitmap and to large extend work can be reused
 498       (to find out metrics we need to hint glyph).
 499       So, we typically go through getGlyphImage code path.
 500 
 501       For initial freetype implementation we delegate
 502       all work to getGlyphImage but drop result image.
 503       This is waste of work related to scan conversion and conversion from
 504       freetype format to our format but for now this seems to be ok.
 505 
 506       NB: investigate performance benefits of refactoring code
 507       to avoid unnecesary work with bitmaps. */
 508 
 509     GlyphInfo *info;
 510     jfloat advance;
 511     jlong image;
 512 
 513     image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
 514                  env, scaler, font2D, pScalerContext, pScaler, glyphCode);
 515     info = (GlyphInfo*) jlong_to_ptr(image);
 516 
 517     advance = info->advanceX;
 518 
 519     free(info);
 520 
 521     return advance;
 522 }
 523 
 524 /*
 525  * Class:     sun_font_FreetypeFontScaler
 526  * Method:    getGlyphMetricsNative
 527  * Signature: (Lsun/font/Font2D;JILjava/awt/geom/Point2D/Float;)V
 528  */
 529 JNIEXPORT void JNICALL
 530 Java_sun_font_FreetypeFontScaler_getGlyphMetricsNative(
 531         JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
 532         jlong pScaler, jint glyphCode, jobject metrics) {
 533 
 534      /* As initial implementation we delegate all work to getGlyphImage
 535         but drop result image. This is clearly waste of resorces.
 536 
 537         TODO: investigate performance benefits of refactoring code
 538               by avoiding bitmap generation and conversion from FT
 539               bitmap format. */
 540      GlyphInfo *info;
 541 
 542      jlong image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
 543                                  env, scaler, font2D,
 544                                  pScalerContext, pScaler, glyphCode);
 545      info = (GlyphInfo*) jlong_to_ptr(image);
 546 
 547      (*env)->SetFloatField(env, metrics, sunFontIDs.xFID, info->advanceX);
 548      (*env)->SetFloatField(env, metrics, sunFontIDs.yFID, info->advanceY);
 549 
 550      free(info);
 551 }
 552 
 553 
 554 static GlyphInfo* getNullGlyphImage() {
 555     GlyphInfo *glyphInfo =  (GlyphInfo*) calloc(1, sizeof(GlyphInfo));
 556     return glyphInfo;
 557 }
 558 
 559 static void CopyBW2Grey8(const void* srcImage, int srcRowBytes,
 560                          void* dstImage, int dstRowBytes,
 561                          int width, int height) {
 562     const UInt8* srcRow = (UInt8*)srcImage;
 563     UInt8* dstRow = (UInt8*)dstImage;
 564     int wholeByteCount = width >> 3;
 565     int remainingBitsCount = width & 7;
 566     int i, j;
 567 
 568     while (height--) {
 569         const UInt8* src8 = srcRow;
 570         UInt8* dstByte = dstRow;
 571         unsigned srcValue;
 572 
 573         srcRow += srcRowBytes;
 574         dstRow += dstRowBytes;
 575 
 576         for (i = 0; i < wholeByteCount; i++) {
 577             srcValue = *src8++;
 578             for (j = 0; j < 8; j++) {
 579                 *dstByte++ = (srcValue & 0x80) ? 0xFF : 0;
 580                 srcValue <<= 1;
 581             }
 582         }
 583         if (remainingBitsCount) {
 584             srcValue = *src8;
 585             for (j = 0; j < remainingBitsCount; j++) {
 586                 *dstByte++ = (srcValue & 0x80) ? 0xFF : 0;
 587                 srcValue <<= 1;
 588             }
 589         }
 590     }
 591 }
 592 
 593 #define Grey4ToAlpha255(value) (((value) << 4) + ((value) >> 3))
 594 
 595 static void CopyGrey4ToGrey8(const void* srcImage, int srcRowBytes,
 596                 void* dstImage, int dstRowBytes, int width, int height) {
 597      const UInt8* srcRow = (UInt8*) srcImage;
 598      UInt8* dstRow = (UInt8*) dstImage;
 599      int i;
 600 
 601      while (height--) {
 602          const UInt8* src8 = srcRow;
 603          UInt8* dstByte = dstRow;
 604          unsigned srcValue;
 605 
 606          srcRow += srcRowBytes;
 607          dstRow += dstRowBytes;
 608 
 609          for (i = 0; i < width; i++) {
 610              srcValue = *src8++;
 611              *dstByte++ = Grey4ToAlpha255(srcValue & 0x0f);
 612              *dstByte++ = Grey4ToAlpha255(srcValue >> 4);
 613          }
 614      }
 615 }
 616 
 617 /* We need it because FT rows are often padded to 4 byte boundaries
 618     and our internal format is not padded */
 619 static void CopyFTSubpixelToSubpixel(const void* srcImage, int srcRowBytes,
 620                                      void* dstImage, int dstRowBytes,
 621                                      int width, int height) {
 622     unsigned char *srcRow = (unsigned char *) srcImage;
 623     unsigned char *dstRow = (unsigned char *) dstImage;
 624 
 625     while (height--) {
 626         memcpy(dstRow, srcRow, width);
 627         srcRow += srcRowBytes;
 628         dstRow += dstRowBytes;
 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 CopyFTSubpixelVToSubpixel(const void* srcImage, int srcRowBytes,
 635                                       void* dstImage, int dstRowBytes,
 636                                       int width, int height) {
 637     unsigned char *srcRow = (unsigned char *) srcImage, *srcByte;
 638     unsigned char *dstRow = (unsigned char *) dstImage, *dstByte;
 639     int i;
 640 
 641     while (height > 0) {
 642         srcByte = srcRow;
 643         dstByte = dstRow;
 644         for (i = 0; i < width; i++) {
 645             *dstByte++ = *srcByte;
 646             *dstByte++ = *(srcByte + srcRowBytes);
 647             *dstByte++ = *(srcByte + 2*srcRowBytes);
 648             srcByte++;
 649         }
 650         srcRow += 3*srcRowBytes;
 651         dstRow += dstRowBytes;
 652         height -= 3;
 653     }
 654 }
 655 
 656 
 657 /*
 658  * Class:     sun_font_FreetypeFontScaler
 659  * Method:    getGlyphImageNative
 660  * Signature: (Lsun/font/Font2D;JI)J
 661  */
 662 JNIEXPORT jlong JNICALL
 663 Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
 664         JNIEnv *env, jobject scaler, jobject font2D,
 665         jlong pScalerContext, jlong pScaler, jint glyphCode) {
 666 
 667     int error, imageSize;
 668     UInt16 width, height;
 669     GlyphInfo *glyphInfo;
 670     int glyph_index;
 671     int renderFlags = FT_LOAD_RENDER, target;
 672     FT_GlyphSlot ftglyph;
 673 
 674     FTScalerContext* context =
 675         (FTScalerContext*) jlong_to_ptr(pScalerContext);
 676     FTScalerInfo *scalerInfo =
 677              (FTScalerInfo*) jlong_to_ptr(pScaler);
 678 
 679     if (isNullScalerContext(context) || scalerInfo == NULL) {
 680         return ptr_to_jlong(getNullGlyphImage());
 681     }
 682 
 683     error = setupFTContext(env, font2D, scalerInfo, context);
 684     if (error) {
 685         invalidateJavaScaler(env, scaler, scalerInfo);
 686         return ptr_to_jlong(getNullGlyphImage());
 687     }
 688 
 689     /* if algorithmic styling is required then we do not request bitmap */
 690     if (context->doBold || context->doItalize) {
 691         renderFlags =  FT_LOAD_DEFAULT;
 692     }
 693 
 694     /* NB: in case of non identity transform
 695      we might also prefer to disable transform before hinting,
 696      and apply it explicitly after hinting is performed.
 697      Or we can disable hinting. */
 698 
 699     /* select appropriate hinting mode */
 700     if (context->aaType == TEXT_AA_OFF) {
 701         target = FT_LOAD_TARGET_MONO;
 702     } else if (context->aaType == TEXT_AA_ON) {
 703         target = FT_LOAD_TARGET_NORMAL;
 704     } else if (context->aaType == TEXT_AA_LCD_HRGB ||
 705                context->aaType == TEXT_AA_LCD_HBGR) {
 706         target = FT_LOAD_TARGET_LCD;
 707     } else {
 708         target = FT_LOAD_TARGET_LCD_V;
 709     }
 710     renderFlags |= target;
 711 
 712     glyph_index = FT_Get_Char_Index(scalerInfo->face, glyphCode);
 713 
 714     error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags);
 715     if (error) {
 716         //do not destroy scaler yet.
 717         //this can be problem of particular context (e.g. with bad transform)
 718         return ptr_to_jlong(getNullGlyphImage());
 719     }
 720 
 721     ftglyph = scalerInfo->face->glyph;
 722 
 723     /* apply styles */
 724     if (context->doBold) { /* if bold style */
 725         FT_GlyphSlot_Embolden(ftglyph);
 726     }
 727     if (context->doItalize) { /* if oblique */
 728         FT_GlyphSlot_Oblique(ftglyph);
 729     }
 730 
 731     /* generate bitmap if it is not done yet
 732      e.g. if algorithmic styling is performed and style was added to outline */
 733     if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) {
 734         FT_Render_Glyph(ftglyph, FT_LOAD_TARGET_MODE(target));
 735     }
 736 
 737     width  = (UInt16) ftglyph->bitmap.width;
 738     height = (UInt16) ftglyph->bitmap.rows;
 739 
 740     imageSize = width*height;
 741     glyphInfo = (GlyphInfo*) malloc(sizeof(GlyphInfo) + imageSize);
 742     if (glyphInfo == NULL) {
 743         glyphInfo = getNullGlyphImage();
 744         return ptr_to_jlong(glyphInfo);
 745     }
 746     glyphInfo->cellInfo  = NULL;
 747     glyphInfo->managed   = UNMANAGED_GLYPH;
 748     glyphInfo->rowBytes  = width;
 749     glyphInfo->width     = width;
 750     glyphInfo->height    = height;
 751     glyphInfo->topLeftX  = (float)  ftglyph->bitmap_left;
 752     glyphInfo->topLeftY  = (float) -ftglyph->bitmap_top;
 753 
 754     if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD) {
 755         glyphInfo->width = width/3;
 756     } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD_V) {
 757         glyphInfo->height = glyphInfo->height/3;
 758     }
 759 
 760     if (context->fmType == TEXT_FM_ON) {
 761         double advh = FTFixedToFloat(ftglyph->linearHoriAdvance);
 762         glyphInfo->advanceX =
 763             (float) (advh * FTFixedToFloat(context->transform.xx));
 764         glyphInfo->advanceY =
 765             (float) (advh * FTFixedToFloat(context->transform.xy));
 766     } else {
 767         if (!ftglyph->advance.y) {
 768             glyphInfo->advanceX =
 769                 (float) ROUND(FT26Dot6ToFloat(ftglyph->advance.x));
 770             glyphInfo->advanceY = 0;
 771         } else if (!ftglyph->advance.x) {
 772             glyphInfo->advanceX = 0;
 773             glyphInfo->advanceY =
 774                 (float) ROUND(FT26Dot6ToFloat(-ftglyph->advance.y));
 775         } else {
 776             glyphInfo->advanceX = FT26Dot6ToFloat(ftglyph->advance.x);
 777             glyphInfo->advanceY = FT26Dot6ToFloat(-ftglyph->advance.y);
 778         }
 779     }
 780 
 781     if (imageSize == 0) {
 782         glyphInfo->image = NULL;
 783     } else {
 784         glyphInfo->image = (unsigned char*) glyphInfo + sizeof(GlyphInfo);
 785         //convert result to output format
 786         //output format is either 3 bytes per pixel (for subpixel modes)
 787         // or 1 byte per pixel for AA and B&W
 788         if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_MONO) {
 789             /* convert from 8 pixels per byte to 1 byte per pixel */
 790             CopyBW2Grey8(ftglyph->bitmap.buffer,
 791                          ftglyph->bitmap.pitch,
 792                          (void *) glyphInfo->image,
 793                          width,
 794                          width,
 795                          height);
 796         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_GRAY) {
 797             /* byte per pixel to byte per pixel => just copy */
 798             memcpy(glyphInfo->image, ftglyph->bitmap.buffer, imageSize);
 799         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_GRAY4) {
 800             /* 4 bits per pixel to byte per pixel */
 801             CopyGrey4ToGrey8(ftglyph->bitmap.buffer,
 802                              ftglyph->bitmap.pitch,
 803                              (void *) glyphInfo->image,
 804                              width,
 805                              width,
 806                              height);
 807         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD) {
 808             /* 3 bytes per pixel to 3 bytes per pixel */
 809             CopyFTSubpixelToSubpixel(ftglyph->bitmap.buffer,
 810                                      ftglyph->bitmap.pitch,
 811                                      (void *) glyphInfo->image,
 812                                      width,
 813                                      width,
 814                                      height);
 815         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD_V) {
 816             /* 3 bytes per pixel to 3 bytes per pixel */
 817             CopyFTSubpixelVToSubpixel(ftglyph->bitmap.buffer,
 818                                       ftglyph->bitmap.pitch,
 819                                       (void *) glyphInfo->image,
 820                                       width*3,
 821                                       width,
 822                                       height);
 823             glyphInfo->rowBytes *=3;
 824         } else {
 825             free(glyphInfo);
 826             glyphInfo = getNullGlyphImage();
 827         }
 828     }
 829 
 830     return ptr_to_jlong(glyphInfo);
 831 }
 832 
 833 
 834 /*
 835  * Class:     sun_font_FreetypeFontScaler
 836  * Method:    getLayoutTableCacheNative
 837  * Signature: (J)J
 838  */
 839 JNIEXPORT jlong JNICALL
 840 Java_sun_font_FreetypeFontScaler_getLayoutTableCacheNative(
 841         JNIEnv *env, jobject scaler, jlong pScaler) {
 842     FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
 843 
 844     if (scalerInfo == NULL) {
 845         invalidateJavaScaler(env, scaler, scalerInfo);
 846         return 0L;
 847     }
 848 
 849     // init layout table cache in font
 850     // we're assuming the font is a file font and moreover it is Truetype font
 851     // otherwise we shouldn't be able to get here...
 852     if (scalerInfo->layoutTables == NULL) {
 853         scalerInfo->layoutTables = newLayoutTableCache();
 854     }
 855 
 856     return ptr_to_jlong(scalerInfo->layoutTables);
 857 }
 858 
 859 /*
 860  * Class:     sun_font_FreetypeFontScaler
 861  * Method:    disposeNativeScaler
 862  * Signature: (J)V
 863  */
 864 JNIEXPORT void JNICALL
 865 Java_sun_font_FreetypeFontScaler_disposeNativeScaler(
 866         JNIEnv *env, jobject scaler, jobject font2D, jlong pScaler) {
 867     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 868 
 869     /* Freetype functions *may* cause callback to java
 870        that can use cached values. Make sure our cache is up to date.
 871        NB: scaler context is not important at this point, can use NULL. */
 872     int errCode = setupFTContext(env, font2D, scalerInfo, NULL);
 873     if (errCode) {
 874         return;
 875     }
 876 
 877     freeNativeResources(env, scalerInfo);
 878 }
 879 
 880 /*
 881  * Class:     sun_font_FreetypeFontScaler
 882  * Method:    getNumGlyphsNative
 883  * Signature: ()I
 884  */
 885 JNIEXPORT jint JNICALL
 886 Java_sun_font_FreetypeFontScaler_getNumGlyphsNative(
 887         JNIEnv *env, jobject scaler, jlong pScaler) {
 888     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 889 
 890     if (scalerInfo == NULL || scalerInfo->face == NULL) { /* bad/null scaler */
 891         /* null scaler can render 1 glyph - "missing glyph" with code 0
 892            (all glyph codes requested by user are mapped to code 0 at
 893            validation step) */
 894         invalidateJavaScaler(env, scaler, scalerInfo);
 895         return (jint) 1;
 896     }
 897 
 898     return (jint) scalerInfo->face->num_glyphs;
 899 }
 900 
 901 /*
 902  * Class:     sun_font_FreetypeFontScaler
 903  * Method:    getMissingGlyphCodeNative
 904  * Signature: ()I
 905  */
 906 JNIEXPORT jint JNICALL
 907 Java_sun_font_FreetypeFontScaler_getMissingGlyphCodeNative(
 908         JNIEnv *env, jobject scaler, jlong pScaler) {
 909 
 910     /* Is it always 0 for freetype? */
 911     return 0;
 912 }
 913 
 914 /*
 915  * Class:     sun_font_FreetypeFontScaler
 916  * Method:    getGlyphCodeNative
 917  * Signature: (C)I
 918  */
 919 JNIEXPORT jint JNICALL
 920 Java_sun_font_FreetypeFontScaler_getGlyphCodeNative(
 921         JNIEnv *env, jobject scaler,
 922         jobject font2D, jlong pScaler, jchar charCode) {
 923 
 924     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 925     int errCode;
 926 
 927     if (scaler == NULL || scalerInfo->face == NULL) { /* bad/null scaler */
 928         invalidateJavaScaler(env, scaler, scalerInfo);
 929         return 0;
 930     }
 931 
 932     /* Freetype functions *may* cause callback to java
 933        that can use cached values. Make sure our cache is up to date.
 934        Scaler context is not important here, can use NULL. */
 935     errCode = setupFTContext(env, font2D, scalerInfo, NULL);
 936     if (errCode) {
 937         return 0;
 938     }
 939 
 940     return FT_Get_Char_Index(scalerInfo->face, charCode);
 941 }
 942 
 943 
 944 #define FloatToF26Dot6(x) ((unsigned int) ((x)*64))
 945 
 946 static FT_Outline* getFTOutline(JNIEnv* env, jobject font2D,
 947         FTScalerContext *context, FTScalerInfo* scalerInfo,
 948         jint glyphCode, jfloat xpos, jfloat ypos) {
 949     int renderFlags;
 950     int glyph_index;
 951     FT_Error error;
 952     FT_GlyphSlot ftglyph;
 953 
 954     if (glyphCode >= INVISIBLE_GLYPHS ||
 955             isNullScalerContext(context) || scalerInfo == NULL) {
 956         return NULL;
 957     }
 958 
 959     error = setupFTContext(env, font2D, scalerInfo, context);
 960     if (error) {
 961         return NULL;
 962     }
 963 
 964     renderFlags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
 965 
 966     glyph_index = FT_Get_Char_Index(scalerInfo->face, glyphCode);
 967 
 968     error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags);
 969     if (error) {
 970         return NULL;
 971     }
 972 
 973     ftglyph = scalerInfo->face->glyph;
 974 
 975     /* apply styles */
 976     if (context->doBold) { /* if bold style */
 977         FT_GlyphSlot_Embolden(ftglyph);
 978     }
 979     if (context->doItalize) { /* if oblique */
 980         FT_GlyphSlot_Oblique(ftglyph);
 981     }
 982 
 983     FT_Outline_Translate(&ftglyph->outline,
 984                          FloatToF26Dot6(xpos),
 985                          -FloatToF26Dot6(ypos));
 986 
 987     return &ftglyph->outline;
 988 }
 989 
 990 #define F26Dot6ToFloat(n) (((float)(n))/((float) 64))
 991 
 992 /* Types of GeneralPath segments.
 993    TODO: pull constants from other place? */
 994 
 995 #define SEG_UNKNOWN -1
 996 #define SEG_MOVETO   0
 997 #define SEG_LINETO   1
 998 #define SEG_QUADTO   2
 999 #define SEG_CUBICTO  3
1000 #define SEG_CLOSE    4
1001 
1002 #define WIND_NON_ZERO 0
1003 #define WIND_EVEN_ODD 1
1004 
1005 /* Placeholder to accumulate GeneralPath data */
1006 typedef struct {
1007     jint numTypes;
1008     jint numCoords;
1009     jint lenTypes;
1010     jint lenCoords;
1011     jint wr;
1012     jbyte* pointTypes;
1013     jfloat* pointCoords;
1014 } GPData;
1015 
1016 /* returns 0 on failure */
1017 static int allocateSpaceForGP(GPData* gpdata, int npoints, int ncontours) {
1018     int maxTypes, maxCoords;
1019 
1020     /* we may have up to N intermediate points per contour
1021        (and for each point can actually cause new curve to be generated)
1022        In addition we can also have 2 extra point per outline.
1023      */
1024     maxTypes  = 2*npoints  + 2*ncontours;
1025     maxCoords = 4*(npoints + 2*ncontours); //we may need to insert
1026                                            //up to n-1 intermediate points
1027 
1028     /* first usage - allocate space and intialize all fields */
1029     if (gpdata->pointTypes == NULL || gpdata->pointCoords == NULL) {
1030         gpdata->lenTypes  = maxTypes;
1031         gpdata->lenCoords = maxCoords;
1032         gpdata->pointTypes  = (jbyte*)
1033              malloc(gpdata->lenTypes*sizeof(jbyte));
1034         gpdata->pointCoords = (jfloat*)
1035              malloc(gpdata->lenCoords*sizeof(jfloat));
1036         gpdata->numTypes = 0;
1037         gpdata->numCoords = 0;
1038         gpdata->wr = WIND_NON_ZERO; /* By default, outlines are filled
1039                                        using the non-zero winding rule. */
1040     } else {
1041         /* do we have enough space? */
1042         if (gpdata->lenTypes - gpdata->numTypes < maxTypes) {
1043             gpdata->lenTypes  += maxTypes;
1044             gpdata->pointTypes  = (jbyte*)
1045               realloc(gpdata->pointTypes, gpdata->lenTypes*sizeof(jbyte));
1046         }
1047 
1048         if (gpdata->lenCoords - gpdata->numCoords < maxCoords) {
1049             gpdata->lenCoords += maxCoords;
1050             gpdata->pointCoords = (jfloat*)
1051               realloc(gpdata->pointCoords, gpdata->lenCoords*sizeof(jfloat));
1052         }
1053     }
1054 
1055     /* failure if any of mallocs failed */
1056     if (gpdata->pointTypes == NULL ||  gpdata->pointCoords == NULL)
1057         return 0;
1058     else
1059         return 1;
1060 }
1061 
1062 static void addSeg(GPData *gp, jbyte type) {
1063     gp->pointTypes[gp->numTypes++] = type;
1064 }
1065 
1066 static void addCoords(GPData *gp, FT_Vector *p) {
1067     gp->pointCoords[gp->numCoords++] =  F26Dot6ToFloat(p->x);
1068     gp->pointCoords[gp->numCoords++] = -F26Dot6ToFloat(p->y);
1069 }
1070 
1071 static int moveTo(FT_Vector *to, GPData *gp) {
1072     if (gp->numCoords)
1073         addSeg(gp, SEG_CLOSE);
1074     addCoords(gp, to);
1075     addSeg(gp, SEG_MOVETO);
1076     return FT_Err_Ok;
1077 }
1078 
1079 static int lineTo(FT_Vector *to, GPData *gp) {
1080     addCoords(gp, to);
1081     addSeg(gp, SEG_LINETO);
1082     return FT_Err_Ok;
1083 }
1084 
1085 static int conicTo(FT_Vector *control, FT_Vector *to, GPData *gp) {
1086     addCoords(gp, control);
1087     addCoords(gp, to);
1088     addSeg(gp, SEG_QUADTO);
1089     return FT_Err_Ok;
1090 }
1091 
1092 static int cubicTo(FT_Vector *control1,
1093                    FT_Vector *control2,
1094                    FT_Vector *to,
1095                    GPData    *gp) {
1096     addCoords(gp, control1);
1097     addCoords(gp, control2);
1098     addCoords(gp, to);
1099     addSeg(gp, SEG_CUBICTO);
1100     return FT_Err_Ok;
1101 }
1102 
1103 static void addToGP(GPData* gpdata, FT_Outline*outline) {
1104     static const FT_Outline_Funcs outline_funcs = {
1105         (FT_Outline_MoveToFunc) moveTo,
1106         (FT_Outline_LineToFunc) lineTo,
1107         (FT_Outline_ConicToFunc) conicTo,
1108         (FT_Outline_CubicToFunc) cubicTo,
1109         0, /* shift */
1110         0, /* delta */
1111     };
1112 
1113     FT_Outline_Decompose(outline, &outline_funcs, gpdata);
1114     if (gpdata->numCoords)
1115         addSeg(gpdata, SEG_CLOSE);
1116 
1117     /* If set to 1, the outline will be filled using the even-odd fill rule */
1118     if (outline->flags & FT_OUTLINE_EVEN_ODD_FILL) {
1119         gpdata->wr = WIND_EVEN_ODD;
1120     }
1121 }
1122 
1123 static void freeGP(GPData* gpdata) {
1124     if (gpdata->pointCoords != NULL) {
1125         free(gpdata->pointCoords);
1126         gpdata->pointCoords = NULL;
1127         gpdata->numCoords = 0;
1128         gpdata->lenCoords = 0;
1129     }
1130     if (gpdata->pointTypes != NULL) {
1131         free(gpdata->pointTypes);
1132         gpdata->pointTypes = NULL;
1133         gpdata->numTypes = 0;
1134         gpdata->lenTypes = 0;
1135     }
1136 }
1137 
1138 static jobject getGlyphGeneralPath(JNIEnv* env, jobject font2D,
1139         FTScalerContext *context, FTScalerInfo *scalerInfo,
1140         jint glyphCode, jfloat xpos, jfloat ypos) {
1141 
1142     FT_Outline* outline;
1143     jobject gp = NULL;
1144     jbyteArray types;
1145     jfloatArray coords;
1146     GPData gpdata;
1147 
1148     outline = getFTOutline(env, font2D, context, scalerInfo,
1149                            glyphCode, xpos, ypos);
1150 
1151     if (outline == NULL || outline->n_points == 0) {
1152         return gp;
1153     }
1154 
1155     gpdata.pointTypes  = NULL;
1156     gpdata.pointCoords = NULL;
1157     if (!allocateSpaceForGP(&gpdata, outline->n_points, outline->n_contours)) {
1158         return gp;
1159     }
1160 
1161     addToGP(&gpdata, outline);
1162 
1163     types  = (*env)->NewByteArray(env, gpdata.numTypes);
1164     coords = (*env)->NewFloatArray(env, gpdata.numCoords);
1165 
1166     if (types && coords) {
1167         (*env)->SetByteArrayRegion(env, types, 0,
1168                                    gpdata.numTypes,
1169                                    gpdata.pointTypes);
1170         (*env)->SetFloatArrayRegion(env, coords, 0,
1171                                     gpdata.numCoords,
1172                                     gpdata.pointCoords);
1173         gp = (*env)->NewObject(env,
1174                                sunFontIDs.gpClass,
1175                                sunFontIDs.gpCtr,
1176                                gpdata.wr,
1177                                types,
1178                                gpdata.numTypes,
1179                                coords,
1180                                gpdata.numCoords);
1181     }
1182 
1183     freeGP(&gpdata);
1184 
1185     return gp;
1186 }
1187 
1188 /*
1189  * Class:     sun_font_FreetypeFontScaler
1190  * Method:    getGlyphOutlineNative
1191  * Signature: (Lsun/font/Font2D;JIFF)Ljava/awt/geom/GeneralPath;
1192  */
1193 JNIEXPORT jobject JNICALL
1194 Java_sun_font_FreetypeFontScaler_getGlyphOutlineNative(
1195       JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
1196       jlong pScaler, jint glyphCode, jfloat xpos, jfloat ypos) {
1197 
1198     FTScalerContext *context =
1199          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1200     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1201 
1202     jobject gp = getGlyphGeneralPath(env,
1203                                font2D,
1204                                context,
1205                                scalerInfo,
1206                                glyphCode,
1207                                xpos,
1208                                ypos);
1209     if (gp == NULL) { /* can be legal */
1210         gp = (*env)->NewObject(env,
1211                                sunFontIDs.gpClass,
1212                                sunFontIDs.gpCtrEmpty);
1213     }
1214     return gp;
1215 }
1216 
1217 /*
1218  * Class:     sun_font_FreetypeFontScaler
1219  * Method:    getGlyphOutlineBoundsNative
1220  * Signature: (Lsun/font/Font2D;JI)Ljava/awt/geom/Rectangle2D/Float;
1221  */
1222 JNIEXPORT jobject JNICALL
1223 Java_sun_font_FreetypeFontScaler_getGlyphOutlineBoundsNative(
1224         JNIEnv *env, jobject scaler, jobject font2D,
1225         jlong pScalerContext, jlong pScaler, jint glyphCode) {
1226 
1227     FT_Outline *outline;
1228     FT_BBox bbox;
1229     int error;
1230     jobject bounds;
1231 
1232     FTScalerContext *context =
1233          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1234     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1235 
1236     outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0);
1237     if (outline == NULL || outline->n_points == 0) {
1238         /* it is legal case, e.g. invisible glyph */
1239         bounds = (*env)->NewObject(env,
1240                                  sunFontIDs.rect2DFloatClass,
1241                                  sunFontIDs.rect2DFloatCtr);
1242         return bounds;
1243     }
1244 
1245     error = FT_Outline_Get_BBox(outline, &bbox);
1246 
1247     //convert bbox
1248     if (error || bbox.xMin >= bbox.xMax || bbox.yMin >= bbox.yMax) {
1249         bounds = (*env)->NewObject(env,
1250                                    sunFontIDs.rect2DFloatClass,
1251                                    sunFontIDs.rect2DFloatCtr);
1252     } else {
1253         bounds = (*env)->NewObject(env,
1254                                    sunFontIDs.rect2DFloatClass,
1255                                    sunFontIDs.rect2DFloatCtr4,
1256                                    F26Dot6ToFloat(bbox.xMin),
1257                                    F26Dot6ToFloat(-bbox.yMax),
1258                                    F26Dot6ToFloat(bbox.xMax-bbox.xMin),
1259                                    F26Dot6ToFloat(bbox.yMax-bbox.yMin));
1260     }
1261 
1262     return bounds;
1263 }
1264 
1265 /*
1266  * Class:     sun_font_FreetypeFontScaler
1267  * Method:    getGlyphVectorOutlineNative
1268  * Signature: (Lsun/font/Font2D;J[IIFF)Ljava/awt/geom/GeneralPath;
1269  */
1270 JNIEXPORT jobject
1271 JNICALL
1272 Java_sun_font_FreetypeFontScaler_getGlyphVectorOutlineNative(
1273         JNIEnv *env, jobject scaler, jobject font2D,
1274         jlong pScalerContext, jlong pScaler,
1275         jintArray glyphArray, jint numGlyphs, jfloat xpos, jfloat ypos) {
1276 
1277     FT_Outline* outline;
1278     jobject gp = NULL;
1279     jbyteArray types;
1280     jfloatArray coords;
1281     GPData gpdata;
1282     int i;
1283     jint *glyphs;
1284 
1285     FTScalerContext *context =
1286          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1287     FTScalerInfo *scalerInfo =
1288              (FTScalerInfo*) jlong_to_ptr(pScaler);
1289 
1290     glyphs = NULL;
1291     if (numGlyphs > 0 && 0xffffffffu / sizeof(jint) >= numGlyphs) {
1292         glyphs = (jint*) malloc(numGlyphs*sizeof(jint));
1293     }
1294     if (glyphs == NULL) {
1295         // We reach here if:
1296         // 1. numGlyphs <= 0,
1297         // 2. overflow check failed, or
1298         // 3. malloc failed.
1299         gp = (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty);
1300         return gp;
1301     }
1302 
1303     (*env)->GetIntArrayRegion(env, glyphArray, 0, numGlyphs, glyphs);
1304 
1305     gpdata.numCoords = 0;
1306     for (i=0; i<numGlyphs;i++) {
1307         if (glyphs[i] >= INVISIBLE_GLYPHS) {
1308             continue;
1309         }
1310         outline = getFTOutline(env,
1311                                font2D,
1312                                context,
1313                                scalerInfo,
1314                                glyphs[i],
1315                                xpos, ypos);
1316 
1317         if (outline == NULL || outline->n_points == 0) {
1318             continue;
1319         }
1320 
1321         gpdata.pointTypes  = NULL;
1322         gpdata.pointCoords = NULL;
1323         if (!allocateSpaceForGP(&gpdata, outline->n_points,
1324                                 outline->n_contours)) {
1325             break;
1326         }
1327 
1328         addToGP(&gpdata, outline);
1329     }
1330     free(glyphs);
1331 
1332     if (gpdata.numCoords != 0) {
1333       types = (*env)->NewByteArray(env, gpdata.numTypes);
1334       coords = (*env)->NewFloatArray(env, gpdata.numCoords);
1335 
1336       if (types && coords) {
1337         (*env)->SetByteArrayRegion(env, types, 0,
1338                                    gpdata.numTypes, gpdata.pointTypes);
1339         (*env)->SetFloatArrayRegion(env, coords, 0,
1340                                     gpdata.numCoords, gpdata.pointCoords);
1341 
1342         gp=(*env)->NewObject(env,
1343                              sunFontIDs.gpClass,
1344                              sunFontIDs.gpCtr,
1345                              gpdata.wr,
1346                              types,
1347                              gpdata.numTypes,
1348                              coords,
1349                              gpdata.numCoords);
1350         return gp;
1351       }
1352     }
1353     return (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty);
1354 }
1355 
1356 JNIEXPORT jlong JNICALL
1357 Java_sun_font_FreetypeFontScaler_getUnitsPerEMNative(
1358         JNIEnv *env, jobject scaler, jlong pScaler) {
1359 
1360     FTScalerInfo *s = (FTScalerInfo* ) jlong_to_ptr(pScaler);
1361 
1362     /* Freetype doc says:
1363      The number of font units per EM square for this face.
1364      This is typically 2048 for TrueType fonts, and 1000 for Type 1 fonts.
1365      Only relevant for scalable formats.
1366      However, layout engine might be not tested with anything but 2048.
1367 
1368      NB: test it! */
1369     if (s != NULL) {
1370         return s->face->units_per_EM;
1371     }
1372     return 2048;
1373 }
1374 
1375 /* This native method is called by the OpenType layout engine. */
1376 JNIEXPORT jobject JNICALL
1377 Java_sun_font_FreetypeFontScaler_getGlyphPointNative(
1378         JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
1379         jlong pScaler, jint glyphCode, jint pointNumber) {
1380 
1381     FT_Outline* outline;
1382     jobject point = NULL;
1383     jfloat x=0, y=0;
1384     FTScalerContext *context =
1385          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1386     FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
1387 
1388     outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0);
1389 
1390     if (outline != NULL && outline->n_points > pointNumber) {
1391         x =  F26Dot6ToFloat(outline->points[pointNumber].x);
1392         y = -F26Dot6ToFloat(outline->points[pointNumber].y);
1393     }
1394 
1395     return (*env)->NewObject(env, sunFontIDs.pt2DFloatClass,
1396                              sunFontIDs.pt2DFloatCtr, x, y);
1397 }
--- EOF ---