Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8264703

Numbers and latin letters rendering in different fonts

XMLWordPrintable

    • 2d
    • x86_64
    • linux

      ADDITIONAL SYSTEM INFORMATION :
      Tested using the Java 11 build distributed with ArchLinux, and using a Oracle OpenJDK 16
      build (though this also appeared in ArchLinux's default OpenJDK 15 build):

      IMPLEMENTOR="Oracle Corporation"
      JAVA_VERSION="16"
      JAVA_VERSION_DATE="2021-03-16"
      LIBC="gnu"
      MODULES="java.base java.compiler java.datatransfer java.xml java.prefs java.desktop java.instrument java.logging java.management java.security.sasl java.naming java.rmi java.management.rmi java.net.http java.scripting java.security.jgss java.transaction.xa java.sql java.sql.rowset java.xml.crypto java.se java.smartcardio jdk.accessibility jdk.internal.jvmstat jdk.attach jdk.charsets jdk.compiler jdk.crypto.ec jdk.crypto.cryptoki jdk.dynalink jdk.internal.ed jdk.editpad jdk.hotspot.agent jdk.httpserver jdk.incubator.foreign jdk.incubator.vector jdk.internal.le jdk.internal.opt jdk.internal.vm.ci jdk.jartool jdk.javadoc jdk.jcmd jdk.management jdk.management.agent jdk.jconsole jdk.jdeps jdk.jdwp.agent jdk.jdi jdk.jfr jdk.jlink jdk.jpackage jdk.jshell jdk.jsobject jdk.jstatd jdk.localedata jdk.management.jfr jdk.naming.dns jdk.naming.rmi jdk.net jdk.nio.mapmode jdk.sctp jdk.security.auth jdk.security.jgss jdk.unsupported jdk.unsupported.desktop jdk.xml.dom jdk.zipfs"
      OS_ARCH="x86_64"
      OS_NAME="Linux"
      SOURCE=".:git:4de3a6be9e60"

      A DESCRIPTION OF THE PROBLEM :
      Text in Swing UIs using the Dialog.plain font are rendered using a mixture of two fonts - one for latin text and
      one for numbers. Unfortunately as this appears to be the default font, the effects are quite widespread in the
      tested applications that don't set the font themselves.

      An example of this rendering can be found here (I coundn't see any way to post images in the bug
      report form): <CAPTURE1.PNG><ATTACHED> - while the example is in a table, this appears everywhere and not
      just tables.

      I've gone through this in a debugger and think I've found the cause:

      The system default font as reported by fc-match is: DejaVuSans.ttf: "DejaVu Sans" "Book"

      This font has a subfamily of 'Book' but the full name is still only "DejaVu Sans" (for comparison, the
      bold variant has a subfamily of 'Bold' and it's included in the full name: "DejaVu Sans Bold"). Apparently
      as a result of the subfamily font-config is producing the full name "DejaVu Sans Book".

      Running fc-cat | grep 'DejaVu Sans Book' thus presents:

      "DejaVuSans.ttf" 0 "DejaVu Sans:familylang=en:style=Book:stylelang=en:fullname=DejaVu Sans Book:<other font rendering information>

      This then appears to make it's way into Java's font cache: ~/.java/fonts/16-ea/fcinfo-1-gearbox-Arch-rolling-en-NZ.properties
      sansserif.3.3.file=/usr/share/fonts/TTF/DejaVuSans.ttf
      sansserif.3.3.fullName=DejaVu Sans Book

      This causes a problem in CompositeFont.java:296 which checks the full name loaded from the TrueType file matches
      the corresponding name in the array passed to it's constructor:

      } else if (!componentNames[slot].equalsIgnoreCase(name)) {
      /* If a component specifies the file with a bad font,
      * the corresponding slot will be initialized by
      * default physical font. In such case findFont2D may
      * return composite font which cannot be casted to
      * physical font.
      */

      This makes it's way to getDefaultPhysicalFont. Unfortunately the font in question *is* the default physical
      font, and that causes SunFontManager.java:1042 to run:

      if (defaultPhysicalFont == null) {
      /* Because of the findFont2D call above, if we reach here, we
      * know all fonts have already been loaded, just accept any
      * match at this point. If this fails we are in real trouble
      * and I don't know how to recover from there being absolutely
      * no fonts anywhere on the system.
      */
      defaultPhysicalFont = physicalFonts.values().stream().findFirst()
      .orElseThrow(()->new Error("Probable fatal error: No physical fonts found."));
      }

      This ends up using "Noto Sans Devanagari UI Thin" as the default font, which contains arabic numerals
      but no latin characters. Since this is inside a CompositeFont those characters will fall through to the next
      font, which is "DejaVu Sans Bold" - the combination of thin and bold text leads to the visually jarring text
      shown above.


      Running "otfinfo /usr/share/fonts/TTF/DejaVuSans.ttf --info" shows that the 'Book' subfamily is not part
      of the full name:

      Family: DejaVu Sans
      Subfamily: Book
      Full name: DejaVu Sans
      PostScript name: DejaVuSans
      Preferred family: DejaVu Sans
      Preferred subfamily: Book
      Version: Version 2.37
      Unique ID: DejaVu Sans
      Manufacturer: DejaVu fonts team
      Vendor URL: http://dejavu.sourceforge.net
      Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
      Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
      DejaVu changes are in public domain

      The SHA256 hash of this file is 2fb91d8d18b8312659070e66001a863b82fb6758a21e37df2c94f1cae83683ed.

      Testing shows the following values are showing up to the CompositeFont constructor:

      Java 11:
      CompositeFont.component{File}Names start withs "/usr/share/fonts/TTF/DejaVuSans.ttf" and "DejaVu Sans"

      Java 16:
      CompositeFont.component{File}Names start withs "/usr/share/fonts/TTF/DejaVuSans.ttf" and "DejaVu Sans Book"
      CompositeFont.java:296 - componentNames[slot]="DejaVu Sans Book" while name="DejaVu Sans"

      This appears to be caused by JDK-8219901, which uses the full names rather than the family names of fonts.

      REGRESSION : Last worked in version 11

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Set DejaVu as the default system font on Linux - this is the default with ArchLinux and KDE.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Text should render using the selected default system font.
      ACTUAL -
      The characters are rendered using two different versions of the system fault: <CAPTURE2.PNG><ATTACHED>
      ---------- BEGIN SOURCE ----------
      import javax.swing.*;

      class Scratch {
          public static void main(String[] args) {
              JFrame frame = new JFrame("Hello World");
              frame.setContentPane(new JTextArea("Testing 1234 test abc123"));
              frame.pack();
              frame.setVisible(true);
          }
      }
      ---------- END SOURCE ----------

      FREQUENCY : always


        1. Capture2.PNG
          Capture2.PNG
          8 kB
        2. Scratch.java
          0.3 kB
        3. Capture1.PNG
          Capture1.PNG
          40 kB
        4. Test.PNG
          Test.PNG
          70 kB

            prr Philip Race
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: