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 {
|