You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BlockStackingLayoutManager.java 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * $Id$
  3. * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
  4. * For details on use and redistribution please refer to the
  5. * LICENSE file included with these sources.
  6. */
  7. package org.apache.fop.layoutmgr;
  8. import org.apache.fop.fo.FObj;
  9. import org.apache.fop.area.Area;
  10. import org.apache.fop.area.BlockParent;
  11. import org.apache.fop.area.Block;
  12. import org.apache.fop.area.MinOptMax;
  13. import java.util.Iterator;
  14. /**
  15. * Base LayoutManager class for all areas which stack their child
  16. * areas in the block-progression direction, such as Flow, Block, ListBlock.
  17. */
  18. public abstract class BlockStackingLayoutManager extends AbstractLayoutManager {
  19. /** Reference to FO whose areas it's managing or to the traits
  20. * of the FO.
  21. */
  22. LayoutManager curChildLM = null;
  23. BlockParent parentArea = null;
  24. public BlockStackingLayoutManager(FObj fobj) {
  25. super(fobj);
  26. }
  27. public boolean splitArea(Area area, SplitContext splitContext) {
  28. // Divide area so that it will be within targetLength if possible
  29. // If not, it can be shorter, but not longer.
  30. /* Iterate over contents of the area. *
  31. // Need to figure out if we can do this generically
  32. // Logically a BlockStacking LM only handles Block-type areas
  33. if (!(area instanceof BlockParent)) {
  34. return false;
  35. }
  36. Iterator areaIter = ((BlockParent) area).getChildAreas().iterator();
  37. BreakCost minBreakCost = null;
  38. MinOptMax remainBPD = splitContext.targetBPD;
  39. splitContext.nextArea = area;
  40. while (areaIter.hasNext()) {
  41. Area childArea = (Area) areaIter.next();
  42. if (remainBPD.max < childArea.getAllocationBPD().min) {
  43. // Past the end point: try to break it
  44. // TODO: get a LayoutManager to do the split of the child
  45. // area, either Area => LM or Area => gen FO => LM
  46. LayoutManager childLM =
  47. childArea.getGeneratingFObj(). getLayoutManager();
  48. splitContext.targetBPD = remainBPD;
  49. if (childLM.splitArea(childArea, splitContext) == false) {
  50. // Can't split, so must split this area before childArea
  51. // Can we pass the iter?
  52. // If already saw several a potential break, use it
  53. if (minBreakCost != null) {
  54. /* Split 'area', placing all children after
  55. * minBreakCost.getArea() into a new area,
  56. * which we store in the splitContext.
  57. *
  58. // splitContext.nextArea = area.splitAfter(minBreakCost.getArea());
  59. } else {
  60. /* This area will be shorter than the desired minimum.
  61. * Split before the current childArea (which will be
  62. * the first area in the newly created Area.
  63. *
  64. //splitContext.nextArea = area.splitBefore(childArea);
  65. }
  66. } else
  67. return true; // childLM has done the work for us!
  68. // Set cost, dimension ???
  69. break;
  70. } else {
  71. remainBPD.subtract(childArea.getAllocationBPD());
  72. if (remainBPD.min < 0) {
  73. // Potential breakpoint: remember break Position and
  74. // break "cost" (constraint violation)
  75. BreakCost breakCost =
  76. evaluateBreakCost(area, childArea);
  77. minBreakCost = breakCost.chooseLowest(minBreakCost);
  78. }
  79. }
  80. //Note: size of area when split can depend on conditional
  81. // space, border and padding of the split area!!!
  82. }
  83. // True if some part of area can be placed, false if none is placed
  84. return (splitContext.nextArea != area);
  85. */
  86. return false;
  87. }
  88. private BreakCost evaluateBreakCost(Area parent, Area child) {
  89. return new BreakCost(child, 0);
  90. }
  91. /** return current area being filled
  92. */
  93. protected BlockParent getCurrentArea() {
  94. return this.parentArea;
  95. }
  96. /**
  97. * Set the current area being filled.
  98. */
  99. protected void setCurrentArea(BlockParent parentArea) {
  100. this.parentArea = parentArea;
  101. }
  102. protected MinOptMax resolveSpaceSpecifier(Area nextArea) {
  103. SpaceSpecifier spaceSpec = new SpaceSpecifier(false);
  104. // Area prevArea = getCurrentArea().getLast();
  105. // if (prevArea != null) {
  106. // spaceSpec.addSpace(prevArea.getSpaceAfter());
  107. // }
  108. // spaceSpec.addSpace(nextArea.getSpaceBefore());
  109. return spaceSpec.resolve(false);
  110. }
  111. /**
  112. * Add the childArea to the passed area.
  113. * Called by child LayoutManager when it has filled one of its areas.
  114. * The LM should already have an Area in which to put the child.
  115. * See if the area will fit in the current area.
  116. * If so, add it. Otherwise initiate breaking.
  117. * @param childArea the area to add: will be some block-stacked Area.
  118. * @param parentArea the area in which to add the childArea
  119. */
  120. protected boolean addChildToArea(Area childArea, BlockParent parentArea) {
  121. // This should be a block-level Area (Block in the generic sense)
  122. if (!(childArea instanceof Block)) {
  123. System.err.println("Child not a Block in BlockStackingLM!");
  124. return false;
  125. }
  126. // See if the whole thing fits, including space before
  127. // Calculate space between last child in curFlow and childArea
  128. MinOptMax targetDim = parentArea.getAvailBPD();
  129. MinOptMax spaceBefore = resolveSpaceSpecifier(childArea);
  130. targetDim.subtract(spaceBefore);
  131. if (targetDim.max >= childArea.getAllocationBPD().min) {
  132. //parentArea.addBlock(new InterBlockSpace(spaceBefore));
  133. parentArea.addBlock((Block) childArea);
  134. return false;
  135. } else {
  136. parentArea.addBlock((Block) childArea);
  137. flush(); // hand off current area to parent
  138. // Probably need something like max BPD so we don't get into
  139. // infinite loops with large unbreakable chunks
  140. //SplitContext splitContext = new SplitContext(targetDim);
  141. /*LayoutManager childLM =
  142. childArea.getGeneratingFObj(). getLayoutManager();
  143. if (childLM.splitArea(childArea, splitContext)) {
  144. //parentArea.addBlock(new InterBlockSpace(spaceBefore));
  145. parentArea.addBlock((Block) childArea);
  146. }*/
  147. //flush(); // hand off current area to parent
  148. //getParentArea(splitContext.nextArea);
  149. //getParentArea(childArea);
  150. // Check that reference IPD hasn't changed!!!
  151. // If it has, we must "reflow" the content
  152. //addChild(splitContext.nextArea);
  153. //addChild(childArea);
  154. return true;
  155. }
  156. }
  157. /**
  158. * Add the childArea to the current area.
  159. * Called by child LayoutManager when it has filled one of its areas.
  160. * The LM should already have an Area in which to put the child.
  161. * See if the area will fit in the current area.
  162. * If so, add it. Otherwise initiate breaking.
  163. * @param childArea the area to add: will be some block-stacked Area.
  164. */
  165. public boolean addChild(Area childArea) {
  166. return addChildToArea(childArea, getCurrentArea());
  167. }
  168. /**
  169. * Force current area to be added to parent area.
  170. */
  171. protected boolean flush() {
  172. if (getCurrentArea() != null)
  173. return parentLM.addChild(getCurrentArea());
  174. return false;
  175. }
  176. }