protected void renderImage(
      UIXRenderingContext context, UINode node, ImageProviderResponse response, String mapName)
      throws IOException {
    // We assume that we have an image to render
    assert (response != null);

    boolean disabled = isDisabled(context, node);
    boolean hasMap = (response.getMapAreas() != null);
    Object shortDesc = getShortDesc(context, node);

    boolean hasLink = !disabled && !hasMap;
    Object destination = hasLink ? getDestination(context, node) : null;

    renderImage(context, node, response, hasMap, mapName, shortDesc, destination);
  }
  protected void renderImage(
      UIXRenderingContext context,
      UINode node,
      ImageProviderResponse response,
      boolean hasMap,
      String mapName,
      Object shortDesc,
      Object destination)
      throws IOException {
    assert node != null;

    boolean hasLink = (destination != null);
    Object longDesc = getLongDesc(context, node);
    String imageStyle = getImageStyle(context, node);
    String imageStyleClass = getImageStyleClass(context, node);

    ResponseWriter writer = context.getResponseWriter();
    UIComponent component = (node == null) ? null : node.getUIComponent();

    if (hasLink) {
      writer.startElement("a", component);
      renderEncodedActionURI(context, "href", destination);
      renderAttribute(context, node, "target", TARGET_FRAME_ATTR);

      // Don't render access key on Netscape... Netscape doesn't
      // support access keys - if this ever changes, it would
      // be confusing if we rendered the accessKey attr without
      // also underlining the access key in the corresponding text.
      if (!isNetscape(context)) {
        renderButtonAccessKey(context, node);
      }

      // If we have a link, we render the standard attributes on
      // the link instead of on the image
      renderAttributes(context, node);
    }

    writer.startElement("img", component);

    // Write out all of the standard attrs
    if (!hasLink) renderAttributes(context, node);

    // Write out the image url
    writeCacheImageURI(context, "src", response.getImageURI());

    // Write out the description attrs.
    renderAltAndTooltipForImage(context, shortDesc);
    renderAttribute(context, "longdesc", longDesc);

    // Null out the border
    renderAttribute(context, "border", "0");

    // Render alignment.  Is this necessary?
    renderHAlign(context, node);

    // This is to address bug #2047577
    // Instead of adding an attribute to control placement of the button,
    // we just force it to middle (which is what everybody wants anyway).
    // We have to make sure we don't put the align attribute in twice.
    // We allow the hAlign attribute to take precedence.
    if (node.getAttributeValue(context, H_ALIGN_ATTR) == null) {
      Object valign = getVAlign(context, node);
      if (valign != null) renderAttribute(context, "align", valign);
    }

    // Render the width/height
    int width = response.getWidth();
    int height = response.getHeight();

    if (width != ImageProviderResponse.UNKNOWN_SIZE)
      renderAttribute(context, "width", IntegerUtils.getString(width));
    if (height != ImageProviderResponse.UNKNOWN_SIZE)
      renderAttribute(context, "height", IntegerUtils.getString(height));

    // The image map
    if (hasMap) writer.writeAttribute("usemap", "#" + mapName, null);

    if (imageStyle != null) renderAttribute(context, "style", imageStyle);
    if (imageStyleClass != null) renderStyleClassAttribute(context, imageStyleClass);

    writer.endElement("img");

    if (hasLink) writer.endElement("a");
  }