protected void processRenderableContent(final RenderableReplacedContentBox node) {
    try {
      final ReportAttributeMap map = node.getAttributes();
      final AttributeList attrs = new AttributeList();
      HtmlTagHelper.applyHtmlAttributes(map, attrs);
      if (attrs.isEmpty() == false) {
        xmlWriter.writeTag(HtmlPrinter.XHTML_NAMESPACE, DIV_TAG, attrs, XmlWriterSupport.OPEN);
      }

      textExtractorHelper.writeLocalAnchor(node.getStyleSheet());

      final StyleSheet styleSheet = node.getStyleSheet();
      final String target = (String) styleSheet.getStyleProperty(ElementStyleKeys.HREF_TARGET);
      if (target != null) {
        textExtractorHelper.handleLinkOnElement(styleSheet, target);
      }

      processReplacedContent(node);

      if (target != null) {
        xmlWriter.writeCloseTag();
      }
      if (attrs.isEmpty() == false) {
        xmlWriter.writeCloseTag();
      }
    } catch (final IOException e) {
      throw new RuntimeException("Failed", e);
    } catch (final ContentIOException e) {
      throw new RuntimeException("Failed", e);
    }
  }
  protected void finishInlineBox(final InlineRenderBox box) {
    if (box.getStaticBoxLayoutProperties().isVisible() == false) {
      return;
    }

    textExtractorHelper.finishBox(box.getInstanceId(), box.getAttributes());
  }
 protected boolean startInlineBox(final InlineRenderBox box) {
   if (box.getStaticBoxLayoutProperties().isVisible() == false) {
     return false;
   }
   return textExtractorHelper.startInlineBox(
       box.getInstanceId(), box.getAttributes(), box.getStyleSheet(), box.getBoxDefinition());
 }
  /**
   * Prints a paragraph cell. This is a special entry point used by the processContent method and is
   * never called from elsewhere. This method assumes that the attributes of the paragraph have been
   * processed as part of the table-cell processing.
   *
   * @param box the paragraph box
   * @throws IOException if an IO error occured.
   */
  protected void processInitialBox(final ParagraphRenderBox box) throws IOException {
    if (box.getStaticBoxLayoutProperties().isVisible() == false) {
      return;
    }

    final StyleSheet styleSheet = box.getStyleSheet();
    final String target = (String) styleSheet.getStyleProperty(ElementStyleKeys.HREF_TARGET);
    if (target != null) {
      textExtractorHelper.handleLinkOnElement(styleSheet, target);
      processStack = new HtmlTextExtractorState(processStack, true);
    } else {
      processStack = new HtmlTextExtractorState(processStack, false);
    }

    if (Boolean.TRUE.equals(
            box.getAttributes()
                .getAttribute(AttributeNames.Html.NAMESPACE, AttributeNames.Html.SUPPRESS_CONTENT))
        == false) {
      processParagraphChilds(box);
    }

    if (processStack.isWrittenTag()) {
      xmlWriter.writeCloseTag();
    }
    processStack = processStack.getParent();
  }
  protected void drawComplexText(final RenderableComplexText renderableComplexText) {
    try {

      if (renderableComplexText.getRichText().isEmpty()) {
        // This text is empty.
        return;
      }
      if (renderableComplexText.isNodeVisible(getParagraphBounds(), isOverflowX(), isOverflowY())
          == false) {
        return;
      }

      // iterate through all inline elements
      for (final RichTextSpec.StyledChunk styledChunk :
          renderableComplexText.getRichText().getStyleChunks()) {
        RenderNode node = styledChunk.getOriginatingTextNode();
        InstanceID dummy = node.getInstanceId();
        textExtractorHelper.startInlineBox(
            dummy,
            styledChunk.getOriginalAttributes(),
            styledChunk.getStyleSheet(),
            BoxDefinition.EMPTY);
        if (node instanceof RenderableReplacedContentBox) {
          processRenderableContent((RenderableReplacedContentBox) node);
          result = true;
        } else {
          String text = styledChunk.getText();
          xmlWriter.writeText(characterEntityParser.encodeEntities(text));
          if (text.trim().length() > 0) {
            result = true;
          }
        }
        textExtractorHelper.finishBox(dummy, styledChunk.getOriginalAttributes());
        clearText();
      }
    } catch (final IOException ioe) {
      throw new InvalidReportStateException("Failed to write text", ioe);
    }
  }
  /** @noinspection StringConcatenation */
  private void processReplacedContent(final RenderableReplacedContentBox node)
      throws IOException, ContentIOException {

    final RenderableReplacedContent rc = node.getContent();
    final ReportAttributeMap attrs = node.getAttributes();
    final long width = node.getWidth();
    final long height = node.getHeight();
    final long contentWidth = rc.getContentWidth();
    final long contentHeight = rc.getContentHeight();
    final StyleSheet styleSheet = node.getStyleSheet();

    final Object rawObject = rc.getRawObject();
    // We have to do three things here. First, we have to check what kind
    // of content we deal with.
    if (textExtractorHelper.processRenderableReplacedContent(
        attrs, styleSheet, width, height, contentWidth, contentHeight, rawObject)) {
      result = true;
    }
  }
  public boolean performOutput(final RenderBox content, final StyleBuilder.StyleCarrier[] cellStyle)
      throws IOException {
    styleBuilder.clear();
    clearText();
    setRawResult(null);
    result = false;
    processStack = new HtmlTextExtractorState(null, false, cellStyle);
    textExtractorHelper.setFirstElement(content.getInstanceId(), processStack);

    try {
      final int nodeType = content.getNodeType();
      if (nodeType == LayoutNodeTypes.TYPE_BOX_PARAGRAPH) {
        processInitialBox((ParagraphRenderBox) content);
      } else if (nodeType == LayoutNodeTypes.TYPE_BOX_CONTENT) {
        processRenderableContent((RenderableReplacedContentBox) content);
      } else {
        processBoxChilds(content);
      }
    } finally {
      processStack = null;
    }
    return result;
  }