diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 23585e4d1588..0ceed06ffbbe 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -4607,10 +4607,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi private void setCursorPosition() { final List caretPoints = new ArrayList(); for (Caret caret : getCaretModel().getAllCarets()) { + boolean isRtl = myUseNewRendering && myView.isRtlLocation(caret.getOffset()); VisualPosition caretPosition = caret.getVisualPosition(); Point pos1 = visualPositionToXY(caretPosition); - Point pos2 = visualPositionToXY(new VisualPosition(caretPosition.line, caretPosition.column + 1)); - caretPoints.add(new CaretRectangle(pos1, pos2.x - pos1.x, caret)); + Point pos2 = visualPositionToXY(new VisualPosition(caretPosition.line, Math.max(0, caretPosition.column + (isRtl ? -1 : 1)))); + caretPoints.add(new CaretRectangle(pos1, Math.abs(pos2.x - pos1.x), caret, isRtl)); } myCaretCursor.setPositions(caretPoints.toArray(new CaretRectangle[caretPoints.size()])); } @@ -4681,11 +4682,13 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi public final Point myPoint; public final int myWidth; public final Caret myCaret; + public final boolean myIsRtl; - private CaretRectangle(Point point, int width, Caret caret) { + private CaretRectangle(Point point, int width, Caret caret, boolean isRtl) { myPoint = point; myWidth = Math.max(width, 2); myCaret = caret; + myIsRtl = isRtl; } } @@ -4698,7 +4701,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi private long myStartTime = 0; private CaretCursor() { - myLocations = new CaretRectangle[] {new CaretRectangle(new Point(0, 0), 0, null)}; + myLocations = new CaretRectangle[] {new CaretRectangle(new Point(0, 0), 0, null, false)}; setEnabled(true); } @@ -4743,8 +4746,13 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } private void repaint() { - for (CaretRectangle location : myLocations) { - myEditorComponent.repaintEditorComponent(location.myPoint.x, location.myPoint.y, location.myWidth, getLineHeight()); + if (myUseNewRendering) { + myView.repaintCarets(); + } + else { + for (CaretRectangle location : myLocations) { + myEditorComponent.repaintEditorComponent(location.myPoint.x, location.myPoint.y, location.myWidth, getLineHeight()); + } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java index 6ea3468366bf..e3b6dbd2fe90 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java @@ -52,6 +52,7 @@ class EditorPainter { private static final Color CARET_DARK = Gray._0; private static final Stroke IME_COMPOSED_TEXT_UNDERLINE_STROKE = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, new float[]{0, 2, 0, 2}, 0); + private static final int CARET_DIRECTION_MARK_SIZE = 5; private final EditorView myView; private final EditorImpl myEditor; @@ -636,46 +637,69 @@ class EditorPainter { } } - private void paintCaret(Graphics2D g) { + private void paintCaret(Graphics2D g_) { EditorImpl.CaretRectangle[] locations = myEditor.getCaretLocations(); if (locations == null) return; - for (EditorImpl.CaretRectangle location : locations) { - paintCaretAt(g, location.myPoint.x, location.myPoint.y, location.myWidth, location.myCaret); - } - } - - private void paintCaretAt(Graphics2D g_, int x, int y, int width, Caret caret) { + Graphics2D g = IdeBackgroundUtil.getOriginalGraphics(g_); int lineHeight = myView.getLineHeight(); EditorSettings settings = myEditor.getSettings(); Color caretColor = myEditor.getColorsScheme().getColor(EditorColors.CARET_COLOR); if (caretColor == null) caretColor = new JBColor(CARET_DARK, CARET_LIGHT); g.setColor(caretColor); - - if (myEditor.isInsertMode() != settings.isBlockCursor()) { - if (UIUtil.isRetina()) { - g.fillRect(x, y, settings.getLineCursorWidth(), lineHeight); - } else { - for (int i = 0; i < settings.getLineCursorWidth(); i++) { - UIUtil.drawLine(g, x + i, y, x + i, y + lineHeight - 1); + for (EditorImpl.CaretRectangle location : locations) { + int x = location.myPoint.x; + int y = location.myPoint.y; + Caret caret = location.myCaret; + boolean isRtl = location.myIsRtl; + if (myEditor.isInsertMode() != settings.isBlockCursor()) { + int lineWidth = settings.getLineCursorWidth(); + g.fillRect(x, y, lineWidth, lineHeight); + if (myDocument.getTextLength() > 0 && caret != null && !myView.getLineLayout(caret.getLogicalPosition().line).isLtr()) { + g.fillPolygon(new int[]{ + isRtl ? x + lineWidth - 1 : x, + isRtl ? x + lineWidth - 1 - CARET_DIRECTION_MARK_SIZE : x + CARET_DIRECTION_MARK_SIZE, + isRtl ? x + lineWidth - 1 : x + }, + new int[]{y, y, y + CARET_DIRECTION_MARK_SIZE}, 3); } } - } - else { - g.fillRect(Math.min(x, x + width), y, Math.abs(width), lineHeight - 1); - int targetVisualColumn = caret.getVisualPosition().column; - for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, caret.getVisualLineStart())) { - int startVisualColumn = fragment.getStartVisualColumn(); - int endVisualColumn = fragment.getEndVisualColumn(); - if (startVisualColumn <= targetVisualColumn && endVisualColumn > targetVisualColumn) { - g.setColor(ColorUtil.isDark(caretColor) ? CARET_LIGHT : CARET_DARK); - fragment.draw(g, x, y + myView.getAscent(), targetVisualColumn - startVisualColumn, targetVisualColumn - startVisualColumn + 1); - break; + else { + int width = location.myWidth; + int startX = Math.max(0, isRtl ? x - width : x); + g.fillRect(startX, y, width, lineHeight - 1); + if (myDocument.getTextLength() > 0 && caret != null) { + int targetVisualColumn = caret.getVisualPosition().column; + for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, caret.getVisualLineStart())) { + int startVisualColumn = fragment.getStartVisualColumn(); + int endVisualColumn = fragment.getEndVisualColumn(); + if (startVisualColumn < targetVisualColumn && endVisualColumn > targetVisualColumn || + startVisualColumn == targetVisualColumn && !isRtl || + endVisualColumn == targetVisualColumn && isRtl) { + g.setColor(ColorUtil.isDark(caretColor) ? CARET_LIGHT : CARET_DARK); + fragment.draw(g, startX, y + myView.getAscent(), + targetVisualColumn - startVisualColumn - (isRtl ? 1 : 0), + targetVisualColumn - startVisualColumn + (isRtl ? 0 : 1)); + break; + } + } } } } } - + + void repaintCarets() { + EditorImpl.CaretRectangle[] locations = myEditor.getCaretLocations(); + if (locations == null) return; + int lineHeight = myView.getLineHeight(); + for (EditorImpl.CaretRectangle location : locations) { + int x = location.myPoint.x; + int y = location.myPoint.y; + int width = Math.max(location.myWidth, CARET_DIRECTION_MARK_SIZE); + myEditor.getContentComponent().repaintEditorComponent(x - width, y, width * 2, lineHeight); + } + } + private void paintLineFragments(Graphics2D g, Rectangle clip, int visualLine, int y, LineFragmentPainter painter) { float x = visualLine == 0 ? myView.getPrefixTextWidthInPixels() : 0; LogicalPosition logicalPosition = myView.visualToLogicalPosition(new VisualPosition(visualLine, 0), false); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java index b04acf2a9523..f6a227f9d1a7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java @@ -198,6 +198,11 @@ public class EditorView implements Disposable { myPainter.paint(g); } + public void repaintCarets() { + assertIsDispatchThread(); + myPainter.repaintCarets(); + } + public Dimension getPreferredSize() { assertIsDispatchThread(); return mySizeManager.getPreferredSize(); @@ -254,6 +259,13 @@ public class EditorView implements Disposable { mySizeManager.reset(); myTextLayoutCache.resetToDocumentSize(); } + + public boolean isRtlLocation(int offset) { + if (myDocument.getTextLength() == 0) return false; + int line = myDocument.getLineNumber(offset); + LineLayout layout = getLineLayout(line); + return layout.isRtlLocation(offset - myDocument.getLineStartOffset(line)); + } @NotNull LineLayout getLineLayout(int line) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java index 51141ad70473..b4c92e682557 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java @@ -200,6 +200,17 @@ class LineLayout { }; } + boolean isLtr() { + return myBidiRunsInLogicalOrder.length == 0 || myBidiRunsInLogicalOrder.length == 1 && !myBidiRunsInLogicalOrder[0].isRtl(); + } + + boolean isRtlLocation(int offset) { + for (BidiRun run : myBidiRunsInLogicalOrder) { + if (offset < run.endOffset) return run.isRtl(); + } + return false; + } + private static class BidiRun { private final byte level; private final int startOffset;