aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/java.desktop/macosx/classes/sun/font/CStrike.java8
-rw-r--r--src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.h11
-rw-r--r--src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.m20
-rw-r--r--src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m226
-rw-r--r--src/java.desktop/share/native/common/font/AccelGlyphCache.h3
-rw-r--r--src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c71
6 files changed, 271 insertions, 68 deletions
diff --git a/src/java.desktop/macosx/classes/sun/font/CStrike.java b/src/java.desktop/macosx/classes/sun/font/CStrike.java
index 77fb013817b..42f0b179f85 100644
--- a/src/java.desktop/macosx/classes/sun/font/CStrike.java
+++ b/src/java.desktop/macosx/classes/sun/font/CStrike.java
@@ -40,7 +40,9 @@ public final class CStrike extends PhysicalStrike {
double[] glyphTx,
double[] invDevTxMatrix,
int aaHint,
- int fmHint);
+ int fmHint,
+ int subpixelResolutionX,
+ int subpixelResolutionY);
// Disposes the native strike
private static native void disposeNativeStrikePtr(long nativeStrikePtr);
@@ -127,7 +129,9 @@ public final class CStrike extends PhysicalStrike {
}
nativeStrikePtr =
createNativeStrikePtr(nativeFont.getNativeFontPtr(),
- glyphTx, invDevTxMatrix, aaHint, fmHint);
+ glyphTx, invDevTxMatrix, aaHint, fmHint,
+ FontUtilities.supplementarySubpixelGlyphResolution.width,
+ FontUtilities.supplementarySubpixelGlyphResolution.height);
}
return nativeStrikePtr;
diff --git a/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.h b/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.h
index 905c730d770..cd8ba219036 100644
--- a/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.h
+++ b/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.h
@@ -35,6 +35,8 @@
JRSFontRenderingStyle fStyle;
jint fAAStyle;
jint fFmHint;
+ jint fSubpixelResolutionX;
+ jint fSubpixelResolutionY;
CGAffineTransform fTx;
CGAffineTransform fDevTx;
@@ -42,6 +44,13 @@
CGAffineTransform fFontTx;
}
-+ (AWTStrike *) awtStrikeForFont:(AWTFont *)awtFont tx:(CGAffineTransform)tx invDevTx:(CGAffineTransform)invDevTx style:(JRSFontRenderingStyle)style aaStyle:(jint)aaStyle fmHint:(jint)fmHint;
++ (AWTStrike *) awtStrikeForFont:(AWTFont *)awtFont
+ tx:(CGAffineTransform)tx
+ invDevTx:(CGAffineTransform)invDevTx
+ style:(JRSFontRenderingStyle)style
+ aaStyle:(jint)aaStyle
+ fmHint:(jint)fmHint
+ subpixelResolutionX:(jint)subpixelResolutionX
+ subpixelResolutionY:(jint)subpixelResolutionY;
@end
diff --git a/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.m b/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.m
index 415574f6d76..d737398cc42 100644
--- a/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.m
+++ b/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.m
@@ -42,7 +42,9 @@ static CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };
invDevTx:(CGAffineTransform)invDevTx
style:(JRSFontRenderingStyle)style
aaStyle:(jint)aaStyle
- fmHint:(jint)fmHint {
+ fmHint:(jint)fmHint
+subpixelResolutionX:(jint)subpixelResolutionX
+subpixelResolutionY:(jint)subpixelResolutionY {
self = [super init];
if (self) {
@@ -50,6 +52,8 @@ static CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };
fStyle = style;
fAAStyle = aaStyle;
fFmHint = fmHint;
+ fSubpixelResolutionX = subpixelResolutionX;
+ fSubpixelResolutionY = subpixelResolutionY;
fTx = tx; // composited glyph and device transform
@@ -80,13 +84,17 @@ static CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };
invDevTx:(CGAffineTransform)invDevTx
style:(JRSFontRenderingStyle)style
aaStyle:(jint)aaStyle
- fmHint:(jint)fmHint {
+ fmHint:(jint)fmHint
+ subpixelResolutionX:(jint)subpixelResolutionX
+ subpixelResolutionY:(jint)subpixelResolutionY {
return [[[AWTStrike alloc] initWithFont:awtFont
tx:tx invDevTx:invDevTx
style:style
aaStyle:aaStyle
- fmHint:fmHint] autorelease];
+ fmHint:fmHint
+ subpixelResolutionX:subpixelResolutionX
+ subpixelResolutionY:subpixelResolutionY] autorelease];
}
@end
@@ -405,7 +413,8 @@ JNF_COCOA_EXIT(env);
* Signature: (J[D[DII)J
*/
JNIEXPORT jlong JNICALL Java_sun_font_CStrike_createNativeStrikePtr
-(JNIEnv *env, jclass clazz, jlong nativeFontPtr, jdoubleArray glyphTxArray, jdoubleArray invDevTxArray, jint aaStyle, jint fmHint)
+(JNIEnv *env, jclass clazz, jlong nativeFontPtr, jdoubleArray glyphTxArray, jdoubleArray invDevTxArray,
+ jint aaStyle, jint fmHint, jint subpixelResolutionX, jint subpixelResolutionY)
{
AWTStrike *awtStrike = nil;
JNF_COCOA_ENTER(env);
@@ -416,7 +425,8 @@ JNF_COCOA_ENTER(env);
CGAffineTransform glyphTx = GetTxFromDoubles(env, glyphTxArray);
CGAffineTransform invDevTx = GetTxFromDoubles(env, invDevTxArray);
- awtStrike = [AWTStrike awtStrikeForFont:awtFont tx:glyphTx invDevTx:invDevTx style:style aaStyle:aaStyle fmHint:fmHint]; // autoreleased
+ awtStrike = [AWTStrike awtStrikeForFont:awtFont tx:glyphTx invDevTx:invDevTx style:style
+ aaStyle:aaStyle fmHint:fmHint subpixelResolutionX:subpixelResolutionX subpixelResolutionY:subpixelResolutionY]; // autoreleased
if (awtStrike)
{
diff --git a/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m b/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m
index 47362ea6ba7..736e5dbb200 100644
--- a/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m
+++ b/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m
@@ -286,6 +286,64 @@ CGGI_ConvertBWPixelToByteGray(UInt32 p)
}
static void
+CGGI_CopySubpixelImageFromCanvasToAlphaInfo(const UInt32* srcImage, int srcRowWidth,
+ UInt8* dstImage,
+ int dstWidth, int dstHeight,
+ int subpixelResolutionX,
+ int subpixelResolutionY,
+ short *tempBuffer)
+{
+ int srcWidth = dstWidth * subpixelResolutionX;
+ int srcHeight = dstHeight * subpixelResolutionY;
+ int imageSize = dstWidth * dstHeight;
+ int xGlyph, yGlyph, x, y;
+ // For each subpixel offset by x axis
+ for (xGlyph = 0; xGlyph < subpixelResolutionX; xGlyph++) {
+ // Sum values by x axis and store into temporary buffer
+ for (y = 0; y < srcHeight; y++) {
+ for (x = 0; x < dstWidth; x++) {
+ int value = 0;
+ int xFrom = x * subpixelResolutionX - xGlyph,
+ xTo = xFrom + subpixelResolutionX;
+ if (xFrom < 0) xFrom = 0;
+ if (xTo > srcWidth) xTo = srcWidth;
+ int i;
+ for (i = xFrom; i < xTo; i++) {
+ value += CGGI_ConvertBWPixelToByteGray(
+ srcImage[y * srcRowWidth + i]);
+ }
+ tempBuffer[y * dstWidth + x] = (short) value;
+ }
+ }
+ // For each subpixel offset by y axis
+ for (yGlyph = 0; yGlyph < subpixelResolutionY; yGlyph++) {
+ UInt8 *dst = dstImage +
+ imageSize * (xGlyph + yGlyph * subpixelResolutionX);
+ // Sum values by y axis and store average into destination image
+ for (y = 0; y < dstHeight; y++) {
+ for (x = 0; x < dstWidth; x++) {
+ int value = 0;
+ int yFrom = y * subpixelResolutionY - yGlyph,
+ yTo = yFrom + subpixelResolutionY;
+ if (yFrom < 0) yFrom = 0;
+ if (yTo > srcHeight) yTo = srcHeight;
+ int j;
+ for (j = yFrom; j < yTo; j++) {
+ value += tempBuffer[j * dstWidth + x];
+ }
+ dst[y * dstWidth + x] =
+ value / subpixelResolutionX / subpixelResolutionY;
+ }
+ }
+ }
+ }
+}
+
+/* Size (in pixels) of stack-allocated temporary buffer for glyph downscaling.
+ * If glyph is too big and requires more memory, it will use malloc. */
+#define SUBPIXEL_DOWNSCALE_STATIC_BUFFER_SIZE 2048
+
+static void
CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
{
UInt32 *src = (UInt32 *)canvas->image->data;
@@ -296,16 +354,35 @@ CGGI_CopyImageFromCanvasToAlphaInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
size_t height = info->height;
- size_t y;
-
- // fill empty glyph image with black-on-white glyph
- for (y = 0; y < height; y++) {
- size_t destRow = y * destRowWidth;
- size_t srcRow = y * srcRowWidth;
- size_t x;
- for (x = 0; x < destRowWidth; x++) {
- UInt32 p = src[srcRow + x];
- dest[destRow + x] = CGGI_ConvertBWPixelToByteGray(p);
+ if (info->subpixelResolutionX > 1 || info->subpixelResolutionY > 1) {
+ int bufferSize = destRowWidth * height * info->subpixelResolutionY;
+ if (bufferSize <= SUBPIXEL_DOWNSCALE_STATIC_BUFFER_SIZE) {
+ short staticBuffer[bufferSize];
+ CGGI_CopySubpixelImageFromCanvasToAlphaInfo(
+ src, srcRowWidth,
+ dest, destRowWidth, height,
+ info->subpixelResolutionX, info->subpixelResolutionY,
+ staticBuffer);
+ } else {
+ short *buffer = malloc(sizeof(short) * bufferSize);
+ CGGI_CopySubpixelImageFromCanvasToAlphaInfo(
+ src, srcRowWidth,
+ dest, destRowWidth, height,
+ info->subpixelResolutionX, info->subpixelResolutionY,
+ buffer);
+ free(buffer);
+ }
+ } else {
+ size_t y;
+ // fill empty glyph image with black-on-white glyph
+ for (y = 0; y < height; y++) {
+ size_t destRow = y * destRowWidth;
+ size_t srcRow = y * srcRowWidth;
+ size_t x;
+ for (x = 0; x < destRowWidth; x++) {
+ UInt32 p = src[srcRow + x];
+ dest[destRow + x] = CGGI_ConvertBWPixelToByteGray(p);
+ }
}
}
}
@@ -353,8 +430,10 @@ typedef struct CGGI_GlyphInfoDescriptor {
} CGGI_GlyphInfoDescriptor;
typedef struct CGGI_RenderingMode {
- CGGI_GlyphInfoDescriptor *glyphDescriptor;
+ CGGI_GlyphInfoDescriptor *mainFontDescriptor;
JRSFontRenderingStyle cgFontMode;
+ bool lcdRendering;
+ bool subpixelResolution;
} CGGI_RenderingMode;
static CGGI_GlyphInfoDescriptor grey =
@@ -379,7 +458,7 @@ static inline CGGI_GlyphInfoDescriptor*
CGGI_GetGlyphInfoDescriptor(const CGGI_RenderingMode *mode, CGFontRef font)
{
bool isFixedColor = CGGI_IsColorFont(font);
- return isFixedColor ? &argb : mode->glyphDescriptor;
+ return isFixedColor ? &argb : mode->mainFontDescriptor;
}
static inline CGGI_RenderingMode
@@ -389,16 +468,26 @@ CGGI_GetRenderingMode(const AWTStrike *strike)
mode.cgFontMode = strike->fStyle;
NSException *e = nil;
+#ifdef USE_IMAGE_ALIGNED_MEMORY
+ mode.subpixelResolution = false;
+#else
+ mode.subpixelResolution = strike->fAAStyle == sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON &&
+ strike->fFmHint == sun_awt_SunHints_INTVAL_FRACTIONALMETRICS_ON &&
+ (strike->fSubpixelResolutionX > 1 || strike->fSubpixelResolutionY > 1);
+#endif
+
switch (strike->fAAStyle) {
case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF:
case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON:
- mode.glyphDescriptor = &grey;
+ mode.lcdRendering = false;
+ mode.mainFontDescriptor = &grey;
break;
case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HBGR:
case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR:
- mode.glyphDescriptor = &rgb;
+ mode.lcdRendering = true;
+ mode.mainFontDescriptor = &rgb;
break;
case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP:
case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT:
@@ -412,6 +501,10 @@ CGGI_GetRenderingMode(const AWTStrike *strike)
userInfo:nil];
@throw e;
}
+ if (CGGI_IsColorFont(strike->fAWTFont->fNativeCGFont)) {
+ mode.mainFontDescriptor = &argb;
+ mode.subpixelResolution = false;
+ }
return mode;
}
@@ -444,7 +537,7 @@ CGGI_InitCanvas(CGGI_GlyphCanvas *canvas,
}
uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
- if (mode->glyphDescriptor == &rgb) {
+ if (mode->lcdRendering) {
bmpInfo |= kCGBitmapByteOrder32Host;
}
@@ -522,8 +615,8 @@ CGGI_ClearCanvas(CGGI_GlyphCanvas *canvas, GlyphInfo *info, bool transparent)
{
vImage_Buffer canvasRectToClear;
canvasRectToClear.data = canvas->image->data;
- canvasRectToClear.height = info->height;
- canvasRectToClear.width = info->width;
+ canvasRectToClear.height = info->height * info->subpixelResolutionY;
+ canvasRectToClear.width = info->width * info->subpixelResolutionX;
// use the row stride of the canvas, not the info
canvasRectToClear.rowBytes = canvas->image->rowBytes;
@@ -561,7 +654,8 @@ static inline CGSize CGGI_ScaleAdvance(CGSize advance, const AWTStrike *strike)
static inline GlyphInfo *
CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox,
const AWTStrike *strike,
- const CGGI_GlyphInfoDescriptor *glyphDescriptor)
+ const CGGI_GlyphInfoDescriptor *glyphDescriptor,
+ bool subpixelResolution)
{
size_t pixelSize = glyphDescriptor->pixelSize;
@@ -573,8 +667,23 @@ CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox,
bbox.origin.x -= CGGI_GLYPH_BBOX_PADDING;
bbox.origin.y -= CGGI_GLYPH_BBOX_PADDING;
- vImagePixelCount width = ceilf(bbox.size.width);
- vImagePixelCount height = ceilf(bbox.size.height);
+ int subpixelResX = 1;
+ int subpixelResY = 1;
+ int topLeftX, topLeftY;
+ vImagePixelCount width, height;
+ if (subpixelResolution) {
+ subpixelResX = strike->fSubpixelResolutionX;
+ subpixelResY = strike->fSubpixelResolutionY;
+ topLeftX = floorf(bbox.origin.x / (float) subpixelResX);
+ topLeftY = floorf(bbox.origin.y / (float) subpixelResY);
+ width = ceilf((bbox.origin.x + bbox.size.width) / (float) subpixelResX) - topLeftX;
+ height = ceilf((bbox.origin.y + bbox.size.height) / (float) subpixelResY) - topLeftY;
+ } else {
+ topLeftX = round(bbox.origin.x);
+ topLeftY = round(bbox.origin.y);
+ width = ceilf(bbox.size.width);
+ height = ceilf(bbox.size.height);
+ }
// if the glyph is larger than 1MB, don't even try...
// the GlyphVector path should have taken over by now
@@ -595,19 +704,20 @@ CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox,
void *image = (void *)malloc(imageBytes + extraPixelStorage);
#else
// create a GlyphInfo struct fused to the image it points to
- GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo) + imageBytes + extraPixelStorage);
+ GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo) +
+ (imageBytes + extraPixelStorage) * subpixelResX * subpixelResY);
#endif
glyphInfo->advanceX = advance.width;
glyphInfo->advanceY = advance.height;
- glyphInfo->topLeftX = round(bbox.origin.x);
- glyphInfo->topLeftY = round(bbox.origin.y);
+ glyphInfo->topLeftX = topLeftX;
+ glyphInfo->topLeftY = topLeftY;
glyphInfo->width = width;
glyphInfo->height = height;
glyphInfo->rowBytes = width * pixelSize;
glyphInfo->cellInfo = NULL;
- glyphInfo->subpixelResolutionX = 1;
- glyphInfo->subpixelResolutionY = 1;
+ glyphInfo->subpixelResolutionX = subpixelResX;
+ glyphInfo->subpixelResolutionY = subpixelResY;
#ifdef USE_IMAGE_ALIGNED_MEMORY
glyphInfo->image = image;
@@ -624,6 +734,19 @@ CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox,
#pragma mark --- Glyph Striking onto Canvas ---
+static inline void CGGI_ScaleTXForSubpixelResolution(CGAffineTransform *tx,
+ const AWTStrike *strike,
+ bool subpixelResolution) {
+ if (subpixelResolution) {
+ float subResX = (float) strike->fSubpixelResolutionX;
+ float subResY = (float) strike->fSubpixelResolutionY;
+ tx->a *= subResX;
+ tx->b *= subResY;
+ tx->c *= subResX;
+ tx->d *= subResY;
+ }
+}
+
/*
* Clears the canvas, strikes the glyph with CoreGraphics, and then
* copies the struck pixels into the GlyphInfo image.
@@ -649,8 +772,8 @@ CGGI_CreateImageForGlyph
CGGI_ClearCanvas(canvas, info, glyphDescriptor == &argb);
// strike the glyph in the upper right corner
- CGFloat x = -info->topLeftX;
- CGFloat y = canvas->image->height + info->topLeftY;
+ CGFloat x = -info->topLeftX * (float) info->subpixelResolutionX;
+ CGFloat y = canvas->image->height + info->topLeftY * (float) info->subpixelResolutionY;
if (isCatalinaOrAbove || glyphDescriptor == &argb) {
CGAffineTransform matrix = CGContextGetTextMatrix(canvas->context);
@@ -699,8 +822,10 @@ CGGI_CreateImageForUnicode
const CGGI_RenderingMode *mode, const UnicodeScalarValue uniChar,
const bool isCatalinaOrAbove)
{
- // save the state of the world
+ // save the graphics state
CGContextSaveGState(canvas->context);
+ // text matrix is not considered part of graphics state
+ CGAffineTransform originalTx = CGContextGetTextMatrix(canvas->context);
// get the glyph, measure it using CG
CGGlyph glyph;
@@ -717,26 +842,32 @@ CGGI_CreateImageForUnicode
fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, &glyph, 1);
}
- CGAffineTransform tx = strike->fTx;
JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
+ const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
+ CGGI_GlyphInfoDescriptor *glyphDescriptor = CGGI_GetGlyphInfoDescriptor(mode, cgFallback);
+
+ bool subpixelResolution = mode->subpixelResolution && glyphDescriptor == &grey;
+
+ CGAffineTransform tx = strike->fTx;
+ CGGI_ScaleTXForSubpixelResolution(&tx, strike, subpixelResolution);
CGRect bbox;
JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, style, &glyph, 1, &bbox);
CGSize advance;
CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
- const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
- CGGI_GlyphInfoDescriptor *glyphDescriptor = CGGI_GetGlyphInfoDescriptor(mode, cgFallback);
// create the Sun2D GlyphInfo we are going to strike into
- GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, glyphDescriptor);
+ GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, glyphDescriptor, subpixelResolution);
// fix the context size, just in case the substituted character is unexpectedly large
- CGGI_SizeCanvas(canvas, info->width, info->height, mode);
+ CGGI_SizeCanvas(canvas, info->width * info->subpixelResolutionX, info->height * info->subpixelResolutionY, mode);
// align the transform for the real CoreText strike
- CGContextSetTextMatrix(canvas->context, strike->fAltTx);
+ CGAffineTransform altTx = strike->fAltTx;
+ CGGI_ScaleTXForSubpixelResolution(&altTx, strike, subpixelResolution);
+ CGContextSetTextMatrix(canvas->context, altTx);
CGContextSetFont(canvas->context, cgFallback);
CFRelease(cgFallback);
@@ -744,8 +875,9 @@ CGGI_CreateImageForUnicode
// clean the canvas - align, strike, and copy the glyph from the canvas into the info
CGGI_CreateImageForGlyph(cgFallback, canvas, glyph, info, glyphDescriptor, strike, isCatalinaOrAbove);
- // restore the state of the world
+ // restore graphics state
CGContextRestoreGState(canvas->context);
+ CGContextSetTextMatrix(canvas->context, originalTx);
CFRelease(fallback);
#ifdef CGGI_DEBUG
@@ -780,20 +912,20 @@ CGGI_FillImagesForGlyphsWithSizedCanvas(CGGI_GlyphCanvas *canvas,
const CGGlyph glyphs[],
const CFIndex len)
{
- CGContextSetTextMatrix(canvas->context, strike->fAltTx);
+ CGAffineTransform tx = strike->fAltTx;
+ CGGI_ScaleTXForSubpixelResolution(&tx, strike, mode->subpixelResolution);
+ CGContextSetTextMatrix(canvas->context, tx);
CGContextSetFont(canvas->context, strike->fAWTFont->fNativeCGFont);
JRSFontSetRenderingStyleOnContext(canvas->context, strike->fStyle);
- CGGI_GlyphInfoDescriptor* mainFontDescriptor = CGGI_GetGlyphInfoDescriptor(mode, strike->fAWTFont->fNativeCGFont);
-
const bool isMojaveOrAbove = IS_OSX_GT10_13;
CFIndex i;
for (i = 0; i < len; i++) {
GlyphInfo *info = (GlyphInfo *)jlong_to_ptr(glyphInfos[i]);
if (info != NULL) {
CGGI_CreateImageForGlyph(strike->fAWTFont->fNativeCGFont,
- canvas, glyphs[i], info, mainFontDescriptor, strike, isMojaveOrAbove);
+ canvas, glyphs[i], info, mode->mainFontDescriptor, strike, isMojaveOrAbove);
} else {
info = CGGI_CreateImageForUnicode(canvas, strike, mode, uniChars[i], isMojaveOrAbove);
glyphInfos[i] = ptr_to_jlong(info);
@@ -852,7 +984,7 @@ CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
NSMutableDictionary *threadDict =
[[NSThread currentThread] threadDictionary];
- NSString* theKey = (mode->glyphDescriptor == &rgb) ?
+ NSString* theKey = mode->lcdRendering ?
threadLocalLCDCanvasKey : threadLocalAACanvasKey;
CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey];
@@ -884,6 +1016,7 @@ CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
{
AWTFont *font = strike->fAWTFont;
CGAffineTransform tx = strike->fTx;
+ CGGI_ScaleTXForSubpixelResolution(&tx, strike, mode->subpixelResolution);
JRSFontRenderingStyle bboxCGMode = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
JRSFontGetBoundingBoxesForGlyphsAndStyle((CTFontRef)font->fFont, &tx, bboxCGMode, glyphs, len, bboxes);
@@ -892,8 +1025,6 @@ CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
size_t maxWidth = 1;
size_t maxHeight = 1;
- CGGI_GlyphInfoDescriptor* mainFontDescriptor = CGGI_GetGlyphInfoDescriptor(mode, strike->fAWTFont->fNativeCGFont);
-
CFIndex i;
for (i = 0; i < len; i++)
{
@@ -906,10 +1037,15 @@ CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
CGSize advance = advances[i];
CGRect bbox = bboxes[i];
- GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mainFontDescriptor);
+ GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike,
+ mode->mainFontDescriptor,
+ mode->subpixelResolution);
+
+ int w = glyphInfo->width * glyphInfo->subpixelResolutionX;
+ int h = glyphInfo->height * glyphInfo->subpixelResolutionY;
- if (maxWidth < glyphInfo->width) maxWidth = glyphInfo->width;
- if (maxHeight < glyphInfo->height) maxHeight = glyphInfo->height;
+ if (maxWidth < w) maxWidth = w;
+ if (maxHeight < h) maxHeight = h;
glyphInfos[i] = ptr_to_jlong(glyphInfo);
}
diff --git a/src/java.desktop/share/native/common/font/AccelGlyphCache.h b/src/java.desktop/share/native/common/font/AccelGlyphCache.h
index 4ffb15a4ea5..b4aa7d3c2f7 100644
--- a/src/java.desktop/share/native/common/font/AccelGlyphCache.h
+++ b/src/java.desktop/share/native/common/font/AccelGlyphCache.h
@@ -57,6 +57,9 @@ struct _CacheCellInfo {
// REMIND: find better name?
// next cell info in the glyph's cell list (next Glyph Cache Info)
CacheCellInfo *nextGCI;
+ // Glyph subimage ID, used to distinguish between different images
+ // Only makes sense when subpixel resolution is enabled for the glyph
+ jint glyphSubimage;
jint timesRendered;
jint x;
jint y;
diff --git a/src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c b/src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c
index 1e65eabc95a..47654aeb22c 100644
--- a/src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c
+++ b/src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c
@@ -242,7 +242,7 @@ OGLTR_InitGlyphCache(jboolean lcdCache)
* associated with the given OGLContext.
*/
static void
-OGLTR_AddToGlyphCache(GlyphInfo *glyph, GLenum pixelFormat)
+OGLTR_AddToGlyphCache(GlyphInfo *glyph, GLenum pixelFormat, jint subimage)
{
CacheCellInfo *ccinfo;
GlyphCacheInfo *gcinfo;
@@ -261,15 +261,16 @@ OGLTR_AddToGlyphCache(GlyphInfo *glyph, GLenum pixelFormat)
return;
}
- AccelGlyphCache_AddGlyph(gcinfo, glyph);
- ccinfo = (CacheCellInfo *) glyph->cellInfo;
+ ccinfo = AccelGlyphCache_AddGlyph(gcinfo, glyph);
if (ccinfo != NULL) {
+ ccinfo->glyphSubimage = subimage;
// store glyph image in texture cell
j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
ccinfo->x, ccinfo->y,
glyph->width, glyph->height,
- pixelFormat, GL_UNSIGNED_BYTE, glyph->image);
+ pixelFormat, GL_UNSIGNED_BYTE, glyph->image +
+ (glyph->rowBytes * glyph->height) * subimage);
}
}
@@ -811,7 +812,8 @@ OGLTR_DisableGlyphModeState()
}
static jboolean
-OGLTR_DrawGrayscaleGlyphViaCache(OGLContext *oglc, GlyphInfo *ginfo, jint x, jint y, jboolean useFontSmoothing)
+OGLTR_DrawGrayscaleGlyphViaCache(OGLContext *oglc, GlyphInfo *ginfo, jint x, jint y,
+ jboolean useFontSmoothing, jint subimage)
{
CacheCellInfo *cell;
jfloat x1, y1, x2, y2;
@@ -834,17 +836,39 @@ OGLTR_DrawGrayscaleGlyphViaCache(OGLContext *oglc, GlyphInfo *ginfo, jint x, jin
glyphMode = MODE_USE_CACHE_GRAY;
}
- if (ginfo->cellInfo == NULL) {
- // attempt to add glyph to accelerated glyph cache
- OGLTR_AddToGlyphCache(ginfo, GL_LUMINANCE);
+ int rx = ginfo->subpixelResolutionX;
+ int ry = ginfo->subpixelResolutionY;
+ if (subimage == 0 && ((rx == 1 && ry == 1) || rx <= 0 || ry <= 0)) {
+ // Subpixel rendering disabled, there must be only one cell info
+ cell = (CacheCellInfo *) (ginfo->cellInfo);
+ } else {
+ // Subpixel rendering enabled, find subimage in cell list
+ cell = NULL;
+ CacheCellInfo *c = (CacheCellInfo *) (ginfo->cellInfo);
+ while (c != NULL) {
+ if (c->glyphSubimage == subimage) {
+ cell = c;
+ break;
+ }
+ c = c->nextGCI;
+ }
+ }
- if (ginfo->cellInfo == NULL) {
+ if (cell == NULL) {
+ // attempt to add glyph to accelerated glyph cache
+ OGLTR_AddToGlyphCache(ginfo, GL_LUMINANCE, subimage);
+ // Our image, added to cache will be the first, so we take it.
+ // If for whatever reason we failed to add it to our cache,
+ // take first cell anyway, it's still better to render glyph
+ // image with wrong subpixel offset than render nothing.
+ cell = (CacheCellInfo *) (ginfo->cellInfo);
+
+ if (cell == NULL) {
// we'll just no-op in the rare case that the cell is NULL
return JNI_TRUE;
}
}
- cell = (CacheCellInfo *) (ginfo->cellInfo);
cell->timesRendered++;
x1 = (jfloat)x;
@@ -1039,7 +1063,7 @@ OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps, GlyphInfo *ginfo,
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
// attempt to add glyph to accelerated glyph cache
- OGLTR_AddToGlyphCache(ginfo, rgbOrder ? GL_RGB : GL_BGR);
+ OGLTR_AddToGlyphCache(ginfo, rgbOrder ? GL_RGB : GL_BGR, 0);
if (ginfo->cellInfo == NULL) {
// we'll just no-op in the rare case that the cell is NULL
@@ -1096,7 +1120,8 @@ OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps, GlyphInfo *ginfo,
static jboolean
OGLTR_DrawGrayscaleGlyphNoCache(OGLContext *oglc,
- GlyphInfo *ginfo, jint x, jint y)
+ GlyphInfo *ginfo, jint x, jint y,
+ jint subimage)
{
jint tw, th;
jint sx, sy, sw, sh;
@@ -1123,7 +1148,8 @@ OGLTR_DrawGrayscaleGlyphNoCache(OGLContext *oglc,
OGLVertexCache_AddMaskQuad(oglc,
sx, sy, x, y, sw, sh,
- w, ginfo->image);
+ w, ginfo->image +
+ (ginfo->rowBytes * ginfo->height) * subimage);
}
}
@@ -1317,6 +1343,9 @@ extern int useFontSmoothing;
#define FLOOR_ASSIGN(l, r) \
if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
+#define ADJUST_SUBPIXEL_GLYPH_POSITION(coord, res) \
+ if ((res) > 1) (coord) += 0.5f / ((float)(res)) - 0.5f
+
void
OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
jint totalGlyphs, jboolean usePositions,
@@ -1388,11 +1417,15 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
jfloat posy = NEXT_FLOAT(positions);
glyphx = glyphListOrigX + posx + ginfo->topLeftX;
glyphy = glyphListOrigY + posy + ginfo->topLeftY;
+ ADJUST_SUBPIXEL_GLYPH_POSITION(glyphx, ginfo->subpixelResolutionX);
+ ADJUST_SUBPIXEL_GLYPH_POSITION(glyphy, ginfo->subpixelResolutionY);
FLOOR_ASSIGN(x, glyphx);
FLOOR_ASSIGN(y, glyphy);
} else {
glyphx = glyphListOrigX + ginfo->topLeftX;
glyphy = glyphListOrigY + ginfo->topLeftY;
+ ADJUST_SUBPIXEL_GLYPH_POSITION(glyphx, ginfo->subpixelResolutionX);
+ ADJUST_SUBPIXEL_GLYPH_POSITION(glyphy, ginfo->subpixelResolutionY);
FLOOR_ASSIGN(x, glyphx);
FLOOR_ASSIGN(y, glyphy);
glyphListOrigX += ginfo->advanceX;
@@ -1406,12 +1439,20 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
if (ginfo->rowBytes == ginfo->width) {
OGLMTVertexCache_disable();
// grayscale or monochrome glyph data
+ int rx = ginfo->subpixelResolutionX;
+ int ry = ginfo->subpixelResolutionY;
+ int subimage;
+ if ((rx == 1 && ry == 1) || rx <= 0 || ry <= 0) {
+ subimage = 0;
+ } else {
+ subimage = (jint)((glyphx - x) * rx) + (jint)((glyphy - y) * ry) * rx;
+ }
if (ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
{
- ok = OGLTR_DrawGrayscaleGlyphViaCache(oglc, ginfo, x, y, fontSmoothing);
+ ok = OGLTR_DrawGrayscaleGlyphViaCache(oglc, ginfo, x, y, fontSmoothing, subimage);
} else {
- ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y);
+ ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y, subimage);
}
} else if (ginfo->rowBytes == ginfo->width * 4) {
OGLMTVertexCache_disable();