Skip to content

Commit 25101ec

Browse files
Larry-NAlexey Bakhtin
authored andcommitted
8348989: Better Glyph drawing
Co-authored-by: Alexey Bakhtin <[email protected]> Reviewed-by: avoitylov, mbalao, andrew Backport-of: 191c37a280faccfaecae033a68313ad06cdfc411
1 parent 233cbfa commit 25101ec

File tree

3 files changed

+93
-21
lines changed

3 files changed

+93
-21
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ + (AWTStrike *) awtStrikeForFont:(AWTFont *)awtFont
151151
// to indicate we should use CoreText to substitute the character
152152
CGGlyph glyph;
153153
const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
154-
CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
154+
CGGlyphImages_GetGlyphMetrics(fallback, &awtStrike->fAltTx, awtStrike->fStyle, &glyph, 1, NULL, &advance);
155155
CFRelease(fallback);
156156
advance = CGSizeApplyAffineTransform(advance, awtStrike->fFontTx);
157157
if (!JRSFontStyleUsesFractionalMetrics(awtStrike->fStyle)) {
@@ -188,7 +188,7 @@ + (AWTStrike *) awtStrikeForFont:(AWTFont *)awtFont
188188
const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
189189

190190
CGRect bbox;
191-
JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, awtStrike->fStyle, &glyph, 1, &bbox);
191+
CGGlyphImages_GetGlyphMetrics(fallback, &tx, awtStrike->fStyle, &glyph, 1, &bbox, NULL);
192192
CFRelease(fallback);
193193

194194
// the origin of this bounding box is relative to the bottom-left corner baseline

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,12 @@ void
3333
CGGlyphImages_GetGlyphImagePtrs(jlong glyphInfos[],
3434
const AWTStrike *strike,
3535
jint rawGlyphCodes[], const CFIndex len);
36-
36+
void
37+
CGGlyphImages_GetGlyphMetrics(const CTFontRef font,
38+
const CGAffineTransform *tx,
39+
const JRSFontRenderingStyle style,
40+
const CGGlyph glyphs[],
41+
size_t count,
42+
CGRect bboxes[],
43+
CGSize advances[]);
3744
#endif /* __CGGLYPHIMAGES_H */

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

Lines changed: 83 additions & 18 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
}
@@ -384,8 +386,10 @@ @implementation CGGI_GlyphCanvas
384386

385387
canvas->image->data = (void *)calloc(byteCount, sizeof(UInt8));
386388
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);
389393
}
390394

391395
uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
@@ -435,25 +439,42 @@ @implementation CGGI_GlyphCanvas
435439

436440
/*
437441
* 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.
438446
*/
439447
static inline void
440448
CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width,
441449
const vImagePixelCount height,
442450
const CGGI_RenderingMode* mode)
443451
{
444452
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)
447455
{
448456
return;
449457
}
450458

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+
451472
// if we don't have enough space to strike the largest glyph in the
452473
// run, resize the canvas
453474
CGGI_FreeCanvas(canvas);
454475
CGGI_InitCanvas(canvas,
455-
width * CGGI_GLYPH_CANVAS_SLACK,
456-
height * CGGI_GLYPH_CANVAS_SLACK,
476+
w,
477+
h,
457478
mode);
458479
JRSFontSetRenderingStyleOnContext(canvas->context, mode->cgFontMode);
459480
}
@@ -469,6 +490,12 @@ @implementation CGGI_GlyphCanvas
469490
canvasRectToClear.data = canvas->image->data;
470491
canvasRectToClear.height = info->height;
471492
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+
}
472499
// use the row stride of the canvas, not the info
473500
canvasRectToClear.rowBytes = canvas->image->rowBytes;
474501

@@ -615,10 +642,8 @@ @implementation CGGI_GlyphCanvas
615642
JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
616643

617644
CGRect bbox;
618-
JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, style, &glyph, 1, &bbox);
619-
620645
CGSize advance;
621-
CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
646+
CGGlyphImages_GetGlyphMetrics(fallback, &tx, style, &glyph, 1, &bbox, &advance);
622647

623648
// create the Sun2D GlyphInfo we are going to strike into
624649
GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
@@ -774,8 +799,8 @@ @implementation CGGI_GlyphCanvas
774799
CGAffineTransform tx = strike->fTx;
775800
JRSFontRenderingStyle bboxCGMode = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
776801

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);
779804

780805
size_t maxWidth = 1;
781806
size_t maxHeight = 1;
@@ -793,7 +818,6 @@ @implementation CGGI_GlyphCanvas
793818
CGRect bbox = bboxes[i];
794819

795820
GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
796-
797821
if (maxWidth < glyphInfo->width) maxWidth = glyphInfo->width;
798822
if (maxHeight < glyphInfo->height) maxHeight = glyphInfo->height;
799823

@@ -870,8 +894,7 @@ @implementation CGGI_GlyphCanvas
870894
}
871895

872896
// 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);
875898
if (buffer == NULL) {
876899
[[NSException exceptionWithName:NSMallocException
877900
reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
@@ -888,3 +911,45 @@ @implementation CGGI_GlyphCanvas
888911

889912
free(buffer);
890913
}
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

Comments
 (0)