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

Wrong caret position with character with multiple combining diacritical marks

XMLWordPrintable

      A DESCRIPTION OF THE PROBLEM :
      If the text in a JTextComponent contains a character with multiple combining diacritical marks, this prevents correct caret positioning. Navigation of the caret with the left and right arrow keys breaks when such character is encountered, e.g. the caret jumps to the end of the text when navigating from left to right. Positioning of the caret with a mouse click also doesn't work in such case. This makes it impossible to select or edit part of the text.

      REGRESSION : Last worked in version 8u401

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Add a JTextField to a JFrame, with the following text,
      \u0063\u0064\u0065\u0301\u0020\u0063\u0062\u0061\u0328\u0304\u0301\u0020\u0067\u0068\u0069\u0304\u002e
      place the caret before the first character and use the RIGHT arrow to navigate the caret to the right until it jumps to the end.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      On every keystroke the caret is expected to move one position in the text.
      ACTUAL -
      When the caret is just before the character with more than one combining diacritical mark, the next right arrow keystroke causes the caret to jump to the end of the text instead of moving one position forward.

      ---------- BEGIN SOURCE ----------

      import java.awt.*;
      import java.awt.event.*;
      import java.lang.reflect.InvocationTargetException;

      import javax.swing.*;
      import javax.swing.border.*;
      import javax.swing.text.JTextComponent;

      /**
       * A class to demonstrate incorrect caret navigation in text components
       * containing characters with multiple combining diacritical marks.
       */
      public class CaretTest {

          public static void main(final String[] argum) {
           System.out.println("Java version: " + System.getProperty("java.version"));
           try {
      EventQueue.invokeAndWait(new Runnable() {
      @Override
      public void run() {
      createFrame();
      }
      });
           } catch (InterruptedException | InvocationTargetException e) {
           e.printStackTrace();
           }
          }
          
          public static void createFrame() {
           JFrame frame = new JFrame("Caret - diacritical marks test");
           frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
          
           String testText = "\u0063\u0064\u0065\u0301\u0020\u0063\u0062\u0061\u0328\u0304\u0301\u0020\u0067\u0068\u0069\u0304\u002e";
           JTextField textField = new JTextField(testText);
           JTextArea textArea = new JTextArea(testText);
          
           frame.getContentPane().add(textField, BorderLayout.PAGE_START);
           frame.getContentPane().add(textArea, BorderLayout.CENTER);
          
           Border border = new CompoundBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5), textField.getBorder());
           textField.setBorder(border);
           textArea.setBorder(border);
          
           frame.setSize(400, 200);
           frame.setVisible(true);
          
           // start a Robot to move the caret forward and backward with right and left arrow keys
           // the error condition: the caret position sequence is 0,1,2,3,4,5,6,7,17 and back again
           new Thread(new Runnable() {
           public void run() {
      try {
      textField.setCaretPosition(0);
      JTextComponent focusComponent = textField;
      int event = KeyEvent.VK_RIGHT;
      Robot robot = new Robot();
      robot.setAutoDelay(500);
      robot.waitForIdle();
      // to show the effect with shift key, selecting part of the text
      // robot.keyPress(KeyEvent.VK_SHIFT);

      // loop until the frame is closed
      while (true) {
      System.out.println(focusComponent.getCaretPosition() + " of " + testText.length());
      robot.keyPress(event);

      if (focusComponent.getCaretPosition() == testText.length()) {
      event = KeyEvent.VK_LEFT;
      } else if (focusComponent.getCaretPosition() == 0) {
      // transfer the focus to the other component
      focusComponent = focusComponent == textField ? textArea : textField;
      focusComponent.requestFocus();
      event = KeyEvent.VK_RIGHT;
      robot.delay(500);
      }
      }
      } catch (AWTException ae) {
      ae.printStackTrace();
      }
           }
           }).start();
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Haven't found one.
      Not sure if this is relevant, but in the array of 'valid' characters named 'charIndices' (e.g. in StandardGlyphVector in caretAtOffsetIsValid() in ExtendedTextSourceLabel), the indices of single combining diacritical marks are left out, but of a sequence of combining diacritical marks only the index of the first one is left out.

      FREQUENCY : always


            psadhukhan Prasanta Sadhukhan
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated: