mirror of
https://github.com/openjdk/jdk8u.git
synced 2025-12-10 00:09:35 -06:00
8348989: Better Glyph drawing
Co-authored-by: Alexey Bakhtin <abakhtin@openjdk.org> Reviewed-by: avoitylov, mbalao, andrew Backport-of: 191c37a280faccfaecae033a68313ad06cdfc411
This commit is contained in:
parent
181b252c79
commit
33624e872e
@ -156,7 +156,7 @@ JNF_COCOA_ENTER(env);
|
||||
// to indicate we should use CoreText to substitute the character
|
||||
CGGlyph glyph;
|
||||
const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
|
||||
CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
|
||||
CGGlyphImages_GetGlyphMetrics(fallback, &awtStrike->fAltTx, awtStrike->fStyle, &glyph, 1, NULL, &advance);
|
||||
CFRelease(fallback);
|
||||
advance = CGSizeApplyAffineTransform(advance, awtStrike->fFontTx);
|
||||
if (!JRSFontStyleUsesFractionalMetrics(awtStrike->fStyle)) {
|
||||
@ -193,7 +193,7 @@ JNF_COCOA_ENTER(env);
|
||||
const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
|
||||
|
||||
CGRect bbox;
|
||||
JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, awtStrike->fStyle, &glyph, 1, &bbox);
|
||||
CGGlyphImages_GetGlyphMetrics(fallback, &tx, awtStrike->fStyle, &glyph, 1, &bbox, NULL);
|
||||
CFRelease(fallback);
|
||||
|
||||
// the origin of this bounding box is relative to the bottom-left corner baseline
|
||||
|
||||
@ -33,5 +33,12 @@ void
|
||||
CGGlyphImages_GetGlyphImagePtrs(jlong glyphInfos[],
|
||||
const AWTStrike *strike,
|
||||
jint rawGlyphCodes[], const CFIndex len);
|
||||
|
||||
void
|
||||
CGGlyphImages_GetGlyphMetrics(const CTFontRef font,
|
||||
const CGAffineTransform *tx,
|
||||
const JRSFontRenderingStyle style,
|
||||
const CGGlyph glyphs[],
|
||||
size_t count,
|
||||
CGRect bboxes[],
|
||||
CGSize advances[]);
|
||||
#endif /* __CGGLYPHIMAGES_H */
|
||||
|
||||
@ -237,6 +237,7 @@ CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
|
||||
{
|
||||
UInt32 *src = (UInt32 *)canvas->image->data;
|
||||
size_t srcRowWidth = canvas->image->width;
|
||||
size_t srcHeight = canvas->image->height;
|
||||
|
||||
UInt8 *dest = (UInt8 *)info->image;
|
||||
size_t destRowWidth = info->width;
|
||||
@ -246,12 +247,12 @@ CGGI_CopyImageFromCanvasToRGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
|
||||
size_t y;
|
||||
|
||||
// fill empty glyph image with black-on-white glyph
|
||||
for (y = 0; y < height; y++) {
|
||||
for (y = 0; y < height && y < srcHeight; y++) {
|
||||
size_t destRow = y * destRowWidth * 3;
|
||||
size_t srcRow = y * srcRowWidth;
|
||||
|
||||
size_t x;
|
||||
for (x = 0; x < destRowWidth; x++) {
|
||||
for (x = 0; x < destRowWidth && x < srcRowWidth; x++) {
|
||||
CGGI_CopyARGBPixelToRGBPixel(src[srcRow + x],
|
||||
dest + destRow + x * 3);
|
||||
}
|
||||
@ -289,6 +290,7 @@ CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
|
||||
{
|
||||
UInt32 *src = (UInt32 *)canvas->image->data;
|
||||
size_t srcRowWidth = canvas->image->width;
|
||||
size_t srcHeight = canvas->image->height;
|
||||
|
||||
UInt8 *dest = (UInt8 *)info->image;
|
||||
size_t destRowWidth = info->width;
|
||||
@ -298,11 +300,11 @@ CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
|
||||
size_t y;
|
||||
|
||||
// fill empty glyph image with black-on-white glyph
|
||||
for (y = 0; y < height; y++) {
|
||||
for (y = 0; y < height && y < srcHeight; y++) {
|
||||
size_t destRow = y * destRowWidth;
|
||||
size_t srcRow = y * srcRowWidth;
|
||||
size_t x;
|
||||
for (x = 0; x < destRowWidth; x++) {
|
||||
for (x = 0; x < destRowWidth && x < srcRowWidth; x++) {
|
||||
UInt32 p = src[srcRow + x];
|
||||
dest[destRow + x] = CGGI_ConvertBWPixelToByteGray(p);
|
||||
}
|
||||
@ -384,8 +386,10 @@ CGGI_InitCanvas(CGGI_GlyphCanvas *canvas,
|
||||
|
||||
canvas->image->data = (void *)calloc(byteCount, sizeof(UInt8));
|
||||
if (canvas->image->data == NULL) {
|
||||
[[NSException exceptionWithName:NSMallocException
|
||||
reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise];
|
||||
canvas->image->width = 0;
|
||||
canvas->image->height = 0;
|
||||
canvas->image->rowBytes = 0;
|
||||
canvas->image->data = malloc(0);
|
||||
}
|
||||
|
||||
uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
|
||||
@ -435,6 +439,10 @@ CGGI_FreeCanvas(CGGI_GlyphCanvas *canvas)
|
||||
|
||||
/*
|
||||
* Quick and easy inline to check if this canvas is big enough.
|
||||
* This function only increases the size. To get a smaller canvas, free it first.
|
||||
* This function adds padding / slack multiplier to the requested size.
|
||||
* So resizes must be based on the size you need, not the size of the canvas.
|
||||
* The function will internally account for the multiplier it uses.
|
||||
*/
|
||||
static inline void
|
||||
CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width,
|
||||
@ -442,18 +450,31 @@ CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width,
|
||||
const CGGI_RenderingMode* mode)
|
||||
{
|
||||
if (canvas->image != NULL &&
|
||||
width < canvas->image->width &&
|
||||
height < canvas->image->height)
|
||||
width * CGGI_GLYPH_CANVAS_SLACK <= canvas->image->width &&
|
||||
height * CGGI_GLYPH_CANVAS_SLACK <= canvas->image->height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vImagePixelCount w = width * CGGI_GLYPH_CANVAS_SLACK;
|
||||
vImagePixelCount h = height * CGGI_GLYPH_CANVAS_SLACK;
|
||||
|
||||
// Do not allow the canvas to be resized smaller.
|
||||
if (canvas->image != NULL) {
|
||||
if (w < canvas->image->width) {
|
||||
w = canvas->image->width;
|
||||
}
|
||||
if (h < canvas->image->height) {
|
||||
h = canvas->image->height;
|
||||
}
|
||||
}
|
||||
|
||||
// if we don't have enough space to strike the largest glyph in the
|
||||
// run, resize the canvas
|
||||
CGGI_FreeCanvas(canvas);
|
||||
CGGI_InitCanvas(canvas,
|
||||
width * CGGI_GLYPH_CANVAS_SLACK,
|
||||
height * CGGI_GLYPH_CANVAS_SLACK,
|
||||
w,
|
||||
h,
|
||||
mode);
|
||||
JRSFontSetRenderingStyleOnContext(canvas->context, mode->cgFontMode);
|
||||
}
|
||||
@ -469,6 +490,12 @@ CGGI_ClearCanvas(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
|
||||
canvasRectToClear.data = canvas->image->data;
|
||||
canvasRectToClear.height = info->height;
|
||||
canvasRectToClear.width = info->width;
|
||||
if (canvas->image->width < canvasRectToClear.width) {
|
||||
canvasRectToClear.width = canvas->image->width;
|
||||
}
|
||||
if (canvas->image->height < canvasRectToClear.height) {
|
||||
canvasRectToClear.height = canvas->image->height;
|
||||
}
|
||||
// use the row stride of the canvas, not the info
|
||||
canvasRectToClear.rowBytes = canvas->image->rowBytes;
|
||||
|
||||
@ -605,10 +632,8 @@ CGGI_CreateImageForUnicode
|
||||
JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
|
||||
|
||||
CGRect bbox;
|
||||
JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, style, &glyph, 1, &bbox);
|
||||
|
||||
CGSize advance;
|
||||
CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
|
||||
CGGlyphImages_GetGlyphMetrics(fallback, &tx, style, &glyph, 1, &bbox, &advance);
|
||||
|
||||
// create the Sun2D GlyphInfo we are going to strike into
|
||||
GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
|
||||
@ -764,8 +789,8 @@ CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
|
||||
CGAffineTransform tx = strike->fTx;
|
||||
JRSFontRenderingStyle bboxCGMode = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
|
||||
|
||||
JRSFontGetBoundingBoxesForGlyphsAndStyle((CTFontRef)font->fFont, &tx, bboxCGMode, glyphs, len, bboxes);
|
||||
CTFontGetAdvancesForGlyphs((CTFontRef)font->fFont, kCTFontDefaultOrientation, glyphs, advances, len);
|
||||
CTFontRef fontRef = (CTFontRef)font->fFont;
|
||||
CGGlyphImages_GetGlyphMetrics(fontRef, &tx, bboxCGMode, glyphs, len, bboxes, advances);
|
||||
|
||||
size_t maxWidth = 1;
|
||||
size_t maxHeight = 1;
|
||||
@ -783,7 +808,6 @@ CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
|
||||
CGRect bbox = bboxes[i];
|
||||
|
||||
GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
|
||||
|
||||
if (maxWidth < glyphInfo->width) maxWidth = glyphInfo->width;
|
||||
if (maxHeight < glyphInfo->height) maxHeight = glyphInfo->height;
|
||||
|
||||
@ -860,8 +884,7 @@ CGGlyphImages_GetGlyphImagePtrs(jlong glyphInfos[],
|
||||
}
|
||||
|
||||
// just do one malloc, and carve it up for all the buffers
|
||||
void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
|
||||
sizeof(CGGlyph) * sizeof(UniChar) * len);
|
||||
void *buffer = malloc((sizeof(CGRect) + sizeof(CGSize) + sizeof(CGGlyph) + sizeof(UniChar)) * len);
|
||||
if (buffer == NULL) {
|
||||
[[NSException exceptionWithName:NSMallocException
|
||||
reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
|
||||
@ -878,3 +901,45 @@ CGGlyphImages_GetGlyphImagePtrs(jlong glyphInfos[],
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
#define TX_FIXED_UNSAFE(v) (isinf(v) || isnan(v) || fabs(v) >= (1<<30))
|
||||
|
||||
/*
|
||||
* Calculates bounding boxes (for given transform) and advance (for untransformed 1pt-size font) for specified glyphs.
|
||||
*/
|
||||
void
|
||||
CGGlyphImages_GetGlyphMetrics(const CTFontRef font,
|
||||
const CGAffineTransform *tx,
|
||||
const JRSFontRenderingStyle style,
|
||||
const CGGlyph glyphs[],
|
||||
size_t count,
|
||||
CGRect bboxes[],
|
||||
CGSize advances[]) {
|
||||
|
||||
if (TX_FIXED_UNSAFE(tx->a) || TX_FIXED_UNSAFE(tx->b) || TX_FIXED_UNSAFE(tx->c) ||
|
||||
TX_FIXED_UNSAFE(tx->d) || TX_FIXED_UNSAFE(tx->tx) || TX_FIXED_UNSAFE(tx->tx)) {
|
||||
|
||||
if (bboxes) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
bboxes[i].origin.x = 0;
|
||||
bboxes[i].origin.y = 0;
|
||||
bboxes[i].size.width = 0;
|
||||
bboxes[i].size.height = 0;
|
||||
}
|
||||
}
|
||||
if (advances) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
advances[i].width = 0;
|
||||
advances[i].height = 0;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (bboxes) {
|
||||
JRSFontGetBoundingBoxesForGlyphsAndStyle(font, tx, style, glyphs, count, bboxes);
|
||||
}
|
||||
if (advances) {
|
||||
CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, glyphs, advances, count);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user