/**
  * Returns a list of pairs of x coordinates for visual ranges representing given logical range. If
  * <code>startOffset == endOffset</code>, a pair of equal numbers is returned, corresponding to
  * target position. Target offsets are supposed to be located on the same visual line.
  */
 private TFloatArrayList logicalRangeToVisualRanges(int startOffset, int endOffset) {
   assert startOffset <= endOffset;
   TFloatArrayList result = new TFloatArrayList();
   for (VisualLineFragmentsIterator.Fragment fragment :
       VisualLineFragmentsIterator.create(myView, startOffset, false)) {
     int minOffset = fragment.getMinOffset();
     int maxOffset = fragment.getMaxOffset();
     if (startOffset == endOffset) {
       if (startOffset >= minOffset && startOffset <= maxOffset) {
         float x = fragment.offsetToX(startOffset);
         result.add(x);
         result.add(x);
         break;
       }
     } else if (startOffset < maxOffset && endOffset > minOffset) {
       float x1 = fragment.offsetToX(Math.max(minOffset, startOffset));
       float x2 = fragment.offsetToX(Math.min(maxOffset, endOffset));
       if (x1 > x2) {
         float tmp = x1;
         x1 = x2;
         x2 = tmp;
       }
       if (result.isEmpty() || x1 > result.get(result.size() - 1)) {
         result.add(x1);
         result.add(x2);
       } else {
         result.set(result.size() - 1, x2);
       }
     }
   }
   return result;
 }
  private void paintCaret(Graphics2D g_) {
    EditorImpl.CaretRectangle[] locations = myEditor.getCaretLocations(true);
    if (locations == null) return;

    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);
    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 = JBUI.scale(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 : x,
                isRtl ? x + lineWidth - CARET_DIRECTION_MARK_SIZE : x + CARET_DIRECTION_MARK_SIZE,
                isRtl ? x + lineWidth : x
              },
              new int[] {y, y, y + CARET_DIRECTION_MARK_SIZE},
              3);
        }
      } 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(), false)) {
            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;
            }
          }
        }
      }
    }
  }
 private void paintLineFragments(
     Graphics2D g, Rectangle clip, int visualLine, int y, LineFragmentPainter painter) {
   float x = visualLine == 0 ? myView.getPrefixTextWidthInPixels() : 0;
   int offset = myView.visualPositionToOffset(new VisualPosition(visualLine, 0));
   int visualLineEndOffset =
       myView.visualPositionToOffset(new VisualPosition(visualLine, Integer.MAX_VALUE, true));
   IterationState it = null;
   int prevEndOffset = -1;
   boolean firstFragment = true;
   int maxColumn = 0;
   for (VisualLineFragmentsIterator.Fragment fragment :
       VisualLineFragmentsIterator.create(myView, offset, false)) {
     int fragmentStartOffset = fragment.getStartOffset();
     int start = fragmentStartOffset;
     int end = fragment.getEndOffset();
     x = fragment.getStartX();
     if (firstFragment) {
       firstFragment = false;
       SoftWrap softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset);
       if (softWrap != null) {
         prevEndOffset = offset;
         it =
             new IterationState(
                 myEditor,
                 offset == 0 ? 0 : offset - 1,
                 visualLineEndOffset,
                 true,
                 false,
                 false,
                 false);
         if (it.getEndOffset() <= offset) {
           it.advance();
         }
         painter.paintBeforeLineStart(
             g,
             it.getStartOffset() == offset
                 ? it.getBeforeLineStartBackgroundAttributes()
                 : it.getMergedAttributes(),
             fragment.getStartVisualColumn(),
             fragment.getStartX(),
             y);
       }
     }
     FoldRegion foldRegion = fragment.getCurrentFoldRegion();
     if (foldRegion == null) {
       if (start != prevEndOffset) {
         it =
             new IterationState(
                 myEditor,
                 start,
                 fragment.isRtl() ? offset : visualLineEndOffset,
                 true,
                 false,
                 false,
                 fragment.isRtl());
       }
       prevEndOffset = end;
       assert it != null;
       while (fragment.isRtl() ? start > end : start < end) {
         if (fragment.isRtl() ? it.getEndOffset() >= start : it.getEndOffset() <= start) {
           assert !it.atEnd();
           it.advance();
         }
         TextAttributes attributes = it.getMergedAttributes();
         int curEnd =
             fragment.isRtl()
                 ? Math.max(it.getEndOffset(), end)
                 : Math.min(it.getEndOffset(), end);
         float xNew = fragment.offsetToX(x, start, curEnd);
         painter.paint(
             g,
             fragment,
             fragment.isRtl() ? fragmentStartOffset - start : start - fragmentStartOffset,
             fragment.isRtl() ? fragmentStartOffset - curEnd : curEnd - fragmentStartOffset,
             attributes,
             x,
             xNew,
             y);
         x = xNew;
         start = curEnd;
       }
     } else {
       float xNew = fragment.getEndX();
       painter.paint(
           g,
           fragment,
           0,
           fragment.getEndVisualColumn() - fragment.getStartVisualColumn(),
           getFoldRegionAttributes(foldRegion),
           x,
           xNew,
           y);
       x = xNew;
       prevEndOffset = -1;
       it = null;
     }
     maxColumn = fragment.getEndVisualColumn();
   }
   if (it == null || it.getEndOffset() != visualLineEndOffset) {
     it =
         new IterationState(
             myEditor,
             visualLineEndOffset == offset ? visualLineEndOffset : visualLineEndOffset - 1,
             visualLineEndOffset,
             true,
             false,
             false,
             false);
   }
   if (!it.atEnd()) {
     it.advance();
   }
   assert it.atEnd();
   painter.paintAfterLineEnd(g, clip, it, maxColumn, x, y);
 }