/**
* ===========================================
* LibLayout : a free Java layouting library
* ===========================================
*
* Project Info: http://reporting.pentaho.org/liblayout/
*
* (C) Copyright 2006-2007, by Pentaho Corporation and Contributors.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------
* $Id: ComputeICMMetricsStep.java 6653 2008-12-02 14:53:40Z tmorgner $
* ------------
* (C) Copyright 2006-2007, by Pentaho Corporation.
*/
package org.jfree.layouting.renderer.process;
import org.jfree.layouting.renderer.border.RenderLength;
import org.jfree.layouting.renderer.model.ParagraphRenderBox;
import org.jfree.layouting.renderer.model.RenderBox;
import org.jfree.layouting.renderer.model.RenderNode;
import org.jfree.layouting.renderer.model.RenderableReplacedContent;
import org.jfree.layouting.renderer.model.ComputedLayoutProperties;
import org.jfree.layouting.renderer.model.page.LogicalPageBox;
import org.jfree.layouting.util.geom.StrictDimension;
/**
* This step performs the first layouting step. The ICM-step computes the
* preferred size of all elements (that is the minimum size the element would
* consume if there were infinite space available) and the minimum chunk size
* (that is the biggest unbreakable content in an element).
* <p/>
* The preferred size is based on the box size (that means: No margins
* included!).
* <p/>
* That step produces the preferred size for the nodes.
* <p/>
* As long as paragraphs can be nested, we cannot assume anything here. A nested
* paragraph can have linebreaks all the time and thus it is dangerous to skip
* the ICM-Computation on such nodes. Maybe we can tweak something with a change
* counter or so.
*
* @author Thomas Morgner
*/
public class ComputeICMMetricsStep extends IterateVisualProcessStep
{
public ComputeICMMetricsStep()
{
}
public void compute(final LogicalPageBox root)
{
startProcessing(root);
}
protected void processParagraphChilds(final ParagraphRenderBox box)
{
processBoxChilds(box.getLineboxContainer());
//startProcessing(box.getLineboxContainer());
}
protected boolean startBlockLevelBox(final RenderBox box)
{
// if (box.isOpen())
// {
// return true;
// }
// if (box.isIcmMetricsFinished() == false)
// {
// return true;
// }
// return false;
return true;
}
protected boolean startInlineLevelBox(final RenderBox box)
{
// if (box.isOpen())
// {
// return true;
// }
// if (box.isIcmMetricsFinished() == false)
// {
// return true;
// }
// return false;
return true;
}
protected void finishInlineLevelBox(final RenderBox box)
{
// Sum up the width; Maximize the height.; add borders and padding
final ComputedLayoutProperties blp = box.getComputedLayoutProperties();
// horizontal border and padding ..
final long hbp = blp.getBorderLeft() + blp.getBorderRight() +
blp.getPaddingLeft() + blp.getPaddingRight() +
blp.getMarginLeft() + blp.getMarginRight();
long minChunkWidth = 0;
long maxBoxWidth = 0;
RenderNode node = box.getVisibleFirst();
while (node != null)
{
maxBoxWidth += node.getMaximumBoxWidth();
final long childChunkWidth = node.getMinimumChunkWidth();
if (childChunkWidth > minChunkWidth)
{
minChunkWidth = childChunkWidth;
}
node = node.getVisibleNext();
}
box.setMinimumChunkWidth(hbp + minChunkWidth);
box.setMaximumBoxWidth(hbp + maxBoxWidth);
box.setIcmMetricsFinished(box.isOpen() == false);
}
protected void finishBlockLevelBox(final RenderBox box)
{
// Sum up the height; Maximize the width.; add borders and padding
final ComputedLayoutProperties blp = box.getComputedLayoutProperties();
// horizontal border and padding ..
final long hbp = blp.getBorderLeft() + blp.getBorderRight() +
blp.getPaddingLeft() + blp.getPaddingRight() +
blp.getMarginLeft() + blp.getMarginRight();
if (box instanceof ParagraphRenderBox)
{
// No margins, no additional checks. And we can be sure that this one
// is the only child. (This is a cheap shortcut).
final ParagraphRenderBox paragraph = (ParagraphRenderBox) box;
final RenderNode linebox = paragraph.getLineboxContainer();
box.setMinimumChunkWidth(hbp + linebox.getMinimumChunkWidth());
box.setMaximumBoxWidth(hbp + linebox.getMaximumBoxWidth());
box.setIcmMetricsFinished(box.isOpen() == false);
return;
}
long minChunkWidth = 0;
long maxBoxWidth = 0;
RenderNode node = box.getVisibleFirst();
while (node != null)
{
final long childChunkWidth = node.getMinimumChunkWidth();
if (childChunkWidth > minChunkWidth)
{
minChunkWidth = childChunkWidth;
}
final long childBoxWidth = node.getMaximumBoxWidth();
if (childBoxWidth > maxBoxWidth)
{
maxBoxWidth = childBoxWidth;
}
node = node.getVisibleNext();
}
box.setMinimumChunkWidth(hbp + minChunkWidth);
box.setMaximumBoxWidth(hbp + maxBoxWidth);
box.setIcmMetricsFinished(box.isOpen() == false);
}
protected void processInlineLevelNode(final RenderNode node)
{
// These nodes have no real change tracker; they are almost immutable anyway
if (node.isIcmMetricsFinished())
{
return;
}
if (node instanceof RenderableReplacedContent)
{
final RenderableReplacedContent rpc = (RenderableReplacedContent) node;
final RenderLength requestedWidth = rpc.getRequestedWidth();
final StrictDimension contentSize = rpc.getContentSize();
if (requestedWidth == RenderLength.AUTO)
{
node.setMaximumBoxWidth(contentSize.getWidth());
}
else
{
node.setMaximumBoxWidth(requestedWidth.resolve(contentSize.getWidth()));
}
node.setMinimumChunkWidth(0);
// replaced content cannot have any childs anymore, so it is safe to
// set this flag to an unconditional true.
node.setIcmMetricsFinished(true);
}
// Text and spacer nodes have been computed at construction time ..
}
protected void processBlockLevelNode(final RenderNode node)
{
// These nodes have no real change tracker; they are almost immutable anyway
if (node.isIcmMetricsFinished())
{
return;
}
if (node instanceof RenderableReplacedContent)
{
final RenderableReplacedContent rpc = (RenderableReplacedContent) node;
final RenderLength requestedWidth = rpc.getRequestedWidth();
final StrictDimension contentSize = rpc.getContentSize();
if (requestedWidth == RenderLength.AUTO)
{
node.setMaximumBoxWidth(contentSize.getWidth());
}
else
{
node.setMaximumBoxWidth(requestedWidth.resolve(contentSize.getWidth()));
}
node.setMinimumChunkWidth(0);
// replaced content cannot have any childs anymore, so it is safe to
// set this flag to an unconditional true.
node.setIcmMetricsFinished(true);
}
// Text and spacer nodes have been computed at construction time ..
}
}