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

Inconsistent Character Rendering of Bidirectional Strings

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      Tested on MacOS 14.5 and Windows 10 pro with Java 21.0.4

      A DESCRIPTION OF THE PROBLEM :
      Both plain text and html rendering of string mixing arabic and latin characters in JLabel is inconsistent.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached application and look at the application window.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The text should be displayed in the same way in all components having the same component orientation including JLabels. They should contain no line breaks.
      ACTUAL -
      No JLabel can draw the characters in the same order as the left-to-right text editor components.
      Additionally, JLabels rendering HTML display unexpected line breaks.

      ---------- BEGIN SOURCE ----------
      import java.awt.ComponentOrientation;
      import java.awt.Font;

      import javax.swing.BorderFactory;
      import javax.swing.Box;
      import javax.swing.BoxLayout;
      import javax.swing.JEditorPane;
      import javax.swing.JFrame;
      import javax.swing.JLabel;
      import javax.swing.JTextField;
      import javax.swing.SwingUtilities;
      import javax.swing.event.DocumentEvent;
      import javax.swing.event.DocumentListener;

      public class CharacterOrderDemo extends JFrame {
          // The Arabic letters are located at the middle of the string after letter 'a' and space.
          // They start with letter 'ا' that appears at the right because of the character direction.
          // They are followed by space and latin letters 'b' and 'c'.
          final static String INITIAL_TEXT = "a ابب بب bc";
          private final JTextField textField;
          private final JLabel label;
          private final JEditorPane htmlEditorPane;
          private final JLabel htmlLabel;
          private final JTextField rtlTextField;
          private final JLabel rtlLabel;
          private final JEditorPane rtlHtmlEditorPane;
          private final JLabel rtlHtmlLabel;
          public CharacterOrderDemo() {
              textField = new JTextField();

              rtlTextField = new JTextField();

              htmlEditorPane = new JEditorPane("text/html", "");
              htmlEditorPane.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, true);

              rtlHtmlEditorPane = new JEditorPane("text/html", "");
              rtlHtmlEditorPane.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, true);

              label = new JLabel();
              rtlLabel = new JLabel();
              htmlLabel = new JLabel();
              rtlHtmlLabel = new JLabel();

              label.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
              htmlEditorPane.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
              textField.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
              textField.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);

              rtlTextField.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
              rtlLabel.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
              rtlHtmlEditorPane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
              rtlHtmlLabel.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

              textField.setAlignmentX(CENTER_ALIGNMENT);
              label.setAlignmentX(CENTER_ALIGNMENT);
              htmlEditorPane.setAlignmentX(CENTER_ALIGNMENT);
              htmlLabel.setAlignmentX(CENTER_ALIGNMENT);

              rtlTextField.setAlignmentX(CENTER_ALIGNMENT);
              rtlLabel.setAlignmentX(CENTER_ALIGNMENT);
              rtlHtmlEditorPane.setAlignmentX(CENTER_ALIGNMENT);
              rtlHtmlLabel.setAlignmentX(CENTER_ALIGNMENT);

              Font font = label.getFont().deriveFont(32.0f);
              label.setFont(font);
              textField.setFont(font);
              htmlEditorPane.setFont(font);
              htmlLabel.setFont(font);
              rtlLabel.setFont(font);
              rtlTextField.setFont(font);
              rtlHtmlEditorPane.setFont(font);
              rtlHtmlLabel.setFont(font);

              label.setBorder(BorderFactory.createTitledBorder("ltrLabel"));
              textField.setBorder(BorderFactory.createTitledBorder("ltrTextField"));
              htmlEditorPane.setBorder(BorderFactory.createTitledBorder("ltrHtmlField"));
              htmlLabel.setBorder(BorderFactory.createTitledBorder("ltrHtmlLabel"));
              rtlLabel.setBorder(BorderFactory.createTitledBorder("rtlLabel"));
              rtlTextField.setBorder(BorderFactory.createTitledBorder("rtlTextField"));
              rtlHtmlEditorPane.setBorder(BorderFactory.createTitledBorder("rtlHtmlEditorPane"));
              rtlHtmlLabel.setBorder(BorderFactory.createTitledBorder("rtlHtmlLabel"));

              rtlHtmlEditorPane.setEditable(false);
              htmlEditorPane.setEditable(false);
              textField.setEditable(false);


              setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
              add(rtlTextField);
              add(rtlLabel);
              add(rtlHtmlEditorPane);
              add(rtlHtmlLabel);
              add(Box.createVerticalStrut(40));
              add(textField);
              add(label);
              add(htmlLabel);
              add(htmlEditorPane);

              rtlTextField.setText(INITIAL_TEXT);
              update();

              rtlTextField.getDocument().addDocumentListener(new DocumentListener() {
                  public void insertUpdate(DocumentEvent e) {
                      update();
                  }
                  public void removeUpdate(DocumentEvent e) {
                      update();
                  }
                  public void changedUpdate(DocumentEvent e) {
                      update();
                  }
              });

              setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              setVisible(true);
          }

          private void update() {
              String text = rtlTextField.getText();
              label.setText(text);
              textField.setText(text);
              htmlEditorPane.setText("<html><body><p>" + text);
              htmlLabel.setText("<html><body><p>" + text);

              rtlLabel.setText(text);
              rtlHtmlEditorPane.setText("<html><body><p>" + text);
              rtlHtmlLabel.setText("<html><body><p>" + text);

              SwingUtilities.invokeLater(() -> pack());
          }
          public static void main(String[] args) {
              new CharacterOrderDemo();
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      No workaround is known.

        1. CharacterOrderDemo.java
          5 kB
        2. Img_MacOS.png
          Img_MacOS.png
          88 kB
        3. Img_Win11.png
          Img_Win11.png
          36 kB

            psadhukhan Prasanta Sadhukhan
            pnarayanaswa Praveen Narayanaswamy
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: