diff options
Diffstat (limited to 'src/java/org/apache/fop/layoutmgr/TextLayoutManager.java')
-rw-r--r-- | src/java/org/apache/fop/layoutmgr/TextLayoutManager.java | 598 |
1 files changed, 521 insertions, 77 deletions
diff --git a/src/java/org/apache/fop/layoutmgr/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/TextLayoutManager.java index 59ddcc73a..e3abe293c 100644 --- a/src/java/org/apache/fop/layoutmgr/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/TextLayoutManager.java @@ -19,8 +19,12 @@ package org.apache.fop.layoutmgr; import java.util.ArrayList; +import java.util.List; +import java.util.LinkedList; +import java.util.ListIterator; import org.apache.fop.fo.FOText; +import org.apache.fop.fo.Constants; import org.apache.fop.traits.SpaceVal; import org.apache.fop.area.Trait; import org.apache.fop.area.inline.InlineArea; @@ -45,18 +49,31 @@ public class TextLayoutManager extends AbstractLayoutManager { private short iStartIndex; private short iBreakIndex; private short iWScount; + private short iLScount; private MinOptMax ipdArea; private boolean bHyphenated; - public AreaInfo(short iSIndex, short iBIndex, short iWS, - MinOptMax ipd, boolean bHyph) { + public AreaInfo(short iSIndex, short iBIndex, short iWS, short iLS, + MinOptMax ipd, boolean bHyph) { iStartIndex = iSIndex; iBreakIndex = iBIndex; iWScount = iWS; + iLScount = iLS; ipdArea = ipd; bHyphenated = bHyph; } } + // this class stores information about changes in vecAreaInfo + // which are not yet applied + private class PendingChange { + public AreaInfo ai; + public int index; + + public PendingChange(AreaInfo ai, int index) { + this.ai = ai; + this.index = index; + } + } // Hold all possible breaks for the text in this LM's FO. private ArrayList vecAreaInfo; @@ -85,6 +102,8 @@ public class TextLayoutManager extends AbstractLayoutManager { // private MinOptMax nextIPD = new MinOptMax(0); /** size of a space character (U+0020) glyph in current font */ private int spaceCharIPD; + private MinOptMax wordSpaceIPD; + private MinOptMax letterSpaceIPD; /** size of the hyphen character glyph in current font */ private int hyphIPD; /** 1/2 of word-spacing value */ @@ -92,6 +111,12 @@ public class TextLayoutManager extends AbstractLayoutManager { /** Number of space characters after previous possible break position. */ private int iNbSpacesPending; + private boolean bChanged = false; + private int iReturnedIndex = 0; + private short iThisStart = 0; + private short iTempStart = 0; + private LinkedList changeList = null; + /** * Create a Text layout manager. * @@ -114,6 +139,23 @@ public class TextLayoutManager extends AbstractLayoutManager { SpaceVal ws = foText.textInfo.wordSpacing; halfWS = new SpaceVal(MinOptMax.multiply(ws.getSpace(), 0.5), ws.isConditional(), ws.isForcing(), ws.getPrecedence()); + SpaceVal ls = foText.textInfo.letterSpacing; + + // letter space applies only to consecutive non-space characters, + // while word space applies to space characters; + // i.e. the spaces in the string "A SIMPLE TEST" are: + // A<<ws>>S<ls>I<ls>M<ls>P<ls>L<ls>E<<ws>>T<ls>E<ls>S<ls>T + // there is no letter space after the last character of a word, + // nor after a space character + + // set letter space and word space dimension; + // the default value "normal" was converted into a MinOptMax value + // in the PropertyManager.getTextLayoutProps() method + letterSpaceIPD = new MinOptMax(ls.getSpace().min, + ls.getSpace().opt, ls.getSpace().max); + wordSpaceIPD = new MinOptMax(spaceCharIPD + ws.getSpace().min, + spaceCharIPD + ws.getSpace().opt, + spaceCharIPD + ws.getSpace().max); } /** @@ -141,8 +183,9 @@ public class TextLayoutManager extends AbstractLayoutManager { // Skip all leading spaces for hyphenation int i; for (i = ai.iStartIndex; - i < ai.iBreakIndex && CharUtilities.isAnySpace(textArray[i]) == true; - i++) { + i < ai.iBreakIndex + && CharUtilities.isAnySpace(textArray[i]) == true; + i++) { //nop } sbChars.append(new String(textArray, i, ai.iBreakIndex - i)); @@ -159,10 +202,12 @@ public class TextLayoutManager extends AbstractLayoutManager { */ public boolean canBreakBefore(LayoutContext context) { char c = textArray[iNextStart]; - return ((c == NEWLINE) || (foText.textInfo.bWrap + return ((c == NEWLINE) + || (foText.textInfo.bWrap && (CharUtilities.isBreakableSpace(c) - || (BREAK_CHARS.indexOf(c) >= 0 && (iNextStart == 0 - || Character.isLetterOrDigit(textArray[iNextStart-1])))))); + || (BREAK_CHARS.indexOf(c) >= 0 + && (iNextStart == 0 + || Character.isLetterOrDigit(textArray[iNextStart-1])))))); } /** @@ -174,8 +219,8 @@ public class TextLayoutManager extends AbstractLayoutManager { if (prevPos != null) { // ASSERT (prevPos.getLM() == this) if (prevPos.getLM() != this) { - log.error( - "TextLayoutManager.resetPosition: " + "LM mismatch!!!"); + log.error("TextLayoutManager.resetPosition: " + + "LM mismatch!!!"); } LeafPosition tbp = (LeafPosition) prevPos; AreaInfo ai = @@ -260,7 +305,7 @@ public class TextLayoutManager extends AbstractLayoutManager { */ if (context.suppressLeadingSpace()) { for (; iNextStart < textArray.length - && textArray[iNextStart] == SPACE; iNextStart++) { + && textArray[iNextStart] == SPACE; iNextStart++) { } // If now at end, nothing to compose here! if (iNextStart >= textArray.length) { @@ -293,7 +338,7 @@ public class TextLayoutManager extends AbstractLayoutManager { ++iWScount; // Counted as word-space if (iNextStart == iThisStart - && (iFlags & BreakPoss.ISFIRST) != 0) { + && (iFlags & BreakPoss.ISFIRST) != 0) { // If possible, treat as normal inter-word space if (context.getLeadingSpace().hasSpaces()) { context.getLeadingSpace().addSpace(halfWS); @@ -330,8 +375,8 @@ public class TextLayoutManager extends AbstractLayoutManager { iFlags |= BreakPoss.ALL_ARE_SUPPRESS_AT_LB; } return makeBreakPoss(iThisStart, spaceIPD, wordIPD, - context.getLeadingSpace(), pendingSpace, iFlags, - iWScount); + context.getLeadingSpace(), pendingSpace, + iFlags, iWScount); } if (context.tryHyphenate()) { @@ -356,7 +401,8 @@ public class TextLayoutManager extends AbstractLayoutManager { if (c != SPACE) { iNextStart++; if (c != NEWLINE) { - wordIPD += foText.textInfo.fs.getCharWidth(c); + wordIPD + += foText.textInfo.fs.getCharWidth(c); } else { iFlags |= BreakPoss.FORCE; } @@ -373,8 +419,8 @@ public class TextLayoutManager extends AbstractLayoutManager { iFlags |= BreakPoss.REST_ARE_SUPPRESS_AT_LB; } return makeBreakPoss(iThisStart, spaceIPD, wordIPD, - context.getLeadingSpace(), null, iFlags, - iWScount); + context.getLeadingSpace(), null, + iFlags, iWScount); } wordIPD += foText.textInfo.fs.getCharWidth(c); // Note, if a normal non-breaking space, is it stretchable??? @@ -382,12 +428,14 @@ public class TextLayoutManager extends AbstractLayoutManager { } } return makeBreakPoss(iThisStart, spaceIPD, wordIPD, - context.getLeadingSpace(), null, iFlags, iWScount); + context.getLeadingSpace(), null, + iFlags, iWScount); } private BreakPoss makeBreakPoss(short iWordStart, MinOptMax spaceIPD, int wordDim, - SpaceSpecifier leadingSpace, SpaceSpecifier trailingSpace, + SpaceSpecifier leadingSpace, + SpaceSpecifier trailingSpace, int flags, short iWScount) { MinOptMax ipd = new MinOptMax(wordDim); ipd.add(spaceIPD); @@ -397,16 +445,12 @@ public class TextLayoutManager extends AbstractLayoutManager { // Note: break position now stores total size to here // Position is the index of the info for this word in the vector - vecAreaInfo.add( - new AreaInfo(iWordStart, iNextStart, iWScount, ipd, - ((flags & BreakPoss.HYPHENATED) != 0))); - BreakPoss bp = new BreakPoss( - new LeafPosition(this, vecAreaInfo.size() - 1)); + BreakPoss bp = new BreakPoss(new LeafPosition(this, + vecAreaInfo.size() - 1)); ipdTotal = ipd; if ((flags & BreakPoss.HYPHENATED) != 0) { // Add the hyphen size, but don't change total IPD! - bp.setStackingSize( - MinOptMax.add(ipd, new MinOptMax(hyphIPD))); + bp.setStackingSize(MinOptMax.add(ipd, new MinOptMax(hyphIPD))); } else { bp.setStackingSize(ipd); } @@ -449,91 +493,108 @@ public class TextLayoutManager extends AbstractLayoutManager { * @param context LayoutContext for adjustments */ public void addAreas(PositionIterator posIter, LayoutContext context) { + // Add word areas AreaInfo ai = null; int iStart = -1; int iWScount = 0; + int iLScount = 0; + MinOptMax realWidth = new MinOptMax(0); /* On first area created, add any leading space. * Calculate word-space stretch value. */ while (posIter.hasNext()) { LeafPosition tbpNext = (LeafPosition) posIter.next(); + // + if (tbpNext.getLeafPos() != -1) { ai = (AreaInfo) vecAreaInfo.get(tbpNext.getLeafPos()); if (iStart == -1) { iStart = ai.iStartIndex; } iWScount += ai.iWScount; + iLScount += ai.iLScount; + realWidth.add(ai.ipdArea); + } } if (ai == null) { return; } - // ignore newline character + // Make an area containing all characters between start and end. + InlineArea word = null; int adjust = 0; + + // ignore newline character if (textArray[ai.iBreakIndex - 1] == NEWLINE) { adjust = 1; } - String str = new String(textArray, iStart, ai.iBreakIndex - iStart - adjust); + String str = new String(textArray, iStart, + ai.iBreakIndex - iStart - adjust); // add hyphenation character if the last word is hyphenated - if (ai.bHyphenated) { + if (context.isLastArea() && ai.bHyphenated) { str += foText.textInfo.hyphChar; - ai.ipdArea = MinOptMax.add(ai.ipdArea, new MinOptMax(hyphIPD)); + realWidth.add(new MinOptMax(hyphIPD)); } - // Calculate total adjustment - int iRealWidth = ai.ipdArea.opt; - int iAdjust = 0; + // Calculate adjustments + int iDifference = 0; + int iTotalAdjust = 0; + int iWordSpaceDim = wordSpaceIPD.opt; + int iLetterSpaceDim = letterSpaceIPD.opt; double dIPDAdjust = context.getIPDAdjust(); - double dSpaceAdjust = context.getSpaceAdjust(); + double dSpaceAdjust = context.getSpaceAdjust(); // not used + + // calculate total difference between real and available width if (dIPDAdjust > 0.0) { - iRealWidth += (int)((double)(ai.ipdArea.max - ai.ipdArea.opt) * dIPDAdjust); - } - else { - iRealWidth += (int)((double)(ai.ipdArea.opt - ai.ipdArea.min) * dIPDAdjust); + iDifference = (int) ((double) (realWidth.max - realWidth.opt) + * dIPDAdjust); + } else { + iDifference = (int) ((double) (realWidth.opt - realWidth.min) + * dIPDAdjust); } - iAdjust = (int)((double)(iRealWidth * dSpaceAdjust)); - //System.err.println(" "); - //System.err.println("TextLayoutManager> recreated difference to fill= " + iAdjust); - - // Make an area containing all characters between start and end. - InlineArea word = null; - - if (" ".equals(str)) { - word = new Space(); - word.setWidth(ai.ipdArea.opt + iAdjust); + + // set letter space adjustment + if (dIPDAdjust > 0.0) { + iLetterSpaceDim + += (int) ((double) (letterSpaceIPD.max - letterSpaceIPD.opt) + * dIPDAdjust); } else { - TextArea t = createTextArea(str, iRealWidth + iAdjust, - context.getBaseline()); - if (iWScount > 0) { - //getLogger().error("Adjustment per word-space= " + - // iAdjust / iWScount); - t.setTextSpaceAdjust(iAdjust / iWScount); - //System.err.println("TextLayoutManager> word spaces= " + iWScount + " adjustment per word space= " + (iAdjust/iWScount)); - } - word = t; - } - if ((textArray[iStart] == SPACE || textArray[iStart] == NBSPACE) - && context.getLeadingSpace().hasSpaces()) { - context.getLeadingSpace().addSpace(halfWS); + iLetterSpaceDim + += (int) ((double) (letterSpaceIPD.opt - letterSpaceIPD.min) + * dIPDAdjust); } - // Set LAST flag if done making characters - int iLastChar; - for (iLastChar = ai.iBreakIndex; - iLastChar < textArray.length && textArray[iLastChar] == SPACE; - iLastChar++) { - //nop - } - context.setFlags(LayoutContext.LAST_AREA, - iLastChar == textArray.length); - - // Can we have any trailing space? Yes, if last char was a space! - context.setTrailingSpace(new SpaceSpecifier(false)); - if (textArray[ai.iBreakIndex - 1] == SPACE - || textArray[ai.iBreakIndex - 1] == NBSPACE) { - context.getTrailingSpace().addSpace(halfWS); + iTotalAdjust += (iLetterSpaceDim - letterSpaceIPD.opt) * iLScount; + + // set word space adjustment + // + if (iWScount > 0) { + iWordSpaceDim += (int) ((iDifference - iTotalAdjust) / iWScount); + } else { + // there are no word spaces in this area } + iTotalAdjust += (iWordSpaceDim - wordSpaceIPD.opt) * iWScount; + + TextArea t = createTextArea(str, realWidth.opt + iTotalAdjust, + context.getBaseline()); + + // iWordSpaceDim is computed in relation to wordSpaceIPD.opt + // but the renderer needs to know the adjustment in relation + // to the size of the space character in the current font; + // moreover, the pdf renderer adds the character spacing even to + // the last character of a word and to space characters: in order + // to avoid this, we must subtract the letter space width twice; + // the renderer will compute the space width as: + // space width = + // = "normal" space width + letterSpaceAdjust + wordSpaceAdjust + // = spaceCharIPD + letterSpaceAdjust + + // + (iWordSpaceDim - spaceCharIPD - 2 * letterSpaceAdjust) + // = iWordSpaceDim - letterSpaceAdjust + t.setTextLetterSpaceAdjust(iLetterSpaceDim); + t.setTextWordSpaceAdjust(iWordSpaceDim - spaceCharIPD + - 2 * t.getTextLetterSpaceAdjust()); + word = t; if (word != null) { parentLM.addChild(word); } @@ -552,17 +613,400 @@ public class TextLayoutManager extends AbstractLayoutManager { TextArea textArea = new TextArea(); textArea.setWidth(width); textArea.setHeight(foText.textInfo.fs.getAscender() - - foText.textInfo.fs.getDescender()); + - foText.textInfo.fs.getDescender()); textArea.setOffset(foText.textInfo.fs.getAscender()); textArea.setOffset(base); textArea.setTextArea(str); textArea.addTrait(Trait.FONT_NAME, foText.textInfo.fs.getFontName()); textArea.addTrait(Trait.FONT_SIZE, - new Integer(foText.textInfo.fs.getFontSize())); + new Integer(foText.textInfo.fs.getFontSize())); textArea.addTrait(Trait.COLOR, foText.textInfo.color); return textArea; } + public LinkedList getNextKnuthElements(LayoutContext context, + int alignment) { + LinkedList returnList = new LinkedList(); + + while (iNextStart < textArray.length) { + if (textArray[iNextStart] == SPACE) { + // normal, breaking space + switch (alignment) { + case CENTER : + vecAreaInfo.add + (new AreaInfo(iNextStart, (short) (iNextStart + 1), + (short) 1, (short) 0, + wordSpaceIPD, false)); + returnList.add + (new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0, + new LeafPosition(this, vecAreaInfo.size() - 1), false)); + returnList.add + (new KnuthPenalty(0, 0, false, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthGlue(wordSpaceIPD.opt, + - 6 * wordSpaceIPD.opt, 0, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthBox(0, 0, 0, 0, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthPenalty(0, KnuthElement.INFINITE, false, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0, + new LeafPosition(this, -1), true)); + iNextStart ++; + break; + + case START : // fall through + case END : + vecAreaInfo.add + (new AreaInfo(iNextStart, (short) (iNextStart + 1), + (short) 1, (short) 0, + wordSpaceIPD, false)); + returnList.add + (new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0, + new LeafPosition(this, vecAreaInfo.size() - 1), false)); + returnList.add + (new KnuthPenalty(0, 0, false, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthGlue(wordSpaceIPD.opt, + - 3 * wordSpaceIPD.opt, 0, + new LeafPosition(this, -1), true)); + iNextStart ++; + break; + + case JUSTIFY: + vecAreaInfo.add + (new AreaInfo(iNextStart, (short) (iNextStart + 1), + (short) 1, (short) 0, + wordSpaceIPD, false)); + returnList.add + (new KnuthGlue(wordSpaceIPD.opt, + wordSpaceIPD.max - wordSpaceIPD.opt, + wordSpaceIPD.opt - wordSpaceIPD.min, + new LeafPosition(this, vecAreaInfo.size() - 1), false)); + iNextStart ++; + break; + + default: + vecAreaInfo.add + (new AreaInfo(iNextStart, (short) (iNextStart + 1), + (short) 1, (short) 0, + wordSpaceIPD, false)); + returnList.add + (new KnuthGlue(wordSpaceIPD.opt, + wordSpaceIPD.max - wordSpaceIPD.opt, 0, + new LeafPosition(this, vecAreaInfo.size() - 1), false)); + iNextStart ++; + } + } else if (textArray[iNextStart] == NBSPACE) { + // non breaking space + vecAreaInfo.add + (new AreaInfo(iNextStart, (short) (iNextStart + 1), + (short) 1, (short) 0, + wordSpaceIPD, false)); + returnList.add + (new KnuthPenalty(0, KnuthElement.INFINITE, false, + new LeafPosition(this, vecAreaInfo.size() - 1), false)); + returnList.add + (new KnuthGlue(wordSpaceIPD.opt, + wordSpaceIPD.max - wordSpaceIPD.opt, + wordSpaceIPD.opt - wordSpaceIPD.min, + new LeafPosition(this, vecAreaInfo.size() - 1), false)); + iNextStart ++; + } else if (textArray[iNextStart] == NEWLINE) { + // linefeed; this can happen when linefeed-treatment="preserve" + // the linefeed character is the first one in textArray, + // so we can just return a list with a penalty item + returnList.add + (new KnuthPenalty(0, -KnuthElement.INFINITE, + false, null, false)); + iNextStart ++; + return returnList; + } else { + // the beginning of a word + iThisStart = iNextStart; + iTempStart = iNextStart; + MinOptMax wordIPD = new MinOptMax(0); + for (; + iTempStart < textArray.length + && textArray[iTempStart] != SPACE + && textArray[iTempStart] != NBSPACE; + iTempStart ++) { + // ignore newline characters + if (textArray[iTempStart] != NEWLINE) { + wordIPD.add + (new MinOptMax(foText.textInfo.fs.getCharWidth(textArray[iTempStart]))); + } + } + wordIPD.add(MinOptMax.multiply(letterSpaceIPD, (iTempStart - iThisStart - 1))); + vecAreaInfo.add + (new AreaInfo(iThisStart, iTempStart, (short) 0, + (short) (iTempStart - iThisStart - 1), + wordIPD, false)); + if (letterSpaceIPD.min == letterSpaceIPD.max) { + // constant letter space; simply return a box + // whose width includes letter spaces + returnList.add + (new KnuthBox(wordIPD.opt, 0, 0, 0, + new LeafPosition(this, vecAreaInfo.size() - 1), false)); + iNextStart = iTempStart; + } else { + // adjustable letter space; + // some other KnuthElements are needed + returnList.add + (new KnuthBox(wordIPD.opt - (iTempStart - iThisStart - 1) * letterSpaceIPD.opt, 0, 0, 0, + new LeafPosition(this, vecAreaInfo.size() - 1), false)); + returnList.add + (new KnuthPenalty(0, KnuthElement.INFINITE, false, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthGlue((iTempStart - iThisStart - 1) * letterSpaceIPD.opt, + (iTempStart - iThisStart - 1) * (letterSpaceIPD.max - letterSpaceIPD.opt), + (iTempStart - iThisStart - 1) * (letterSpaceIPD.opt - letterSpaceIPD.min), + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthBox(0, 0, 0, 0, + new LeafPosition(this, -1), true)); + iNextStart = iTempStart; + } + } + } // end of while + setFinished(true); + if (returnList.size() > 0) { + return returnList; + } else { + return null; + } + } + + public int getWordSpaceIPD() { + return wordSpaceIPD.opt; + } + + public KnuthElement addALetterSpaceTo(KnuthElement element) { + LeafPosition pos = (LeafPosition) element.getPosition(); + AreaInfo ai = (AreaInfo) vecAreaInfo.get(pos.getLeafPos()); + ai.iLScount ++; + ai.ipdArea.add(letterSpaceIPD); + if (letterSpaceIPD.min == letterSpaceIPD.max) { + return new KnuthBox(ai.ipdArea.opt, 0, 0, 0, pos, false); + } else { + return new KnuthGlue(ai.iLScount * letterSpaceIPD.opt, + ai.iLScount * (letterSpaceIPD.max - letterSpaceIPD.opt), + ai.iLScount * (letterSpaceIPD.opt - letterSpaceIPD.min), + new LeafPosition(this, -1), true); + } + } + + public void hyphenate(Position pos, HyphContext hc) { + AreaInfo ai + = (AreaInfo) vecAreaInfo.get(((LeafPosition) pos).getLeafPos()); + int iStartIndex = ai.iStartIndex; + int iStopIndex; + boolean bNothingChanged = true; + + while (iStartIndex < ai.iBreakIndex) { + MinOptMax newIPD = new MinOptMax(0); + boolean bHyphenFollows; + + if (hc.hasMoreHyphPoints() + && (iStopIndex = iStartIndex + hc.getNextHyphPoint()) + <= ai.iBreakIndex) { + // iStopIndex is the index of the first character + // after a hyphenation point + bHyphenFollows = true; + } else { + // there are no more hyphenation points, + // or the next one is after ai.iBreakIndex + bHyphenFollows = false; + iStopIndex = ai.iBreakIndex; + } + + hc.updateOffset(iStopIndex - iStartIndex); + + for (int i = iStartIndex; i < iStopIndex; i++) { + char c = textArray[i]; + newIPD.add(new MinOptMax(foText.textInfo.fs.getCharWidth(c))); + } + // add letter spaces + boolean bIsWordEnd + = iStopIndex == ai.iBreakIndex + && ai.iLScount < (ai.iBreakIndex - ai.iStartIndex); + newIPD.add(MinOptMax.multiply(letterSpaceIPD, + (bIsWordEnd + ? (iStopIndex - iStartIndex - 1) + : (iStopIndex - iStartIndex)))); + + if (!(bNothingChanged + && iStopIndex == ai.iBreakIndex + && bHyphenFollows == false)) { + // the new AreaInfo object is not equal to the old one + if (changeList == null) { + changeList = new LinkedList(); + } + changeList.add + (new PendingChange + (new AreaInfo((short) iStartIndex, (short) iStopIndex, + (short) 0, + (short) (bIsWordEnd + ? (iStopIndex - iStartIndex - 1) + : (iStopIndex - iStartIndex)), + newIPD, bHyphenFollows), + ((LeafPosition) pos).getLeafPos())); + bNothingChanged = false; + } + iStartIndex = iStopIndex; + } + if (!bChanged && !bNothingChanged) { + bChanged = true; + } + } + + public boolean applyChanges(List oldList) { + setFinished(false); + + if (changeList != null) { + int iAddedAI = 0; + int iRemovedAI = 0; + int iOldIndex = -1; + PendingChange currChange = null; + ListIterator changeListIterator = changeList.listIterator(); + while (changeListIterator.hasNext()) { + currChange = (PendingChange) changeListIterator.next(); + if (currChange.index != iOldIndex) { + iRemovedAI ++; + iAddedAI ++; + iOldIndex = currChange.index; + vecAreaInfo.remove(currChange.index + iAddedAI - iRemovedAI); + vecAreaInfo.add(currChange.index + iAddedAI - iRemovedAI, + currChange.ai); + } else { + iAddedAI ++; + vecAreaInfo.add(currChange.index + iAddedAI - iRemovedAI, + currChange.ai); + } + } + changeList.clear(); + } + + iReturnedIndex = 0; + return bChanged; + } + + public LinkedList getChangedKnuthElements(List oldList, + int flaggedPenalty, + int alignment) { + if (isFinished()) { + return null; + } + + LinkedList returnList = new LinkedList(); + + while (iReturnedIndex < vecAreaInfo.size()) { + AreaInfo ai = (AreaInfo) vecAreaInfo.get(iReturnedIndex); + if (ai.iWScount == 0) { + // ai refers either to a word or a word fragment + if (letterSpaceIPD.min == letterSpaceIPD.max) { + returnList.add + (new KnuthBox(ai.ipdArea.opt, 0, 0, 0, + new LeafPosition(this, iReturnedIndex), false)); + } else { + returnList.add + (new KnuthBox(ai.ipdArea.opt + - ai.iLScount * letterSpaceIPD.opt, + 0, 0, 0, + new LeafPosition(this, iReturnedIndex), false)); + returnList.add + (new KnuthPenalty(0, KnuthElement.INFINITE, false, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthGlue(ai.iLScount * letterSpaceIPD.opt, + ai.iLScount * (letterSpaceIPD.max - letterSpaceIPD.opt), + ai.iLScount * (letterSpaceIPD.opt - letterSpaceIPD.min), + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthBox(0, 0, 0, 0, + new LeafPosition(this, -1), true)); + } + if (ai.bHyphenated) { + returnList.add + (new KnuthPenalty(hyphIPD, flaggedPenalty, true, + new LeafPosition(this, -1), false)); + } + iReturnedIndex ++; + } else { + // ai refers to a space + switch (alignment) { + case CENTER : + returnList.add + (new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0, + new LeafPosition(this, iReturnedIndex), false)); + returnList.add + (new KnuthPenalty(0, 0, false, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthGlue(wordSpaceIPD.opt, + - 6 * wordSpaceIPD.opt, 0, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthBox(0, 0, 0, 0, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthPenalty(0, KnuthElement.INFINITE, false, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0, + new LeafPosition(this, -1), true)); + iReturnedIndex ++; + break; + case START : // fall through + case END : + returnList.add + (new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0, + new LeafPosition(this, iReturnedIndex), false)); + returnList.add + (new KnuthPenalty(0, 0, false, + new LeafPosition(this, -1), true)); + returnList.add + (new KnuthGlue(wordSpaceIPD.opt, + - 3 * wordSpaceIPD.opt, 0, + new LeafPosition(this, -1), true)); + iReturnedIndex ++; + break; + case JUSTIFY: + returnList.add + (new KnuthGlue(wordSpaceIPD.opt, + wordSpaceIPD.max - wordSpaceIPD.opt, + wordSpaceIPD.opt - wordSpaceIPD.min, + new LeafPosition(this, iReturnedIndex), false)); + iReturnedIndex ++; + break; + + default: + returnList.add + (new KnuthGlue(wordSpaceIPD.opt, + wordSpaceIPD.max - wordSpaceIPD.opt, 0, + new LeafPosition(this, iReturnedIndex), false)); + iReturnedIndex ++; + } + } + } // end of while + setFinished(true); + return returnList; + } + + public void getWordChars(StringBuffer sbChars, Position pos) { + int iLeafValue = ((LeafPosition) pos).getLeafPos(); + if (iLeafValue != -1) { + AreaInfo ai = (AreaInfo) vecAreaInfo.get(iLeafValue); + sbChars.append(new String(textArray, ai.iStartIndex, + ai.iBreakIndex - ai.iStartIndex)); + } + } } |