protected int doPaintText(Graphics2D g, int textStart, boolean focusAroundIcon) {
    synchronized (myFragments) {
      // If there is no icon, then we have to add left internal padding
      if (textStart == 0) {
        textStart = myIpad.left;
      }

      float offset = textStart;
      if (border != null) {
        offset += border.getBorderInsets(this).left;
      }
      offset += getInsets().left;

      final class Frag {
        private final int index;
        private final float start;
        private final float end;
        private final float baseLine;
        private final Font font;
        private final Frag next;

        private Frag(int index, float start, float end, float baseLine, @NotNull Font font, Frag next) {
          this.index = index;
          this.start = start;
          this.end = end;
          this.baseLine = baseLine;
          this.font = font;
          this.next = next;
        }
      }
      int height = getHeight();

      applyAdditionalHints(g);
      final Font baseFont = getBaseFont();
      g.setFont(baseFont);
      offset += computeTextAlignShift();
      int baseSize = baseFont.getSize();
      FontMetrics baseMetrics = g.getFontMetrics();
      Rectangle area = computePaintArea();
      final int textBaseline = area.y + getTextBaseLine(baseMetrics, area.height);
      boolean wasSmaller = false;
      Frag secondPassFrag = null;
      for (int i = 0; i < myFragments.size(); i++) {
        ColoredFragment fragment = myFragments.get(i);
        final SimpleTextAttributes attributes = fragment.attributes;

        Font font = g.getFont();
        boolean isSmaller = attributes.isSmaller();
        if (font.getStyle() != attributes.getFontStyle() || isSmaller != wasSmaller) { // derive font only if it is necessary
          font = deriveFont(font, attributes.getFontStyle(), isSmaller ? UIUtil.getFontSize(UIUtil.FontSize.SMALL) : baseSize);
        }
        wasSmaller = isSmaller;

        g.setFont(font);
        final FontMetrics metrics = g.getFontMetrics(font);

        float fragmentWidth = computeStringWidth(fragment, i, font);

        final int fragmentPadding = fragment.padding;

        boolean secondPass = attributes.isSearchMatch() || attributes.isClickable();
        final Color bgColor = secondPass ? null : attributes.getBgColor();
        if ((attributes.isOpaque() || isOpaque()) && bgColor != null) {
          doPaintFragmentBackground(g, i, bgColor, (int)offset, 0, (int)fragmentWidth, height);
        }

        Color color;
        color = isEnabled() ? getActiveTextColor(attributes.getFgColor()) : NamedColorUtil.getInactiveTextColor();
        g.setColor(color);

        final int fragmentAlignment = fragment.alignment;

        final float endOffset;
        if (fragmentPadding > 0 &&
            fragmentPadding > fragmentWidth) {
          endOffset = fragmentPadding;
          if (fragmentAlignment == SwingConstants.RIGHT || fragmentAlignment == SwingConstants.TRAILING) {
            offset = fragmentPadding - fragmentWidth;
          }
        }
        else {
          endOffset = offset + fragmentWidth;
        }

        if (offset < area.getMaxX()) {
          if (!secondPass) {
            if (shouldDrawDimmed()) {
              color = ColorUtil.dimmer(color);
            }

            g.setColor(color);
            doDrawString(g, fragment, i, offset, textBaseline);

            // for some reason strokeState here may be incorrect, resetting the stroke helps
            g.setStroke(g.getStroke());

            drawTextAttributes(g, attributes, (int)offset, textBaseline, (int)fragmentWidth, metrics, font);
          }

          if (secondPass) {
            secondPassFrag = new Frag(i, offset, offset + fragmentWidth, textBaseline, font, secondPassFrag);
          }
        }

        offset = endOffset;
      }

      // Paint focus border around the text and icon (if necessary)
      if (myPaintFocusBorder && border != null) {
        int width = getWidth();
        if (focusAroundIcon) {
          border.paintBorder(this, g, 0, 0, width, height);
        }
        else {
          border.paintBorder(this, g, textStart, 0, width - textStart, height);
        }
      }

      // draw search matches after all
      for (Frag frag = secondPassFrag; frag != null; frag = frag.next) {
        float x1 = frag.start;
        float x2 = frag.end;
        float baseline = frag.baseLine;
        ColoredFragment fragment = myFragments.get(frag.index);
        String text = fragment.text;
        SimpleTextAttributes attributes = fragment.attributes;
        Color fgColor;
        if (attributes.isSearchMatch()) {
          fgColor = new JBColor(Gray._50, Gray._0);
          UIUtil.drawSearchMatch(g, x1, x2, height);
        }
        else if (attributes.isClickable()) {
          boolean selected = UIUtil.getTreeSelectionBackground(true) == getBackground();
          fgColor = ObjectUtils.notNull(attributes.getFgColor(), UIUtil.getLabelForeground());
          drawClickableFrag(g, x1, x2, height, selected, attributes.isHovered(), attributes.isNoBorder());
        }
        else {
          continue;
        }
        g.setFont(frag.font);
        g.setColor(fgColor);
        if (!drawWithClipping(frag.index, g, frag.font, frag.start, frag.end, baseline)) {
          g.drawString(text, x1, baseline);
        }

        int fragmentWidth = (int)(x2 - x1);
        drawTextAttributes(g, attributes, (int)x1, (int)baseline, fragmentWidth, g.getFontMetrics(), g.getFont());
      }
      return (int)offset;
    }
  }
protected int doPaintText(Graphics2D g, int textStart, boolean focusAroundIcon)