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 static unsigned long ReadTTFontFileFunc(FT_Stream stream,
 151                                         unsigned long offset,
 152                                         unsigned char* destBuffer,
 153                                         unsigned long numBytes)
 154 {
 155     FTScalerInfo *scalerInfo = (FTScalerInfo *) stream->pathname.pointer;
 156     JNIEnv* env = scalerInfo->env;
 157     jobject bBuffer;
 158     int bread = 0;
 159 
 160     if (numBytes == 0) return 0;
 161 
 162     /* Large reads will bypass the cache and data copying */
 163     if (numBytes > FILEDATACACHESIZE) {
 164         bBuffer = (*env)->NewDirectByteBuffer(env, destBuffer, numBytes);
 165         if (bBuffer != NULL) {
 166             bread = (*env)->CallIntMethod(env,
 167                                           scalerInfo->font2D,
 168                                           sunFontIDs.ttReadBlockMID,
 169                                           bBuffer, offset, numBytes);
 170             return bread;
 171         } else {
 172             /* We probably hit bug 4845371. For reasons that
 173              * are currently unclear, the call stacks after the initial
 174              * createScaler call that read large amounts of data seem to
 175              * be OK and can create the byte buffer above, but this code
 176              * is here just in case.
 177              * 4845371 is fixed now so I don't expect this code path to
 178              * ever get called but its harmless to leave it here on the
 179              * small chance its needed.
 180              */
 181             jbyteArray byteArray = (jbyteArray)
 182             (*env)->CallObjectMethod(env, scalerInfo->font2D,
 183                                      sunFontIDs.ttReadBytesMID,
 184                                      offset, numBytes);
 185             (*env)->GetByteArrayRegion(env, byteArray,
 186                                        0, numBytes, (jbyte*)destBuffer);
 187             return numBytes;
 188         }
 189     } /* Do we have a cache hit? */
 190       else if (scalerInfo->fontDataOffset <= offset &&
 191         scalerInfo->fontDataOffset + scalerInfo->fontDataLength >=
 192                                                          offset + numBytes)
 193     {
 194         unsigned cacheOffset = offset - scalerInfo->fontDataOffset;
 195 
 196         memcpy(destBuffer, scalerInfo->fontData+(size_t)cacheOffset, numBytes);
 197         return numBytes;
 198     } else {
 199         /* Must fill the cache */
 200         scalerInfo->fontDataOffset = offset;
 201         scalerInfo->fontDataLength =
 202                  (offset + FILEDATACACHESIZE > scalerInfo->fileSize) ?
 203                  scalerInfo->fileSize - offset : FILEDATACACHESIZE;
 204         bBuffer = scalerInfo->directBuffer;
 205         bread = (*env)->CallIntMethod(env, scalerInfo->font2D,
 206                                       sunFontIDs.ttReadBlockMID,
 207                                       bBuffer, offset,
 208                                       scalerInfo->fontDataLength);
 209         memcpy(destBuffer, scalerInfo->fontData, numBytes);
 210         return numBytes;
 211     }
 212 }
 213 
 214 /*
 215  * Class:     sun_font_FreetypeFontScaler
 216  * Method:    initNativeScaler
 217  * Signature: (Lsun/font/Font2D;IIZI)J
 218  */
 219 JNIEXPORT jlong JNICALL
 220 Java_sun_font_FreetypeFontScaler_initNativeScaler(
 221         JNIEnv *env, jobject scaler, jobject font2D, jint type,
 222         jint indexInCollection, jboolean supportsCJK, jint filesize) {
 223     FTScalerInfo* scalerInfo = NULL;
 224     FT_Open_Args ft_open_args;
 225     int error;
 226     jobject bBuffer;
 227     scalerInfo = (FTScalerInfo*) calloc(1, sizeof(FTScalerInfo));
 228 
 229     if (scalerInfo == NULL)
 230         return 0;
 231 
 232     scalerInfo->env = env;
 233     scalerInfo->font2D = font2D;
 234     scalerInfo->fontDataOffset = 0;
 235     scalerInfo->fontDataLength = 0;
 236     scalerInfo->fileSize = filesize;
 237 
 238     /*
 239        We can consider sharing freetype library between different
 240        scalers. However, Freetype docs suggest to use different libraries
 241        for different threads. Also, our architecture implies that single
 242        FontScaler object is shared for different sizes/transforms/styles
 243        of the same font.
 244 
 245        On other hand these methods can not be concurrently executed
 246        becaused they are "synchronized" in java.
 247     */
 248     error = FT_Init_FreeType(&scalerInfo->library);
 249     if (error) {
 250         free(scalerInfo);
 251         return 0;
 252     }
 253 
 254 #define TYPE1_FROM_JAVA        2
 255 
 256     error = 1; /* triggers memory freeing unless we clear it */
 257     if (type == TYPE1_FROM_JAVA) { /* TYPE1 */
 258         scalerInfo->fontData = (unsigned char*) malloc(filesize);
 259         scalerInfo->directBuffer = NULL;
 260         scalerInfo->layoutTables = NULL;
 261         scalerInfo->fontDataLength = filesize;
 262 
 263         if (scalerInfo->fontData != NULL) {
 264             bBuffer = (*env)->NewDirectByteBuffer(env,
 265                                               scalerInfo->fontData,
 266                                               scalerInfo->fontDataLength);
 267             if (bBuffer != NULL) {
 268                 (*env)->CallObjectMethod(env, font2D,
 269                                    sunFontIDs.readFileMID, bBuffer);
 270 
 271                 error = FT_New_Memory_Face(scalerInfo->library,
 272                                    scalerInfo->fontData,
 273                                    scalerInfo->fontDataLength,
 274                                    indexInCollection,
 275                                    &scalerInfo->face);
 276             }
 277         }
 278     } else { /* Truetype */
 279         scalerInfo->fontData = (unsigned char*) malloc(FILEDATACACHESIZE);
 280 
 281         if (scalerInfo->fontData != NULL) {
 282             FT_Stream ftstream = (FT_Stream) calloc(1, sizeof(FT_StreamRec));
 283             if (ftstream != NULL) {
 284                 scalerInfo->directBuffer = (*env)->NewDirectByteBuffer(env,
 285                                            scalerInfo->fontData,
 286                                            FILEDATACACHESIZE);
 287                 if (scalerInfo->directBuffer != NULL) {
 288                     scalerInfo->directBuffer = (*env)->NewGlobalRef(env,
 289                                                scalerInfo->directBuffer);
 290                     ftstream->base = NULL;
 291                     ftstream->size = filesize;
 292                     ftstream->pos = 0;
 293                     ftstream->read = (FT_Stream_IoFunc) ReadTTFontFileFunc;
 294                     ftstream->close = NULL;
 295                     ftstream->pathname.pointer = (void *) scalerInfo;
 296 
 297                     memset(&ft_open_args, 0, sizeof(FT_Open_Args));
 298                     ft_open_args.flags = FT_OPEN_STREAM;
 299                     ft_open_args.stream = ftstream;
 300 
 301                     error = FT_Open_Face(scalerInfo->library,
 302                                          &ft_open_args,
 303                                          indexInCollection,
 304                                          &scalerInfo->face);



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