VisualPosition (@NotNull Point p) { if (myUseNewRendering) return myView.xyToVisualPosition(p); int line = yPositionToVisibleLine(Math.max(p.y, 0)); int px = p.x; if (line == 0 && myPrefixText != null) { px -= myPrefixWidthInPixels; } if (px < 0) { px = 0; } int textLength = myDocument.getTextLength(); LogicalPosition logicalPosition = visualToLogicalPosition(new VisualPosition(line, 0)); int offset = logicalPositionToOffset(logicalPosition); int plainSpaceSize = EditorUtil.getSpaceWidth(Font.PLAIN, this); if (offset >= textLength) return new VisualPosition(line, EditorUtil.columnsNumber(px, plainSpaceSize)); // There is a possible case that starting logical line is split by soft-wraps and it's part after the split should be drawn. // We mark that we're under such circumstances then. boolean activeSoftWrapProcessed = logicalPosition.softWrapLinesOnCurrentLogicalLine <= 0; CharSequence text = myDocument.getImmutableCharSequence(); LogicalPosition endLogicalPosition = visualToLogicalPosition(new VisualPosition(line + 1, 0)); int endOffset = logicalPositionToOffset(endLogicalPosition); if (offset > endOffset) { LogMessageEx.error(LOG, "Detected invalid (x; y)->VisualPosition processing", String.format( "Given point: %s, mapped to visual line %d. Visual(%d; %d) is mapped to " + "logical position '%s' which is mapped to offset %d (start offset). Visual(%d; %d) is mapped to logical '%s' which is mapped " + "to offset %d (end offset). State: %s", p, line, line, 0, logicalPosition, offset, line + 1, 0, endLogicalPosition, endOffset, dumpState() )); return new VisualPosition(line, EditorUtil.columnsNumber(px, plainSpaceSize)); } IterationState state = new IterationState(this, offset, endOffset, false); int fontType = state.getMergedAttributes().getFontType(); int x = 0; int charWidth; boolean onSoftWrapDrawing = false; char c = ' '; int prevX = 0; int column = 0; outer: while (true) { charWidth = -1; if (offset >= textLength) { break; } if (offset >= state.getEndOffset()) { state.advance(); fontType = state.getMergedAttributes().getFontType(); } SoftWrap softWrap = mySoftWrapModel.getSoftWrap(offset); if (softWrap != null) { if (activeSoftWrapProcessed) { prevX = x; charWidth = getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED); x += charWidth; if (x >= px) { onSoftWrapDrawing = true; } else { column++; } break; } else { CharSequence softWrapText = softWrap.getText(); for (int i = 1/*Assuming line feed is located at the first position*/; i < softWrapText.length(); i++) { c = softWrapText.charAt(i); prevX = x; charWidth = charToVisibleWidth(c, fontType, x); x += charWidth; if (x >= px) { break outer; } column += EditorUtil.columnsNumber(c, x, prevX, plainSpaceSize); } // Process 'after soft wrap' sign. prevX = x; charWidth = mySoftWrapModel.getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP); x += charWidth; if (x >= px) { onSoftWrapDrawing = true; break; } column++; activeSoftWrapProcessed = true; } } FoldRegion region = state.getCurrentFold(); if (region != null) { char[] placeholder = region.getPlaceholderText().toCharArray(); for (char aPlaceholder : placeholder) { c = aPlaceholder; x += EditorUtil.charWidth(c, fontType, this); if (x >= px) { break outer; } column++; } offset = region.getEndOffset(); } else { prevX = x; c = text.charAt(offset); if (c == '\n') { break; } charWidth = charToVisibleWidth(c, fontType, x); x += charWidth; if (x >= px) { break; } column += EditorUtil.columnsNumber(c, x, prevX, plainSpaceSize); offset++; } } if (charWidth < 0) { charWidth = EditorUtil.charWidth(c, fontType, this); } if (charWidth < 0) { charWidth = plainSpaceSize; } if (x >= px && c == '\t' && !onSoftWrapDrawing) { if (mySettings.isCaretInsideTabs()) { column += (px - prevX) / plainSpaceSize; if ((px - prevX) % plainSpaceSize > plainSpaceSize / 2) column++; } else if ((x - px) * 2 < x - prevX) { column += EditorUtil.columnsNumber(c, x, prevX, plainSpaceSize); } } else { if (x >= px) { if (c != '\n' && (x - px) * 2 < charWidth) column++; } else { int diff = px - x; column += diff / plainSpaceSize; if (diff % plainSpaceSize * 2 >= plainSpaceSize) { column++; } } } return new VisualPosition(line, column); }