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 CGGI_LCD_GLYPH_IN_TWO_STAGES
  41 
  42 #define PRINT_TX(x) \
  43     NSLog(@"(%f, %f, %f, %f, %f, %f)", x.a, x.b, x.c, x.d, x.tx, x.ty);
  44 
  45 /*
  46  * The GlyphCanvas is a global shared CGContext that characters are struck into.
  47  * For each character, the glyph is struck, copied into a GlyphInfo struct, and
  48  * the canvas is cleared for the next glyph.
  49  *
  50  * If the necessary canvas is too large, the shared one will not be used and a
  51  * temporary one will be provided.
  52  */
  53 typedef enum {
  54     BLACK_ON_WHITE_STAGE,
  55     WHITE_ON_BLACK_STAGE
  56 } CGGI_GlyphRenderingStage;
  57 
  58 @interface CGGI_GlyphCanvas : NSObject {
  59 @public
  60     CGContextRef context;
  61     vImage_Buffer *image;
  62     CGGI_GlyphRenderingStage stage;
  63 }
  64 @end;
  65 
  66 @implementation CGGI_GlyphCanvas
  67 - (id) init {
  68     if (self = [super init]) {
  69         context = NULL;
  70         image = NULL;
  71         stage = BLACK_ON_WHITE_STAGE;
  72     }
  73     return self;
  74 }
  75 @end
  76 
  77 
  78 #pragma mark --- Debugging Helpers ---
  79 
  80 /*
  81  * These debug functions are only compiled when CGGI_DEBUG is activated.
  82  * They will print out a full UInt8 canvas and any pixels struck (assuming
  83  * the canvas is not too big).
  84  *
  85  * As another debug feature, the entire canvas will be filled with a light
  86  * alpha value so it is easy to see where the glyph painting regions are
  87  * at runtime.
  88  */
  89 
  90 #ifdef CGGI_DEBUG_DUMP
  91 static void
  92 DUMP_PIXELS(const char msg[], const UInt8 pixels[],
  93             const size_t bytesPerPixel, const int width, const int height)
  94 {
  95     printf("| %s: (%d, %d)\n", msg, width, height);
  96 
  97     if (width > 80 || height > 80) {
  98         printf("| too big\n");
  99         return;
 100     }
 101 
 102     size_t i, j = 0, k, size = width * height;
 103     for (i = 0; i < size; i++) {
 104         for (k = 0; k < bytesPerPixel; k++) {
 105             if (pixels[i * bytesPerPixel + k] > 0x80) j++;
 106         }
 107     }
 108 
 109     if (j == 0) {
 110         printf("| empty\n");
 111         return;
 112     }
 113 
 114     printf("|_");
 115     int x, y;
 116     for (x = 0; x < width; x++) {
 117         printf("__");
 118     }
 119     printf("_\n");
 120 
 121     for (y = 0; y < height; y++) {
 122         printf("| ");
 123         for (x = 0; x < width; x++) {
 124             int p = 0;
 125             for(k = 0; k < bytesPerPixel; k++) {
 126                 p += pixels[(y * width + x) * bytesPerPixel + k];
 127             }
 128 
 129             if (p < 0x80) {
 130                 printf("  ");
 131             } else {
 132                 printf("[]");
 133             }
 134         }
 135         printf(" |\n");
 136     }
 137 }
 138 
 139 static void
 140 DUMP_IMG_PIXELS(const char msg[], const vImage_Buffer *image)
 141 {
 142     const void *pixels = image->data;
 143     const size_t pixelSize = image->rowBytes / image->width;
 144     const size_t width = image->width;
 145     const size_t height = image->height;
 146 
 147     DUMP_PIXELS(msg, pixels, pixelSize, width, height);
 148 }
 149 
 150 static void
 151 PRINT_CGSTATES_INFO(const CGContextRef cgRef)
 152 {
 153     // TODO(cpc): lots of SPI use in this method; remove/rewrite?
 154 #if 0
 155     CGRect clip = CGContextGetClipBoundingBox(cgRef);
 156     fprintf(stderr, "    clip: ((%f, %f), (%f, %f))\n",
 157             clip.origin.x, clip.origin.y, clip.size.width, clip.size.height);
 158 
 159     CGAffineTransform ctm = CGContextGetCTM(cgRef);
 160     fprintf(stderr, "    ctm: (%f, %f, %f, %f, %f, %f)\n",
 161             ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty);
 162 
 163     CGAffineTransform txtTx = CGContextGetTextMatrix(cgRef);
 164     fprintf(stderr, "    txtTx: (%f, %f, %f, %f, %f, %f)\n",
 165             txtTx.a, txtTx.b, txtTx.c, txtTx.d, txtTx.tx, txtTx.ty);
 166 
 167     if (CGContextIsPathEmpty(cgRef) == 0) {
 168         CGPoint pathpoint = CGContextGetPathCurrentPoint(cgRef);
 169         CGRect pathbbox = CGContextGetPathBoundingBox(cgRef);
 170         fprintf(stderr, "    [pathpoint: (%f, %f)] [pathbbox: ((%f, %f), (%f, %f))]\n",
 171                 pathpoint.x, pathpoint.y, pathbbox.origin.x, pathbbox.origin.y,
 172                 pathbbox.size.width, pathbbox.size.width);
 173     }
 174 
 175     CGFloat linewidth = CGContextGetLineWidth(cgRef);
 176     CGLineCap linecap = CGContextGetLineCap(cgRef);
 177     CGLineJoin linejoin = CGContextGetLineJoin(cgRef);
 178     CGFloat miterlimit = CGContextGetMiterLimit(cgRef);
 179     size_t dashcount = CGContextGetLineDashCount(cgRef);
 180     fprintf(stderr, "    [linewidth: %f] [linecap: %d] [linejoin: %d] [miterlimit: %f] [dashcount: %lu]\n",
 181             linewidth, linecap, linejoin, miterlimit, (unsigned long)dashcount);
 182 
 183     CGFloat smoothness = CGContextGetSmoothness(cgRef);
 184     bool antialias = CGContextGetShouldAntialias(cgRef);
 185     bool smoothfont = CGContextGetShouldSmoothFonts(cgRef);
 186     JRSFontRenderingStyle fRendMode = CGContextGetFontRenderingMode(cgRef);
 187     fprintf(stderr, "    [smoothness: %f] [antialias: %d] [smoothfont: %d] [fontrenderingmode: %d]\n",
 188             smoothness, antialias, smoothfont, fRendMode);
 189 #endif
 190 }
 191 #endif
 192 
 193 #ifdef CGGI_DEBUG
 194 
 195 static void
 196 DUMP_GLYPHINFO(const GlyphInfo *info)
 197 {
 198     printf("size: (%d, %d) pixelSize: %d\n",
 199            info->width, info->height, info->rowBytes / info->width);
 200     printf("adv: (%f, %f) top: (%f, %f)\n",
 201            info->advanceX, info->advanceY, info->topLeftX, info->topLeftY);
 202 
 203 #ifdef CGGI_DEBUG_DUMP
 204     DUMP_PIXELS("Glyph Info Struct",
 205                 info->image, info->rowBytes / info->width,
 206                 info->width, info->height);
 207 #endif
 208 }
 209 
 210 #endif
 211 
 212 
 213 #pragma mark --- Font Rendering Mode Descriptors ---
 214 
 215 static inline void
 216 CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst)
 217 {
 218     *(dst + 0) = 0xFF - (p >> 16 & 0xFF);  // red
 219     *(dst + 1) = 0xFF - (p >>  8 & 0xFF);  // green
 220     *(dst + 2) = 0xFF - (p & 0xFF);        // blue






 221 }
 222 
 223 static void
 224 CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 225 {
 226     UInt32 *src = (UInt32 *)canvas->image->data;
 227     size_t srcRowWidth = canvas->image->width;
 228 
 229     UInt8 *dest = (UInt8 *)info->image;
 230     size_t destRowWidth = info->width;
 231 
 232     size_t height = info->height;
 233 
 234     size_t y;
 235     switch (canvas->stage) {
 236         case BLACK_ON_WHITE_STAGE:
 237             // fill empty glyph image with black-on-white glyph
 238             for (y = 0; y < height; y++) {
 239                 size_t destRow = y * destRowWidth * 3;
 240                 size_t srcRow = y * srcRowWidth;
 241 
 242                 size_t x;
 243                 for (x = 0; x < destRowWidth; x++) {





 244                     CGGI_CopyARGBPixelToRGBPixel(src[srcRow + x],
 245                             dest + destRow + x * 3);
 246                 }
 247             }
 248             break;
 249         case WHITE_ON_BLACK_STAGE:
 250             // merge black-on-white glyph (which is already in the glyph image)
 251             // with white-on-black glyph
 252             for (y = 0; y < height; y++) {
 253                 size_t destRow = y * destRowWidth * 3;
 254                 size_t srcRow = y * srcRowWidth;
 255 
 256                 size_t x;
 257                 for (x = 0; x < destRowWidth; x++) {
 258                     UInt8* pDst = dest + destRow + x * 3;
 259                     UInt32 srcPixel = src[srcRow + x];
 260 
 261                     UInt16 r = *(pDst + 0) + (0xff & (srcPixel >> 16));
 262                     *(pDst + 0) = (UInt8)(r >> 1);
 263                     UInt16 g = *(pDst + 1) + (0xff & (srcPixel >>  8));
 264                     *(pDst + 1) = (UInt8)(g >> 1);
 265                     UInt16 b = *(pDst + 2) + (0xff & (srcPixel      ));
 266                     *(pDst + 2) = (UInt8)(b >> 1);
 267                 }
 268             }
 269             break;
 270     }
 271 }
 272 
 273 //static void CGGI_copyImageFromCanvasToAlphaInfo
 274 //(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 275 //{
 276 //    vImage_Buffer infoBuffer;
 277 //    infoBuffer.data = info->image;
 278 //    infoBuffer.width = info->width;
 279 //    infoBuffer.height = info->height;
 280 //    infoBuffer.rowBytes = info->width; // three bytes per RGB pixel
 281 //
 282 //    UInt8 scrapPixel[info->width * info->height];
 283 //    vImage_Buffer scrapBuffer;
 284 //    scrapBuffer.data = &scrapPixel;
 285 //    scrapBuffer.width = info->width;
 286 //    scrapBuffer.height = info->height;
 287 //    scrapBuffer.rowBytes = info->width;
 288 //
 289 //    vImageConvert_ARGB8888toPlanar8(canvas->image, &infoBuffer,
 290 //        &scrapBuffer, &scrapBuffer, &scrapBuffer, kvImageNoFlags);
 291 //}
 292 
 293 static inline UInt8
 294 CGGI_ConvertBWPixelToByteGray(UInt32 p)
 295 {
 296     return 0xFF - (((p >> 24 & 0xFF) + (p >> 16 & 0xFF) + (p >> 8 & 0xFF)) / 3);




 297 }
 298 
 299 static void
 300 CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 301 {
 302     UInt32 *src = (UInt32 *)canvas->image->data;
 303     size_t srcRowWidth = canvas->image->width;
 304 
 305     UInt8 *dest = (UInt8 *)info->image;
 306     size_t destRowWidth = info->width;
 307 
 308     size_t height = info->height;
 309 
 310     size_t y;
 311     
 312     if (canvas->stage != BLACK_ON_WHITE_STAGE) {
 313         // not needed for AA
 314         return;
 315     }
 316     
 317     // fill empty glyph image with black-on-white glyph
 318     for (y = 0; y < height; y++) {
 319         size_t destRow = y * destRowWidth;
 320         size_t srcRow = y * srcRowWidth;

 321         size_t x;
 322         for (x = 0; x < destRowWidth; x++) {
 323             UInt32 p = src[srcRow + x];
 324             dest[destRow + x] = CGGI_ConvertBWPixelToByteGray(p);
 325         }
 326     }
 327 }
 328 
 329 
 330 #pragma mark --- Pixel Size, Modes, and Canvas Shaping Helper Functions ---
 331 
 332 typedef struct CGGI_GlyphInfoDescriptor {
 333     size_t pixelSize;
 334     void (*copyFxnPtr)(CGGI_GlyphCanvas *canvas, GlyphInfo *info);
 335 } CGGI_GlyphInfoDescriptor;
 336 
 337 typedef struct CGGI_RenderingMode {
 338     CGGI_GlyphInfoDescriptor *glyphDescriptor;
 339     JRSFontRenderingStyle cgFontMode;
 340 } CGGI_RenderingMode;
 341 
 342 static CGGI_GlyphInfoDescriptor grey =
 343     { 1, &CGGI_CopyImageFromCanvasToAlphaInfo };
 344 static CGGI_GlyphInfoDescriptor rgb =
 345     { 3, &CGGI_CopyImageFromCanvasToRGBInfo };
 346 
 347 static inline CGGI_RenderingMode
 348 CGGI_GetRenderingMode(const AWTStrike *strike)
 349 {
 350     CGGI_RenderingMode mode;
 351     mode.cgFontMode = strike->fStyle;
 352     NSException *e = nil;
 353 
 354     switch (strike->fAAStyle) {

 355     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF:
 356     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON:


 357         mode.glyphDescriptor = &grey;
 358         break;
 359     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
 360     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HBGR:
 361     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
 362     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR:
 363         mode.glyphDescriptor = &rgb;
 364         break;
 365     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP:
 366     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT:
 367     default:
 368         e = [NSException
 369                 exceptionWithName:@"IllegalArgumentException"
 370                 reason:@"Invalid hint value"
 371                 userInfo:nil];
 372         @throw e;
 373     }
 374 
 375     return mode;
 376 }
 377 
 378 
 379 #pragma mark --- Canvas Managment ---
 380 
 381 /*
 382  * Creates a new canvas of a fixed size, and initializes the CGContext as
 383  * an 32-bit ARGB BitmapContext with some generic RGB color space.
 384  */
 385 static inline void
 386 CGGI_InitCanvas(CGGI_GlyphCanvas *canvas,
 387                 const vImagePixelCount width, const vImagePixelCount height,
 388                 const CGGI_RenderingMode* mode)
 389 {
 390     // our canvas is *always* 4-byte ARGB
 391     size_t bytesPerRow = width * sizeof(UInt32);
 392     size_t byteCount = bytesPerRow * height;
 393 
 394     canvas->image = malloc(sizeof(vImage_Buffer));
 395     canvas->image->width = width;
 396     canvas->image->height = height;
 397     canvas->image->rowBytes = bytesPerRow;
 398 
 399     canvas->image->data = (void *)calloc(byteCount, sizeof(UInt8));
 400     if (canvas->image->data == NULL) {
 401         [[NSException exceptionWithName:NSMallocException
 402             reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
 403     }
 404 
 405     canvas->stage = BLACK_ON_WHITE_STAGE;
 406 
 407     uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
 408     if (mode->glyphDescriptor == &rgb) {
 409         bmpInfo |= kCGBitmapByteOrder32Host;
 410     }
 411 
 412     CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
 413     canvas->context = CGBitmapContextCreate(canvas->image->data,
 414                                             width, height, 8, bytesPerRow,
 415                                             colorSpace,
 416                                             bmpInfo);
 417 
 418     // set foreground color
 419     CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
 420     
 421     CGContextSetFontSize(canvas->context, 1);
 422     CGContextSaveGState(canvas->context);
 423 
 424     CGColorSpaceRelease(colorSpace);
 425 }
 426 
 427 /*
 428  * Releases the BitmapContext and the associated memory backing it.
 429  */
 430 static inline void
 431 CGGI_FreeCanvas(CGGI_GlyphCanvas *canvas)
 432 {
 433     if (canvas->context != NULL) {
 434         CGContextRelease(canvas->context);
 435     }
 436 
 437     if (canvas->image != NULL) {
 438         if (canvas->image->data != NULL) {
 439             free(canvas->image->data);
 440         }
 441         free(canvas->image);
 442     }
 443 }
 444 
 445 /*
 446  * This is the slack space that is preallocated for the global GlyphCanvas
 447  * when it needs to be expanded. It has been set somewhat liberally to
 448  * avoid re-upsizing frequently.
 449  */
 450 #define CGGI_GLYPH_CANVAS_SLACK 2.5
 451 
 452 /*
 453  * Quick and easy inline to check if this canvas is big enough.
 454  */
 455 static inline void
 456 CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width,
 457         const vImagePixelCount height,
 458         const CGGI_RenderingMode* mode)
 459 {
 460     if (canvas->image != NULL &&
 461         width  < canvas->image->width &&
 462         height < canvas->image->height)
 463     {
 464         return;
 465     }
 466 
 467     // if we don't have enough space to strike the largest glyph in the
 468     // run, resize the canvas
 469     CGGI_FreeCanvas(canvas);
 470     CGGI_InitCanvas(canvas,
 471                     width * CGGI_GLYPH_CANVAS_SLACK,
 472                     height * CGGI_GLYPH_CANVAS_SLACK,
 473                     mode);
 474     JRSFontSetRenderingStyleOnContext(canvas->context, mode->cgFontMode);
 475 }
 476 
 477 /*
 478  * Clear the canvas by blitting white only into the region of interest
 479  * (the rect which we will copy out of once the glyph is struck).
 480  */
 481 static inline void
 482 CGGI_ClearCanvas(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 483 {
 484     vImage_Buffer canvasRectToClear;
 485     canvasRectToClear.data = canvas->image->data;
 486     canvasRectToClear.height = info->height;
 487     canvasRectToClear.width = info->width;
 488     // use the row stride of the canvas, not the info
 489     canvasRectToClear.rowBytes = canvas->image->rowBytes;
 490 
 491     // clean the canvas
 492 #ifdef CGGI_DEBUG
 493     Pixel_8888 opaqueWhite = { 0xE0, 0xE0, 0xE0, 0xE0 };
 494     Pixel_8888 opaqueBlack = { 0x10, 0x10, 0x10, 0xF0 };
 495 #else
 496     Pixel_8888 opaqueWhite = { 0xFF, 0xFF, 0xFF, 0xFF };
 497     Pixel_8888 opaqueBlack = { 0x00, 0x00, 0x00, 0xFF };
 498 #endif
 499 
 500     // clear canvas background and set foreground color
 501     switch(canvas->stage) {
 502         case BLACK_ON_WHITE_STAGE:
 503             vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueWhite, kvImageNoFlags);
 504             CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
 505             break;
 506         case WHITE_ON_BLACK_STAGE:
 507             vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueBlack, kvImageNoFlags);
 508             CGContextSetRGBFillColor(canvas->context, 1.0f, 1.0f, 1.0f, 1.0f);
 509             break;
 510     }
 511     CGContextSaveGState(canvas->context);
 512 }
 513 
 514 
 515 #pragma mark --- GlyphInfo Creation & Copy Functions ---
 516 
 517 /*
 518  * Creates a GlyphInfo with exactly the correct size image and measurements.
 519  */
 520 #define CGGI_GLYPH_BBOX_PADDING 2.0f
 521 static inline GlyphInfo *
 522 CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox,
 523                             const AWTStrike *strike,
 524                             const CGGI_RenderingMode *mode)
 525 {
 526     size_t pixelSize = mode->glyphDescriptor->pixelSize;
 527 
 528     // adjust the bounding box to be 1px bigger on each side than what
 529     // CGFont-whatever suggests - because it gives a bounding box that
 530     // is too tight
 531     bbox.size.width += CGGI_GLYPH_BBOX_PADDING * 2.0f;
 532     bbox.size.height += CGGI_GLYPH_BBOX_PADDING * 2.0f;
 533     bbox.origin.x -= CGGI_GLYPH_BBOX_PADDING;
 534     bbox.origin.y -= CGGI_GLYPH_BBOX_PADDING;
 535 
 536     vImagePixelCount width = ceilf(bbox.size.width);
 537     vImagePixelCount height = ceilf(bbox.size.height);
 538 
 539     // if the glyph is larger than 1MB, don't even try...
 540     // the GlyphVector path should have taken over by now
 541     // and zero pixels is ok
 542     if (width * height > 1024 * 1024) {
 543         width = 1;
 544         height = 1;
 545     }
 546     advance = CGSizeApplyAffineTransform(advance, strike->fFontTx);
 547     if (!JRSFontStyleUsesFractionalMetrics(strike->fStyle)) {
 548         advance.width = round(advance.width);
 549         advance.height = round(advance.height);
 550     }
 551     advance = CGSizeApplyAffineTransform(advance, strike->fDevTx);
 552 
 553 #ifdef USE_IMAGE_ALIGNED_MEMORY
 554     // create separate memory
 555     GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo));
 556     void *image = (void *)malloc(height * width * pixelSize);
 557 #else
 558     // create a GlyphInfo struct fused to the image it points to
 559     GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo) +
 560                                                height * width * pixelSize);
 561 #endif
 562 
 563     glyphInfo->advanceX = advance.width;
 564     glyphInfo->advanceY = advance.height;
 565     glyphInfo->topLeftX = round(bbox.origin.x);
 566     glyphInfo->topLeftY = round(bbox.origin.y);
 567     glyphInfo->width = width;
 568     glyphInfo->height = height;
 569     glyphInfo->rowBytes = width * pixelSize;
 570     glyphInfo->cellInfo = NULL;
 571 
 572 #ifdef USE_IMAGE_ALIGNED_MEMORY
 573     glyphInfo->image = image;
 574 #else
 575     glyphInfo->image = ((void *)glyphInfo) + sizeof(GlyphInfo);
 576 #endif
 577 
 578     return glyphInfo;
 579 }
 580 
 581 
 582 #pragma mark --- Glyph Striking onto Canvas ---
 583 
 584 /*
 585  * Clears the canvas, strikes the glyph with CoreGraphics, and then
 586  * copies the struck pixels into the GlyphInfo image.
 587  */
 588 static inline void
 589 CGGI_CreateImageForGlyph
 590     (CGGI_GlyphCanvas *canvas, const CGGlyph glyph,
 591      GlyphInfo *info, const CGGI_RenderingMode *mode)
 592 {
 593     // clean the canvas
 594     CGGI_ClearCanvas(canvas, info);
 595 
 596     // strike the glyph in the upper right corner
 597     CGContextShowGlyphsAtPoint(canvas->context,
 598                                -info->topLeftX,
 599                                canvas->image->height + info->topLeftY,
 600                                &glyph, 1);
 601 
 602     // copy the glyph from the canvas into the info
 603     (*mode->glyphDescriptor->copyFxnPtr)(canvas, info);
 604 }
 605 
 606 /*
 607  * CoreText path...
 608  */
 609 static inline GlyphInfo *
 610 CGGI_CreateImageForUnicode
 611     (CGGI_GlyphCanvas *canvas, const AWTStrike *strike,
 612      const CGGI_RenderingMode *mode, const UniChar uniChar)
 613 {
 614     // save the state of the world
 615     CGContextSaveGState(canvas->context);
 616 
 617     // get the glyph, measure it using CG
 618     CGGlyph glyph;
 619     CTFontRef fallback;
 620     if (uniChar > 0xFFFF) {
 621         UTF16Char charRef[2];
 622         CTS_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
 623         CGGlyph glyphTmp[2];
 624         fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
 625         glyph = glyphTmp[0];
 626     } else {
 627         UTF16Char charRef;
 628         charRef = (UTF16Char) uniChar; // truncate.
 629         fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, &glyph, 1);
 630     }
 631 
 632     CGAffineTransform tx = strike->fTx;
 633     JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
 634 
 635     CGRect bbox;
 636     JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, style, &glyph, 1, &bbox);
 637 
 638     CGSize advance;
 639     CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
 640 
 641     // create the Sun2D GlyphInfo we are going to strike into
 642     GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
 643 
 644     // fix the context size, just in case the substituted character is unexpectedly large
 645     CGGI_SizeCanvas(canvas, info->width, info->height, mode);
 646 
 647     // align the transform for the real CoreText strike
 648     CGContextSetTextMatrix(canvas->context, strike->fAltTx);
 649 
 650     const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
 651     CGContextSetFont(canvas->context, cgFallback);
 652     CFRelease(cgFallback);
 653 
 654     // clean the canvas - align, strike, and copy the glyph from the canvas into the info
 655     CGGI_CreateImageForGlyph(canvas, glyph, info, mode);
 656 
 657     // restore the state of the world
 658     CGContextRestoreGState(canvas->context);
 659 
 660     CFRelease(fallback);
 661 #ifdef CGGI_DEBUG
 662     DUMP_GLYPHINFO(info);
 663 #endif
 664 
 665 #ifdef CGGI_DEBUG_DUMP
 666     DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
 667 #if 0
 668     PRINT_CGSTATES_INFO(NULL);
 669 #endif
 670 #endif
 671 
 672     return info;
 673 }
 674 
 675 
 676 #pragma mark --- GlyphInfo Filling and Canvas Managment ---
 677 
 678 /*
 679  * Sets all the per-run properties for the canvas, and then iterates through
 680  * the character run, and creates images in the GlyphInfo structs.
 681  *
 682  * Not inlined because it would create two copies in the function below
 683  */
 684 static void
 685 CGGI_FillImagesForGlyphsWithSizedCanvas(CGGI_GlyphCanvas *canvas,
 686                                         const AWTStrike *strike,
 687                                         const CGGI_RenderingMode *mode,
 688                                         jlong glyphInfos[],
 689                                         const UniChar uniChars[],
 690                                         const CGGlyph glyphs[],
 691                                         const CFIndex len)
 692 {
 693     CGContextSetTextMatrix(canvas->context, strike->fAltTx);
 694 
 695     CGContextSetFont(canvas->context, strike->fAWTFont->fNativeCGFont);
 696     JRSFontSetRenderingStyleOnContext(canvas->context, strike->fStyle);
 697 
 698     CFIndex i;
 699     for (i = 0; i < len; i++) {
 700         GlyphInfo *info = (GlyphInfo *)jlong_to_ptr(glyphInfos[i]);
 701         if (info != NULL) {
 702             CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mode);
 703         } else {
 704             info = CGGI_CreateImageForUnicode(canvas, strike, mode, uniChars[i]);
 705             glyphInfos[i] = ptr_to_jlong(info);
 706         }
 707 #ifdef CGGI_DEBUG
 708         DUMP_GLYPHINFO(info);
 709 #endif
 710 
 711 #ifdef CGGI_DEBUG_DUMP
 712         DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
 713 #endif
 714     }
 715 #ifdef CGGI_DEBUG_DUMP
 716     DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
 717     PRINT_CGSTATES_INFO(canvas->context);
 718 #endif
 719 }
 720 
 721 static NSString *threadLocalAACanvasKey =
 722     @"Java CoreGraphics Text Renderer Cached Canvas for AA";
 723 
 724 static NSString *threadLocalLCDCanvasKey =
 725     @"Java CoreGraphics Text Renderer Cached Canvas for LCD";
 726 
 727 /*
 728  * This is the maximum length and height times the above slack squared
 729  * to determine if we go with the global canvas, or malloc one on the spot.
 730  */
 731 #define CGGI_GLYPH_CANVAS_MAX 100
 732 
 733 /*
 734  * Based on the space needed to strike the largest character in the run,
 735  * either use the global shared canvas, or make one up on the spot, strike
 736  * the glyphs, and destroy it.
 737  */
 738 static inline void
 739 CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
 740                          const CGGI_RenderingMode *mode,
 741                          const UniChar uniChars[], const CGGlyph glyphs[],
 742                          const size_t maxWidth, const size_t maxHeight,
 743                          const CFIndex len)
 744 {
 745     if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK >
 746         CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK)
 747     {
 748         CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
 749         CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode);
 750         // create black-on-white glyph image
 751         CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
 752                 mode, glyphInfos, uniChars,
 753                 glyphs, len);
 754 
 755 #ifdef CGGI_LCD_GLYPH_IN_TWO_STAGES
 756         if (mode->glyphDescriptor == &rgb) {
 757             // merge lcd glyph image with white-on-black glyph
 758             tmpCanvas->stage = WHITE_ON_BLACK_STAGE;
 759             CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
 760                                                     mode, glyphInfos, uniChars,
 761                                                     glyphs, len);
 762         }
 763 #endif
 764         CGGI_FreeCanvas(tmpCanvas);
 765 
 766         [tmpCanvas release];
 767         return;
 768     }

 769     NSMutableDictionary *threadDict =
 770         [[NSThread currentThread] threadDictionary];
 771 
 772     NSString* theKey = (mode->glyphDescriptor == &rgb) ?
 773         threadLocalLCDCanvasKey : threadLocalAACanvasKey;
 774     
 775     CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey];
 776     if (canvas == nil) {
 777         canvas = [[CGGI_GlyphCanvas alloc] init];
 778         [threadDict setObject:canvas forKey:theKey];
 779     }
 780 
 781     CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode);
 782     // create black-on-white glyph image
 783     canvas->stage = BLACK_ON_WHITE_STAGE;
 784     CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
 785                                             glyphInfos, uniChars, glyphs, len);
 786 
 787 #ifdef CGGI_LCD_GLYPH_IN_TWO_STAGES
 788     if (mode->glyphDescriptor == &rgb) {
 789         // merge lcd glyph image with white-on-black glyph
 790         canvas->stage = WHITE_ON_BLACK_STAGE;
 791         CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
 792                                                 glyphInfos, uniChars, glyphs, len);
 793     }
 794 #endif
 795 
 796 }
 797 
 798 /*
 799  * Finds the advances and bounding boxes of the characters in the run,
 800  * cycles through all the bounds and calculates the maximum canvas space
 801  * required by the largest glyph.
 802  *
 803  * Creates a GlyphInfo struct with a malloc that also encapsulates the
 804  * image the struct points to.  This is done to meet memory layout
 805  * expectations in the Sun text rasterizer memory managment code.
 806  * The image immediately follows the struct physically in memory.
 807  */
 808 static inline void
 809 CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
 810                       const CGGI_RenderingMode *mode,
 811                       const UniChar uniChars[], const CGGlyph glyphs[],
 812                       CGSize advances[], CGRect bboxes[], const CFIndex len)
 813 {
 814     AWTFont *font = strike->fAWTFont;
 815     CGAffineTransform tx = strike->fTx;
 816     JRSFontRenderingStyle bboxCGMode = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
 817 
 818     JRSFontGetBoundingBoxesForGlyphsAndStyle((CTFontRef)font->fFont, &tx, bboxCGMode, glyphs, len, bboxes);
 819     CTFontGetAdvancesForGlyphs((CTFontRef)font->fFont, kCTFontDefaultOrientation, glyphs, advances, len);
 820 
 821     size_t maxWidth = 1;
 822     size_t maxHeight = 1;
 823 
 824     CFIndex i;
 825     for (i = 0; i < len; i++)
 826     {
 827         if (uniChars[i] != 0)
 828         {
 829             glyphInfos[i] = 0L;
 830             continue; // will be handled later
 831         }
 832 
 833         CGSize advance = advances[i];
 834         CGRect bbox = bboxes[i];
 835 
 836         GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
 837 
 838         if (maxWidth < glyphInfo->width)   maxWidth = glyphInfo->width;
 839         if (maxHeight < glyphInfo->height) maxHeight = glyphInfo->height;
 840 
 841         glyphInfos[i] = ptr_to_jlong(glyphInfo);
 842     }
 843 
 844     CGGI_FillImagesForGlyphs(glyphInfos, strike, mode, uniChars,
 845                              glyphs, maxWidth, maxHeight, len);
 846 }
 847 
 848 
 849 #pragma mark --- Temporary Buffer Allocations and Initialization ---
 850 
 851 /*
 852  * This stage separates the already valid glyph codes from the unicode values
 853  * that need special handling - the rawGlyphCodes array is no longer used
 854  * after this stage.
 855  */
 856 static void
 857 CGGI_CreateGlyphsAndScanForComplexities(jlong *glyphInfos,
 858                                         const AWTStrike *strike,
 859                                         const CGGI_RenderingMode *mode,
 860                                         jint rawGlyphCodes[],
 861                                         UniChar uniChars[], CGGlyph glyphs[],
 862                                         CGSize advances[], CGRect bboxes[],
 863                                         const CFIndex len)
 864 {
 865     CFIndex i;
 866     for (i = 0; i < len; i++) {
 867         jint code = rawGlyphCodes[i];
 868         if (code < 0) {
 869             glyphs[i] = 0;
 870             uniChars[i] = -code;
 871         } else {
 872             glyphs[i] = code;
 873             uniChars[i] = 0;
 874         }
 875     }
 876 
 877     CGGI_CreateGlyphInfos(glyphInfos, strike, mode,
 878                           uniChars, glyphs, advances, bboxes, len);
 879 
 880 #ifdef CGGI_DEBUG_HIT_COUNT
 881     static size_t hitCount = 0;
 882     hitCount++;
 883     printf("%d\n", (int)hitCount);
 884 #endif
 885 }
 886 
 887 /*
 888  * Conditionally stack allocates buffers for glyphs, bounding boxes,
 889  * and advances.  Unfortunately to use CG or CT in bulk runs (which is
 890  * faster than calling them per character), we have to copy into and out
 891  * of these buffers. Still a net win though.
 892  */
 893 void
 894 CGGlyphImages_GetGlyphImagePtrs(jlong glyphInfos[],
 895                                 const AWTStrike *strike,
 896                                 jint rawGlyphCodes[], const CFIndex len)
 897 {
 898     const CGGI_RenderingMode mode = CGGI_GetRenderingMode(strike);
 899 
 900     if (len < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) {
 901         CGRect bboxes[len];
 902         CGSize advances[len];
 903         CGGlyph glyphs[len];
 904         UniChar uniChars[len];
 905 
 906         CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
 907                                                 rawGlyphCodes, uniChars, glyphs,
 908                                                 advances, bboxes, len);
 909 
 910         return;
 911     }
 912 
 913     // just do one malloc, and carve it up for all the buffers
 914     void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
 915                           sizeof(CGGlyph) * sizeof(UniChar) * len);
 916     if (buffer == NULL) {
 917         [[NSException exceptionWithName:NSMallocException
 918             reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
 919     }
 920 
 921     CGRect *bboxes = (CGRect *)(buffer);
 922     CGSize *advances = (CGSize *)(bboxes + sizeof(CGRect) * len);
 923     CGGlyph *glyphs = (CGGlyph *)(advances + sizeof(CGGlyph) * len);
 924     UniChar *uniChars = (UniChar *)(glyphs + sizeof(UniChar) * len);
 925 
 926     CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
 927                                             rawGlyphCodes, uniChars, glyphs,
 928                                             advances, bboxes, len);
 929 
 930     free(buffer);
 931 }
--- EOF ---