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