@DirtyUI
    @Override
    protected void paintComponent(@NotNull Graphics g) {
      if (myVisualLine == -1 || myEditor.isDisposed()) return;
      Dimension size = getPreferredSize();
      if (size.width <= 0 || size.height <= 0) return;

      EditorGutterComponentEx gutter = myEditor.getGutterComponentEx();
      EditorComponentImpl content = myEditor.getContentComponent();

      int gutterWidth = gutter.getWidth();
      int lineHeight = myEditor.getLineHeight();
      if (myCacheLevel2 != null && (myEditor.visualLineToY(myStartVisualLine) < myCacheFromY ||
                                    myEditor.visualLineToY(myEndVisualLine) + lineHeight > myCacheToY)) {
        myCacheLevel2 = null;
      }
      if (myCacheLevel2 == null) {
        myCacheFromY = Math.max(0, myEditor.visualLineToY(myVisualLine) - CACHE_PREVIEW_LINES * lineHeight);
        myCacheToY = Math.min(myEditor.visualLineToY(myEditor.getVisibleLineCount()),
                              myCacheFromY + (2 * CACHE_PREVIEW_LINES + 1) * lineHeight);
        myCacheLevel2 = ImageUtil.createImage(g, size.width, myCacheToY - myCacheFromY, BufferedImage.TYPE_INT_RGB);
        Graphics2D cg = myCacheLevel2.createGraphics();
        final AffineTransform t = cg.getTransform();
        EditorUIUtil.setupAntialiasing(cg);
        int lineShift = -myCacheFromY;

        int shift = JBUIScale.scale(EDITOR_FRAGMENT_POPUP_BORDER) + myContentInsets;
        AffineTransform gutterAT = AffineTransform.getTranslateInstance(-shift, lineShift);
        AffineTransform contentAT = AffineTransform.getTranslateInstance(gutterWidth - shift, lineShift);
        gutterAT.preConcatenate(t);
        contentAT.preConcatenate(t);

        EditorTextField.SUPPLEMENTARY_KEY.set(myEditor, Boolean.TRUE);
        try {
          cg.setTransform(gutterAT);
          cg.setClip(0, -lineShift, gutterWidth, myCacheLevel2.getHeight());
          gutter.paint(cg);

          cg.setTransform(contentAT);
          cg.setClip(0, -lineShift, content.getWidth(), myCacheLevel2.getHeight());
          content.paint(cg);
        }
        finally {
          EditorTextField.SUPPLEMENTARY_KEY.set(myEditor, null);
        }
      }
      if (myCacheLevel1 == null) {
        myCacheLevel1 = ImageUtil.createImage(g, size.width, lineHeight * (2 * PREVIEW_LINES + 1), BufferedImage.TYPE_INT_RGB);
        isDirty = true;
      }
      if (isDirty) {
        myRelativeY = SwingUtilities.convertPoint(this, 0, 0, myEditor.getScrollPane()).y;
        Graphics2D g2d = myCacheLevel1.createGraphics();
        final AffineTransform transform = g2d.getTransform();
        EditorUIUtil.setupAntialiasing(g2d);
        GraphicsUtil.setupAAPainting(g2d);
        g2d.setColor(myEditor.getBackgroundColor());
        g2d.fillRect(0, 0, getWidth(), getHeight());
        int topDisplayedY = Math.max(myEditor.visualLineToY(myStartVisualLine),
                                     myEditor.visualLineToY(myVisualLine) - PREVIEW_LINES * lineHeight);
        AffineTransform translateInstance = AffineTransform.getTranslateInstance(gutterWidth, myCacheFromY - topDisplayedY);
        translateInstance.preConcatenate(transform);
        g2d.setTransform(translateInstance);
        UIUtil.drawImage(g2d, myCacheLevel2, -gutterWidth, 0, null);
        Int2IntMap rightEdges = new Int2IntOpenHashMap();
        int h = lineHeight - 2;

        EditorColorsScheme colorsScheme = myEditor.getColorsScheme();
        Font font = UIUtil.getFontWithFallback(colorsScheme.getFont(EditorFontType.PLAIN));
        g2d.setFont(font.deriveFont(font.getSize() * .8F));

        for (RangeHighlighterEx ex : myHighlighters) {
          if (!ex.isValid()) continue;
          int hEndOffset = ex.getAffectedAreaEndOffset();
          Object tooltip = ex.getErrorStripeTooltip();
          if (tooltip == null) continue;
          String s = tooltip instanceof HighlightInfo ? ((HighlightInfo)tooltip).getDescription() : String.valueOf(tooltip);
          if (StringUtil.isEmpty(s)) continue;
          s = s.replaceAll("&nbsp;", " ").replaceAll("\\s+", " ");
          s = StringUtil.unescapeXmlEntities(s);

          LogicalPosition logicalPosition = myEditor.offsetToLogicalPosition(hEndOffset);
          int endOfLineOffset = myEditor.getDocument().getLineEndOffset(logicalPosition.line);
          logicalPosition = myEditor.offsetToLogicalPosition(endOfLineOffset);
          Point placeToShow = myEditor.logicalPositionToXY(logicalPosition);
          logicalPosition = myEditor.xyToLogicalPosition(placeToShow);//wraps&foldings workaround
          placeToShow.x += R * 3 / 2;
          placeToShow.y -= myCacheFromY - 1;

          int w = g2d.getFontMetrics().stringWidth(s);

          int rightEdge = rightEdges.get(logicalPosition.line);
          placeToShow.x = Math.max(placeToShow.x, rightEdge);
          rightEdge = Math.max(rightEdge, placeToShow.x + w + 3 * R);
          rightEdges.put(logicalPosition.line, rightEdge);

          g2d.setColor(MessageType.WARNING.getPopupBackground());
          g2d.fillRoundRect(placeToShow.x, placeToShow.y, w + 2 * R, h, R, R);
          g2d.setColor(new JBColor(JBColor.GRAY, Gray._200));
          g2d.drawRoundRect(placeToShow.x, placeToShow.y, w + 2 * R, h, R, R);
          g2d.setColor(JBColor.foreground());
          g2d.drawString(s, placeToShow.x + R, placeToShow.y + h - g2d.getFontMetrics(g2d.getFont()).getDescent() / 2 - 2);
        }
        isDirty = false;
      }
      Graphics2D g2 = (Graphics2D)g.create();
      try {
        GraphicsUtil.setupAAPainting(g2);
        g2.setClip(new RoundRectangle2D.Double(0, 0, size.width - .5, size.height - .5, 2, 2));
        UIUtil.drawImage(g2, myCacheLevel1, 0, 0, this);
        if (StartupUiUtil.isUnderDarcula() && !ExperimentalUI.isNewUI()) {
          //Add glass effect
          Shape s = new Rectangle(0, 0, size.width, size.height);
          double cx = size.width / 2.0;
          double rx = size.width / 10.0;
          int ry = lineHeight * 3 / 2;
          g2.setPaint(new GradientPaint(0, 0, Gray._255.withAlpha(75), 0, ry, Gray._255.withAlpha(10)));
          double pseudoMajorAxis = size.width - rx * 9 / 5;
          double cy = 0;
          Shape topShape1 = new Ellipse2D.Double(cx - rx - pseudoMajorAxis / 2, cy - ry, 2 * rx, 2 * ry);
          Shape topShape2 = new Ellipse2D.Double(cx - rx + pseudoMajorAxis / 2, cy - ry, 2 * rx, 2 * ry);
          Area topArea = new Area(topShape1);
          topArea.add(new Area(topShape2));
          topArea.add(new Area(new Rectangle.Double(cx - pseudoMajorAxis / 2, cy, pseudoMajorAxis, ry)));
          g2.fill(topArea);
          Area bottomArea = new Area(s);
          bottomArea.subtract(topArea);
          g2.setPaint(new GradientPaint(0, size.height - ry, Gray._0.withAlpha(10), 0, size.height, Gray._255.withAlpha(30)));
          g2.fill(bottomArea);
        }
      }
      finally {
        g2.dispose();
      }
    }
@DirtyUI
    @Override
    protected void paintComponent(@NotNull Graphics g)