--- old/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java 2014-12-12 19:56:18.000000000 +0300 +++ new/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java 2014-12-12 19:56:18.000000000 +0300 @@ -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_HRGB); desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, fontHints); desktopProperties.put("awt.mouse.numButtons", BUTTONS); --- old/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.m 2014-12-12 19:56:19.000000000 +0300 +++ new/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.m 2014-12-12 19:56:18.000000000 +0300 @@ -314,21 +314,26 @@ jlong *glyphInfos = (*env)->GetPrimitiveArrayCritical(env, glyphInfoLongArray, NULL); - if (glyphInfos != NULL) { - jint *rawGlyphCodes = - (*env)->GetPrimitiveArrayCritical(env, glyphCodes, NULL); - if (rawGlyphCodes != NULL) { + jint *rawGlyphCodes = + (*env)->GetPrimitiveArrayCritical(env, glyphCodes, NULL); + @try { + if (rawGlyphCodes != NULL && glyphInfos != NULL) { CGGlyphImages_GetGlyphImagePtrs(glyphInfos, awtStrike, - rawGlyphCodes, len); - + rawGlyphCodes, len); + } + } + @finally { + if (rawGlyphCodes != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, glyphCodes, - rawGlyphCodes, JNI_ABORT); + rawGlyphCodes, JNI_ABORT); + } + if (glyphInfos != NULL) { + // Do not use JNI_COMMIT, as that will not free the buffer copy + // when +ProtectJavaHeap is on. + (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoLongArray, + glyphInfos, 0); } - // Do not use JNI_COMMIT, as that will not free the buffer copy - // when +ProtectJavaHeap is on. - (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoLongArray, - glyphInfos, 0); } JNF_COCOA_EXIT(env); --- old/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m 2014-12-12 19:56:19.000000000 +0300 +++ new/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m 2014-12-12 19:56:19.000000000 +0300 @@ -199,15 +199,9 @@ static inline void 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); -#else - *(dst) = 0xFF - (p >> 16 & 0xFF); - *(dst + 1) = 0xFF - (p >> 8 & 0xFF); - *(dst + 2) = 0xFF - (p & 0xFF); -#endif + *(dst + 0) = 0xFF - (p >> 16 & 0xFF); // red + *(dst + 1) = 0xFF - (p >> 8 & 0xFF); // green + *(dst + 2) = 0xFF - (p & 0xFF); // blue } static void @@ -316,13 +310,11 @@ { CGGI_RenderingMode mode; mode.cgFontMode = strike->fStyle; + NSException *e = nil; 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 +323,14 @@ 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: + e = [NSException + exceptionWithName:@"IllegalArgumentException" + reason:@"Invalid hint value" + userInfo:nil]; + @throw e; } return mode; @@ -345,7 +345,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 +363,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 +410,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 +424,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 +584,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 +660,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 +688,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 +700,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/opengl/OGLSurfaceData.java 2014-12-12 19:56:20.000000000 +0300 +++ new/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java 2014-12-12 19:56:20.000000000 +0300 @@ -25,10 +25,7 @@ package sun.java2d.opengl; -import java.awt.AlphaComposite; -import java.awt.GraphicsEnvironment; -import java.awt.Rectangle; -import java.awt.Transparency; +import java.awt.*; import java.awt.image.ColorModel; import java.awt.image.Raster; import sun.awt.SunHints; @@ -400,9 +397,8 @@ /** * For now, we can only render LCD text if: * - the fragment shader extension is available, and - * - blending is disabled, and - * - the source color is opaque - * - and the destination is opaque + * - the source color is opaque, and + * - blending is SrcOverNoEa or disabled * * Eventually, we could enhance the native OGL text rendering code * and remove the above restrictions, but that would require significantly @@ -411,9 +407,19 @@ public boolean canRenderLCDText(SunGraphics2D sg2d) { return graphicsConfig.isCapPresent(CAPS_EXT_LCD_SHADER) && - sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && - sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR && - sg2d.surfaceData.getTransparency() == Transparency.OPAQUE; + sg2d.surfaceData.getTransparency() == Transparency.OPAQUE && + sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && + (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY || + (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA && canHandleComposite(sg2d.composite))); + } + + private boolean canHandleComposite(Composite c) { + if (c instanceof AlphaComposite) { + AlphaComposite ac = (AlphaComposite)c; + + return ac.getRule() == AlphaComposite.SRC_OVER && ac.getAlpha() >= 1f; + } + return false; } public void validatePipe(SunGraphics2D sg2d) { --- old/src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c 2014-12-12 19:56:20.000000000 +0300 +++ new/src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c 2014-12-12 19:56:20.000000000 +0300 @@ -272,7 +272,7 @@ * * The "uniform" variables at the top are initialized once the program is * linked, and are updated at runtime as needed (e.g. when the source color - * changes, we will modify the "src_adj" value in OGLTR_UpdateLCDTextColor()). + * changes, we will modify the "src_clr" value in OGLTR_UpdateLCDTextColor()). * * The "main" function is executed for each "fragment" (or pixel) in the * glyph image. We have determined that the pow() function can be quite @@ -296,7 +296,7 @@ * Cr = (Ag*(Cs^Ga) + (1-Ag)*(Cd^Ga)) ^ (1/Ga) */ static const char *lcdTextShaderSource = - "uniform vec3 src_adj;" + "uniform vec4 src_clr;" "uniform sampler2D glyph_tex;" "uniform sampler2D dst_tex;" "uniform sampler3D invgamma_tex;" @@ -310,14 +310,20 @@ // zero coverage, so skip this fragment " discard;" " }" - // load the RGB value from the corresponding destination pixel - " vec3 dst_clr = vec3(texture2D(dst_tex, gl_TexCoord[1].st));" + // load the RGBA value from the corresponding destination pixel + " vec4 dst_clr = vec4(texture2D(dst_tex, gl_TexCoord[1].st));" + // blend src and dst colors as SrcOverNoEa + " vec3 src_comp = vec3(src_clr.rgb + ((1.0 - src_clr.a) * dst_clr.rgb));" + // gamma adjust the blended src color using the invgamma LUT + " vec3 src_adj = vec3(texture3D(invgamma_tex, src_comp));" // gamma adjust the dest color using the invgamma LUT - " vec3 dst_adj = vec3(texture3D(invgamma_tex, dst_clr.stp));" + " vec3 dst_adj = vec3(texture3D(invgamma_tex, dst_clr.rgb));" // linearly interpolate the three color values " vec3 result = mix(dst_adj, src_adj, glyph_clr);" - // gamma re-adjust the resulting color (alpha is always set to 1.0) - " gl_FragColor = vec4(vec3(texture3D(gamma_tex, result.stp)), 1.0);" + // calculate the resulting alpha + " dst_clr.a = src_clr.a + (1.0 - src_clr.a) * dst_clr.a;" + // gamma re-adjust the resulting color + " gl_FragColor = vec4(vec3(texture3D(gamma_tex, result.rgb)), dst_clr.a);" "}"; /** @@ -467,45 +473,24 @@ } /** - * Updates the current gamma-adjusted source color ("src_adj") of the LCD - * text shader program. Note that we could calculate this value in the - * shader (e.g. just as we do for "dst_adj"), but would be unnecessary work - * (and a measurable performance hit, maybe around 5%) since this value is - * constant over the entire glyph list. So instead we just calculate the - * gamma-adjusted value once and update the uniform parameter of the LCD - * shader as needed. + * Updates the current source color ("src_clr") of the LCD text shader program. */ static jboolean OGLTR_UpdateLCDTextColor(jint contrast) { - double gamma = ((double)contrast) / 100.0; - GLfloat radj, gadj, badj; + double gamma = 100.0 / ((double)contrast); GLfloat clr[4]; GLint loc; J2dTraceLn1(J2D_TRACE_INFO, "OGLTR_UpdateLCDTextColor: contrast=%d", contrast); - /* - * Note: Ideally we would update the "src_adj" uniform parameter only - * when there is a change in the source color. Fortunately, the cost - * of querying the current OpenGL color state and updating the uniform - * value is quite small, and in the common case we only need to do this - * once per GlyphList, so we gain little from trying to optimize too - * eagerly here. - */ - // get the current OpenGL primary color state j2d_glGetFloatv(GL_CURRENT_COLOR, clr); - // gamma adjust the primary color - radj = (GLfloat)pow(clr[0], gamma); - gadj = (GLfloat)pow(clr[1], gamma); - badj = (GLfloat)pow(clr[2], gamma); - - // update the "src_adj" parameter of the shader program with this value - loc = j2d_glGetUniformLocationARB(lcdTextProgram, "src_adj"); - j2d_glUniform3fARB(loc, radj, gadj, badj); + // update the "src_clr" parameter of the shader program with this value + loc = j2d_glGetUniformLocationARB(lcdTextProgram, "src_clr"); + j2d_glUniform4fARB(loc, clr[0], clr[1], clr[2], clr[3]); return JNI_TRUE; }