Source Code Cross Referenced for TextLayoutManager.java in  » Graphic-Library » fop » org » apache » fop » layoutmgr » inline » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Graphic Library » fop » org.apache.fop.layoutmgr.inline 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         * 
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         * 
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        /* $Id: TextLayoutManager.java 563951 2007-08-08 17:37:33Z vhennebert $ */
0019:
0020:        package org.apache.fop.layoutmgr.inline;
0021:
0022:        import java.util.ArrayList;
0023:        import java.util.List;
0024:        import java.util.LinkedList;
0025:        import java.util.ListIterator;
0026:
0027:        import org.apache.commons.logging.Log;
0028:        import org.apache.commons.logging.LogFactory;
0029:        import org.apache.fop.area.Trait;
0030:        import org.apache.fop.area.inline.TextArea;
0031:        import org.apache.fop.fo.Constants;
0032:        import org.apache.fop.fo.FOText;
0033:        import org.apache.fop.fonts.Font;
0034:        import org.apache.fop.layoutmgr.InlineKnuthSequence;
0035:        import org.apache.fop.layoutmgr.KnuthBox;
0036:        import org.apache.fop.layoutmgr.KnuthElement;
0037:        import org.apache.fop.layoutmgr.KnuthGlue;
0038:        import org.apache.fop.layoutmgr.KnuthPenalty;
0039:        import org.apache.fop.layoutmgr.KnuthSequence;
0040:        import org.apache.fop.layoutmgr.LayoutContext;
0041:        import org.apache.fop.layoutmgr.LeafPosition;
0042:        import org.apache.fop.layoutmgr.Position;
0043:        import org.apache.fop.layoutmgr.PositionIterator;
0044:        import org.apache.fop.layoutmgr.TraitSetter;
0045:        import org.apache.fop.text.linebreak.LineBreakStatus;
0046:        import org.apache.fop.traits.MinOptMax;
0047:        import org.apache.fop.traits.SpaceVal;
0048:        import org.apache.fop.util.CharUtilities;
0049:
0050:        /**
0051:         * LayoutManager for text (a sequence of characters) which generates one
0052:         * or more inline areas.
0053:         */
0054:        public class TextLayoutManager extends LeafNodeLayoutManager {
0055:
0056:            /**
0057:             * Store information about each potential text area.
0058:             * Index of character which ends the area, IPD of area, including
0059:             * any word-space and letter-space.
0060:             * Number of word-spaces?
0061:             */
0062:            private class AreaInfo {
0063:                private short iStartIndex;
0064:                private short iBreakIndex;
0065:                private short iWScount;
0066:                private short iLScount;
0067:                private MinOptMax ipdArea;
0068:                private boolean bHyphenated;
0069:                private boolean isSpace;
0070:                private boolean breakOppAfter;
0071:
0072:                public AreaInfo(short iSIndex, short iBIndex, short iWS,
0073:                        short iLS, MinOptMax ipd, boolean bHyph,
0074:                        boolean isSpace, boolean breakOppAfter) {
0075:                    iStartIndex = iSIndex;
0076:                    iBreakIndex = iBIndex;
0077:                    iWScount = iWS;
0078:                    iLScount = iLS;
0079:                    ipdArea = ipd;
0080:                    bHyphenated = bHyph;
0081:                    this .isSpace = isSpace;
0082:                    this .breakOppAfter = breakOppAfter;
0083:                }
0084:
0085:                public String toString() {
0086:                    return "[ lscnt=" + iLScount + ", wscnt=" + iWScount
0087:                            + ", ipd=" + ipdArea.toString() + ", sidx="
0088:                            + iStartIndex + ", bidx=" + iBreakIndex + ", hyph="
0089:                            + bHyphenated + ", space=" + isSpace + "]";
0090:                }
0091:
0092:            }
0093:
0094:            // this class stores information about changes in vecAreaInfo
0095:            // which are not yet applied
0096:            private class PendingChange {
0097:                public AreaInfo ai;
0098:                public int index;
0099:
0100:                public PendingChange(AreaInfo ai, int index) {
0101:                    this .ai = ai;
0102:                    this .index = index;
0103:                }
0104:            }
0105:
0106:            /**
0107:             * logging instance
0108:             */
0109:            private static Log log = LogFactory.getLog(TextLayoutManager.class);
0110:
0111:            // Hold all possible breaks for the text in this LM's FO.
0112:            private ArrayList vecAreaInfo;
0113:
0114:            /** Non-space characters on which we can end a line. */
0115:            private static final String BREAK_CHARS = "-/";
0116:
0117:            /** Used to reduce instantiation of MinOptMax with zero length. Do not modify! */
0118:            private static final MinOptMax ZERO_MINOPTMAX = new MinOptMax(0);
0119:
0120:            private FOText foText;
0121:            private char[] textArray;
0122:            /**
0123:             * Contains an array of widths to adjust for kerning. The first entry can
0124:             * be used to influence the start position of the first letter. The entry i+1 defines the
0125:             * cursor advancement after the character i. A null entry means no special advancement.
0126:             */
0127:            private MinOptMax[] letterAdjustArray; //size = textArray.length + 1
0128:
0129:            private static final char NEWLINE = '\n';
0130:
0131:            private Font font = null;
0132:            /** Start index of first character in this parent Area */
0133:            private short iAreaStart = 0;
0134:            /** Start index of next TextArea */
0135:            private short iNextStart = 0;
0136:            /** Size since last makeArea call, except for last break */
0137:            private MinOptMax ipdTotal;
0138:            /** Size including last break possibility returned */
0139:            // private MinOptMax nextIPD = new MinOptMax(0);
0140:            /** size of a space character (U+0020) glyph in current font */
0141:            private int spaceCharIPD;
0142:            private MinOptMax wordSpaceIPD;
0143:            private MinOptMax letterSpaceIPD;
0144:            /** size of the hyphen character glyph in current font */
0145:            private int hyphIPD;
0146:            /** 1/1 of word-spacing value */
0147:            private SpaceVal ws;
0148:            /** 1/2 of word-spacing value */
0149:            private SpaceVal halfWS;
0150:            /** 1/2 of letter-spacing value */
0151:            private SpaceVal halfLS;
0152:            /** Number of space characters after previous possible break position. */
0153:            private int iNbSpacesPending;
0154:
0155:            private boolean bChanged = false;
0156:            private int iReturnedIndex = 0;
0157:            private short iThisStart = 0;
0158:            private short iTempStart = 0;
0159:            private LinkedList changeList = null;
0160:
0161:            private AlignmentContext alignmentContext = null;
0162:
0163:            private int lineStartBAP = 0;
0164:            private int lineEndBAP = 0;
0165:
0166:            private boolean keepTogether;
0167:
0168:            /**
0169:             * Create a Text layout manager.
0170:             *
0171:             * @param node The FOText object to be rendered
0172:             */
0173:            public TextLayoutManager(FOText node) {
0174:                super ();
0175:                foText = node;
0176:
0177:                textArray = new char[node.endIndex - node.startIndex];
0178:                System.arraycopy(node.ca, node.startIndex, textArray, 0,
0179:                        node.endIndex - node.startIndex);
0180:                letterAdjustArray = new MinOptMax[textArray.length + 1];
0181:
0182:                vecAreaInfo = new java.util.ArrayList();
0183:            }
0184:
0185:            /** @see org.apache.fop.layoutmgr.LayoutManager#initialize */
0186:            public void initialize() {
0187:                font = foText.getCommonFont().getFontState(
0188:                        foText.getFOEventHandler().getFontInfo(), this );
0189:
0190:                // With CID fonts, space isn't neccesary currentFontState.width(32)
0191:                spaceCharIPD = font.getCharWidth(' ');
0192:                // Use hyphenationChar property
0193:                hyphIPD = font
0194:                        .getCharWidth(foText.getCommonHyphenation().hyphenationCharacter);
0195:
0196:                SpaceVal ls = SpaceVal.makeLetterSpacing(foText
0197:                        .getLetterSpacing());
0198:                halfLS = new SpaceVal(MinOptMax.multiply(ls.getSpace(), 0.5),
0199:                        ls.isConditional(), ls.isForcing(), ls.getPrecedence());
0200:
0201:                ws = SpaceVal
0202:                        .makeWordSpacing(foText.getWordSpacing(), ls, font);
0203:                // Make half-space: <space> on either side of a word-space)
0204:                halfWS = new SpaceVal(MinOptMax.multiply(ws.getSpace(), 0.5),
0205:                        ws.isConditional(), ws.isForcing(), ws.getPrecedence());
0206:
0207:                // letter space applies only to consecutive non-space characters,
0208:                // while word space applies to space characters;
0209:                // i.e. the spaces in the string "A SIMPLE TEST" are:
0210:                //      A<<ws>>S<ls>I<ls>M<ls>P<ls>L<ls>E<<ws>>T<ls>E<ls>S<ls>T
0211:                // there is no letter space after the last character of a word,
0212:                // nor after a space character
0213:                // NOTE: The above is not quite correct. Read on in XSL 1.0, 7.16.2, letter-spacing
0214:
0215:                // set letter space and word space dimension;
0216:                // the default value "normal" was converted into a MinOptMax value
0217:                // in the SpaceVal.makeWordSpacing() method
0218:                letterSpaceIPD = ls.getSpace();
0219:                wordSpaceIPD = MinOptMax.add(new MinOptMax(spaceCharIPD), ws
0220:                        .getSpace());
0221:
0222:                keepTogether = foText.getKeepTogether().getWithinLine()
0223:                        .getEnum() == Constants.EN_ALWAYS;
0224:
0225:            }
0226:
0227:            /**
0228:             * Reset position for returning next BreakPossibility.
0229:             *
0230:             * @param prevPos the position to reset to
0231:             */
0232:            public void resetPosition(Position prevPos) {
0233:                if (prevPos != null) {
0234:                    // ASSERT (prevPos.getLM() == this)
0235:                    if (prevPos.getLM() != this ) {
0236:                        log.error("TextLayoutManager.resetPosition: "
0237:                                + "LM mismatch!!!");
0238:                    }
0239:                    LeafPosition tbp = (LeafPosition) prevPos;
0240:                    AreaInfo ai = (AreaInfo) vecAreaInfo.get(tbp.getLeafPos());
0241:                    if (ai.iBreakIndex != iNextStart) {
0242:                        iNextStart = ai.iBreakIndex;
0243:                        vecAreaInfo.ensureCapacity(tbp.getLeafPos() + 1);
0244:                        // TODO: reset or recalculate total IPD = sum of all word IPD
0245:                        // up to the break position
0246:                        ipdTotal = ai.ipdArea;
0247:                        setFinished(false);
0248:                    }
0249:                } else {
0250:                    // Reset to beginning!
0251:                    vecAreaInfo.clear();
0252:                    iNextStart = 0;
0253:                    setFinished(false);
0254:                }
0255:            }
0256:
0257:            // TODO: see if we can use normal getNextBreakPoss for this with
0258:            // extra hyphenation information in LayoutContext
0259:            private boolean getHyphenIPD(HyphContext hc, MinOptMax hyphIPD) {
0260:                // Skip leading word-space before calculating count?
0261:                boolean bCanHyphenate = true;
0262:                int iStopIndex = iNextStart + hc.getNextHyphPoint();
0263:
0264:                if (textArray.length < iStopIndex) {
0265:                    iStopIndex = textArray.length;
0266:                    bCanHyphenate = false;
0267:                }
0268:                hc.updateOffset(iStopIndex - iNextStart);
0269:
0270:                for (; iNextStart < iStopIndex; iNextStart++) {
0271:                    char c = textArray[iNextStart];
0272:                    hyphIPD.opt += font.getCharWidth(c);
0273:                    // letter-space?
0274:                }
0275:                // Need to include hyphen size too, but don't count it in the
0276:                // stored running total, since it would be double counted
0277:                // with later hyphenation points
0278:                return bCanHyphenate;
0279:            }
0280:
0281:            /**
0282:             * Generate and add areas to parent area.
0283:             * This can either generate an area for each TextArea and each space, or
0284:             * an area containing all text with a parameter controlling the size of
0285:             * the word space. The latter is most efficient for PDF generation.
0286:             * Set size of each area.
0287:             * @param posIter Iterator over Position information returned
0288:             * by this LayoutManager.
0289:             * @param context LayoutContext for adjustments
0290:             */
0291:            public void addAreas(PositionIterator posIter, LayoutContext context) {
0292:
0293:                // Add word areas
0294:                AreaInfo ai = null;
0295:                int iWScount = 0;
0296:                int iLScount = 0;
0297:                int firstAreaInfoIndex = -1;
0298:                int lastAreaInfoIndex = 0;
0299:                MinOptMax realWidth = new MinOptMax(0);
0300:
0301:                /* On first area created, add any leading space.
0302:                 * Calculate word-space stretch value.
0303:                 */
0304:                while (posIter.hasNext()) {
0305:                    LeafPosition tbpNext = (LeafPosition) posIter.next();
0306:                    if (tbpNext == null) {
0307:                        continue; //Ignore elements without Positions
0308:                    }
0309:                    if (tbpNext.getLeafPos() != -1) {
0310:                        ai = (AreaInfo) vecAreaInfo.get(tbpNext.getLeafPos());
0311:                        if (firstAreaInfoIndex == -1) {
0312:                            firstAreaInfoIndex = tbpNext.getLeafPos();
0313:                        }
0314:                        iWScount += ai.iWScount;
0315:                        iLScount += ai.iLScount;
0316:                        realWidth.add(ai.ipdArea);
0317:                        lastAreaInfoIndex = tbpNext.getLeafPos();
0318:                    }
0319:                }
0320:                if (ai == null) {
0321:                    return;
0322:                }
0323:                int textLength = ai.iBreakIndex - ai.iStartIndex;
0324:                if (ai.iLScount == textLength && !ai.bHyphenated
0325:                        && context.isLastArea()) {
0326:                    // the line ends at a character like "/" or "-";
0327:                    // remove the letter space after the last character
0328:                    realWidth.add(MinOptMax.multiply(letterSpaceIPD, -1));
0329:                    iLScount--;
0330:                }
0331:
0332:                for (int i = ai.iStartIndex; i < ai.iBreakIndex; i++) {
0333:                    MinOptMax ladj = letterAdjustArray[i + 1];
0334:                    if (ladj != null && ladj.isElastic()) {
0335:                        iLScount++;
0336:                    }
0337:                }
0338:
0339:                // add hyphenation character if the last word is hyphenated
0340:                if (context.isLastArea() && ai.bHyphenated) {
0341:                    realWidth.add(new MinOptMax(hyphIPD));
0342:                }
0343:
0344:                // Calculate adjustments
0345:                int iDifference = 0;
0346:                int iTotalAdjust = 0;
0347:                int iWordSpaceDim = wordSpaceIPD.opt;
0348:                int iLetterSpaceDim = letterSpaceIPD.opt;
0349:                double dIPDAdjust = context.getIPDAdjust();
0350:                double dSpaceAdjust = context.getSpaceAdjust(); // not used
0351:
0352:                // calculate total difference between real and available width
0353:                if (dIPDAdjust > 0.0) {
0354:                    iDifference = (int) ((double) (realWidth.max - realWidth.opt) * dIPDAdjust);
0355:                } else {
0356:                    iDifference = (int) ((double) (realWidth.opt - realWidth.min) * dIPDAdjust);
0357:                }
0358:
0359:                // set letter space adjustment
0360:                if (dIPDAdjust > 0.0) {
0361:                    iLetterSpaceDim += (int) ((double) (letterSpaceIPD.max - letterSpaceIPD.opt) * dIPDAdjust);
0362:                } else {
0363:                    iLetterSpaceDim += (int) ((double) (letterSpaceIPD.opt - letterSpaceIPD.min) * dIPDAdjust);
0364:                }
0365:                iTotalAdjust += (iLetterSpaceDim - letterSpaceIPD.opt)
0366:                        * iLScount;
0367:
0368:                // set word space adjustment
0369:                // 
0370:                if (iWScount > 0) {
0371:                    iWordSpaceDim += (int) ((iDifference - iTotalAdjust) / iWScount);
0372:                } else {
0373:                    // there are no word spaces in this area
0374:                }
0375:                iTotalAdjust += (iWordSpaceDim - wordSpaceIPD.opt) * iWScount;
0376:                if (iTotalAdjust != iDifference) {
0377:                    // the applied adjustment is greater or smaller than the needed one
0378:                    log
0379:                            .trace("TextLM.addAreas: error in word / letter space adjustment = "
0380:                                    + (iTotalAdjust - iDifference));
0381:                    // set iTotalAdjust = iDifference, so that the width of the TextArea
0382:                    // will counterbalance the error and the other inline areas will be
0383:                    // placed correctly
0384:                    iTotalAdjust = iDifference;
0385:                }
0386:
0387:                TextArea t = createTextArea(realWidth, iTotalAdjust, context,
0388:                        wordSpaceIPD.opt - spaceCharIPD, firstAreaInfoIndex,
0389:                        lastAreaInfoIndex, context.isLastArea());
0390:
0391:                // iWordSpaceDim is computed in relation to wordSpaceIPD.opt
0392:                // but the renderer needs to know the adjustment in relation
0393:                // to the size of the space character in the current font;
0394:                // moreover, the pdf renderer adds the character spacing even to
0395:                // the last character of a word and to space characters: in order
0396:                // to avoid this, we must subtract the letter space width twice;
0397:                // the renderer will compute the space width as:
0398:                //   space width = 
0399:                //     = "normal" space width + letterSpaceAdjust + wordSpaceAdjust
0400:                //     = spaceCharIPD + letterSpaceAdjust +
0401:                //       + (iWordSpaceDim - spaceCharIPD -  2 * letterSpaceAdjust)
0402:                //     = iWordSpaceDim - letterSpaceAdjust
0403:                t.setTextLetterSpaceAdjust(iLetterSpaceDim);
0404:                t.setTextWordSpaceAdjust(iWordSpaceDim - spaceCharIPD - 2
0405:                        * t.getTextLetterSpaceAdjust());
0406:                if (context.getIPDAdjust() != 0) {
0407:                    // add information about space width
0408:                    t.setSpaceDifference(wordSpaceIPD.opt - spaceCharIPD - 2
0409:                            * t.getTextLetterSpaceAdjust());
0410:                }
0411:                parentLM.addChildArea(t);
0412:            }
0413:
0414:            /**
0415:             * Create an inline word area.
0416:             * This creates a TextArea and sets up the various attributes.
0417:             *
0418:             * @param width the MinOptMax width of the content
0419:             * @param adjust the total ipd adjustment with respect to the optimal width
0420:             * @param context the layout context
0421:             * @param spaceDiff unused
0422:             * @param firstIndex the index of the first AreaInfo used for the TextArea
0423:             * @param lastIndex the index of the last AreaInfo used for the TextArea 
0424:             * @param isLastArea is this TextArea the last in a line?
0425:             * @return the new text area
0426:             */
0427:            protected TextArea createTextArea(MinOptMax width, int adjust,
0428:                    LayoutContext context, int spaceDiff, int firstIndex,
0429:                    int lastIndex, boolean isLastArea) {
0430:                TextArea textArea;
0431:                if (context.getIPDAdjust() == 0.0) {
0432:                    // create just a TextArea
0433:                    textArea = new TextArea();
0434:                } else {
0435:                    // justified area: create a TextArea with extra info
0436:                    // about potential adjustments
0437:                    textArea = new TextArea(width.max - width.opt, width.opt
0438:                            - width.min, adjust);
0439:                }
0440:                textArea.setIPD(width.opt + adjust);
0441:                textArea.setBPD(font.getAscender() - font.getDescender());
0442:                textArea.setBaselineOffset(font.getAscender());
0443:                if (textArea.getBPD() == alignmentContext.getHeight()) {
0444:                    textArea.setOffset(0);
0445:                } else {
0446:                    textArea.setOffset(alignmentContext.getOffset());
0447:                }
0448:
0449:                // set the text of the TextArea, split into words and spaces
0450:                int wordStartIndex = -1;
0451:                AreaInfo areaInfo;
0452:                int len = 0;
0453:                for (int i = firstIndex; i <= lastIndex; i++) {
0454:                    areaInfo = (AreaInfo) vecAreaInfo.get(i);
0455:                    if (areaInfo.isSpace) {
0456:                        // areaInfo stores information about spaces
0457:                        // add the spaces - except zero-width spaces - to the TextArea
0458:                        for (int j = areaInfo.iStartIndex; j < areaInfo.iBreakIndex; j++) {
0459:                            char spaceChar = textArray[j];
0460:                            if (!CharUtilities.isZeroWidthSpace(spaceChar)) {
0461:                                textArea.addSpace(spaceChar, 0, CharUtilities
0462:                                        .isAdjustableSpace(spaceChar));
0463:                            }
0464:                        }
0465:                    } else {
0466:                        // areaInfo stores information about a word fragment
0467:                        if (wordStartIndex == -1) {
0468:                            // here starts a new word
0469:                            wordStartIndex = i;
0470:                            len = 0;
0471:                        }
0472:                        len += areaInfo.iBreakIndex - areaInfo.iStartIndex;
0473:                        if (i == lastIndex
0474:                                || ((AreaInfo) vecAreaInfo.get(i + 1)).isSpace) {
0475:                            // here ends a new word
0476:                            // add a word to the TextArea
0477:                            if (isLastArea && i == lastIndex
0478:                                    && areaInfo.bHyphenated) {
0479:                                len++;
0480:                            }
0481:                            StringBuffer wordChars = new StringBuffer(len);
0482:                            int[] letterAdjust = new int[len];
0483:                            int letter = 0;
0484:                            for (int j = wordStartIndex; j <= i; j++) {
0485:                                AreaInfo ai = (AreaInfo) vecAreaInfo.get(j);
0486:                                int lsCount = ai.iLScount;
0487:                                wordChars.append(textArray, ai.iStartIndex,
0488:                                        ai.iBreakIndex - ai.iStartIndex);
0489:                                for (int k = 0; k < ai.iBreakIndex
0490:                                        - ai.iStartIndex; k++) {
0491:                                    MinOptMax adj = letterAdjustArray[ai.iStartIndex
0492:                                            + k];
0493:                                    if (letter > 0) {
0494:                                        letterAdjust[letter] = (adj != null ? adj.opt
0495:                                                : 0);
0496:                                    }
0497:                                    if (lsCount > 0) {
0498:                                        letterAdjust[letter] += textArea
0499:                                                .getTextLetterSpaceAdjust();
0500:                                        lsCount--;
0501:                                    }
0502:                                    letter++;
0503:                                }
0504:                            }
0505:                            // String wordChars = new String(textArray, wordStartIndex, len);
0506:                            if (isLastArea && i == lastIndex
0507:                                    && areaInfo.bHyphenated) {
0508:                                // add the hyphenation character
0509:                                wordChars
0510:                                        .append(foText.getCommonHyphenation().hyphenationCharacter);
0511:                            }
0512:                            textArea.addWord(wordChars.toString(), 0,
0513:                                    letterAdjust);
0514:                            wordStartIndex = -1;
0515:                        }
0516:                    }
0517:                }
0518:                TraitSetter.addFontTraits(textArea, font);
0519:                textArea.addTrait(Trait.COLOR, foText.getColor());
0520:
0521:                TraitSetter.addTextDecoration(textArea, foText
0522:                        .getTextDecoration());
0523:
0524:                return textArea;
0525:            }
0526:
0527:            private void addToLetterAdjust(int index, int width) {
0528:                if (letterAdjustArray[index] == null) {
0529:                    letterAdjustArray[index] = new MinOptMax(width);
0530:                } else {
0531:                    letterAdjustArray[index].add(width);
0532:                }
0533:            }
0534:
0535:            private void addToLetterAdjust(int index, MinOptMax width) {
0536:                if (letterAdjustArray[index] == null) {
0537:                    letterAdjustArray[index] = new MinOptMax(width);
0538:                } else {
0539:                    letterAdjustArray[index].add(width);
0540:                }
0541:            }
0542:
0543:            /**
0544:             * Indicates whether a character is a space in terms of this layout manager.
0545:             * @param ch the character
0546:             * @return true if it's a space
0547:             */
0548:            private static boolean isSpace(final char ch) {
0549:                return ch == CharUtilities.SPACE
0550:                        || CharUtilities.isNonBreakableSpace(ch)
0551:                        || CharUtilities.isFixedWidthSpace(ch);
0552:            }
0553:
0554:            /** @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(LayoutContext, int) */
0555:            public LinkedList getNextKnuthElements(LayoutContext context,
0556:                    int alignment) {
0557:                lineStartBAP = context.getLineStartBorderAndPaddingWidth();
0558:                lineEndBAP = context.getLineEndBorderAndPaddingWidth();
0559:                alignmentContext = context.getAlignmentContext();
0560:
0561:                LinkedList returnList = new LinkedList();
0562:                KnuthSequence sequence = new InlineKnuthSequence();
0563:                AreaInfo ai = null;
0564:                AreaInfo prevAi = null;
0565:                returnList.add(sequence);
0566:
0567:                LineBreakStatus lbs = new LineBreakStatus();
0568:                iThisStart = iNextStart;
0569:                boolean inWord = false;
0570:                boolean inWhitespace = false;
0571:                char ch = 0;
0572:                while (iNextStart < textArray.length) {
0573:                    ch = textArray[iNextStart];
0574:                    boolean breakOpportunity = false;
0575:                    byte breakAction = keepTogether ? LineBreakStatus.PROHIBITED_BREAK
0576:                            : lbs.nextChar(ch);
0577:                    switch (breakAction) {
0578:                    case LineBreakStatus.COMBINING_PROHIBITED_BREAK:
0579:                    case LineBreakStatus.PROHIBITED_BREAK:
0580:                        break;
0581:                    case LineBreakStatus.EXPLICIT_BREAK:
0582:                        break;
0583:                    case LineBreakStatus.COMBINING_INDIRECT_BREAK:
0584:                    case LineBreakStatus.DIRECT_BREAK:
0585:                    case LineBreakStatus.INDIRECT_BREAK:
0586:                        breakOpportunity = true;
0587:                        break;
0588:                    default:
0589:                        log.error("Unexpected breakAction: " + breakAction);
0590:                    }
0591:                    if (inWord) {
0592:                        if (breakOpportunity || isSpace(ch) || ch == NEWLINE) {
0593:                            //Word boundary found, process widths and kerning
0594:                            int lastIndex = iNextStart;
0595:                            while (lastIndex > 0
0596:                                    && textArray[lastIndex - 1] == CharUtilities.SOFT_HYPHEN) {
0597:                                lastIndex--;
0598:                            }
0599:                            int wordLength = lastIndex - iThisStart;
0600:                            boolean kerning = font.hasKerning();
0601:                            MinOptMax wordIPD = new MinOptMax(0);
0602:                            for (int i = iThisStart; i < lastIndex; i++) {
0603:                                char c = textArray[i];
0604:
0605:                                //character width
0606:                                int charWidth = font.getCharWidth(c);
0607:                                wordIPD.add(charWidth);
0608:
0609:                                //kerning
0610:                                if (kerning) {
0611:                                    int kern = 0;
0612:                                    if (i > iThisStart) {
0613:                                        char previous = textArray[i - 1];
0614:                                        kern = font.getKernValue(previous, c)
0615:                                                * font.getFontSize() / 1000;
0616:                                    } else if (prevAi != null
0617:                                            && !prevAi.isSpace
0618:                                            && prevAi.iBreakIndex > 0) {
0619:                                        char previous = textArray[prevAi.iBreakIndex - 1];
0620:                                        kern = font.getKernValue(previous, c)
0621:                                                * font.getFontSize() / 1000;
0622:                                    }
0623:                                    if (kern != 0) {
0624:                                        //log.info("Kerning between " + previous + " and " + c + ": " + kern);
0625:                                        addToLetterAdjust(i, kern);
0626:                                        wordIPD.add(kern);
0627:                                    }
0628:                                }
0629:                            }
0630:                            if (kerning
0631:                                    && breakOpportunity
0632:                                    && !isSpace(ch)
0633:                                    && lastIndex > 0
0634:                                    && textArray[lastIndex] == CharUtilities.SOFT_HYPHEN) {
0635:                                int kern = font.getKernValue(
0636:                                        textArray[lastIndex - 1], ch)
0637:                                        * font.getFontSize() / 1000;
0638:                                if (kern != 0) {
0639:                                    addToLetterAdjust(lastIndex, kern);
0640:                                }
0641:                            }
0642:                            int iLetterSpaces = wordLength - 1;
0643:                            // if there is a break opportunity and the next one
0644:                            // is not a space, it could be used as a line end;
0645:                            // add one more letter space, in case other text follows
0646:                            if (breakOpportunity && !isSpace(ch)) {
0647:                                iLetterSpaces++;
0648:                            }
0649:                            wordIPD.add(MinOptMax.multiply(letterSpaceIPD,
0650:                                    iLetterSpaces));
0651:
0652:                            // create the AreaInfo object
0653:                            ai = new AreaInfo(
0654:                                    iThisStart,
0655:                                    (short) lastIndex,
0656:                                    (short) 0,
0657:                                    (short) iLetterSpaces,
0658:                                    wordIPD,
0659:                                    textArray[lastIndex] == CharUtilities.SOFT_HYPHEN,
0660:                                    false, breakOpportunity);
0661:                            vecAreaInfo.add(ai);
0662:                            prevAi = ai;
0663:                            iTempStart = iNextStart;
0664:
0665:                            // create the elements
0666:                            sequence.addAll(createElementsForAWordFragment(
0667:                                    alignment, ai, vecAreaInfo.size() - 1,
0668:                                    letterSpaceIPD));
0669:                            ai = null;
0670:
0671:                            iThisStart = iNextStart;
0672:                        }
0673:                    } else if (inWhitespace) {
0674:                        if (ch != CharUtilities.SPACE || breakOpportunity) {
0675:                            // End of whitespace
0676:                            // create the AreaInfo object
0677:                            ai = new AreaInfo(iThisStart, (short) (iNextStart),
0678:                                    (short) (iNextStart - iThisStart),
0679:                                    (short) 0, MinOptMax.multiply(wordSpaceIPD,
0680:                                            iNextStart - iThisStart), false,
0681:                                    true, breakOpportunity);
0682:                            vecAreaInfo.add(ai);
0683:                            prevAi = ai;
0684:
0685:                            // create the elements
0686:                            sequence.addAll(createElementsForASpace(alignment,
0687:                                    ai, vecAreaInfo.size() - 1));
0688:                            ai = null;
0689:
0690:                            iThisStart = iNextStart;
0691:                        }
0692:                    } else {
0693:                        if (ai != null) {
0694:                            vecAreaInfo.add(ai);
0695:                            prevAi = ai;
0696:                            ai.breakOppAfter = ch == CharUtilities.SPACE
0697:                                    || breakOpportunity;
0698:                            sequence.addAll(createElementsForASpace(alignment,
0699:                                    ai, vecAreaInfo.size() - 1));
0700:                            ai = null;
0701:                        }
0702:                        if (breakAction == LineBreakStatus.EXPLICIT_BREAK) {
0703:                            if (lineEndBAP != 0) {
0704:                                sequence.add(new KnuthGlue(lineEndBAP, 0, 0,
0705:                                        new LeafPosition(this , -1), true));
0706:                            }
0707:                            sequence.endSequence();
0708:                            sequence = new InlineKnuthSequence();
0709:                            returnList.add(sequence);
0710:                        }
0711:                    }
0712:
0713:                    if ((ch == CharUtilities.SPACE && foText
0714:                            .getWhitespaceTreatment() == Constants.EN_PRESERVE)
0715:                            || ch == CharUtilities.NBSPACE) {
0716:                        // preserved space or non-breaking space:
0717:                        // create the AreaInfo object
0718:                        ai = new AreaInfo(iNextStart, (short) (iNextStart + 1),
0719:                                (short) 1, (short) 0, wordSpaceIPD, false,
0720:                                true, breakOpportunity);
0721:                        iThisStart = (short) (iNextStart + 1);
0722:                    } else if (CharUtilities.isFixedWidthSpace(ch)
0723:                            || CharUtilities.isZeroWidthSpace(ch)) {
0724:                        // create the AreaInfo object
0725:                        MinOptMax ipd = new MinOptMax(font.getCharWidth(ch));
0726:                        ai = new AreaInfo(iNextStart, (short) (iNextStart + 1),
0727:                                (short) 0, (short) 0, ipd, false, true,
0728:                                breakOpportunity);
0729:                        iThisStart = (short) (iNextStart + 1);
0730:                    } else if (ch == NEWLINE) {
0731:                        // linefeed; this can happen when linefeed-treatment="preserve"
0732:                        iThisStart = (short) (iNextStart + 1);
0733:                    }
0734:                    inWord = !isSpace(ch) && ch != NEWLINE;
0735:                    inWhitespace = ch == CharUtilities.SPACE
0736:                            && foText.getWhitespaceTreatment() != Constants.EN_PRESERVE;
0737:                    iNextStart++;
0738:                } // end of while
0739:
0740:                // Process any last elements
0741:                if (inWord) {
0742:                    int lastIndex = iNextStart;
0743:                    if (textArray[iNextStart - 1] == CharUtilities.SOFT_HYPHEN) {
0744:                        lastIndex--;
0745:                    }
0746:                    int wordLength = lastIndex - iThisStart;
0747:                    boolean kerning = font.hasKerning();
0748:                    MinOptMax wordIPD = new MinOptMax(0);
0749:                    for (int i = iThisStart; i < lastIndex; i++) {
0750:                        char c = textArray[i];
0751:
0752:                        //character width
0753:                        int charWidth = font.getCharWidth(c);
0754:                        wordIPD.add(charWidth);
0755:
0756:                        //kerning
0757:                        if (kerning) {
0758:                            int kern = 0;
0759:                            if (i > iThisStart) {
0760:                                char previous = textArray[i - 1];
0761:                                kern = font.getKernValue(previous, c)
0762:                                        * font.getFontSize() / 1000;
0763:                            } else if (prevAi != null && !prevAi.isSpace) {
0764:                                char previous = textArray[prevAi.iBreakIndex - 1];
0765:                                kern = font.getKernValue(previous, c)
0766:                                        * font.getFontSize() / 1000;
0767:                            }
0768:                            if (kern != 0) {
0769:                                //log.info("Kerning between " + previous + " and " + c + ": " + kern);
0770:                                addToLetterAdjust(i, kern);
0771:                                wordIPD.add(kern);
0772:                            }
0773:                        }
0774:                    }
0775:                    int iLetterSpaces = wordLength - 1;
0776:                    wordIPD.add(MinOptMax.multiply(letterSpaceIPD,
0777:                            iLetterSpaces));
0778:
0779:                    // create the AreaInfo object
0780:                    ai = new AreaInfo(iThisStart, (short) lastIndex, (short) 0,
0781:                            (short) iLetterSpaces, wordIPD, false, false, false);
0782:                    vecAreaInfo.add(ai);
0783:                    iTempStart = iNextStart;
0784:
0785:                    // create the elements
0786:                    sequence.addAll(createElementsForAWordFragment(alignment,
0787:                            ai, vecAreaInfo.size() - 1, letterSpaceIPD));
0788:                    ai = null;
0789:                } else if (inWhitespace) {
0790:                    ai = new AreaInfo(iThisStart, (short) (iNextStart),
0791:                            (short) (iNextStart - iThisStart), (short) 0,
0792:                            MinOptMax.multiply(wordSpaceIPD, iNextStart
0793:                                    - iThisStart), false, true, true);
0794:                    vecAreaInfo.add(ai);
0795:
0796:                    // create the elements
0797:                    sequence.addAll(createElementsForASpace(alignment, ai,
0798:                            vecAreaInfo.size() - 1));
0799:                    ai = null;
0800:                } else if (ai != null) {
0801:                    vecAreaInfo.add(ai);
0802:                    ai.breakOppAfter = ch == CharUtilities.ZERO_WIDTH_SPACE;
0803:                    sequence.addAll(createElementsForASpace(alignment, ai,
0804:                            vecAreaInfo.size() - 1));
0805:                    ai = null;
0806:                } else if (ch == NEWLINE) {
0807:                    if (lineEndBAP != 0) {
0808:                        sequence.add(new KnuthGlue(lineEndBAP, 0, 0,
0809:                                new LeafPosition(this , -1), true));
0810:                    }
0811:                    sequence.endSequence();
0812:                    sequence = new InlineKnuthSequence();
0813:                    returnList.add(sequence);
0814:                }
0815:
0816:                if (((List) returnList.getLast()).size() == 0) {
0817:                    //Remove an empty sequence because of a trailing newline
0818:                    returnList.removeLast();
0819:                }
0820:                setFinished(true);
0821:                if (returnList.size() > 0) {
0822:                    return returnList;
0823:                } else {
0824:                    return null;
0825:                }
0826:            }
0827:
0828:            /** @see InlineLevelLayoutManager#addALetterSpaceTo(List) */
0829:            public List addALetterSpaceTo(List oldList) {
0830:                // old list contains only a box, or the sequence: box penalty glue box;
0831:                // look at the Position stored in the first element in oldList
0832:                // which is always a box
0833:                ListIterator oldListIterator = oldList.listIterator();
0834:                KnuthElement el = (KnuthElement) oldListIterator.next();
0835:                LeafPosition pos = (LeafPosition) ((KnuthBox) el).getPosition();
0836:                AreaInfo ai = (AreaInfo) vecAreaInfo.get(pos.getLeafPos());
0837:                ai.iLScount++;
0838:                ai.ipdArea.add(letterSpaceIPD);
0839:                if (BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0) {
0840:                    // the last character could be used as a line break
0841:                    // append new elements to oldList
0842:                    oldListIterator = oldList.listIterator(oldList.size());
0843:                    oldListIterator.add(new KnuthPenalty(0,
0844:                            KnuthPenalty.FLAGGED_PENALTY, true,
0845:                            new LeafPosition(this , -1), false));
0846:                    oldListIterator.add(new KnuthGlue(letterSpaceIPD.opt,
0847:                            letterSpaceIPD.max - letterSpaceIPD.opt,
0848:                            letterSpaceIPD.opt - letterSpaceIPD.min,
0849:                            new LeafPosition(this , -1), false));
0850:                } else if (letterSpaceIPD.min == letterSpaceIPD.max) {
0851:                    // constant letter space: replace the box
0852:                    oldListIterator.set(new KnuthInlineBox(ai.ipdArea.opt,
0853:                            alignmentContext, pos, false));
0854:                } else {
0855:                    // adjustable letter space: replace the glue
0856:                    oldListIterator.next(); // this would return the penalty element
0857:                    oldListIterator.next(); // this would return the glue element
0858:                    oldListIterator
0859:                            .set(new KnuthGlue(
0860:                                    ai.iLScount * letterSpaceIPD.opt,
0861:                                    ai.iLScount
0862:                                            * (letterSpaceIPD.max - letterSpaceIPD.opt),
0863:                                    ai.iLScount
0864:                                            * (letterSpaceIPD.opt - letterSpaceIPD.min),
0865:                                    new LeafPosition(this , -1), true));
0866:                }
0867:                return oldList;
0868:            }
0869:
0870:            /**
0871:             * remove the AreaInfo object represented by the given elements,
0872:             * so that it won't generate any element when getChangedKnuthElements
0873:             * will be called
0874:             *
0875:             * @param oldList the elements representing the word space
0876:             */
0877:            public void removeWordSpace(List oldList) {
0878:                // find the element storing the Position whose value
0879:                // points to the AreaInfo object
0880:                ListIterator oldListIterator = oldList.listIterator();
0881:                if (((KnuthElement) ((LinkedList) oldList).getFirst())
0882:                        .isPenalty()) {
0883:                    // non breaking space: oldList starts with a penalty
0884:                    oldListIterator.next();
0885:                }
0886:                if (oldList.size() > 2) {
0887:                    // alignment is either center, start or end:
0888:                    // the first two elements does not store the needed Position
0889:                    oldListIterator.next();
0890:                    oldListIterator.next();
0891:                }
0892:                int leafValue = ((LeafPosition) ((KnuthElement) oldListIterator
0893:                        .next()).getPosition()).getLeafPos();
0894:                // only the last word space can be a trailing space!
0895:                if (leafValue == vecAreaInfo.size() - 1) {
0896:                    vecAreaInfo.remove(leafValue);
0897:                } else {
0898:                    log.error("trying to remove a non-trailing word space");
0899:                }
0900:            }
0901:
0902:            /** @see InlineLevelLayoutManager#hyphenate(Position, HyphContext) */
0903:            public void hyphenate(Position pos, HyphContext hc) {
0904:                AreaInfo ai = (AreaInfo) vecAreaInfo.get(((LeafPosition) pos)
0905:                        .getLeafPos());
0906:                int iStartIndex = ai.iStartIndex;
0907:                int iStopIndex;
0908:                boolean bNothingChanged = true;
0909:
0910:                while (iStartIndex < ai.iBreakIndex) {
0911:                    MinOptMax newIPD = new MinOptMax(0);
0912:                    boolean bHyphenFollows;
0913:
0914:                    if (hc.hasMoreHyphPoints()
0915:                            && (iStopIndex = iStartIndex
0916:                                    + hc.getNextHyphPoint()) <= ai.iBreakIndex) {
0917:                        // iStopIndex is the index of the first character
0918:                        // after a hyphenation point
0919:                        bHyphenFollows = true;
0920:                    } else {
0921:                        // there are no more hyphenation points,
0922:                        // or the next one is after ai.iBreakIndex
0923:                        bHyphenFollows = false;
0924:                        iStopIndex = ai.iBreakIndex;
0925:                    }
0926:
0927:                    hc.updateOffset(iStopIndex - iStartIndex);
0928:
0929:                    //log.info("Word: " + new String(textArray, iStartIndex, iStopIndex - iStartIndex));
0930:                    for (int i = iStartIndex; i < iStopIndex; i++) {
0931:                        char c = textArray[i];
0932:                        newIPD.add(new MinOptMax(font.getCharWidth(c)));
0933:                        //if (i > iStartIndex) {
0934:                        if (i < iStopIndex) {
0935:                            MinOptMax la = this .letterAdjustArray[i + 1];
0936:                            if ((i == iStopIndex - 1) && bHyphenFollows) {
0937:                                //the letter adjust here needs to be handled further down during
0938:                                //element generation because it depends on hyph/no-hyph condition
0939:                                la = null;
0940:                            }
0941:                            if (la != null) {
0942:                                newIPD.add(la);
0943:                            }
0944:                        }
0945:                    }
0946:                    // add letter spaces
0947:                    boolean bIsWordEnd = iStopIndex == ai.iBreakIndex
0948:                            && ai.iLScount < (ai.iBreakIndex - ai.iStartIndex);
0949:                    newIPD.add(MinOptMax.multiply(letterSpaceIPD,
0950:                            (bIsWordEnd ? (iStopIndex - iStartIndex - 1)
0951:                                    : (iStopIndex - iStartIndex))));
0952:
0953:                    if (!(bNothingChanged && iStopIndex == ai.iBreakIndex && bHyphenFollows == false)) {
0954:                        // the new AreaInfo object is not equal to the old one
0955:                        if (changeList == null) {
0956:                            changeList = new LinkedList();
0957:                        }
0958:                        changeList.add(new PendingChange(new AreaInfo(
0959:                                (short) iStartIndex, (short) iStopIndex,
0960:                                (short) 0, (short) (bIsWordEnd ? (iStopIndex
0961:                                        - iStartIndex - 1)
0962:                                        : (iStopIndex - iStartIndex)), newIPD,
0963:                                bHyphenFollows, false, false),
0964:                                ((LeafPosition) pos).getLeafPos()));
0965:                        bNothingChanged = false;
0966:                    }
0967:                    iStartIndex = iStopIndex;
0968:                }
0969:                if (!bChanged && !bNothingChanged) {
0970:                    bChanged = true;
0971:                }
0972:            }
0973:
0974:            /** @see InlineLevelLayoutManager#applyChanges(List) */
0975:            public boolean applyChanges(List oldList) {
0976:                setFinished(false);
0977:
0978:                if (changeList != null) {
0979:                    int iAddedAI = 0;
0980:                    int iRemovedAI = 0;
0981:                    int iOldIndex = -1;
0982:                    PendingChange currChange = null;
0983:                    ListIterator changeListIterator = changeList.listIterator();
0984:                    while (changeListIterator.hasNext()) {
0985:                        currChange = (PendingChange) changeListIterator.next();
0986:                        if (currChange.index != iOldIndex) {
0987:                            iRemovedAI++;
0988:                            iAddedAI++;
0989:                            iOldIndex = currChange.index;
0990:                            vecAreaInfo.remove(currChange.index + iAddedAI
0991:                                    - iRemovedAI);
0992:                            vecAreaInfo.add(currChange.index + iAddedAI
0993:                                    - iRemovedAI, currChange.ai);
0994:                        } else {
0995:                            iAddedAI++;
0996:                            vecAreaInfo.add(currChange.index + iAddedAI
0997:                                    - iRemovedAI, currChange.ai);
0998:                        }
0999:                    }
1000:                    changeList.clear();
1001:                }
1002:
1003:                iReturnedIndex = 0;
1004:                return bChanged;
1005:            }
1006:
1007:            /** @see org.apache.fop.layoutmgr.LayoutManager#getChangedKnuthElements(List, int) */
1008:            public LinkedList getChangedKnuthElements(List oldList,
1009:                    int alignment) {
1010:                if (isFinished()) {
1011:                    return null;
1012:                }
1013:
1014:                LinkedList returnList = new LinkedList();
1015:
1016:                while (iReturnedIndex < vecAreaInfo.size()) {
1017:                    AreaInfo ai = (AreaInfo) vecAreaInfo.get(iReturnedIndex);
1018:                    if (ai.iWScount == 0) {
1019:                        // ai refers either to a word or a word fragment
1020:                        returnList.addAll(createElementsForAWordFragment(
1021:                                alignment, ai, iReturnedIndex, letterSpaceIPD));
1022:                    } else {
1023:                        // ai refers to a space
1024:                        returnList.addAll(createElementsForASpace(alignment,
1025:                                ai, iReturnedIndex));
1026:                    }
1027:                    iReturnedIndex++;
1028:                } // end of while
1029:                setFinished(true);
1030:                //ElementListObserver.observe(returnList, "text-changed", null);
1031:                return returnList;
1032:            }
1033:
1034:            /** @see InlineLevelLayoutManager#getWordChars(StringBuffer, Position) */
1035:            public void getWordChars(StringBuffer sbChars, Position pos) {
1036:                int iLeafValue = ((LeafPosition) pos).getLeafPos();
1037:                if (iLeafValue != -1) {
1038:                    AreaInfo ai = (AreaInfo) vecAreaInfo.get(iLeafValue);
1039:                    sbChars.append(new String(textArray, ai.iStartIndex,
1040:                            ai.iBreakIndex - ai.iStartIndex));
1041:                }
1042:            }
1043:
1044:            private LinkedList createElementsForASpace(int alignment,
1045:                    AreaInfo ai, int leafValue) {
1046:                LinkedList spaceElements = new LinkedList();
1047:                LeafPosition mainPosition = new LeafPosition(this , leafValue);
1048:
1049:                if (!ai.breakOppAfter) {
1050:                    // a non-breaking space
1051:                    if (alignment == EN_JUSTIFY) {
1052:                        // the space can stretch and shrink, and must be preserved
1053:                        // when starting a line
1054:                        spaceElements.add(new KnuthInlineBox(0, null,
1055:                                notifyPos(new LeafPosition(this , -1)), true));
1056:                        spaceElements.add(new KnuthPenalty(0,
1057:                                KnuthElement.INFINITE, false, new LeafPosition(
1058:                                        this , -1), false));
1059:                        spaceElements.add(new KnuthGlue(ai.ipdArea.opt,
1060:                                ai.ipdArea.max - ai.ipdArea.opt, ai.ipdArea.opt
1061:                                        - ai.ipdArea.min, mainPosition, false));
1062:                    } else {
1063:                        // the space does not need to stretch or shrink, and must be
1064:                        // preserved when starting a line
1065:                        spaceElements.add(new KnuthInlineBox(ai.ipdArea.opt,
1066:                                null, mainPosition, true));
1067:                    }
1068:                } else {
1069:                    if (textArray[ai.iStartIndex] != CharUtilities.SPACE
1070:                            || foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) {
1071:                        // a breaking space that needs to be preserved
1072:                        switch (alignment) {
1073:                        case EN_CENTER:
1074:                            // centered text:
1075:                            // if the second element is chosen as a line break these elements 
1076:                            // add a constant amount of stretch at the end of a line and at the
1077:                            // beginning of the next one, otherwise they don't add any stretch
1078:                            spaceElements.add(new KnuthGlue(lineEndBAP,
1079:                                    3 * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1080:                                    0, new LeafPosition(this , -1), false));
1081:                            spaceElements.add(new KnuthPenalty(0, 0, false,
1082:                                    new LeafPosition(this , -1), false));
1083:                            spaceElements.add(new KnuthGlue(
1084:                                    -(lineStartBAP + lineEndBAP),
1085:                                    -6 * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1086:                                    0, new LeafPosition(this , -1), false));
1087:                            spaceElements.add(new KnuthInlineBox(0, null,
1088:                                    notifyPos(new LeafPosition(this , -1)),
1089:                                    false));
1090:                            spaceElements.add(new KnuthPenalty(0,
1091:                                    KnuthElement.INFINITE, false,
1092:                                    new LeafPosition(this , -1), false));
1093:                            spaceElements.add(new KnuthGlue(ai.ipdArea.opt
1094:                                    + lineStartBAP,
1095:                                    3 * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1096:                                    0, mainPosition, false));
1097:                            break;
1098:
1099:                        case EN_START: // fall through
1100:                        case EN_END:
1101:                            // left- or right-aligned text:
1102:                            // if the second element is chosen as a line break these elements 
1103:                            // add a constant amount of stretch at the end of a line, otherwise
1104:                            // they don't add any stretch
1105:                            spaceElements.add(new KnuthGlue(lineEndBAP,
1106:                                    3 * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1107:                                    0, new LeafPosition(this , -1), false));
1108:                            spaceElements.add(new KnuthPenalty(0, 0, false,
1109:                                    new LeafPosition(this , -1), false));
1110:                            spaceElements.add(new KnuthGlue(
1111:                                    -(lineStartBAP + lineEndBAP),
1112:                                    -3 * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1113:                                    0, new LeafPosition(this , -1), false));
1114:                            spaceElements.add(new KnuthInlineBox(0, null,
1115:                                    notifyPos(new LeafPosition(this , -1)),
1116:                                    false));
1117:                            spaceElements.add(new KnuthPenalty(0,
1118:                                    KnuthElement.INFINITE, false,
1119:                                    new LeafPosition(this , -1), false));
1120:                            spaceElements.add(new KnuthGlue(ai.ipdArea.opt
1121:                                    + lineStartBAP, 0, 0, mainPosition, false));
1122:                            break;
1123:
1124:                        case EN_JUSTIFY:
1125:                            // justified text:
1126:                            // the stretch and shrink depends on the space width
1127:                            spaceElements.add(new KnuthGlue(lineEndBAP, 0, 0,
1128:                                    new LeafPosition(this , -1), false));
1129:                            spaceElements.add(new KnuthPenalty(0, 0, false,
1130:                                    new LeafPosition(this , -1), false));
1131:                            spaceElements.add(new KnuthGlue(
1132:                                    -(lineStartBAP + lineEndBAP),
1133:                                    ai.ipdArea.max - ai.ipdArea.opt,
1134:                                    ai.ipdArea.opt - ai.ipdArea.min,
1135:                                    new LeafPosition(this , -1), false));
1136:                            spaceElements.add(new KnuthInlineBox(0, null,
1137:                                    notifyPos(new LeafPosition(this , -1)),
1138:                                    false));
1139:                            spaceElements.add(new KnuthPenalty(0,
1140:                                    KnuthElement.INFINITE, false,
1141:                                    new LeafPosition(this , -1), false));
1142:                            spaceElements
1143:                                    .add(new KnuthGlue(lineStartBAP
1144:                                            + ai.ipdArea.opt, 0, 0,
1145:                                            mainPosition, false));
1146:                            break;
1147:
1148:                        default:
1149:                            // last line justified, the other lines unjustified:
1150:                            // use only the space stretch
1151:                            spaceElements.add(new KnuthGlue(lineEndBAP, 0, 0,
1152:                                    new LeafPosition(this , -1), false));
1153:                            spaceElements.add(new KnuthPenalty(0, 0, false,
1154:                                    new LeafPosition(this , -1), false));
1155:                            spaceElements.add(new KnuthGlue(
1156:                                    -(lineStartBAP + lineEndBAP),
1157:                                    ai.ipdArea.max - ai.ipdArea.opt, 0,
1158:                                    new LeafPosition(this , -1), false));
1159:                            spaceElements.add(new KnuthInlineBox(0, null,
1160:                                    notifyPos(new LeafPosition(this , -1)),
1161:                                    false));
1162:                            spaceElements.add(new KnuthPenalty(0,
1163:                                    KnuthElement.INFINITE, false,
1164:                                    new LeafPosition(this , -1), false));
1165:                            spaceElements
1166:                                    .add(new KnuthGlue(lineStartBAP
1167:                                            + ai.ipdArea.opt, 0, 0,
1168:                                            mainPosition, false));
1169:                        }
1170:                    } else {
1171:                        // a (possible block) of breaking spaces
1172:                        switch (alignment) {
1173:                        case EN_CENTER:
1174:                            // centered text:
1175:                            // if the second element is chosen as a line break these elements 
1176:                            // add a constant amount of stretch at the end of a line and at the
1177:                            // beginning of the next one, otherwise they don't add any stretch
1178:                            spaceElements.add(new KnuthGlue(lineEndBAP,
1179:                                    3 * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1180:                                    0, new LeafPosition(this , -1), false));
1181:                            spaceElements.add(new KnuthPenalty(0, 0, false,
1182:                                    new LeafPosition(this , -1), false));
1183:                            spaceElements.add(new KnuthGlue(ai.ipdArea.opt
1184:                                    - (lineStartBAP + lineEndBAP), -6
1185:                                    * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1186:                                    mainPosition, false));
1187:                            spaceElements.add(new KnuthInlineBox(0, null,
1188:                                    notifyPos(new LeafPosition(this , -1)),
1189:                                    false));
1190:                            spaceElements.add(new KnuthPenalty(0,
1191:                                    KnuthElement.INFINITE, false,
1192:                                    new LeafPosition(this , -1), false));
1193:                            spaceElements.add(new KnuthGlue(lineStartBAP,
1194:                                    3 * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1195:                                    0, new LeafPosition(this , -1), false));
1196:                            break;
1197:
1198:                        case EN_START: // fall through
1199:                        case EN_END:
1200:                            // left- or right-aligned text:
1201:                            // if the second element is chosen as a line break these elements 
1202:                            // add a constant amount of stretch at the end of a line, otherwise
1203:                            // they don't add any stretch
1204:                            if (lineStartBAP != 0 || lineEndBAP != 0) {
1205:                                spaceElements
1206:                                        .add(new KnuthGlue(
1207:                                                lineEndBAP,
1208:                                                3 * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1209:                                                0, new LeafPosition(this , -1),
1210:                                                false));
1211:                                spaceElements.add(new KnuthPenalty(0, 0, false,
1212:                                        new LeafPosition(this , -1), false));
1213:                                spaceElements
1214:                                        .add(new KnuthGlue(
1215:                                                ai.ipdArea.opt
1216:                                                        - (lineStartBAP + lineEndBAP),
1217:                                                -3
1218:                                                        * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1219:                                                0, mainPosition, false));
1220:                                spaceElements.add(new KnuthInlineBox(0, null,
1221:                                        notifyPos(new LeafPosition(this , -1)),
1222:                                        false));
1223:                                spaceElements.add(new KnuthPenalty(0,
1224:                                        KnuthElement.INFINITE, false,
1225:                                        new LeafPosition(this , -1), false));
1226:                                spaceElements
1227:                                        .add(new KnuthGlue(lineStartBAP, 0, 0,
1228:                                                new LeafPosition(this , -1),
1229:                                                false));
1230:                            } else {
1231:                                spaceElements
1232:                                        .add(new KnuthGlue(
1233:                                                0,
1234:                                                3 * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1235:                                                0, new LeafPosition(this , -1),
1236:                                                false));
1237:                                spaceElements.add(new KnuthPenalty(0, 0, false,
1238:                                        new LeafPosition(this , -1), false));
1239:                                spaceElements
1240:                                        .add(new KnuthGlue(
1241:                                                ai.ipdArea.opt,
1242:                                                -3
1243:                                                        * LineLayoutManager.DEFAULT_SPACE_WIDTH,
1244:                                                0, mainPosition, false));
1245:                            }
1246:                            break;
1247:
1248:                        case EN_JUSTIFY:
1249:                            // justified text:
1250:                            // the stretch and shrink depends on the space width
1251:                            if (lineStartBAP != 0 || lineEndBAP != 0) {
1252:                                spaceElements.add(new KnuthGlue(lineEndBAP, 0,
1253:                                        0, new LeafPosition(this , -1), false));
1254:                                spaceElements.add(new KnuthPenalty(0, 0, false,
1255:                                        new LeafPosition(this , -1), false));
1256:                                spaceElements.add(new KnuthGlue(ai.ipdArea.opt
1257:                                        - (lineStartBAP + lineEndBAP),
1258:                                        ai.ipdArea.max - ai.ipdArea.opt,
1259:                                        ai.ipdArea.opt - ai.ipdArea.min,
1260:                                        mainPosition, false));
1261:                                spaceElements.add(new KnuthInlineBox(0, null,
1262:                                        notifyPos(new LeafPosition(this , -1)),
1263:                                        false));
1264:                                spaceElements.add(new KnuthPenalty(0,
1265:                                        KnuthElement.INFINITE, false,
1266:                                        new LeafPosition(this , -1), false));
1267:                                spaceElements
1268:                                        .add(new KnuthGlue(lineStartBAP, 0, 0,
1269:                                                new LeafPosition(this , -1),
1270:                                                false));
1271:                            } else {
1272:                                spaceElements.add(new KnuthGlue(ai.ipdArea.opt,
1273:                                        ai.ipdArea.max - ai.ipdArea.opt,
1274:                                        ai.ipdArea.opt - ai.ipdArea.min,
1275:                                        mainPosition, false));
1276:                            }
1277:                            break;
1278:
1279:                        default:
1280:                            // last line justified, the other lines unjustified:
1281:                            // use only the space stretch
1282:                            if (lineStartBAP != 0 || lineEndBAP != 0) {
1283:                                spaceElements.add(new KnuthGlue(lineEndBAP, 0,
1284:                                        0, new LeafPosition(this , -1), false));
1285:                                spaceElements.add(new KnuthPenalty(0, 0, false,
1286:                                        new LeafPosition(this , -1), false));
1287:                                spaceElements.add(new KnuthGlue(ai.ipdArea.opt
1288:                                        - (lineStartBAP + lineEndBAP),
1289:                                        ai.ipdArea.max - ai.ipdArea.opt, 0,
1290:                                        mainPosition, false));
1291:                                spaceElements.add(new KnuthInlineBox(0, null,
1292:                                        notifyPos(new LeafPosition(this , -1)),
1293:                                        false));
1294:                                spaceElements.add(new KnuthPenalty(0,
1295:                                        KnuthElement.INFINITE, false,
1296:                                        new LeafPosition(this , -1), false));
1297:                                spaceElements
1298:                                        .add(new KnuthGlue(lineStartBAP, 0, 0,
1299:                                                new LeafPosition(this , -1),
1300:                                                false));
1301:                            } else {
1302:                                spaceElements.add(new KnuthGlue(ai.ipdArea.opt,
1303:                                        ai.ipdArea.max - ai.ipdArea.opt, 0,
1304:                                        mainPosition, false));
1305:                            }
1306:                        }
1307:                    }
1308:                }
1309:
1310:                return spaceElements;
1311:            }
1312:
1313:            private LinkedList createElementsForAWordFragment(int alignment,
1314:                    AreaInfo ai, int leafValue, MinOptMax letterSpaceWidth) {
1315:                LinkedList wordElements = new LinkedList();
1316:                LeafPosition mainPosition = new LeafPosition(this , leafValue);
1317:
1318:                // if the last character of the word fragment is '-' or '/',
1319:                // the fragment could end a line; in this case, it loses one
1320:                // of its letter spaces;
1321:                boolean bSuppressibleLetterSpace = ai.breakOppAfter
1322:                        && !ai.bHyphenated;
1323:
1324:                if (letterSpaceWidth.min == letterSpaceWidth.max) {
1325:                    // constant letter spacing
1326:                    wordElements.add(new KnuthInlineBox(
1327:                            bSuppressibleLetterSpace ? ai.ipdArea.opt
1328:                                    - letterSpaceWidth.opt : ai.ipdArea.opt,
1329:                            alignmentContext, notifyPos(mainPosition), false));
1330:                } else {
1331:                    // adjustable letter spacing
1332:                    int unsuppressibleLetterSpaces = bSuppressibleLetterSpace ? ai.iLScount - 1
1333:                            : ai.iLScount;
1334:                    wordElements.add(new KnuthInlineBox(ai.ipdArea.opt
1335:                            - ai.iLScount * letterSpaceWidth.opt,
1336:                            alignmentContext, notifyPos(mainPosition), false));
1337:                    wordElements.add(new KnuthPenalty(0, KnuthElement.INFINITE,
1338:                            false, new LeafPosition(this , -1), true));
1339:                    wordElements
1340:                            .add(new KnuthGlue(
1341:                                    unsuppressibleLetterSpaces
1342:                                            * letterSpaceWidth.opt,
1343:                                    unsuppressibleLetterSpaces
1344:                                            * (letterSpaceWidth.max - letterSpaceWidth.opt),
1345:                                    unsuppressibleLetterSpaces
1346:                                            * (letterSpaceWidth.opt - letterSpaceWidth.min),
1347:                                    new LeafPosition(this , -1), true));
1348:                    wordElements.add(new KnuthInlineBox(0, null,
1349:                            notifyPos(new LeafPosition(this , -1)), true));
1350:                }
1351:
1352:                // extra-elements if the word fragment is the end of a syllable,
1353:                // or it ends with a character that can be used as a line break
1354:                if (ai.bHyphenated) {
1355:                    MinOptMax widthIfNoBreakOccurs = null;
1356:                    if (ai.iBreakIndex < textArray.length) {
1357:                        //Add in kerning in no-break condition
1358:                        widthIfNoBreakOccurs = letterAdjustArray[ai.iBreakIndex];
1359:                    }
1360:                    //if (ai.iBreakIndex)
1361:
1362:                    // the word fragment ends at the end of a syllable:
1363:                    // if a break occurs the content width increases,
1364:                    // otherwise nothing happens
1365:                    wordElements.addAll(createElementsForAHyphen(alignment,
1366:                            hyphIPD, widthIfNoBreakOccurs, ai.breakOppAfter
1367:                                    && ai.bHyphenated));
1368:                } else if (bSuppressibleLetterSpace) {
1369:                    // the word fragment ends with a character that acts as a hyphen
1370:                    // if a break occurs the width does not increase,
1371:                    // otherwise there is one more letter space
1372:                    wordElements.addAll(createElementsForAHyphen(alignment, 0,
1373:                            letterSpaceWidth, true));
1374:                }
1375:                return wordElements;
1376:            }
1377:
1378:            // static final int SOFT_HYPHEN_PENALTY = KnuthPenalty.FLAGGED_PENALTY / 10;
1379:            static final int SOFT_HYPHEN_PENALTY = 1;
1380:
1381:            private LinkedList createElementsForAHyphen(int alignment,
1382:                    int widthIfBreakOccurs, MinOptMax widthIfNoBreakOccurs,
1383:                    boolean unflagged) {
1384:                if (widthIfNoBreakOccurs == null) {
1385:                    widthIfNoBreakOccurs = ZERO_MINOPTMAX;
1386:                }
1387:                LinkedList hyphenElements = new LinkedList();
1388:
1389:                switch (alignment) {
1390:                case EN_CENTER:
1391:                    // centered text:
1392:                    /*
1393:                    hyphenElements.add
1394:                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1395:                                new LeafPosition(this, -1), false));
1396:                    hyphenElements.add
1397:                        (new KnuthPenalty(hyphIPD,
1398:                                KnuthPenalty.FLAGGED_PENALTY, true,
1399:                                new LeafPosition(this, -1), false));
1400:                    hyphenElements.add
1401:                        (new KnuthGlue(0,
1402:                                - 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1403:                                new LeafPosition(this, -1), false));
1404:                    hyphenElements.add
1405:                        (new KnuthInlineBox(0, 0, 0, 0,
1406:                                new LeafPosition(this, -1), false));
1407:                    hyphenElements.add
1408:                        (new KnuthPenalty(0, KnuthElement.INFINITE, true,
1409:                                new LeafPosition(this, -1), false));
1410:                    hyphenElements.add
1411:                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1412:                                new LeafPosition(this, -1), false));
1413:                     */
1414:                    hyphenElements.add(new KnuthPenalty(0,
1415:                            KnuthElement.INFINITE, false, new LeafPosition(
1416:                                    this , -1), true));
1417:                    hyphenElements.add(new KnuthGlue(lineEndBAP,
1418:                            3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1419:                            new LeafPosition(this , -1), true));
1420:                    hyphenElements.add(new KnuthPenalty(hyphIPD,
1421:                            unflagged ? SOFT_HYPHEN_PENALTY
1422:                                    : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
1423:                            new LeafPosition(this , -1), false));
1424:                    hyphenElements.add(new KnuthGlue(
1425:                            -(lineEndBAP + lineStartBAP), -6
1426:                                    * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1427:                            new LeafPosition(this , -1), false));
1428:                    hyphenElements.add(new KnuthInlineBox(0, null,
1429:                            notifyPos(new LeafPosition(this , -1)), true));
1430:                    hyphenElements.add(new KnuthPenalty(0,
1431:                            KnuthElement.INFINITE, false, new LeafPosition(
1432:                                    this , -1), true));
1433:                    hyphenElements.add(new KnuthGlue(lineStartBAP,
1434:                            3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1435:                            new LeafPosition(this , -1), true));
1436:                    break;
1437:
1438:                case EN_START: // fall through
1439:                case EN_END:
1440:                    // left- or right-aligned text:
1441:                    /*
1442:                    hyphenElements.add
1443:                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1444:                                new LeafPosition(this, -1), false));
1445:                    hyphenElements.add
1446:                        (new KnuthPenalty(widthIfBreakOccurs,
1447:                                KnuthPenalty.FLAGGED_PENALTY, true,
1448:                                new LeafPosition(this, -1), false));
1449:                     hyphenElements.add
1450:                        (new KnuthGlue(widthIfNoBreakOccurs.opt,
1451:                                - 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1452:                                new LeafPosition(this, -1), false));
1453:                     */
1454:                    if (lineStartBAP != 0 || lineEndBAP != 0) {
1455:                        hyphenElements.add(new KnuthPenalty(0,
1456:                                KnuthElement.INFINITE, false, new LeafPosition(
1457:                                        this , -1), true));
1458:                        hyphenElements.add(new KnuthGlue(lineEndBAP,
1459:                                3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1460:                                new LeafPosition(this , -1), false));
1461:                        hyphenElements.add(new KnuthPenalty(widthIfBreakOccurs,
1462:                                unflagged ? SOFT_HYPHEN_PENALTY
1463:                                        : KnuthPenalty.FLAGGED_PENALTY,
1464:                                !unflagged, new LeafPosition(this , -1), false));
1465:                        hyphenElements.add(new KnuthGlue(
1466:                                widthIfNoBreakOccurs.opt
1467:                                        - (lineStartBAP + lineEndBAP),
1468:                                -3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1469:                                new LeafPosition(this , -1), false));
1470:                        hyphenElements.add(new KnuthInlineBox(0, null,
1471:                                notifyPos(new LeafPosition(this , -1)), false));
1472:                        hyphenElements.add(new KnuthPenalty(0,
1473:                                KnuthElement.INFINITE, false, new LeafPosition(
1474:                                        this , -1), false));
1475:                        hyphenElements.add(new KnuthGlue(lineStartBAP, 0, 0,
1476:                                new LeafPosition(this , -1), false));
1477:                    } else {
1478:                        hyphenElements.add(new KnuthPenalty(0,
1479:                                KnuthElement.INFINITE, false, new LeafPosition(
1480:                                        this , -1), true));
1481:                        hyphenElements.add(new KnuthGlue(0,
1482:                                3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1483:                                new LeafPosition(this , -1), false));
1484:                        hyphenElements.add(new KnuthPenalty(widthIfBreakOccurs,
1485:                                unflagged ? SOFT_HYPHEN_PENALTY
1486:                                        : KnuthPenalty.FLAGGED_PENALTY,
1487:                                !unflagged, new LeafPosition(this , -1), false));
1488:                        hyphenElements.add(new KnuthGlue(
1489:                                widthIfNoBreakOccurs.opt,
1490:                                -3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
1491:                                new LeafPosition(this , -1), false));
1492:                    }
1493:                    break;
1494:
1495:                default:
1496:                    // justified text, or last line justified:
1497:                    // just a flagged penalty
1498:                    /*
1499:                    hyphenElements.add
1500:                        (new KnuthPenalty(widthIfBreakOccurs,
1501:                                KnuthPenalty.FLAGGED_PENALTY, true,
1502:                                new LeafPosition(this, -1), false));
1503:                     */
1504:                    if (lineStartBAP != 0 || lineEndBAP != 0) {
1505:                        hyphenElements.add(new KnuthPenalty(0,
1506:                                KnuthElement.INFINITE, false, new LeafPosition(
1507:                                        this , -1), true));
1508:
1509:                        hyphenElements.add(new KnuthGlue(lineEndBAP, 0, 0,
1510:                                new LeafPosition(this , -1), false));
1511:                        hyphenElements.add(new KnuthPenalty(widthIfBreakOccurs,
1512:                                unflagged ? SOFT_HYPHEN_PENALTY
1513:                                        : KnuthPenalty.FLAGGED_PENALTY,
1514:                                !unflagged, new LeafPosition(this , -1), false));
1515:                        // extra elements representing a letter space that is suppressed
1516:                        // if a break occurs
1517:                        if (widthIfNoBreakOccurs.min != 0
1518:                                || widthIfNoBreakOccurs.max != 0) {
1519:                            hyphenElements.add(new KnuthGlue(
1520:                                    widthIfNoBreakOccurs.opt
1521:                                            - (lineStartBAP + lineEndBAP),
1522:                                    widthIfNoBreakOccurs.max
1523:                                            - widthIfNoBreakOccurs.opt,
1524:                                    widthIfNoBreakOccurs.opt
1525:                                            - widthIfNoBreakOccurs.min,
1526:                                    new LeafPosition(this , -1), false));
1527:                        } else {
1528:                            hyphenElements.add(new KnuthGlue(
1529:                                    -(lineStartBAP + lineEndBAP), 0, 0,
1530:                                    new LeafPosition(this , -1), false));
1531:                        }
1532:                        hyphenElements.add(new KnuthInlineBox(0, null,
1533:                                notifyPos(new LeafPosition(this , -1)), false));
1534:                        hyphenElements.add(new KnuthPenalty(0,
1535:                                KnuthElement.INFINITE, false, new LeafPosition(
1536:                                        this , -1), false));
1537:                        hyphenElements.add(new KnuthGlue(lineStartBAP, 0, 0,
1538:                                new LeafPosition(this , -1), false));
1539:                    } else {
1540:                        hyphenElements.add(new KnuthPenalty(widthIfBreakOccurs,
1541:                                unflagged ? SOFT_HYPHEN_PENALTY
1542:                                        : KnuthPenalty.FLAGGED_PENALTY,
1543:                                !unflagged, new LeafPosition(this , -1), false));
1544:                        // extra elements representing a letter space that is suppressed
1545:                        // if a break occurs
1546:                        if (widthIfNoBreakOccurs.min != 0
1547:                                || widthIfNoBreakOccurs.max != 0) {
1548:                            hyphenElements.add(new KnuthGlue(
1549:                                    widthIfNoBreakOccurs.opt,
1550:                                    widthIfNoBreakOccurs.max
1551:                                            - widthIfNoBreakOccurs.opt,
1552:                                    widthIfNoBreakOccurs.opt
1553:                                            - widthIfNoBreakOccurs.min,
1554:                                    new LeafPosition(this , -1), false));
1555:                        }
1556:                    }
1557:                }
1558:
1559:                return hyphenElements;
1560:            }
1561:
1562:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.