private void paintLineFragments(VisualLinesIterator visLineIterator,
                                    int y,
                                    LineFragmentPainter painter,
                                    MarginWidthConsumer marginWidthConsumer) {
      int visualLine = visLineIterator.getVisualLine();
      float x = myCorrector.startX(visualLine) + (visualLine == 0 ? myView.getPrefixTextWidthInPixels() : 0);
      int offset = visLineIterator.getVisualLineStartOffset();
      int visualLineEndOffset = visLineIterator.getVisualLineEndOffset();
      IterationState it = null;
      int prevEndOffset = -1;
      boolean firstFragment = true;
      int maxColumn = 0;
      int endLogicalLine = visLineIterator.getEndLogicalLine();
      boolean marginReached = false;
      for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visLineIterator, null, true)) {
        int fragmentStartOffset = fragment.getStartOffset();
        int start = fragmentStartOffset;
        int end = fragment.getEndOffset();
        x = fragment.getStartX();
        if (firstFragment) {
          firstFragment = false;
          SoftWrap softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset);
          boolean hasSoftWrap = softWrap != null;
          if (hasSoftWrap || myEditor.isRightAligned()) {
            prevEndOffset = offset;
            it = new IterationState(myEditor, offset == 0 ? 0 : DocumentUtil.getPreviousCodePointOffset(myDocument, offset),
                                    visualLineEndOffset,
                                    myCaretData, false, false, false, false);
            if (it.getEndOffset() <= offset) {
              it.advance();
            }
            if (x >= myClip.getMinX()) {
              TextAttributes attributes = it.getStartOffset() == offset ? it.getBeforeLineStartBackgroundAttributes() :
                                          it.getMergedAttributes();
              painter.paintBeforeLineStart(attributes, hasSoftWrap, fragment.getStartVisualColumn(), x, y);
            }
          }
        }
        FoldRegion foldRegion = fragment.getCurrentFoldRegion();
        if (foldRegion == null) {
          if (start != prevEndOffset) {
            it = new IterationState(myEditor, start, fragment.isRtl() ? offset : visualLineEndOffset,
                                    myCaretData, false, false, false, fragment.isRtl());
          }
          prevEndOffset = end;
          assert it != null;
          if (start == end) { // special case of inlays
            if (start == it.getEndOffset() && !it.atEnd()) {
              it.advance();
            }
            TextAttributes attributes = it.getStartOffset() == start ? it.getBreakAttributes() : it.getMergedAttributes();
            float xNew = fragment.getEndX();
            if (xNew >= myClip.getMinX()) {
              painter.paint(fragment, 0, 0, attributes, x, xNew, y);
            }
            x = xNew;
          }
          else {
            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);
              if (xNew >= myClip.getMinX()) {
                painter.paint(fragment,
                              fragment.isRtl() ? fragmentStartOffset - start : start - fragmentStartOffset,
                              fragment.isRtl() ? fragmentStartOffset - curEnd : curEnd - fragmentStartOffset,
                              attributes, x, xNew, y);
              }
              x = xNew;
              start = curEnd;
            }
            if (marginWidthConsumer != null && fragment.getEndLogicalLine() == endLogicalLine &&
                fragment.getStartLogicalColumn() <= myMarginColumns && fragment.getEndLogicalColumn() > myMarginColumns) {
              marginWidthConsumer.process(fragment.visualColumnToX(fragment.logicalToVisualColumn(myMarginColumns)));
              marginReached = true;
            }
          }
        }
        else if (foldRegion instanceof CustomFoldRegion) {
          break; // real painting happens in paintAfterLineEnd
        }
        else {
          float xNew = fragment.getEndX();
          if (xNew >= myClip.getMinX()) {
            painter.paint(fragment, 0, fragment.getVisualLength(), getFoldRegionAttributes(foldRegion), x, xNew, y);
          }
          x = xNew;
          prevEndOffset = -1;
          it = null;
        }
        if (x > myClip.getMaxX()) return;
        maxColumn = fragment.getEndVisualColumn();
      }
      if (firstFragment && myEditor.isRightAligned()) {
        it = new IterationState(myEditor, offset, visualLineEndOffset, myCaretData, false, false, false, false);
        if (it.getEndOffset() <= offset) {
          it.advance();
        }
        painter.paintBeforeLineStart(it.getBeforeLineStartBackgroundAttributes(), false, maxColumn, x, y);
      }
      if (it == null || it.getEndOffset() != visualLineEndOffset) {
        it = new IterationState(myEditor,
                                visualLineEndOffset == offset ? visualLineEndOffset
                                                              : DocumentUtil.getPreviousCodePointOffset(myDocument, visualLineEndOffset),
                                visualLineEndOffset,
                                CaretData.copyOf(myCaretData, visLineIterator.isCustomFoldRegionLine() &&
                                                                             !Registry.is("highlight.caret.line.at.custom.fold")),
                                false, false, false, false);
      }
      if (!it.atEnd()) {
        it.advance();
      }
      assert it.atEnd();
      painter.paintAfterLineEnd(it, maxColumn, x, y);
      if (marginWidthConsumer != null && !marginReached &&
          (visualLine == myEditor.getCaretModel().getVisualPosition().line || x > myMarginColumns * myView.getPlainSpaceWidth())) {
        int endLogicalColumn = myView.offsetToLogicalPosition(visualLineEndOffset).column;
        if (endLogicalColumn <= myMarginColumns) {
          marginWidthConsumer.process(x + (myMarginColumns - endLogicalColumn) * myView.getPlainSpaceWidth());
        }
      }
    }
private void paintLineFragments(VisualLinesIterator visLineIterator,
                                    int y,
                                    LineFragmentPainter painter,
                                    MarginWidthConsumer marginWidthConsumer)