/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.layout.process;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderLength;
import org.pentaho.reporting.engine.classic.core.layout.model.context.BoxDefinition;
import org.pentaho.reporting.engine.classic.core.layout.process.util.MinorAxisNodeContext;
import org.pentaho.reporting.engine.classic.core.layout.process.util.ProcessUtility;
public class MinorAxisLayoutStepUtil
{
public static final RenderLength FULL_WIDTH_LENGTH = RenderLength.createFromRaw(-100);
private MinorAxisLayoutStepUtil()
{
}
public static long resolveNodeWidthOnStart(final RenderBox box,
final MinorAxisNodeContext nodeContext,
final long x)
{
final long width = resolveNodeWidthOnStartInternal(box, nodeContext);
return correctForRoundingErrors(nodeContext, x, width);
}
private static long correctForRoundingErrors(final MinorAxisNodeContext nodeContext, final long x, final long width)
{
final long parentX2 = nodeContext.getParentX2();
if (parentX2 == 0)
{
return width;
}
final long currentX2 = width + x;
final long delta = Math.abs(parentX2 - currentX2);
if (delta != 0 && delta < 10)
{
// prefer the parent's edge over the calculated edge. We only do that when the edges are close by,
// usually after a rounding error.
return parentX2 - x;
}
return width;
}
/**
* Resolves the current element against the parent's content-area.
*
* @param box
* @return
*/
private static long resolveNodeWidthOnStartInternal(final RenderBox box,
final MinorAxisNodeContext nodeContext)
{
final long minChunkWidth = 0;
final BoxDefinition boxDef = box.getBoxDefinition();
final RenderLength minLength = boxDef.getMinimumWidth();
final RenderLength prefLength = boxDef.getPreferredWidth();
final RenderLength maxLength = boxDef.getMaximumWidth();
final long bcw = nodeContext.getBlockContextWidth();
final long min = minLength.resolve(bcw, 0);
final long max = maxLength.resolve(bcw, ComputeStaticPropertiesProcessStep.MAX_AUTO);
if (box.getBoxDefinition().isSizeSpecifiesBorderBox())
{
final long parentSize = nodeContext.getResolvedPreferredSize();
// We are assuming that any size specified by the user already includes the padding and borders.
// min-chunk-width must take insets into account. We will not add the insets to the computed width.
final long pref = prefLength.resolve(bcw, Math.max(parentSize, minChunkWidth));
return ProcessUtility.computeLength(min, max, pref);
}
else
{
// We are assuming that any size specified by the user does not include padding or border.
// min-chunk-width is used without borders. We will add the insets unconditionally later.
final long parentSize = nodeContext.getResolvedPreferredSize() - box.getInsets();
final long pref = prefLength.resolve(bcw, Math.max(parentSize, minChunkWidth));
return ProcessUtility.computeLength(min, max, pref) + box.getInsets();
}
}
public static long resolveNodeWidthOnStartForCanvasLegacy(final RenderBox box,
final MinorAxisNodeContext nodeContext,
final long x)
{
final long width = resolveNodeWidthOnStartForCanvasLegacyInternal(box, nodeContext);
return correctForRoundingErrors(nodeContext, x, width);
}
/**
* Resolves the current element against the parent's content-area.
*
* @param box
* @return
*/
private static long resolveNodeWidthOnStartForCanvasLegacyInternal(final RenderBox box,
final MinorAxisNodeContext nodeContext)
{
final long minChunkWidth = 0;
final BoxDefinition boxDef = box.getBoxDefinition();
final RenderLength definedMinLength = boxDef.getMinimumWidth();
final RenderLength minLength;
if (definedMinLength.getValue() == 0)
{
// PRD-3857 - Auto-correcting min-size to 100% for zero-defined boxes that are not canvas
// blows up the min-chunk-width test
minLength = FULL_WIDTH_LENGTH;
}
else
{
minLength = definedMinLength;
}
final RenderLength prefLength = boxDef.getPreferredWidth();
final RenderLength maxLength = boxDef.getMaximumWidth();
final long bcw = nodeContext.getBlockContextWidth();
final long min = minLength.resolve(bcw, 0);
final long max = maxLength.resolve(bcw, ComputeStaticPropertiesProcessStep.MAX_AUTO);
if (box.getBoxDefinition().isSizeSpecifiesBorderBox())
{
final long parentSize = nodeContext.getResolvedPreferredSize();
// We are assuming that any size specified by the user already includes the padding and borders.
// min-chunk-width must take insets into account. We will not add the insets to the computed width.
final long pref = prefLength.resolve(bcw, Math.max(parentSize, minChunkWidth));
return ProcessUtility.computeLength(min, max, pref);
}
else
{
// We are assuming that any size specified by the user does not include padding or border.
// min-chunk-width is used without borders. We will add the insets unconditionally later.
final long parentSize = nodeContext.getResolvedPreferredSize() - box.getInsets();
final long pref = prefLength.resolve(bcw, Math.max(parentSize, minChunkWidth));
return ProcessUtility.computeLength(min, max, pref) + box.getInsets();
}
}
public static long resolveNodeWidthOnFinish(final RenderBox box,
final MinorAxisNodeContext nodeContext,
final boolean strictLegacyMode)
{
final long width = resolveNodeWidthOnFinishInternal(box, nodeContext, strictLegacyMode);
return correctForRoundingErrors(nodeContext, nodeContext.getX(), width);
}
/**
* If the element has no preferred size, apply the current element's constraints against the box children's used
* area.
*
* @param box
* @return
*/
private static long resolveNodeWidthOnFinishInternal(final RenderBox box,
final MinorAxisNodeContext nodeContext,
final boolean strictLegacyMode)
{
final BoxDefinition boxDef = box.getBoxDefinition();
if (RenderLength.AUTO.equals(boxDef.getPreferredWidth()) == false)
{
return nodeContext.getWidth();
}
final long minChunkWidth;
final RenderLength minLength;
if (strictLegacyMode == false || box.useMinimumChunkWidth())
{
minChunkWidth = nodeContext.getMaxChildX2() - nodeContext.getX1();
minLength = boxDef.getMinimumWidth();
}
else
{
minChunkWidth = nodeContext.getX2() - nodeContext.getX1();
if (boxDef.getMinimumWidth().getValue() == 0)
{
minLength = FULL_WIDTH_LENGTH;
}
else
{
minLength = boxDef.getMinimumWidth();
}
}
final RenderLength maxLength = boxDef.getMaximumWidth();
final long bcw = nodeContext.getBlockContextWidth();
final long min = minLength.resolve(bcw, 0);
final long max = maxLength.resolve(bcw, ComputeStaticPropertiesProcessStep.MAX_AUTO);
if (box.getBoxDefinition().isSizeSpecifiesBorderBox())
{
final long parentSize = nodeContext.getResolvedPreferredSize();
// We are assuming that any size specified by the user already includes the padding and borders.
// min-chunk-width must take insets into account. We will not add the insets to the computed width.
final long pref = Math.max(parentSize, minChunkWidth + box.getInsets());
return ProcessUtility.computeLength(min, max, pref);
}
else
{
// We are assuming that any size specified by the user does not include padding or border.
// min-chunk-width is used without borders. We will add the insets unconditionally later.
final long parentSize = nodeContext.getResolvedPreferredSize() - box.getInsets();
final long pref = Math.max(parentSize, minChunkWidth);
return ProcessUtility.computeLength(min, max, pref) + box.getInsets();
}
}
/**
* Calculates the minimum area a element will consume. The returned value references the border-box,
* the area that includes border, padding and content-box.
*
* @param box
* @return
*/
public static long resolveNodeWidthForMinChunkCalculation(final RenderBox box)
{
final BoxDefinition boxDef = box.getBoxDefinition();
final RenderLength minLength = boxDef.getMinimumWidth();
final RenderLength prefLength = boxDef.getPreferredWidth();
final RenderLength maxLength = boxDef.getMaximumWidth();
final long min = minLength.resolve(0, 0);
final long max = maxLength.resolve(0, ComputeStaticPropertiesProcessStep.MAX_AUTO);
if (box.getBoxDefinition().isSizeSpecifiesBorderBox())
{
// We are assuming that any size specified by the user already includes the padding and borders.
// min-chunk-width must take insets into account. We will not add the insets to the computed width.
final long pref = prefLength.resolve(0, box.getInsets());
return ProcessUtility.computeLength(min, max, pref);
}
else
{
// We are assuming that any size specified by the user does not include padding or border.
// min-chunk-width is used without borders. We will add the insets unconditionally later.
final long pref = prefLength.resolve(0, 0);
return ProcessUtility.computeLength(min, max, pref) + box.getInsets();
}
}
}