changeset 57999:82fe2f667c29

8236996: Incorrect Roboto font rendering on Windows with subpixel antialiasing Reviewed-by: prr, serb
author dbatrak
date Mon, 27 Jan 2020 13:02:54 -0800
parents ffcc3bd2b5da
children 2777408b8281
files src/java.desktop/share/classes/sun/font/FileFontStrike.java src/java.desktop/share/classes/sun/font/TrueTypeFont.java src/java.desktop/windows/native/libfontmanager/lcdglyph.c
diffstat 3 files changed, 35 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.desktop/share/classes/sun/font/FileFontStrike.java	Fri Jan 24 18:39:51 2020 -0800
+++ b/src/java.desktop/share/classes/sun/font/FileFontStrike.java	Mon Jan 27 13:02:54 2020 -0800
@@ -328,7 +328,8 @@
                                                   int style,
                                                   int size,
                                                   int glyphCode,
-                                                  boolean fracMetrics);
+                                                  boolean fracMetrics,
+                                                  int fontDataSize);
 
     long getGlyphImageFromWindows(int glyphCode) {
         String family = fileFont.getFamilyName(null);
@@ -337,7 +338,8 @@
         int size = intPtSize;
         long ptr = _getGlyphImageFromWindows
             (family, style, size, glyphCode,
-             desc.fmHint == INTVAL_FRACTIONALMETRICS_ON);
+             desc.fmHint == INTVAL_FRACTIONALMETRICS_ON,
+             ((TrueTypeFont)fileFont).fontDataSize);
         if (ptr != 0) {
             /* Get the advance from the JDK rasterizer. This is mostly
              * necessary for the fractional metrics case, but there are
@@ -351,6 +353,12 @@
                                         advance);
             return ptr;
         } else {
+            if (FontUtilities.isLogging()) {
+                FontUtilities.getLogger().warning(
+                        "Failed to render glyph using GDI: code=" + glyphCode
+                                + ", fontFamily=" + family + ", style=" + style
+                                + ", size=" + size);
+            }
             return fileFont.getGlyphImage(pScalerContext, glyphCode);
         }
     }
--- a/src/java.desktop/share/classes/sun/font/TrueTypeFont.java	Fri Jan 24 18:39:51 2020 -0800
+++ b/src/java.desktop/share/classes/sun/font/TrueTypeFont.java	Mon Jan 27 13:02:54 2020 -0800
@@ -180,6 +180,15 @@
     private String localeFamilyName;
     private String localeFullName;
 
+    /*
+     * Used on Windows to validate the font selected by GDI for (sub-pixel
+     * antialiased) rendering. For 'standalone' fonts it's equal to the font
+     * file size, for collection (TTC, OTC) members it's the number of bytes in
+     * the collection file from the start of this font's offset table till the
+     * end of the file.
+     */
+    int fontDataSize;
+
     public TrueTypeFont(String platname, Object nativeNames, int fIndex,
                  boolean javaRasterizer)
         throws FontFormatException
@@ -537,11 +546,13 @@
                 fontIndex = fIndex;
                 buffer = readBlock(TTCHEADERSIZE+4*fIndex, 4);
                 headerOffset = buffer.getInt();
+                fontDataSize = Math.max(0, fileSize - headerOffset);
                 break;
 
             case v1ttTag:
             case trueTag:
             case ottoTag:
+                fontDataSize = fileSize;
                 break;
 
             default:
--- a/src/java.desktop/windows/native/libfontmanager/lcdglyph.c	Fri Jan 24 18:39:51 2020 -0800
+++ b/src/java.desktop/windows/native/libfontmanager/lcdglyph.c	Mon Jan 27 13:02:54 2020 -0800
@@ -172,7 +172,8 @@
 JNIEXPORT jlong JNICALL
 Java_sun_font_FileFontStrike__1getGlyphImageFromWindows
 (JNIEnv *env, jobject unused,
- jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm) {
+ jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm,
+ jint fontDataSize) {
 
     GLYPHMETRICS glyphMetrics;
     LOGFONTW lf;
@@ -188,6 +189,7 @@
     LPWSTR name;
     HFONT oldFont, hFont;
     MAT2 mat2;
+    DWORD actualFontDataSize;
 
     unsigned short width;
     unsigned short height;
@@ -254,6 +256,17 @@
     }
     oldFont = SelectObject(hMemoryDC, hFont);
 
+    if (fontDataSize > 0) {
+        // GDI doesn't allow to select a specific font file for drawing, we can
+        // only check that it picks the file we need by validating font size.
+        // If it doesn't match, we cannot proceed, as the same glyph code can
+        // correspond to a completely different glyph in the selected font.
+        actualFontDataSize = GetFontData(hMemoryDC, 0, 0, NULL, 0);
+        if (actualFontDataSize != fontDataSize) {
+            FREE_AND_RETURN;
+        }
+    }
+
     tmpBitmap = CreateCompatibleBitmap(hDesktopDC, 1, 1);
     if (tmpBitmap == NULL) {
         FREE_AND_RETURN;