//System.out.println("Chunks: " + numChunks);
float prevBotMargin = 0;
for (int chunk=0; clIter.hasNext(); chunk++) {
// System.out.println("Chunk: " + chunk);
AttributedCharacterIterator aci = acis[chunk];
if (currentRegion != null)
{
List extraP = (List)aci.getAttribute(FLOW_EMPTY_PARAGRAPH);
if (extraP != null) {
Iterator epi = extraP.iterator();
while (epi.hasNext()) {
MarginInfo emi = (MarginInfo)epi.next();
float inc = ((prevBotMargin > emi.getTopMargin())
? prevBotMargin
: emi.getTopMargin());
if ((dy + inc <= height) &&
!emi.isFlowRegionBreak()) {
dy += inc;
} else {
// Move to next flow region..
if (!flowRectsIter.hasNext()) {
currentRegion = null;
break; // No flow rect stop layout here...
}
// NEXT FLOW REGION
currentRegion = (RegionInfo) flowRectsIter.next();
height = (float) currentRegion.getHeight();
// start a new alignment offset for this flow rect.
verticalAlignOffset = new Point2D.Float(0,0);
// New rect so no previous row to consider...
dy = emi.getTopMargin();
}
prevBotMargin = emi.getBottomMargin();
}
if (currentRegion == null) break;
}
}
List gvl = new LinkedList();
List layouts = (List)clIter.next();
Iterator iter = layouts.iterator();
while (iter.hasNext()) {
GlyphLayout gl = (GlyphLayout)iter.next();
gvl.add(gl.getGlyphVector());
}
GVTGlyphVector gv = new MultiGlyphVector(gvl);
gvs[chunk] = gv;
int numGlyphs = gv.getNumGlyphs();
// System.out.println("Glyphs: " + numGlyphs);
aci.first();
MarginInfo mi = (MarginInfo)aci.getAttribute(FLOW_PARAGRAPH);
if (mi == null) {
continue;
}
int justification = mi.getJustification();
if (currentRegion == null) {
for(int idx=0; idx <numGlyphs; idx++)
gv.setGlyphVisible(idx, false);
continue;
}
float inc = ((prevBotMargin > mi.getTopMargin())
? prevBotMargin : mi.getTopMargin());
if (dy + inc <= height) {
dy += inc;
} else {
// Move to next flow region..
// NEXT FLOW REGION
if (!flowRectsIter.hasNext()) {
currentRegion = null;
break; // No flow rect stop layout here...
}
// NEXT FLOW REGION
currentRegion = (RegionInfo) flowRectsIter.next();
height = (float) currentRegion.getHeight();
// start a new alignment offset for this flow rect..
verticalAlignOffset = new Point2D.Float(0,0);
// New rect so no previous row to consider...
dy = mi.getTopMargin();
}
prevBotMargin = mi.getBottomMargin();
float leftMargin = mi.getLeftMargin();
float rightMargin = mi.getRightMargin();
if (((GlyphLayout)layouts.get(0)).isLeftToRight()) {
leftMargin += mi.getIndent();
} else {
rightMargin += mi.getIndent();
}
x0 = (float) currentRegion.getX() + leftMargin;
y0 = (float) currentRegion.getY();
width = (float) (currentRegion.getWidth() -
(leftMargin + rightMargin));
height = (float) currentRegion.getHeight();
List lineInfos = new LinkedList();
chunkLineInfos[chunk] = lineInfos;
float prevDesc = 0.0f;
GlyphIterator gi = new GlyphIterator(aci, gv);
gis[chunk] = gi;
GlyphIterator breakGI = null, newBreakGI = null;
if (!gi.done() && !gi.isPrinting()) {
// This will place any preceeding whitespace on an
// imaginary line that preceeds the real first line of
// the paragraph, also calculate the vertical
// alignment offset, this will be repeated until the
// last line in the flow rect.
updateVerticalAlignOffset(verticalAlignOffset,
currentRegion, dy);
lineInfos.add(gi.newLine
(new Point2D.Float(x0, y0+dy),
width, true, verticalAlignOffset));
}
GlyphIterator lineGI = gi.copy();
boolean firstLine = true;
while (!gi.done()) {
boolean doBreak = false;
boolean partial = false;
if (gi.isPrinting() && (gi.getAdv() > width)) {
if (breakGI == null) {
// first char on line didn't fit.
// move to next flow rect.
if (!flowRectsIter.hasNext()) {
currentRegion = null;
gi = lineGI.copy(gi);
break; // No flow rect stop layout here...
}
// NEXT FLOW REGION
currentRegion = (RegionInfo) flowRectsIter.next();
x0 = (float) currentRegion.getX() + leftMargin;
y0 = (float) currentRegion.getY();
width = (float) (currentRegion.getWidth() -
(leftMargin+rightMargin));
height = (float) currentRegion.getHeight();
// start a new alignment offset for this flow rect..
verticalAlignOffset = new Point2D.Float(0,0);
// New rect so no previous row to consider...
dy = firstLine ? mi.getTopMargin() : 0;
;
prevDesc = 0;
gi = lineGI.copy(gi);
continue;
}
gi = breakGI.copy(gi); // Back up to break loc...
nextLineMult = 1;
doBreak = true;
partial = false;
} else if (gi.isLastChar()) {
nextLineMult = 1;
doBreak = true;
partial = true;
}
int lnBreaks = gi.getLineBreaks();
if (lnBreaks != 0) {
if (doBreak)
nextLineMult -= 1;
nextLineMult += lnBreaks;
doBreak = true;
partial = true;
}
if (!doBreak) {
// System.out.println("No Brk Adv: " + gi.getAdv());
// We don't need to break the line because of this glyph
// So we just check if we need to update our break loc.
if ((gi.isBreakChar()) ||
(breakGI == null) ||
(!breakGI.isBreakChar())) {
// Make this the new break if curr char is a
// break char or we don't have any break chars
// yet, or our current break char is also not
// a break char.
newBreakGI = gi.copy(newBreakGI);
gi.nextChar();
if (gi.getChar() != GlyphIterator.ZERO_WIDTH_JOINER) {
GlyphIterator tmpGI = breakGI;
breakGI = newBreakGI;
newBreakGI = tmpGI;
}
} else {
gi.nextChar();
}
continue;
}
// System.out.println(" Brk Adv: " + gi.getAdv());
// We will now attempt to break the line just
// after 'gi'.
// Note we are trying to figure out where the current
// line is going to be placed (not the next line). We
// must wait until we have a potential line break so
// we know how tall the line is.
// Get the nomial line advance based on the
// largest font we encountered on line...
float lineSize = gi.getMaxAscent()+gi.getMaxDescent();
float lineBoxHeight;
if (lineHeightRelative)
lineBoxHeight = gi.getMaxFontSize()*lineHeight;
else
lineBoxHeight = lineHeight;
float halfLeading = (lineBoxHeight-lineSize)/2;
float ladv = prevDesc + halfLeading + gi.getMaxAscent();
float newDesc = halfLeading + gi.getMaxDescent();
dy += ladv;
float bottomEdge = newDesc;
if (newDesc < gi.getMaxDescent())
bottomEdge = gi.getMaxDescent();
if ((dy + bottomEdge) > height) {
// The current Line doesn't fit in the
// current flow rectangle so we need to
// move line to the next flow rect.
// System.out.println("Doesn't Fit: " + dy);
if (!flowRectsIter.hasNext()) {
currentRegion = null;
gi = lineGI.copy(gi);
break; // No flow rect stop layout here...
}
// Remember how wide this rectangle is...
float oldWidth = width;
// Get info for new flow rect.
currentRegion = (RegionInfo) flowRectsIter.next();
x0 = (float) currentRegion.getX() + leftMargin;
y0 = (float) currentRegion.getY();
width = (float)(currentRegion.getWidth() -
(leftMargin+rightMargin));
height = (float) currentRegion.getHeight();
// start a new alignment offset for this flow rect..
verticalAlignOffset = new Point2D.Float(0,0);
// New rect so no previous row to consider...
dy = firstLine ? mi.getTopMargin() : 0;
;
prevDesc = 0;
// previous flows?
if (gi.getAdv() > oldWidth) {
// need to back up to start of line...
gi = lineGI.copy(gi);
}
continue;
}
prevDesc = newDesc + (nextLineMult-1)*lineBoxHeight;
nextLineMult = 0f;
updateVerticalAlignOffset(verticalAlignOffset,
currentRegion, dy + bottomEdge);
lineInfos.add(gi.newLine
(new Point2D.Float(x0, y0 + dy), width, partial,
verticalAlignOffset));
// System.out.println("Fit: " + dy);
x0 -= leftMargin;
width += leftMargin+rightMargin;
leftMargin = mi.getLeftMargin();
rightMargin = mi.getRightMargin();
x0 += leftMargin;
width -= leftMargin+rightMargin;
firstLine = false;
// The line fits in the current flow rectangle.
lineGI = gi.copy(lineGI);
breakGI = null;
}
dy += prevDesc;
int idx = gi.getGlyphIndex();
while(idx <numGlyphs)
gv.setGlyphVisible(idx++, false);
if (mi.isFlowRegionBreak()) {
// Move to next flow region..
currentRegion = null;
if (flowRectsIter.hasNext()) {
currentRegion = (RegionInfo) flowRectsIter.next();
height = (float) currentRegion.getHeight();
dy = mi.getTopMargin();
verticalAlignOffset = new Point2D.Float(0,0);
}
}
}
for (int chunk=0; chunk < acis.length; chunk++) {
List lineInfos = chunkLineInfos[chunk];
if (lineInfos == null) continue;
AttributedCharacterIterator aci = acis[chunk];
aci.first();
MarginInfo mi = (MarginInfo)aci.getAttribute(FLOW_PARAGRAPH);
if (mi == null) {
continue;
}
int justification = mi.getJustification();