private void paintBackground() {
      int lineCount = myEditor.getVisibleLineCount();
      boolean calculateMarginWidths = Registry.is("editor.adjust.right.margin") && isMarginShown() && myStartVisualLine < lineCount;
      myMarginPositions = calculateMarginWidths ? new MarginPositions(Math.min(myEndVisualLine, lineCount - 1) - myStartVisualLine + 2)
                                                : null;
      final LineWhitespacePaintingStrategy whitespacePaintingStrategy = new LineWhitespacePaintingStrategy(myEditor.getSettings());
      boolean paintAllSoftWraps = myEditor.getSettings().isAllSoftWrapsShown();
      float whiteSpaceScale = getWhiteSpaceScale(myEditor);
      final BasicStroke whiteSpaceStroke = new BasicStroke(calcFeatureSize(1, whiteSpaceScale));

      PeekableIterator<Caret> caretIterator = null;
      if (myEditor.getInlayModel().hasBlockElements()) {
        Iterator<Caret> carets = myEditor.getCaretModel().getAllCarets()
          .stream()
          .filter(Caret::hasSelection)
          .sorted(Comparator.comparingInt(Caret::getSelectionStart))
          .iterator();
        caretIterator = new PeekableIteratorWrapper<>(carets);
      }

      final VisualPosition primarySelectionStart = myEditor.getSelectionModel().getSelectionStartPosition();
      final VisualPosition primarySelectionEnd = myEditor.getSelectionModel().getSelectionEndPosition();

      LineLayout prefixLayout = myView.getPrefixLayout();
      if (myStartVisualLine == 0 && prefixLayout != null) {
        float width = prefixLayout.getWidth();
        TextAttributes attributes = myView.getPrefixAttributes();
        paintBackground(attributes, myCorrector.startX(myStartVisualLine), myYShift + myView.visualLineToY(0), width);
        myTextDrawingTasks.add(g -> {
          paintLineLayoutWithEffect(prefixLayout,
                                    myCorrector.startX(myStartVisualLine), myAscent + myYShift + myView.visualLineToY(0),
                                    attributes.getForegroundColor(), attributes.getEffectColor(), attributes.getEffectType());
        });
      }

      int startX = myInsets.left;
      int endX = myClip.x + myClip.width;
      int prevY = Math.max(myInsets.top, myClip.y) + myYShift;
      VisualLinesIterator visLinesIterator = new VisualLinesIterator(myEditor, myStartVisualLine);
      while (!visLinesIterator.atEnd()) {
        int visualLine = visLinesIterator.getVisualLine();
        if (visualLine > myEndVisualLine + 1) break;
        int y = visLinesIterator.getY() + myYShift;
        if (calculateMarginWidths) myMarginPositions.y[visualLine - myStartVisualLine] = y;
        if (y > prevY) {
          TextAttributes attributes = getBetweenLinesAttributes(visualLine, visLinesIterator.getVisualLineStartOffset(),
                                                                Objects.requireNonNull(caretIterator));
          myBetweenLinesAttributes.put(visualLine, attributes);
          paintBackground(attributes.getBackgroundColor(), startX, prevY, endX - startX, y - prevY);
        }
        boolean dryRun = visualLine > myEndVisualLine;
        if (dryRun && !calculateMarginWidths) break;
        boolean paintSoftWraps = paintAllSoftWraps ||
                                 myEditor.getCaretModel().getLogicalPosition().line == visLinesIterator.getDisplayedLogicalLine();
        int[] currentLogicalLine = new int[]{-1};
        paintLineFragments(visLinesIterator, y, new LineFragmentPainter() {
          @Override
          public void paintBeforeLineStart(TextAttributes attributes, boolean hasSoftWrap, int columnEnd, float xEnd, int y) {
            if (dryRun) return;
            if (visualLine == 0) xEnd -= myView.getPrefixTextWidthInPixels();
            paintBackground(attributes, startX, y, xEnd);
            if (!hasSoftWrap) return;
            paintSelectionOnSecondSoftWrapLineIfNecessary(visualLine, columnEnd, xEnd, y, primarySelectionStart, primarySelectionEnd);
            if (paintSoftWraps) {
              int x = (int)xEnd;
              myTextDrawingTasks.add(g -> {
                SoftWrapModelImpl softWrapModel = myEditor.getSoftWrapModel();
                int symbolWidth = softWrapModel.getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP);
                softWrapModel.doPaint(g, SoftWrapDrawingType.AFTER_SOFT_WRAP, x - symbolWidth, y, myLineHeight);
              });
            }
          }

          @Override
          public void paint(VisualLineFragmentsIterator.Fragment fragment, int start, int end,
                            TextAttributes attributes, float xStart, float xEnd, int y) {
            if (dryRun) return;
            FoldRegion foldRegion = fragment.getCurrentFoldRegion();
            TextAttributes foldRegionInnerAttributes =
              foldRegion == null || !Registry.is("editor.highlight.foldings") ? null : getInnerHighlighterAttributes(foldRegion);
            if (foldRegionInnerAttributes == null ||
                !paintFoldingBackground(foldRegionInnerAttributes, xStart, y, xEnd - xStart, foldRegion)) {
              paintBackground(attributes, xStart, y, xEnd - xStart);
            }
            Inlay inlay = fragment.getCurrentInlay();
            if (inlay != null) {
              TextAttributes attrs = attributes.clone();
              myTextDrawingTasks.add(g -> {
                inlay.getRenderer().paint(inlay, g, new Rectangle2D.Double(xStart, y, xEnd - xStart, myLineHeight), attrs);
              });
            }
            else {
              if (foldRegionInnerAttributes != null) {
                attributes = TextAttributes.merge(attributes, foldRegionInnerAttributes);
              }
              if (attributes != null) {
                attributes.forEachEffect((type, color) -> myTextDrawingTasks.add(
                  g -> paintTextEffect(xStart, xEnd, y + myAscent, color, type, foldRegion != null)
                ));
              }
              if (attributes != null) {
                Color color = attributes.getForegroundColor();
                if (color != null) {
                  myTextDrawingTasks.add(g -> g.setColor(color));
                  myTextDrawingTasks.add(fragment.draw(xStart, y + myAscent, start, end));
                }
              }
            }
            if (foldRegion == null) {
              int logicalLine = fragment.getStartLogicalLine();
              if (logicalLine != currentLogicalLine[0]) {
                whitespacePaintingStrategy.update(myText,
                                                  myDocument.getLineStartOffset(logicalLine), myDocument.getLineEndOffset(logicalLine));
                currentLogicalLine[0] = logicalLine;
              }
              paintWhitespace(xStart, y + myAscent, start, end, whitespacePaintingStrategy, fragment, whiteSpaceStroke,
                              whiteSpaceScale);
            }
          }

          @Override
          public void paintAfterLineEnd(IterationState it, int columnStart, float x, int y) {
            if (dryRun) return;
            TextAttributes backgroundAttributes = it.getPastLineEndBackgroundAttributes().clone();
            CustomFoldRegion cfr = visLinesIterator.getCustomFoldRegion();
            if (cfr != null) {
              paintBackground(backgroundAttributes, startX, y, endX - startX, cfr.getHeightInPixels());
              myTextDrawingTasks.add(g -> {
                cfr.getRenderer().paint(cfr, g, new Rectangle2D.Double(x, y, cfr.getWidthInPixels(), cfr.getHeightInPixels()),
                                        backgroundAttributes);
              });
              return;
            }
            paintBackground(backgroundAttributes, x, y, endX - x);
            int offset = it.getEndOffset();
            SoftWrap softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset);
            if (softWrap == null) {
              int logicalLine = myDocument.getLineNumber(offset);
              List<Inlay<?>> inlays = myEditor.getInlayModel().getAfterLineEndElementsForLogicalLine(logicalLine);
              float extensionsStartX = inlays.isEmpty()
                                       ? x
                                       : x + myView.getPlainSpaceWidth() + inlays.stream().mapToInt(Inlay::getWidthInPixels).sum();
              collectExtensions(visualLine, offset);
              paintLineExtensionsBackground(visualLine, extensionsStartX, y);
              paintVirtualSelectionIfNecessary(visualLine, columnStart, x, y);
              myTextDrawingTasks.add(g -> {
                if (!inlays.isEmpty()) {
                  float curX = x + myView.getPlainSpaceWidth();
                  for (Inlay inlay : inlays) {
                    int width = inlay.getWidthInPixels();
                    inlay.getRenderer().paint(inlay, g, new Rectangle2D.Double(curX, y, width, myLineHeight), backgroundAttributes);
                    curX += width;
                  }
                }
                paintLineExtensions(visualLine, logicalLine, extensionsStartX, y + myAscent);
              });
            }
            else {
              paintSelectionOnFirstSoftWrapLineIfNecessary(visualLine, columnStart, x, y, primarySelectionStart, primarySelectionEnd);
              if (paintSoftWraps) {
                myTextDrawingTasks.add(g -> {
                  myEditor.getSoftWrapModel().doPaint(g, SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED, (int)x, y, myLineHeight);
                });
              }
            }
          }
        }, calculateMarginWidths && !visLinesIterator.endsWithSoftWrap() && !visLinesIterator.startsWithSoftWrap()
           ? width -> myMarginPositions.x[visualLine - myStartVisualLine] = width : null);
        prevY = y + visLinesIterator.getLineHeight();
        visLinesIterator.advance();
      }
      if (calculateMarginWidths && myEndVisualLine >= lineCount - 1) {
        myMarginPositions.y[myMarginPositions.y.length - 1] = myMarginPositions.y[myMarginPositions.y.length - 2] + myLineHeight;
      }
    }
private void paintBackground()