private static List<BidiRun> createFragments(
     @NotNull EditorView view,
     int lineStartOffset,
     int lineEndOffset,
     @NotNull FontRenderContext fontRenderContext) {
   if (lineEndOffset <= lineStartOffset) return Collections.emptyList();
   EditorImpl editor = view.getEditor();
   FontPreferences fontPreferences = editor.getColorsScheme().getFontPreferences();
   char[] chars =
       CharArrayUtil.fromSequence(
           editor.getDocument().getImmutableCharSequence(), lineStartOffset, lineEndOffset);
   List<BidiRun> runs = createRuns(editor, chars, lineStartOffset);
   for (BidiRun run : runs) {
     IterationState it =
         new IterationState(
             editor,
             lineStartOffset + run.startOffset,
             lineStartOffset + run.endOffset,
             false,
             false,
             false,
             false);
     while (!it.atEnd()) {
       addFragments(
           run,
           chars,
           it.getStartOffset() - lineStartOffset,
           it.getEndOffset() - lineStartOffset,
           it.getMergedAttributes().getFontType(),
           fontPreferences,
           fontRenderContext,
           view.getTabFragment());
       it.advance();
     }
     assert !run.fragments.isEmpty();
   }
   return runs;
 }
 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);
 }