1 /*
   2  * Copyright (c) 2011, 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 #import <Accelerate/Accelerate.h> // for vImage_Buffer
  27 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  28 
  29 #import "CGGlyphImages.h"
  30 #import "CoreTextSupport.h"
  31 #import "fontscalerdefs.h" // contains the definition of GlyphInfo struct
  32 
  33 #import "sun_awt_SunHints.h"
  34 
  35 //#define USE_IMAGE_ALIGNED_MEMORY 1
  36 //#define CGGI_DEBUG 1
  37 //#define CGGI_DEBUG_DUMP 1
  38 //#define CGGI_DEBUG_HIT_COUNT 1
  39 
  40 #define PRINT_TX(x) \
  41     NSLog(@"(%f, %f, %f, %f, %f, %f)", x.a, x.b, x.c, x.d, x.tx, x.ty);
  42 
  43 /*
  44  * The GlyphCanvas is a global shared CGContext that characters are struck into.
  45  * For each character, the glyph is struck, copied into a GlyphInfo struct, and
  46  * the canvas is cleared for the next glyph.
  47  *
  48  * If the necessary canvas is too large, the shared one will not be used and a
  49  * temporary one will be provided.
  50  */
  51 typedef enum {
  52     BLACK_ON_WHITE_STAGE,
  53     WHITE_ON_BLACK_STAGE
  54 } CGGI_GlyphRenderingStage;
  55 
  56 @interface CGGI_GlyphCanvas : NSObject {
  57 @public
  58     CGContextRef context;
  59     vImage_Buffer *image;
  60     CGGI_GlyphRenderingStage stage;
  61 }
  62 @end;
  63 
  64 @implementation CGGI_GlyphCanvas
  65 - (id) init {
  66     if (self = [super init]) {
  67         context = NULL;
  68         image = NULL;
  69         stage = BLACK_ON_WHITE_STAGE;
  70     }
  71     return self;
  72 }
  73 @end
  74 
  75 
  76 #pragma mark --- Debugging Helpers ---
  77 
  78 /*
  79  * These debug functions are only compiled when CGGI_DEBUG is activated.
  80  * They will print out a full UInt8 canvas and any pixels struck (assuming
  81  * the canvas is not too big).
  82  *
  83  * As another debug feature, the entire canvas will be filled with a light
  84  * alpha value so it is easy to see where the glyph painting regions are
  85  * at runtime.
  86  */
  87 
  88 #ifdef CGGI_DEBUG_DUMP
  89 static void
  90 DUMP_PIXELS(const char msg[], const UInt8 pixels[],
  91             const size_t bytesPerPixel, const int width, const int height)
  92 {
  93     printf("| %s: (%d, %d)\n", msg, width, height);
  94 
  95     if (width > 80 || height > 80) {
  96         printf("| too big\n");
  97         return;
  98     }
  99 
 100     size_t i, j = 0, k, size = width * height;
 101     for (i = 0; i < size; i++) {
 102         for (k = 0; k < bytesPerPixel; k++) {
 103             if (pixels[i * bytesPerPixel + k] > 0x80) j++;
 104         }
 105     }
 106 
 107     if (j == 0) {
 108         printf("| empty\n");
 109         return;
 110     }
 111 
 112     printf("|_");
 113     int x, y;
 114     for (x = 0; x < width; x++) {
 115         printf("__");
 116     }
 117     printf("_\n");
 118 
 119     for (y = 0; y < height; y++) {
 120         printf("| ");
 121         for (x = 0; x < width; x++) {
 122             int p = 0;
 123             for(k = 0; k < bytesPerPixel; k++) {
 124                 p += pixels[(y * width + x) * bytesPerPixel + k];
 125             }
 126 
 127             if (p < 0x80) {
 128                 printf("  ");
 129             } else {
 130                 printf("[]");
 131             }
 132         }
 133         printf(" |\n");
 134     }
 135 }
 136 
 137 static void
 138 DUMP_IMG_PIXELS(const char msg[], const vImage_Buffer *image)
 139 {
 140     const void *pixels = image->data;
 141     const size_t pixelSize = image->rowBytes / image->width;
 142     const size_t width = image->width;
 143     const size_t height = image->height;
 144 
 145     DUMP_PIXELS(msg, pixels, pixelSize, width, height);
 146 }
 147 
 148 static void
 149 PRINT_CGSTATES_INFO(const CGContextRef cgRef)
 150 {
 151     // TODO(cpc): lots of SPI use in this method; remove/rewrite?
 152 #if 0
 153     CGRect clip = CGContextGetClipBoundingBox(cgRef);
 154     fprintf(stderr, "    clip: ((%f, %f), (%f, %f))\n",
 155             clip.origin.x, clip.origin.y, clip.size.width, clip.size.height);
 156 
 157     CGAffineTransform ctm = CGContextGetCTM(cgRef);
 158     fprintf(stderr, "    ctm: (%f, %f, %f, %f, %f, %f)\n",
 159             ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty);
 160 
 161     CGAffineTransform txtTx = CGContextGetTextMatrix(cgRef);
 162     fprintf(stderr, "    txtTx: (%f, %f, %f, %f, %f, %f)\n",
 163             txtTx.a, txtTx.b, txtTx.c, txtTx.d, txtTx.tx, txtTx.ty);
 164 
 165     if (CGContextIsPathEmpty(cgRef) == 0) {
 166         CGPoint pathpoint = CGContextGetPathCurrentPoint(cgRef);
 167         CGRect pathbbox = CGContextGetPathBoundingBox(cgRef);
 168         fprintf(stderr, "    [pathpoint: (%f, %f)] [pathbbox: ((%f, %f), (%f, %f))]\n",
 169                 pathpoint.x, pathpoint.y, pathbbox.origin.x, pathbbox.origin.y,
 170                 pathbbox.size.width, pathbbox.size.width);
 171     }
 172 
 173     CGFloat linewidth = CGContextGetLineWidth(cgRef);
 174     CGLineCap linecap = CGContextGetLineCap(cgRef);
 175     CGLineJoin linejoin = CGContextGetLineJoin(cgRef);
 176     CGFloat miterlimit = CGContextGetMiterLimit(cgRef);
 177     size_t dashcount = CGContextGetLineDashCount(cgRef);
 178     fprintf(stderr, "    [linewidth: %f] [linecap: %d] [linejoin: %d] [miterlimit: %f] [dashcount: %lu]\n",
 179             linewidth, linecap, linejoin, miterlimit, (unsigned long)dashcount);
 180 
 181     CGFloat smoothness = CGContextGetSmoothness(cgRef);
 182     bool antialias = CGContextGetShouldAntialias(cgRef);
 183     bool smoothfont = CGContextGetShouldSmoothFonts(cgRef);
 184     JRSFontRenderingStyle fRendMode = CGContextGetFontRenderingMode(cgRef);
 185     fprintf(stderr, "    [smoothness: %f] [antialias: %d] [smoothfont: %d] [fontrenderingmode: %d]\n",
 186             smoothness, antialias, smoothfont, fRendMode);
 187 #endif
 188 }
 189 #endif
 190 
 191 #ifdef CGGI_DEBUG
 192 
 193 static void
 194 DUMP_GLYPHINFO(const GlyphInfo *info)
 195 {
 196     printf("size: (%d, %d) pixelSize: %d\n",
 197            info->width, info->height, info->rowBytes / info->width);
 198     printf("adv: (%f, %f) top: (%f, %f)\n",
 199            info->advanceX, info->advanceY, info->topLeftX, info->topLeftY);
 200 
 201 #ifdef CGGI_DEBUG_DUMP
 202     DUMP_PIXELS("Glyph Info Struct",
 203                 info->image, info->rowBytes / info->width,
 204                 info->width, info->height);
 205 #endif
 206 }
 207 
 208 #endif
 209 
 210 
 211 #pragma mark --- Font Rendering Mode Descriptors ---
 212 
 213 static inline void
 214 CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst)
 215 {
 216     *(dst + 0) = 0xFF - (p >> 16 & 0xFF);  // red
 217     *(dst + 1) = 0xFF - (p >>  8 & 0xFF);  // green
 218     *(dst + 2) = 0xFF - (p & 0xFF);        // blue
 219 }
 220 
 221 static void
 222 CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 223 {
 224     UInt32 *src = (UInt32 *)canvas->image->data;
 225     size_t srcRowWidth = canvas->image->width;
 226 
 227     UInt8 *dest = (UInt8 *)info->image;
 228     size_t destRowWidth = info->width;
 229 
 230     size_t height = info->height;
 231 
 232     size_t y;
 233     switch (canvas->stage) {
 234         case BLACK_ON_WHITE_STAGE:
 235             // fill empty glyph image with black-on-white glyph
 236             for (y = 0; y < height; y++) {
 237                 size_t destRow = y * destRowWidth * 3;
 238                 size_t srcRow = y * srcRowWidth;
 239 
 240                 size_t x;
 241                 for (x = 0; x < destRowWidth; x++) {
 242                     CGGI_CopyARGBPixelToRGBPixel(src[srcRow + x],
 243                             dest + destRow + x * 3);
 244                 }
 245             }
 246             break;
 247         case WHITE_ON_BLACK_STAGE:
 248             // merge black-on-white glyph (which is already in the glyph image)
 249             // with white-on-black glyph
 250             for (y = 0; y < height; y++) {
 251                 size_t destRow = y * destRowWidth * 3;
 252                 size_t srcRow = y * srcRowWidth;
 253 
 254                 size_t x;
 255                 for (x = 0; x < destRowWidth; x++) {
 256                     UInt8* pDst = dest + destRow + x * 3;
 257                     UInt32 srcPixel = src[srcRow + x];
 258 
 259                     UInt16 r = *(pDst + 0) + (0xff & (srcPixel >> 16));
 260                     *(pDst + 0) = (UInt8)(r >> 1);
 261                     UInt16 g = *(pDst + 1) + (0xff & (srcPixel >>  8));
 262                     *(pDst + 1) = (UInt8)(g >> 1);
 263                     UInt16 b = *(pDst + 2) + (0xff & (srcPixel      ));
 264                     *(pDst + 2) = (UInt8)(b >> 1);
 265                 }
 266             }
 267             break;
 268     }
 269 }
 270 
 271 //static void CGGI_copyImageFromCanvasToAlphaInfo
 272 //(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 273 //{
 274 //    vImage_Buffer infoBuffer;
 275 //    infoBuffer.data = info->image;
 276 //    infoBuffer.width = info->width;
 277 //    infoBuffer.height = info->height;
 278 //    infoBuffer.rowBytes = info->width; // three bytes per RGB pixel
 279 //
 280 //    UInt8 scrapPixel[info->width * info->height];
 281 //    vImage_Buffer scrapBuffer;
 282 //    scrapBuffer.data = &scrapPixel;
 283 //    scrapBuffer.width = info->width;
 284 //    scrapBuffer.height = info->height;
 285 //    scrapBuffer.rowBytes = info->width;
 286 //
 287 //    vImageConvert_ARGB8888toPlanar8(canvas->image, &infoBuffer,
 288 //        &scrapBuffer, &scrapBuffer, &scrapBuffer, kvImageNoFlags);
 289 //}
 290 
 291 static inline UInt8
 292 CGGI_ConvertWBPixelToByteGray(UInt32 p) {
 293     return ((p >> 16 & 0xFF) + (p >> 8 & 0xFF) + (p & 0xFF)) / 3;
 294 }
 295 
 296 static inline UInt8
 297 CGGI_ConvertBWPixelToByteGray(UInt32 p)
 298 {
 299     return 0xFF - CGGI_ConvertWBPixelToByteGray(p);
 300 }
 301 
 302 static void
 303 CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 304 {
 305     UInt32 *src = (UInt32 *)canvas->image->data;
 306     size_t srcRowWidth = canvas->image->width;
 307 
 308     UInt8 *dest = (UInt8 *)info->image;
 309     size_t destRowWidth = info->width;
 310 
 311     size_t height = info->height;
 312 
 313     size_t y;
 314     switch (canvas->stage) {
 315         case BLACK_ON_WHITE_STAGE:
 316             // fill empty glyph image with black-on-white glyph
 317             for (y = 0; y < height; y++) {
 318                 size_t destRow = y * destRowWidth;
 319                 size_t srcRow = y * srcRowWidth;
 320                 size_t x;
 321                 for (x = 0; x < destRowWidth; x++) {
 322                     UInt32 p = src[srcRow + x];
 323                     dest[destRow + x] = CGGI_ConvertBWPixelToByteGray(p);
 324                 }
 325             }
 326             break;
 327         case WHITE_ON_BLACK_STAGE:
 328             // merge black-on-white glyph (which is already in the glyph image)
 329             // with white-on-black glyph
 330             for (y = 0; y < height; y++) {
 331                 size_t destRow = y * destRowWidth;
 332                 size_t srcRow = y * srcRowWidth;
 333 
 334                 size_t x;
 335                 for (x = 0; x < destRowWidth; x++) {
 336                     UInt32 p = src[srcRow + x];
 337                     UInt16 gray = dest[destRow + x] + CGGI_ConvertWBPixelToByteGray(p);
 338                     dest[destRow + x] = (UInt8)(gray >> 1);
 339                 }
 340             }
 341             break;
 342     }
 343 }
 344 
 345 
 346 #pragma mark --- Pixel Size, Modes, and Canvas Shaping Helper Functions ---
 347 
 348 typedef struct CGGI_GlyphInfoDescriptor {
 349     size_t pixelSize;
 350     void (*copyFxnPtr)(CGGI_GlyphCanvas *canvas, GlyphInfo *info);
 351 } CGGI_GlyphInfoDescriptor;
 352 
 353 typedef struct CGGI_RenderingMode {
 354     CGGI_GlyphInfoDescriptor *glyphDescriptor;
 355     JRSFontRenderingStyle cgFontMode;
 356 } CGGI_RenderingMode;
 357 
 358 static CGGI_GlyphInfoDescriptor grey =
 359     { 1, &CGGI_CopyImageFromCanvasToAlphaInfo };
 360 static CGGI_GlyphInfoDescriptor rgb =
 361     { 3, &CGGI_CopyImageFromCanvasToRGBInfo };
 362 
 363 static inline CGGI_RenderingMode
 364 CGGI_GetRenderingMode(const AWTStrike *strike)
 365 {
 366     CGGI_RenderingMode mode;
 367     mode.cgFontMode = strike->fStyle;
 368     NSException *e = nil;
 369 
 370     switch (strike->fAAStyle) {
 371     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF:
 372     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON:
 373         mode.glyphDescriptor = &grey;
 374         break;
 375     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
 376     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HBGR:
 377     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
 378     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR:
 379         mode.glyphDescriptor = &rgb;
 380         break;
 381     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP:
 382     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT:
 383     default:
 384         e = [NSException
 385                 exceptionWithName:@"IllegalArgumentException"
 386                 reason:@"Invalid hint value"
 387                 userInfo:nil];
 388         @throw e;
 389     }
 390 
 391     return mode;
 392 }
 393 
 394 
 395 #pragma mark --- Canvas Managment ---
 396 
 397 /*
 398  * Creates a new canvas of a fixed size, and initializes the CGContext as
 399  * an 32-bit ARGB BitmapContext with some generic RGB color space.
 400  */
 401 static inline void
 402 CGGI_InitCanvas(CGGI_GlyphCanvas *canvas,
 403                 const vImagePixelCount width, const vImagePixelCount height,
 404                 const CGGI_RenderingMode* mode)
 405 {
 406     // our canvas is *always* 4-byte ARGB
 407     size_t bytesPerRow = width * sizeof(UInt32);
 408     size_t byteCount = bytesPerRow * height;
 409 
 410     canvas->image = malloc(sizeof(vImage_Buffer));
 411     canvas->image->width = width;
 412     canvas->image->height = height;
 413     canvas->image->rowBytes = bytesPerRow;
 414 
 415     canvas->image->data = (void *)calloc(byteCount, sizeof(UInt8));
 416     if (canvas->image->data == NULL) {
 417         [[NSException exceptionWithName:NSMallocException
 418             reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
 419     }
 420 
 421     canvas->stage = BLACK_ON_WHITE_STAGE;
 422 
 423     uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
 424     if (mode->glyphDescriptor == &rgb) {
 425         bmpInfo |= kCGBitmapByteOrder32Host;
 426     }
 427 
 428     CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
 429     canvas->context = CGBitmapContextCreate(canvas->image->data,
 430                                             width, height, 8, bytesPerRow,
 431                                             colorSpace,
 432                                             bmpInfo);
 433 
 434     // set foreground color
 435     CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
 436     
 437     CGContextSetFontSize(canvas->context, 1);
 438     CGContextSaveGState(canvas->context);
 439 
 440     CGColorSpaceRelease(colorSpace);
 441 }
 442 
 443 /*
 444  * Releases the BitmapContext and the associated memory backing it.
 445  */
 446 static inline void
 447 CGGI_FreeCanvas(CGGI_GlyphCanvas *canvas)
 448 {
 449     if (canvas->context != NULL) {
 450         CGContextRelease(canvas->context);
 451     }
 452 
 453     if (canvas->image != NULL) {
 454         if (canvas->image->data != NULL) {
 455             free(canvas->image->data);
 456         }
 457         free(canvas->image);
 458     }
 459 }
 460 
 461 /*
 462  * This is the slack space that is preallocated for the global GlyphCanvas
 463  * when it needs to be expanded. It has been set somewhat liberally to
 464  * avoid re-upsizing frequently.
 465  */
 466 #define CGGI_GLYPH_CANVAS_SLACK 2.5
 467 
 468 /*
 469  * Quick and easy inline to check if this canvas is big enough.
 470  */
 471 static inline void
 472 CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width,
 473         const vImagePixelCount height,
 474         const CGGI_RenderingMode* mode)
 475 {
 476     if (canvas->image != NULL &&
 477         width  < canvas->image->width &&
 478         height < canvas->image->height)
 479     {
 480         return;
 481     }
 482 
 483     // if we don't have enough space to strike the largest glyph in the
 484     // run, resize the canvas
 485     CGGI_FreeCanvas(canvas);
 486     CGGI_InitCanvas(canvas,
 487                     width * CGGI_GLYPH_CANVAS_SLACK,
 488                     height * CGGI_GLYPH_CANVAS_SLACK,
 489                     mode);
 490     JRSFontSetRenderingStyleOnContext(canvas->context, mode->cgFontMode);
 491 }
 492 
 493 /*
 494  * Clear the canvas by blitting white only into the region of interest
 495  * (the rect which we will copy out of once the glyph is struck).
 496  */
 497 static inline void
 498 CGGI_ClearCanvas(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 499 {
 500     vImage_Buffer canvasRectToClear;
 501     canvasRectToClear.data = canvas->image->data;
 502     canvasRectToClear.height = info->height;
 503     canvasRectToClear.width = info->width;
 504     // use the row stride of the canvas, not the info
 505     canvasRectToClear.rowBytes = canvas->image->rowBytes;
 506 
 507     // clean the canvas
 508 #ifdef CGGI_DEBUG
 509     Pixel_8888 opaqueWhite = { 0xE0, 0xE0, 0xE0, 0xE0 };
 510     Pixel_8888 opaqueBlack = { 0x10, 0x10, 0x10, 0xF0 };
 511 #else
 512     Pixel_8888 opaqueWhite = { 0xFF, 0xFF, 0xFF, 0xFF };
 513     Pixel_8888 opaqueBlack = { 0x00, 0x00, 0x00, 0xFF };
 514 #endif
 515 
 516     // clear canvas background and set foreground color
 517     switch(canvas->stage) {
 518         case BLACK_ON_WHITE_STAGE:
 519             vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueWhite, kvImageNoFlags);
 520             CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
 521             break;
 522         case WHITE_ON_BLACK_STAGE:
 523             vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueBlack, kvImageNoFlags);
 524             CGContextSetRGBFillColor(canvas->context, 1.0f, 1.0f, 1.0f, 1.0f);
 525             break;
 526     }
 527     CGContextSaveGState(canvas->context);
 528 }
 529 
 530 
 531 #pragma mark --- GlyphInfo Creation & Copy Functions ---
 532 
 533 /*
 534  * Creates a GlyphInfo with exactly the correct size image and measurements.
 535  */
 536 #define CGGI_GLYPH_BBOX_PADDING 2.0f
 537 static inline GlyphInfo *
 538 CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox,
 539                             const AWTStrike *strike,
 540                             const CGGI_RenderingMode *mode)
 541 {
 542     size_t pixelSize = mode->glyphDescriptor->pixelSize;
 543 
 544     // adjust the bounding box to be 1px bigger on each side than what
 545     // CGFont-whatever suggests - because it gives a bounding box that
 546     // is too tight
 547     bbox.size.width += CGGI_GLYPH_BBOX_PADDING * 2.0f;
 548     bbox.size.height += CGGI_GLYPH_BBOX_PADDING * 2.0f;
 549     bbox.origin.x -= CGGI_GLYPH_BBOX_PADDING;
 550     bbox.origin.y -= CGGI_GLYPH_BBOX_PADDING;
 551 
 552     vImagePixelCount width = ceilf(bbox.size.width);
 553     vImagePixelCount height = ceilf(bbox.size.height);
 554 
 555     // if the glyph is larger than 1MB, don't even try...
 556     // the GlyphVector path should have taken over by now
 557     // and zero pixels is ok
 558     if (width * height > 1024 * 1024) {
 559         width = 1;
 560         height = 1;
 561     }
 562     advance = CGSizeApplyAffineTransform(advance, strike->fFontTx);
 563     if (!JRSFontStyleUsesFractionalMetrics(strike->fStyle)) {
 564         advance.width = round(advance.width);
 565         advance.height = round(advance.height);
 566     }
 567     advance = CGSizeApplyAffineTransform(advance, strike->fDevTx);
 568 
 569 #ifdef USE_IMAGE_ALIGNED_MEMORY
 570     // create separate memory
 571     GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo));
 572     void *image = (void *)malloc(height * width * pixelSize);
 573 #else
 574     // create a GlyphInfo struct fused to the image it points to
 575     GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo) +
 576                                                height * width * pixelSize);
 577 #endif
 578 
 579     glyphInfo->advanceX = advance.width;
 580     glyphInfo->advanceY = advance.height;
 581     glyphInfo->topLeftX = round(bbox.origin.x);
 582     glyphInfo->topLeftY = round(bbox.origin.y);
 583     glyphInfo->width = width;
 584     glyphInfo->height = height;
 585     glyphInfo->rowBytes = width * pixelSize;
 586     glyphInfo->cellInfo = NULL;
 587 
 588 #ifdef USE_IMAGE_ALIGNED_MEMORY
 589     glyphInfo->image = image;
 590 #else
 591     glyphInfo->image = ((void *)glyphInfo) + sizeof(GlyphInfo);
 592 #endif
 593 
 594     return glyphInfo;
 595 }
 596 
 597 
 598 #pragma mark --- Glyph Striking onto Canvas ---
 599 
 600 /*
 601  * Clears the canvas, strikes the glyph with CoreGraphics, and then
 602  * copies the struck pixels into the GlyphInfo image.
 603  */
 604 static inline void
 605 CGGI_CreateImageForGlyph
 606     (CGGI_GlyphCanvas *canvas, const CGGlyph glyph,
 607      GlyphInfo *info, const CGGI_RenderingMode *mode)
 608 {
 609     // clean the canvas
 610     CGGI_ClearCanvas(canvas, info);
 611 
 612     // strike the glyph in the upper right corner
 613     CGContextShowGlyphsAtPoint(canvas->context,
 614                                -info->topLeftX,
 615                                canvas->image->height + info->topLeftY,
 616                                &glyph, 1);
 617 
 618     // copy the glyph from the canvas into the info
 619     (*mode->glyphDescriptor->copyFxnPtr)(canvas, info);
 620 }
 621 
 622 /*
 623  * CoreText path...
 624  */
 625 static inline GlyphInfo *
 626 CGGI_CreateImageForUnicode
 627     (CGGI_GlyphCanvas *canvas, const AWTStrike *strike,
 628      const CGGI_RenderingMode *mode, const UniChar uniChar)
 629 {
 630     // save the state of the world
 631     CGContextSaveGState(canvas->context);
 632 
 633     // get the glyph, measure it using CG
 634     CGGlyph glyph;
 635     CTFontRef fallback;
 636     if (uniChar > 0xFFFF) {
 637         UTF16Char charRef[2];
 638         CTS_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
 639         CGGlyph glyphTmp[2];
 640         fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
 641         glyph = glyphTmp[0];
 642     } else {
 643         UTF16Char charRef;
 644         charRef = (UTF16Char) uniChar; // truncate.
 645         fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, &glyph, 1);
 646     }
 647 
 648     CGAffineTransform tx = strike->fTx;
 649     JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
 650 
 651     CGRect bbox;
 652     JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, style, &glyph, 1, &bbox);
 653 
 654     CGSize advance;
 655     CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
 656 
 657     // create the Sun2D GlyphInfo we are going to strike into
 658     GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
 659 
 660     // fix the context size, just in case the substituted character is unexpectedly large
 661     CGGI_SizeCanvas(canvas, info->width, info->height, mode);
 662 
 663     // align the transform for the real CoreText strike
 664     CGContextSetTextMatrix(canvas->context, strike->fAltTx);
 665 
 666     const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
 667     CGContextSetFont(canvas->context, cgFallback);
 668     CFRelease(cgFallback);
 669 
 670     // clean the canvas - align, strike, and copy the glyph from the canvas into the info
 671     CGGI_CreateImageForGlyph(canvas, glyph, info, mode);
 672 
 673     // restore the state of the world
 674     CGContextRestoreGState(canvas->context);
 675 
 676     CFRelease(fallback);
 677 #ifdef CGGI_DEBUG
 678     DUMP_GLYPHINFO(info);
 679 #endif
 680 
 681 #ifdef CGGI_DEBUG_DUMP
 682     DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
 683 #if 0
 684     PRINT_CGSTATES_INFO(NULL);
 685 #endif
 686 #endif
 687 
 688     return info;
 689 }
 690 
 691 
 692 #pragma mark --- GlyphInfo Filling and Canvas Managment ---
 693 
 694 /*
 695  * Sets all the per-run properties for the canvas, and then iterates through
 696  * the character run, and creates images in the GlyphInfo structs.
 697  *
 698  * Not inlined because it would create two copies in the function below
 699  */
 700 static void
 701 CGGI_FillImagesForGlyphsWithSizedCanvas(CGGI_GlyphCanvas *canvas,
 702                                         const AWTStrike *strike,
 703                                         const CGGI_RenderingMode *mode,
 704                                         jlong glyphInfos[],
 705                                         const UniChar uniChars[],
 706                                         const CGGlyph glyphs[],
 707                                         const CFIndex len)
 708 {
 709     CGContextSetTextMatrix(canvas->context, strike->fAltTx);
 710 
 711     CGContextSetFont(canvas->context, strike->fAWTFont->fNativeCGFont);
 712     JRSFontSetRenderingStyleOnContext(canvas->context, strike->fStyle);
 713 
 714     CFIndex i;
 715     for (i = 0; i < len; i++) {
 716         GlyphInfo *info = (GlyphInfo *)jlong_to_ptr(glyphInfos[i]);
 717         if (info != NULL) {
 718             CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mode);
 719         } else {
 720             info = CGGI_CreateImageForUnicode(canvas, strike, mode, uniChars[i]);
 721             glyphInfos[i] = ptr_to_jlong(info);
 722         }
 723 #ifdef CGGI_DEBUG
 724         DUMP_GLYPHINFO(info);
 725 #endif
 726 
 727 #ifdef CGGI_DEBUG_DUMP
 728         DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
 729 #endif
 730     }
 731 #ifdef CGGI_DEBUG_DUMP
 732     DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
 733     PRINT_CGSTATES_INFO(canvas->context);
 734 #endif
 735 }
 736 
 737 static NSString *threadLocalAACanvasKey =
 738     @"Java CoreGraphics Text Renderer Cached Canvas for AA";
 739 
 740 static NSString *threadLocalLCDCanvasKey =
 741     @"Java CoreGraphics Text Renderer Cached Canvas for LCD";
 742 
 743 /*
 744  * This is the maximum length and height times the above slack squared
 745  * to determine if we go with the global canvas, or malloc one on the spot.
 746  */
 747 #define CGGI_GLYPH_CANVAS_MAX 100
 748 
 749 /*
 750  * Based on the space needed to strike the largest character in the run,
 751  * either use the global shared canvas, or make one up on the spot, strike
 752  * the glyphs, and destroy it.
 753  */
 754 static inline void
 755 CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
 756                          const CGGI_RenderingMode *mode,
 757                          const UniChar uniChars[], const CGGlyph glyphs[],
 758                          const size_t maxWidth, const size_t maxHeight,
 759                          const CFIndex len)
 760 {
 761     if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK >
 762         CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK)
 763     {
 764         CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
 765         CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode);
 766         // create black-on-white glyph image
 767         CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
 768                 mode, glyphInfos, uniChars,
 769                 glyphs, len);
 770 
 771         // merge glyph image with white-on-black glyph
 772         tmpCanvas->stage = WHITE_ON_BLACK_STAGE;
 773         CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
 774                                                 mode, glyphInfos, uniChars,
 775                                                 glyphs, len);
 776         CGGI_FreeCanvas(tmpCanvas);
 777 
 778         [tmpCanvas release];
 779         return;
 780     }
 781     NSMutableDictionary *threadDict =
 782         [[NSThread currentThread] threadDictionary];
 783 
 784     NSString* theKey = (mode->glyphDescriptor == &rgb) ?
 785         threadLocalLCDCanvasKey : threadLocalAACanvasKey;
 786     
 787     CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey];
 788     if (canvas == nil) {
 789         canvas = [[CGGI_GlyphCanvas alloc] init];
 790         [threadDict setObject:canvas forKey:theKey];
 791     }
 792 
 793     CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode);
 794     // create black-on-white glyph image
 795     canvas->stage = BLACK_ON_WHITE_STAGE;
 796     CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
 797                                             glyphInfos, uniChars, glyphs, len);
 798 
 799     // merge glyph image with white-on-black glyph
 800     canvas->stage = WHITE_ON_BLACK_STAGE;
 801     CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
 802                                             glyphInfos, uniChars, glyphs, len);
 803 
 804 }
 805 
 806 /*
 807  * Finds the advances and bounding boxes of the characters in the run,
 808  * cycles through all the bounds and calculates the maximum canvas space
 809  * required by the largest glyph.
 810  *
 811  * Creates a GlyphInfo struct with a malloc that also encapsulates the
 812  * image the struct points to.  This is done to meet memory layout
 813  * expectations in the Sun text rasterizer memory managment code.
 814  * The image immediately follows the struct physically in memory.
 815  */
 816 static inline void
 817 CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
 818                       const CGGI_RenderingMode *mode,
 819                       const UniChar uniChars[], const CGGlyph glyphs[],
 820                       CGSize advances[], CGRect bboxes[], const CFIndex len)
 821 {
 822     AWTFont *font = strike->fAWTFont;
 823     CGAffineTransform tx = strike->fTx;
 824     JRSFontRenderingStyle bboxCGMode = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
 825 
 826     JRSFontGetBoundingBoxesForGlyphsAndStyle((CTFontRef)font->fFont, &tx, bboxCGMode, glyphs, len, bboxes);
 827     CTFontGetAdvancesForGlyphs((CTFontRef)font->fFont, kCTFontDefaultOrientation, glyphs, advances, len);
 828 
 829     size_t maxWidth = 1;
 830     size_t maxHeight = 1;
 831 
 832     CFIndex i;
 833     for (i = 0; i < len; i++)
 834     {
 835         if (uniChars[i] != 0)
 836         {
 837             glyphInfos[i] = 0L;
 838             continue; // will be handled later
 839         }
 840 
 841         CGSize advance = advances[i];
 842         CGRect bbox = bboxes[i];
 843 
 844         GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
 845 
 846         if (maxWidth < glyphInfo->width)   maxWidth = glyphInfo->width;
 847         if (maxHeight < glyphInfo->height) maxHeight = glyphInfo->height;
 848 
 849         glyphInfos[i] = ptr_to_jlong(glyphInfo);
 850     }
 851 
 852     CGGI_FillImagesForGlyphs(glyphInfos, strike, mode, uniChars,
 853                              glyphs, maxWidth, maxHeight, len);
 854 }
 855 
 856 
 857 #pragma mark --- Temporary Buffer Allocations and Initialization ---
 858 
 859 /*
 860  * This stage separates the already valid glyph codes from the unicode values
 861  * that need special handling - the rawGlyphCodes array is no longer used
 862  * after this stage.
 863  */
 864 static void
 865 CGGI_CreateGlyphsAndScanForComplexities(jlong *glyphInfos,
 866                                         const AWTStrike *strike,
 867                                         const CGGI_RenderingMode *mode,
 868                                         jint rawGlyphCodes[],
 869                                         UniChar uniChars[], CGGlyph glyphs[],
 870                                         CGSize advances[], CGRect bboxes[],
 871                                         const CFIndex len)
 872 {
 873     CFIndex i;
 874     for (i = 0; i < len; i++) {
 875         jint code = rawGlyphCodes[i];
 876         if (code < 0) {
 877             glyphs[i] = 0;
 878             uniChars[i] = -code;
 879         } else {
 880             glyphs[i] = code;
 881             uniChars[i] = 0;
 882         }
 883     }
 884 
 885     CGGI_CreateGlyphInfos(glyphInfos, strike, mode,
 886                           uniChars, glyphs, advances, bboxes, len);
 887 
 888 #ifdef CGGI_DEBUG_HIT_COUNT
 889     static size_t hitCount = 0;
 890     hitCount++;
 891     printf("%d\n", (int)hitCount);
 892 #endif
 893 }
 894 
 895 /*
 896  * Conditionally stack allocates buffers for glyphs, bounding boxes,
 897  * and advances.  Unfortunately to use CG or CT in bulk runs (which is
 898  * faster than calling them per character), we have to copy into and out
 899  * of these buffers. Still a net win though.
 900  */
 901 void
 902 CGGlyphImages_GetGlyphImagePtrs(jlong glyphInfos[],
 903                                 const AWTStrike *strike,
 904                                 jint rawGlyphCodes[], const CFIndex len)
 905 {
 906     const CGGI_RenderingMode mode = CGGI_GetRenderingMode(strike);
 907 
 908     if (len < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) {
 909         CGRect bboxes[len];
 910         CGSize advances[len];
 911         CGGlyph glyphs[len];
 912         UniChar uniChars[len];
 913 
 914         CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
 915                                                 rawGlyphCodes, uniChars, glyphs,
 916                                                 advances, bboxes, len);
 917 
 918         return;
 919     }
 920 
 921     // just do one malloc, and carve it up for all the buffers
 922     void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
 923                           sizeof(CGGlyph) * sizeof(UniChar) * len);
 924     if (buffer == NULL) {
 925         [[NSException exceptionWithName:NSMallocException
 926             reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
 927     }
 928 
 929     CGRect *bboxes = (CGRect *)(buffer);
 930     CGSize *advances = (CGSize *)(bboxes + sizeof(CGRect) * len);
 931     CGGlyph *glyphs = (CGGlyph *)(advances + sizeof(CGGlyph) * len);
 932     UniChar *uniChars = (UniChar *)(glyphs + sizeof(UniChar) * len);
 933 
 934     CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
 935                                             rawGlyphCodes, uniChars, glyphs,
 936                                             advances, bboxes, len);
 937 
 938     free(buffer);
 939 }