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