KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > layoutmgr > BlockContainerLayoutManager


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id: BlockContainerLayoutManager.java 453310 2006-10-05 18:44:15Z spepping $ */
19
20 package org.apache.fop.layoutmgr;
21
22 import java.util.LinkedList JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.ListIterator JavaDoc;
25 import java.awt.Point JavaDoc;
26 import java.awt.geom.Rectangle2D JavaDoc;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.fop.area.Area;
31 import org.apache.fop.area.BlockViewport;
32 import org.apache.fop.area.Block;
33 import org.apache.fop.area.Trait;
34 import org.apache.fop.fo.FONode;
35 import org.apache.fop.fo.flow.BlockContainer;
36 import org.apache.fop.fo.properties.CommonAbsolutePosition;
37 import org.apache.fop.area.CTM;
38 import org.apache.fop.datatypes.FODimension;
39 import org.apache.fop.datatypes.Length;
40 import org.apache.fop.traits.MinOptMax;
41 import org.apache.fop.traits.SpaceVal;
42
43 /**
44  * LayoutManager for a block-container FO.
45  */

46 public class BlockContainerLayoutManager extends BlockStackingLayoutManager
47                 implements ConditionalElementListener {
48
49     /**
50      * logging instance
51      */

52     private static Log log = LogFactory.getLog(BlockContainerLayoutManager.class);
53     
54     private BlockViewport viewportBlockArea;
55     private Block referenceArea;
56
57     private CommonAbsolutePosition abProps;
58     private FODimension relDims;
59     private CTM absoluteCTM;
60     private Length width;
61     private Length height;
62     //private int vpContentIPD;
63
private int vpContentBPD;
64     
65     // When viewport should grow with the content.
66
private boolean autoHeight = true;
67     
68     /* holds the (one-time use) fo:block space-before
69     and -after properties. Large fo:blocks are split
70     into multiple Area.Blocks to accomodate the subsequent
71     regions (pages) they are placed on. space-before
72     is applied at the beginning of the first
73     Block and space-after at the end of the last Block
74     used in rendering the fo:block.
75     */

76     //TODO space-before|after: handle space-resolution rules
77
private MinOptMax foBlockSpaceBefore;
78     private MinOptMax foBlockSpaceAfter;
79     
80     private boolean discardBorderBefore;
81     private boolean discardBorderAfter;
82     private boolean discardPaddingBefore;
83     private boolean discardPaddingAfter;
84     private MinOptMax effSpaceBefore;
85     private MinOptMax effSpaceAfter;
86
87     
88     /**
89      * Create a new block container layout manager.
90      * @param node block-container node to create the layout manager for.
91      */

92     public BlockContainerLayoutManager(BlockContainer node) {
93         super(node);
94     }
95     
96     /** @see org.apache.fop.layoutmgr.LayoutManager#initialize() */
97     public void initialize() {
98         abProps = getBlockContainerFO().getCommonAbsolutePosition();
99         foBlockSpaceBefore = new SpaceVal(getBlockContainerFO().getCommonMarginBlock()
100                     .spaceBefore, this).getSpace();
101         foBlockSpaceAfter = new SpaceVal(getBlockContainerFO().getCommonMarginBlock()
102                     .spaceAfter, this).getSpace();
103         startIndent = getBlockContainerFO().getCommonMarginBlock().startIndent.getValue(this);
104         endIndent = getBlockContainerFO().getCommonMarginBlock().endIndent.getValue(this);
105
106         boolean rotated = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
107         if (rotated) {
108             height = getBlockContainerFO().getInlineProgressionDimension()
109                             .getOptimum(this).getLength();
110             width = getBlockContainerFO().getBlockProgressionDimension()
111                             .getOptimum(this).getLength();
112         } else {
113             height = getBlockContainerFO().getBlockProgressionDimension()
114                             .getOptimum(this).getLength();
115             width = getBlockContainerFO().getInlineProgressionDimension()
116                             .getOptimum(this).getLength();
117         }
118         
119         bpUnit = 0; //layoutProps.blockProgressionUnit;
120
if (bpUnit == 0) {
121             // use optimum space values
122
adjustedSpaceBefore = getBlockContainerFO().getCommonMarginBlock()
123                 .spaceBefore.getSpace().getOptimum(this).getLength().getValue(this);
124             adjustedSpaceAfter = getBlockContainerFO().getCommonMarginBlock()
125                 .spaceAfter.getSpace().getOptimum(this).getLength().getValue(this);
126         } else {
127             // use minimum space values
128
adjustedSpaceBefore = getBlockContainerFO().getCommonMarginBlock()
129                 .spaceBefore.getSpace().getMinimum(this).getLength().getValue(this);
130             adjustedSpaceAfter = getBlockContainerFO().getCommonMarginBlock()
131                 .spaceAfter.getSpace().getMinimum(this).getLength().getValue(this);
132         }
133     }
134     
135     private void resetSpaces() {
136         this.discardBorderBefore = false;
137         this.discardBorderAfter = false;
138         this.discardPaddingBefore = false;
139         this.discardPaddingAfter = false;
140         this.effSpaceBefore = null;
141         this.effSpaceAfter = null;
142     }
143
144     /** @return the content IPD */
145     protected int getRotatedIPD() {
146         return getBlockContainerFO().getInlineProgressionDimension()
147                 .getOptimum(this).getLength().getValue(this);
148     }
149
150     private boolean needClip() {
151         int overflow = getBlockContainerFO().getOverflow();
152         return (overflow == EN_HIDDEN || overflow == EN_ERROR_IF_OVERFLOW);
153     }
154     
155     private int getSpaceBefore() {
156         return foBlockSpaceBefore.opt;
157     }
158     
159     private int getBPIndents() {
160         int indents = 0;
161         /* TODO This is wrong isn't it?
162         indents += getBlockContainerFO().getCommonMarginBlock()
163                     .spaceBefore.getOptimum(this).getLength().getValue(this);
164         indents += getBlockContainerFO().getCommonMarginBlock()
165                     .spaceAfter.getOptimum(this).getLength().getValue(this);
166         */

167         indents += getBlockContainerFO().getCommonBorderPaddingBackground()
168                     .getBPPaddingAndBorder(false, this);
169         return indents;
170     }
171     
172     private boolean isAbsoluteOrFixed() {
173         return (abProps.absolutePosition == EN_ABSOLUTE)
174                 || (abProps.absolutePosition == EN_FIXED);
175     }
176
177     private boolean isFixed() {
178         return (abProps.absolutePosition == EN_FIXED);
179     }
180     
181     /** @see org.apache.fop.layoutmgr.LayoutManager#getContentAreaBPD() */
182     public int getContentAreaBPD() {
183         if (autoHeight) {
184             return -1;
185         } else {
186             return this.vpContentBPD;
187         }
188     }
189     
190     /** @see org.apache.fop.layoutmgr.LayoutManager */
191     public LinkedList JavaDoc getNextKnuthElements(LayoutContext context, int alignment) {
192         resetSpaces();
193         if (isAbsoluteOrFixed()) {
194             return getNextKnuthElementsAbsolute(context, alignment);
195         }
196         
197         autoHeight = false;
198         //boolean rotated = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
199
int maxbpd = context.getStackLimit().opt;
200         int allocBPD;
201         if (height.getEnum() == EN_AUTO
202                 || (!height.isAbsolute() && getAncestorBlockAreaBPD() <= 0)) {
203             //auto height when height="auto" or "if that dimension is not specified explicitly
204
//(i.e., it depends on content's blockprogression-dimension)" (XSL 1.0, 7.14.1)
205
allocBPD = maxbpd;
206             autoHeight = true;
207         } else {
208             allocBPD = height.getValue(this); //this is the content-height
209
allocBPD += getBPIndents();
210         }
211         vpContentBPD = allocBPD - getBPIndents();
212
213         referenceIPD = context.getRefIPD();
214         if (width.getEnum() == EN_AUTO) {
215             updateContentAreaIPDwithOverconstrainedAdjust();
216         } else {
217             int contentWidth = width.getValue(this);
218             updateContentAreaIPDwithOverconstrainedAdjust(contentWidth);
219         }
220         
221         double contentRectOffsetX = 0;
222         contentRectOffsetX += getBlockContainerFO()
223                 .getCommonMarginBlock().startIndent.getValue(this);
224         double contentRectOffsetY = 0;
225         contentRectOffsetY += getBlockContainerFO()
226                 .getCommonBorderPaddingBackground().getBorderBeforeWidth(false);
227         contentRectOffsetY += getBlockContainerFO()
228                 .getCommonBorderPaddingBackground().getPaddingBefore(false, this);
229         
230         Rectangle2D JavaDoc rect = new Rectangle2D.Double JavaDoc(
231                 contentRectOffsetX, contentRectOffsetY,
232                 getContentAreaIPD(), getContentAreaBPD());
233         relDims = new FODimension(0, 0);
234         absoluteCTM = CTM.getCTMandRelDims(getBlockContainerFO().getReferenceOrientation(),
235                 getBlockContainerFO().getWritingMode(), rect, relDims);
236
237         int availableIPD = referenceIPD - getIPIndents();
238         if (rect.getWidth() > availableIPD) {
239             log.warn(FONode.decorateWithContextInfo(
240                     "The extent in inline-progression-direction (width) of a block-container is"
241                     + " bigger than the available space ("
242                     + rect.getWidth() + "mpt > " + context.getRefIPD() + "mpt)",
243                     getBlockContainerFO()));
244         }
245         
246         MinOptMax stackLimit = new MinOptMax(relDims.bpd);
247
248         LinkedList JavaDoc returnedList = null;
249         LinkedList JavaDoc contentList = new LinkedList JavaDoc();
250         LinkedList JavaDoc returnList = new LinkedList JavaDoc();
251         
252         if (!breakBeforeServed) {
253             try {
254                 if (addKnuthElementsForBreakBefore(returnList, context)) {
255                     return returnList;
256                 }
257             } finally {
258                 breakBeforeServed = true;
259             }
260         }
261
262         if (!firstVisibleMarkServed) {
263             addKnuthElementsForSpaceBefore(returnList, alignment);
264         }
265         
266         addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
267         firstVisibleMarkServed = true;
268
269         if (autoHeight) {
270             //Spaces, border and padding to be repeated at each break
271
addPendingMarks(context);
272
273             BlockLevelLayoutManager curLM; // currently active LM
274
BlockLevelLayoutManager prevLM = null; // previously active LM
275
while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
276                 LayoutContext childLC = new LayoutContext(0);
277                 childLC.copyPendingMarksFrom(context);
278                 // curLM is a ?
279
childLC.setStackLimit(MinOptMax.subtract(context
280                         .getStackLimit(), stackLimit));
281                 childLC.setRefIPD(relDims.ipd);
282                 childLC.setWritingMode(getBlockContainerFO().getWritingMode());
283
284                 // get elements from curLM
285
returnedList = curLM.getNextKnuthElements(childLC, alignment);
286                 if (returnedList.size() == 1
287                         && ((ListElement)returnedList.getFirst()).isForcedBreak()) {
288                     // a descendant of this block has break-before
289
/*
290                     if (returnList.size() == 0) {
291                         // the first child (or its first child ...) has
292                         // break-before;
293                         // all this block, including space before, will be put in
294                         // the
295                         // following page
296                         bSpaceBeforeServed = false;
297                     }*/

298                     contentList.addAll(returnedList);
299
300                     // "wrap" the Position inside each element
301
// moving the elements from contentList to returnList
302
returnedList = new LinkedList JavaDoc();
303                     wrapPositionElements(contentList, returnList);
304
305                     return returnList;
306                 } else {
307                     if (prevLM != null) {
308                         // there is a block handled by prevLM
309
// before the one handled by curLM
310
if (mustKeepTogether()
311                                 || prevLM.mustKeepWithNext()
312                                 || curLM.mustKeepWithPrevious()) {
313                             // add an infinite penalty to forbid a break between
314
// blocks
315
contentList.add(new BreakElement(
316                                     new Position(this), KnuthElement.INFINITE, context));
317                         } else if (!((ListElement) contentList.getLast()).isGlue()) {
318                             // add a null penalty to allow a break between blocks
319
contentList.add(new BreakElement(
320                                     new Position(this), 0, context));
321                         } else {
322                             // the last element in contentList is a glue;
323
// it is a feasible breakpoint, there is no need to add
324
// a penalty
325
}
326                     }
327                     contentList.addAll(returnedList);
328                     if (returnedList.size() == 0) {
329                         //Avoid NoSuchElementException below (happens with empty blocks)
330
continue;
331                     }
332                     if (((ListElement)returnedList.getLast()).isForcedBreak()) {
333                         // a descendant of this block has break-after
334
if (curLM.isFinished()) {
335                             // there is no other content in this block;
336
// it's useless to add space after before a page break
337
setFinished(true);
338                         }
339
340                         returnedList = new LinkedList JavaDoc();
341                         wrapPositionElements(contentList, returnList);
342
343                         return returnList;
344                     }
345                 }
346                 prevLM = curLM;
347             }
348
349             returnedList = new LinkedList JavaDoc();
350             wrapPositionElements(contentList, returnList);
351
352         } else {
353             MinOptMax range = new MinOptMax(relDims.ipd);
354             BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
355             breaker.doLayout(relDims.bpd, autoHeight);
356             boolean contentOverflows = false;
357             if (!breaker.isEmpty()) {
358                 contentOverflows = (breaker.deferredAlg.getPageBreaks().size() > 1);
359             }
360
361             Position bcPosition = new BlockContainerPosition(this, breaker);
362             returnList.add(new KnuthBox(vpContentBPD, notifyPos(bcPosition), false));
363             //TODO Handle min/opt/max for block-progression-dimension
364
/* These two elements will be used to add stretchability to the above box
365             returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE,
366                                    false, returnPosition, false));
367             returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
368                                    LINE_NUMBER_ADJUSTMENT, returnPosition, false));
369             */

370
371             if (contentOverflows) {
372                 log.warn("Contents overflow block-container viewport: clipping");
373                 if (getBlockContainerFO().getOverflow() == EN_ERROR_IF_OVERFLOW) {
374                     //TODO Throw layout exception
375
}
376             }
377         }
378         addKnuthElementsForBorderPaddingAfter(returnList, true);
379         addKnuthElementsForSpaceAfter(returnList, alignment);
380         addKnuthElementsForBreakAfter(returnList, context);
381
382         setFinished(true);
383         return returnList;
384     }
385     
386     private LinkedList JavaDoc getNextKnuthElementsAbsolute(LayoutContext context, int alignment) {
387         autoHeight = false;
388
389         Point JavaDoc offset = getAbsOffset();
390         int allocBPD, allocIPD;
391         if (height.getEnum() == EN_AUTO
392                 || (!height.isAbsolute() && getAncestorBlockAreaBPD() <= 0)) {
393             //auto height when height="auto" or "if that dimension is not specified explicitly
394
//(i.e., it depends on content's blockprogression-dimension)" (XSL 1.0, 7.14.1)
395
allocBPD = 0;
396             if (abProps.bottom.getEnum() != EN_AUTO) {
397                 int availHeight;
398                 if (isFixed()) {
399                     availHeight = (int)getCurrentPV().getViewArea().getHeight();
400                 } else {
401                     availHeight = context.getStackLimit().opt;
402                 }
403                 allocBPD = availHeight;
404                 allocBPD -= offset.y;
405                 if (abProps.bottom.getEnum() != EN_AUTO) {
406                     allocBPD -= abProps.bottom.getValue(this);
407                     if (allocBPD < 0) {
408                         //TODO Fix absolute b-c layout, layout may need to be defferred until
409
//after page breaking when the size of the containing box is known.
410
/* Warning disabled due to a interpretation mistake.
411                          * See: http://marc.theaimsgroup.com/?l=fop-dev&m=113189981926163&w=2
412                         log.error("The current combination of top and bottom properties results"
413                                 + " in a negative extent for the block-container. 'bottom' may be"
414                                 + " at most " + (allocBPD + abProps.bottom.getValue(this)) + " mpt,"
415                                 + " but was actually " + abProps.bottom.getValue(this) + " mpt."
416                                 + " The nominal available height is " + availHeight + " mpt.");
417                         */

418                         allocBPD = 0;
419                     }
420                 } else {
421                     if (allocBPD < 0) {
422                         /* Warning disabled due to a interpretation mistake.
423                          * See: http://marc.theaimsgroup.com/?l=fop-dev&m=113189981926163&w=2
424                         log.error("The current combination of top and bottom properties results"
425                                 + " in a negative extent for the block-container. 'top' may be"
426                                 + " at most " + availHeight + " mpt,"
427                                 + " but was actually " + offset.y + " mpt."
428                                 + " The nominal available height is " + availHeight + " mpt.");
429                         */

430                         allocBPD = 0;
431                     }
432                 }
433             } else {
434                 autoHeight = true;
435             }
436         } else {
437             allocBPD = height.getValue(this); //this is the content-height
438
allocBPD += getBPIndents();
439         }
440         if (width.getEnum() == EN_AUTO) {
441             int availWidth;
442             if (isFixed()) {
443                 availWidth = (int)getCurrentPV().getViewArea().getWidth();
444             } else {
445                 availWidth = context.getRefIPD();
446             }
447             allocIPD = availWidth;
448             if (abProps.left.getEnum() != EN_AUTO) {
449                 allocIPD -= abProps.left.getValue(this);
450             }
451             if (abProps.right.getEnum() != EN_AUTO) {
452                 allocIPD -= abProps.right.getValue(this);
453                 if (allocIPD < 0) {
454                     /* Warning disabled due to a interpretation mistake.
455                      * See: http://marc.theaimsgroup.com/?l=fop-dev&m=113189981926163&w=2
456                     log.error("The current combination of left and right properties results"
457                             + " in a negative extent for the block-container. 'right' may be"
458                             + " at most " + (allocIPD + abProps.right.getValue(this)) + " mpt,"
459                             + " but was actually " + abProps.right.getValue(this) + " mpt."
460                             + " The nominal available width is " + availWidth + " mpt.");
461                     */

462                     allocIPD = 0;
463                 }
464             } else {
465                 if (allocIPD < 0) {
466                     /* Warning disabled due to a interpretation mistake.
467                      * See: http://marc.theaimsgroup.com/?l=fop-dev&m=113189981926163&w=2
468                     log.error("The current combination of left and right properties results"
469                             + " in a negative extent for the block-container. 'left' may be"
470                             + " at most " + allocIPD + " mpt,"
471                             + " but was actually " + abProps.left.getValue(this) + " mpt."
472                             + " The nominal available width is " + availWidth + " mpt.");
473                     */

474                     allocIPD = 0;
475                 }
476             }
477         } else {
478             allocIPD = width.getValue(this); //this is the content-width
479
allocIPD += getIPIndents();
480         }
481
482         vpContentBPD = allocBPD - getBPIndents();
483         setContentAreaIPD(allocIPD - getIPIndents());
484         
485         double contentRectOffsetX = offset.getX();
486         contentRectOffsetX += getBlockContainerFO()
487                 .getCommonMarginBlock().startIndent.getValue(this);
488         double contentRectOffsetY = offset.getY();
489         contentRectOffsetY += getSpaceBefore(); //TODO Uhm, is that necessary?
490
contentRectOffsetY += getBlockContainerFO()
491                 .getCommonBorderPaddingBackground().getBorderBeforeWidth(false);
492         contentRectOffsetY += getBlockContainerFO()
493                 .getCommonBorderPaddingBackground().getPaddingBefore(false, this);
494         
495         Rectangle2D JavaDoc rect = new Rectangle2D.Double JavaDoc(
496                 contentRectOffsetX, contentRectOffsetY,
497                 getContentAreaIPD(), vpContentBPD);
498         relDims = new FODimension(0, 0);
499         absoluteCTM = CTM.getCTMandRelDims(
500                 getBlockContainerFO().getReferenceOrientation(),
501                 getBlockContainerFO().getWritingMode(),
502                 rect, relDims);
503
504         MinOptMax range = new MinOptMax(relDims.ipd);
505         BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
506         breaker.doLayout(relDims.bpd, autoHeight);
507         boolean contentOverflows = breaker.isOverflow();
508         LinkedList JavaDoc returnList = new LinkedList JavaDoc();
509         if (!breaker.isEmpty()) {
510             Position bcPosition = new BlockContainerPosition(this, breaker);
511             returnList.add(new KnuthBox(0, notifyPos(bcPosition), false));
512     
513             //TODO Maybe check for page overflow when autoHeight=true
514
if (!autoHeight & (contentOverflows/*usedBPD > relDims.bpd*/)) {
515                 log.warn("Contents overflow block-container viewport: clipping");
516                 if (getBlockContainerFO().getOverflow() == EN_ERROR_IF_OVERFLOW) {
517                     //TODO Throw layout exception
518
}
519             }
520         }
521
522         setFinished(true);
523         return returnList;
524     }
525     
526     private class BlockContainerPosition extends NonLeafPosition {
527
528         private BlockContainerBreaker breaker;
529
530         public BlockContainerPosition(LayoutManager lm, BlockContainerBreaker breaker) {
531             super(lm, null);
532             this.breaker = breaker;
533         }
534         
535         public BlockContainerBreaker getBreaker() {
536             return this.breaker;
537         }
538         
539     }
540     
541     private class BlockContainerBreaker extends AbstractBreaker {
542         
543         private BlockContainerLayoutManager bclm;
544         private MinOptMax ipd;
545         
546         //Info for deferred adding of areas
547
private PageBreakingAlgorithm deferredAlg;
548         private BlockSequence deferredOriginalList;
549         private BlockSequence deferredEffectiveList;
550         
551         public BlockContainerBreaker(BlockContainerLayoutManager bclm, MinOptMax ipd) {
552             this.bclm = bclm;
553             this.ipd = ipd;
554         }
555
556         /** @see org.apache.fop.layoutmgr.AbstractBreaker#observeElementList(java.util.List) */
557         protected void observeElementList(List JavaDoc elementList) {
558             ElementListObserver.observe(elementList, "block-container",
559                     bclm.getBlockContainerFO().getId());
560         }
561         
562         /** @see org.apache.fop.layoutmgr.AbstractBreaker#isPartOverflowRecoveryActivated() */
563         protected boolean isPartOverflowRecoveryActivated() {
564             //For block-containers, this must be disabled because of wanted overflow.
565
return false;
566         }
567
568         /** @see org.apache.fop.layoutmgr.AbstractBreaker#isSinglePartFavored() */
569         protected boolean isSinglePartFavored() {
570             return true;
571         }
572
573         public int getDifferenceOfFirstPart() {
574             PageBreakPosition pbp = (PageBreakPosition)this.deferredAlg.getPageBreaks().getFirst();
575             return pbp.difference;
576         }
577         
578         public boolean isOverflow() {
579             if (isEmpty()) {
580                 return false;
581             } else {
582                 return (deferredAlg.getPageBreaks().size() > 1);
583             }
584         }
585         
586         protected LayoutManager getTopLevelLM() {
587             return bclm;
588         }
589
590         protected LayoutContext createLayoutContext() {
591             LayoutContext lc = super.createLayoutContext();
592             lc.setRefIPD(ipd.opt);
593             lc.setWritingMode(getBlockContainerFO().getWritingMode());
594             return lc;
595         }
596         
597         protected LinkedList JavaDoc getNextKnuthElements(LayoutContext context, int alignment) {
598             LayoutManager curLM; // currently active LM
599
LinkedList JavaDoc returnList = new LinkedList JavaDoc();
600
601             while ((curLM = getChildLM()) != null) {
602                 LayoutContext childLC = new LayoutContext(0);
603                 childLC.setStackLimit(context.getStackLimit());
604                 childLC.setRefIPD(context.getRefIPD());
605                 childLC.setWritingMode(getBlockContainerFO().getWritingMode());
606                 
607                 LinkedList JavaDoc returnedList = null;
608                 if (!curLM.isFinished()) {
609                     returnedList = curLM.getNextKnuthElements(childLC, alignment);
610                 }
611                 if (returnedList != null) {
612                     bclm.wrapPositionElements(returnedList, returnList);
613                 }
614             }
615             SpaceResolver.resolveElementList(returnList);
616             setFinished(true);
617             return returnList;
618         }
619
620         protected int getCurrentDisplayAlign() {
621             return getBlockContainerFO().getDisplayAlign();
622         }
623         
624         protected boolean hasMoreContent() {
625             return !isFinished();
626         }
627         
628         protected void addAreas(PositionIterator posIter, LayoutContext context) {
629             AreaAdditionUtil.addAreas(bclm, posIter, context);
630         }
631         
632         protected void doPhase3(PageBreakingAlgorithm alg, int partCount,
633                 BlockSequence originalList, BlockSequence effectiveList) {
634             //Defer adding of areas until addAreas is called by the parent LM
635
this.deferredAlg = alg;
636             this.deferredOriginalList = originalList;
637             this.deferredEffectiveList = effectiveList;
638         }
639         
640         protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
641             //nop for bclm
642
}
643         
644         protected LayoutManager getCurrentChildLM() {
645             return curChildLM;
646         }
647         
648         public void addContainedAreas() {
649             if (isEmpty()) {
650                 return;
651             }
652             //Rendering all parts (not just the first) at once for the case where the parts that
653
//overflow should be visible.
654
//TODO Check if this has any unwanted side-effects. Feels a bit like a hack.
655
this.addAreas(this.deferredAlg,
656                           /*1*/ this.deferredAlg.getPageBreaks().size(),
657                           this.deferredOriginalList, this.deferredEffectiveList);
658         }
659         
660     }
661     
662     private Point JavaDoc getAbsOffset() {
663         int x = 0;
664         int y = 0;
665         if (abProps.left.getEnum() != EN_AUTO) {
666             x = abProps.left.getValue(this);
667         }
668         if (abProps.top.getEnum() != EN_AUTO) {
669             y = abProps.top.getValue(this);
670         }
671         return new Point JavaDoc(x, y);
672     }
673     
674     /** @see org.apache.fop.layoutmgr.LayoutManager */
675     public void addAreas(PositionIterator parentIter,
676             LayoutContext layoutContext) {
677         getParentArea(null);
678
679         // if this will create the first block area in a page
680
// and display-align is bottom or center, add space before
681
if (layoutContext.getSpaceBefore() > 0) {
682             addBlockSpacing(0.0, new MinOptMax(layoutContext.getSpaceBefore()));
683         }
684
685         LayoutManager childLM = null;
686         LayoutManager lastLM = null;
687         LayoutContext lc = new LayoutContext(0);
688         lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
689         // set space after in the LayoutContext for children
690
if (layoutContext.getSpaceAfter() > 0) {
691             lc.setSpaceAfter(layoutContext.getSpaceAfter());
692         }
693         BlockContainerPosition bcpos = null;
694         PositionIterator childPosIter;
695
696         // "unwrap" the NonLeafPositions stored in parentIter
697
// and put them in a new list;
698
LinkedList JavaDoc positionList = new LinkedList JavaDoc();
699         Position pos;
700         boolean bSpaceBefore = false;
701         boolean bSpaceAfter = false;
702         Position firstPos = null;
703         Position lastPos = null;
704         while (parentIter.hasNext()) {
705             pos = (Position) parentIter.next();
706             if (pos.getIndex() >= 0) {
707                 if (firstPos == null) {
708                     firstPos = pos;
709                 }
710                 lastPos = pos;
711             }
712             Position innerPosition = pos;
713             if (pos instanceof NonLeafPosition) {
714                 innerPosition = ((NonLeafPosition)pos).getPosition();
715             }
716             if (pos instanceof BlockContainerPosition) {
717                 if (bcpos != null) {
718                     throw new IllegalStateException JavaDoc("Only one BlockContainerPosition allowed");
719                 }
720                 bcpos = (BlockContainerPosition)pos;
721                 //Add child areas inside the reference area
722
//bcpos.getBreaker().addContainedAreas();
723
} else if (innerPosition == null) {
724                 if (pos instanceof NonLeafPosition) {
725                     // pos was created by this BCLM and was inside an element
726
// representing space before or after
727
// this means the space was not discarded
728
if (positionList.size() == 0 && bcpos == null) {
729                         // pos was in the element representing space-before
730
bSpaceBefore = true;
731                     } else {
732                         // pos was in the element representing space-after
733
bSpaceAfter = true;
734                     }
735                 } else {
736                     //ignore (probably a Position for a simple penalty between blocks)
737
}
738             } else if (innerPosition.getLM() == this
739                     && !(innerPosition instanceof MappingPosition)) {
740                 // pos was created by this BlockLM and was inside a penalty
741
// allowing or forbidding a page break
742
// nothing to do
743
} else {
744                 // innerPosition was created by another LM
745
positionList.add(innerPosition);
746                 lastLM = innerPosition.getLM();
747             }
748         }
749
750         getPSLM().addIDToPage(getBlockContainerFO().getId());
751         if (markers != null) {
752             getCurrentPV().addMarkers(markers, true, isFirst(firstPos), isLast(lastPos));
753         }
754
755         if (bcpos == null) {
756             if (bpUnit == 0) {
757                 // the Positions in positionList were inside the elements
758
// created by the LineLM
759
childPosIter = new StackingIter(positionList.listIterator());
760             } else {
761                 // the Positions in positionList were inside the elements
762
// created by the BCLM in the createUnitElements() method
763
//if (((Position) positionList.getLast()) instanceof
764
// LeafPosition) {
765
// // the last item inside positionList is a LeafPosition
766
// // (a LineBreakPosition, more precisely); this means that
767
// // the whole paragraph is on the same page
768
// childPosIter = new KnuthPossPosIter(storedList, 0,
769
// storedList.size());
770
//} else {
771
// // the last item inside positionList is a Position;
772
// // this means that the paragraph has been split
773
// // between consecutive pages
774
LinkedList JavaDoc splitList = new LinkedList JavaDoc();
775                 int splitLength = 0;
776                 int iFirst = ((MappingPosition) positionList.getFirst()).getFirstIndex();
777                 int iLast = ((MappingPosition) positionList.getLast()).getLastIndex();
778                 // copy from storedList to splitList all the elements from
779
// iFirst to iLast
780
ListIterator JavaDoc storedListIterator = storedList.listIterator(iFirst);
781                 while (storedListIterator.nextIndex() <= iLast) {
782                     KnuthElement element = (KnuthElement) storedListIterator
783                             .next();
784                     // some elements in storedList (i.e. penalty items) were created
785
// by this BlockLM, and must be ignored
786
if (element.getLayoutManager() != this) {
787                         splitList.add(element);
788                         splitLength += element.getW();
789                         lastLM = element.getLayoutManager();
790                     }
791                 }
792                 //log.debug("Adding areas from " + iFirst + " to " + iLast);
793
//log.debug("splitLength= " + splitLength
794
// + " (" + neededUnits(splitLength) + " units') "
795
// + (neededUnits(splitLength) * bpUnit - splitLength)
796
// + " spacing");
797
// add space before and / or after the paragraph
798
// to reach a multiple of bpUnit
799
if (bSpaceBefore && bSpaceAfter) {
800                     foBlockSpaceBefore = new SpaceVal(getBlockContainerFO()
801                                 .getCommonMarginBlock().spaceBefore, this).getSpace();
802                     foBlockSpaceAfter = new SpaceVal(getBlockContainerFO()
803                                 .getCommonMarginBlock().spaceAfter, this).getSpace();
804                     adjustedSpaceBefore = (neededUnits(splitLength
805                             + foBlockSpaceBefore.min
806                             + foBlockSpaceAfter.min)
807                             * bpUnit - splitLength) / 2;
808                     adjustedSpaceAfter = neededUnits(splitLength
809                             + foBlockSpaceBefore.min
810                             + foBlockSpaceAfter.min)
811                             * bpUnit - splitLength - adjustedSpaceBefore;
812                 } else if (bSpaceBefore) {
813                     adjustedSpaceBefore = neededUnits(splitLength
814                             + foBlockSpaceBefore.min)
815                             * bpUnit - splitLength;
816                 } else {
817                     adjustedSpaceAfter = neededUnits(splitLength
818                             + foBlockSpaceAfter.min)
819                             * bpUnit - splitLength;
820                 }
821                 //log.debug("space before = " + adjustedSpaceBefore
822
// + " space after = " + adjustedSpaceAfter + " total = " +
823
// (adjustedSpaceBefore + adjustedSpaceAfter + splitLength));
824
childPosIter = new KnuthPossPosIter(splitList, 0, splitList
825                         .size());
826                 //}
827
}
828     
829             while ((childLM = childPosIter.getNextChildLM()) != null) {
830                 // set last area flag
831
lc.setFlags(LayoutContext.LAST_AREA,
832                         (layoutContext.isLastArea() && childLM == lastLM));
833                 /*LF*/lc.setStackLimit(layoutContext.getStackLimit());
834                 // Add the line areas to Area
835
childLM.addAreas(childPosIter, lc);
836             }
837         } else {
838             //Add child areas inside the reference area
839
bcpos.getBreaker().addContainedAreas();
840         }
841
842         if (markers != null) {
843             getCurrentPV().addMarkers(markers, false, isFirst(firstPos), isLast(lastPos));
844         }
845
846         TraitSetter.addSpaceBeforeAfter(viewportBlockArea, layoutContext.getSpaceAdjust(),
847                 effSpaceBefore, effSpaceAfter);
848         flush();
849
850         viewportBlockArea = null;
851         referenceArea = null;
852         resetSpaces();
853         
854         getPSLM().notifyEndOfLayout(((BlockContainer)getFObj()).getId());
855     }
856     
857     /**
858      * Get the parent area for children of this block container.
859      * This returns the current block container area
860      * and creates it if required.
861      *
862      * @see org.apache.fop.layoutmgr.LayoutManager#getParentArea(Area)
863      */

864     public Area getParentArea(Area childArea) {
865         if (referenceArea == null) {
866             viewportBlockArea = new BlockViewport();
867             viewportBlockArea.addTrait(Trait.IS_VIEWPORT_AREA, Boolean.TRUE);
868             viewportBlockArea.setIPD(getContentAreaIPD());
869             if (autoHeight) {
870                 viewportBlockArea.setBPD(0);
871             } else {
872                 viewportBlockArea.setBPD(getContentAreaBPD());
873             }
874
875             TraitSetter.setProducerID(viewportBlockArea, getBlockContainerFO().getId());
876             TraitSetter.addBorders(viewportBlockArea,
877                     getBlockContainerFO().getCommonBorderPaddingBackground(),
878                     discardBorderBefore, discardBorderAfter, false, false, this);
879             TraitSetter.addPadding(viewportBlockArea,
880                     getBlockContainerFO().getCommonBorderPaddingBackground(),
881                     discardPaddingBefore, discardPaddingAfter, false, false, this);
882             // TraitSetter.addBackground(viewportBlockArea,
883
// getBlockContainerFO().getCommonBorderPaddingBackground(),
884
// this);
885
TraitSetter.addMargins(viewportBlockArea,
886                     getBlockContainerFO().getCommonBorderPaddingBackground(),
887                     startIndent, endIndent,
888                     this);
889             
890             viewportBlockArea.setCTM(absoluteCTM);
891             viewportBlockArea.setClip(needClip());
892             /*
893             if (getSpaceBefore() != 0) {
894                 viewportBlockArea.addTrait(Trait.SPACE_BEFORE, new Integer(getSpaceBefore()));
895             }
896             if (foBlockSpaceAfter.opt != 0) {
897                 viewportBlockArea.addTrait(Trait.SPACE_AFTER, new Integer(foBlockSpaceAfter.opt));
898             }*/

899
900             if (abProps.absolutePosition == EN_ABSOLUTE
901                     || abProps.absolutePosition == EN_FIXED) {
902                 Point JavaDoc offset = getAbsOffset();
903                 viewportBlockArea.setXOffset(offset.x);
904                 viewportBlockArea.setYOffset(offset.y);
905             } else {
906                 //nop
907
}
908
909             referenceArea = new Block();
910             referenceArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
911             TraitSetter.setProducerID(referenceArea, getBlockContainerFO().getId());
912
913             if (abProps.absolutePosition == EN_ABSOLUTE) {
914                 viewportBlockArea.setPositioning(Block.ABSOLUTE);
915             } else if (abProps.absolutePosition == EN_FIXED) {
916                 viewportBlockArea.setPositioning(Block.FIXED);
917             }
918
919             // Set up dimensions
920
// Must get dimensions from parent area
921
/*Area parentArea =*/ parentLM.getParentArea(referenceArea);
922             //int referenceIPD = parentArea.getIPD();
923
referenceArea.setIPD(relDims.ipd);
924             // Get reference IPD from parentArea
925
setCurrentArea(viewportBlockArea); // ??? for generic operations
926
}
927         return referenceArea;
928     }
929
930     /**
931      * Add the child to the block container.
932      *
933      * @see org.apache.fop.layoutmgr.LayoutManager#addChildArea(Area)
934      */

935     public void addChildArea(Area childArea) {
936         if (referenceArea != null) {
937             referenceArea.addBlock((Block) childArea);
938         }
939     }
940
941     /**
942      * @see org.apache.fop.layoutmgr.LayoutManager#resetPosition(org.apache.fop.layoutmgr.Position)
943      */

944     public void resetPosition(Position resetPos) {
945         if (resetPos == null) {
946             reset(null);
947         }
948     }
949
950     /**
951      * Force current area to be added to parent area.
952      * @see org.apache.fop.layoutmgr.BlockStackingLayoutManager#flush()
953      */

954     protected void flush() {
955         viewportBlockArea.addBlock(referenceArea, autoHeight);
956
957         TraitSetter.addBackground(viewportBlockArea,
958                 getBlockContainerFO().getCommonBorderPaddingBackground(),
959                 this);
960         
961         // Fake a 0 height for absolute positioned blocks.
962
int saveBPD = viewportBlockArea.getBPD();
963         if (viewportBlockArea.getPositioning() == Block.ABSOLUTE) {
964             viewportBlockArea.setBPD(0);
965         }
966         super.flush();
967         // Restore the right height.
968
if (viewportBlockArea.getPositioning() == Block.ABSOLUTE) {
969             viewportBlockArea.setBPD(saveBPD);
970         }
971     }
972
973     /** @see org.apache.fop.layoutmgr.BlockLevelLayoutManager */
974     public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
975         // TODO Auto-generated method stub
976
return 0;
977     }
978
979     /** @see org.apache.fop.layoutmgr.BlockLevelLayoutManager */
980     public void discardSpace(KnuthGlue spaceGlue) {
981         // TODO Auto-generated method stub
982

983     }
984
985     /**
986      * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether()
987      */

988     public boolean mustKeepTogether() {
989         //TODO Keeps will have to be more sophisticated sooner or later
990
return ((BlockLevelLayoutManager)getParent()).mustKeepTogether()
991                 || !getBlockContainerFO().getKeepTogether().getWithinPage().isAuto()
992                 || !getBlockContainerFO().getKeepTogether().getWithinColumn().isAuto();
993     }
994
995     /**
996      * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious()
997      */

998     public boolean mustKeepWithPrevious() {
999         return !getBlockContainerFO().getKeepWithPrevious().getWithinPage().isAuto()
1000                || !getBlockContainerFO().getKeepWithPrevious().getWithinColumn().isAuto();
1001    }
1002
1003    /**
1004     * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext()
1005     */

1006    public boolean mustKeepWithNext() {
1007        return !getBlockContainerFO().getKeepWithNext().getWithinPage().isAuto()
1008                || !getBlockContainerFO().getKeepWithNext().getWithinColumn().isAuto();
1009    }
1010
1011    /**
1012     * @return the BlockContainer node
1013     */

1014    protected BlockContainer getBlockContainerFO() {
1015        return (BlockContainer) fobj;
1016    }
1017
1018    // --------- Property Resolution related functions --------- //
1019

1020    /**
1021     * @see org.apache.fop.layoutmgr.LayoutManager#getGeneratesReferenceArea
1022     */

1023    public boolean getGeneratesReferenceArea() {
1024        return true;
1025    }
1026   
1027    /**
1028     * @see org.apache.fop.layoutmgr.LayoutManager#getGeneratesBlockArea
1029     */

1030    public boolean getGeneratesBlockArea() {
1031        return true;
1032    }
1033
1034    /** @see org.apache.fop.layoutmgr.ConditionalElementListener */
1035    public void notifySpace(RelSide side, MinOptMax effectiveLength) {
1036        if (RelSide.BEFORE == side) {
1037            if (log.isDebugEnabled()) {
1038                log.debug(this + ": Space " + side + ", "
1039                        + this.effSpaceBefore + "-> " + effectiveLength);
1040            }
1041            this.effSpaceBefore = effectiveLength;
1042        } else {
1043            if (log.isDebugEnabled()) {
1044                log.debug(this + ": Space " + side + ", "
1045                        + this.effSpaceAfter + "-> " + effectiveLength);
1046            }
1047            this.effSpaceAfter = effectiveLength;
1048        }
1049    }
1050
1051    /** @see org.apache.fop.layoutmgr.ConditionalElementListener */
1052    public void notifyBorder(RelSide side, MinOptMax effectiveLength) {
1053        if (effectiveLength == null) {
1054            if (RelSide.BEFORE == side) {
1055                this.discardBorderBefore = true;
1056            } else {
1057                this.discardBorderAfter = true;
1058            }
1059        }
1060        if (log.isDebugEnabled()) {
1061            log.debug(this + ": Border " + side + " -> " + effectiveLength);
1062        }
1063    }
1064
1065    /** @see org.apache.fop.layoutmgr.ConditionalElementListener */
1066    public void notifyPadding(RelSide side, MinOptMax effectiveLength) {
1067        if (effectiveLength == null) {
1068            if (RelSide.BEFORE == side) {
1069                this.discardPaddingBefore = true;
1070            } else {
1071                this.discardPaddingAfter = true;
1072            }
1073        }
1074        if (log.isDebugEnabled()) {
1075            log.debug(this + ": Padding " + side + " -> " + effectiveLength);
1076        }
1077    }
1078
1079}
1080
1081
Popular Tags