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