1 17 18 19 20 package org.apache.fop.layoutmgr; 21 22 import java.util.Iterator ; 23 import java.util.LinkedList ; 24 import java.util.List ; 25 import java.util.ListIterator ; 26 27 import org.apache.commons.logging.Log; 28 import org.apache.commons.logging.LogFactory; 29 import org.apache.fop.area.Area; 30 import org.apache.fop.area.BlockParent; 31 import org.apache.fop.area.Block; 32 import org.apache.fop.fo.FObj; 33 import org.apache.fop.fo.properties.CommonBorderPaddingBackground; 34 import org.apache.fop.fo.properties.SpaceProperty; 35 import org.apache.fop.layoutmgr.inline.InlineLayoutManager; 36 import org.apache.fop.layoutmgr.inline.LineLayoutManager; 37 import org.apache.fop.traits.MinOptMax; 38 39 43 public abstract class BlockStackingLayoutManager extends AbstractLayoutManager 44 implements BlockLevelLayoutManager { 45 46 49 private static Log log = LogFactory.getLog(BlockStackingLayoutManager.class); 50 51 55 protected BlockParent parentArea = null; 57 58 59 protected int bpUnit = 0; 60 61 protected int adjustedSpaceBefore = 0; 62 63 protected int adjustedSpaceAfter = 0; 64 65 protected LinkedList storedList = null; 66 67 protected boolean breakBeforeServed = false; 68 69 protected boolean firstVisibleMarkServed = false; 70 71 protected int referenceIPD = 0; 72 73 protected int startIndent = 0; 74 75 protected int endIndent = 0; 76 85 protected MinOptMax foSpaceBefore = null; 86 87 protected MinOptMax foSpaceAfter = null; 88 89 private Position auxiliaryPosition; 90 91 private int contentAreaIPD = 0; 92 93 96 public BlockStackingLayoutManager(FObj node) { 97 super(node); 98 setGeneratesBlockArea(true); 99 } 100 101 104 protected BlockParent getCurrentArea() { 105 return this.parentArea; 106 } 107 108 109 113 protected void setCurrentArea(BlockParent parentArea) { 114 this.parentArea = parentArea; 115 } 116 117 124 public void addBlockSpacing(double adjust, MinOptMax minoptmax) { 125 int sp = TraitSetter.getEffectiveSpace(adjust, minoptmax); 126 if (sp != 0) { 127 Block spacer = new Block(); 128 spacer.setBPD(sp); 129 parentLM.addChildArea(spacer); 130 } 131 } 132 133 142 protected void addChildToArea(Area childArea, 143 BlockParent parentArea) { 144 if (!(childArea instanceof Block)) { 146 } 148 149 parentArea.addBlock((Block) childArea); 150 flush(); } 152 153 154 162 public void addChildArea(Area childArea) { 163 addChildToArea(childArea, getCurrentArea()); 164 } 165 166 169 protected void flush() { 170 if (getCurrentArea() != null) { 171 parentLM.addChildArea(getCurrentArea()); 172 } 173 } 174 175 176 protected Position getAuxiliaryPosition() { 177 if (this.auxiliaryPosition == null) { 178 this.auxiliaryPosition = new NonLeafPosition(this, null); 179 } 180 return this.auxiliaryPosition; 181 } 182 183 187 protected int neededUnits(int len) { 188 return (int) Math.ceil((float)len / bpUnit); 189 } 190 191 197 protected int updateContentAreaIPDwithOverconstrainedAdjust() { 198 int ipd = referenceIPD - (startIndent + endIndent); 199 if (ipd < 0) { 200 log.debug("Adjusting end-indent based on overconstrained geometry rules for " + fobj); 202 endIndent += ipd; 203 ipd = 0; 204 } 206 setContentAreaIPD(ipd); 207 return ipd; 208 } 209 210 215 protected int updateContentAreaIPDwithOverconstrainedAdjust(int contentIPD) { 216 int ipd = referenceIPD - (contentIPD + (startIndent + endIndent)); 217 if (ipd < 0) { 218 log.debug("Adjusting end-indent based on overconstrained geometry rules for " + fobj); 220 endIndent += ipd; 221 } 222 setContentAreaIPD(contentIPD); 223 return contentIPD; 224 } 225 226 229 public LinkedList getNextKnuthElements(LayoutContext context, int alignment) { 230 BlockLevelLayoutManager curLM; BlockLevelLayoutManager prevLM = null; 239 referenceIPD = context.getRefIPD(); 240 241 updateContentAreaIPDwithOverconstrainedAdjust(); 242 243 LinkedList returnedList = null; 244 LinkedList contentList = new LinkedList (); 245 LinkedList returnList = new LinkedList (); 246 247 if (!breakBeforeServed) { 248 try { 249 if (addKnuthElementsForBreakBefore(returnList, context)) { 250 return returnList; 251 } 252 } finally { 253 breakBeforeServed = true; 254 } 255 } 256 257 if (!firstVisibleMarkServed) { 258 addKnuthElementsForSpaceBefore(returnList, alignment); 259 } 260 261 addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed); 262 firstVisibleMarkServed = true; 263 264 addPendingMarks(context); 266 267 while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) { 268 LayoutContext childLC = new LayoutContext(0); 269 childLC.copyPendingMarksFrom(context); 270 if (curLM instanceof LineLayoutManager) { 271 childLC.setStackLimit(new MinOptMax(getContentAreaIPD())); 274 childLC.setRefIPD(getContentAreaIPD()); 275 } else { 276 childLC.setStackLimit(context.getStackLimit()); 280 childLC.setRefIPD(referenceIPD); 281 } 282 283 returnedList = curLM.getNextKnuthElements(childLC, alignment); 285 if (contentList.size() == 0 && childLC.isKeepWithPreviousPending()) { 286 context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); 287 childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false); 288 } 289 if (returnedList != null 290 && returnedList.size() == 1 291 && ((ListElement) returnedList.getFirst()).isForcedBreak()) { 292 302 contentList.addAll(returnedList); 303 304 305 if (bpUnit > 0) { 306 storedList = contentList; 307 contentList = createUnitElements(contentList); 308 } 309 310 311 returnedList = new LinkedList (); 314 wrapPositionElements(contentList, returnList); 315 316 return returnList; 317 } else { 318 if (prevLM != null) { 319 if (mustKeepTogether() 322 || context.isKeepWithNextPending() 323 || childLC.isKeepWithPreviousPending()) { 324 context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false); 326 contentList.add(new BreakElement( 329 new Position(this), KnuthElement.INFINITE, context)); 330 } else if (!((ListElement) contentList.getLast()).isGlue()) { 331 contentList.add(new BreakElement( 333 new Position(this), 0, context)); 334 } else { 335 log.warn("glue-type break possibility not handled properly, yet"); 339 } 342 } 343 if (returnedList == null || returnedList.size() == 0) { 344 continue; 346 } 347 contentList.addAll(returnedList); 348 if (((ListElement) returnedList.getLast()).isForcedBreak()) { 349 351 352 if (bpUnit > 0) { 353 storedList = contentList; 354 contentList = createUnitElements(contentList); 355 } 356 357 358 returnedList = new LinkedList (); 359 wrapPositionElements(contentList, returnList); 360 361 return returnList; 362 } 363 } 364 context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, childLC.isKeepWithNextPending()); 366 childLC.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false); 367 childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false); 368 prevLM = curLM; 369 } 370 371 372 if (bpUnit > 0) { 373 storedList = contentList; 374 contentList = createUnitElements(contentList); 375 } 376 377 378 returnedList = new LinkedList (); 379 if (contentList.size() > 0) { 380 wrapPositionElements(contentList, returnList); 381 } else { 382 returnList.add(new KnuthBox(0, notifyPos(new Position(this)), true)); 384 } 385 386 addKnuthElementsForBorderPaddingAfter(returnList, true); 387 addKnuthElementsForSpaceAfter(returnList, alignment); 388 addKnuthElementsForBreakAfter(returnList, context); 389 390 if (mustKeepWithNext()) { 391 context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING); 392 } 393 if (mustKeepWithPrevious()) { 394 context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); 395 } 396 397 setFinished(true); 398 399 return returnList; 400 } 401 402 405 public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) { 406 Position innerPosition = ((NonLeafPosition) lastElement.getPosition()).getPosition(); 412 413 if (innerPosition == null && lastElement.isGlue()) { 414 if (((KnuthGlue) lastElement).getAdjustmentClass() == SPACE_BEFORE_ADJUSTMENT) { 416 adjustedSpaceBefore += adj; 418 } else { 420 adjustedSpaceAfter += adj; 422 } 424 return adj; 425 } else if (innerPosition instanceof MappingPosition) { 426 MappingPosition mappingPos = (MappingPosition)innerPosition; 430 if (lastElement.isGlue()) { 431 ListIterator storedListIterator = storedList.listIterator( 434 mappingPos.getFirstIndex()); 435 int newAdjustment = 0; 436 while (storedListIterator.nextIndex() <= mappingPos.getLastIndex()) { 437 KnuthElement storedElement = (KnuthElement)storedListIterator.next(); 438 if (storedElement.isGlue()) { 439 newAdjustment += ((BlockLevelLayoutManager)storedElement 440 .getLayoutManager()).negotiateBPDAdjustment( 441 adj - newAdjustment, storedElement); 442 } 445 } 446 newAdjustment = (newAdjustment > 0 ? bpUnit * neededUnits(newAdjustment) 447 : -bpUnit * neededUnits(-newAdjustment)); 448 return newAdjustment; 449 } else { 450 KnuthPenalty storedPenalty = (KnuthPenalty) 455 storedList.get(mappingPos.getLastIndex()); 456 if (storedPenalty.getW() > 0) { 457 return ((BlockLevelLayoutManager)storedPenalty.getLayoutManager()) 460 .negotiateBPDAdjustment(storedPenalty.getW(), 461 (KnuthElement)storedPenalty); 462 } else { 463 return adj; 467 } 468 } 469 } else if (innerPosition.getLM() != this) { 470 NonLeafPosition savedPos = (NonLeafPosition) lastElement.getPosition(); 472 lastElement.setPosition(innerPosition); 473 int returnValue = ((BlockLevelLayoutManager)lastElement.getLayoutManager()) 474 .negotiateBPDAdjustment(adj, lastElement); 475 lastElement.setPosition(savedPos); 476 return returnValue; 478 } else { 479 log.error("BlockLayoutManager.negotiateBPDAdjustment(): unexpected Position"); 481 return 0; 482 } 483 } 484 485 488 public void discardSpace(KnuthGlue spaceGlue) { 489 Position innerPosition = ((NonLeafPosition) spaceGlue.getPosition()).getPosition(); 491 492 if (innerPosition == null || innerPosition.getLM() == this) { 493 if (spaceGlue.getAdjustmentClass() == SPACE_BEFORE_ADJUSTMENT) { 497 adjustedSpaceBefore = 0; 499 foSpaceBefore = new MinOptMax(0); 500 } else { 501 adjustedSpaceAfter = 0; 503 foSpaceAfter = new MinOptMax(0); 504 } 506 } else { 507 NonLeafPosition savedPos = (NonLeafPosition)spaceGlue.getPosition(); 509 spaceGlue.setPosition(innerPosition); 510 ((BlockLevelLayoutManager) spaceGlue.getLayoutManager()).discardSpace(spaceGlue); 511 spaceGlue.setPosition(savedPos); 512 } 513 } 514 515 518 public LinkedList getChangedKnuthElements(List oldList, int alignment) { 519 ListIterator oldListIterator = oldList.listIterator(); 523 KnuthElement returnedElement; 524 KnuthElement currElement = null; 525 KnuthElement prevElement = null; 526 LinkedList returnedList = new LinkedList (); 527 LinkedList returnList = new LinkedList (); 528 int fromIndex = 0; 529 530 KnuthElement oldElement = null; 532 while (oldListIterator.hasNext()) { 533 oldElement = (KnuthElement)oldListIterator.next(); 534 Position innerPosition = ((NonLeafPosition) oldElement.getPosition()).getPosition(); 535 if (innerPosition != null) { 541 oldElement.setPosition(innerPosition); 543 } else { 544 oldElement.setPosition(new Position(this)); 548 } 549 } 550 551 List workList; 553 if (bpUnit == 0) { 554 workList = oldList; 555 } else { 556 oldListIterator = oldList.listIterator(); 560 KnuthElement el = (KnuthElement) oldListIterator.next(); 561 while (!(el.getPosition() instanceof MappingPosition)) { 562 el = (KnuthElement) oldListIterator.next(); 563 } 564 int iFirst = ((MappingPosition) el.getPosition()).getFirstIndex(); 565 566 oldListIterator = oldList.listIterator(oldList.size()); 569 el = (KnuthElement) oldListIterator.previous(); 570 while (!(el.getPosition() instanceof MappingPosition)) { 571 el = (KnuthElement) oldListIterator.previous(); 572 } 573 int iLast = ((MappingPosition) el.getPosition()).getLastIndex(); 574 575 workList = storedList.subList(iFirst, iLast + 1); 578 } 579 ListIterator workListIterator = workList.listIterator(); 580 581 584 while (workListIterator.hasNext()) { 585 currElement = (KnuthElement) workListIterator.next(); 586 if (prevElement != null 589 && prevElement.getLayoutManager() != currElement.getLayoutManager()) { 590 BlockLevelLayoutManager prevLM = (BlockLevelLayoutManager) 592 prevElement.getLayoutManager(); 593 BlockLevelLayoutManager currLM = (BlockLevelLayoutManager) 594 currElement.getLayoutManager(); 595 boolean bSomethingAdded = false; 596 if (prevLM != this) { 597 returnedList.addAll(prevLM.getChangedKnuthElements(workList.subList( 601 fromIndex, workListIterator.previousIndex()), alignment)); 602 bSomethingAdded = true; 603 } else { 604 } 610 fromIndex = workListIterator.previousIndex(); 611 612 616 if (bSomethingAdded 618 && (this.mustKeepTogether() 619 || prevLM.mustKeepWithNext() 620 || currLM.mustKeepWithPrevious())) { 621 returnedList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, 623 new Position(this), false)); 624 } else if (bSomethingAdded && !((KnuthElement) returnedList.getLast()).isGlue()) { 625 returnedList.add(new KnuthPenalty(0, 0, false, new Position(this), false)); 627 } 628 } 629 prevElement = currElement; 630 } 631 if (currElement != null) { 632 BlockLevelLayoutManager currLM = (BlockLevelLayoutManager) 633 currElement.getLayoutManager(); 634 if (currLM != this) { 635 returnedList.addAll(currLM.getChangedKnuthElements( 638 workList.subList(fromIndex, workList.size()), alignment)); 639 } else { 640 if (returnedList.size() > 0) { 644 returnedList.removeLast(); 645 } 646 } 649 } 650 651 boolean spaceBeforeIsConditional = true; 653 if (fobj instanceof org.apache.fop.fo.flow.Block) { 654 spaceBeforeIsConditional = ((org.apache.fop.fo.flow.Block)fobj) 655 .getCommonMarginBlock().spaceBefore.getSpace().isDiscard(); 656 } 657 if (bpUnit > 0 658 || adjustedSpaceBefore != 0) { 659 if (!spaceBeforeIsConditional) { 660 returnList.add(new KnuthBox(0, 662 new NonLeafPosition(this, null), false)); 663 returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, 664 new NonLeafPosition(this, null), false)); 665 } 666 if (bpUnit > 0) { 667 returnList.add(new KnuthGlue(0, 0, 0, 668 SPACE_BEFORE_ADJUSTMENT, new NonLeafPosition(this, null), true)); 669 } else { 670 returnList.add(new KnuthGlue(adjustedSpaceBefore, 0, 0, 671 SPACE_BEFORE_ADJUSTMENT, new NonLeafPosition(this, null), true)); 672 } 673 } 674 675 678 679 if (bpUnit > 0) { 680 storedList = returnedList; 681 returnedList = createUnitElements(returnedList); 682 } 683 684 685 ListIterator listIter = returnedList.listIterator(); 688 while (listIter.hasNext()) { 689 returnedElement = (KnuthElement)listIter.next(); 690 returnedElement.setPosition(new NonLeafPosition(this, returnedElement.getPosition())); 691 returnList.add(returnedElement); 692 } 693 694 boolean spaceAfterIsConditional = true; 696 if (fobj instanceof org.apache.fop.fo.flow.Block) { 697 spaceAfterIsConditional = ((org.apache.fop.fo.flow.Block)fobj) 698 .getCommonMarginBlock().spaceAfter.getSpace().isDiscard(); 699 } 700 if (bpUnit > 0 || adjustedSpaceAfter != 0) { 701 if (!spaceAfterIsConditional) { 702 returnList.add(new KnuthPenalty(0, 703 KnuthElement.INFINITE, false, 704 new NonLeafPosition(this, null), false)); 705 } 706 if (bpUnit > 0) { 707 returnList.add(new KnuthGlue(0, 0, 0, 708 SPACE_AFTER_ADJUSTMENT, 709 new NonLeafPosition(this, null), 710 (!spaceAfterIsConditional) ? false : true)); 711 } else { 712 returnList.add(new KnuthGlue(adjustedSpaceAfter, 0, 0, 713 SPACE_AFTER_ADJUSTMENT, 714 new NonLeafPosition(this, null), 715 (!spaceAfterIsConditional) ? false : true)); 716 } 717 if (!spaceAfterIsConditional) { 718 returnList.add(new KnuthBox(0, 719 new NonLeafPosition(this, null), true)); 720 } 721 } 722 723 return returnList; 726 } 727 728 731 public boolean mustKeepTogether() { 733 return ((getParent() instanceof BlockLevelLayoutManager 734 && ((BlockLevelLayoutManager) getParent()).mustKeepTogether()) 735 || (getParent() instanceof InlineLayoutManager 736 && ((InlineLayoutManager) getParent()).mustKeepTogether())); 737 } 738 739 742 public boolean mustKeepWithPrevious() { 743 return false; 744 } 745 746 749 public boolean mustKeepWithNext() { 750 return false; 751 } 752 753 758 protected void addPendingMarks(LayoutContext context) { 759 CommonBorderPaddingBackground borderAndPadding = getBorderPaddingBackground(); 760 if (borderAndPadding != null) { 761 if (borderAndPadding.getBorderBeforeWidth(false) > 0) { 762 context.addPendingBeforeMark(new BorderElement( 763 getAuxiliaryPosition(), 764 borderAndPadding.getBorderInfo( 765 CommonBorderPaddingBackground.BEFORE).getWidth(), 766 RelSide.BEFORE, 767 false, false, this)); 768 } 769 if (borderAndPadding.getPaddingBefore(false, this) > 0) { 770 context.addPendingBeforeMark(new PaddingElement( 771 getAuxiliaryPosition(), 772 borderAndPadding.getPaddingLengthProperty( 773 CommonBorderPaddingBackground.BEFORE), 774 RelSide.BEFORE, 775 false, false, this)); 776 } 777 if (borderAndPadding.getBorderAfterWidth(false) > 0) { 778 context.addPendingAfterMark(new BorderElement( 779 getAuxiliaryPosition(), 780 borderAndPadding.getBorderInfo( 781 CommonBorderPaddingBackground.AFTER).getWidth(), 782 RelSide.AFTER, 783 false, false, this)); 784 } 785 if (borderAndPadding.getPaddingAfter(false, this) > 0) { 786 context.addPendingAfterMark(new PaddingElement( 787 getAuxiliaryPosition(), 788 borderAndPadding.getPaddingLengthProperty( 789 CommonBorderPaddingBackground.AFTER), 790 RelSide.AFTER, 791 false, false, this)); 792 } 793 } 794 } 795 796 797 private CommonBorderPaddingBackground getBorderPaddingBackground() { 798 if (fobj instanceof org.apache.fop.fo.flow.Block) { 799 return ((org.apache.fop.fo.flow.Block)fobj) 800 .getCommonBorderPaddingBackground(); 801 } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { 802 return ((org.apache.fop.fo.flow.BlockContainer)fobj) 803 .getCommonBorderPaddingBackground(); 804 } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) { 805 return ((org.apache.fop.fo.flow.ListBlock)fobj) 806 .getCommonBorderPaddingBackground(); 807 } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) { 808 return ((org.apache.fop.fo.flow.ListItem)fobj) 809 .getCommonBorderPaddingBackground(); 810 } else if (fobj instanceof org.apache.fop.fo.flow.Table) { 811 return ((org.apache.fop.fo.flow.Table)fobj) 812 .getCommonBorderPaddingBackground(); 813 } else { 814 return null; 815 } 816 } 817 818 819 private SpaceProperty getSpaceBeforeProperty() { 820 if (fobj instanceof org.apache.fop.fo.flow.Block) { 821 return ((org.apache.fop.fo.flow.Block)fobj) 822 .getCommonMarginBlock().spaceBefore; 823 } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { 824 return ((org.apache.fop.fo.flow.BlockContainer)fobj) 825 .getCommonMarginBlock().spaceBefore; 826 } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) { 827 return ((org.apache.fop.fo.flow.ListBlock)fobj) 828 .getCommonMarginBlock().spaceBefore; 829 } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) { 830 return ((org.apache.fop.fo.flow.ListItem)fobj) 831 .getCommonMarginBlock().spaceBefore; 832 } else if (fobj instanceof org.apache.fop.fo.flow.Table) { 833 return ((org.apache.fop.fo.flow.Table)fobj) 834 .getCommonMarginBlock().spaceBefore; 835 } else { 836 return null; 837 } 838 } 839 840 841 private SpaceProperty getSpaceAfterProperty() { 842 if (fobj instanceof org.apache.fop.fo.flow.Block) { 843 return ((org.apache.fop.fo.flow.Block)fobj) 844 .getCommonMarginBlock().spaceAfter; 845 } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { 846 return ((org.apache.fop.fo.flow.BlockContainer)fobj) 847 .getCommonMarginBlock().spaceAfter; 848 } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) { 849 return ((org.apache.fop.fo.flow.ListBlock)fobj) 850 .getCommonMarginBlock().spaceAfter; 851 } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) { 852 return ((org.apache.fop.fo.flow.ListItem)fobj) 853 .getCommonMarginBlock().spaceAfter; 854 } else if (fobj instanceof org.apache.fop.fo.flow.Table) { 855 return ((org.apache.fop.fo.flow.Table)fobj) 856 .getCommonMarginBlock().spaceAfter; 857 } else { 858 return null; 859 } 860 } 861 862 868 protected void addKnuthElementsForBorderPaddingBefore(LinkedList returnList, boolean isFirst) { 869 CommonBorderPaddingBackground borderAndPadding = getBorderPaddingBackground(); 871 if (borderAndPadding != null) { 872 if (borderAndPadding.getBorderBeforeWidth(false) > 0) { 873 returnList.add(new BorderElement( 874 getAuxiliaryPosition(), 875 borderAndPadding.getBorderInfo(CommonBorderPaddingBackground.BEFORE) 876 .getWidth(), 877 RelSide.BEFORE, isFirst, false, this)); 878 } 879 if (borderAndPadding.getPaddingBefore(false, this) > 0) { 880 returnList.add(new PaddingElement( 881 getAuxiliaryPosition(), 882 borderAndPadding.getPaddingLengthProperty( 883 CommonBorderPaddingBackground.BEFORE), 884 RelSide.BEFORE, isFirst, false, this)); 885 } 886 } 887 } 888 889 895 protected void addKnuthElementsForBorderPaddingAfter(LinkedList returnList, boolean isLast) { 896 CommonBorderPaddingBackground borderAndPadding = getBorderPaddingBackground(); 898 if (borderAndPadding != null) { 899 if (borderAndPadding.getPaddingAfter(false, this) > 0) { 900 returnList.add(new PaddingElement( 901 getAuxiliaryPosition(), 902 borderAndPadding.getPaddingLengthProperty( 903 CommonBorderPaddingBackground.AFTER), 904 RelSide.AFTER, false, isLast, this)); 905 } 906 if (borderAndPadding.getBorderAfterWidth(false) > 0) { 907 returnList.add(new BorderElement( 908 getAuxiliaryPosition(), 909 borderAndPadding.getBorderInfo(CommonBorderPaddingBackground.AFTER) 910 .getWidth(), 911 RelSide.AFTER, false, isLast, this)); 912 } 913 } 914 } 915 916 922 protected boolean addKnuthElementsForBreakBefore(LinkedList returnList, 923 LayoutContext context) { 924 int breakBefore = -1; 925 if (fobj instanceof org.apache.fop.fo.flow.Block) { 926 breakBefore = ((org.apache.fop.fo.flow.Block) fobj).getBreakBefore(); 927 } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { 928 breakBefore = ((org.apache.fop.fo.flow.BlockContainer) fobj).getBreakBefore(); 929 } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) { 930 breakBefore = ((org.apache.fop.fo.flow.ListBlock) fobj).getBreakBefore(); 931 } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) { 932 breakBefore = ((org.apache.fop.fo.flow.ListItem) fobj).getBreakBefore(); 933 } else if (fobj instanceof org.apache.fop.fo.flow.Table) { 934 breakBefore = ((org.apache.fop.fo.flow.Table) fobj).getBreakBefore(); 935 } 936 if (breakBefore == EN_PAGE 937 || breakBefore == EN_COLUMN 938 || breakBefore == EN_EVEN_PAGE 939 || breakBefore == EN_ODD_PAGE) { 940 returnList.add(new BreakElement(getAuxiliaryPosition(), 942 0, -KnuthElement.INFINITE, breakBefore, context)); 943 return true; 944 } else { 945 return false; 946 } 947 } 948 949 955 protected boolean addKnuthElementsForBreakAfter(LinkedList returnList, 956 LayoutContext context) { 957 int breakAfter = -1; 958 if (fobj instanceof org.apache.fop.fo.flow.Block) { 959 breakAfter = ((org.apache.fop.fo.flow.Block) fobj).getBreakAfter(); 960 } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { 961 breakAfter = ((org.apache.fop.fo.flow.BlockContainer) fobj).getBreakAfter(); 962 } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) { 963 breakAfter = ((org.apache.fop.fo.flow.ListBlock) fobj).getBreakAfter(); 964 } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) { 965 breakAfter = ((org.apache.fop.fo.flow.ListItem) fobj).getBreakAfter(); 966 } else if (fobj instanceof org.apache.fop.fo.flow.Table) { 967 breakAfter = ((org.apache.fop.fo.flow.Table) fobj).getBreakAfter(); 968 } 969 if (breakAfter == EN_PAGE 970 || breakAfter == EN_COLUMN 971 || breakAfter == EN_EVEN_PAGE 972 || breakAfter == EN_ODD_PAGE) { 973 returnList.add(new BreakElement(getAuxiliaryPosition(), 975 0, -KnuthElement.INFINITE, breakAfter, context)); 976 return true; 977 } else { 978 return false; 979 } 980 } 981 982 987 protected void addKnuthElementsForSpaceBefore(LinkedList returnList, int alignment) { 989 SpaceProperty spaceBefore = getSpaceBeforeProperty(); 990 if (spaceBefore != null 992 && !(spaceBefore.getMinimum(this).getLength().getValue(this) == 0 993 && spaceBefore.getMaximum(this).getLength().getValue(this) == 0)) { 994 returnList.add(new SpaceElement(getAuxiliaryPosition(), spaceBefore, 995 RelSide.BEFORE, 996 true, false, this)); 997 } 998 1029 } 1030 1031 1036 protected void addKnuthElementsForSpaceAfter(LinkedList returnList, 1037 int alignment) { 1038 SpaceProperty spaceAfter = getSpaceAfterProperty(); 1039 if (spaceAfter != null 1041 && !(spaceAfter.getMinimum(this).getLength().getValue(this) == 0 1042 && spaceAfter.getMaximum(this).getLength().getValue(this) == 0)) { 1043 returnList.add(new SpaceElement(getAuxiliaryPosition(), spaceAfter, 1044 RelSide.AFTER, 1045 false, true, this)); 1046 } 1047 1079 } 1080 1081 protected LinkedList createUnitElements(LinkedList oldList) { 1082 LayoutManager lm = ((KnuthElement)oldList.getFirst()).getLayoutManager(); 1088 boolean bAddedBoxBefore = false; 1089 boolean bAddedBoxAfter = false; 1090 if (adjustedSpaceBefore > 0) { 1091 oldList.addFirst(new KnuthBox(adjustedSpaceBefore, 1092 new Position(lm), true)); 1093 bAddedBoxBefore = true; 1094 } 1095 if (adjustedSpaceAfter > 0) { 1096 oldList.addLast(new KnuthBox(adjustedSpaceAfter, 1097 new Position(lm), true)); 1098 bAddedBoxAfter = true; 1099 } 1100 1101 MinOptMax totalLength = new MinOptMax(0); 1102 MinOptMax totalUnits = new MinOptMax(0); 1103 LinkedList newList = new LinkedList (); 1104 1105 ListIterator oldListIterator = oldList.listIterator(); 1108 while (oldListIterator.hasNext()) { 1109 KnuthElement element = (KnuthElement) oldListIterator.next(); 1110 if (element.isBox()) { 1111 totalLength.add(new MinOptMax(element.getW())); 1112 } else if (element.isGlue()) { 1114 totalLength.min -= ((KnuthGlue) element).getZ(); 1115 totalLength.max += ((KnuthGlue) element).getY(); 1116 } else { 1120 } 1123 } 1124 totalUnits = new MinOptMax(neededUnits(totalLength.min), 1126 neededUnits(totalLength.opt), 1127 neededUnits(totalLength.max)); 1128 1131 oldListIterator = oldList.listIterator(); 1136 boolean bPrevIsBox = false; 1137 MinOptMax lengthBeforeBreak = new MinOptMax(0); 1138 MinOptMax lengthAfterBreak = (MinOptMax) totalLength.clone(); 1139 MinOptMax unitsBeforeBreak; 1140 MinOptMax unitsAfterBreak; 1141 MinOptMax unsuppressibleUnits = new MinOptMax(0); 1142 int firstIndex = 0; 1143 int lastIndex = -1; 1144 while (oldListIterator.hasNext()) { 1145 KnuthElement element = (KnuthElement) oldListIterator.next(); 1146 lastIndex++; 1147 if (element.isBox()) { 1148 lengthBeforeBreak.add(new MinOptMax(element.getW())); 1149 lengthAfterBreak.subtract(new MinOptMax(element.getW())); 1150 bPrevIsBox = true; 1151 } else if (element.isGlue()) { 1152 lengthBeforeBreak.min -= ((KnuthGlue) element).getZ(); 1153 lengthAfterBreak.min += ((KnuthGlue) element).getZ(); 1154 lengthBeforeBreak.max += ((KnuthGlue) element).getY(); 1155 lengthAfterBreak.max -= ((KnuthGlue) element).getY(); 1156 bPrevIsBox = false; 1157 } else { 1158 lengthBeforeBreak.add(new MinOptMax(element.getW())); 1159 bPrevIsBox = false; 1160 } 1161 1162 if (element.isPenalty() && ((KnuthPenalty) element).getP() < KnuthElement.INFINITE 1164 || element.isGlue() && bPrevIsBox 1165 || !oldListIterator.hasNext()) { 1166 int iStepsForward = 0; 1168 while (oldListIterator.hasNext()) { 1169 KnuthElement el = (KnuthElement) oldListIterator.next(); 1170 iStepsForward++; 1171 if (el.isGlue()) { 1172 lengthAfterBreak.min += ((KnuthGlue) el).getZ(); 1174 lengthAfterBreak.max -= ((KnuthGlue) el).getY(); 1175 } else if (el.isPenalty()) { 1176 } else { 1178 break; 1180 } 1181 } 1182 unitsBeforeBreak = new MinOptMax(neededUnits(lengthBeforeBreak.min), 1184 neededUnits(lengthBeforeBreak.opt), 1185 neededUnits(lengthBeforeBreak.max)); 1186 unitsAfterBreak = new MinOptMax(neededUnits(lengthAfterBreak.min), 1187 neededUnits(lengthAfterBreak.opt), 1188 neededUnits(lengthAfterBreak.max)); 1189 1190 for (int i = 0; i < iStepsForward; i++) { 1192 KnuthElement el = (KnuthElement) oldListIterator.previous(); 1193 if (el.isGlue()) { 1194 lengthAfterBreak.min -= ((KnuthGlue) el).getZ(); 1195 lengthAfterBreak.max += ((KnuthGlue) el).getY(); 1196 } 1197 } 1198 1199 int uLengthChange = unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt; 1201 int uStretchChange = (unitsBeforeBreak.max + unitsAfterBreak.max - totalUnits.max) 1202 - (unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt); 1203 int uShrinkChange = (unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt) 1204 - (unitsBeforeBreak.min + unitsAfterBreak.min - totalUnits.min); 1205 1206 int uNewNormal = unitsBeforeBreak.opt - unsuppressibleUnits.opt; 1209 int uNewStretch = (unitsBeforeBreak.max - unitsBeforeBreak.opt) 1210 - (unsuppressibleUnits.max - unsuppressibleUnits.opt); 1211 int uNewShrink = (unitsBeforeBreak.opt - unitsBeforeBreak.min) 1212 - (unsuppressibleUnits.opt - unsuppressibleUnits.min); 1213 1214 1225 int firstIndexCorrection = 0; 1228 int lastIndexCorrection = 0; 1229 if (bAddedBoxBefore) { 1230 if (firstIndex != 0) { 1231 firstIndexCorrection++; 1232 } 1233 lastIndexCorrection++; 1234 } 1235 if (bAddedBoxAfter && lastIndex == (oldList.size() - 1)) { 1236 lastIndexCorrection++; 1237 } 1238 MappingPosition mappingPos = new MappingPosition(this, 1239 firstIndex - firstIndexCorrection, 1240 lastIndex - lastIndexCorrection); 1241 1242 newList.add(new KnuthBox((uNewNormal - uLengthChange) * bpUnit, 1244 mappingPos, 1245 false)); 1246 unsuppressibleUnits.add(new MinOptMax(uNewNormal - uLengthChange)); 1247 1249 if (uNewStretch - uStretchChange > 0 1251 || uNewShrink - uShrinkChange > 0) { 1252 int iStretchUnits = (uNewStretch - uStretchChange > 0 1253 ? (uNewStretch - uStretchChange) : 0); 1254 int iShrinkUnits = (uNewShrink - uShrinkChange > 0 1255 ? (uNewShrink - uShrinkChange) : 0); 1256 newList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, 1257 mappingPos, 1258 false)); 1259 newList.add(new KnuthGlue(0, 1260 iStretchUnits * bpUnit, 1261 iShrinkUnits * bpUnit, 1262 LINE_NUMBER_ADJUSTMENT, 1263 mappingPos, 1264 false)); 1265 unsuppressibleUnits.max += iStretchUnits; 1268 unsuppressibleUnits.min -= iShrinkUnits; 1269 if (!oldListIterator.hasNext()) { 1270 newList.add(new KnuthBox(0, 1271 mappingPos, 1272 false)); 1273 } 1275 } 1276 1277 if (uStretchChange != 0 1279 || uShrinkChange != 0) { 1280 newList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, 1282 mappingPos, 1283 false)); 1284 newList.add(new KnuthGlue(0, 1285 uStretchChange * bpUnit, 1286 uShrinkChange * bpUnit, 1287 LINE_NUMBER_ADJUSTMENT, 1288 mappingPos, 1289 false)); 1290 newList.add(new KnuthPenalty(uLengthChange * bpUnit, 1291 0, false, element.getPosition(), false)); 1292 newList.add(new KnuthGlue(0, 1293 -uStretchChange * bpUnit, 1294 -uShrinkChange * bpUnit, 1295 LINE_NUMBER_ADJUSTMENT, 1296 mappingPos, 1297 false)); 1298 } else if (oldListIterator.hasNext()) { 1304 newList.add(new KnuthPenalty(uLengthChange * bpUnit, 1306 0, false, 1307 mappingPos, 1308 false)); 1309 } 1311 firstIndex = lastIndex + 1; 1313 } 1314 1315 if (element.isPenalty()) { 1316 lengthBeforeBreak.add(new MinOptMax(-element.getW())); 1317 } 1318 1319 } 1320 1321 if (adjustedSpaceBefore > 0) { 1324 oldList.removeFirst(); 1325 } 1326 if (adjustedSpaceAfter > 0) { 1327 oldList.removeLast(); 1328 } 1329 1330 boolean correctFirstElement = false; 1332 if (fobj instanceof org.apache.fop.fo.flow.Block) { 1333 correctFirstElement = ((org.apache.fop.fo.flow.Block)fobj) 1334 .getCommonMarginBlock().spaceBefore.getSpace().isDiscard(); 1335 } 1336 if (correctFirstElement) { 1337 KnuthBox wrongBox = (KnuthBox) newList.removeFirst(); 1339 int decreasedLength = (neededUnits(totalLength.opt) 1342 - neededUnits(totalLength.opt - adjustedSpaceBefore)) 1343 * bpUnit; 1344 newList.addFirst(new KnuthBox(wrongBox.getW() - decreasedLength, 1346 wrongBox.getPosition(), false)); 1347 newList.addFirst(new KnuthGlue(decreasedLength, 0, 0, SPACE_BEFORE_ADJUSTMENT, 1348 wrongBox.getPosition(), false)); 1349 } 1354 1355 boolean correctLastElement = false; 1357 if (fobj instanceof org.apache.fop.fo.flow.Block) { 1358 correctLastElement = ((org.apache.fop.fo.flow.Block)fobj) 1359 .getCommonMarginBlock().spaceAfter.getSpace().isDiscard(); 1360 } 1361 if (correctLastElement) { 1362 KnuthBox wrongBox = (KnuthBox) newList.removeLast(); 1364 LinkedList preserveList = new LinkedList (); 1368 if (wrongBox.getW() == 0) { 1369 preserveList.add(wrongBox); 1370 preserveList.addFirst((KnuthGlue) newList.removeLast()); 1371 preserveList.addFirst((KnuthPenalty) newList.removeLast()); 1372 wrongBox = (KnuthBox) newList.removeLast(); 1373 } 1374 1375 int decreasedLength = (neededUnits(totalLength.opt) 1378 - neededUnits(totalLength.opt - adjustedSpaceAfter)) 1379 * bpUnit; 1380 newList.addLast(new KnuthBox(wrongBox.getW() - decreasedLength, 1382 wrongBox.getPosition(), false)); 1383 if (preserveList.size() > 0) { 1385 newList.addAll(preserveList); 1386 } 1387 newList.addLast(new KnuthGlue(decreasedLength, 0, 0, SPACE_AFTER_ADJUSTMENT, 1389 wrongBox.getPosition(), false)); 1390 } 1395 1396 return newList; 1397 } 1398 1399 protected static class StackingIter extends PositionIterator { 1400 StackingIter(Iterator parentIter) { 1401 super(parentIter); 1402 } 1403 1404 protected LayoutManager getLM(Object nextObj) { 1405 return ((Position) nextObj).getLM(); 1406 } 1407 1408 protected Position getPos(Object nextObj) { 1409 return ((Position) nextObj); 1410 } 1411 } 1412 1413 protected static class MappingPosition extends Position { 1414 private int iFirstIndex; 1415 private int iLastIndex; 1416 1417 public MappingPosition(LayoutManager lm, int first, int last) { 1418 super(lm); 1419 iFirstIndex = first; 1420 iLastIndex = last; 1421 } 1422 1423 public int getFirstIndex() { 1424 return iFirstIndex; 1425 } 1426 1427 public int getLastIndex() { 1428 return iLastIndex; 1429 } 1430 } 1431 1432 1438 protected void wrapPositionElements(List sourceList, List targetList) { 1439 wrapPositionElements(sourceList, targetList, false); 1440 } 1441 1442 1449 protected void wrapPositionElements(List sourceList, List targetList, boolean force) { 1450 1451 ListIterator listIter = sourceList.listIterator(); 1452 while (listIter.hasNext()) { 1453 ListElement tempElement; 1454 tempElement = (ListElement) listIter.next(); 1455 if (force || tempElement.getLayoutManager() != this) { 1456 tempElement.setPosition(notifyPos(new NonLeafPosition(this, 1457 tempElement.getPosition()))); 1458 } 1459 targetList.add(tempElement); 1460 } 1461 } 1462 1463 1464 protected int getIPIndents() { 1465 return startIndent + endIndent; 1466 } 1467 1468 1472 public int getContentAreaIPD() { 1473 return contentAreaIPD; 1474 } 1475 1476 1480 protected void setContentAreaIPD(int contentAreaIPD) { 1481 this.contentAreaIPD = contentAreaIPD; 1482 } 1483 1484 1488 public int getContentAreaBPD() { 1489 return -1; 1490 } 1491 1492} 1493 1494 | Popular Tags |