@@ -237,6 +237,7 @@ @implementation CGGI_GlyphCanvas
237237{
238238 UInt32 *src = (UInt32 *)canvas->image ->data ;
239239 size_t srcRowWidth = canvas->image ->width ;
240+ size_t srcHeight = canvas->image ->height ;
240241
241242 UInt8 *dest = (UInt8 *)info->image ;
242243 size_t destRowWidth = info->width ;
@@ -246,12 +247,12 @@ @implementation CGGI_GlyphCanvas
246247 size_t y;
247248
248249 // 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++) {
250251 size_t destRow = y * destRowWidth * 3 ;
251252 size_t srcRow = y * srcRowWidth;
252253
253254 size_t x;
254- for (x = 0 ; x < destRowWidth; x++) {
255+ for (x = 0 ; x < destRowWidth && x < srcRowWidth ; x++) {
255256 CGGI_CopyARGBPixelToRGBPixel (src[srcRow + x],
256257 dest + destRow + x * 3 );
257258 }
@@ -289,6 +290,7 @@ @implementation CGGI_GlyphCanvas
289290{
290291 UInt32 *src = (UInt32 *)canvas->image ->data ;
291292 size_t srcRowWidth = canvas->image ->width ;
293+ size_t srcHeight = canvas->image ->height ;
292294
293295 UInt8 *dest = (UInt8 *)info->image ;
294296 size_t destRowWidth = info->width ;
@@ -298,11 +300,11 @@ @implementation CGGI_GlyphCanvas
298300 size_t y;
299301
300302 // 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++) {
302304 size_t destRow = y * destRowWidth;
303305 size_t srcRow = y * srcRowWidth;
304306 size_t x;
305- for (x = 0 ; x < destRowWidth; x++) {
307+ for (x = 0 ; x < destRowWidth && x < srcRowWidth ; x++) {
306308 UInt32 p = src[srcRow + x];
307309 dest[destRow + x] = CGGI_ConvertBWPixelToByteGray (p);
308310 }
@@ -317,6 +319,7 @@ @implementation CGGI_GlyphCanvas
317319
318320 UInt32 *src = (UInt32 *)canvas->image ->data ;
319321 size_t srcRowWidth = canvas->image ->width ;
322+ size_t srcHeight = canvas->image ->height ;
320323
321324 UInt8 *dest = (UInt8 *)info->image ;
322325 size_t destRowWidth = info->width ;
@@ -325,15 +328,16 @@ @implementation CGGI_GlyphCanvas
325328
326329 size_t y;
327330
328- for (y = 0 ; y < height; y++) {
331+ for (y = 0 ; y < height && y < srcHeight ; y++) {
329332 size_t srcRow = y * srcRowWidth;
330333 if (littleEndian) {
331- UInt16 destRowBytes = info->rowBytes ;
334+ size_t srcRowBytes = canvas->image ->rowBytes ;
335+ UInt16 destRowBytes = (info->rowBytes < srcRowBytes) ? info->rowBytes : srcRowBytes;
332336 memcpy (dest, src + srcRow, destRowBytes);
333337 dest += destRowBytes;
334338 } else {
335339 size_t x;
336- for (x = 0 ; x < destRowWidth; x++) {
340+ for (x = 0 ; x < destRowWidth && x < srcRowWidth ; x++) {
337341 UInt32 p = src[srcRow + x];
338342 *dest++ = (p >> 24 & 0xFF ); // blue (alpha-premultiplied)
339343 *dest++ = (p >> 16 & 0xFF ); // green (alpha-premultiplied)
@@ -426,8 +430,10 @@ @implementation CGGI_GlyphCanvas
426430
427431 canvas->image ->data = (void *)calloc (byteCount, sizeof (UInt8));
428432 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 );
431437 }
432438
433439 uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst ;
@@ -477,25 +483,42 @@ @implementation CGGI_GlyphCanvas
477483
478484/*
479485 * 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.
480490 */
481491static inline void
482492CGGI_SizeCanvas (CGGI_GlyphCanvas *canvas, const vImagePixelCount width,
483493 const vImagePixelCount height,
484494 const CGGI_RenderingMode* mode)
485495{
486496 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 )
489499 {
490500 return ;
491501 }
492502
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+
493516 // if we don't have enough space to strike the largest glyph in the
494517 // run, resize the canvas
495518 CGGI_FreeCanvas (canvas);
496519 CGGI_InitCanvas (canvas,
497- width * CGGI_GLYPH_CANVAS_SLACK ,
498- height * CGGI_GLYPH_CANVAS_SLACK ,
520+ w ,
521+ h ,
499522 mode);
500523 JRSFontSetRenderingStyleOnContext (canvas->context , mode->cgFontMode );
501524}
@@ -511,6 +534,12 @@ @implementation CGGI_GlyphCanvas
511534 canvasRectToClear.data = canvas->image ->data ;
512535 canvasRectToClear.height = info->height ;
513536 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+ }
514543 // use the row stride of the canvas, not the info
515544 canvasRectToClear.rowBytes = canvas->image ->rowBytes ;
516545
@@ -870,7 +899,6 @@ @implementation CGGI_GlyphCanvas
870899 CGRect bbox = bboxes[i];
871900
872901 GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom (advance, bbox, strike, mainFontDescriptor);
873-
874902 if (maxWidth < glyphInfo->width ) maxWidth = glyphInfo->width ;
875903 if (maxHeight < glyphInfo->height ) maxHeight = glyphInfo->height ;
876904
@@ -947,8 +975,7 @@ @implementation CGGI_GlyphCanvas
947975 }
948976
949977 // 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);
952979 if (buffer == NULL ) {
953980 [[NSException exceptionWithName: NSMallocException
954981 reason: @" Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo: nil ] raise ];
@@ -966,6 +993,8 @@ @implementation CGGI_GlyphCanvas
966993 free (buffer);
967994}
968995
996+ #define TX_FIXED_UNSAFE (v ) (isinf(v) || isnan(v) || fabs(v) >= (1 <<30 ))
997+
969998/*
970999 * Calculates bounding boxes (for given transform) and advance (for untransformed 1pt-size font) for specified glyphs.
9711000 */
@@ -977,6 +1006,27 @@ @implementation CGGI_GlyphCanvas
9771006 size_t count,
9781007 CGRect bboxes[],
9791008 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+
9801030 if (IsEmojiFont (font)) {
9811031 // Glyph metrics for emoji font are not strictly proportional to font size,
9821032 // so we need to construct real-sized font object to calculate them.
0 commit comments