public Rectangle getVisualBounds(JComponent c, int type, int width, int height) {
    Rectangle bounds = new Rectangle(0, 0, width, height);
    if (type == VisuallyLayoutable.CLIP_BOUNDS) {
      return bounds;
    }

    AbstractButton b = (AbstractButton) c;

    if (type == VisuallyLayoutable.COMPONENT_BOUNDS
        && b.getBorder() != null
        && b.isBorderPainted()) {
      Border border = b.getBorder();
      if (border instanceof BackgroundBorder) {
        border = ((BackgroundBorder) border).getBackgroundBorder();
        if (border instanceof VisualMargin) {
          InsetsUtil.subtractInto(((VisualMargin) border).getVisualMargin(c), bounds);
        } else if (border instanceof QuaquaButtonBorder) {
          InsetsUtil.subtractInto(((QuaquaButtonBorder) border).getVisualMargin(c), bounds);
        }
      }
      return bounds;
    }

    String text = b.getText();
    boolean isEmpty = (text == null || text.length() == 0);
    if (isEmpty) {
      text = " ";
    }
    Icon icon = (b.isEnabled()) ? b.getIcon() : b.getDisabledIcon();

    if ((icon == null) && (text == null)) {
      return null;
    }

    FontMetrics fm = c.getFontMetrics(c.getFont());
    Insets insets = c.getInsets(viewInsets);

    viewR.x = insets.left;
    viewR.y = insets.top;
    viewR.width = width - (insets.left + insets.right);
    viewR.height = height - (insets.top + insets.bottom);

    iconR.x = iconR.y = iconR.width = iconR.height = 0;
    textR.x = textR.y = textR.width = textR.height = 0;

    String clippedText = layoutCL(b, fm, text, icon, viewR, iconR, textR);

    Rectangle textBounds = Fonts.getPerceivedBounds(text, c.getFont(), c);
    if (isEmpty) {
      textBounds.width = 0;
    }
    int ascent = fm.getAscent();
    textR.x += textBounds.x;
    textR.width = textBounds.width;
    textR.y += ascent + textBounds.y;
    textR.height -= fm.getHeight() - textBounds.height;

    bounds.setBounds(textR);
    return bounds;
  }
  /**
   * This method gets called when a bound property is changed on the associated JTextComponent. This
   * is a hook which UI implementations may change to reflect how the UI displays bound properties
   * of JTextComponent subclasses. If the font, foreground or document has changed, the the
   * appropriate property is set in the default style of the document.
   *
   * @param evt the property change event
   */
  @Override
  protected void propertyChange(PropertyChangeEvent evt) {
    super.propertyChange(evt);

    String name = evt.getPropertyName();

    if (name.equals("foreground")) {
      updateForeground((Color) evt.getNewValue());
    } else if (name.equals("font")) {
      updateFont((Font) evt.getNewValue());
    } else if (name.equals("document")) {
      JComponent comp = getComponent();
      updateForeground(comp.getForeground());
      updateFont(comp.getFont());
    }
  }
 /**
  * Installs the UI for a component. This does the following things.
  *
  * <ol>
  *   <li>Sets opaqueness of the associated component according to its style, if the opaque
  *       property has not already been set by the client program.
  *   <li>Installs the default caret and highlighter into the associated component. These
  *       properties are only set if their current value is either {@code null} or an instance of
  *       {@link UIResource}.
  *   <li>Attaches to the editor and model. If there is no model, a default one is created.
  *   <li>Creates the view factory and the view hierarchy used to represent the model.
  * </ol>
  *
  * @param c the editor component
  * @see javax.swing.plaf.basic.BasicTextUI#installUI
  * @see ComponentUI#installUI
  */
 @Override
 public void installUI(JComponent c) {
   super.installUI(c);
   updateForeground(c.getForeground());
   updateFont(c.getFont());
 }