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.

BlockLayoutManager.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.layoutmgr;
  18. import java.util.ListIterator;
  19. import java.util.ArrayList;
  20. import java.util.List;
  21. import org.apache.fop.datatypes.PercentBase;
  22. import org.apache.fop.fo.FObj;
  23. import org.apache.fop.fo.TextInfo;
  24. import org.apache.fop.fo.PropertyManager;
  25. import org.apache.fop.area.Area;
  26. import org.apache.fop.area.Block;
  27. import org.apache.fop.area.LineArea;
  28. import org.apache.fop.traits.LayoutProps;
  29. import org.apache.fop.fo.properties.CommonBorderAndPadding;
  30. import org.apache.fop.fo.properties.CommonBackground;
  31. import org.apache.fop.fo.properties.CommonMarginBlock;
  32. import org.apache.fop.traits.MinOptMax;
  33. /**
  34. * LayoutManager for a block FO.
  35. */
  36. public class BlockLayoutManager extends BlockStackingLayoutManager {
  37. private Block curBlockArea;
  38. private LayoutProps layoutProps;
  39. private CommonBorderAndPadding borderProps;
  40. private CommonBackground backgroundProps;
  41. private CommonMarginBlock marginProps;
  42. /* holds the (one-time use) fo:block space-before
  43. and -after properties. Large fo:blocks are split
  44. into multiple Area.Blocks to accomodate the subsequent
  45. regions (pages) they are placed on. space-before
  46. is applied at the beginning of the first
  47. Block and space-after at the end of the last Block
  48. used in rendering the fo:block.
  49. */
  50. private MinOptMax foBlockSpaceBefore = null;
  51. // need to retain foBlockSpaceAfter from previous instantiation
  52. private static MinOptMax foBlockSpaceAfter = null;
  53. private MinOptMax prevFoBlockSpaceAfter = null;
  54. private int lead = 12000;
  55. private int lineHeight = 14000;
  56. private int follow = 2000;
  57. private int iStartPos = 0;
  58. protected List childBreaks = new java.util.ArrayList();
  59. /**
  60. * Iterator for Block layout.
  61. * This iterator combines consecutive inline areas and
  62. * creates a line layout manager.
  63. * The use of this iterator means that it can be reset properly.
  64. */
  65. protected class BlockLMiter extends LMiter {
  66. private ListIterator proxy;
  67. public BlockLMiter(LayoutProcessor lp, ListIterator pr) {
  68. super(lp, null);
  69. proxy = pr;
  70. }
  71. protected boolean preLoadNext() {
  72. while (proxy.hasNext()) {
  73. LayoutProcessor lm = (LayoutProcessor) proxy.next();
  74. lm.setParent(BlockLayoutManager.this);
  75. if (lm.generatesInlineAreas()) {
  76. LineLayoutManager lineLM = createLineManager(lm);
  77. listLMs.add(lineLM);
  78. } else {
  79. listLMs.add(lm);
  80. }
  81. if (curPos < listLMs.size()) {
  82. return true;
  83. }
  84. }
  85. return false;
  86. }
  87. protected LineLayoutManager createLineManager(
  88. LayoutManager firstlm) {
  89. LayoutProcessor lm;
  90. List inlines = new ArrayList();
  91. inlines.add(firstlm);
  92. while (proxy.hasNext()) {
  93. lm = (LayoutProcessor) proxy.next();
  94. lm.setParent(BlockLayoutManager.this);
  95. if (lm.generatesInlineAreas()) {
  96. inlines.add(lm);
  97. } else {
  98. proxy.previous();
  99. break;
  100. }
  101. }
  102. LineLayoutManager child;
  103. child = new LineLayoutManager(lineHeight,
  104. lead, follow);
  105. child.setUserAgent(getUserAgent());
  106. child.setFObj(fobj);
  107. child.setLMiter(inlines.listIterator());
  108. return child;
  109. }
  110. }
  111. public BlockLayoutManager() {
  112. }
  113. /**
  114. * Set the FO object for this layout manager
  115. *
  116. * @param fo the fo for this layout manager
  117. */
  118. public void setFObj(FObj fo) {
  119. super.setFObj(fo);
  120. childLMiter = new BlockLMiter(this, childLMiter);
  121. }
  122. public void setBlockTextInfo(TextInfo ti) {
  123. lead = ti.fs.getAscender();
  124. follow = -ti.fs.getDescender();
  125. lineHeight = ti.lineHeight;
  126. }
  127. /**
  128. * This method provides a hook for a LayoutManager to intialize traits
  129. * for the areas it will create, based on Properties set on its FO.
  130. */
  131. protected void initProperties(PropertyManager pm) {
  132. layoutProps = pm.getLayoutProps();
  133. borderProps = pm.getBorderAndPadding();
  134. backgroundProps = pm.getBackgroundProps();
  135. marginProps = pm.getMarginProps();
  136. foBlockSpaceBefore = layoutProps.spaceBefore.getSpace();
  137. prevFoBlockSpaceAfter = foBlockSpaceAfter;
  138. }
  139. public BreakPoss getNextBreakPoss(LayoutContext context) {
  140. LayoutProcessor curLM; // currently active LM
  141. int ipd = context.getRefIPD();
  142. int iIndents = marginProps.startIndent + marginProps.endIndent;
  143. int bIndents = borderProps.getBPPaddingAndBorder(false);
  144. ipd -= iIndents;
  145. MinOptMax stackSize = new MinOptMax();
  146. if (prevFoBlockSpaceAfter != null) {
  147. stackSize.add(prevFoBlockSpaceAfter);
  148. prevFoBlockSpaceAfter = null;
  149. }
  150. if (foBlockSpaceBefore != null) {
  151. // this function called before addAreas(), so
  152. // resetting foBlockSpaceBefore = null in addAreas()
  153. stackSize.add(foBlockSpaceBefore);
  154. }
  155. BreakPoss lastPos = null;
  156. // Set context for percentage property values.
  157. fobj.setLayoutDimension(PercentBase.BLOCK_IPD, ipd);
  158. fobj.setLayoutDimension(PercentBase.BLOCK_BPD, -1);
  159. while ((curLM = getChildLM()) != null) {
  160. // Make break positions and return blocks!
  161. // Set up a LayoutContext
  162. BreakPoss bp;
  163. LayoutContext childLC = new LayoutContext(0);
  164. // if line layout manager then set stack limit to ipd
  165. // line LM actually generates a LineArea which is a block
  166. if (curLM.generatesInlineAreas()) {
  167. // set stackLimit for lines
  168. childLC.setStackLimit(new MinOptMax(ipd/* - iIndents - iTextIndent*/));
  169. childLC.setRefIPD(ipd);
  170. } else {
  171. childLC.setStackLimit(
  172. MinOptMax.subtract(context.getStackLimit(),
  173. stackSize));
  174. childLC.setRefIPD(ipd);
  175. }
  176. boolean over = false;
  177. while (!curLM.isFinished()) {
  178. if ((bp = curLM.getNextBreakPoss(childLC)) != null) {
  179. if (stackSize.opt + bp.getStackingSize().opt > context.getStackLimit().max) {
  180. // reset to last break
  181. if (lastPos != null) {
  182. LayoutProcessor lm = lastPos.getLayoutManager();
  183. lm.resetPosition(lastPos.getPosition());
  184. if (lm != curLM) {
  185. curLM.resetPosition(null);
  186. }
  187. } else {
  188. curLM.resetPosition(null);
  189. }
  190. over = true;
  191. break;
  192. }
  193. stackSize.add(bp.getStackingSize());
  194. lastPos = bp;
  195. childBreaks.add(bp);
  196. if (bp.nextBreakOverflows()) {
  197. over = true;
  198. break;
  199. }
  200. if (curLM.generatesInlineAreas()) {
  201. // Reset stackLimit for non-first lines
  202. childLC.setStackLimit(new MinOptMax(ipd/* - iIndents*/));
  203. } else {
  204. childLC.setStackLimit(MinOptMax.subtract(
  205. context.getStackLimit(), stackSize));
  206. }
  207. }
  208. }
  209. if (getChildLM() == null || over) {
  210. if (getChildLM() == null) {
  211. setFinished(true);
  212. stackSize.add(layoutProps.spaceAfter.getSpace());
  213. }
  214. BreakPoss breakPoss = new BreakPoss(
  215. new LeafPosition(this, childBreaks.size() - 1));
  216. if (over) {
  217. breakPoss.setFlag(BreakPoss.NEXT_OVERFLOWS, true);
  218. }
  219. breakPoss.setStackingSize(stackSize);
  220. return breakPoss;
  221. }
  222. }
  223. setFinished(true);
  224. BreakPoss breakPoss = new BreakPoss(new LeafPosition(this, -2));
  225. breakPoss.setStackingSize(stackSize);
  226. return breakPoss;
  227. }
  228. public void addAreas(PositionIterator parentIter,
  229. LayoutContext layoutContext) {
  230. getParentArea(null);
  231. // if adjusted space before
  232. double adjust = layoutContext.getSpaceAdjust();
  233. addBlockSpacing(adjust, foBlockSpaceBefore);
  234. foBlockSpaceBefore = null;
  235. addID();
  236. addMarkers(true, true);
  237. LayoutProcessor childLM;
  238. LayoutContext lc = new LayoutContext(0);
  239. while (parentIter.hasNext()) {
  240. LeafPosition lfp = (LeafPosition) parentIter.next();
  241. if (lfp.getLeafPos() == -2) {
  242. curBlockArea = null;
  243. flush();
  244. return;
  245. }
  246. // Add the block areas to Area
  247. PositionIterator breakPosIter =
  248. new BreakPossPosIter(childBreaks, iStartPos,
  249. lfp.getLeafPos() + 1);
  250. iStartPos = lfp.getLeafPos() + 1;
  251. while ((childLM = breakPosIter.getNextChildLM()) != null) {
  252. childLM.addAreas(breakPosIter, lc);
  253. }
  254. }
  255. int bIndents = borderProps.getBPPaddingAndBorder(false);
  256. curBlockArea.setHeight(curBlockArea.getHeight() + bIndents);
  257. addMarkers(false, true);
  258. flush();
  259. // if adjusted space after
  260. foBlockSpaceAfter = layoutProps.spaceAfter.getSpace();
  261. addBlockSpacing(adjust, foBlockSpaceAfter);
  262. curBlockArea = null;
  263. }
  264. /**
  265. * Return an Area which can contain the passed childArea. The childArea
  266. * may not yet have any content, but it has essential traits set.
  267. * In general, if the LayoutManager already has an Area it simply returns
  268. * it. Otherwise, it makes a new Area of the appropriate class.
  269. * It gets a parent area for its area by calling its parent LM.
  270. * Finally, based on the dimensions of the parent area, it initializes
  271. * its own area. This includes setting the content IPD and the maximum
  272. * BPD.
  273. */
  274. public Area getParentArea(Area childArea) {
  275. if (curBlockArea == null) {
  276. curBlockArea = new Block();
  277. // set traits
  278. TraitSetter.addBorders(curBlockArea, borderProps);
  279. TraitSetter.addBackground(curBlockArea, backgroundProps);
  280. TraitSetter.addMargins(curBlockArea, borderProps, marginProps);
  281. // Set up dimensions
  282. // Must get dimensions from parent area
  283. Area parentArea = parentLM.getParentArea(curBlockArea);
  284. int referenceIPD = parentArea.getIPD();
  285. curBlockArea.setIPD(referenceIPD);
  286. curBlockArea.setWidth(referenceIPD);
  287. // Get reference IPD from parentArea
  288. setCurrentArea(curBlockArea); // ??? for generic operations
  289. }
  290. return curBlockArea;
  291. }
  292. public void addChild(Area childArea) {
  293. if (curBlockArea != null) {
  294. if (childArea instanceof LineArea) {
  295. curBlockArea.addLineArea((LineArea) childArea);
  296. } else {
  297. curBlockArea.addBlock((Block) childArea);
  298. }
  299. }
  300. }
  301. public void resetPosition(Position resetPos) {
  302. if (resetPos == null) {
  303. reset(null);
  304. childBreaks.clear();
  305. iStartPos = 0;
  306. } else {
  307. //reset(resetPos);
  308. LayoutManager lm = resetPos.getLM();
  309. }
  310. }
  311. }