< prev index next >

src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m

Print this page




 182     printf("size: (%d, %d) pixelSize: %d\n",
 183            info->width, info->height, info->rowBytes / info->width);
 184     printf("adv: (%f, %f) top: (%f, %f)\n",
 185            info->advanceX, info->advanceY, info->topLeftX, info->topLeftY);
 186 
 187 #ifdef CGGI_DEBUG_DUMP
 188     DUMP_PIXELS("Glyph Info Struct",
 189                 info->image, info->rowBytes / info->width,
 190                 info->width, info->height);
 191 #endif
 192 }
 193 
 194 #endif
 195 
 196 
 197 #pragma mark --- Font Rendering Mode Descriptors ---
 198 
 199 static inline void
 200 CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst)
 201 {
 202 #if __LITTLE_ENDIAN__
 203     *(dst + 2) = 0xFF - (p >> 24 & 0xFF);
 204     *(dst + 1) = 0xFF - (p >> 16 & 0xFF);
 205     *(dst) = 0xFF - (p >> 8 & 0xFF);
 206 #else
 207     *(dst) = 0xFF - (p >> 16 & 0xFF);
 208     *(dst + 1) = 0xFF - (p >> 8 & 0xFF);
 209     *(dst + 2) = 0xFF - (p & 0xFF);
 210 #endif
 211 }
 212 
 213 static void
 214 CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 215 {
 216     UInt32 *src = (UInt32 *)canvas->image->data;
 217     size_t srcRowWidth = canvas->image->width;
 218 
 219     UInt8 *dest = (UInt8 *)info->image;
 220     size_t destRowWidth = info->width;
 221 
 222     size_t height = info->height;
 223 
 224     size_t y;
 225     for (y = 0; y < height; y++) {
 226         size_t destRow = y * destRowWidth * 3;
 227         size_t srcRow = y * srcRowWidth;
 228 
 229         size_t x;
 230         for (x = 0; x < destRowWidth; x++) {


 299 typedef struct CGGI_GlyphInfoDescriptor {
 300     size_t pixelSize;
 301     void (*copyFxnPtr)(CGGI_GlyphCanvas *canvas, GlyphInfo *info);
 302 } CGGI_GlyphInfoDescriptor;
 303 
 304 typedef struct CGGI_RenderingMode {
 305     CGGI_GlyphInfoDescriptor *glyphDescriptor;
 306     JRSFontRenderingStyle cgFontMode;
 307 } CGGI_RenderingMode;
 308 
 309 static CGGI_GlyphInfoDescriptor grey =
 310     { 1, &CGGI_CopyImageFromCanvasToAlphaInfo };
 311 static CGGI_GlyphInfoDescriptor rgb =
 312     { 3, &CGGI_CopyImageFromCanvasToRGBInfo };
 313 
 314 static inline CGGI_RenderingMode
 315 CGGI_GetRenderingMode(const AWTStrike *strike)
 316 {
 317     CGGI_RenderingMode mode;
 318     mode.cgFontMode = strike->fStyle;

 319 
 320     switch (strike->fAAStyle) {
 321     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT:
 322     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF:
 323     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON:
 324     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP:
 325     default:
 326         mode.glyphDescriptor = &grey;
 327         break;
 328     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
 329     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HBGR:
 330     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
 331     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR:
 332         mode.glyphDescriptor = &rgb;
 333         break;








 334     }
 335 
 336     return mode;
 337 }
 338 
 339 
 340 #pragma mark --- Canvas Managment ---
 341 
 342 /*
 343  * Creates a new canvas of a fixed size, and initializes the CGContext as
 344  * an 32-bit ARGB BitmapContext with some generic RGB color space.
 345  */
 346 static inline void
 347 CGGI_InitCanvas(CGGI_GlyphCanvas *canvas,
 348                 const vImagePixelCount width, const vImagePixelCount height)

 349 {
 350     // our canvas is *always* 4-byte ARGB
 351     size_t bytesPerRow = width * sizeof(UInt32);
 352     size_t byteCount = bytesPerRow * height;
 353 
 354     canvas->image = malloc(sizeof(vImage_Buffer));
 355     canvas->image->width = width;
 356     canvas->image->height = height;
 357     canvas->image->rowBytes = bytesPerRow;
 358 
 359     canvas->image->data = (void *)calloc(byteCount, sizeof(UInt32));
 360     if (canvas->image->data == NULL) {
 361         [[NSException exceptionWithName:NSMallocException
 362             reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
 363     }
 364 





 365     CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
 366     canvas->context = CGBitmapContextCreate(canvas->image->data,
 367                                             width, height, 8, bytesPerRow,
 368                                             colorSpace,
 369                                             kCGImageAlphaPremultipliedFirst);
 370 
 371     CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
 372     CGContextSetFontSize(canvas->context, 1);
 373     CGContextSaveGState(canvas->context);
 374 
 375     CGColorSpaceRelease(colorSpace);
 376 }
 377 
 378 /*
 379  * Releases the BitmapContext and the associated memory backing it.
 380  */
 381 static inline void
 382 CGGI_FreeCanvas(CGGI_GlyphCanvas *canvas)
 383 {
 384     if (canvas->context != NULL) {
 385         CGContextRelease(canvas->context);
 386     }
 387 
 388     if (canvas->image != NULL) {
 389         if (canvas->image->data != NULL) {
 390             free(canvas->image->data);
 391         }
 392         free(canvas->image);
 393     }
 394 }
 395 
 396 /*
 397  * This is the slack space that is preallocated for the global GlyphCanvas
 398  * when it needs to be expanded. It has been set somewhat liberally to
 399  * avoid re-upsizing frequently.
 400  */
 401 #define CGGI_GLYPH_CANVAS_SLACK 2.5
 402 
 403 /*
 404  * Quick and easy inline to check if this canvas is big enough.
 405  */
 406 static inline void
 407 CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width, const vImagePixelCount height, const JRSFontRenderingStyle style)
 408 {
 409     if (canvas->image != NULL &&
 410         width  < canvas->image->width &&
 411         height < canvas->image->height)
 412     {
 413         return;
 414     }
 415 
 416     // if we don't have enough space to strike the largest glyph in the
 417     // run, resize the canvas
 418     CGGI_FreeCanvas(canvas);
 419     CGGI_InitCanvas(canvas,
 420                     width * CGGI_GLYPH_CANVAS_SLACK,
 421                     height * CGGI_GLYPH_CANVAS_SLACK);
 422     JRSFontSetRenderingStyleOnContext(canvas->context, style);

 423 }
 424 
 425 /*
 426  * Clear the canvas by blitting white only into the region of interest
 427  * (the rect which we will copy out of once the glyph is struck).
 428  */
 429 static inline void
 430 CGGI_ClearCanvas(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 431 {
 432     vImage_Buffer canvasRectToClear;
 433     canvasRectToClear.data = canvas->image->data;
 434     canvasRectToClear.height = info->height;
 435     canvasRectToClear.width = info->width;
 436     // use the row stride of the canvas, not the info
 437     canvasRectToClear.rowBytes = canvas->image->rowBytes;
 438 
 439     // clean the canvas
 440 #ifdef CGGI_DEBUG
 441     Pixel_8888 opaqueWhite = { 0xE0, 0xE0, 0xE0, 0xE0 };
 442 #else


 560         glyph = glyphTmp[0];
 561     } else {
 562         UTF16Char charRef;
 563         charRef = (UTF16Char) uniChar; // truncate.
 564         fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, &glyph, 1);
 565     }
 566 
 567     CGAffineTransform tx = strike->fTx;
 568     JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
 569 
 570     CGRect bbox;
 571     JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, style, &glyph, 1, &bbox);
 572 
 573     CGSize advance;
 574     CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
 575 
 576     // create the Sun2D GlyphInfo we are going to strike into
 577     GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
 578 
 579     // fix the context size, just in case the substituted character is unexpectedly large
 580     CGGI_SizeCanvas(canvas, info->width, info->height, mode->cgFontMode);
 581 
 582     // align the transform for the real CoreText strike
 583     CGContextSetTextMatrix(canvas->context, strike->fAltTx);
 584 
 585     const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
 586     CGContextSetFont(canvas->context, cgFallback);
 587     CFRelease(cgFallback);
 588 
 589     // clean the canvas - align, strike, and copy the glyph from the canvas into the info
 590     CGGI_CreateImageForGlyph(canvas, glyph, info, mode);
 591 
 592     // restore the state of the world
 593     CGContextRestoreGState(canvas->context);
 594 
 595     CFRelease(fallback);
 596 #ifdef CGGI_DEBUG
 597     DUMP_GLYPHINFO(info);
 598 #endif
 599 
 600 #ifdef CGGI_DEBUG_DUMP


 636         if (info != NULL) {
 637             CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mode);
 638         } else {
 639             info = CGGI_CreateImageForUnicode(canvas, strike, mode, uniChars[i]);
 640             glyphInfos[i] = ptr_to_jlong(info);
 641         }
 642 #ifdef CGGI_DEBUG
 643         DUMP_GLYPHINFO(info);
 644 #endif
 645 
 646 #ifdef CGGI_DEBUG_DUMP
 647         DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
 648 #endif
 649     }
 650 #ifdef CGGI_DEBUG_DUMP
 651     DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
 652     PRINT_CGSTATES_INFO(canvas->context);
 653 #endif
 654 }
 655 
 656 static NSString *threadLocalCanvasKey =
 657     @"Java CoreGraphics Text Renderer Cached Canvas";



 658 
 659 /*
 660  * This is the maximum length and height times the above slack squared
 661  * to determine if we go with the global canvas, or malloc one on the spot.
 662  */
 663 #define CGGI_GLYPH_CANVAS_MAX 100
 664 
 665 /*
 666  * Based on the space needed to strike the largest character in the run,
 667  * either use the global shared canvas, or make one up on the spot, strike
 668  * the glyphs, and destroy it.
 669  */
 670 static inline void
 671 CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
 672                          const CGGI_RenderingMode *mode,
 673                          const UniChar uniChars[], const CGGlyph glyphs[],
 674                          const size_t maxWidth, const size_t maxHeight,
 675                          const CFIndex len)
 676 {
 677     if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK >
 678         CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK)
 679     {
 680         CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
 681         CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight);
 682         CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
 683                                                 mode, glyphInfos, uniChars,
 684                                                 glyphs, len);
 685         CGGI_FreeCanvas(tmpCanvas);
 686 
 687         [tmpCanvas release];
 688         return;
 689     }
 690 
 691     NSMutableDictionary *threadDict =
 692         [[NSThread currentThread] threadDictionary];
 693     CGGI_GlyphCanvas *canvas = [threadDict objectForKey:threadLocalCanvasKey];









 694     if (canvas == nil) {
 695         canvas = [[CGGI_GlyphCanvas alloc] init];
 696         [threadDict setObject:canvas forKey:threadLocalCanvasKey];
 697     }
 698 
 699     CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode->cgFontMode);
 700     CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
 701                                             glyphInfos, uniChars, glyphs, len);
 702 }
 703 
 704 /*
 705  * Finds the advances and bounding boxes of the characters in the run,
 706  * cycles through all the bounds and calculates the maximum canvas space
 707  * required by the largest glyph.
 708  *
 709  * Creates a GlyphInfo struct with a malloc that also encapsulates the
 710  * image the struct points to.  This is done to meet memory layout
 711  * expectations in the Sun text rasterizer memory managment code.
 712  * The image immediately follows the struct physically in memory.
 713  */
 714 static inline void
 715 CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
 716                       const CGGI_RenderingMode *mode,
 717                       const UniChar uniChars[], const CGGlyph glyphs[],
 718                       CGSize advances[], CGRect bboxes[], const CFIndex len)
 719 {




 182     printf("size: (%d, %d) pixelSize: %d\n",
 183            info->width, info->height, info->rowBytes / info->width);
 184     printf("adv: (%f, %f) top: (%f, %f)\n",
 185            info->advanceX, info->advanceY, info->topLeftX, info->topLeftY);
 186 
 187 #ifdef CGGI_DEBUG_DUMP
 188     DUMP_PIXELS("Glyph Info Struct",
 189                 info->image, info->rowBytes / info->width,
 190                 info->width, info->height);
 191 #endif
 192 }
 193 
 194 #endif
 195 
 196 
 197 #pragma mark --- Font Rendering Mode Descriptors ---
 198 
 199 static inline void
 200 CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst)
 201 {
 202     *(dst + 0) = 0xFF - (p >> 16 & 0xFF);  // red
 203     *(dst + 1) = 0xFF - (p >>  8 & 0xFF);  // green
 204     *(dst + 2) = 0xFF - (p & 0xFF);        // blue






 205 }
 206 
 207 static void
 208 CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 209 {
 210     UInt32 *src = (UInt32 *)canvas->image->data;
 211     size_t srcRowWidth = canvas->image->width;
 212 
 213     UInt8 *dest = (UInt8 *)info->image;
 214     size_t destRowWidth = info->width;
 215 
 216     size_t height = info->height;
 217 
 218     size_t y;
 219     for (y = 0; y < height; y++) {
 220         size_t destRow = y * destRowWidth * 3;
 221         size_t srcRow = y * srcRowWidth;
 222 
 223         size_t x;
 224         for (x = 0; x < destRowWidth; x++) {


 293 typedef struct CGGI_GlyphInfoDescriptor {
 294     size_t pixelSize;
 295     void (*copyFxnPtr)(CGGI_GlyphCanvas *canvas, GlyphInfo *info);
 296 } CGGI_GlyphInfoDescriptor;
 297 
 298 typedef struct CGGI_RenderingMode {
 299     CGGI_GlyphInfoDescriptor *glyphDescriptor;
 300     JRSFontRenderingStyle cgFontMode;
 301 } CGGI_RenderingMode;
 302 
 303 static CGGI_GlyphInfoDescriptor grey =
 304     { 1, &CGGI_CopyImageFromCanvasToAlphaInfo };
 305 static CGGI_GlyphInfoDescriptor rgb =
 306     { 3, &CGGI_CopyImageFromCanvasToRGBInfo };
 307 
 308 static inline CGGI_RenderingMode
 309 CGGI_GetRenderingMode(const AWTStrike *strike)
 310 {
 311     CGGI_RenderingMode mode;
 312     mode.cgFontMode = strike->fStyle;
 313     NSException *e = nil;
 314 
 315     switch (strike->fAAStyle) {

 316     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF:
 317     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON:


 318         mode.glyphDescriptor = &grey;
 319         break;
 320     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
 321     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HBGR:
 322     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
 323     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR:
 324         mode.glyphDescriptor = &rgb;
 325         break;
 326     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP:
 327     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT:
 328     default:
 329         e = [NSException
 330                 exceptionWithName:@"IllegalArgumentException"
 331                 reason:@"Invalid hint value"
 332                 userInfo:nil];
 333         @throw e;
 334     }
 335 
 336     return mode;
 337 }
 338 
 339 
 340 #pragma mark --- Canvas Managment ---
 341 
 342 /*
 343  * Creates a new canvas of a fixed size, and initializes the CGContext as
 344  * an 32-bit ARGB BitmapContext with some generic RGB color space.
 345  */
 346 static inline void
 347 CGGI_InitCanvas(CGGI_GlyphCanvas *canvas,
 348                 const vImagePixelCount width, const vImagePixelCount height,
 349                 const CGGI_RenderingMode* mode)
 350 {
 351     // our canvas is *always* 4-byte ARGB
 352     size_t bytesPerRow = width * sizeof(UInt32);
 353     size_t byteCount = bytesPerRow * height;
 354 
 355     canvas->image = malloc(sizeof(vImage_Buffer));
 356     canvas->image->width = width;
 357     canvas->image->height = height;
 358     canvas->image->rowBytes = bytesPerRow;
 359 
 360     canvas->image->data = (void *)calloc(byteCount, sizeof(UInt32));
 361     if (canvas->image->data == NULL) {
 362         [[NSException exceptionWithName:NSMallocException
 363             reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
 364     }
 365 
 366     uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
 367     if (mode->glyphDescriptor == &rgb) {
 368         bmpInfo |= kCGBitmapByteOrder32Host;
 369     }
 370 
 371     CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
 372     canvas->context = CGBitmapContextCreate(canvas->image->data,
 373                                             width, height, 8, bytesPerRow,
 374                                             colorSpace,
 375                                             bmpInfo);
 376 
 377     CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f);
 378     CGContextSetFontSize(canvas->context, 1);
 379     CGContextSaveGState(canvas->context);
 380 
 381     CGColorSpaceRelease(colorSpace);
 382 }
 383 
 384 /*
 385  * Releases the BitmapContext and the associated memory backing it.
 386  */
 387 static inline void
 388 CGGI_FreeCanvas(CGGI_GlyphCanvas *canvas)
 389 {
 390     if (canvas->context != NULL) {
 391         CGContextRelease(canvas->context);
 392     }
 393 
 394     if (canvas->image != NULL) {
 395         if (canvas->image->data != NULL) {
 396             free(canvas->image->data);
 397         }
 398         free(canvas->image);
 399     }
 400 }
 401 
 402 /*
 403  * This is the slack space that is preallocated for the global GlyphCanvas
 404  * when it needs to be expanded. It has been set somewhat liberally to
 405  * avoid re-upsizing frequently.
 406  */
 407 #define CGGI_GLYPH_CANVAS_SLACK 2.5
 408 
 409 /*
 410  * Quick and easy inline to check if this canvas is big enough.
 411  */
 412 static inline void
 413 CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width, const vImagePixelCount height, const CGGI_RenderingMode* mode)
 414 {
 415     if (canvas->image != NULL &&
 416         width  < canvas->image->width &&
 417         height < canvas->image->height)
 418     {
 419         return;
 420     }
 421 
 422     // if we don't have enough space to strike the largest glyph in the
 423     // run, resize the canvas
 424     CGGI_FreeCanvas(canvas);
 425     CGGI_InitCanvas(canvas,
 426                     width * CGGI_GLYPH_CANVAS_SLACK,
 427                     height * CGGI_GLYPH_CANVAS_SLACK,
 428                     mode);
 429     JRSFontSetRenderingStyleOnContext(canvas->context, mode->cgFontMode);
 430 }
 431 
 432 /*
 433  * Clear the canvas by blitting white only into the region of interest
 434  * (the rect which we will copy out of once the glyph is struck).
 435  */
 436 static inline void
 437 CGGI_ClearCanvas(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 438 {
 439     vImage_Buffer canvasRectToClear;
 440     canvasRectToClear.data = canvas->image->data;
 441     canvasRectToClear.height = info->height;
 442     canvasRectToClear.width = info->width;
 443     // use the row stride of the canvas, not the info
 444     canvasRectToClear.rowBytes = canvas->image->rowBytes;
 445 
 446     // clean the canvas
 447 #ifdef CGGI_DEBUG
 448     Pixel_8888 opaqueWhite = { 0xE0, 0xE0, 0xE0, 0xE0 };
 449 #else


 567         glyph = glyphTmp[0];
 568     } else {
 569         UTF16Char charRef;
 570         charRef = (UTF16Char) uniChar; // truncate.
 571         fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, &glyph, 1);
 572     }
 573 
 574     CGAffineTransform tx = strike->fTx;
 575     JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
 576 
 577     CGRect bbox;
 578     JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, style, &glyph, 1, &bbox);
 579 
 580     CGSize advance;
 581     CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
 582 
 583     // create the Sun2D GlyphInfo we are going to strike into
 584     GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
 585 
 586     // fix the context size, just in case the substituted character is unexpectedly large
 587     CGGI_SizeCanvas(canvas, info->width, info->height, mode);
 588 
 589     // align the transform for the real CoreText strike
 590     CGContextSetTextMatrix(canvas->context, strike->fAltTx);
 591 
 592     const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
 593     CGContextSetFont(canvas->context, cgFallback);
 594     CFRelease(cgFallback);
 595 
 596     // clean the canvas - align, strike, and copy the glyph from the canvas into the info
 597     CGGI_CreateImageForGlyph(canvas, glyph, info, mode);
 598 
 599     // restore the state of the world
 600     CGContextRestoreGState(canvas->context);
 601 
 602     CFRelease(fallback);
 603 #ifdef CGGI_DEBUG
 604     DUMP_GLYPHINFO(info);
 605 #endif
 606 
 607 #ifdef CGGI_DEBUG_DUMP


 643         if (info != NULL) {
 644             CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mode);
 645         } else {
 646             info = CGGI_CreateImageForUnicode(canvas, strike, mode, uniChars[i]);
 647             glyphInfos[i] = ptr_to_jlong(info);
 648         }
 649 #ifdef CGGI_DEBUG
 650         DUMP_GLYPHINFO(info);
 651 #endif
 652 
 653 #ifdef CGGI_DEBUG_DUMP
 654         DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
 655 #endif
 656     }
 657 #ifdef CGGI_DEBUG_DUMP
 658     DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
 659     PRINT_CGSTATES_INFO(canvas->context);
 660 #endif
 661 }
 662 
 663 static NSString *threadLocalAACanvasKey =
 664     @"Java CoreGraphics Text Renderer Cached Canvas for AA";
 665 
 666 static NSString *threadLocalLCDCanvasKey =
 667         @"Java CoreGraphics Text Renderer Cached Canvas for LCD";
 668 
 669 /*
 670  * This is the maximum length and height times the above slack squared
 671  * to determine if we go with the global canvas, or malloc one on the spot.
 672  */
 673 #define CGGI_GLYPH_CANVAS_MAX 100
 674 
 675 /*
 676  * Based on the space needed to strike the largest character in the run,
 677  * either use the global shared canvas, or make one up on the spot, strike
 678  * the glyphs, and destroy it.
 679  */
 680 static inline void
 681 CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
 682                          const CGGI_RenderingMode *mode,
 683                          const UniChar uniChars[], const CGGlyph glyphs[],
 684                          const size_t maxWidth, const size_t maxHeight,
 685                          const CFIndex len)
 686 {
 687     if (maxWidth*maxHeight*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK >
 688         CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK)
 689     {
 690         CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
 691         CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode);
 692         CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
 693                                                 mode, glyphInfos, uniChars,
 694                                                 glyphs, len);
 695         CGGI_FreeCanvas(tmpCanvas);
 696 
 697         [tmpCanvas release];
 698         return;
 699     }
 700 
 701     NSMutableDictionary *threadDict =
 702         [[NSThread currentThread] threadDictionary];
 703 
 704     NSString* theKey;
 705 
 706     if (mode->glyphDescriptor == &rgb) {
 707         theKey = threadLocalLCDCanvasKey;
 708     } else {
 709         theKey = threadLocalAACanvasKey;
 710     }
 711 
 712     CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey];
 713     if (canvas == nil) {
 714         canvas = [[CGGI_GlyphCanvas alloc] init];
 715         [threadDict setObject:canvas forKey:theKey];
 716     }
 717 
 718     CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode);
 719     CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
 720                                             glyphInfos, uniChars, glyphs, len);
 721 }
 722 
 723 /*
 724  * Finds the advances and bounding boxes of the characters in the run,
 725  * cycles through all the bounds and calculates the maximum canvas space
 726  * required by the largest glyph.
 727  *
 728  * Creates a GlyphInfo struct with a malloc that also encapsulates the
 729  * image the struct points to.  This is done to meet memory layout
 730  * expectations in the Sun text rasterizer memory managment code.
 731  * The image immediately follows the struct physically in memory.
 732  */
 733 static inline void
 734 CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
 735                       const CGGI_RenderingMode *mode,
 736                       const UniChar uniChars[], const CGGlyph glyphs[],
 737                       CGSize advances[], CGRect bboxes[], const CFIndex len)
 738 {


< prev index next >