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     }
 706 
 707     /* NB: in case of non identity transform
 708      we might also prefer to disable transform before hinting,
 709      and apply it explicitly after hinting is performed.
 710      Or we can disable hinting. */
 711 
 712     /* select appropriate hinting mode */
 713     if (context->aaType == TEXT_AA_OFF) {
 714         target = FT_LOAD_TARGET_MONO;
 715     } else if (context->aaType == TEXT_AA_ON) {
 716         target = FT_LOAD_TARGET_NORMAL;
 717     } else if (context->aaType == TEXT_AA_LCD_HRGB ||
 718                context->aaType == TEXT_AA_LCD_HBGR) {
 719         target = FT_LOAD_TARGET_LCD;
 720     } else {
 721         target = FT_LOAD_TARGET_LCD_V;
 722     }
 723     renderFlags |= target;
 724 
 725     error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags);
 726     if (error) {
 727         //do not destroy scaler yet.
 728         //this can be problem of particular context (e.g. with bad transform)
 729         return ptr_to_jlong(getNullGlyphImage());
 730     }
 731 
 732     ftglyph = scalerInfo->face->glyph;
 733 
 734     /* apply styles */
 735     if (context->doBold) { /* if bold style */
 736         FT_GlyphSlot_Embolden(ftglyph);
 737     }
 738     if (context->doItalize) { /* if oblique */
 739         FT_GlyphSlot_Oblique(ftglyph);
 740     }
 741 
 742     /* generate bitmap if it is not done yet
 743      e.g. if algorithmic styling is performed and style was added to outline */
 744     if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) {
 745         FT_Render_Glyph(ftglyph, FT_LOAD_TARGET_MODE(target));
 746     }
 747 
 748     width  = (UInt16) ftglyph->bitmap.width;
 749     height = (UInt16) ftglyph->bitmap.rows;
 750 
 751     imageSize = width*height;
 752     glyphInfo = (GlyphInfo*) malloc(sizeof(GlyphInfo) + imageSize);
 753     if (glyphInfo == NULL) {
 754         glyphInfo = getNullGlyphImage();
 755         return ptr_to_jlong(glyphInfo);
 756     }
 757     glyphInfo->cellInfo  = NULL;
 758     glyphInfo->managed   = UNMANAGED_GLYPH;
 759     glyphInfo->rowBytes  = width;
 760     glyphInfo->width     = width;
 761     glyphInfo->height    = height;
 762     glyphInfo->topLeftX  = (float)  ftglyph->bitmap_left;
 763     glyphInfo->topLeftY  = (float) -ftglyph->bitmap_top;
 764 
 765     if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD) {
 766         glyphInfo->width = width/3;
 767     } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD_V) {
 768         glyphInfo->height = glyphInfo->height/3;
 769     }
 770 
 771     if (context->fmType == TEXT_FM_ON) {
 772         double advh = FTFixedToFloat(ftglyph->linearHoriAdvance);
 773         glyphInfo->advanceX =
 774             (float) (advh * FTFixedToFloat(context->transform.xx));
 775         glyphInfo->advanceY =
 776             (float) (advh * FTFixedToFloat(context->transform.xy));
 777     } else {
 778         if (!ftglyph->advance.y) {
 779             glyphInfo->advanceX =
 780                 (float) FT26Dot6ToInt(ftglyph->advance.x);
 781             glyphInfo->advanceY = 0;
 782         } else if (!ftglyph->advance.x) {
 783             glyphInfo->advanceX = 0;
 784             glyphInfo->advanceY =
 785                 (float) FT26Dot6ToInt(-ftglyph->advance.y);
 786         } else {
 787             glyphInfo->advanceX = FT26Dot6ToFloat(ftglyph->advance.x);
 788             glyphInfo->advanceY = FT26Dot6ToFloat(-ftglyph->advance.y);
 789         }
 790     }
 791 
 792     if (imageSize == 0) {
 793         glyphInfo->image = NULL;
 794     } else {
 795         glyphInfo->image = (unsigned char*) glyphInfo + sizeof(GlyphInfo);
 796         //convert result to output format
 797         //output format is either 3 bytes per pixel (for subpixel modes)
 798         // or 1 byte per pixel for AA and B&W
 799         if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_MONO) {
 800             /* convert from 8 pixels per byte to 1 byte per pixel */
 801             CopyBW2Grey8(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_GRAY) {
 808             /* byte per pixel to byte per pixel => just copy */
 809             memcpy(glyphInfo->image, ftglyph->bitmap.buffer, imageSize);
 810         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_GRAY4) {
 811             /* 4 bits per pixel to byte per pixel */
 812             CopyGrey4ToGrey8(ftglyph->bitmap.buffer,
 813                              ftglyph->bitmap.pitch,
 814                              (void *) glyphInfo->image,
 815                              width,
 816                              width,
 817                              height);
 818         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD) {
 819             /* 3 bytes per pixel to 3 bytes per pixel */
 820             CopyFTSubpixelToSubpixel(ftglyph->bitmap.buffer,
 821                                      ftglyph->bitmap.pitch,
 822                                      (void *) glyphInfo->image,
 823                                      width,
 824                                      width,
 825                                      height);
 826         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD_V) {
 827             /* 3 bytes per pixel to 3 bytes per pixel */
 828             CopyFTSubpixelVToSubpixel(ftglyph->bitmap.buffer,
 829                                       ftglyph->bitmap.pitch,
 830                                       (void *) glyphInfo->image,
 831                                       width*3,
 832                                       width,
 833                                       height);
 834             glyphInfo->rowBytes *=3;
 835         } else {
 836             free(glyphInfo);
 837             glyphInfo = getNullGlyphImage();
 838         }
 839     }
 840 
 841     return ptr_to_jlong(glyphInfo);
 842 }
 843 
 844 
 845 /*
 846  * Class:     sun_font_FreetypeFontScaler
 847  * Method:    getLayoutTableCacheNative
 848  * Signature: (J)J
 849  */
 850 JNIEXPORT jlong JNICALL
 851 Java_sun_font_FreetypeFontScaler_getLayoutTableCacheNative(
 852         JNIEnv *env, jobject scaler, jlong pScaler) {
 853     FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
 854 
 855     if (scalerInfo == NULL) {
 856         invalidateJavaScaler(env, scaler, scalerInfo);
 857         return 0L;
 858     }
 859 
 860     // init layout table cache in font
 861     // we're assuming the font is a file font and moreover it is Truetype font
 862     // otherwise we shouldn't be able to get here...
 863     if (scalerInfo->layoutTables == NULL) {
 864         scalerInfo->layoutTables = newLayoutTableCache();
 865     }
 866 
 867     return ptr_to_jlong(scalerInfo->layoutTables);
 868 }
 869 
 870 /*
 871  * Class:     sun_font_FreetypeFontScaler
 872  * Method:    disposeNativeScaler
 873  * Signature: (J)V
 874  */
 875 JNIEXPORT void JNICALL
 876 Java_sun_font_FreetypeFontScaler_disposeNativeScaler(
 877         JNIEnv *env, jobject scaler, jobject font2D, jlong pScaler) {
 878     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 879 
 880     /* Freetype functions *may* cause callback to java
 881        that can use cached values. Make sure our cache is up to date.
 882        NB: scaler context is not important at this point, can use NULL. */
 883     int errCode = setupFTContext(env, font2D, scalerInfo, NULL);
 884     if (errCode) {
 885         return;
 886     }
 887 
 888     freeNativeResources(env, scalerInfo);
 889 }
 890 
 891 /*
 892  * Class:     sun_font_FreetypeFontScaler
 893  * Method:    getNumGlyphsNative
 894  * Signature: ()I
 895  */
 896 JNIEXPORT jint JNICALL
 897 Java_sun_font_FreetypeFontScaler_getNumGlyphsNative(
 898         JNIEnv *env, jobject scaler, jlong pScaler) {
 899     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 900 
 901     if (scalerInfo == NULL || scalerInfo->face == NULL) { /* bad/null scaler */
 902         /* null scaler can render 1 glyph - "missing glyph" with code 0
 903            (all glyph codes requested by user are mapped to code 0 at
 904            validation step) */
 905         invalidateJavaScaler(env, scaler, scalerInfo);
 906         return (jint) 1;
 907     }
 908 
 909     return (jint) scalerInfo->face->num_glyphs;
 910 }
 911 
 912 /*
 913  * Class:     sun_font_FreetypeFontScaler
 914  * Method:    getMissingGlyphCodeNative
 915  * Signature: ()I
 916  */
 917 JNIEXPORT jint JNICALL
 918 Java_sun_font_FreetypeFontScaler_getMissingGlyphCodeNative(
 919         JNIEnv *env, jobject scaler, jlong pScaler) {
 920 
 921     /* Is it always 0 for freetype? */
 922     return 0;
 923 }
 924 
 925 /*
 926  * Class:     sun_font_FreetypeFontScaler
 927  * Method:    getGlyphCodeNative
 928  * Signature: (C)I
 929  */
 930 JNIEXPORT jint JNICALL
 931 Java_sun_font_FreetypeFontScaler_getGlyphCodeNative(
 932         JNIEnv *env, jobject scaler,
 933         jobject font2D, jlong pScaler, jchar charCode) {
 934 
 935     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 936     int errCode;
 937 
 938     if (scaler == NULL || scalerInfo->face == NULL) { /* bad/null scaler */
 939         invalidateJavaScaler(env, scaler, scalerInfo);
 940         return 0;
 941     }
 942 
 943     /* Freetype functions *may* cause callback to java
 944        that can use cached values. Make sure our cache is up to date.
 945        Scaler context is not important here, can use NULL. */
 946     errCode = setupFTContext(env, font2D, scalerInfo, NULL);
 947     if (errCode) {
 948         return 0;
 949     }
 950 
 951     return FT_Get_Char_Index(scalerInfo->face, charCode);
 952 }
 953 
 954 
 955 #define FloatToF26Dot6(x) ((unsigned int) ((x)*64))
 956 
 957 static FT_Outline* getFTOutline(JNIEnv* env, jobject font2D,
 958         FTScalerContext *context, FTScalerInfo* scalerInfo,
 959         jint glyphCode, jfloat xpos, jfloat ypos) {
 960     int renderFlags;
 961     FT_Error error;
 962     FT_GlyphSlot ftglyph;
 963 
 964     if (glyphCode >= INVISIBLE_GLYPHS ||
 965             isNullScalerContext(context) || scalerInfo == NULL) {
 966         return NULL;
 967     }
 968 
 969     error = setupFTContext(env, font2D, scalerInfo, context);
 970     if (error) {
 971         return NULL;
 972     }
 973 
 974     renderFlags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
 975 
 976     error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags);
 977     if (error) {
 978         return NULL;
 979     }
 980 
 981     ftglyph = scalerInfo->face->glyph;
 982 
 983     /* apply styles */
 984     if (context->doBold) { /* if bold style */
 985         FT_GlyphSlot_Embolden(ftglyph);
 986     }
 987     if (context->doItalize) { /* if oblique */
 988         FT_GlyphSlot_Oblique(ftglyph);
 989     }
 990 
 991     FT_Outline_Translate(&ftglyph->outline,
 992                          FloatToF26Dot6(xpos),
 993                          -FloatToF26Dot6(ypos));
 994 
 995     return &ftglyph->outline;
 996 }
 997 
 998 #define F26Dot6ToFloat(n) (((float)(n))/((float) 64))
 999 
1000 /* Types of GeneralPath segments.
1001    TODO: pull constants from other place? */
1002 
1003 #define SEG_UNKNOWN -1
1004 #define SEG_MOVETO   0
1005 #define SEG_LINETO   1
1006 #define SEG_QUADTO   2
1007 #define SEG_CUBICTO  3
1008 #define SEG_CLOSE    4
1009 
1010 #define WIND_NON_ZERO 0
1011 #define WIND_EVEN_ODD 1
1012 
1013 /* Placeholder to accumulate GeneralPath data */
1014 typedef struct {
1015     jint numTypes;
1016     jint numCoords;
1017     jint lenTypes;
1018     jint lenCoords;
1019     jint wr;
1020     jbyte* pointTypes;
1021     jfloat* pointCoords;
1022 } GPData;
1023 
1024 /* returns 0 on failure */
1025 static int allocateSpaceForGP(GPData* gpdata, int npoints, int ncontours) {
1026     int maxTypes, maxCoords;
1027 
1028     /* we may have up to N intermediate points per contour
1029        (and for each point can actually cause new curve to be generated)
1030        In addition we can also have 2 extra point per outline.
1031      */
1032     maxTypes  = 2*npoints  + 2*ncontours;
1033     maxCoords = 4*(npoints + 2*ncontours); //we may need to insert
1034                                            //up to n-1 intermediate points
1035 
1036     /* first usage - allocate space and intialize all fields */
1037     if (gpdata->pointTypes == NULL || gpdata->pointCoords == NULL) {
1038         gpdata->lenTypes  = maxTypes;
1039         gpdata->lenCoords = maxCoords;
1040         gpdata->pointTypes  = (jbyte*)
1041              malloc(gpdata->lenTypes*sizeof(jbyte));
1042         gpdata->pointCoords = (jfloat*)
1043              malloc(gpdata->lenCoords*sizeof(jfloat));
1044         gpdata->numTypes = 0;
1045         gpdata->numCoords = 0;
1046         gpdata->wr = WIND_NON_ZERO; /* By default, outlines are filled
1047                                        using the non-zero winding rule. */
1048     } else {
1049         /* do we have enough space? */
1050         if (gpdata->lenTypes - gpdata->numTypes < maxTypes) {
1051             gpdata->lenTypes  += maxTypes;
1052             gpdata->pointTypes  = (jbyte*)
1053               realloc(gpdata->pointTypes, gpdata->lenTypes*sizeof(jbyte));
1054         }
1055 
1056         if (gpdata->lenCoords - gpdata->numCoords < maxCoords) {
1057             gpdata->lenCoords += maxCoords;
1058             gpdata->pointCoords = (jfloat*)
1059               realloc(gpdata->pointCoords, gpdata->lenCoords*sizeof(jfloat));
1060         }
1061     }
1062 
1063     /* failure if any of mallocs failed */
1064     if (gpdata->pointTypes == NULL ||  gpdata->pointCoords == NULL)
1065         return 0;
1066     else
1067         return 1;
1068 }
1069 
1070 static void addSeg(GPData *gp, jbyte type) {
1071     gp->pointTypes[gp->numTypes++] = type;
1072 }
1073 
1074 static void addCoords(GPData *gp, FT_Vector *p) {
1075     gp->pointCoords[gp->numCoords++] =  F26Dot6ToFloat(p->x);
1076     gp->pointCoords[gp->numCoords++] = -F26Dot6ToFloat(p->y);
1077 }
1078 
1079 static int moveTo(FT_Vector *to, GPData *gp) {
1080     if (gp->numCoords)
1081         addSeg(gp, SEG_CLOSE);
1082     addCoords(gp, to);
1083     addSeg(gp, SEG_MOVETO);
1084     return FT_Err_Ok;
1085 }
1086 
1087 static int lineTo(FT_Vector *to, GPData *gp) {
1088     addCoords(gp, to);
1089     addSeg(gp, SEG_LINETO);
1090     return FT_Err_Ok;
1091 }
1092 
1093 static int conicTo(FT_Vector *control, FT_Vector *to, GPData *gp) {
1094     addCoords(gp, control);
1095     addCoords(gp, to);
1096     addSeg(gp, SEG_QUADTO);
1097     return FT_Err_Ok;
1098 }
1099 
1100 static int cubicTo(FT_Vector *control1,
1101                    FT_Vector *control2,
1102                    FT_Vector *to,
1103                    GPData    *gp) {
1104     addCoords(gp, control1);
1105     addCoords(gp, control2);
1106     addCoords(gp, to);
1107     addSeg(gp, SEG_CUBICTO);
1108     return FT_Err_Ok;
1109 }
1110 
1111 static void addToGP(GPData* gpdata, FT_Outline*outline) {
1112     static const FT_Outline_Funcs outline_funcs = {
1113         (FT_Outline_MoveToFunc) moveTo,
1114         (FT_Outline_LineToFunc) lineTo,
1115         (FT_Outline_ConicToFunc) conicTo,
1116         (FT_Outline_CubicToFunc) cubicTo,
1117         0, /* shift */
1118         0, /* delta */
1119     };
1120 
1121     FT_Outline_Decompose(outline, &outline_funcs, gpdata);
1122     if (gpdata->numCoords)
1123         addSeg(gpdata, SEG_CLOSE);
1124 
1125     /* If set to 1, the outline will be filled using the even-odd fill rule */
1126     if (outline->flags & FT_OUTLINE_EVEN_ODD_FILL) {
1127         gpdata->wr = WIND_EVEN_ODD;
1128     }
1129 }
1130 
1131 static void freeGP(GPData* gpdata) {
1132     if (gpdata->pointCoords != NULL) {
1133         free(gpdata->pointCoords);
1134         gpdata->pointCoords = NULL;
1135         gpdata->numCoords = 0;
1136         gpdata->lenCoords = 0;
1137     }
1138     if (gpdata->pointTypes != NULL) {
1139         free(gpdata->pointTypes);
1140         gpdata->pointTypes = NULL;
1141         gpdata->numTypes = 0;
1142         gpdata->lenTypes = 0;
1143     }
1144 }
1145 
1146 static jobject getGlyphGeneralPath(JNIEnv* env, jobject font2D,
1147         FTScalerContext *context, FTScalerInfo *scalerInfo,
1148         jint glyphCode, jfloat xpos, jfloat ypos) {
1149 
1150     FT_Outline* outline;
1151     jobject gp = NULL;
1152     jbyteArray types;
1153     jfloatArray coords;
1154     GPData gpdata;
1155 
1156     outline = getFTOutline(env, font2D, context, scalerInfo,
1157                            glyphCode, xpos, ypos);
1158 
1159     if (outline == NULL || outline->n_points == 0) {
1160         return gp;
1161     }
1162 
1163     gpdata.pointTypes  = NULL;
1164     gpdata.pointCoords = NULL;
1165     if (!allocateSpaceForGP(&gpdata, outline->n_points, outline->n_contours)) {
1166         return gp;
1167     }
1168 
1169     addToGP(&gpdata, outline);
1170 
1171     types  = (*env)->NewByteArray(env, gpdata.numTypes);
1172     coords = (*env)->NewFloatArray(env, gpdata.numCoords);
1173 
1174     if (types && coords) {
1175         (*env)->SetByteArrayRegion(env, types, 0,
1176                                    gpdata.numTypes,
1177                                    gpdata.pointTypes);
1178         (*env)->SetFloatArrayRegion(env, coords, 0,
1179                                     gpdata.numCoords,
1180                                     gpdata.pointCoords);
1181         gp = (*env)->NewObject(env,
1182                                sunFontIDs.gpClass,
1183                                sunFontIDs.gpCtr,
1184                                gpdata.wr,
1185                                types,
1186                                gpdata.numTypes,
1187                                coords,
1188                                gpdata.numCoords);
1189     }
1190 
1191     freeGP(&gpdata);
1192 
1193     return gp;
1194 }
1195 
1196 /*
1197  * Class:     sun_font_FreetypeFontScaler
1198  * Method:    getGlyphOutlineNative
1199  * Signature: (Lsun/font/Font2D;JIFF)Ljava/awt/geom/GeneralPath;
1200  */
1201 JNIEXPORT jobject JNICALL
1202 Java_sun_font_FreetypeFontScaler_getGlyphOutlineNative(
1203       JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
1204       jlong pScaler, jint glyphCode, jfloat xpos, jfloat ypos) {
1205 
1206     FTScalerContext *context =
1207          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1208     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1209 
1210     jobject gp = getGlyphGeneralPath(env,
1211                                font2D,
1212                                context,
1213                                scalerInfo,
1214                                glyphCode,
1215                                xpos,
1216                                ypos);
1217     if (gp == NULL) { /* can be legal */
1218         gp = (*env)->NewObject(env,
1219                                sunFontIDs.gpClass,
1220                                sunFontIDs.gpCtrEmpty);
1221     }
1222     return gp;
1223 }
1224 
1225 /*
1226  * Class:     sun_font_FreetypeFontScaler
1227  * Method:    getGlyphOutlineBoundsNative
1228  * Signature: (Lsun/font/Font2D;JI)Ljava/awt/geom/Rectangle2D/Float;
1229  */
1230 JNIEXPORT jobject JNICALL
1231 Java_sun_font_FreetypeFontScaler_getGlyphOutlineBoundsNative(
1232         JNIEnv *env, jobject scaler, jobject font2D,
1233         jlong pScalerContext, jlong pScaler, jint glyphCode) {
1234 
1235     FT_Outline *outline;
1236     FT_BBox bbox;
1237     int error;
1238     jobject bounds;
1239 
1240     FTScalerContext *context =
1241          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1242     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1243 
1244     outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0);
1245     if (outline == NULL || outline->n_points == 0) {
1246         /* it is legal case, e.g. invisible glyph */
1247         bounds = (*env)->NewObject(env,
1248                                  sunFontIDs.rect2DFloatClass,
1249                                  sunFontIDs.rect2DFloatCtr);
1250         return bounds;
1251     }
1252 
1253     error = FT_Outline_Get_BBox(outline, &bbox);
1254 
1255     //convert bbox
1256     if (error || bbox.xMin >= bbox.xMax || bbox.yMin >= bbox.yMax) {
1257         bounds = (*env)->NewObject(env,
1258                                    sunFontIDs.rect2DFloatClass,
1259                                    sunFontIDs.rect2DFloatCtr);
1260     } else {
1261         bounds = (*env)->NewObject(env,
1262                                    sunFontIDs.rect2DFloatClass,
1263                                    sunFontIDs.rect2DFloatCtr4,
1264                                    F26Dot6ToFloat(bbox.xMin),
1265                                    F26Dot6ToFloat(-bbox.yMax),
1266                                    F26Dot6ToFloat(bbox.xMax-bbox.xMin),
1267                                    F26Dot6ToFloat(bbox.yMax-bbox.yMin));
1268     }
1269 
1270     return bounds;
1271 }
1272 
1273 /*
1274  * Class:     sun_font_FreetypeFontScaler
1275  * Method:    getGlyphVectorOutlineNative
1276  * Signature: (Lsun/font/Font2D;J[IIFF)Ljava/awt/geom/GeneralPath;
1277  */
1278 JNIEXPORT jobject
1279 JNICALL
1280 Java_sun_font_FreetypeFontScaler_getGlyphVectorOutlineNative(
1281         JNIEnv *env, jobject scaler, jobject font2D,
1282         jlong pScalerContext, jlong pScaler,
1283         jintArray glyphArray, jint numGlyphs, jfloat xpos, jfloat ypos) {
1284 
1285     FT_Outline* outline;
1286     jobject gp = NULL;
1287     jbyteArray types;
1288     jfloatArray coords;
1289     GPData gpdata;
1290     int i;
1291     jint *glyphs;
1292 
1293     FTScalerContext *context =
1294          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1295     FTScalerInfo *scalerInfo =
1296              (FTScalerInfo*) jlong_to_ptr(pScaler);
1297 
1298     glyphs = NULL;
1299     if (numGlyphs > 0 && 0xffffffffu / sizeof(jint) >= numGlyphs) {
1300         glyphs = (jint*) malloc(numGlyphs*sizeof(jint));
1301     }
1302     if (glyphs == NULL) {
1303         // We reach here if:
1304         // 1. numGlyphs <= 0,
1305         // 2. overflow check failed, or
1306         // 3. malloc failed.
1307         gp = (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty);
1308         return gp;
1309     }
1310 
1311     (*env)->GetIntArrayRegion(env, glyphArray, 0, numGlyphs, glyphs);
1312 
1313     gpdata.numCoords = 0;
1314     for (i=0; i<numGlyphs;i++) {
1315         if (glyphs[i] >= INVISIBLE_GLYPHS) {
1316             continue;
1317         }
1318         outline = getFTOutline(env,
1319                                font2D,
1320                                context,
1321                                scalerInfo,
1322                                glyphs[i],
1323                                xpos, ypos);
1324 
1325         if (outline == NULL || outline->n_points == 0) {
1326             continue;
1327         }
1328 
1329         gpdata.pointTypes  = NULL;
1330         gpdata.pointCoords = NULL;
1331         if (!allocateSpaceForGP(&gpdata, outline->n_points,
1332                                 outline->n_contours)) {
1333             break;
1334         }
1335 
1336         addToGP(&gpdata, outline);
1337     }
1338     free(glyphs);
1339 
1340     if (gpdata.numCoords != 0) {
1341       types = (*env)->NewByteArray(env, gpdata.numTypes);
1342       coords = (*env)->NewFloatArray(env, gpdata.numCoords);
1343 
1344       if (types && coords) {
1345         (*env)->SetByteArrayRegion(env, types, 0,
1346                                    gpdata.numTypes, gpdata.pointTypes);
1347         (*env)->SetFloatArrayRegion(env, coords, 0,
1348                                     gpdata.numCoords, gpdata.pointCoords);
1349 
1350         gp=(*env)->NewObject(env,
1351                              sunFontIDs.gpClass,
1352                              sunFontIDs.gpCtr,
1353                              gpdata.wr,
1354                              types,
1355                              gpdata.numTypes,
1356                              coords,
1357                              gpdata.numCoords);
1358         return gp;
1359       }
1360     }
1361     return (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty);
1362 }
1363 
1364 JNIEXPORT jlong JNICALL
1365 Java_sun_font_FreetypeFontScaler_getUnitsPerEMNative(
1366         JNIEnv *env, jobject scaler, jlong pScaler) {
1367 
1368     FTScalerInfo *s = (FTScalerInfo* ) jlong_to_ptr(pScaler);
1369 
1370     /* Freetype doc says:
1371      The number of font units per EM square for this face.
1372      This is typically 2048 for TrueType fonts, and 1000 for Type 1 fonts.
1373      Only relevant for scalable formats.
1374      However, layout engine might be not tested with anything but 2048.
1375 
1376      NB: test it! */
1377     if (s != NULL) {
1378         return s->face->units_per_EM;
1379     }
1380     return 2048;
1381 }
1382 
1383 /* This native method is called by the OpenType layout engine. */
1384 JNIEXPORT jobject JNICALL
1385 Java_sun_font_FreetypeFontScaler_getGlyphPointNative(
1386         JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
1387         jlong pScaler, jint glyphCode, jint pointNumber) {
1388 
1389     FT_Outline* outline;
1390     jobject point = NULL;
1391     jfloat x=0, y=0;
1392     FTScalerContext *context =
1393          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1394     FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
1395 
1396     outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0);
1397 
1398     if (outline != NULL && outline->n_points > pointNumber) {
1399         x =  F26Dot6ToFloat(outline->points[pointNumber].x);
1400         y = -F26Dot6ToFloat(outline->points[pointNumber].y);
1401     }
1402 
1403     return (*env)->NewObject(env, sunFontIDs.pt2DFloatClass,
1404                              sunFontIDs.pt2DFloatCtr, x, y);
1405 }