lineStartBAP = context.getLineStartBorderAndPaddingWidth();
lineEndBAP = context.getLineEndBorderAndPaddingWidth();
alignmentContext = context.getAlignmentContext();
LinkedList returnList = new LinkedList();
KnuthSequence sequence = new InlineKnuthSequence();
AreaInfo ai = null;
AreaInfo prevAi = null;
returnList.add(sequence);
LineBreakStatus lbs = new LineBreakStatus();
iThisStart = iNextStart;
boolean inWord = false;
boolean inWhitespace = false;
char ch = 0;
while (iNextStart < textArray.length) {
ch = textArray[iNextStart];
boolean breakOpportunity = false;
byte breakAction = keepTogether? LineBreakStatus.PROHIBITED_BREAK : lbs.nextChar(ch);
switch (breakAction) {
case LineBreakStatus.COMBINING_PROHIBITED_BREAK:
case LineBreakStatus.PROHIBITED_BREAK:
break;
case LineBreakStatus.EXPLICIT_BREAK:
break;
case LineBreakStatus.COMBINING_INDIRECT_BREAK:
case LineBreakStatus.DIRECT_BREAK:
case LineBreakStatus.INDIRECT_BREAK:
breakOpportunity = true;
break;
default:
log.error("Unexpected breakAction: " + breakAction);
}
if (inWord) {
if (breakOpportunity || isSpace(ch) || ch == NEWLINE) {
//Word boundary found, process widths and kerning
int lastIndex = iNextStart;
while (lastIndex > 0 && textArray[lastIndex - 1] == CharUtilities.SOFT_HYPHEN) {
lastIndex--;
}
int wordLength = lastIndex - iThisStart;
boolean kerning = font.hasKerning();
MinOptMax wordIPD = new MinOptMax(0);
for (int i = iThisStart; i < lastIndex; i++) {
char c = textArray[i];
//character width
int charWidth = font.getCharWidth(c);
wordIPD.add(charWidth);
//kerning
if (kerning) {
int kern = 0;
if (i > iThisStart) {
char previous = textArray[i - 1];
kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
} else if (prevAi != null && !prevAi.isSpace && prevAi.iBreakIndex > 0) {
char previous = textArray[prevAi.iBreakIndex - 1];
kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
}
if (kern != 0) {
//log.info("Kerning between " + previous + " and " + c + ": " + kern);
addToLetterAdjust(i, kern);
wordIPD.add(kern);
}
}
}
if (kerning && breakOpportunity && !isSpace(ch) && lastIndex > 0 && textArray[lastIndex] == CharUtilities.SOFT_HYPHEN) {
int kern = font.getKernValue(textArray[lastIndex - 1], ch) * font.getFontSize() / 1000;
if (kern != 0) {
addToLetterAdjust(lastIndex, kern);
}
}
int iLetterSpaces = wordLength - 1;
// if there is a break opportunity and the next one
// is not a space, it could be used as a line end;
// add one more letter space, in case other text follows
if (breakOpportunity && !isSpace(ch)) {
iLetterSpaces++;
}
wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));
// create the AreaInfo object
ai = new AreaInfo(iThisStart, (short)lastIndex, (short) 0,
(short) iLetterSpaces,
wordIPD, textArray[lastIndex] == CharUtilities.SOFT_HYPHEN, false, breakOpportunity);
vecAreaInfo.add(ai);
prevAi = ai;
iTempStart = iNextStart;
// create the elements
sequence.addAll(createElementsForAWordFragment(alignment, ai,
vecAreaInfo.size() - 1, letterSpaceIPD));
ai = null;
iThisStart = iNextStart;
}
} else if (inWhitespace) {
if (ch != CharUtilities.SPACE || breakOpportunity) {
// End of whitespace
// create the AreaInfo object
ai = new AreaInfo(iThisStart, (short) (iNextStart),
(short) (iNextStart - iThisStart), (short) 0,
MinOptMax.multiply(wordSpaceIPD, iNextStart - iThisStart),
false, true, breakOpportunity);
vecAreaInfo.add(ai);
prevAi = ai;
// create the elements
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1));
ai = null;
iThisStart = iNextStart;
}
} else {
if (ai != null) {
vecAreaInfo.add(ai);
prevAi = ai;
ai.breakOppAfter = ch == CharUtilities.SPACE || breakOpportunity;
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1));
ai = null;
}
if (breakAction == LineBreakStatus.EXPLICIT_BREAK) {
if (lineEndBAP != 0) {
sequence.add
(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), true));
}
sequence.endSequence();
sequence = new InlineKnuthSequence();
returnList.add(sequence);
}
}
if ((ch == CharUtilities.SPACE
&& foText.getWhitespaceTreatment() == Constants.EN_PRESERVE)
|| ch == CharUtilities.NBSPACE) {
// preserved space or non-breaking space:
// create the AreaInfo object
ai = new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false, true, breakOpportunity);
iThisStart = (short) (iNextStart + 1);
} else if (CharUtilities.isFixedWidthSpace(ch) || CharUtilities.isZeroWidthSpace(ch)) {
// create the AreaInfo object
MinOptMax ipd = new MinOptMax(font.getCharWidth(ch));
ai = new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 0, (short) 0,
ipd, false, true, breakOpportunity);
iThisStart = (short) (iNextStart + 1);
} else if (ch == NEWLINE) {
// linefeed; this can happen when linefeed-treatment="preserve"
iThisStart = (short) (iNextStart + 1);
}
inWord = !isSpace(ch) && ch != NEWLINE;
inWhitespace = ch == CharUtilities.SPACE && foText.getWhitespaceTreatment() != Constants.EN_PRESERVE;
iNextStart++;
} // end of while
// Process any last elements
if (inWord) {
int lastIndex = iNextStart;
if (textArray[iNextStart - 1] == CharUtilities.SOFT_HYPHEN) {
lastIndex--;
}
int wordLength = lastIndex - iThisStart;
boolean kerning = font.hasKerning();
MinOptMax wordIPD = new MinOptMax(0);
for (int i = iThisStart; i < lastIndex; i++) {
char c = textArray[i];
//character width
int charWidth = font.getCharWidth(c);
wordIPD.add(charWidth);
//kerning
if (kerning) {
int kern = 0;
if (i > iThisStart) {
char previous = textArray[i - 1];
kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
} else if (prevAi != null && !prevAi.isSpace) {
char previous = textArray[prevAi.iBreakIndex - 1];
kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
}
if (kern != 0) {
//log.info("Kerning between " + previous + " and " + c + ": " + kern);
addToLetterAdjust(i, kern);
wordIPD.add(kern);
}
}
}
int iLetterSpaces = wordLength - 1;
wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));
// create the AreaInfo object
ai = new AreaInfo(iThisStart, (short)lastIndex, (short) 0,
(short) iLetterSpaces,
wordIPD, false, false, false);
vecAreaInfo.add(ai);
iTempStart = iNextStart;
// create the elements
sequence.addAll(createElementsForAWordFragment(alignment, ai,
vecAreaInfo.size() - 1, letterSpaceIPD));
ai = null;
} else if (inWhitespace) {
ai = new AreaInfo(iThisStart, (short) (iNextStart),
(short) (iNextStart - iThisStart), (short) 0,
MinOptMax.multiply(wordSpaceIPD, iNextStart - iThisStart),
false, true, true);
vecAreaInfo.add(ai);
// create the elements
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1));
ai = null;
} else if (ai != null) {
vecAreaInfo.add(ai);
ai.breakOppAfter = ch == CharUtilities.ZERO_WIDTH_SPACE;
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1));
ai = null;
} else if (ch == NEWLINE) {
if (lineEndBAP != 0) {
sequence.add
(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), true));
}
sequence.endSequence();
sequence = new InlineKnuthSequence();
returnList.add(sequence);
}
if (((List)returnList.getLast()).size() == 0) {
//Remove an empty sequence because of a trailing newline