< prev index next >

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

Print this page




 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;


 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 {




 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 >> 16 & 0xFF);
 204     *(dst + 1) = 0xFF - (p >> 8 & 0xFF);
 205     *(dst) = 0xFF - (p & 0xFF);
 206 #else
 207     // TODO: check whether do we need big endian case
 208     *(dst) = 0xFF - (p >> 16 & 0xFF);
 209     *(dst + 1) = 0xFF - (p >> 8 & 0xFF);
 210     *(dst + 2) = 0xFF - (p & 0xFF);
 211 #endif
 212 }
 213 
 214 static void
 215 CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
 216 {
 217     UInt32 *src = (UInt32 *)canvas->image->data;
 218     size_t srcRowWidth = canvas->image->width;
 219 
 220     UInt8 *dest = (UInt8 *)info->image;
 221     size_t destRowWidth = info->width;
 222 
 223     size_t height = info->height;
 224 
 225     size_t y;
 226     for (y = 0; y < height; y++) {
 227         size_t destRow = y * destRowWidth * 3;


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

 322     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF:
 323     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON:


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


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


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


< prev index next >