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  FT26Dot6ToInt(x) (((int)(x)) >> 6)
  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 
 107     if (scalerInfo == NULL)
 108         return;
 109 
 110     // FT_Done_Face always closes the stream, but only frees the memory
 111     // of the data structure if it was internally allocated by FT.
 112     // We hold on to a pointer to the stream structure if we provide it
 113     // ourselves, so that we can free it here.
 114     FT_Done_Face(scalerInfo->face);
 115     FT_Done_FreeType(scalerInfo->library);
 116 
 117     if (scalerInfo->directBuffer != NULL) {
 118         (*env)->DeleteGlobalRef(env, scalerInfo->directBuffer);
 119     }
 120 
 121     if (scalerInfo->fontData != NULL) {
 122         free(scalerInfo->fontData);
 123     }
 124 
 125     if (scalerInfo->faceStream != NULL) {
 126         free(scalerInfo->faceStream);
 127     }
 128     free(scalerInfo);
 129 }
 130 
 131 /* invalidates state of java scaler object */
 132 static void invalidateJavaScaler(JNIEnv *env,
 133                                  jobject scaler,
 134                                  FTScalerInfo* scalerInfo) {
 135     freeNativeResources(env, scalerInfo);
 136     (*env)->CallVoidMethod(env, scaler, invalidateScalerMID);
 137 }
 138 
 139 /******************* I/O handlers ***************************/
 140 
 141 #define FILEDATACACHESIZE 1024
 142 
 143 static unsigned long ReadTTFontFileFunc(FT_Stream stream,
 144                                         unsigned long offset,
 145                                         unsigned char* destBuffer,
 146                                         unsigned long numBytes)
 147 {
 148     FTScalerInfo *scalerInfo = (FTScalerInfo *) stream->pathname.pointer;
 149     JNIEnv* env = scalerInfo->env;
 150     jobject bBuffer;
 151     int bread = 0;
 152 
 153     if (numBytes == 0) return 0;
 154 
 155     /* Large reads will bypass the cache and data copying */
 156     if (numBytes > FILEDATACACHESIZE) {
 157         bBuffer = (*env)->NewDirectByteBuffer(env, destBuffer, numBytes);
 158         if (bBuffer != NULL) {
 159             bread = (*env)->CallIntMethod(env,
 160                                           scalerInfo->font2D,
 161                                           sunFontIDs.ttReadBlockMID,
 162                                           bBuffer, offset, numBytes);
 163             return bread;
 164         } else {
 165             /* We probably hit bug 4845371. For reasons that
 166              * are currently unclear, the call stacks after the initial
 167              * createScaler call that read large amounts of data seem to
 168              * be OK and can create the byte buffer above, but this code
 169              * is here just in case.
 170              * 4845371 is fixed now so I don't expect this code path to
 171              * ever get called but its harmless to leave it here on the
 172              * small chance its needed.
 173              */
 174             jbyteArray byteArray = (jbyteArray)
 175             (*env)->CallObjectMethod(env, scalerInfo->font2D,
 176                                      sunFontIDs.ttReadBytesMID,
 177                                      offset, numBytes);
 178             (*env)->GetByteArrayRegion(env, byteArray,
 179                                        0, numBytes, (jbyte*)destBuffer);
 180             return numBytes;
 181         }
 182     } /* Do we have a cache hit? */
 183       else if (scalerInfo->fontDataOffset <= offset &&
 184         scalerInfo->fontDataOffset + scalerInfo->fontDataLength >=
 185                                                          offset + numBytes)
 186     {
 187         unsigned cacheOffset = offset - scalerInfo->fontDataOffset;
 188 
 189         memcpy(destBuffer, scalerInfo->fontData+(size_t)cacheOffset, numBytes);
 190         return numBytes;
 191     } else {
 192         /* Must fill the cache */
 193         scalerInfo->fontDataOffset = offset;
 194         scalerInfo->fontDataLength =
 195                  (offset + FILEDATACACHESIZE > scalerInfo->fileSize) ?
 196                  scalerInfo->fileSize - offset : FILEDATACACHESIZE;
 197         bBuffer = scalerInfo->directBuffer;
 198         bread = (*env)->CallIntMethod(env, scalerInfo->font2D,
 199                                       sunFontIDs.ttReadBlockMID,
 200                                       bBuffer, offset,
 201                                       scalerInfo->fontDataLength);
 202         memcpy(destBuffer, scalerInfo->fontData, numBytes);
 203         return numBytes;
 204     }
 205 }
 206 
 207 /*
 208  * Class:     sun_font_FreetypeFontScaler
 209  * Method:    initNativeScaler
 210  * Signature: (Lsun/font/Font2D;IIZI)J
 211  */
 212 JNIEXPORT jlong JNICALL
 213 Java_sun_font_FreetypeFontScaler_initNativeScaler(
 214         JNIEnv *env, jobject scaler, jobject font2D, jint type,
 215         jint indexInCollection, jboolean supportsCJK, jint filesize) {
 216     FTScalerInfo* scalerInfo = NULL;
 217     FT_Open_Args ft_open_args;
 218     int error;
 219     jobject bBuffer;
 220     scalerInfo = (FTScalerInfo*) calloc(1, sizeof(FTScalerInfo));
 221 
 222     if (scalerInfo == NULL)
 223         return 0;
 224 
 225     scalerInfo->env = env;
 226     scalerInfo->font2D = font2D;
 227     scalerInfo->fontDataOffset = 0;
 228     scalerInfo->fontDataLength = 0;
 229     scalerInfo->fileSize = filesize;
 230 
 231     /*
 232        We can consider sharing freetype library between different
 233        scalers. However, Freetype docs suggest to use different libraries
 234        for different threads. Also, our architecture implies that single
 235        FontScaler object is shared for different sizes/transforms/styles
 236        of the same font.
 237 
 238        On other hand these methods can not be concurrently executed
 239        becaused they are "synchronized" in java.
 240     */
 241     error = FT_Init_FreeType(&scalerInfo->library);
 242     if (error) {
 243         free(scalerInfo);
 244         return 0;
 245     }
 246 
 247 #define TYPE1_FROM_JAVA        2
 248 
 249     error = 1; /* triggers memory freeing unless we clear it */
 250     if (type == TYPE1_FROM_JAVA) { /* TYPE1 */
 251         scalerInfo->fontData = (unsigned char*) malloc(filesize);
 252         scalerInfo->directBuffer = NULL;
 253         scalerInfo->layoutTables = NULL;
 254         scalerInfo->fontDataLength = filesize;
 255 
 256         if (scalerInfo->fontData != NULL) {
 257             bBuffer = (*env)->NewDirectByteBuffer(env,
 258                                               scalerInfo->fontData,
 259                                               scalerInfo->fontDataLength);
 260             if (bBuffer != NULL) {
 261                 (*env)->CallVoidMethod(env, font2D,
 262                                    sunFontIDs.readFileMID, bBuffer);
 263 
 264                 error = FT_New_Memory_Face(scalerInfo->library,
 265                                    scalerInfo->fontData,
 266                                    scalerInfo->fontDataLength,
 267                                    indexInCollection,
 268                                    &scalerInfo->face);
 269             }
 270         }
 271     } else { /* Truetype */
 272         scalerInfo->fontData = (unsigned char*) malloc(FILEDATACACHESIZE);
 273 
 274         if (scalerInfo->fontData != NULL) {
 275             FT_Stream ftstream = (FT_Stream) calloc(1, sizeof(FT_StreamRec));
 276             if (ftstream != NULL) {
 277                 scalerInfo->directBuffer = (*env)->NewDirectByteBuffer(env,
 278                                            scalerInfo->fontData,
 279                                            FILEDATACACHESIZE);
 280                 if (scalerInfo->directBuffer != NULL) {
 281                     scalerInfo->directBuffer = (*env)->NewGlobalRef(env,
 282                                                scalerInfo->directBuffer);
 283                     ftstream->base = NULL;
 284                     ftstream->size = filesize;
 285                     ftstream->pos = 0;
 286                     ftstream->read = (FT_Stream_IoFunc) ReadTTFontFileFunc;
 287                     ftstream->close = NULL;
 288                     ftstream->pathname.pointer = (void *) scalerInfo;
 289 
 290                     memset(&ft_open_args, 0, sizeof(FT_Open_Args));
 291                     ft_open_args.flags = FT_OPEN_STREAM;
 292                     ft_open_args.stream = ftstream;
 293 
 294                     error = FT_Open_Face(scalerInfo->library,
 295                                          &ft_open_args,
 296                                          indexInCollection,
 297                                          &scalerInfo->face);
 298                     if (!error) {
 299                         scalerInfo->faceStream = ftstream;
 300                     }
 301                 }
 302                 if (error || scalerInfo->directBuffer == NULL) {
 303                     free(ftstream);
 304                 }
 305             }
 306         }
 307     }
 308 
 309     if (error) {
 310         FT_Done_FreeType(scalerInfo->library);
 311         if (scalerInfo->directBuffer != NULL) {
 312             (*env)->DeleteGlobalRef(env, scalerInfo->directBuffer);
 313         }
 314         if (scalerInfo->fontData != NULL)
 315             free(scalerInfo->fontData);
 316         free(scalerInfo);
 317         return 0;
 318     }
 319 
 320     return ptr_to_jlong(scalerInfo);
 321 }
 322 
 323 static double euclidianDistance(double a, double b) {
 324     if (a < 0) a=-a;
 325     if (b < 0) b=-b;
 326 
 327     if (a == 0) return b;
 328     if (b == 0) return a;
 329 
 330     return sqrt(a*a+b*b);
 331 }
 332 
 333 JNIEXPORT jlong JNICALL
 334 Java_sun_font_FreetypeFontScaler_createScalerContextNative(
 335         JNIEnv *env, jobject scaler, jlong pScaler, jdoubleArray matrix,
 336         jint aa, jint fm, jfloat boldness, jfloat italic) {
 337     double dmat[4], ptsz;
 338     FTScalerContext *context =
 339             (FTScalerContext*) calloc(1, sizeof(FTScalerContext));
 340     FTScalerInfo *scalerInfo =
 341              (FTScalerInfo*) jlong_to_ptr(pScaler);
 342 
 343     if (context == NULL) {
 344         invalidateJavaScaler(env, scaler, NULL);
 345         return (jlong) 0;
 346     }
 347     (*env)->GetDoubleArrayRegion(env, matrix, 0, 4, dmat);
 348     ptsz = euclidianDistance(dmat[2], dmat[3]); //i.e. y-size
 349     if (ptsz < 1.0) {
 350         //text can not be smaller than 1 point
 351         ptsz = 1.0;
 352     }
 353     context->ptsz = (int)(ptsz * 64);
 354     context->transform.xx =  FloatToFTFixed((float)dmat[0]/ptsz);
 355     context->transform.yx = -FloatToFTFixed((float)dmat[1]/ptsz);
 356     context->transform.xy = -FloatToFTFixed((float)dmat[2]/ptsz);
 357     context->transform.yy =  FloatToFTFixed((float)dmat[3]/ptsz);
 358     context->aaType = aa;
 359     context->fmType = fm;
 360 
 361     /* If using algorithmic styling, the base values are
 362      * boldness = 1.0, italic = 0.0.
 363      */
 364     context->doBold = (boldness != 1.0);
 365     context->doItalize = (italic != 0);
 366 













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