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