/**
  * 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 paintVirtualSelectionIfNecessary(
     Graphics2D g,
     Map<Integer, Couple<Integer>> virtualSelectionMap,
     int columnStart,
     float xStart,
     float xEnd,
     int y) {
   int visualLine = myView.yToVisualLine(y);
   Couple<Integer> selectionRange = virtualSelectionMap.get(visualLine);
   if (selectionRange == null || selectionRange.second <= columnStart) return;
   float startX =
       selectionRange.first <= columnStart
           ? xStart
           : myView.visualPositionToXY(new VisualPosition(visualLine, selectionRange.first)).x;
   float endX =
       Math.min(
           xEnd,
           myView.visualPositionToXY(new VisualPosition(visualLine, selectionRange.second)).x);
   paintBackground(
       g,
       myEditor.getColorsScheme().getColor(EditorColors.SELECTION_BACKGROUND_COLOR),
       startX,
       y,
       endX - startX);
 }
  private void paintComposedTextDecoration(Graphics2D g) {
    TextRange composedTextRange = myEditor.getComposedTextRange();
    if (composedTextRange != null) {
      Point p1 =
          myView.offsetToXY(
              Math.min(composedTextRange.getStartOffset(), myDocument.getTextLength()),
              true,
              false);
      Point p2 =
          myView.offsetToXY(
              Math.min(composedTextRange.getEndOffset(), myDocument.getTextLength()), false, true);

      int y = p1.y + myView.getAscent() + 1;

      g.setStroke(IME_COMPOSED_TEXT_UNDERLINE_STROKE);
      g.setColor(myEditor.getColorsScheme().getDefaultForeground());
      UIUtil.drawLine(g, p1.x, y, p2.x, y);
    }
  }
  private void paintLineMarkerSeparator(RangeHighlighter marker, Rectangle clip, Graphics g) {
    Color separatorColor = marker.getLineSeparatorColor();
    LineSeparatorRenderer lineSeparatorRenderer = marker.getLineSeparatorRenderer();
    if (separatorColor == null && lineSeparatorRenderer == null) {
      return;
    }
    int line =
        myDocument.getLineNumber(
            marker.getLineSeparatorPlacement() == SeparatorPlacement.TOP
                ? marker.getStartOffset()
                : marker.getEndOffset());
    int visualLine =
        myView.logicalToVisualPosition(
                new LogicalPosition(
                    line + (marker.getLineSeparatorPlacement() == SeparatorPlacement.TOP ? 0 : 1),
                    0),
                false)
            .line;
    int y = myView.visualLineToY(visualLine) - 1;
    int endShift = clip.x + clip.width;
    EditorSettings settings = myEditor.getSettings();
    if (settings.isRightMarginShown()
        && myEditor.getColorsScheme().getColor(EditorColors.RIGHT_MARGIN_COLOR) != null) {
      endShift =
          Math.min(
              endShift,
              settings.getRightMargin(myEditor.getProject()) * myView.getPlainSpaceWidth());
    }

    g.setColor(separatorColor);
    if (lineSeparatorRenderer != null) {
      lineSeparatorRenderer.drawLine(g, 0, endShift, y);
    } else {
      UIUtil.drawLine(g, 0, y, endShift, y);
    }
  }
 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);
 }