選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

BodyAreaContainer.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  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.layout;
  8. // FOP
  9. import org.apache.fop.render.Renderer;
  10. import org.apache.fop.fo.properties.*;
  11. import org.apache.fop.datatypes.IDReferences;
  12. import org.apache.fop.apps.FOPException;
  13. import org.apache.fop.fo.FObj;
  14. import org.apache.fop.fo.flow.Block;
  15. import org.apache.fop.fo.flow.BlockContainer;
  16. // Java
  17. import java.util.Vector;
  18. import java.util.Enumeration;
  19. public class BodyAreaContainer extends Area {
  20. // dimensions for the 'region-reference-area'
  21. private int xPosition; // should be able to take value 'left' and 'right' too
  22. private int yPosition; // should be able to take value 'top' and 'bottom' too
  23. private int position;
  24. // the column-count and column-gap
  25. private int columnCount;
  26. private int columnGap;
  27. // the 3 primary reference areas
  28. private AreaContainer mainReferenceArea;
  29. private AreaContainer beforeFloatReferenceArea;
  30. private AreaContainer footnoteReferenceArea;
  31. // current heights
  32. private int mainRefAreaHeight;
  33. private int beforeFloatRefAreaHeight;
  34. private int footnoteRefAreaHeight;
  35. // reference area yPositions
  36. private int mainYPosition;
  37. private int beforeFloatYPosition;
  38. private int footnoteYPosition;
  39. // the start FO in case of rollback
  40. private FObj startFO;
  41. private boolean isNewSpanArea;
  42. // keeps track of footnote state for multiple layouts
  43. private int footnoteState = 0;
  44. public BodyAreaContainer(FontState fontState, int xPosition,
  45. int yPosition, int allocationWidth,
  46. int maxHeight, int position, int columnCount,
  47. int columnGap) {
  48. super(fontState, allocationWidth, maxHeight);
  49. this.xPosition = xPosition;
  50. this.yPosition = yPosition;
  51. this.position = position;
  52. this.columnCount = columnCount;
  53. this.columnGap = columnGap;
  54. // create the primary reference areas
  55. beforeFloatRefAreaHeight = 0;
  56. footnoteRefAreaHeight = 0;
  57. mainRefAreaHeight = maxHeight - beforeFloatRefAreaHeight
  58. - footnoteRefAreaHeight;
  59. beforeFloatReferenceArea = new AreaContainer(fontState, xPosition,
  60. yPosition, allocationWidth, beforeFloatRefAreaHeight,
  61. Position.ABSOLUTE);
  62. beforeFloatReferenceArea.setAreaName("before-float-reference-area");
  63. this.addChild(beforeFloatReferenceArea);
  64. mainReferenceArea = new AreaContainer(fontState, xPosition,
  65. yPosition, allocationWidth,
  66. mainRefAreaHeight,
  67. Position.ABSOLUTE);
  68. mainReferenceArea.setAreaName("main-reference-area");
  69. this.addChild(mainReferenceArea);
  70. int footnoteRefAreaYPosition = yPosition - mainRefAreaHeight;
  71. footnoteReferenceArea = new AreaContainer(fontState, xPosition,
  72. footnoteRefAreaYPosition,
  73. allocationWidth,
  74. footnoteRefAreaHeight,
  75. Position.ABSOLUTE);
  76. footnoteReferenceArea.setAreaName("footnote-reference-area");
  77. this.addChild(footnoteReferenceArea);
  78. // all padding and border-width must be 0
  79. // setBorderAndPadding(new BorderAndPadding());
  80. // setPadding(0, 0, 0, 0);
  81. // setBorderWidth(0, 0, 0, 0);
  82. }
  83. public int getPosition() {
  84. return position;
  85. }
  86. public int getXPosition() {
  87. return xPosition + getPaddingLeft() + getBorderLeftWidth();
  88. }
  89. public void setXPosition(int value) {
  90. xPosition = value;
  91. }
  92. public int getYPosition() {
  93. return yPosition + getPaddingTop() + getBorderTopWidth();
  94. }
  95. public void setYPosition(int value) {
  96. yPosition = value;
  97. }
  98. public AreaContainer getMainReferenceArea() {
  99. return mainReferenceArea;
  100. }
  101. public AreaContainer getBeforeFloatReferenceArea() {
  102. return beforeFloatReferenceArea;
  103. }
  104. public AreaContainer getFootnoteReferenceArea() {
  105. return footnoteReferenceArea;
  106. }
  107. public void setIDReferences(IDReferences idReferences) {
  108. mainReferenceArea.setIDReferences(idReferences);
  109. }
  110. public IDReferences getIDReferences() {
  111. return mainReferenceArea.getIDReferences();
  112. }
  113. /**
  114. * Depending on the column-count of the next FO, determine whether
  115. * a new span area needs to be constructed or not, and return the
  116. * appropriate ColumnArea.
  117. * The next cut of this method should also inspect the FO to see
  118. * whether the area to be returned ought not to be the footnote
  119. * or before-float reference area.
  120. * @param fo The next formatting object
  121. * @returns the next column area (possibly the current one)
  122. */
  123. public AreaContainer getNextArea(FObj fo) throws FOPException {
  124. isNewSpanArea = false;
  125. int span = Span.NONE;
  126. if (fo instanceof Block)
  127. span = ((Block)fo).getSpan();
  128. else if (fo instanceof BlockContainer)
  129. span = ((BlockContainer)fo).getSpan();
  130. if (this.mainReferenceArea.getChildren().isEmpty()) {
  131. if (span == Span.ALL)
  132. return addSpanArea(1);
  133. else
  134. return addSpanArea(columnCount);
  135. }
  136. Vector spanAreas = this.mainReferenceArea.getChildren();
  137. SpanArea spanArea = (SpanArea)spanAreas.elementAt(spanAreas.size()
  138. - 1);
  139. if ((span == Span.ALL) && (spanArea.getColumnCount() == 1)) {
  140. // return the single column area in the same span area
  141. return spanArea.getCurrentColumnArea();
  142. } else if ((span == Span.NONE)
  143. && (spanArea.getColumnCount() == columnCount)) {
  144. // return the current column area in the same span area
  145. return spanArea.getCurrentColumnArea();
  146. } else if (span == Span.ALL) {
  147. // create new span area with one column; return column area
  148. return addSpanArea(1);
  149. } else if (span == Span.NONE) {
  150. // create new span area with multiple columns; return first column area
  151. return addSpanArea(columnCount);
  152. } else {
  153. throw new FOPException("BodyAreaContainer::getNextArea(): Span attribute messed up");
  154. }
  155. }
  156. /**
  157. * Add a new span area with specified number of column areas.
  158. * @param numColumns The number of column areas
  159. * @returns AreaContainer The next column area
  160. */
  161. private AreaContainer addSpanArea(int numColumns) {
  162. resetHeights();
  163. // create span area and child column-areas, using whatever
  164. // height remains after existing span areas (in the main
  165. // reference area).
  166. int spanAreaYPosition = getYPosition()
  167. - this.mainReferenceArea.getContentHeight();
  168. SpanArea spanArea = new SpanArea(fontState, getXPosition(),
  169. spanAreaYPosition, allocationWidth,
  170. getRemainingHeight(), numColumns,
  171. columnGap);
  172. this.mainReferenceArea.addChild(spanArea);
  173. spanArea.setPage(this.getPage());
  174. this.isNewSpanArea = true;
  175. return spanArea.getCurrentColumnArea();
  176. }
  177. /**
  178. * This almost does what getNewArea() does, without actually
  179. * returning an area. These 2 methods can be reworked.
  180. * @param fo The next formatting object
  181. * @returns boolean True if we need to balance.
  182. */
  183. public boolean isBalancingRequired(FObj fo) {
  184. if (this.mainReferenceArea.getChildren().isEmpty())
  185. return false;
  186. Vector spanAreas = this.mainReferenceArea.getChildren();
  187. SpanArea spanArea = (SpanArea)spanAreas.elementAt(spanAreas.size()
  188. - 1);
  189. if (spanArea.isBalanced())
  190. return false;
  191. int span = Span.NONE;
  192. if (fo instanceof Block)
  193. span = ((Block)fo).getSpan();
  194. else if (fo instanceof BlockContainer)
  195. span = ((BlockContainer)fo).getSpan();
  196. if ((span == Span.ALL) && (spanArea.getColumnCount() == 1))
  197. return false;
  198. else if ((span == Span.NONE)
  199. && (spanArea.getColumnCount() == columnCount))
  200. return false;
  201. else if (span == Span.ALL)
  202. return true;
  203. else if (span == Span.NONE)
  204. return false;
  205. else
  206. return false;
  207. }
  208. /**
  209. * This is where the balancing algorithm lives, or gets called.
  210. * Right now it's primitive: get the total content height in all
  211. * columns, divide by the column count, and add a heuristic
  212. * safety factor.
  213. * Then the previous (unbalanced) span area is removed, and a new
  214. * one added with the computed max height.
  215. */
  216. public void resetSpanArea() {
  217. Vector spanAreas = this.mainReferenceArea.getChildren();
  218. SpanArea spanArea = (SpanArea)spanAreas.elementAt(spanAreas.size()
  219. - 1);
  220. if (!spanArea.isBalanced()) {
  221. // span area maintains a record of the total height of
  222. // laid-out content in the previous (first) attempt
  223. int newHeight = spanArea.getTotalContentHeight()
  224. / spanArea.getColumnCount();
  225. newHeight += 2 * 15600; // ???
  226. this.mainReferenceArea.removeChild(spanArea);
  227. resetHeights();
  228. SpanArea newSpanArea = new SpanArea(fontState, getXPosition(),
  229. spanArea.getYPosition(),
  230. allocationWidth, newHeight,
  231. spanArea.getColumnCount(),
  232. columnGap);
  233. this.mainReferenceArea.addChild(newSpanArea);
  234. newSpanArea.setPage(this.getPage());
  235. newSpanArea.setIsBalanced();
  236. this.isNewSpanArea = true;
  237. } else {
  238. throw new IllegalStateException("Trying to balance balanced area");
  239. }
  240. }
  241. /**
  242. * Determine remaining height for new span area. Needs to be
  243. * modified for footnote and before-float reference areas when
  244. * those are supported.
  245. * @returns int The remaining available height in millipoints.
  246. */
  247. public int getRemainingHeight() {
  248. return this.mainReferenceArea.getMaxHeight()
  249. - this.mainReferenceArea.getContentHeight();
  250. }
  251. /**
  252. * Used by resetSpanArea() and addSpanArea() to adjust the main
  253. * reference area height before creating a new span.
  254. */
  255. private void resetHeights() {
  256. int totalHeight = 0;
  257. for (Enumeration e = this.mainReferenceArea.getChildren().elements();
  258. e.hasMoreElements(); ) {
  259. SpanArea spanArea = (SpanArea)e.nextElement();
  260. int spanContentHeight = spanArea.getMaxContentHeight();
  261. int spanMaxHeight = spanArea.getMaxHeight();
  262. totalHeight += (spanContentHeight < spanMaxHeight)
  263. ? spanContentHeight : spanMaxHeight;
  264. }
  265. this.mainReferenceArea.setHeight(totalHeight);
  266. }
  267. /**
  268. * Used in Flow when layout returns incomplete.
  269. * @returns boolean Is this the last column in this span?
  270. */
  271. public boolean isLastColumn() {
  272. Vector spanAreas = this.mainReferenceArea.getChildren();
  273. SpanArea spanArea = (SpanArea)spanAreas.elementAt(spanAreas.size()
  274. - 1);
  275. return spanArea.isLastColumn();
  276. }
  277. /**
  278. * This variable is unset by getNextArea(), is set by addSpanArea(),
  279. * and <i>may</i> be set by resetSpanArea().
  280. * @returns boolean Is the span area new or not?
  281. */
  282. public boolean isNewSpanArea() {
  283. return isNewSpanArea;
  284. }
  285. public AreaContainer getCurrentColumnArea() {
  286. Vector spanAreas = this.mainReferenceArea.getChildren();
  287. SpanArea spanArea = (SpanArea)spanAreas.elementAt(spanAreas.size()
  288. - 1);
  289. return spanArea.getCurrentColumnArea();
  290. }
  291. public int getFootnoteState() {
  292. return footnoteState;
  293. }
  294. public boolean needsFootnoteAdjusting() {
  295. footnoteYPosition = footnoteReferenceArea.getYPosition();
  296. switch (footnoteState) {
  297. case 0:
  298. resetHeights();
  299. if (footnoteReferenceArea.getHeight() > 0
  300. && mainYPosition + mainReferenceArea.getHeight()
  301. > footnoteYPosition) {
  302. return true;
  303. }
  304. case 1:
  305. break;
  306. }
  307. return false;
  308. }
  309. public void adjustFootnoteArea() {
  310. footnoteState++;
  311. if (footnoteState == 1) {
  312. mainReferenceArea.setMaxHeight(footnoteReferenceArea.getYPosition()
  313. - mainYPosition);
  314. footnoteYPosition = footnoteReferenceArea.getYPosition();
  315. footnoteReferenceArea.setMaxHeight(footnoteReferenceArea.getHeight());
  316. Vector childs = footnoteReferenceArea.getChildren();
  317. for (Enumeration en = childs.elements(); en.hasMoreElements(); ) {
  318. Object obj = en.nextElement();
  319. if (obj instanceof Area) {
  320. Area childArea = (Area)obj;
  321. footnoteReferenceArea.removeChild(childArea);
  322. }
  323. }
  324. getPage().setPendingFootnotes(null);
  325. }
  326. }
  327. protected static void resetMaxHeight(Area ar, int change) {
  328. ar.setMaxHeight(change);
  329. Vector childs = ar.getChildren();
  330. for (Enumeration en = childs.elements(); en.hasMoreElements(); ) {
  331. Object obj = en.nextElement();
  332. if (obj instanceof Area) {
  333. Area childArea = (Area)obj;
  334. resetMaxHeight(childArea, change);
  335. }
  336. }
  337. }
  338. }