@@ -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
}
@@ -317,6 +319,7 @@ @implementation CGGI_GlyphCanvas
317
319
318
320
UInt32 *src = (UInt32 *)canvas->image ->data ;
319
321
size_t srcRowWidth = canvas->image ->width ;
322
+ size_t srcHeight = canvas->image ->height ;
320
323
321
324
UInt8 *dest = (UInt8 *)info->image ;
322
325
size_t destRowWidth = info->width ;
@@ -325,15 +328,16 @@ @implementation CGGI_GlyphCanvas
325
328
326
329
size_t y;
327
330
328
- for (y = 0 ; y < height; y++) {
331
+ for (y = 0 ; y < height && y < srcHeight ; y++) {
329
332
size_t srcRow = y * srcRowWidth;
330
333
if (littleEndian) {
331
- UInt16 destRowBytes = info->rowBytes ;
334
+ size_t srcRowBytes = canvas->image ->rowBytes ;
335
+ UInt16 destRowBytes = (info->rowBytes < srcRowBytes) ? info->rowBytes : srcRowBytes;
332
336
memcpy (dest, src + srcRow, destRowBytes);
333
337
dest += destRowBytes;
334
338
} else {
335
339
size_t x;
336
- for (x = 0 ; x < destRowWidth; x++) {
340
+ for (x = 0 ; x < destRowWidth && x < srcRowWidth ; x++) {
337
341
UInt32 p = src[srcRow + x];
338
342
*dest++ = (p >> 24 & 0xFF ); // blue (alpha-premultiplied)
339
343
*dest++ = (p >> 16 & 0xFF ); // green (alpha-premultiplied)
@@ -426,8 +430,10 @@ @implementation CGGI_GlyphCanvas
426
430
427
431
canvas->image ->data = (void *)calloc (byteCount, sizeof (UInt8));
428
432
if (canvas->image ->data == NULL ) {
429
- [[NSException exceptionWithName: NSMallocException
430
- reason: @" Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo: nil ] raise ];
433
+ canvas->image ->width = 0 ;
434
+ canvas->image ->height = 0 ;
435
+ canvas->image ->rowBytes = 0 ;
436
+ canvas->image ->data = malloc (0 );
431
437
}
432
438
433
439
uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst ;
@@ -477,25 +483,42 @@ @implementation CGGI_GlyphCanvas
477
483
478
484
/*
479
485
* Quick and easy inline to check if this canvas is big enough.
486
+ * This function only increases the size. To get a smaller canvas, free it first.
487
+ * This function adds padding / slack multiplier to the requested size.
488
+ * So resizes must be based on the size you need, not the size of the canvas.
489
+ * The function will internally account for the multiplier it uses.
480
490
*/
481
491
static inline void
482
492
CGGI_SizeCanvas (CGGI_GlyphCanvas *canvas, const vImagePixelCount width,
483
493
const vImagePixelCount height,
484
494
const CGGI_RenderingMode* mode)
485
495
{
486
496
if (canvas->image != NULL &&
487
- width < canvas->image ->width &&
488
- height < canvas->image ->height )
497
+ width * CGGI_GLYPH_CANVAS_SLACK <= canvas->image ->width &&
498
+ height * CGGI_GLYPH_CANVAS_SLACK <= canvas->image ->height )
489
499
{
490
500
return ;
491
501
}
492
502
503
+ vImagePixelCount w = width * CGGI_GLYPH_CANVAS_SLACK;
504
+ vImagePixelCount h = height * CGGI_GLYPH_CANVAS_SLACK;
505
+
506
+ // Do not allow the canvas to be resized smaller.
507
+ if (canvas->image != NULL ) {
508
+ if (w < canvas->image ->width ) {
509
+ w = canvas->image ->width ;
510
+ }
511
+ if (h < canvas->image ->height ) {
512
+ h = canvas->image ->height ;
513
+ }
514
+ }
515
+
493
516
// if we don't have enough space to strike the largest glyph in the
494
517
// run, resize the canvas
495
518
CGGI_FreeCanvas (canvas);
496
519
CGGI_InitCanvas (canvas,
497
- width * CGGI_GLYPH_CANVAS_SLACK ,
498
- height * CGGI_GLYPH_CANVAS_SLACK ,
520
+ w ,
521
+ h ,
499
522
mode);
500
523
JRSFontSetRenderingStyleOnContext (canvas->context , mode->cgFontMode );
501
524
}
@@ -511,6 +534,12 @@ @implementation CGGI_GlyphCanvas
511
534
canvasRectToClear.data = canvas->image ->data ;
512
535
canvasRectToClear.height = info->height ;
513
536
canvasRectToClear.width = info->width ;
537
+ if (canvas->image ->width < canvasRectToClear.width ) {
538
+ canvasRectToClear.width = canvas->image ->width ;
539
+ }
540
+ if (canvas->image ->height < canvasRectToClear.height ) {
541
+ canvasRectToClear.height = canvas->image ->height ;
542
+ }
514
543
// use the row stride of the canvas, not the info
515
544
canvasRectToClear.rowBytes = canvas->image ->rowBytes ;
516
545
@@ -870,7 +899,6 @@ @implementation CGGI_GlyphCanvas
870
899
CGRect bbox = bboxes[i];
871
900
872
901
GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom (advance, bbox, strike, mainFontDescriptor);
873
-
874
902
if (maxWidth < glyphInfo->width ) maxWidth = glyphInfo->width ;
875
903
if (maxHeight < glyphInfo->height ) maxHeight = glyphInfo->height ;
876
904
@@ -947,8 +975,7 @@ @implementation CGGI_GlyphCanvas
947
975
}
948
976
949
977
// just do one malloc, and carve it up for all the buffers
950
- void *buffer = malloc (sizeof (CGRect) * sizeof (CGSize) *
951
- sizeof (CGGlyph) * sizeof (UnicodeScalarValue) * len);
978
+ void *buffer = malloc ((sizeof (CGRect) + sizeof (CGSize) + sizeof (CGGlyph) + sizeof (UnicodeScalarValue)) * len);
952
979
if (buffer == NULL ) {
953
980
[[NSException exceptionWithName: NSMallocException
954
981
reason: @" Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo: nil ] raise ];
@@ -966,6 +993,8 @@ @implementation CGGI_GlyphCanvas
966
993
free (buffer);
967
994
}
968
995
996
+ #define TX_FIXED_UNSAFE (v ) (isinf(v) || isnan(v) || fabs(v) >= (1 <<30 ))
997
+
969
998
/*
970
999
* Calculates bounding boxes (for given transform) and advance (for untransformed 1pt-size font) for specified glyphs.
971
1000
*/
@@ -977,6 +1006,27 @@ @implementation CGGI_GlyphCanvas
977
1006
size_t count,
978
1007
CGRect bboxes[],
979
1008
CGSize advances[]) {
1009
+
1010
+ if (TX_FIXED_UNSAFE (tx->a ) || TX_FIXED_UNSAFE (tx->b ) || TX_FIXED_UNSAFE (tx->c ) ||
1011
+ TX_FIXED_UNSAFE (tx->d ) || TX_FIXED_UNSAFE (tx->tx ) || TX_FIXED_UNSAFE (tx->tx )) {
1012
+
1013
+ if (bboxes) {
1014
+ for (int i = 0 ; i < count; i++) {
1015
+ bboxes[i].origin .x = 0 ;
1016
+ bboxes[i].origin .y = 0 ;
1017
+ bboxes[i].size .width = 0 ;
1018
+ bboxes[i].size .height = 0 ;
1019
+ }
1020
+ }
1021
+ if (advances) {
1022
+ for (int i = 0 ; i < count; i++) {
1023
+ advances[i].width = 0 ;
1024
+ advances[i].height = 0 ;
1025
+ }
1026
+ }
1027
+ return ;
1028
+ }
1029
+
980
1030
if (IsEmojiFont (font)) {
981
1031
// Glyph metrics for emoji font are not strictly proportional to font size,
982
1032
// so we need to construct real-sized font object to calculate them.
0 commit comments