@@ -689,7 +689,7 @@ public void mergeDiacritic(TextPosition diacritic)
689689 break ;
690690 }
691691 float currCharXEnd = currCharXStart + widths [i ];
692-
692+
693693 // this is the case where there is an overlap of the diacritic character with the
694694 // current character and the previous character. If no previous character, just append
695695 // the diacritic after the current one
@@ -759,16 +759,25 @@ private void insertDiacritic(int i, TextPosition diacritic)
759759 float [] widths2 = new float [widths .length + 1 ];
760760 System .arraycopy (widths , 0 , widths2 , 0 , i );
761761
762+ // First we add a zero-width entry for the diacritic in the widths array
763+ widths2 [i ] = widths [i ];
764+ widths2 [i + 1 ] = 0 ;
765+ System .arraycopy (widths , i + 1 , widths2 , i + 2 , widths .length - i - 1 );
766+
762767 // Unicode combining diacritics always go after the base character, regardless of whether
763768 // the string is in presentation order or logical order
764769 sb .append (unicode .charAt (i ));
765- widths2 [i ] = widths [i ];
770+
771+ // If a surrogate starts at the current position, make sure we preserve it
772+ if (i < unicode .length () - 1 && Character .isSurrogatePair (unicode .charAt (i ), unicode .charAt (i + 1 ))) {
773+ sb .append (unicode .charAt (i + 1 ));
774+ i ++;
775+ }
776+
766777 sb .append (combineDiacritic (diacritic .getUnicode ()));
767- widths2 [i + 1 ] = 0 ;
768778
769779 // get the rest of the string
770780 sb .append (unicode .substring (i + 1 ));
771- System .arraycopy (widths , i + 1 , widths2 , i + 2 , widths .length - i - 1 );
772781
773782 unicode = sb .toString ();
774783 widths = widths2 ;
0 commit comments