/*!
* 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.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.layout.model.FinishedRenderNode;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderNode;
import org.pentaho.reporting.engine.classic.core.util.RingBuffer;
public class WidowBlockContext implements WidowContext {
private static final Log logger = LogFactory.getLog( WidowBlockContext.class );
private StackedObjectPool<WidowBlockContext> pool;
private WidowContext parent;
private RenderBox contextBox;
private int widows;
private int widowCount;
private RingBuffer<RenderNode> widowSize;
private long widowOverride;
private long widowOverrideWithKeepTogether;
private RenderNode currentNode;
private boolean breakMarkerSeen;
public WidowBlockContext() {
}
public void init( final StackedObjectPool<WidowBlockContext> pool, final WidowContext parent,
final RenderBox contextBox, final int widows ) {
this.breakMarkerSeen = false;
this.pool = pool;
this.parent = parent;
this.contextBox = contextBox;
this.widows = widows;
this.widowCount = 0;
this.widowOverride = contextBox.getCachedY2();
this.widowOverrideWithKeepTogether = contextBox.getCachedY2();
if ( widows > 0 ) {
if ( this.widowSize == null ) {
this.widowSize = new RingBuffer<RenderNode>( widows );
} else {
this.widowSize.resize( widows );
}
}
}
public void startChild( final RenderBox box ) {
currentNode = box;
if ( parent != null ) {
parent.startChild( box );
}
}
public void endChild( final RenderBox box ) {
if ( currentNode != null ) {
if ( widowCount < widows && widows > 0 ) {
widowSize.add( box );
box.setRestrictFinishedClearOut( RenderBox.RestrictFinishClearOut.LEAF );
}
widowCount += 1;
currentNode = null;
}
if ( parent != null ) {
parent.endChild( box );
}
}
public void registerFinishedNode( final FinishedRenderNode box ) {
if ( widowCount < widows && widows > 0 ) {
widowSize.add( box );
box.getParent().setRestrictFinishedClearOut( RenderBox.RestrictFinishClearOut.RESTRICTED );
}
widowCount += box.getWidowLeafCount();
currentNode = null;
if ( parent != null ) {
parent.registerFinishedNode( box );
}
}
public void registerBreakMark( final RenderBox box ) {
breakMarkerSeen = true;
if ( parent != null ) {
parent.registerBreakMark( box );
}
}
private long getWidowValue() {
if ( widows == 0 ) {
return widowOverride;
}
final RenderNode box = widowSize.getLastValue();
if ( box == null ) {
return widowOverride;
}
final long y2 = box.getCachedY2() - box.getCachedHeight();
return Math.min( widowOverride, y2 );
}
public WidowContext commit( final RenderBox box ) {
final boolean keepTogether = box.getStaticBoxLayoutProperties().isAvoidPagebreakInside();
final long constraintSize;
final long widowValue = getWidowValue();
if ( keepTogether ) {
constraintSize = box.getCachedY2() - box.getCachedY();
} else {
constraintSize = box.getCachedY2() - widowValue;
}
box.setWidowConstraintSizeWithKeepTogether( constraintSize );
box.setWidowConstraintSize( box.getCachedY2() - widowValue );
box.setWidowLeafCount( widowCount );
if ( breakMarkerSeen == false && box.isInvalidWidowOrphanNode() == false ) {
final boolean incomplete = box.isOpen() || box.getContentRefCount() > 0;
if ( incomplete ) {
if ( widows > 0 && widowCount == 0 ) {
// the box is open, has a widow-constraint and has not seen a single widow box yet.
box.setInvalidWidowOrphanNode( true );
} else {
box.setInvalidWidowOrphanNode( false );
}
} else {
// the box is safe to process
box.setInvalidWidowOrphanNode( false );
}
}
if ( widowSize != null ) {
for ( int i = 0; i < widowSize.size(); i += 1 ) {
final RenderNode renderNode = widowSize.get( i );
if ( renderNode == null ) {
continue;
}
if ( renderNode instanceof RenderBox ) {
final RenderBox rbox = (RenderBox) renderNode;
rbox.setWidowBox( true );
}
}
}
if ( parent != null ) {
parent.subContextCommitted( box );
}
return parent;
}
public void subContextCommitted( final RenderBox contextBox ) {
final long cachedY2 = contextBox.getCachedY2();
if ( cachedY2 > getWidowValue() || ( cachedY2 == this.contextBox.getCachedY2() && cachedY2 == getWidowValue() ) ) {
widowOverride = Math.min( widowOverride, cachedY2 - contextBox.getWidowConstraintSize() );
widowOverrideWithKeepTogether =
Math.min( widowOverrideWithKeepTogether, cachedY2 - contextBox.getWidowConstraintSizeWithKeepTogether() );
}
if ( parent != null ) {
parent.subContextCommitted( contextBox );
}
}
public void clearForPooledReuse() {
parent = null;
contextBox = null;
pool.free( this );
}
}