/*!
* 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.alignment;
import org.pentaho.reporting.engine.classic.core.layout.model.LayoutNodeTypes;
import org.pentaho.reporting.engine.classic.core.layout.model.PageGrid;
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.layout.output.OutputProcessorMetaData;
import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.InlineSequenceElement;
import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.SequenceList;
import org.pentaho.reporting.engine.classic.core.util.LongList;
import org.pentaho.reporting.libraries.base.util.FastStack;
import java.util.ArrayList;
public class FastAlignmentProcessor implements TextAlignmentProcessor {
private static final long MAX_SIZE = (long) Math.pow( 2, 50 );
private long start;
private long end;
private PageGrid breaks;
private boolean overflowX;
private long[] pagebreaks;
private ChunkIterator iterator;
public FastAlignmentProcessor() {
this.pagebreaks = new long[10];
}
public void initialize( final OutputProcessorMetaData metaData, final SequenceList sequence, final long start,
final long end, final PageGrid breaks, final boolean overflowX ) {
this.start = start;
this.end = end;
this.breaks = breaks;
this.overflowX = overflowX;
if ( overflowX ) {
this.end = MAX_SIZE;
}
updateBreaks();
this.iterator = new ChunkIterator( sequence, 0 );
}
private void updateBreaks() {
final long[] horizontalBreaks = breaks.getHorizontalBreaks();
final int breakCount = horizontalBreaks.length;
final LongList pageLongList = new LongList( breakCount );
for ( int i = 0; i < ( breakCount - 1 ); i++ ) {
final long pos = horizontalBreaks[i];
if ( pos <= start ) {
// skip ..
continue;
}
if ( overflowX == false && pos >= end ) {
break;
}
pageLongList.add( pos );
}
pageLongList.add( end );
this.pagebreaks = pageLongList.toArray( this.pagebreaks );
}
public void updateLineSize( final long start, final long end ) {
this.start = start;
this.end = end;
}
public void deinitialize() {
}
public boolean hasNext() {
return iterator.hasNext();
}
private long calculateWidth( final AlignmentChunk chunk, final boolean stripFirstSpacer ) {
final int chunkEnd = chunk.getEnd();
boolean first = stripFirstSpacer;
long length = 0;
for ( int i = chunk.getStart(); i < chunkEnd; i++ ) {
final RenderNode node = chunk.getNode( i );
final InlineSequenceElement sequenceElement = chunk.getSequenceElement( i );
final InlineSequenceElement.Classification classification = sequenceElement.getType();
if ( classification == InlineSequenceElement.Classification.CONTENT ) {
if ( first && node.getNodeType() == LayoutNodeTypes.TYPE_NODE_SPACER ) {
continue;
}
first = false;
}
final long minimumLength = sequenceElement.getMaximumWidth( node );
length += minimumLength;
}
return length;
}
public RenderBox next() {
boolean first = true;
long posX = start;
RenderBox rootBox = null;
final FastStack<RenderBox> context = new FastStack<RenderBox>();
while ( iterator.hasNext() ) {
final AlignmentChunk chunk = iterator.next();
final long chunkWidth = calculateWidth( chunk, first );
if ( first || posX + chunkWidth < end ) {
// simple, add that chunk ..
final int chunkEnd = chunk.getEnd();
for ( int i = chunk.getStart(); i < chunkEnd; i++ ) {
final RenderNode node = chunk.getNode( i );
final InlineSequenceElement sequenceElement = chunk.getSequenceElement( i );
final InlineSequenceElement.Classification classification = sequenceElement.getType();
final long minimumLength = sequenceElement.getMaximumWidth( node );
if ( classification == InlineSequenceElement.Classification.START ) {
node.setCachedX( posX );
final RenderBox renderBox = (RenderBox) node.derive( false );
context.push( renderBox );
if ( rootBox == null ) {
rootBox = renderBox;
}
} else if ( classification == InlineSequenceElement.Classification.END ) {
final RenderBox b = context.pop();
b.setCachedWidth( ( posX - b.getCachedX() ) + minimumLength );
if ( context.isEmpty() == false ) {
context.peek().addGeneratedChild( b );
}
} else {
if ( first == false || node.getNodeType() != LayoutNodeTypes.TYPE_NODE_SPACER ) {
final RenderNode n = node.derive( true );
n.setCachedX( posX );
n.setCachedWidth( minimumLength );
context.peek().addGeneratedChild( n );
} else {
continue;
}
first = false;
}
posX += minimumLength;
}
first = false;
} else {
final int size = context.size();
final ArrayList<RenderBox> paddingBoxes = new ArrayList<RenderBox>( size );
for ( int i = 0; i < size; i++ ) {
final RenderBox renderBox = context.get( i );
renderBox.setCachedWidth( posX - renderBox.getCachedX() );
final RenderBox split = renderBox.split( RenderNode.HORIZONTAL_AXIS );
paddingBoxes.add( split );
}
iterator = iterator.createPadding( chunk.getStart(), paddingBoxes );
break;
}
}
return rootBox;
}
}