/*!
* 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();
}
}
}