--- old/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java 2014-10-10 18:18:53.000000000 +0400 +++ new/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java 2014-10-10 18:18:53.000000000 +0400 @@ -63,6 +63,11 @@ this.height = height * scale; } + public boolean canRenderLCDText(SunGraphics2D sg2d) { + // TODO: check LCD requirements + return true; + } + protected CGLSurfaceData(CPlatformView pView, CGLGraphicsConfig gc, ColorModel cm, int type,int width, int height) { --- old/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java 2014-10-10 18:18:54.000000000 +0400 +++ new/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java 2014-10-10 18:18:53.000000000 +0400 @@ -371,7 +371,7 @@ super.initializeDesktopProperties(); Map fontHints = new HashMap<>(); fontHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - fontHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + fontHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR); desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, fontHints); desktopProperties.put("awt.mouse.numButtons", BUTTONS); --- old/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m 2014-10-10 18:18:54.000000000 +0400 +++ new/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m 2014-10-10 18:18:54.000000000 +0400 @@ -200,10 +200,11 @@ CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst) { #if __LITTLE_ENDIAN__ - *(dst + 2) = 0xFF - (p >> 24 & 0xFF); - *(dst + 1) = 0xFF - (p >> 16 & 0xFF); - *(dst) = 0xFF - (p >> 8 & 0xFF); + *(dst + 2) = 0xFF - (p >> 16 & 0xFF); + *(dst + 1) = 0xFF - (p >> 8 & 0xFF); + *(dst) = 0xFF - (p & 0xFF); #else + // TODO: check whether do we need big endian case *(dst) = 0xFF - (p >> 16 & 0xFF); *(dst + 1) = 0xFF - (p >> 8 & 0xFF); *(dst + 2) = 0xFF - (p & 0xFF); @@ -318,11 +319,8 @@ mode.cgFontMode = strike->fStyle; switch (strike->fAAStyle) { - case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON: - case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP: - default: mode.glyphDescriptor = &grey; break; case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB: @@ -331,6 +329,11 @@ case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR: mode.glyphDescriptor = &rgb; break; + case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP: + case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT: + default: + // TODO: generate an error? + break; } return mode; @@ -345,7 +348,8 @@ */ static inline void CGGI_InitCanvas(CGGI_GlyphCanvas *canvas, - const vImagePixelCount width, const vImagePixelCount height) + const vImagePixelCount width, const vImagePixelCount height, + const CGGI_RenderingMode* mode) { // our canvas is *always* 4-byte ARGB size_t bytesPerRow = width * sizeof(UInt32); @@ -362,11 +366,16 @@ reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise]; } + uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst; + if (mode->glyphDescriptor == &rgb) { + bmpInfo |= kCGBitmapByteOrder32Host; + } + CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); canvas->context = CGBitmapContextCreate(canvas->image->data, width, height, 8, bytesPerRow, colorSpace, - kCGImageAlphaPremultipliedFirst); + bmpInfo); CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f); CGContextSetFontSize(canvas->context, 1); @@ -404,7 +413,7 @@ * Quick and easy inline to check if this canvas is big enough. */ static inline void -CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width, const vImagePixelCount height, const JRSFontRenderingStyle style) +CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width, const vImagePixelCount height, const CGGI_RenderingMode* mode) { if (canvas->image != NULL && width < canvas->image->width && @@ -418,8 +427,9 @@ CGGI_FreeCanvas(canvas); CGGI_InitCanvas(canvas, width * CGGI_GLYPH_CANVAS_SLACK, - height * CGGI_GLYPH_CANVAS_SLACK); - JRSFontSetRenderingStyleOnContext(canvas->context, style); + height * CGGI_GLYPH_CANVAS_SLACK, + mode); + JRSFontSetRenderingStyleOnContext(canvas->context, mode->cgFontMode); } /* @@ -577,7 +587,7 @@ GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode); // fix the context size, just in case the substituted character is unexpectedly large - CGGI_SizeCanvas(canvas, info->width, info->height, mode->cgFontMode); + CGGI_SizeCanvas(canvas, info->width, info->height, mode); // align the transform for the real CoreText strike CGContextSetTextMatrix(canvas->context, strike->fAltTx); @@ -653,8 +663,11 @@ #endif } -static NSString *threadLocalCanvasKey = - @"Java CoreGraphics Text Renderer Cached Canvas"; +static NSString *threadLocalAACanvasKey = + @"Java CoreGraphics Text Renderer Cached Canvas for AA"; + +static NSString *threadLocalLCDCanvasKey = + @"Java CoreGraphics Text Renderer Cached Canvas for LCD"; /* * This is the maximum length and height times the above slack squared @@ -678,7 +691,7 @@ CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK) { CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init]; - CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight); + CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode); CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike, mode, glyphInfos, uniChars, glyphs, len); @@ -690,13 +703,22 @@ NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; - CGGI_GlyphCanvas *canvas = [threadDict objectForKey:threadLocalCanvasKey]; + + NSString* theKey; + + if (mode->glyphDescriptor == &rgb) { + theKey = threadLocalLCDCanvasKey; + } else { + theKey = threadLocalAACanvasKey; + } + + CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey]; if (canvas == nil) { canvas = [[CGGI_GlyphCanvas alloc] init]; - [threadDict setObject:canvas forKey:threadLocalCanvasKey]; + [threadDict setObject:canvas forKey:theKey]; } - CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode->cgFontMode); + CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode); CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode, glyphInfos, uniChars, glyphs, len); } --- old/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java 2014-10-10 18:18:55.000000000 +0400 +++ new/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java 2014-10-10 18:18:55.000000000 +0400 @@ -721,31 +721,38 @@ } else { aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF; } - } else if (aahint >= SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB) { - /* loops for default rendering modes are installed in the SG2D - * constructor. If there are none this will be null. - * Not all compositing modes update the render loops, so - * we also test that this is a mode we know should support - * this. One minor issue is that the loops aren't necessarily - * installed for a new rendering mode until after this - * method is called during pipeline validation. So it is - * theoretically possible that it was set to null for a - * compositing mode, the composite is then set back to Src, - * but the loop is still null when this is called and AA=ON - * is installed instead of an LCD mode. - * However this is done in the right order in SurfaceData.java - * so this is not likely to be a problem - but not - * guaranteed. - */ - if ( - !surfaceData.canRenderLCDText(this) -// loops.drawGlyphListLCDLoop == null || -// compositeState > COMP_ISCOPY || -// paintState > PAINT_ALPHACOLOR - ) { - aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON; - } else { - info.lcdRGBOrder = true; + } + } + + if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_ON && FontUtilities.isMacOSX) { + // TODO: check subpixel order + aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HBGR; + } + if (aahint >= SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB) { + /* loops for default rendering modes are installed in the SG2D + * constructor. If there are none this will be null. + * Not all compositing modes update the render loops, so + * we also test that this is a mode we know should support + * this. One minor issue is that the loops aren't necessarily + * installed for a new rendering mode until after this + * method is called during pipeline validation. So it is + * theoretically possible that it was set to null for a + * compositing mode, the composite is then set back to Src, + * but the loop is still null when this is called and AA=ON + * is installed instead of an LCD mode. + * However this is done in the right order in SurfaceData.java + * so this is not likely to be a problem - but not + * guaranteed. + */ + if ( + !surfaceData.canRenderLCDText(this) +// loops.drawGlyphListLCDLoop == null || +// compositeState > COMP_ISCOPY || +// paintState > PAINT_ALPHACOLOR + ) { + aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON; + } else { + info.lcdRGBOrder = true; /* Collapse these into just HRGB or VRGB. * Pipe selection code needs only to test for these two. * Since these both select the same pipe anyway its @@ -767,7 +774,6 @@ info.lcdSubPixPos = fmhint == SunHints.INTVAL_FRACTIONALMETRICS_ON && aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB; - } } } info.aaHint = aahint; --- old/src/java.desktop/share/classes/sun/java2d/SurfaceData.java 2014-10-10 18:18:55.000000000 +0400 +++ new/src/java.desktop/share/classes/sun/java2d/SurfaceData.java 2014-10-10 18:18:55.000000000 +0400 @@ -747,8 +747,9 @@ case SunHints.INTVAL_TEXT_ANTIALIAS_OFF: return solidTextRenderer; - case SunHints.INTVAL_TEXT_ANTIALIAS_ON: - return aaTextRenderer; + // TODO: we have to take into account aaHint on macosx + //case SunHints.INTVAL_TEXT_ANTIALIAS_ON: + // return aaTextRenderer; default: switch (sg2d.getFontInfo().aaHint) {