protected void processInlineLevelNode(final RenderNode node) {
    if (lineBreakState.isInsideParagraph() == false) {
      throw new InvalidReportStateException(
          "A inline-level box outside of a paragraph box is not allowed.");
    }

    final int nodeType = node.getNodeType();
    if (nodeType == LayoutNodeTypes.TYPE_NODE_FINISHEDNODE) {
      final FinishedRenderNode finNode = (FinishedRenderNode) node;
      node.setCachedWidth(finNode.getLayoutedWidth());
      return;
    }

    if (nodeType == LayoutNodeTypes.TYPE_NODE_TEXT) {
      lineBreakState.add(TextSequenceElement.INSTANCE, node);
    } else if (nodeType == LayoutNodeTypes.TYPE_NODE_SPACER) {
      final StyleSheet styleSheet = node.getStyleSheet();
      if (WhitespaceCollapse.PRESERVE.equals(
              styleSheet.getStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE))
          && styleSheet.getBooleanStyleProperty(TextStyleKeys.TRIM_TEXT_CONTENT) == false) {
        // bug-alert: This condition could indicate a workaround for a logic-flaw in the
        // text-processor
        lineBreakState.add(SpacerSequenceElement.INSTANCE, node);
      } else if (lineBreakState.isContainsContent()) {
        lineBreakState.add(SpacerSequenceElement.INSTANCE, node);
      }
    } else {
      lineBreakState.add(InlineNodeSequenceElement.INSTANCE, node);
    }
  }
  protected void drawAnchor(final RenderNode content) {
    if (content.isNodeVisible(getDrawArea()) == false) {
      return;
    }
    final String anchorName =
        (String) content.getStyleSheet().getStyleProperty(ElementStyleKeys.ANCHOR_NAME);
    if (anchorName == null) {
      return;
    }
    final AffineTransform affineTransform = getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    final float upperY =
        translateX + (float) (globalHeight - StrictGeomUtility.toExternalValue(content.getY()));
    final float leftX = (float) (StrictGeomUtility.toExternalValue(content.getX()));
    final PdfDestination dest = new PdfDestination(PdfDestination.FIT, leftX, upperY, 0);
    writer.getDirectContent().localDestination(anchorName, dest);
  }
  protected void processLinksAndAnchors(final RenderNode box) {
    final StyleSheet styleSheet = box.getStyleSheet();
    if (drawPdfScript(box) == false) {
      final String target = (String) styleSheet.getStyleProperty(ElementStyleKeys.HREF_TARGET);
      final String title = (String) styleSheet.getStyleProperty(ElementStyleKeys.HREF_TITLE);
      if (target != null || title != null) {
        final String window = (String) styleSheet.getStyleProperty(ElementStyleKeys.HREF_WINDOW);
        drawHyperlink(box, target, window, title);
      }
    }

    final String anchor = (String) styleSheet.getStyleProperty(ElementStyleKeys.ANCHOR_NAME);
    if (anchor != null) {
      drawAnchor(box);
    }

    final String bookmark = (String) styleSheet.getStyleProperty(BandStyleKeys.BOOKMARK);
    if (bookmark != null) {
      drawBookmark(box, bookmark);
    }
  }
  public RenderBox next() {
    cleanFirstSpacers();

    Arrays.fill(elementDimensions, 0);
    Arrays.fill(elementPositions, 0);

    int lastPosition = iterate(sequenceElements, sequenceFill);
    if (lastPosition == 0) {
      // This could evolve into an infinite loop. Thats evil.
      // We have two choices to prevent that:
      // (1) Try to break the element.
      //      if (getBreakableIndex() >= 0)
      //      {
      //        // Todo: Breaking is not yet implemented ..
      //      }
      if (getSkipIndex() >= 0) {
        // This causes an overflow ..
        performSkipAlignment(getSkipIndex());
        lastPosition = getSkipIndex();
      } else {
        // Skip the complete line. Oh, thats not good, really!
        lastPosition = sequenceFill;
      }
    }

    // now, build the line and update the array ..
    pendingElements.clear();
    contexts.clear();
    RenderBox firstBox = null;
    RenderBox box = null;
    for (int i = 0; i < lastPosition; i++) {
      final RenderNode node = nodes[i];
      final InlineSequenceElement element = sequenceElements[i];
      if (element instanceof EndSequenceElement) {
        contexts.pop();
        final long boxX2 = (elementPositions[i] + elementDimensions[i]);
        box.setCachedWidth(boxX2 - box.getCachedX());

        if (contexts.isEmpty()) {
          box = null;
        } else {
          final RenderNode tmpnode = box;
          box = contexts.peek();
          box.addGeneratedChild(tmpnode);
        }
        continue;
      }

      if (element instanceof StartSequenceElement) {
        box = (RenderBox) node.derive(false);
        box.setCachedX(elementPositions[i]);
        contexts.push(box);
        if (firstBox == null) {
          firstBox = box;
        }
        continue;
      }

      if (box == null) {
        throw new IllegalStateException(
            "Invalid sequence: " + "Cannot have elements before we open the box context.");
      }

      // Content element: Perform a deep-deriveForAdvance, so that we preserve the
      // possibly existing sub-nodes.
      final RenderNode child = node.derive(true);
      child.setCachedX(elementPositions[i]);
      child.setCachedWidth(elementDimensions[i]);
      if (box.getStaticBoxLayoutProperties().isPreserveSpace()
          && box.getStyleSheet().getBooleanStyleProperty(TextStyleKeys.TRIM_TEXT_CONTENT)
              == false) {
        // Take a shortcut as we know that we will never have any pending elements if preserve is
        // true and
        // trim-content is false.
        box.addGeneratedChild(child);
        continue;
      }

      if (child.isIgnorableForRendering()) {
        pendingElements.add(child);
      } else {
        for (int j = 0; j < pendingElements.size(); j++) {
          final RenderNode pendingNode = pendingElements.get(j);
          box.addGeneratedChild(pendingNode);
        }
        pendingElements.clear();
        box.addGeneratedChild(child);
      }
    }

    // Remove all spacers and other non printable content that might
    // look ugly at the beginning of a new line ..
    for (; lastPosition < sequenceFill; lastPosition++) {
      final RenderNode node = nodes[lastPosition];
      final StyleSheet styleSheet = node.getStyleSheet();
      if (WhitespaceCollapse.PRESERVE.equals(
              styleSheet.getStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE))
          && styleSheet.getBooleanStyleProperty(TextStyleKeys.TRIM_TEXT_CONTENT) == false) {
        break;
      }

      if (node.isIgnorableForRendering() == false) {
        break;
      }
    }

    // If there are open contexts, then add the split-result to the new line
    // and update the width of the current line
    RenderBox previousContext = null;
    final int openContexts = contexts.size();
    for (int i = 0; i < openContexts; i++) {
      final RenderBox renderBox = contexts.get(i);
      final long cachedWidth = getEndOfLine() - renderBox.getCachedX();
      renderBox.setCachedWidth(cachedWidth);

      final InlineRenderBox rightBox =
          (InlineRenderBox) renderBox.split(RenderNode.HORIZONTAL_AXIS);
      sequenceElements[i] = StartSequenceElement.INSTANCE;
      nodes[i] = rightBox;
      if (previousContext != null) {
        previousContext.addGeneratedChild(renderBox);
      }
      previousContext = renderBox;
    }

    final int length = sequenceFill - lastPosition;
    System.arraycopy(sequenceElements, lastPosition, sequenceElements, openContexts, length);
    System.arraycopy(nodes, lastPosition, nodes, openContexts, length);
    sequenceFill = openContexts + length;
    Arrays.fill(sequenceElements, sequenceFill, sequenceElements.length, null);
    Arrays.fill(nodes, sequenceFill, nodes.length, null);

    return firstBox;
  }