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

Wrong display of NFD normalized UTF characters on Linux and OS X

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • 8u45
    • javafx
    • Linux Mint 17 Cinnamon 64-bit, Cinnamon-Version 2.2.16, Linux-Kernel 3.13.0-24-generic
      and
      Mac OS X 10.9.5, iMac, 2010

      We display Strings using a JavaFX Label control with Java 8u45. Some of the data we display uses NFD normalized characters and some is NFC normalized.

      For instance the NFC representation of the character "ü" (german umlaut ü) is "c3 bc" while the NFD representation is "75 cc 88" - both are valid UTF-8 encodings of the german umlaut "ü" and both should render as a valid "ü" character.

      The display is correct when we run our application on Windows.

      However with Linux and OS X the rendered character data seems to be different DEPENDING on the way we load the javafx.scene.text.Font resource!

      If we directly load the TTF font file using:

      Font font1 = Font.loadFont(Main.class.getResource("/fonts/OpenSans-Regular.ttf").toExternalForm(), 14);

      we get a different display of the characters as when we would load the font and later request it with the font family name, f.i.:

      Font font3 = Font.font("Open Sans", 14);

      Please note that we first load the font using Font.loadFont() (first line above) and later reference the same font using it's font family name "Open Sans". Which should, from our understanding, get us the same font since the loadFont method call registered the font data within JavaFX (according to the JavaDoc of the loadFont method).

      However, we see different results and a wrong display in some cases as illustrated in the following image: http://i.imgur.com/keu6cTX.png when we run our application on Linux or OS X!

      When we further inspect both Fonts we can see that they both use a nativeFont instance of "PrismFont". However the Font resolved via the font family name uses an internal fontResource of "PrismCompositeFontResource" while the directly loaded font uses a CTFontFile directly. (see second screenshot from the debugger: http://i.imgur.com/mOsZK3F.png) Maybe this is a cause why we see different character displayed?

      Independenly of the way we load the font and if it is normalized as NFD or NFC we would expect the same rendering result!

      A SSCCE source is attached below which requires the font we've linked below as well:

      -----

      package com.example.font;

      import javafx.application.Application;
      import javafx.geometry.Insets;
      import javafx.scene.Scene;
      import javafx.scene.control.Label;
      import javafx.scene.layout.VBox;
      import javafx.scene.text.Font;
      import javafx.stage.Stage;

      import java.nio.ByteBuffer;
      import java.nio.charset.CharacterCodingException;
      import java.nio.charset.Charset;
      import java.nio.charset.CharsetDecoder;

      public class Main extends Application {

          public static void main(final String[] args) {
              launch(args);
          }

          @Override
          public void start(final Stage stage) throws Exception {
              String vowelString = getVowelString();

              Label label1 = new Label(vowelString);
              Font font1 = Font.loadFont(Main.class.getResource("/fonts/OpenSans-Regular.ttf").toExternalForm(), 14);
              label1.setFont(font1);

              // load global font
              Label label2 = new Label(vowelString);
              Font font3 = Font.font("Open Sans", 14);
              label2.setFont(font3);

              VBox vbox = new VBox();
              vbox.getChildren().addAll(label1, label2);
              vbox.setPadding(new Insets(10));

              Scene scene = new Scene(vbox);
              // applyCssSkin(scene);

              stage.setScene(scene);
              stage.setWidth(100);
              stage.setHeight(100);
              stage.show();
          }

          private String getVowelString() throws CharacterCodingException {
              byte[] hex = new byte[] { (byte) 0xC3, (byte) 0xBC, (byte) 0x20, (byte) 0x75, (byte) 0xCC, (byte) 0x88 };
              CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
              return decoder.decode(ByteBuffer.wrap(hex)).toString();
          }
      }

      -----

      Open Sans Font:
      https://www.google.com/fonts#UsePlace:use/Collection:Open+Sans

      Direct Download:
      https://www.google.com/fonts/download?kit=3hvsV99qyKCBS55e5pvb3ltkqrIMaAZWyLYEoB48lSQ

            prr Philip Race
            jhohmuthjfx Jens Hohmuth (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Imported: