diff --git a/editor.lib/src/org/netbeans/editor/DrawEngineLineView.java b/editor.lib/src/org/netbeans/editor/DrawEngineLineView.java --- a/editor.lib/src/org/netbeans/editor/DrawEngineLineView.java +++ b/editor.lib/src/org/netbeans/editor/DrawEngineLineView.java @@ -52,6 +52,7 @@ import javax.swing.text.Element; import javax.swing.text.JTextComponent; import javax.swing.text.Position; +import javax.swing.text.Position.Bias; import javax.swing.text.View; import javax.swing.text.ViewFactory; import org.netbeans.editor.view.spi.EstimatedSpanView; @@ -894,5 +895,40 @@ } } // End of FragmentView class - + + // #164820 + @Override + public int getNextVisualPositionFrom(int pos, Bias b, Shape a, int direction, Bias[] biasRet) throws BadLocationException { + + switch (direction) { + case WEST: + { + pos = super.getNextVisualPositionFrom(pos, b, a, direction, biasRet); + char[] chars = getDocument().getText(pos, 1).toCharArray(); + if (chars.length > 0 && Character.isLowSurrogate(chars[0])) { + // Supplementary character + return super.getNextVisualPositionFrom(pos, b, a, direction, biasRet); + } + } + break; + + case EAST: + { + pos = super.getNextVisualPositionFrom(pos, b, a, direction, biasRet); + char[] chars = getDocument().getText(pos, 1).toCharArray(); + if (chars.length > 0 && Character.isLowSurrogate(chars[0])) { + // Supplementary character + return super.getNextVisualPositionFrom(pos, b, a, direction, biasRet); + } + } + break; + + default: + pos = super.getNextVisualPositionFrom(pos, b, a, direction, biasRet); + break; + } + + return pos; + } + } diff --git a/editor.lib/src/org/netbeans/editor/Mark.java b/editor.lib/src/org/netbeans/editor/Mark.java --- a/editor.lib/src/org/netbeans/editor/Mark.java +++ b/editor.lib/src/org/netbeans/editor/Mark.java @@ -47,6 +47,7 @@ import javax.swing.text.BadLocationException; import javax.swing.text.Element; import javax.swing.text.Position; +import javax.swing.text.Position.Bias; /** * Marks hold the relative position in the document. @@ -109,9 +110,25 @@ + ", class=" + this.getClass()); // NOI18N } - if (offset < 0 || offset > ldoc.getLength() + 1) { // doc.getEndPosition() is valid - throw new BadLocationException("Invalid offset", offset); // NOI18N - } + if (offset < 0 || offset > ldoc.getLength() + 1) { // doc.getEndPosition() is valid + throw new BadLocationException("Invalid offset", offset); // NOI18N + } + + // Deal with supplementary characters #164820 + char[] chars = doc.getText(offset, 1).toCharArray(); + if (chars.length > 0 && Character.isLowSurrogate(chars[0])) { + if (bias == Bias.Forward && offset < ldoc.getLength()) { + offset++; + + } else if (bias == Bias.Backward && offset > 0) { + offset--; + } + + // If there is still a low surrogate after recalculating, + // treat it as an invalid document, just ignore and pass through. + // Since there should be a surrogate pair in Java and Unicode to + // represent a supplementary character. + } multiMark = doc.marksStorage.createBiasMark(offset, bias); doc.marksStorage.insert(multiMark); diff --git a/editor.lib/src/org/netbeans/editor/Utilities.java b/editor.lib/src/org/netbeans/editor/Utilities.java --- a/editor.lib/src/org/netbeans/editor/Utilities.java +++ b/editor.lib/src/org/netbeans/editor/Utilities.java @@ -355,18 +355,38 @@ int best = findBestSpan(c, start, end, x); if (best= 0){ - return nextVisualPosition; - } + // #164820 + // We are in the collapsed fold, now try to find which position + // is the best, whether foldEnd or foldStart + tempRect = c.modelToView(nextVisualPosition); + if (tempRect == null) { + return nextVisualPosition; + } + int leftX = tempRect.x; + int nextVisualPositionRight = c.getUI().getNextVisualPositionFrom(c, + nextVisualPosition, javax.swing.text.Position.Bias.Forward, javax.swing.SwingConstants.EAST, null); + tempRect = c.modelToView(nextVisualPositionRight); + if (tempRect == null) { + return nextVisualPosition; + } + int rightX = tempRect.x; + + if (Math.abs(leftX - x) < Math.abs(rightX - x)) { + return nextVisualPosition; + } else { + return nextVisualPositionRight; + } + } } - + return best; - } - + } + /** Get the position that is one line above and visually at some * x-coordinate value. * @param c text component to operate on