1 /*
   2  * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "jni.h"
  27 #include "jni_util.h"
  28 #include "jlong.h"
  29 #include "sunfontids.h"
  30 #include "sun_font_FreetypeFontScaler.h"
  31 
  32 #include<stdlib.h>
  33 #include <math.h>
  34 #include "ft2build.h"
  35 #include FT_FREETYPE_H
  36 #include FT_GLYPH_H
  37 #include FT_BBOX_H
  38 #include FT_SIZES_H
  39 #include FT_OUTLINE_H
  40 #include FT_SYNTHESIS_H
  41 
  42 #include "fontscaler.h"
  43 
  44 #define  ftFixed1  (FT_Fixed) (1 << 16)
  45 #define  FloatToFTFixed(f) (FT_Fixed)((f) * (float)(ftFixed1))
  46 #define  FTFixedToFloat(x) ((x) / (float)(ftFixed1))
  47 #define  FT26Dot6ToFloat(x)  ((x) / ((float) (1<<6)))
  48 #define  ROUND(x) ((int) (x+0.5))
  49 
  50 typedef struct {
  51     /* Important note:
  52          JNI forbids sharing same env between different threads.
  53          We are safe, because pointer is overwritten every time we get into
  54          JNI call (see setupFTContext).
  55 
  56          Pointer is used by font data reading callbacks
  57          such as ReadTTFontFileFunc.
  58 
  59          NB: We may consider switching to JNI_GetEnv. */
  60     JNIEnv* env;
  61     FT_Library library;
  62     FT_Face face;
  63     jobject font2D;
  64     jobject directBuffer;
  65 
  66     unsigned char* fontData;
  67     unsigned fontDataOffset;
  68     unsigned fontDataLength;
  69     unsigned fileSize;
  70     TTLayoutTableCache* layoutTables;
  71 } FTScalerInfo;
  72 
  73 typedef struct FTScalerContext {
  74     FT_Matrix  transform;     /* glyph transform, including device transform */
  75     jboolean   useSbits;      /* sbit usage enabled? */
  76     jint       aaType;        /* antialiasing mode (off/on/grey/lcd) */
  77     jint       fmType;        /* fractional metrics - on/off */
  78     jboolean   doBold;        /* perform algorithmic bolding? */
  79     jboolean   doItalize;     /* perform algorithmic italicizing? */
  80     int        renderFlags;   /* configuration specific to particular engine */
  81     int        pathType;
  82     int        ptsz;          /* size in points */
  83 } FTScalerContext;
  84 
  85 #ifdef DEBUG
  86 /* These are referenced in the freetype sources if DEBUG macro is defined.
  87    To simplify work with debuging version of freetype we define
  88    them here. */
  89 int z_verbose;
  90 void z_error(char *s) {}
  91 #endif
  92 
  93 /**************** Error handling utilities *****************/
  94 
  95 static jmethodID invalidateScalerMID;
  96 
  97 JNIEXPORT void JNICALL
  98 Java_sun_font_FreetypeFontScaler_initIDs(
  99         JNIEnv *env, jobject scaler, jclass FFSClass) {
 100     invalidateScalerMID =
 101         (*env)->GetMethodID(env, FFSClass, "invalidateScaler", "()V");
 102 }
 103 
 104 static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) {
 105     void *stream;
 106 
 107     if (scalerInfo == NULL)
 108         return;
 109 
 110     //apparently Done_Face will only close the stream
 111     // but will not relase the memory of stream structure.
 112     // We need to free it explicitly to avoid leak.
 113     //Direct access to the stream field might be not ideal solution as
 114     // it is considred to be "private".
 115     //Alternatively we could have stored pointer to the structure
 116     // in the scalerInfo but this will increase size of the structure
 117     // for no good reason
 118     stream = scalerInfo->face->stream;
 119 
 120     FT_Done_Face(scalerInfo->face);
 121     FT_Done_FreeType(scalerInfo->library);
 122 
 123     if (scalerInfo->directBuffer != NULL) {
 124         (*env)->DeleteGlobalRef(env, scalerInfo->directBuffer);
 125     }
 126 
 127     if (scalerInfo->fontData != NULL) {
 128         free(scalerInfo->fontData);
 129     }
 130 
 131    if (stream != NULL) {
 132         free(stream);
 133    }
 134 
 135     free(scalerInfo);
 136 }
 137 
 138 /* invalidates state of java scaler object */
 139 static void invalidateJavaScaler(JNIEnv *env,
 140                                  jobject scaler,
 141                                  FTScalerInfo* scalerInfo) {
 142     freeNativeResources(env, scalerInfo);
 143     (*env)->CallVoidMethod(env, scaler, invalidateScalerMID);
 144 }
 145 
 146 /******************* I/O handlers ***************************/
 147 
 148 #define FILEDATACACHESIZE 1024
 149 
 150 /* NB: is it ever called? */
 151 static void CloseTTFontFileFunc(FT_Stream stream) {
 152     FTScalerInfo *scalerInfo = (FTScalerInfo *) stream->pathname.pointer;
 153     JNIEnv* env = scalerInfo->env;
 154     jclass tmpClass = (*env)->FindClass(env, "sun/font/TrueTypeFont");
 155     jfieldID platNameField =
 156          (*env)->GetFieldID(env, tmpClass, "platName", "Ljava/lang/String;");
 157     jstring platName = (*env)->GetObjectField(env,
 158                                               scalerInfo->font2D,
 159                                               platNameField);
 160     const char *name = JNU_GetStringPlatformChars(env, platName, NULL);
 161     JNU_ReleaseStringPlatformChars(env, platName, name);
 162 }
 163 
 164 static unsigned long ReadTTFontFileFunc(FT_Stream stream,
 165                                         unsigned long offset,
 166                                         unsigned char* destBuffer,
 167                                         unsigned long numBytes)
 168 {
 169     FTScalerInfo *scalerInfo = (FTScalerInfo *) stream->pathname.pointer;
 170     JNIEnv* env = scalerInfo->env;
 171     jobject bBuffer;
 172     int bread = 0;
 173 
 174     if (numBytes == 0) return 0;
 175 
 176     /* Large reads will bypass the cache and data copying */
 177     if (numBytes > FILEDATACACHESIZE) {
 178         bBuffer = (*env)->NewDirectByteBuffer(env, destBuffer, numBytes);
 179         if (bBuffer != NULL) {
 180             /* Loop until the read succeeds (or EOF).
 181              * This should improve robustness in the event of a problem in
 182              * the I/O system. If we find that we ever end up spinning here
 183              * we are going to have to do some serious work to recover.
 184              * Just returning without reading the data will cause a crash.
 185              */
 186             while (bread == 0) {
 187                 bread = (*env)->CallIntMethod(env,
 188                                               scalerInfo->font2D,
 189                                               sunFontIDs.ttReadBlockMID,
 190                                               bBuffer, offset, numBytes);
 191             }
 192             return bread;
 193         } else {
 194             /* We probably hit bug bug 4845371. For reasons that
 195              * are currently unclear, the call stacks after the initial
 196              * createScaler call that read large amounts of data seem to
 197              * be OK and can create the byte buffer above, but this code
 198              * is here just in case.
 199              * 4845371 is fixed now so I don't expect this code path to
 200              * ever get called but its harmless to leave it here on the
 201              * small chance its needed.
 202              */
 203             jbyteArray byteArray = (jbyteArray)
 204             (*env)->CallObjectMethod(env, scalerInfo->font2D,
 205                                      sunFontIDs.ttReadBytesMID,
 206                                      offset, numBytes);
 207             (*env)->GetByteArrayRegion(env, byteArray,
 208                                        0, numBytes, (jbyte*)destBuffer);
 209             return numBytes;
 210         }
 211     } /* Do we have a cache hit? */
 212       else if (scalerInfo->fontDataOffset <= offset &&
 213         scalerInfo->fontDataOffset + scalerInfo->fontDataLength >=
 214                                                          offset + numBytes)
 215     {
 216         unsigned cacheOffset = offset - scalerInfo->fontDataOffset;
 217 
 218         memcpy(destBuffer, scalerInfo->fontData+(size_t)cacheOffset, numBytes);
 219         return numBytes;
 220     } else {
 221         /* Must fill the cache */
 222         scalerInfo->fontDataOffset = offset;
 223         scalerInfo->fontDataLength =
 224                  (offset + FILEDATACACHESIZE > scalerInfo->fileSize) ?
 225                  scalerInfo->fileSize - offset : FILEDATACACHESIZE;
 226         bBuffer = scalerInfo->directBuffer;
 227         /* Loop until all the read succeeds (or EOF).
 228          * This should improve robustness in the event of a problem in
 229          * the I/O system. If we find that we ever end up spinning here
 230          * we are going to have to do some serious work to recover.
 231          * Just returning without reading the data will cause a crash.
 232          */
 233         while (bread == 0) {
 234             bread = (*env)->CallIntMethod(env, scalerInfo->font2D,
 235                                           sunFontIDs.ttReadBlockMID,
 236                                           bBuffer, offset,
 237                                           scalerInfo->fontDataLength);
 238         }
 239 
 240         memcpy(destBuffer, scalerInfo->fontData, numBytes);
 241         return numBytes;
 242     }
 243 }
 244 
 245 /*
 246  * Class:     sun_font_FreetypeFontScaler
 247  * Method:    initNativeScaler
 248  * Signature: (Lsun/font/Font2D;IIZI)J
 249  */
 250 JNIEXPORT jlong JNICALL
 251 Java_sun_font_FreetypeFontScaler_initNativeScaler(
 252         JNIEnv *env, jobject scaler, jobject font2D, jint type,
 253         jint indexInCollection, jboolean supportsCJK, jint filesize) {
 254     FTScalerInfo* scalerInfo = NULL;
 255     FT_Open_Args ft_open_args;
 256     int error;
 257     jobject bBuffer;
 258     scalerInfo = (FTScalerInfo*) calloc(1, sizeof(FTScalerInfo));
 259 
 260     if (scalerInfo == NULL)
 261         return 0;
 262 
 263     scalerInfo->env = env;
 264     scalerInfo->font2D = font2D;
 265     scalerInfo->fontDataOffset = 0;
 266     scalerInfo->fontDataLength = 0;
 267     scalerInfo->fileSize = filesize;
 268 
 269     /*
 270        We can consider sharing freetype library between different
 271        scalers. However, Freetype docs suggest to use different libraries
 272        for different threads. Also, our architecture implies that single
 273        FontScaler object is shared for for different sizes/transforms/styles
 274        of the same font.
 275 
 276        On other hand these methods can not be concurrently executed
 277        becaused they are "synchronized" in java.
 278     */
 279     error = FT_Init_FreeType(&scalerInfo->library);
 280     if (error) {
 281         free(scalerInfo);
 282         return 0;
 283     }
 284 
 285 #define TYPE1_FROM_JAVA        2
 286 
 287     error = 1; /* triggers memory freeing unless we clear it */
 288     if (type == TYPE1_FROM_JAVA) { /* TYPE1 */
 289         scalerInfo->fontData = (unsigned char*) malloc(filesize);
 290         scalerInfo->directBuffer = NULL;
 291         scalerInfo->layoutTables = NULL;
 292         scalerInfo->fontDataLength = filesize;
 293 
 294         if (scalerInfo->fontData != NULL) {
 295             bBuffer = (*env)->NewDirectByteBuffer(env,
 296                                               scalerInfo->fontData,
 297                                               scalerInfo->fontDataLength);
 298             if (bBuffer != NULL) {
 299                 (*env)->CallObjectMethod(env, font2D,
 300                                    sunFontIDs.readFileMID, bBuffer);
 301 
 302                 error = FT_New_Memory_Face(scalerInfo->library,
 303                                    scalerInfo->fontData,
 304                                    scalerInfo->fontDataLength,
 305                                    indexInCollection,
 306                                    &scalerInfo->face);
 307             }
 308         }
 309     } else { /* Truetype */
 310         scalerInfo->fontData = (unsigned char*) malloc(FILEDATACACHESIZE);
 311 
 312         if (scalerInfo->fontData != NULL) {
 313             FT_Stream ftstream = (FT_Stream) calloc(1, sizeof(FT_StreamRec));
 314             if (ftstream != NULL) {
 315                 scalerInfo->directBuffer = (*env)->NewDirectByteBuffer(env,
 316                                            scalerInfo->fontData,
 317                                            FILEDATACACHESIZE);
 318                 if (scalerInfo->directBuffer != NULL) {
 319                     scalerInfo->directBuffer = (*env)->NewGlobalRef(env,
 320                                                scalerInfo->directBuffer);
 321                     ftstream->base = NULL;
 322                     ftstream->size = filesize;
 323                     ftstream->pos = 0;
 324                     ftstream->read = (FT_Stream_IoFunc) ReadTTFontFileFunc;
 325                     ftstream->close = (FT_Stream_CloseFunc) CloseTTFontFileFunc;
 326                     ftstream->pathname.pointer = (void *) scalerInfo;
 327 
 328                     memset(&ft_open_args, 0, sizeof(FT_Open_Args));
 329                     ft_open_args.flags = FT_OPEN_STREAM;
 330                     ft_open_args.stream = ftstream;
 331 
 332                     error = FT_Open_Face(scalerInfo->library,
 333                                          &ft_open_args,
 334                                          indexInCollection,
 335                                          &scalerInfo->face);
 336                 }
 337                 if (error || scalerInfo->directBuffer == NULL) {
 338                     free(ftstream);
 339                 }
 340             }
 341         }
 342     }
 343 
 344     if (error) {
 345         FT_Done_FreeType(scalerInfo->library);
 346         if (scalerInfo->directBuffer != NULL) {
 347             (*env)->DeleteGlobalRef(env, scalerInfo->directBuffer);
 348         }
 349         if (scalerInfo->fontData != NULL)
 350             free(scalerInfo->fontData);
 351         free(scalerInfo);
 352         return 0;
 353     }
 354 
 355     return ptr_to_jlong(scalerInfo);
 356 }
 357 
 358 static double euclidianDistance(double a, double b) {
 359     if (a < 0) a=-a;
 360     if (b < 0) b=-b;
 361 
 362     if (a == 0) return b;
 363     if (b == 0) return a;
 364 
 365     return sqrt(a*a+b*b);
 366 }
 367 
 368 JNIEXPORT jlong JNICALL
 369 Java_sun_font_FreetypeFontScaler_createScalerContextNative(
 370         JNIEnv *env, jobject scaler, jlong pScaler, jdoubleArray matrix,
 371         jint aa, jint fm, jfloat boldness, jfloat italic) {
 372     double dmat[4], ptsz;
 373     FTScalerContext *context =
 374             (FTScalerContext*) calloc(1, sizeof(FTScalerContext));
 375     FTScalerInfo *scalerInfo =
 376              (FTScalerInfo*) jlong_to_ptr(pScaler);
 377 
 378     if (context == NULL) {
 379         invalidateJavaScaler(env, scaler, NULL);
 380         return (jlong) 0;
 381     }
 382     (*env)->GetDoubleArrayRegion(env, matrix, 0, 4, dmat);
 383     ptsz = euclidianDistance(dmat[2], dmat[3]); //i.e. y-size
 384     if (ptsz < 1.0) {
 385         //text can not be smaller than 1 point
 386         ptsz = 1.0;
 387     }
 388     context->ptsz = (int)(ptsz * 64);
 389     context->transform.xx =  FloatToFTFixed((float)dmat[0]/ptsz);
 390     context->transform.yx = -FloatToFTFixed((float)dmat[1]/ptsz);
 391     context->transform.xy = -FloatToFTFixed((float)dmat[2]/ptsz);
 392     context->transform.yy =  FloatToFTFixed((float)dmat[3]/ptsz);
 393     context->aaType = aa;
 394     context->fmType = fm;
 395 
 396     /* If using algorithmic styling, the base values are
 397      * boldness = 1.0, italic = 0.0.
 398      */
 399     context->doBold = (boldness != 1.0);
 400     context->doItalize = (italic != 0);
 401 
 402     return ptr_to_jlong(context);
 403 }
 404 
 405 static int setupFTContext(JNIEnv *env,
 406                           jobject font2D,
 407                           FTScalerInfo *scalerInfo,
 408                           FTScalerContext *context) {
 409     int errCode = 0;
 410 
 411     scalerInfo->env = env;
 412     scalerInfo->font2D = font2D;
 413 
 414     if (context != NULL) {
 415         FT_Set_Transform(scalerInfo->face, &context->transform, NULL);
 416 
 417         errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72);
 418 
 419         if (errCode == 0) {
 420             errCode = FT_Activate_Size(scalerInfo->face->size);
 421         }
 422     }
 423 
 424     return errCode;
 425 }
 426 
 427 /* ftsynth.c uses (0x10000, 0x06000, 0x0, 0x10000) matrix to get oblique
 428    outline.  Therefore x coordinate will change by 0x06000*y.
 429    Note that y coordinate does not change. */
 430 #define OBLIQUE_MODIFIER(y)  (context->doItalize ? ((y)*6/16) : 0)
 431 
 432 /*
 433  * Class:     sun_font_FreetypeFontScaler
 434  * Method:    getFontMetricsNative
 435  * Signature: (Lsun/font/Font2D;J)Lsun/font/StrikeMetrics;
 436  */
 437 JNIEXPORT jobject JNICALL
 438 Java_sun_font_FreetypeFontScaler_getFontMetricsNative(
 439         JNIEnv *env, jobject scaler, jobject font2D,
 440         jlong pScalerContext, jlong pScaler) {
 441 
 442     jobject metrics;
 443     jfloat ax, ay, dx, dy, bx, by, lx, ly, mx, my;
 444     jfloat f0 = 0.0;
 445     FT_Pos bmodifier = 0;
 446     FTScalerContext *context =
 447         (FTScalerContext*) jlong_to_ptr(pScalerContext);
 448     FTScalerInfo *scalerInfo =
 449              (FTScalerInfo*) jlong_to_ptr(pScaler);
 450 
 451     int errCode;
 452 
 453     if (isNullScalerContext(context) || scalerInfo == NULL) {
 454         return (*env)->NewObject(env,
 455                                  sunFontIDs.strikeMetricsClass,
 456                                  sunFontIDs.strikeMetricsCtr,
 457                                  f0, f0, f0, f0, f0, f0, f0, f0, f0, f0);
 458     }
 459 
 460     errCode = setupFTContext(env, font2D, scalerInfo, context);
 461 
 462     if (errCode) {
 463         metrics = (*env)->NewObject(env,
 464                                  sunFontIDs.strikeMetricsClass,
 465                                  sunFontIDs.strikeMetricsCtr,
 466                                  f0, f0, f0, f0, f0, f0, f0, f0, f0, f0);
 467         invalidateJavaScaler(env, scaler, scalerInfo);
 468         return metrics;
 469     }
 470 
 471     /* This is ugly and has to be reworked.
 472        Freetype provide means to add style to glyph but
 473        it seems there is no way to adjust metrics accordingly.
 474 
 475        So, we have to do adust them explicitly and stay consistent with what
 476        freetype does to outlines. */
 477 
 478     /* For bolding glyphs are not just widened. Height is also changed
 479        (see ftsynth.c).
 480 
 481        TODO: In vertical direction we could do better job and adjust metrics
 482        proportionally to glyoh shape. */
 483     if (context->doBold) {
 484         bmodifier = FT_MulFix(
 485                        scalerInfo->face->units_per_EM,
 486                        scalerInfo->face->size->metrics.y_scale)/24;
 487     }
 488 
 489 
 490     /**** Note: only some metrics are affected by styling ***/
 491 
 492     /* ascent */
 493     ax = 0;
 494     ay = -(jfloat) FT26Dot6ToFloat(FT_MulFix(
 495                        ((jlong) scalerInfo->face->ascender + bmodifier/2),
 496                        (jlong) scalerInfo->face->size->metrics.y_scale));
 497     /* descent */
 498     dx = 0;
 499     dy = -(jfloat) FT26Dot6ToFloat(FT_MulFix(
 500                        ((jlong) scalerInfo->face->descender + bmodifier/2),
 501                        (jlong) scalerInfo->face->size->metrics.y_scale));
 502     /* baseline */
 503     bx = by = 0;
 504 
 505     /* leading */
 506     lx = 0;
 507     ly = (jfloat) FT26Dot6ToFloat(FT_MulFix(
 508                       (jlong) scalerInfo->face->height + bmodifier,
 509                       (jlong) scalerInfo->face->size->metrics.y_scale))
 510                   + ay - dy;
 511     /* max advance */
 512     mx = (jfloat) FT26Dot6ToFloat(
 513                      scalerInfo->face->size->metrics.max_advance +
 514                      2*bmodifier +
 515                      OBLIQUE_MODIFIER(scalerInfo->face->size->metrics.height));
 516     my = 0;
 517 
 518     metrics = (*env)->NewObject(env,
 519                                 sunFontIDs.strikeMetricsClass,
 520                                 sunFontIDs.strikeMetricsCtr,
 521                                 ax, ay, dx, dy, bx, by, lx, ly, mx, my);
 522 
 523     return metrics;
 524 }
 525 
 526 /*
 527  * Class:     sun_font_FreetypeFontScaler
 528  * Method:    getGlyphAdvanceNative
 529  * Signature: (Lsun/font/Font2D;JI)F
 530  */
 531 JNIEXPORT jfloat JNICALL
 532 Java_sun_font_FreetypeFontScaler_getGlyphAdvanceNative(
 533         JNIEnv *env, jobject scaler, jobject font2D,
 534         jlong pScalerContext, jlong pScaler, jint glyphCode) {
 535 
 536    /* This method is rarely used because requests for metrics are usually
 537       coupled with request for bitmap and to large extend work can be reused
 538       (to find out metrics we need to hint glyph).
 539       So, we typically go through getGlyphImage code path.
 540 
 541       For initial freetype implementation we delegate
 542       all work to getGlyphImage but drop result image.
 543       This is waste of work related to scan conversion and conversion from
 544       freetype format to our format but for now this seems to be ok.
 545 
 546       NB: investigate performance benefits of refactoring code
 547       to avoid unnecesary work with bitmaps. */
 548 
 549     GlyphInfo *info;
 550     jfloat advance;
 551     jlong image;
 552 
 553     image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
 554                  env, scaler, font2D, pScalerContext, pScaler, glyphCode);
 555     info = (GlyphInfo*) jlong_to_ptr(image);
 556 
 557     advance = info->advanceX;
 558 
 559     free(info);
 560 
 561     return advance;
 562 }
 563 
 564 /*
 565  * Class:     sun_font_FreetypeFontScaler
 566  * Method:    getGlyphMetricsNative
 567  * Signature: (Lsun/font/Font2D;JILjava/awt/geom/Point2D/Float;)V
 568  */
 569 JNIEXPORT void JNICALL
 570 Java_sun_font_FreetypeFontScaler_getGlyphMetricsNative(
 571         JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
 572         jlong pScaler, jint glyphCode, jobject metrics) {
 573 
 574      /* As initial implementation we delegate all work to getGlyphImage
 575         but drop result image. This is clearly waste of resorces.
 576 
 577         TODO: investigate performance benefits of refactoring code
 578               by avoiding bitmap generation and conversion from FT
 579               bitmap format. */
 580      GlyphInfo *info;
 581 
 582      jlong image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
 583                                  env, scaler, font2D,
 584                                  pScalerContext, pScaler, glyphCode);
 585      info = (GlyphInfo*) jlong_to_ptr(image);
 586 
 587      (*env)->SetFloatField(env, metrics, sunFontIDs.xFID, info->advanceX);
 588      (*env)->SetFloatField(env, metrics, sunFontIDs.yFID, info->advanceY);
 589 
 590      free(info);
 591 }
 592 
 593 
 594 static GlyphInfo* getNullGlyphImage() {
 595     GlyphInfo *glyphInfo =  (GlyphInfo*) calloc(1, sizeof(GlyphInfo));
 596     return glyphInfo;
 597 }
 598 
 599 static void CopyBW2Grey8(const void* srcImage, int srcRowBytes,
 600                          void* dstImage, int dstRowBytes,
 601                          int width, int height) {
 602     const UInt8* srcRow = (UInt8*)srcImage;
 603     UInt8* dstRow = (UInt8*)dstImage;
 604     int wholeByteCount = width >> 3;
 605     int remainingBitsCount = width & 7;
 606     int i, j;
 607 
 608     while (height--) {
 609         const UInt8* src8 = srcRow;
 610         UInt8* dstByte = dstRow;
 611         unsigned srcValue;
 612 
 613         srcRow += srcRowBytes;
 614         dstRow += dstRowBytes;
 615 
 616         for (i = 0; i < wholeByteCount; i++) {
 617             srcValue = *src8++;
 618             for (j = 0; j < 8; j++) {
 619                 *dstByte++ = (srcValue & 0x80) ? 0xFF : 0;
 620                 srcValue <<= 1;
 621             }
 622         }
 623         if (remainingBitsCount) {
 624             srcValue = *src8;
 625             for (j = 0; j < remainingBitsCount; j++) {
 626                 *dstByte++ = (srcValue & 0x80) ? 0xFF : 0;
 627                 srcValue <<= 1;
 628             }
 629         }
 630     }
 631 }
 632 
 633 #define Grey4ToAlpha255(value) (((value) << 4) + ((value) >> 3))
 634 
 635 static void CopyGrey4ToGrey8(const void* srcImage, int srcRowBytes,
 636                 void* dstImage, int dstRowBytes, int width, int height) {
 637      const UInt8* srcRow = (UInt8*) srcImage;
 638      UInt8* dstRow = (UInt8*) dstImage;
 639      int i;
 640 
 641      while (height--) {
 642          const UInt8* src8 = srcRow;
 643          UInt8* dstByte = dstRow;
 644          unsigned srcValue;
 645 
 646          srcRow += srcRowBytes;
 647          dstRow += dstRowBytes;
 648 
 649          for (i = 0; i < width; i++) {
 650              srcValue = *src8++;
 651              *dstByte++ = Grey4ToAlpha255(srcValue & 0x0f);
 652              *dstByte++ = Grey4ToAlpha255(srcValue >> 4);
 653          }
 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 CopyFTSubpixelToSubpixel(const void* srcImage, int srcRowBytes,
 660                                      void* dstImage, int dstRowBytes,
 661                                      int width, int height) {
 662     unsigned char *srcRow = (unsigned char *) srcImage;
 663     unsigned char *dstRow = (unsigned char *) dstImage;
 664 
 665     while (height--) {
 666         memcpy(dstRow, srcRow, width);
 667         srcRow += srcRowBytes;
 668         dstRow += dstRowBytes;
 669     }
 670 }
 671 
 672 /* We need it because FT rows are often padded to 4 byte boundaries
 673    and our internal format is not padded */
 674 static void CopyFTSubpixelVToSubpixel(const void* srcImage, int srcRowBytes,
 675                                       void* dstImage, int dstRowBytes,
 676                                       int width, int height) {
 677     unsigned char *srcRow = (unsigned char *) srcImage, *srcByte;
 678     unsigned char *dstRow = (unsigned char *) dstImage, *dstByte;
 679     int i;
 680 
 681     while (height > 0) {
 682         srcByte = srcRow;
 683         dstByte = dstRow;
 684         for (i = 0; i < width; i++) {
 685             *dstByte++ = *srcByte;
 686             *dstByte++ = *(srcByte + srcRowBytes);
 687             *dstByte++ = *(srcByte + 2*srcRowBytes);
 688             srcByte++;
 689         }
 690         srcRow += 3*srcRowBytes;
 691         dstRow += dstRowBytes;
 692         height -= 3;
 693     }
 694 }
 695 
 696 
 697 /*
 698  * Class:     sun_font_FreetypeFontScaler
 699  * Method:    getGlyphImageNative
 700  * Signature: (Lsun/font/Font2D;JI)J
 701  */
 702 JNIEXPORT jlong JNICALL
 703 Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
 704         JNIEnv *env, jobject scaler, jobject font2D,
 705         jlong pScalerContext, jlong pScaler, jint glyphCode) {
 706 
 707     int error, imageSize;
 708     UInt16 width, height;
 709     GlyphInfo *glyphInfo;
 710     int glyph_index;
 711     int renderFlags = FT_LOAD_RENDER, target;
 712     FT_GlyphSlot ftglyph;
 713 
 714     FTScalerContext* context =
 715         (FTScalerContext*) jlong_to_ptr(pScalerContext);
 716     FTScalerInfo *scalerInfo =
 717              (FTScalerInfo*) jlong_to_ptr(pScaler);
 718 
 719     if (isNullScalerContext(context) || scalerInfo == NULL) {
 720         return ptr_to_jlong(getNullGlyphImage());
 721     }
 722 
 723     error = setupFTContext(env, font2D, scalerInfo, context);
 724     if (error) {
 725         invalidateJavaScaler(env, scaler, scalerInfo);
 726         return ptr_to_jlong(getNullGlyphImage());
 727     }
 728 
 729     /* if algorithmic styling is required then we do not request bitmap */
 730     if (context->doBold || context->doItalize) {
 731         renderFlags =  FT_LOAD_DEFAULT;
 732     }
 733 
 734     /* NB: in case of non identity transform
 735      we might also prefer to disable transform before hinting,
 736      and apply it explicitly after hinting is performed.
 737      Or we can disable hinting. */
 738 
 739     /* select appropriate hinting mode */
 740     if (context->aaType == TEXT_AA_OFF) {
 741         target = FT_LOAD_TARGET_MONO;
 742     } else if (context->aaType == TEXT_AA_ON) {
 743         target = FT_LOAD_TARGET_NORMAL;
 744     } else if (context->aaType == TEXT_AA_LCD_HRGB ||
 745                context->aaType == TEXT_AA_LCD_HBGR) {
 746         target = FT_LOAD_TARGET_LCD;
 747     } else {
 748         target = FT_LOAD_TARGET_LCD_V;
 749     }
 750     renderFlags |= target;
 751 
 752     glyph_index = FT_Get_Char_Index(scalerInfo->face, glyphCode);
 753 
 754     error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags);
 755     if (error) {
 756         //do not destroy scaler yet.
 757         //this can be problem of particular context (e.g. with bad transform)
 758         return ptr_to_jlong(getNullGlyphImage());
 759     }
 760 
 761     ftglyph = scalerInfo->face->glyph;
 762 
 763     /* apply styles */
 764     if (context->doBold) { /* if bold style */
 765         FT_GlyphSlot_Embolden(ftglyph);
 766     }
 767     if (context->doItalize) { /* if oblique */
 768         FT_GlyphSlot_Oblique(ftglyph);
 769     }
 770 
 771     /* generate bitmap if it is not done yet
 772      e.g. if algorithmic styling is performed and style was added to outline */
 773     if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) {
 774         FT_Render_Glyph(ftglyph, FT_LOAD_TARGET_MODE(target));
 775     }
 776 
 777     width  = (UInt16) ftglyph->bitmap.width;
 778     height = (UInt16) ftglyph->bitmap.rows;
 779 
 780     imageSize = width*height;
 781     glyphInfo = (GlyphInfo*) malloc(sizeof(GlyphInfo) + imageSize);
 782     if (glyphInfo == NULL) {
 783         glyphInfo = getNullGlyphImage();
 784         return ptr_to_jlong(glyphInfo);
 785     }
 786     glyphInfo->cellInfo  = NULL;
 787     glyphInfo->managed   = UNMANAGED_GLYPH;
 788     glyphInfo->rowBytes  = width;
 789     glyphInfo->width     = width;
 790     glyphInfo->height    = height;
 791     glyphInfo->topLeftX  = (float)  ftglyph->bitmap_left;
 792     glyphInfo->topLeftY  = (float) -ftglyph->bitmap_top;
 793 
 794     if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD) {
 795         glyphInfo->width = width/3;
 796     } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD_V) {
 797         glyphInfo->height = glyphInfo->height/3;
 798     }
 799 
 800     if (context->fmType == TEXT_FM_ON) {
 801         double advh = FTFixedToFloat(ftglyph->linearHoriAdvance);
 802         glyphInfo->advanceX =
 803             (float) (advh * FTFixedToFloat(context->transform.xx));
 804         glyphInfo->advanceY =
 805             (float) (advh * FTFixedToFloat(context->transform.xy));
 806     } else {
 807         if (!ftglyph->advance.y) {
 808             glyphInfo->advanceX =
 809                 (float) ROUND(FT26Dot6ToFloat(ftglyph->advance.x));
 810             glyphInfo->advanceY = 0;
 811         } else if (!ftglyph->advance.x) {
 812             glyphInfo->advanceX = 0;
 813             glyphInfo->advanceY =
 814                 (float) ROUND(FT26Dot6ToFloat(-ftglyph->advance.y));
 815         } else {
 816             glyphInfo->advanceX = FT26Dot6ToFloat(ftglyph->advance.x);
 817             glyphInfo->advanceY = FT26Dot6ToFloat(-ftglyph->advance.y);
 818         }
 819     }
 820 
 821     if (imageSize == 0) {
 822         glyphInfo->image = NULL;
 823     } else {
 824         glyphInfo->image = (unsigned char*) glyphInfo + sizeof(GlyphInfo);
 825         //convert result to output format
 826         //output format is either 3 bytes per pixel (for subpixel modes)
 827         // or 1 byte per pixel for AA and B&W
 828         if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_MONO) {
 829             /* convert from 8 pixels per byte to 1 byte per pixel */
 830             CopyBW2Grey8(ftglyph->bitmap.buffer,
 831                          ftglyph->bitmap.pitch,
 832                          (void *) glyphInfo->image,
 833                          width,
 834                          width,
 835                          height);
 836         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_GRAY) {
 837             /* byte per pixel to byte per pixel => just copy */
 838             memcpy(glyphInfo->image, ftglyph->bitmap.buffer, imageSize);
 839         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_GRAY4) {
 840             /* 4 bits per pixel to byte per pixel */
 841             CopyGrey4ToGrey8(ftglyph->bitmap.buffer,
 842                              ftglyph->bitmap.pitch,
 843                              (void *) glyphInfo->image,
 844                              width,
 845                              width,
 846                              height);
 847         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD) {
 848             /* 3 bytes per pixel to 3 bytes per pixel */
 849             CopyFTSubpixelToSubpixel(ftglyph->bitmap.buffer,
 850                                      ftglyph->bitmap.pitch,
 851                                      (void *) glyphInfo->image,
 852                                      width,
 853                                      width,
 854                                      height);
 855         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD_V) {
 856             /* 3 bytes per pixel to 3 bytes per pixel */
 857             CopyFTSubpixelVToSubpixel(ftglyph->bitmap.buffer,
 858                                       ftglyph->bitmap.pitch,
 859                                       (void *) glyphInfo->image,
 860                                       width*3,
 861                                       width,
 862                                       height);
 863             glyphInfo->rowBytes *=3;
 864         } else {
 865             free(glyphInfo);
 866             glyphInfo = getNullGlyphImage();
 867         }
 868     }
 869 
 870     return ptr_to_jlong(glyphInfo);
 871 }
 872 
 873 
 874 /*
 875  * Class:     sun_font_FreetypeFontScaler
 876  * Method:    getLayoutTableCacheNative
 877  * Signature: (J)J
 878  */
 879 JNIEXPORT jlong JNICALL
 880 Java_sun_font_FreetypeFontScaler_getLayoutTableCacheNative(
 881         JNIEnv *env, jobject scaler, jlong pScaler) {
 882     FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
 883 
 884     if (scalerInfo == NULL) {
 885         invalidateJavaScaler(env, scaler, scalerInfo);
 886         return 0L;
 887     }
 888 
 889     // init layout table cache in font
 890     // we're assuming the font is a file font and moreover it is Truetype font
 891     // otherwise we shouldn't be able to get here...
 892     if (scalerInfo->layoutTables == NULL) {
 893         scalerInfo->layoutTables = newLayoutTableCache();
 894     }
 895 
 896     return ptr_to_jlong(scalerInfo->layoutTables);
 897 }
 898 
 899 /*
 900  * Class:     sun_font_FreetypeFontScaler
 901  * Method:    disposeNativeScaler
 902  * Signature: (J)V
 903  */
 904 JNIEXPORT void JNICALL
 905 Java_sun_font_FreetypeFontScaler_disposeNativeScaler(
 906         JNIEnv *env, jobject scaler, jobject font2D, jlong pScaler) {
 907     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 908 
 909     /* Freetype functions *may* cause callback to java
 910        that can use cached values. Make sure our cache is up to date.
 911        NB: scaler context is not important at this point, can use NULL. */
 912     int errCode = setupFTContext(env, font2D, scalerInfo, NULL);
 913     if (errCode) {
 914         return;
 915     }
 916 
 917     freeNativeResources(env, scalerInfo);
 918 }
 919 
 920 /*
 921  * Class:     sun_font_FreetypeFontScaler
 922  * Method:    getNumGlyphsNative
 923  * Signature: ()I
 924  */
 925 JNIEXPORT jint JNICALL
 926 Java_sun_font_FreetypeFontScaler_getNumGlyphsNative(
 927         JNIEnv *env, jobject scaler, jlong pScaler) {
 928     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 929 
 930     if (scalerInfo == NULL || scalerInfo->face == NULL) { /* bad/null scaler */
 931         /* null scaler can render 1 glyph - "missing glyph" with code 0
 932            (all glyph codes requested by user are mapped to code 0 at
 933            validation step) */
 934         invalidateJavaScaler(env, scaler, scalerInfo);
 935         return (jint) 1;
 936     }
 937 
 938     return (jint) scalerInfo->face->num_glyphs;
 939 }
 940 
 941 /*
 942  * Class:     sun_font_FreetypeFontScaler
 943  * Method:    getMissingGlyphCodeNative
 944  * Signature: ()I
 945  */
 946 JNIEXPORT jint JNICALL
 947 Java_sun_font_FreetypeFontScaler_getMissingGlyphCodeNative(
 948         JNIEnv *env, jobject scaler, jlong pScaler) {
 949 
 950     /* Is it always 0 for freetype? */
 951     return 0;
 952 }
 953 
 954 /*
 955  * Class:     sun_font_FreetypeFontScaler
 956  * Method:    getGlyphCodeNative
 957  * Signature: (C)I
 958  */
 959 JNIEXPORT jint JNICALL
 960 Java_sun_font_FreetypeFontScaler_getGlyphCodeNative(
 961         JNIEnv *env, jobject scaler,
 962         jobject font2D, jlong pScaler, jchar charCode) {
 963 
 964     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
 965     int errCode;
 966 
 967     if (scaler == NULL || scalerInfo->face == NULL) { /* bad/null scaler */
 968         invalidateJavaScaler(env, scaler, scalerInfo);
 969         return 0;
 970     }
 971 
 972     /* Freetype functions *may* cause callback to java
 973        that can use cached values. Make sure our cache is up to date.
 974        Scaler context is not important here, can use NULL. */
 975     errCode = setupFTContext(env, font2D, scalerInfo, NULL);
 976     if (errCode) {
 977         return 0;
 978     }
 979 
 980     return FT_Get_Char_Index(scalerInfo->face, charCode);
 981 }
 982 
 983 
 984 #define FloatToF26Dot6(x) ((unsigned int) ((x)*64))
 985 
 986 static FT_Outline* getFTOutline(JNIEnv* env, jobject font2D,
 987         FTScalerContext *context, FTScalerInfo* scalerInfo,
 988         jint glyphCode, jfloat xpos, jfloat ypos) {
 989     int renderFlags;
 990     int glyph_index;
 991     FT_Error error;
 992     FT_GlyphSlot ftglyph;
 993 
 994     if (glyphCode >= INVISIBLE_GLYPHS ||
 995             isNullScalerContext(context) || scalerInfo == NULL) {
 996         return NULL;
 997     }
 998 
 999     error = setupFTContext(env, font2D, scalerInfo, context);
1000     if (error) {
1001         return NULL;
1002     }
1003 
1004     renderFlags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
1005 
1006     glyph_index = FT_Get_Char_Index(scalerInfo->face, glyphCode);
1007 
1008     error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags);
1009     if (error) {
1010         return NULL;
1011     }
1012 
1013     ftglyph = scalerInfo->face->glyph;
1014 
1015     /* apply styles */
1016     if (context->doBold) { /* if bold style */
1017         FT_GlyphSlot_Embolden(ftglyph);
1018     }
1019     if (context->doItalize) { /* if oblique */
1020         FT_GlyphSlot_Oblique(ftglyph);
1021     }
1022 
1023     FT_Outline_Translate(&ftglyph->outline,
1024                          FloatToF26Dot6(xpos),
1025                          -FloatToF26Dot6(ypos));
1026 
1027     return &ftglyph->outline;
1028 }
1029 
1030 #define F26Dot6ToFloat(n) (((float)(n))/((float) 64))
1031 
1032 /* Types of GeneralPath segments.
1033    TODO: pull constants from other place? */
1034 
1035 #define SEG_UNKNOWN -1
1036 #define SEG_MOVETO   0
1037 #define SEG_LINETO   1
1038 #define SEG_QUADTO   2
1039 #define SEG_CUBICTO  3
1040 #define SEG_CLOSE    4
1041 
1042 #define WIND_NON_ZERO 0
1043 #define WIND_EVEN_ODD 1
1044 
1045 /* Placeholder to accumulate GeneralPath data */
1046 typedef struct {
1047     jint numTypes;
1048     jint numCoords;
1049     jint lenTypes;
1050     jint lenCoords;
1051     jint wr;
1052     jbyte* pointTypes;
1053     jfloat* pointCoords;
1054 } GPData;
1055 
1056 /* returns 0 on failure */
1057 static int allocateSpaceForGP(GPData* gpdata, int npoints, int ncontours) {
1058     int maxTypes, maxCoords;
1059 
1060     /* we may have up to N intermediate points per contour
1061        (and for each point can actually cause new curve to be generated)
1062        In addition we can also have 2 extra point per outline.
1063      */
1064     maxTypes  = 2*npoints  + 2*ncontours;
1065     maxCoords = 4*(npoints + 2*ncontours); //we may need to insert
1066                                            //up to n-1 intermediate points
1067 
1068     /* first usage - allocate space and intialize all fields */
1069     if (gpdata->pointTypes == NULL || gpdata->pointCoords == NULL) {
1070         gpdata->lenTypes  = maxTypes;
1071         gpdata->lenCoords = maxCoords;
1072         gpdata->pointTypes  = (jbyte*)
1073              malloc(gpdata->lenTypes*sizeof(jbyte));
1074         gpdata->pointCoords = (jfloat*)
1075              malloc(gpdata->lenCoords*sizeof(jfloat));
1076         gpdata->numTypes = 0;
1077         gpdata->numCoords = 0;
1078         gpdata->wr = WIND_NON_ZERO; /* By default, outlines are filled
1079                                        using the non-zero winding rule. */
1080     } else {
1081         /* do we have enough space? */
1082         if (gpdata->lenTypes - gpdata->numTypes < maxTypes) {
1083             gpdata->lenTypes  += maxTypes;
1084             gpdata->pointTypes  = (jbyte*)
1085               realloc(gpdata->pointTypes, gpdata->lenTypes*sizeof(jbyte));
1086         }
1087 
1088         if (gpdata->lenCoords - gpdata->numCoords < maxCoords) {
1089             gpdata->lenCoords += maxCoords;
1090             gpdata->pointCoords = (jfloat*)
1091               realloc(gpdata->pointCoords, gpdata->lenCoords*sizeof(jfloat));
1092         }
1093     }
1094 
1095     /* failure if any of mallocs failed */
1096     if (gpdata->pointTypes == NULL ||  gpdata->pointCoords == NULL)
1097         return 0;
1098     else
1099         return 1;
1100 }
1101 
1102 static void addToGP(GPData* gpdata, FT_Outline*outline) {
1103     jbyte current_type=SEG_UNKNOWN;
1104     int i, j;
1105     jfloat x, y;
1106 
1107     j = 0;
1108     for(i=0; i<outline->n_points; i++) {
1109         x =  F26Dot6ToFloat(outline->points[i].x);
1110         y = -F26Dot6ToFloat(outline->points[i].y);
1111 
1112         if (FT_CURVE_TAG(outline->tags[i]) == FT_CURVE_TAG_ON) {
1113             /* If bit 0 is unset, the point is "off" the curve,
1114              i.e., a Bezier control point, while it is "on" when set. */
1115             if (current_type == SEG_UNKNOWN) { /* special case:
1116                                                   very first point */
1117                 /* add segment */
1118                 gpdata->pointTypes[gpdata->numTypes++] = SEG_MOVETO;
1119                 current_type = SEG_LINETO;
1120             } else {
1121                 gpdata->pointTypes[gpdata->numTypes++] = current_type;
1122                 current_type = SEG_LINETO;
1123             }
1124         } else {
1125             if (current_type == SEG_UNKNOWN) { /* special case:
1126                                                    very first point */
1127                 if (FT_CURVE_TAG(outline->tags[i+1]) == FT_CURVE_TAG_ON) {
1128                     /* just skip first point. Adhoc heuristic? */
1129                     continue;
1130                 } else {
1131                     x = (x + F26Dot6ToFloat(outline->points[i+1].x))/2;
1132                     y = (y - F26Dot6ToFloat(outline->points[i+1].y))/2;
1133                     gpdata->pointTypes[gpdata->numTypes++] = SEG_MOVETO;
1134                     current_type = SEG_LINETO;
1135                 }
1136             } else if (FT_CURVE_TAG(outline->tags[i]) == FT_CURVE_TAG_CUBIC) {
1137                 /* Bit 1 is meaningful for 'off' points only.
1138                    If set, it indicates a third-order Bezier arc control
1139                    point; and a second-order control point if unset.  */
1140                 current_type = SEG_CUBICTO;
1141             } else {
1142                 /* two successive conic "off" points forces the rasterizer
1143                    to create (during the scan-line conversion process
1144                    exclusively) a virtual "on" point amidst them, at their
1145                    exact middle. This greatly facilitates the definition of
1146                    successive conic Bezier arcs.  Moreover, it is the way
1147                    outlines are described in the TrueType specification. */
1148                 if (current_type == SEG_QUADTO) {
1149                     gpdata->pointCoords[gpdata->numCoords++] =
1150                         F26Dot6ToFloat(outline->points[i].x +
1151                         outline->points[i-1].x)/2;
1152                     gpdata->pointCoords[gpdata->numCoords++] =
1153                         - F26Dot6ToFloat(outline->points[i].y +
1154                         outline->points[i-1].y)/2;
1155                     gpdata->pointTypes[gpdata->numTypes++] = SEG_QUADTO;
1156                 }
1157                 current_type = SEG_QUADTO;
1158             }
1159         }
1160         gpdata->pointCoords[gpdata->numCoords++] = x;
1161         gpdata->pointCoords[gpdata->numCoords++] = y;
1162         if (outline->contours[j] == i) { //end of contour
1163             int start = j > 0 ? outline->contours[j-1]+1 : 0;
1164             gpdata->pointTypes[gpdata->numTypes++] = current_type;
1165             if (current_type == SEG_QUADTO &&
1166             FT_CURVE_TAG(outline->tags[start]) != FT_CURVE_TAG_ON) {
1167                 gpdata->pointCoords[gpdata->numCoords++] =
1168                             (F26Dot6ToFloat(outline->points[start].x) + x)/2;
1169                 gpdata->pointCoords[gpdata->numCoords++] =
1170                             (-F26Dot6ToFloat(outline->points[start].y) + y)/2;
1171             } else {
1172                 gpdata->pointCoords[gpdata->numCoords++] =
1173                             F26Dot6ToFloat(outline->points[start].x);
1174                 gpdata->pointCoords[gpdata->numCoords++] =
1175                             -F26Dot6ToFloat(outline->points[start].y);
1176             }
1177             gpdata->pointTypes[gpdata->numTypes++] = SEG_CLOSE;
1178             current_type = SEG_UNKNOWN;
1179             j++;
1180         }
1181     }
1182 
1183     /* If set to 1, the outline will be filled using the even-odd fill rule */
1184     if (outline->flags & FT_OUTLINE_EVEN_ODD_FILL) {
1185         gpdata->wr = WIND_EVEN_ODD;
1186     }
1187 }
1188 
1189 static void freeGP(GPData* gpdata) {
1190     if (gpdata->pointCoords != NULL) {
1191         free(gpdata->pointCoords);
1192         gpdata->pointCoords = NULL;
1193         gpdata->numCoords = 0;
1194         gpdata->lenCoords = 0;
1195     }
1196     if (gpdata->pointTypes != NULL) {
1197         free(gpdata->pointTypes);
1198         gpdata->pointTypes = NULL;
1199         gpdata->numTypes = 0;
1200         gpdata->lenTypes = 0;
1201     }
1202 }
1203 
1204 static jobject getGlyphGeneralPath(JNIEnv* env, jobject font2D,
1205         FTScalerContext *context, FTScalerInfo *scalerInfo,
1206         jint glyphCode, jfloat xpos, jfloat ypos) {
1207 
1208     FT_Outline* outline;
1209     jobject gp = NULL;
1210     jbyteArray types;
1211     jfloatArray coords;
1212     GPData gpdata;
1213 
1214     outline = getFTOutline(env, font2D, context, scalerInfo,
1215                            glyphCode, xpos, ypos);
1216 
1217     if (outline == NULL || outline->n_points == 0) {
1218         return gp;
1219     }
1220 
1221     gpdata.pointTypes  = NULL;
1222     gpdata.pointCoords = NULL;
1223     if (!allocateSpaceForGP(&gpdata, outline->n_points, outline->n_contours)) {
1224         return gp;
1225     }
1226 
1227     addToGP(&gpdata, outline);
1228 
1229     types  = (*env)->NewByteArray(env, gpdata.numTypes);
1230     coords = (*env)->NewFloatArray(env, gpdata.numCoords);
1231 
1232     if (types && coords) {
1233         (*env)->SetByteArrayRegion(env, types, 0,
1234                                    gpdata.numTypes,
1235                                    gpdata.pointTypes);
1236         (*env)->SetFloatArrayRegion(env, coords, 0,
1237                                     gpdata.numCoords,
1238                                     gpdata.pointCoords);
1239         gp = (*env)->NewObject(env,
1240                                sunFontIDs.gpClass,
1241                                sunFontIDs.gpCtr,
1242                                gpdata.wr,
1243                                types,
1244                                gpdata.numTypes,
1245                                coords,
1246                                gpdata.numCoords);
1247     }
1248 
1249     freeGP(&gpdata);
1250 
1251     return gp;
1252 }
1253 
1254 /*
1255  * Class:     sun_font_FreetypeFontScaler
1256  * Method:    getGlyphOutlineNative
1257  * Signature: (Lsun/font/Font2D;JIFF)Ljava/awt/geom/GeneralPath;
1258  */
1259 JNIEXPORT jobject JNICALL
1260 Java_sun_font_FreetypeFontScaler_getGlyphOutlineNative(
1261       JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
1262       jlong pScaler, jint glyphCode, jfloat xpos, jfloat ypos) {
1263 
1264     FTScalerContext *context =
1265          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1266     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1267 
1268     jobject gp = getGlyphGeneralPath(env,
1269                                font2D,
1270                                context,
1271                                scalerInfo,
1272                                glyphCode,
1273                                xpos,
1274                                ypos);
1275     if (gp == NULL) { /* can be legal */
1276         gp = (*env)->NewObject(env,
1277                                sunFontIDs.gpClass,
1278                                sunFontIDs.gpCtrEmpty);
1279     }
1280     return gp;
1281 }
1282 
1283 /*
1284  * Class:     sun_font_FreetypeFontScaler
1285  * Method:    getGlyphOutlineBoundsNative
1286  * Signature: (Lsun/font/Font2D;JI)Ljava/awt/geom/Rectangle2D/Float;
1287  */
1288 JNIEXPORT jobject JNICALL
1289 Java_sun_font_FreetypeFontScaler_getGlyphOutlineBoundsNative(
1290         JNIEnv *env, jobject scaler, jobject font2D,
1291         jlong pScalerContext, jlong pScaler, jint glyphCode) {
1292 
1293     FT_Outline *outline;
1294     FT_BBox bbox;
1295     int error;
1296     jobject bounds;
1297 
1298     FTScalerContext *context =
1299          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1300     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1301 
1302     outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0);
1303     if (outline == NULL || outline->n_points == 0) {
1304         /* it is legal case, e.g. invisible glyph */
1305         bounds = (*env)->NewObject(env,
1306                                  sunFontIDs.rect2DFloatClass,
1307                                  sunFontIDs.rect2DFloatCtr);
1308         return bounds;
1309     }
1310 
1311     error = FT_Outline_Get_BBox(outline, &bbox);
1312 
1313     //convert bbox
1314     if (error || bbox.xMin >= bbox.xMax || bbox.yMin >= bbox.yMax) {
1315         bounds = (*env)->NewObject(env,
1316                                    sunFontIDs.rect2DFloatClass,
1317                                    sunFontIDs.rect2DFloatCtr);
1318     } else {
1319         bounds = (*env)->NewObject(env,
1320                                    sunFontIDs.rect2DFloatClass,
1321                                    sunFontIDs.rect2DFloatCtr4,
1322                                    F26Dot6ToFloat(bbox.xMin),
1323                                    F26Dot6ToFloat(-bbox.yMax),
1324                                    F26Dot6ToFloat(bbox.xMax-bbox.xMin),
1325                                    F26Dot6ToFloat(bbox.yMax-bbox.yMin));
1326     }
1327 
1328     return bounds;
1329 }
1330 
1331 /*
1332  * Class:     sun_font_FreetypeFontScaler
1333  * Method:    getGlyphVectorOutlineNative
1334  * Signature: (Lsun/font/Font2D;J[IIFF)Ljava/awt/geom/GeneralPath;
1335  */
1336 JNIEXPORT jobject
1337 JNICALL
1338 Java_sun_font_FreetypeFontScaler_getGlyphVectorOutlineNative(
1339         JNIEnv *env, jobject scaler, jobject font2D,
1340         jlong pScalerContext, jlong pScaler,
1341         jintArray glyphArray, jint numGlyphs, jfloat xpos, jfloat ypos) {
1342 
1343     FT_Outline* outline;
1344     jobject gp = NULL;
1345     jbyteArray types;
1346     jfloatArray coords;
1347     GPData gpdata;
1348     int i;
1349     jint *glyphs;
1350 
1351     FTScalerContext *context =
1352          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1353     FTScalerInfo *scalerInfo =
1354              (FTScalerInfo*) jlong_to_ptr(pScaler);
1355 
1356     glyphs = NULL;
1357     if (numGlyphs > 0 && 0xffffffffu / sizeof(jint) >= numGlyphs) {
1358         glyphs = (jint*) malloc(numGlyphs*sizeof(jint));
1359     }
1360     if (glyphs == NULL) {
1361         // We reach here if:
1362         // 1. numGlyphs <= 0,
1363         // 2. overflow check failed, or
1364         // 3. malloc failed.
1365         gp = (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty);
1366         return gp;
1367     }
1368 
1369     (*env)->GetIntArrayRegion(env, glyphArray, 0, numGlyphs, glyphs);
1370 
1371     gpdata.numCoords = 0;
1372     for (i=0; i<numGlyphs;i++) {
1373         if (glyphs[i] >= INVISIBLE_GLYPHS) {
1374             continue;
1375         }
1376         outline = getFTOutline(env,
1377                                font2D,
1378                                context,
1379                                scalerInfo,
1380                                glyphs[i],
1381                                xpos, ypos);
1382 
1383         if (outline == NULL || outline->n_points == 0) {
1384             continue;
1385         }
1386 
1387         gpdata.pointTypes  = NULL;
1388         gpdata.pointCoords = NULL;
1389         if (!allocateSpaceForGP(&gpdata, outline->n_points,
1390                                 outline->n_contours)) {
1391             break;
1392         }
1393 
1394         addToGP(&gpdata, outline);
1395     }
1396     free(glyphs);
1397 
1398     if (gpdata.numCoords != 0) {
1399       types = (*env)->NewByteArray(env, gpdata.numTypes);
1400       coords = (*env)->NewFloatArray(env, gpdata.numCoords);
1401 
1402       if (types && coords) {
1403         (*env)->SetByteArrayRegion(env, types, 0,
1404                                    gpdata.numTypes, gpdata.pointTypes);
1405         (*env)->SetFloatArrayRegion(env, coords, 0,
1406                                     gpdata.numCoords, gpdata.pointCoords);
1407 
1408         gp=(*env)->NewObject(env,
1409                              sunFontIDs.gpClass,
1410                              sunFontIDs.gpCtr,
1411                              gpdata.wr,
1412                              types,
1413                              gpdata.numTypes,
1414                              coords,
1415                              gpdata.numCoords);
1416         return gp;
1417       }
1418     }
1419     return (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty);
1420 }
1421 
1422 JNIEXPORT jlong JNICALL
1423 Java_sun_font_FreetypeFontScaler_getUnitsPerEMNative(
1424         JNIEnv *env, jobject scaler, jlong pScaler) {
1425 
1426     FTScalerInfo *s = (FTScalerInfo* ) jlong_to_ptr(pScaler);
1427 
1428     /* Freetype doc says:
1429      The number of font units per EM square for this face.
1430      This is typically 2048 for TrueType fonts, and 1000 for Type 1 fonts.
1431      Only relevant for scalable formats.
1432      However, layout engine might be not tested with anything but 2048.
1433 
1434      NB: test it! */
1435     if (s != NULL) {
1436         return s->face->units_per_EM;
1437     }
1438     return 2048;
1439 }
1440 
1441 /* This native method is called by the OpenType layout engine. */
1442 JNIEXPORT jobject JNICALL
1443 Java_sun_font_FreetypeFontScaler_getGlyphPointNative(
1444         JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
1445         jlong pScaler, jint glyphCode, jint pointNumber) {
1446 
1447     FT_Outline* outline;
1448     jobject point = NULL;
1449     jfloat x=0, y=0;
1450     FTScalerContext *context =
1451          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1452     FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
1453 
1454     outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0);
1455 
1456     if (outline != NULL && outline->n_points > pointNumber) {
1457         x =  F26Dot6ToFloat(outline->points[pointNumber].x);
1458         y = -F26Dot6ToFloat(outline->points[pointNumber].y);
1459     }
1460 
1461     return (*env)->NewObject(env, sunFontIDs.pt2DFloatClass,
1462                              sunFontIDs.pt2DFloatCtr, x, y);
1463 }