/**
   * The padding between the "content area" (that is, the icon rect and text rect) and the edges of
   * this button. This is a calculated value.
   */
  protected Insets getContentInsets(AbstractButton button) {
    int horizontalPosition = getHorizontalPosition(button);
    int verticalPosition = getVerticalPosition(button);

    Insets i = new Insets(0, 0, 0, 0);
    if (getFocusPainting(button) == PaintFocus.OUTSIDE
        || getFocusPainting(button) == PaintFocus.BOTH) {
      if (horizontalPosition == POS_LEFT || horizontalPosition == POS_ONLY) {
        i.left += focusSize;
      }
      if (horizontalPosition == POS_RIGHT || horizontalPosition == POS_ONLY) {
        i.right += focusSize;
      }
      if (verticalPosition == POS_TOP || verticalPosition == POS_ONLY) {
        i.top += focusSize;
      }
      if (verticalPosition == POS_BOTTOM || verticalPosition == POS_ONLY) {
        i.bottom += focusSize;
      }
    } else {
      if (fill.getShadowHighlight(button) != null
          && (verticalPosition == POS_BOTTOM || verticalPosition == POS_ONLY)) {
        i.bottom++;
      }
    }
    return i;
  }
  /**
   * This calls the other relevant <code>paint...()</code> methods in this object. The layering of
   * the focus varies based on whether it should be painted outside or inside the filled shape, but
   * otherwise the layers are:
   *
   * <ul>
   *   <li>Filling the bounds with <code>button.getBackground()</code> (if <code>button.isOpaque()
   *       </code> is true).
   *   <li>If <code>getShadowHighlight()</code> is non-null, painting the stroke/border 1 pixel
   *       below its usual location.
   *   <li><code>paintBackground(g)</code>
   *   <li><code>paintEffects(g,false)</code>
   *   <li><code>paintIcon(g)</code>
   *   <li><code>paintText(g)</code>
   *   <LI><code>paintForeground(g)</code>
   *   <LI><code>paintEffects(g,true)</code>
   * </ul>
   */
  @Override
  public void paint(Graphics g0, JComponent c) {
    AbstractButton button = (AbstractButton) c;

    if (isLayoutValid(button) == false) updateLayout(button, getButtonInfo(button));

    if (button.isOpaque()) {
      g0.setColor(button.getBackground());
      g0.fillRect(0, 0, button.getWidth(), button.getHeight());
    }

    Graphics2D g = new OptimizedGraphics2D((Graphics2D) g0);

    g.setComposite(getComposite(button));

    ButtonInfo info = getButtonInfo(button);

    Color highlight = fill.getShadowHighlight(button);
    if (highlight != null && isStrokePainted(button)) {
      g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g.translate(0, 1);
      g.setColor(highlight);
      g.draw(info.fill);
      g.translate(0, -1);
    }

    PaintFocus focus = getFocusPainting(button);
    boolean hasFocus = hasFocus(button);
    if (Boolean.FALSE.equals(hasFocus) || button.isFocusPainted() == false) focus = PaintFocus.NONE;

    // this shouldn't be an issue, but just in case:
    if (isEnabled(button) == false) focus = PaintFocus.NONE;

    if (focus == PaintFocus.OUTSIDE) {
      if (isFillOpaque()) {
        // the opaque fill will overwrite the inner part of
        // this stroke...
        PlafPaintUtils.paintFocus(g, info.stroke, focusSize);
      } else {
        // this still has some rendering quirks in
        // Quartz (remove the clipping to study closely)
        // ... but other than the top horizontal & vertical
        // line it's OK.  And even those are ... partly there.
        Graphics2D focusG = (Graphics2D) g.create();
        GeneralPath outsideClip = new GeneralPath(Path2D.WIND_EVEN_ODD);
        outsideClip.append(new Rectangle(0, 0, button.getWidth(), button.getHeight()), false);
        outsideClip.append(info.fill, false);
        focusG.clip(outsideClip);
        PlafPaintUtils.paintFocus(focusG, info.stroke, focusSize);
        focusG.dispose();
      }
    }
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);

    paintBackground(g, info);
    paintEffects(g, info, true);

    g.setStroke(new BasicStroke(1));
    if (focus == PaintFocus.INSIDE) {
      Graphics2D focusG = (Graphics2D) g.create();
      focusG.clip(info.fill);
      PlafPaintUtils.paintFocus(focusG, info.stroke, focusSize);
      focusG.dispose();
      paintStroke(g, info);
    } else if (focus == PaintFocus.BOTH) {
      paintStroke(g, info);
      PlafPaintUtils.paintFocus(g, info.stroke, focusSize);
    } else {
      paintStroke(g, info);
    }

    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    paintIcon(g, info);
    paintText(g, info);

    g.setComposite(isEnabled(button) ? AlphaComposite.SrcOver : SRC_OVER_TRANSLUCENT);
    paintForeground(g, info);
    paintEffects(g, info, false);
  }