@@ -237,6 +237,7 @@ @implementation CGGI_GlyphCanvas
237
237
{
238
238
UInt32 *src = (UInt32 *)canvas->image ->data ;
239
239
size_t srcRowWidth = canvas->image ->width ;
240
+ size_t srcHeight = canvas->image ->height ;
240
241
241
242
UInt8 *dest = (UInt8 *)info->image ;
242
243
size_t destRowWidth = info->width ;
@@ -246,12 +247,12 @@ @implementation CGGI_GlyphCanvas
246
247
size_t y;
247
248
248
249
// fill empty glyph image with black-on-white glyph
249
- for (y = 0 ; y < height; y++) {
250
+ for (y = 0 ; y < height && y < srcHeight ; y++) {
250
251
size_t destRow = y * destRowWidth * 3 ;
251
252
size_t srcRow = y * srcRowWidth;
252
253
253
254
size_t x;
254
- for (x = 0 ; x < destRowWidth; x++) {
255
+ for (x = 0 ; x < destRowWidth && x < srcRowWidth ; x++) {
255
256
CGGI_CopyARGBPixelToRGBPixel (src[srcRow + x],
256
257
dest + destRow + x * 3 );
257
258
}
@@ -289,6 +290,7 @@ @implementation CGGI_GlyphCanvas
289
290
{
290
291
UInt32 *src = (UInt32 *)canvas->image ->data ;
291
292
size_t srcRowWidth = canvas->image ->width ;
293
+ size_t srcHeight = canvas->image ->height ;
292
294
293
295
UInt8 *dest = (UInt8 *)info->image ;
294
296
size_t destRowWidth = info->width ;
@@ -298,11 +300,11 @@ @implementation CGGI_GlyphCanvas
298
300
size_t y;
299
301
300
302
// fill empty glyph image with black-on-white glyph
301
- for (y = 0 ; y < height; y++) {
303
+ for (y = 0 ; y < height && y < srcHeight ; y++) {
302
304
size_t destRow = y * destRowWidth;
303
305
size_t srcRow = y * srcRowWidth;
304
306
size_t x;
305
- for (x = 0 ; x < destRowWidth; x++) {
307
+ for (x = 0 ; x < destRowWidth && x < srcRowWidth ; x++) {
306
308
UInt32 p = src[srcRow + x];
307
309
dest[destRow + x] = CGGI_ConvertBWPixelToByteGray (p);
308
310
}
@@ -384,8 +386,10 @@ @implementation CGGI_GlyphCanvas
384
386
385
387
canvas->image ->data = (void *)calloc (byteCount, sizeof (UInt8));
386
388
if (canvas->image ->data == NULL ) {
387
- [[NSException exceptionWithName: NSMallocException
388
- reason: @" Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo: nil ] raise ];
389
+ canvas->image ->width = 0 ;
390
+ canvas->image ->height = 0 ;
391
+ canvas->image ->rowBytes = 0 ;
392
+ canvas->image ->data = malloc (0 );
389
393
}
390
394
391
395
uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst ;
@@ -435,25 +439,42 @@ @implementation CGGI_GlyphCanvas
435
439
436
440
/*
437
441
* Quick and easy inline to check if this canvas is big enough.
442
+ * This function only increases the size. To get a smaller canvas, free it first.
443
+ * This function adds padding / slack multiplier to the requested size.
444
+ * So resizes must be based on the size you need, not the size of the canvas.
445
+ * The function will internally account for the multiplier it uses.
438
446
*/
439
447
static inline void
440
448
CGGI_SizeCanvas (CGGI_GlyphCanvas *canvas, const vImagePixelCount width,
441
449
const vImagePixelCount height,
442
450
const CGGI_RenderingMode* mode)
443
451
{
444
452
if (canvas->image != NULL &&
445
- width < canvas->image ->width &&
446
- height < canvas->image ->height )
453
+ width * CGGI_GLYPH_CANVAS_SLACK <= canvas->image ->width &&
454
+ height * CGGI_GLYPH_CANVAS_SLACK <= canvas->image ->height )
447
455
{
448
456
return ;
449
457
}
450
458
459
+ vImagePixelCount w = width * CGGI_GLYPH_CANVAS_SLACK;
460
+ vImagePixelCount h = height * CGGI_GLYPH_CANVAS_SLACK;
461
+
462
+ // Do not allow the canvas to be resized smaller.
463
+ if (canvas->image != NULL ) {
464
+ if (w < canvas->image ->width ) {
465
+ w = canvas->image ->width ;
466
+ }
467
+ if (h < canvas->image ->height ) {
468
+ h = canvas->image ->height ;
469
+ }
470
+ }
471
+
451
472
// if we don't have enough space to strike the largest glyph in the
452
473
// run, resize the canvas
453
474
CGGI_FreeCanvas (canvas);
454
475
CGGI_InitCanvas (canvas,
455
- width * CGGI_GLYPH_CANVAS_SLACK ,
456
- height * CGGI_GLYPH_CANVAS_SLACK ,
476
+ w ,
477
+ h ,
457
478
mode);
458
479
JRSFontSetRenderingStyleOnContext (canvas->context , mode->cgFontMode );
459
480
}
@@ -469,6 +490,12 @@ @implementation CGGI_GlyphCanvas
469
490
canvasRectToClear.data = canvas->image ->data ;
470
491
canvasRectToClear.height = info->height ;
471
492
canvasRectToClear.width = info->width ;
493
+ if (canvas->image ->width < canvasRectToClear.width ) {
494
+ canvasRectToClear.width = canvas->image ->width ;
495
+ }
496
+ if (canvas->image ->height < canvasRectToClear.height ) {
497
+ canvasRectToClear.height = canvas->image ->height ;
498
+ }
472
499
// use the row stride of the canvas, not the info
473
500
canvasRectToClear.rowBytes = canvas->image ->rowBytes ;
474
501
@@ -615,10 +642,8 @@ @implementation CGGI_GlyphCanvas
615
642
JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement (strike->fStyle );
616
643
617
644
CGRect bbox;
618
- JRSFontGetBoundingBoxesForGlyphsAndStyle (fallback, &tx, style, &glyph, 1 , &bbox);
619
-
620
645
CGSize advance;
621
- CTFontGetAdvancesForGlyphs (fallback, kCTFontDefaultOrientation , &glyph, &advance, 1 );
646
+ CGGlyphImages_GetGlyphMetrics (fallback, &tx, style, &glyph, 1 , &bbox, &advance );
622
647
623
648
// create the Sun2D GlyphInfo we are going to strike into
624
649
GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom (advance, bbox, strike, mode);
@@ -774,8 +799,8 @@ @implementation CGGI_GlyphCanvas
774
799
CGAffineTransform tx = strike->fTx ;
775
800
JRSFontRenderingStyle bboxCGMode = JRSFontAlignStyleForFractionalMeasurement (strike->fStyle );
776
801
777
- JRSFontGetBoundingBoxesForGlyphsAndStyle (( CTFontRef)font->fFont , &tx, bboxCGMode, glyphs, len, bboxes) ;
778
- CTFontGetAdvancesForGlyphs ((CTFontRef)font-> fFont , kCTFontDefaultOrientation , glyphs, advances , len);
802
+ CTFontRef fontRef = ( CTFontRef)font->fFont ;
803
+ CGGlyphImages_GetGlyphMetrics (fontRef, &tx, bboxCGMode, glyphs , len, bboxes, advances );
779
804
780
805
size_t maxWidth = 1 ;
781
806
size_t maxHeight = 1 ;
@@ -793,7 +818,6 @@ @implementation CGGI_GlyphCanvas
793
818
CGRect bbox = bboxes[i];
794
819
795
820
GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom (advance, bbox, strike, mode);
796
-
797
821
if (maxWidth < glyphInfo->width ) maxWidth = glyphInfo->width ;
798
822
if (maxHeight < glyphInfo->height ) maxHeight = glyphInfo->height ;
799
823
@@ -870,8 +894,7 @@ @implementation CGGI_GlyphCanvas
870
894
}
871
895
872
896
// just do one malloc, and carve it up for all the buffers
873
- void *buffer = malloc (sizeof (CGRect) * sizeof (CGSize) *
874
- sizeof (CGGlyph) * sizeof (UnicodeScalarValue) * len);
897
+ void *buffer = malloc ((sizeof (CGRect) + sizeof (CGSize) + sizeof (CGGlyph) + sizeof (UnicodeScalarValue)) * len);
875
898
if (buffer == NULL ) {
876
899
[[NSException exceptionWithName: NSMallocException
877
900
reason: @" Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo: nil ] raise ];
@@ -888,3 +911,45 @@ @implementation CGGI_GlyphCanvas
888
911
889
912
free (buffer);
890
913
}
914
+
915
+ #define TX_FIXED_UNSAFE (v ) (isinf(v) || isnan(v) || fabs(v) >= (1 <<30 ))
916
+
917
+ /*
918
+ * Calculates bounding boxes (for given transform) and advance (for untransformed 1pt-size font) for specified glyphs.
919
+ */
920
+ void
921
+ CGGlyphImages_GetGlyphMetrics (const CTFontRef font,
922
+ const CGAffineTransform *tx,
923
+ const JRSFontRenderingStyle style,
924
+ const CGGlyph glyphs[],
925
+ size_t count,
926
+ CGRect bboxes[],
927
+ CGSize advances[]) {
928
+
929
+ if (TX_FIXED_UNSAFE (tx->a ) || TX_FIXED_UNSAFE (tx->b ) || TX_FIXED_UNSAFE (tx->c ) ||
930
+ TX_FIXED_UNSAFE (tx->d ) || TX_FIXED_UNSAFE (tx->tx ) || TX_FIXED_UNSAFE (tx->tx )) {
931
+
932
+ if (bboxes) {
933
+ for (int i = 0 ; i < count; i++) {
934
+ bboxes[i].origin .x = 0 ;
935
+ bboxes[i].origin .y = 0 ;
936
+ bboxes[i].size .width = 0 ;
937
+ bboxes[i].size .height = 0 ;
938
+ }
939
+ }
940
+ if (advances) {
941
+ for (int i = 0 ; i < count; i++) {
942
+ advances[i].width = 0 ;
943
+ advances[i].height = 0 ;
944
+ }
945
+ }
946
+ return ;
947
+ }
948
+
949
+ if (bboxes) {
950
+ JRSFontGetBoundingBoxesForGlyphsAndStyle (font, tx, style, glyphs, count, bboxes);
951
+ }
952
+ if (advances) {
953
+ CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation , glyphs, advances, count);
954
+ }
955
+ }
0 commit comments