Source Code Cross Referenced for AbstractBreaker.java in  » Graphic-Library » fop » org » apache » fop » layoutmgr » 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 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:
018:        /* $Id: AbstractBreaker.java 554094 2007-07-07 00:04:25Z adelmelle $ */
019:
020:        package org.apache.fop.layoutmgr;
021:
022:        import java.util.LinkedList;
023:        import java.util.List;
024:        import java.util.ListIterator;
025:
026:        import org.apache.commons.logging.Log;
027:        import org.apache.commons.logging.LogFactory;
028:        import org.apache.fop.fo.Constants;
029:        import org.apache.fop.traits.MinOptMax;
030:
031:        /**
032:         * Abstract base class for breakers (page breakers, static region handlers etc.).
033:         */
034:        public abstract class AbstractBreaker {
035:
036:            /** logging instance */
037:            protected static Log log = LogFactory.getLog(AbstractBreaker.class);
038:
039:            public static class PageBreakPosition extends LeafPosition {
040:                double bpdAdjust; // Percentage to adjust (stretch or shrink)
041:                int difference;
042:                int footnoteFirstListIndex;
043:                int footnoteFirstElementIndex;
044:                int footnoteLastListIndex;
045:                int footnoteLastElementIndex;
046:
047:                PageBreakPosition(LayoutManager lm, int iBreakIndex, int ffli,
048:                        int ffei, int flli, int flei, double bpdA, int diff) {
049:                    super (lm, iBreakIndex);
050:                    bpdAdjust = bpdA;
051:                    difference = diff;
052:                    footnoteFirstListIndex = ffli;
053:                    footnoteFirstElementIndex = ffei;
054:                    footnoteLastListIndex = flli;
055:                    footnoteLastElementIndex = flei;
056:                }
057:            }
058:
059:            public class BlockSequence extends BlockKnuthSequence {
060:
061:                /** Number of elements to ignore at the beginning of the list. */
062:                public int ignoreAtStart = 0;
063:                /** Number of elements to ignore at the end of the list. */
064:                public int ignoreAtEnd = 0;
065:
066:                /**
067:                 * startOn represents where on the page/which page layout
068:                 * should start for this BlockSequence.  Acceptable values:
069:                 * Constants.EN_ANY (can continue from finished location 
070:                 * of previous BlockSequence?), EN_COLUMN, EN_ODD_PAGE, 
071:                 * EN_EVEN_PAGE. 
072:                 */
073:                private int startOn;
074:
075:                private int displayAlign;
076:
077:                /**
078:                 * Creates a new BlockSequence.
079:                 * @param iStartOn the kind of page the sequence should start on. One of EN_ANY, EN_COLUMN, 
080:                 *                 EN_ODD_PAGE, EN_EVEN_PAGE.
081:                 * @param displayAlign the value for the display-align property
082:                 */
083:                public BlockSequence(int iStartOn, int displayAlign) {
084:                    super ();
085:                    startOn = iStartOn;
086:                    this .displayAlign = displayAlign;
087:                }
088:
089:                /**
090:                 * @return the kind of page the sequence should start on. One of EN_ANY, EN_COLUMN, 
091:                 *         EN_ODD_PAGE, EN_EVEN_PAGE.
092:                 */
093:                public int getStartOn() {
094:                    return this .startOn;
095:                }
096:
097:                /** @return the value for the display-align property */
098:                public int getDisplayAlign() {
099:                    return this .displayAlign;
100:                }
101:
102:                /**
103:                 * Finalizes a Knuth sequence.
104:                 * @return a finalized sequence.
105:                 */
106:                public KnuthSequence endSequence() {
107:                    return endSequence(null);
108:                }
109:
110:                /**
111:                 * Finalizes a Knuth sequence.
112:                 * @param breakPosition a Position instance for the last penalty (may be null)
113:                 * @return a finalized sequence.
114:                 */
115:                public KnuthSequence endSequence(Position breakPosition) {
116:                    // remove glue and penalty item at the end of the paragraph
117:                    while (this .size() > ignoreAtStart
118:                            && !((KnuthElement) this .get(this .size() - 1))
119:                                    .isBox()) {
120:                        this .remove(this .size() - 1);
121:                    }
122:                    if (this .size() > ignoreAtStart) {
123:                        // add the elements representing the space at the end of the last line
124:                        // and the forced break
125:                        if (getDisplayAlign() == Constants.EN_X_DISTRIBUTE
126:                                && isSinglePartFavored()) {
127:                            this .add(new KnuthPenalty(0,
128:                                    -KnuthElement.INFINITE, false,
129:                                    breakPosition, false));
130:                            ignoreAtEnd = 1;
131:                        } else {
132:                            this .add(new KnuthPenalty(0, KnuthElement.INFINITE,
133:                                    false, null, false));
134:                            this 
135:                                    .add(new KnuthGlue(0, 10000000, 0, null,
136:                                            false));
137:                            this .add(new KnuthPenalty(0,
138:                                    -KnuthElement.INFINITE, false,
139:                                    breakPosition, false));
140:                            ignoreAtEnd = 3;
141:                        }
142:                        return this ;
143:                    } else {
144:                        this .clear();
145:                        return null;
146:                    }
147:                }
148:
149:                public BlockSequence endBlockSequence(Position breakPosition) {
150:                    KnuthSequence temp = endSequence(breakPosition);
151:                    if (temp != null) {
152:                        BlockSequence returnSequence = new BlockSequence(
153:                                startOn, displayAlign);
154:                        returnSequence.addAll(temp);
155:                        returnSequence.ignoreAtEnd = this .ignoreAtEnd;
156:                        return returnSequence;
157:                    } else {
158:                        return null;
159:                    }
160:                }
161:
162:            }
163:
164:            /** blockListIndex of the current BlockSequence in blockLists */
165:            private int blockListIndex = 0;
166:
167:            private List blockLists = null;
168:
169:            protected int alignment;
170:            private int alignmentLast;
171:
172:            protected MinOptMax footnoteSeparatorLength = new MinOptMax(0);
173:
174:            protected abstract int getCurrentDisplayAlign();
175:
176:            protected abstract boolean hasMoreContent();
177:
178:            protected abstract void addAreas(PositionIterator posIter,
179:                    LayoutContext context);
180:
181:            protected abstract LayoutManager getTopLevelLM();
182:
183:            protected abstract LayoutManager getCurrentChildLM();
184:
185:            /**
186:             * Controls the behaviour of the algorithm in cases where the first element of a part
187:             * overflows a line/page. 
188:             * @return true if the algorithm should try to send the element to the next line/page.
189:             */
190:            protected boolean isPartOverflowRecoveryActivated() {
191:                return true;
192:            }
193:
194:            /**
195:             * @return true if one a single part should be produced if possible (ex. for block-containers)
196:             */
197:            protected boolean isSinglePartFavored() {
198:                return false;
199:            }
200:
201:            /**
202:             * Returns the PageProvider if any. PageBreaker overrides this method because each
203:             * page may have a different available BPD which needs to be accessible to the breaking
204:             * algorithm.
205:             * @return the applicable PageProvider, or null if not applicable
206:             */
207:            protected PageProvider getPageProvider() {
208:                return null;
209:            }
210:
211:            /**
212:             * Returns a PageBreakingLayoutListener for the PageBreakingAlgorithm to notify about layout
213:             * problems.
214:             * @return the listener instance or null if no notifications are needed
215:             */
216:            protected PageBreakingAlgorithm.PageBreakingLayoutListener getLayoutListener() {
217:                return null;
218:            }
219:
220:            /*
221:             * This method is to contain the logic to determine the LM's
222:             * getNextKnuthElements() implementation(s) that are to be called. 
223:             * @return LinkedList of Knuth elements.  
224:             */
225:            protected abstract LinkedList getNextKnuthElements(
226:                    LayoutContext context, int alignment);
227:
228:            /** @return true if there's no content that could be handled. */
229:            public boolean isEmpty() {
230:                return (this .blockLists.size() == 0);
231:            }
232:
233:            protected void startPart(BlockSequence list, int breakClass) {
234:                //nop
235:            }
236:
237:            /**
238:             * This method is called when no content is available for a part. Used to force empty pages.
239:             */
240:            protected void handleEmptyContent() {
241:                //nop    
242:            }
243:
244:            protected abstract void finishPart(PageBreakingAlgorithm alg,
245:                    PageBreakPosition pbp);
246:
247:            /**
248:             * Creates the top-level LayoutContext for the breaker operation.
249:             * @return the top-level LayoutContext
250:             */
251:            protected LayoutContext createLayoutContext() {
252:                return new LayoutContext(0);
253:            }
254:
255:            /**
256:             * Used to update the LayoutContext in subclasses prior to starting a new element list.
257:             * @param context the LayoutContext to update
258:             */
259:            protected void updateLayoutContext(LayoutContext context) {
260:                //nop
261:            }
262:
263:            /**
264:             * Used for debugging purposes. Notifies all registered observers about the element list.
265:             * Override to set different parameters.
266:             * @param elementList the Knuth element list
267:             */
268:            protected void observeElementList(List elementList) {
269:                ElementListObserver.observe(elementList, "breaker", null);
270:            }
271:
272:            /**
273:             * Starts the page breaking process.
274:             * @param flowBPD the constant available block-progression-dimension (used for every part)
275:             */
276:            public void doLayout(int flowBPD) {
277:                doLayout(flowBPD, false);
278:            }
279:
280:            /**
281:             * Starts the page breaking process.
282:             * @param flowBPD the constant available block-progression-dimension (used for every part)
283:             * @param autoHeight true if warnings about overflows should be disabled because the
284:             *                   the BPD is really undefined (for footnote-separators, for example)
285:             */
286:            public void doLayout(int flowBPD, boolean autoHeight) {
287:                LayoutContext childLC = createLayoutContext();
288:                childLC.setStackLimit(new MinOptMax(flowBPD));
289:
290:                if (getCurrentDisplayAlign() == Constants.EN_X_FILL) {
291:                    //EN_X_FILL is non-standard (by LF)
292:                    alignment = Constants.EN_JUSTIFY;
293:                } else if (getCurrentDisplayAlign() == Constants.EN_X_DISTRIBUTE) {
294:                    //EN_X_DISTRIBUTE is non-standard (by LF)
295:                    alignment = Constants.EN_JUSTIFY;
296:                } else {
297:                    alignment = Constants.EN_START;
298:                }
299:                alignmentLast = Constants.EN_START;
300:                if (isSinglePartFavored() && alignment == Constants.EN_JUSTIFY) {
301:                    alignmentLast = Constants.EN_JUSTIFY;
302:                }
303:                childLC.setBPAlignment(alignment);
304:
305:                BlockSequence blockList;
306:                this .blockLists = new java.util.ArrayList();
307:
308:                log.debug("PLM> flow BPD =" + flowBPD);
309:
310:                //*** Phase 1: Get Knuth elements ***
311:                int nextSequenceStartsOn = Constants.EN_ANY;
312:                while (hasMoreContent()) {
313:                    blockLists.clear();
314:
315:                    nextSequenceStartsOn = getNextBlockList(childLC,
316:                            nextSequenceStartsOn);
317:
318:                    //*** Phase 2: Alignment and breaking ***
319:                    log.debug("PLM> blockLists.size() = " + blockLists.size());
320:                    for (blockListIndex = 0; blockListIndex < blockLists.size(); blockListIndex++) {
321:                        blockList = (BlockSequence) blockLists
322:                                .get(blockListIndex);
323:
324:                        //debug code start
325:                        if (log.isDebugEnabled()) {
326:                            log.debug("  blockListIndex = " + blockListIndex);
327:                            String pagina = (blockList.startOn == Constants.EN_ANY) ? "any page"
328:                                    : (blockList.startOn == Constants.EN_ODD_PAGE) ? "odd page"
329:                                            : "even page";
330:                            log.debug("  sequence starts on " + pagina);
331:                        }
332:                        observeElementList(blockList);
333:                        //debug code end
334:
335:                        log.debug("PLM> start of algorithm ("
336:                                + this .getClass().getName() + "), flow BPD ="
337:                                + flowBPD);
338:                        PageBreakingAlgorithm alg = new PageBreakingAlgorithm(
339:                                getTopLevelLM(), getPageProvider(),
340:                                getLayoutListener(), alignment, alignmentLast,
341:                                footnoteSeparatorLength,
342:                                isPartOverflowRecoveryActivated(), autoHeight,
343:                                isSinglePartFavored());
344:                        int iOptPageCount;
345:
346:                        BlockSequence effectiveList;
347:                        if (getCurrentDisplayAlign() == Constants.EN_X_FILL) {
348:                            /* justification */
349:                            effectiveList = justifyBoxes(blockList, alg,
350:                                    flowBPD);
351:                        } else {
352:                            /* no justification */
353:                            effectiveList = blockList;
354:                        }
355:
356:                        //iOptPageCount = alg.firstFit(effectiveList, flowBPD, 1, true);
357:                        alg.setConstantLineWidth(flowBPD);
358:                        iOptPageCount = alg.findBreakingPoints(effectiveList, /*flowBPD,*/
359:                        1, true, BreakingAlgorithm.ALL_BREAKS);
360:                        log.debug("PLM> iOptPageCount= " + iOptPageCount
361:                                + " pageBreaks.size()= "
362:                                + alg.getPageBreaks().size());
363:
364:                        //*** Phase 3: Add areas ***
365:                        doPhase3(alg, iOptPageCount, blockList, effectiveList);
366:                    }
367:                }
368:
369:            }
370:
371:            /**
372:             * Phase 3 of Knuth algorithm: Adds the areas 
373:             * @param alg PageBreakingAlgorithm instance which determined the breaks
374:             * @param partCount number of parts (pages) to be rendered
375:             * @param originalList original Knuth element list
376:             * @param effectiveList effective Knuth element list (after adjustments)
377:             */
378:            protected abstract void doPhase3(PageBreakingAlgorithm alg,
379:                    int partCount, BlockSequence originalList,
380:                    BlockSequence effectiveList);
381:
382:            /**
383:             * Phase 3 of Knuth algorithm: Adds the areas 
384:             * @param alg PageBreakingAlgorithm instance which determined the breaks
385:             * @param partCount number of parts (pages) to be rendered
386:             * @param originalList original Knuth element list
387:             * @param effectiveList effective Knuth element list (after adjustments)
388:             */
389:            protected void addAreas(PageBreakingAlgorithm alg, int partCount,
390:                    BlockSequence originalList, BlockSequence effectiveList) {
391:                addAreas(alg, 0, partCount, originalList, effectiveList);
392:            }
393:
394:            /**
395:             * Phase 3 of Knuth algorithm: Adds the areas 
396:             * @param alg PageBreakingAlgorithm instance which determined the breaks
397:             * @param startPart index of the first part (page) to be rendered
398:             * @param partCount number of parts (pages) to be rendered
399:             * @param originalList original Knuth element list
400:             * @param effectiveList effective Knuth element list (after adjustments)
401:             */
402:            protected void addAreas(PageBreakingAlgorithm alg, int startPart,
403:                    int partCount, BlockSequence originalList,
404:                    BlockSequence effectiveList) {
405:                LayoutContext childLC;
406:                // add areas
407:                ListIterator effectiveListIterator = effectiveList
408:                        .listIterator();
409:                int startElementIndex = 0;
410:                int endElementIndex = 0;
411:                int lastBreak = -1;
412:                for (int p = startPart; p < startPart + partCount; p++) {
413:                    PageBreakPosition pbp = (PageBreakPosition) alg
414:                            .getPageBreaks().get(p);
415:
416:                    //Check the last break position for forced breaks
417:                    int lastBreakClass;
418:                    if (p == 0) {
419:                        lastBreakClass = effectiveList.getStartOn();
420:                    } else {
421:                        ListElement lastBreakElement = effectiveList
422:                                .getElement(endElementIndex);
423:                        if (lastBreakElement.isPenalty()) {
424:                            KnuthPenalty pen = (KnuthPenalty) lastBreakElement;
425:                            lastBreakClass = pen.getBreakClass();
426:                        } else {
427:                            lastBreakClass = Constants.EN_COLUMN;
428:                        }
429:                    }
430:
431:                    //the end of the new part
432:                    endElementIndex = pbp.getLeafPos();
433:
434:                    // ignore the first elements added by the
435:                    // PageSequenceLayoutManager
436:                    startElementIndex += (startElementIndex == 0) ? effectiveList.ignoreAtStart
437:                            : 0;
438:
439:                    log.debug("PLM> part: " + (p + 1) + ", start at pos "
440:                            + startElementIndex + ", break at pos "
441:                            + endElementIndex + ", break class = "
442:                            + lastBreakClass);
443:
444:                    startPart(effectiveList, lastBreakClass);
445:
446:                    int displayAlign = getCurrentDisplayAlign();
447:
448:                    //The following is needed by SpaceResolver.performConditionalsNotification()
449:                    //further down as there may be important Position elements in the element list trailer
450:                    int notificationEndElementIndex = endElementIndex;
451:
452:                    // ignore the last elements added by the
453:                    // PageSequenceLayoutManager
454:                    endElementIndex -= (endElementIndex == (originalList.size() - 1)) ? effectiveList.ignoreAtEnd
455:                            : 0;
456:
457:                    // ignore the last element in the page if it is a KnuthGlue
458:                    // object
459:                    if (((KnuthElement) effectiveList.get(endElementIndex))
460:                            .isGlue()) {
461:                        endElementIndex--;
462:                    }
463:
464:                    // ignore KnuthGlue and KnuthPenalty objects
465:                    // at the beginning of the line
466:                    effectiveListIterator = effectiveList
467:                            .listIterator(startElementIndex);
468:                    KnuthElement firstElement;
469:                    while (effectiveListIterator.hasNext()
470:                            && !(firstElement = (KnuthElement) effectiveListIterator
471:                                    .next()).isBox()) {
472:                        /*
473:                        if (firstElement.isGlue() && firstElement.getLayoutManager() != null) {
474:                            // discard the space representd by the glue element
475:                            ((BlockLevelLayoutManager) firstElement
476:                                    .getLayoutManager())
477:                                    .discardSpace((KnuthGlue) firstElement);
478:                        }*/
479:                        startElementIndex++;
480:                    }
481:
482:                    if (startElementIndex <= endElementIndex) {
483:                        if (log.isDebugEnabled()) {
484:                            log.debug("     addAreas from " + startElementIndex
485:                                    + " to " + endElementIndex);
486:                        }
487:                        childLC = new LayoutContext(0);
488:                        // set the space adjustment ratio
489:                        childLC.setSpaceAdjust(pbp.bpdAdjust);
490:                        // add space before if display-align is center or bottom
491:                        // add space after if display-align is distribute and
492:                        // this is not the last page
493:                        if (pbp.difference != 0
494:                                && displayAlign == Constants.EN_CENTER) {
495:                            childLC.setSpaceBefore(pbp.difference / 2);
496:                        } else if (pbp.difference != 0
497:                                && displayAlign == Constants.EN_AFTER) {
498:                            childLC.setSpaceBefore(pbp.difference);
499:                        } else if (pbp.difference != 0
500:                                && displayAlign == Constants.EN_X_DISTRIBUTE
501:                                && p < (partCount - 1)) {
502:                            // count the boxes whose width is not 0
503:                            int boxCount = 0;
504:                            effectiveListIterator = effectiveList
505:                                    .listIterator(startElementIndex);
506:                            while (effectiveListIterator.nextIndex() <= endElementIndex) {
507:                                KnuthElement tempEl = (KnuthElement) effectiveListIterator
508:                                        .next();
509:                                if (tempEl.isBox() && tempEl.getW() > 0) {
510:                                    boxCount++;
511:                                }
512:                            }
513:                            // split the difference
514:                            if (boxCount >= 2) {
515:                                childLC.setSpaceAfter(pbp.difference
516:                                        / (boxCount - 1));
517:                            }
518:                        }
519:
520:                        /* *** *** non-standard extension *** *** */
521:                        if (displayAlign == Constants.EN_X_FILL) {
522:                            int averageLineLength = optimizeLineLength(
523:                                    effectiveList, startElementIndex,
524:                                    endElementIndex);
525:                            if (averageLineLength != 0) {
526:                                childLC.setStackLimit(new MinOptMax(
527:                                        averageLineLength));
528:                            }
529:                        }
530:                        /* *** *** non-standard extension *** *** */
531:
532:                        // Handle SpaceHandling(Break)Positions, see SpaceResolver!
533:                        SpaceResolver.performConditionalsNotification(
534:                                effectiveList, startElementIndex,
535:                                notificationEndElementIndex, lastBreak);
536:
537:                        // Add areas now!
538:                        addAreas(new KnuthPossPosIter(effectiveList,
539:                                startElementIndex, endElementIndex + 1),
540:                                childLC);
541:                    } else {
542:                        //no content for this part
543:                        handleEmptyContent();
544:                    }
545:
546:                    finishPart(alg, pbp);
547:
548:                    lastBreak = endElementIndex;
549:                    startElementIndex = pbp.getLeafPos() + 1;
550:                }
551:            }
552:
553:            /**
554:             * Notifies the layout managers about the space and conditional length situation based on
555:             * the break decisions.
556:             * @param effectiveList Element list to be painted
557:             * @param startElementIndex start index of the part
558:             * @param endElementIndex end index of the part
559:             * @param lastBreak index of the last break element
560:             */
561:            /**
562:             * Handles span changes reported through the <code>LayoutContext</code>. 
563:             * Only used by the PSLM and called by <code>getNextBlockList()</code>.
564:             * @param childLC the LayoutContext
565:             * @param nextSequenceStartsOn previous value for break handling
566:             * @return effective value for break handling
567:             */
568:            protected int handleSpanChange(LayoutContext childLC,
569:                    int nextSequenceStartsOn) {
570:                return nextSequenceStartsOn;
571:            }
572:
573:            /**
574:             * Gets the next block list (sequence) and adds it to a list of block lists if it's not empty.
575:             * @param childLC LayoutContext to use
576:             * @param nextSequenceStartsOn indicates on what page the next sequence should start
577:             * @return the page on which the next content should appear after a hard break
578:             */
579:            protected int getNextBlockList(LayoutContext childLC,
580:                    int nextSequenceStartsOn) {
581:                updateLayoutContext(childLC);
582:                //Make sure the span change signal is reset
583:                childLC.signalSpanChange(Constants.NOT_SET);
584:
585:                BlockSequence blockList;
586:                LinkedList returnedList = getNextKnuthElements(childLC,
587:                        alignment);
588:                if (returnedList != null) {
589:                    if (returnedList.size() == 0) {
590:                        nextSequenceStartsOn = handleSpanChange(childLC,
591:                                nextSequenceStartsOn);
592:                        return nextSequenceStartsOn;
593:                    }
594:                    blockList = new BlockSequence(nextSequenceStartsOn,
595:                            getCurrentDisplayAlign());
596:
597:                    //Only implemented by the PSLM
598:                    nextSequenceStartsOn = handleSpanChange(childLC,
599:                            nextSequenceStartsOn);
600:
601:                    Position breakPosition = null;
602:                    if (((KnuthElement) returnedList.getLast()).isPenalty()
603:                            && ((KnuthPenalty) returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
604:                        KnuthPenalty breakPenalty = (KnuthPenalty) returnedList
605:                                .removeLast();
606:                        breakPosition = breakPenalty.getPosition();
607:                        switch (breakPenalty.getBreakClass()) {
608:                        case Constants.EN_PAGE:
609:                            log.debug("PLM> break - PAGE");
610:                            nextSequenceStartsOn = Constants.EN_ANY;
611:                            break;
612:                        case Constants.EN_COLUMN:
613:                            log.debug("PLM> break - COLUMN");
614:                            //TODO Fix this when implementing multi-column layout
615:                            nextSequenceStartsOn = Constants.EN_COLUMN;
616:                            break;
617:                        case Constants.EN_ODD_PAGE:
618:                            log.debug("PLM> break - ODD PAGE");
619:                            nextSequenceStartsOn = Constants.EN_ODD_PAGE;
620:                            break;
621:                        case Constants.EN_EVEN_PAGE:
622:                            log.debug("PLM> break - EVEN PAGE");
623:                            nextSequenceStartsOn = Constants.EN_EVEN_PAGE;
624:                            break;
625:                        default:
626:                            throw new IllegalStateException(
627:                                    "Invalid break class: "
628:                                            + breakPenalty.getBreakClass());
629:                        }
630:                    }
631:                    blockList.addAll(returnedList);
632:                    BlockSequence seq = null;
633:                    seq = blockList.endBlockSequence(breakPosition);
634:                    if (seq != null) {
635:                        this .blockLists.add(seq);
636:                    }
637:                }
638:                return nextSequenceStartsOn;
639:            }
640:
641:            /**
642:             * Returns the average width of all the lines in the given range.
643:             * @param effectiveList effective block list to work on
644:             * @param startElementIndex
645:             * @param endElementIndex
646:             * @return the average line length, 0 if there's no content
647:             */
648:            private int optimizeLineLength(KnuthSequence effectiveList,
649:                    int startElementIndex, int endElementIndex) {
650:                ListIterator effectiveListIterator;
651:                // optimize line length
652:                int boxCount = 0;
653:                int accumulatedLineLength = 0;
654:                int greatestMinimumLength = 0;
655:                effectiveListIterator = effectiveList
656:                        .listIterator(startElementIndex);
657:                while (effectiveListIterator.nextIndex() <= endElementIndex) {
658:                    KnuthElement tempEl = (KnuthElement) effectiveListIterator
659:                            .next();
660:                    if (tempEl instanceof  KnuthBlockBox) {
661:                        KnuthBlockBox blockBox = (KnuthBlockBox) tempEl;
662:                        if (blockBox.getBPD() > 0) {
663:                            log.debug("PSLM> nominal length of line = "
664:                                    + blockBox.getBPD());
665:                            log
666:                                    .debug("      range = "
667:                                            + blockBox.getIPDRange());
668:                            boxCount++;
669:                            accumulatedLineLength += ((KnuthBlockBox) tempEl)
670:                                    .getBPD();
671:                        }
672:                        if (blockBox.getIPDRange().min > greatestMinimumLength) {
673:                            greatestMinimumLength = blockBox.getIPDRange().min;
674:                        }
675:                    }
676:                }
677:                int averageLineLength = 0;
678:                if (accumulatedLineLength > 0 && boxCount > 0) {
679:                    averageLineLength = (int) (accumulatedLineLength / boxCount);
680:                    log.debug("Average line length = " + averageLineLength);
681:                    if (averageLineLength < greatestMinimumLength) {
682:                        averageLineLength = greatestMinimumLength;
683:                        log.debug("  Correction to: " + averageLineLength);
684:                    }
685:                }
686:                return averageLineLength;
687:            }
688:
689:            /**
690:             * Justifies the boxes and returns them as a new KnuthSequence.
691:             * @param blockList block list to justify
692:             * @param alg reference to the algorithm instance
693:             * @param availableBPD the available BPD 
694:             * @return the effective list
695:             */
696:            private BlockSequence justifyBoxes(BlockSequence blockList,
697:                    PageBreakingAlgorithm alg, int availableBPD) {
698:                int iOptPageNumber;
699:                alg.setConstantLineWidth(availableBPD);
700:                iOptPageNumber = alg.findBreakingPoints(blockList, /*availableBPD,*/
701:                1, true, BreakingAlgorithm.ALL_BREAKS);
702:                log.debug("PLM> iOptPageNumber= " + iOptPageNumber);
703:
704:                // 
705:                ListIterator sequenceIterator = blockList.listIterator();
706:                ListIterator breakIterator = alg.getPageBreaks().listIterator();
707:                KnuthElement this Element = null;
708:                PageBreakPosition this Break;
709:                int accumulatedS; // accumulated stretch or shrink
710:                int adjustedDiff; // difference already adjusted
711:                int firstElementIndex;
712:
713:                while (breakIterator.hasNext()) {
714:                    this Break = (PageBreakPosition) breakIterator.next();
715:                    if (log.isDebugEnabled()) {
716:                        log.debug("| first page: break= "
717:                                + this Break.getLeafPos() + " difference= "
718:                                + this Break.difference + " ratio= "
719:                                + this Break.bpdAdjust);
720:                    }
721:                    accumulatedS = 0;
722:                    adjustedDiff = 0;
723:
724:                    // glue and penalty items at the beginning of the page must
725:                    // be ignored:
726:                    // the first element returned by sequenceIterator.next()
727:                    // inside the
728:                    // while loop must be a box
729:                    KnuthElement firstElement;
730:                    while (!(firstElement = (KnuthElement) sequenceIterator
731:                            .next()).isBox()) {
732:                        // 
733:                        log.debug("PLM> ignoring glue or penalty element "
734:                                + "at the beginning of the sequence");
735:                        if (firstElement.isGlue()) {
736:                            ((BlockLevelLayoutManager) firstElement
737:                                    .getLayoutManager())
738:                                    .discardSpace((KnuthGlue) firstElement);
739:                        }
740:                    }
741:                    firstElementIndex = sequenceIterator.previousIndex();
742:                    sequenceIterator.previous();
743:
744:                    // scan the sub-sequence representing a page,
745:                    // collecting information about potential adjustments
746:                    MinOptMax lineNumberMaxAdjustment = new MinOptMax(0);
747:                    MinOptMax spaceMaxAdjustment = new MinOptMax(0);
748:                    double spaceAdjustmentRatio = 0.0;
749:                    LinkedList blockSpacesList = new LinkedList();
750:                    LinkedList unconfirmedList = new LinkedList();
751:                    LinkedList adjustableLinesList = new LinkedList();
752:                    boolean bBoxSeen = false;
753:                    while (sequenceIterator.hasNext()
754:                            && sequenceIterator.nextIndex() <= this Break
755:                                    .getLeafPos()) {
756:                        this Element = (KnuthElement) sequenceIterator.next();
757:                        if (this Element.isGlue()) {
758:                            // glue elements are used to represent adjustable
759:                            // lines
760:                            // and adjustable spaces between blocks
761:                            switch (((KnuthGlue) this Element)
762:                                    .getAdjustmentClass()) {
763:                            case BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT:
764:                                // fall through
765:                            case BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT:
766:                                // potential space adjustment
767:                                // glue items before the first box or after the
768:                                // last one
769:                                // must be ignored
770:                                unconfirmedList.add(this Element);
771:                                break;
772:                            case BlockLevelLayoutManager.LINE_NUMBER_ADJUSTMENT:
773:                                // potential line number adjustment
774:                                lineNumberMaxAdjustment.max += ((KnuthGlue) this Element)
775:                                        .getY();
776:                                lineNumberMaxAdjustment.min -= ((KnuthGlue) this Element)
777:                                        .getZ();
778:                                adjustableLinesList.add(this Element);
779:                                break;
780:                            case BlockLevelLayoutManager.LINE_HEIGHT_ADJUSTMENT:
781:                                // potential line height adjustment
782:                                break;
783:                            default:
784:                                // nothing
785:                            }
786:                        } else if (this Element.isBox()) {
787:                            if (!bBoxSeen) {
788:                                // this is the first box met in this page
789:                                bBoxSeen = true;
790:                            } else if (unconfirmedList.size() > 0) {
791:                                // glue items in unconfirmedList were not after
792:                                // the last box
793:                                // in this page; they must be added to
794:                                // blockSpaceList
795:                                while (unconfirmedList.size() > 0) {
796:                                    KnuthGlue blockSpace = (KnuthGlue) unconfirmedList
797:                                            .removeFirst();
798:                                    spaceMaxAdjustment.max += ((KnuthGlue) blockSpace)
799:                                            .getY();
800:                                    spaceMaxAdjustment.min -= ((KnuthGlue) blockSpace)
801:                                            .getZ();
802:                                    blockSpacesList.add(blockSpace);
803:                                }
804:                            }
805:                        }
806:                    }
807:                    log.debug("| line number adj= " + lineNumberMaxAdjustment);
808:                    log.debug("| space adj      = " + spaceMaxAdjustment);
809:
810:                    if (this Element.isPenalty() && this Element.getW() > 0) {
811:                        log
812:                                .debug("  mandatory variation to the number of lines!");
813:                        ((BlockLevelLayoutManager) this Element
814:                                .getLayoutManager()).negotiateBPDAdjustment(
815:                                this Element.getW(), this Element);
816:                    }
817:
818:                    if (this Break.bpdAdjust != 0
819:                            && (this Break.difference > 0 && this Break.difference <= spaceMaxAdjustment.max)
820:                            || (this Break.difference < 0 && this Break.difference >= spaceMaxAdjustment.min)) {
821:                        // modify only the spaces between blocks
822:                        spaceAdjustmentRatio = ((double) this Break.difference / (this Break.difference > 0 ? spaceMaxAdjustment.max
823:                                : spaceMaxAdjustment.min));
824:                        adjustedDiff += adjustBlockSpaces(
825:                                blockSpacesList,
826:                                this Break.difference,
827:                                (this Break.difference > 0 ? spaceMaxAdjustment.max
828:                                        : -spaceMaxAdjustment.min));
829:                        log.debug("single space: "
830:                                + (adjustedDiff == this Break.difference
831:                                        || this Break.bpdAdjust == 0 ? "ok"
832:                                        : "ERROR"));
833:                    } else if (this Break.bpdAdjust != 0) {
834:                        adjustedDiff += adjustLineNumbers(
835:                                adjustableLinesList,
836:                                this Break.difference,
837:                                (this Break.difference > 0 ? lineNumberMaxAdjustment.max
838:                                        : -lineNumberMaxAdjustment.min));
839:                        adjustedDiff += adjustBlockSpaces(
840:                                blockSpacesList,
841:                                this Break.difference - adjustedDiff,
842:                                ((this Break.difference - adjustedDiff) > 0 ? spaceMaxAdjustment.max
843:                                        : -spaceMaxAdjustment.min));
844:                        log.debug("lines and space: "
845:                                + (adjustedDiff == this Break.difference
846:                                        || this Break.bpdAdjust == 0 ? "ok"
847:                                        : "ERROR"));
848:
849:                    }
850:                }
851:
852:                // create a new sequence: the new elements will contain the
853:                // Positions
854:                // which will be used in the addAreas() phase
855:                BlockSequence effectiveList = new BlockSequence(blockList
856:                        .getStartOn(), blockList.getDisplayAlign());
857:                effectiveList.addAll(getCurrentChildLM()
858:                        .getChangedKnuthElements(
859:                                blockList.subList(0, blockList.size()
860:                                        - blockList.ignoreAtEnd),
861:                                /* 0, */0));
862:                //effectiveList.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
863:                // false, new Position(this), false));
864:                effectiveList.endSequence();
865:
866:                ElementListObserver.observe(effectiveList, "breaker-effective",
867:                        null);
868:
869:                alg.getPageBreaks().clear(); //Why this?
870:                return effectiveList;
871:            }
872:
873:            private int adjustBlockSpaces(LinkedList spaceList, int difference,
874:                    int total) {
875:                if (log.isDebugEnabled()) {
876:                    log.debug("AdjustBlockSpaces: difference " + difference
877:                            + " / " + total + " on " + spaceList.size()
878:                            + " spaces in block");
879:                }
880:                ListIterator spaceListIterator = spaceList.listIterator();
881:                int adjustedDiff = 0;
882:                int partial = 0;
883:                while (spaceListIterator.hasNext()) {
884:                    KnuthGlue blockSpace = (KnuthGlue) spaceListIterator.next();
885:                    partial += (difference > 0 ? blockSpace.getY() : blockSpace
886:                            .getZ());
887:                    if (log.isDebugEnabled()) {
888:                        log.debug("available = " + partial + " / " + total);
889:                        log
890:                                .debug("competenza  = "
891:                                        + (((int) ((float) partial * difference / total)) - adjustedDiff)
892:                                        + " / " + difference);
893:                    }
894:                    int newAdjust = ((BlockLevelLayoutManager) blockSpace
895:                            .getLayoutManager()).negotiateBPDAdjustment(
896:                            ((int) ((float) partial * difference / total))
897:                                    - adjustedDiff, blockSpace);
898:                    adjustedDiff += newAdjust;
899:                }
900:                return adjustedDiff;
901:            }
902:
903:            private int adjustLineNumbers(LinkedList lineList, int difference,
904:                    int total) {
905:                if (log.isDebugEnabled()) {
906:                    log.debug("AdjustLineNumbers: difference " + difference
907:                            + " / " + total + " on " + lineList.size()
908:                            + " elements");
909:                }
910:
911:                //            int adjustedDiff = 0;
912:                //            int partial = 0;
913:                //            KnuthGlue prevLine = null;
914:                //            KnuthGlue currLine = null;
915:                //            ListIterator lineListIterator = lineList.listIterator();
916:                //            while (lineListIterator.hasNext()) {
917:                //                currLine = (KnuthGlue)lineListIterator.next();
918:                //                if (prevLine != null
919:                //                    && prevLine.getLayoutManager() != currLine.getLayoutManager()) {
920:                //                    int newAdjust = ((BlockLevelLayoutManager) prevLine.getLayoutManager())
921:                //                                    .negotiateBPDAdjustment(((int) ((float) partial * difference / total)) - adjustedDiff, prevLine);
922:                //                    adjustedDiff += newAdjust;
923:                //                }
924:                //                partial += (difference > 0 ? currLine.getY() : currLine.getZ());
925:                //                prevLine = currLine;
926:                //            }
927:                //            if (currLine != null) {
928:                //                int newAdjust = ((BlockLevelLayoutManager) currLine.getLayoutManager())
929:                //                                .negotiateBPDAdjustment(((int) ((float) partial * difference / total)) - adjustedDiff, currLine);
930:                //                adjustedDiff += newAdjust;
931:                //            }
932:                //            return adjustedDiff;
933:
934:                ListIterator lineListIterator = lineList.listIterator();
935:                int adjustedDiff = 0;
936:                int partial = 0;
937:                while (lineListIterator.hasNext()) {
938:                    KnuthGlue line = (KnuthGlue) lineListIterator.next();
939:                    partial += (difference > 0 ? line.getY() : line.getZ());
940:                    int newAdjust = ((BlockLevelLayoutManager) line
941:                            .getLayoutManager()).negotiateBPDAdjustment(
942:                            ((int) ((float) partial * difference / total))
943:                                    - adjustedDiff, line);
944:                    adjustedDiff += newAdjust;
945:                }
946:                return adjustedDiff;
947:            }
948:
949:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.