Skip to content

Commit 10a28c0

Browse files
Ilarion NakonechnyyRealCLanger
authored andcommitted
8348989: Better Glyph drawing
Reviewed-by: avoitylov, mbalao, andrew Backport-of: 191c37a280faccfaecae033a68313ad06cdfc411
1 parent e1f1a11 commit 10a28c0

File tree

1 file changed

+66
-16
lines changed

1 file changed

+66
-16
lines changed

src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
481491
static inline void
482492
CGGI_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

Comments
 (0)