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.

TableCell.java 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. * $Id$
  3. * ============================================================================
  4. * The Apache Software License, Version 1.1
  5. * ============================================================================
  6. *
  7. * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without modifica-
  10. * tion, are permitted provided that the following conditions are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright notice,
  13. * this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if any, must
  20. * include the following acknowledgment: "This product includes software
  21. * developed by the Apache Software Foundation (http://www.apache.org/)."
  22. * Alternately, this acknowledgment may appear in the software itself, if
  23. * and wherever such third-party acknowledgments normally appear.
  24. *
  25. * 4. The names "FOP" and "Apache Software Foundation" must not be used to
  26. * endorse or promote products derived from this software without prior
  27. * written permission. For written permission, please contact
  28. * apache@apache.org.
  29. *
  30. * 5. Products derived from this software may not be called "Apache", nor may
  31. * "Apache" appear in their name, without prior written permission of the
  32. * Apache Software Foundation.
  33. *
  34. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  35. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  36. * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  37. * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  38. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
  39. * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  40. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  41. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  43. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. * ============================================================================
  45. *
  46. * This software consists of voluntary contributions made by many individuals
  47. * on behalf of the Apache Software Foundation and was originally created by
  48. * James Tauber <jtauber@jtauber.com>. For more information on the Apache
  49. * Software Foundation, please see <http://www.apache.org/>.
  50. */
  51. package org.apache.fop.fo.flow;
  52. // FOP
  53. import org.apache.fop.fo.FObj;
  54. import org.apache.fop.fo.PropertyList;
  55. import org.apache.fop.fo.Status;
  56. import org.apache.fop.fo.properties.BorderCollapse;
  57. import org.apache.fop.fo.properties.DisplayAlign;
  58. import org.apache.fop.fo.properties.Position;
  59. import org.apache.fop.layout.Area;
  60. import org.apache.fop.layout.BorderAndPadding;
  61. import org.apache.fop.layout.AccessibilityProps;
  62. import org.apache.fop.layout.AuralProps;
  63. import org.apache.fop.layout.BackgroundProps;
  64. import org.apache.fop.layout.RelativePositionProps;
  65. import org.apache.fop.layout.AreaContainer;
  66. import org.apache.fop.apps.FOPException;
  67. public class TableCell extends FObj {
  68. public static class Maker extends FObj.Maker {
  69. public FObj make(FObj parent, PropertyList propertyList,
  70. String systemId, int line, int column)
  71. throws FOPException {
  72. return new TableCell(parent, propertyList, systemId, line, column);
  73. }
  74. }
  75. public static FObj.Maker maker() {
  76. return new TableCell.Maker();
  77. }
  78. // int spaceBefore;
  79. // int spaceAfter;
  80. String id;
  81. int numColumnsSpanned;
  82. int numRowsSpanned;
  83. int iColNumber = -1; // uninitialized
  84. /**
  85. * Offset of content rectangle in inline-progression-direction,
  86. * relative to table.
  87. */
  88. protected int startOffset;
  89. /**
  90. * Dimension of allocation rectangle in inline-progression-direction,
  91. * determined by the width of the column(s) occupied by the cell
  92. */
  93. protected int width;
  94. /**
  95. * Offset of content rectangle, in block-progression-direction,
  96. * relative to the row.
  97. */
  98. protected int beforeOffset = 0;
  99. /**
  100. * Offset of content rectangle, in inline-progression-direction,
  101. * relative to the column start edge.
  102. */
  103. protected int startAdjust = 0;
  104. /**
  105. * Adjust to theoretical column width to obtain content width
  106. * relative to the column start edge.
  107. */
  108. protected int widthAdjust = 0;
  109. /* For collapsed border style */
  110. protected int borderHeight = 0;
  111. /**
  112. * Minimum ontent height of cell.
  113. */
  114. protected int minCellHeight = 0;
  115. protected int height = 0;
  116. protected int top; // Ypos of cell ???
  117. protected int verticalAlign;
  118. protected boolean bRelativeAlign = false;
  119. // boolean setup = false;
  120. boolean bSepBorders = true;
  121. /**
  122. * Set to true if all content completely laid out.
  123. */
  124. boolean bDone=false;
  125. /**
  126. * Border separation value in the block-progression dimension.
  127. * Used in calculating cells height.
  128. */
  129. int m_borderSeparation = 0;
  130. // public AreaContainer cellArea;
  131. public java.lang.ref.WeakReference areaContainerRef;
  132. public TableCell(FObj parent, PropertyList propertyList,
  133. String systemId, int line, int column)
  134. throws FOPException {
  135. super(parent, propertyList, systemId, line, column);
  136. if (!(parent instanceof TableRow)) {
  137. throw new FOPException("A table cell must be child of fo:table-row,"
  138. + " not " + parent.getName(), systemId, line, column);
  139. }
  140. doSetup(); // init some basic property values
  141. }
  142. public String getName() {
  143. return "fo:table-cell";
  144. }
  145. // Set position relative to table (set by body?)
  146. public void setStartOffset(int offset) {
  147. startOffset = offset;
  148. }
  149. // Initially same as the column width containg this cell or the
  150. // sum of the spanned columns if numColumnsSpanned > 1
  151. public void setWidth(int width) {
  152. this.width = width;
  153. }
  154. public int getColumnNumber() {
  155. return iColNumber;
  156. }
  157. public int getNumColumnsSpanned() {
  158. return numColumnsSpanned;
  159. }
  160. public int getNumRowsSpanned() {
  161. return numRowsSpanned;
  162. }
  163. public void doSetup() // throws FOPException
  164. {
  165. // Common Accessibility Properties
  166. AccessibilityProps mAccProps = propMgr.getAccessibilityProps();
  167. // Common Aural Properties
  168. AuralProps mAurProps = propMgr.getAuralProps();
  169. // Common Border, Padding, and Background Properties
  170. BorderAndPadding bap = propMgr.getBorderAndPadding();
  171. BackgroundProps bProps = propMgr.getBackgroundProps();
  172. // Common Relative Position Properties
  173. RelativePositionProps mRelProps = propMgr.getRelativePositionProps();
  174. // this.properties.get("border-after-precedence");
  175. // this.properties.get("border-before-precendence");
  176. // this.properties.get("border-end-precendence");
  177. // this.properties.get("border-start-precendence");
  178. // this.properties.get("block-progression-dimension");
  179. // this.properties.get("column-number");
  180. // this.properties.get("display-align");
  181. // this.properties.get("relative-align");
  182. // this.properties.get("empty-cells");
  183. // this.properties.get("ends-row");
  184. // this.properties.get("height");
  185. // this.properties.get("id");
  186. // this.properties.get("number-columns-spanned");
  187. // this.properties.get("number-rows-spanned");
  188. // this.properties.get("starts-row");
  189. // this.properties.get("width");
  190. this.iColNumber =
  191. properties.get("column-number").getNumber().intValue();
  192. if (iColNumber < 0) {
  193. iColNumber = 0;
  194. }
  195. this.numColumnsSpanned =
  196. this.properties.get("number-columns-spanned").getNumber().intValue();
  197. if (numColumnsSpanned < 1) {
  198. numColumnsSpanned = 1;
  199. }
  200. this.numRowsSpanned =
  201. this.properties.get("number-rows-spanned").getNumber().intValue();
  202. if (numRowsSpanned < 1) {
  203. numRowsSpanned = 1;
  204. }
  205. this.id = this.properties.get("id").getString();
  206. bSepBorders = (this.properties.get("border-collapse").getEnum()
  207. == BorderCollapse.SEPARATE);
  208. calcBorders(propMgr.getBorderAndPadding());
  209. // Vertical cell alignment
  210. verticalAlign = this.properties.get("display-align").getEnum();
  211. if (verticalAlign == DisplayAlign.AUTO) {
  212. // Depends on all cells starting in row
  213. bRelativeAlign = true;
  214. verticalAlign = this.properties.get("relative-align").getEnum();
  215. } else
  216. bRelativeAlign = false; // Align on a per-cell basis
  217. this.minCellHeight =
  218. this.properties.get("height").getLength().mvalue();
  219. }
  220. public int layout(Area area) throws FOPException {
  221. int originalAbsoluteHeight = area.getAbsoluteHeight();
  222. if (this.marker == BREAK_AFTER) {
  223. return Status.OK;
  224. }
  225. if (this.marker == START) {
  226. // if (!setup) {
  227. // doSetup(area);
  228. // }
  229. // Calculate cell borders
  230. // calcBorders(propMgr.getBorderAndPadding());
  231. try {
  232. area.getIDReferences().createID(id);
  233. }
  234. catch(FOPException e) {
  235. if (!e.isLocationSet()) {
  236. e.setLocation(systemId, line, column);
  237. }
  238. throw e;
  239. }
  240. this.marker = 0;
  241. this.bDone=false;
  242. }
  243. /*
  244. * if ((spaceBefore != 0) && (this.marker ==0)) {
  245. * area.increaseHeight(spaceBefore);
  246. * }
  247. */
  248. if (marker == 0) {
  249. // configure id
  250. area.getIDReferences().configureID(id, area);
  251. }
  252. // int spaceLeft = area.spaceLeft() - m_borderSeparation/2 + borderHeight/2 ;
  253. int spaceLeft = area.spaceLeft() - m_borderSeparation;
  254. // The Area position defines the content rectangle! Borders
  255. // and padding are outside of this rectangle.
  256. AreaContainer cellArea =
  257. new AreaContainer(propMgr.getFontState(area.getFontInfo()),
  258. startOffset + startAdjust, beforeOffset,
  259. width - widthAdjust, spaceLeft,
  260. Position.RELATIVE);
  261. cellArea.foCreator = this; // G Seshadri
  262. cellArea.setPage(area.getPage());
  263. cellArea.setParent(area);
  264. try {
  265. cellArea.setBorderAndPadding((BorderAndPadding)
  266. propMgr.getBorderAndPadding().clone());
  267. } catch (CloneNotSupportedException e) {
  268. System.err.println("Can't clone BorderAndPadding: " + e) ;
  269. cellArea.setBorderAndPadding(propMgr.getBorderAndPadding());
  270. }
  271. cellArea.setBackground(propMgr.getBackgroundProps());
  272. cellArea.start();
  273. cellArea.setAbsoluteHeight(area.getAbsoluteHeight()); // ???
  274. cellArea.setIDReferences(area.getIDReferences());
  275. // Add adjust for padding and border to fix link alignment!
  276. cellArea.setTableCellXOffset(startOffset + startAdjust);
  277. this.areaContainerRef = new java.lang.ref.WeakReference(cellArea);
  278. int numChildren = this.children.size();
  279. for (int i = this.marker; bDone==false && i < numChildren; i++) {
  280. FObj fo = (FObj)children.get(i);
  281. fo.setIsInTableCell();
  282. fo.forceWidth(width); // ???
  283. // Overflows may cause a row to be re-layedout,
  284. // need to pass already processed content.
  285. this.marker = i;
  286. int status;
  287. if (Status.isIncomplete((status = fo.layout(cellArea)))) {
  288. // this.marker = i;
  289. if ((i == 0) && (status == Status.AREA_FULL_NONE)) {
  290. return Status.AREA_FULL_NONE;
  291. } else {
  292. // hani Elabed 11/21/2000
  293. area.addChild(cellArea);
  294. // area.setAbsoluteHeight(cellArea.getAbsoluteHeight());
  295. return Status.AREA_FULL_SOME;
  296. }
  297. }
  298. area.setMaxHeight(area.getMaxHeight() - spaceLeft
  299. + cellArea.getMaxHeight());
  300. }
  301. this.bDone=true;
  302. cellArea.end();
  303. area.addChild(cellArea);
  304. // Adjust for minimum cell content height
  305. if (minCellHeight > cellArea.getContentHeight()) {
  306. cellArea.setHeight(minCellHeight);
  307. }
  308. // This is the allocation height of the cell (including borders
  309. // and padding
  310. // ALSO need to include offsets if using "separate borders"
  311. height = cellArea.getHeight();
  312. top = cellArea.getCurrentYPosition(); // CHECK THIS!!!
  313. // reset absoluteHeight to beginning of row
  314. // area.setHeight(cellArea.getHeight() + spaceBefore + spaceAfter);
  315. // I don't think we should do this here (KL) !!!
  316. // area.setHeight(cellArea.getHeight());
  317. // area.setAbsoluteHeight(originalAbsoluteHeight);
  318. return Status.OK;
  319. }
  320. /**
  321. * Return the allocation height of the cell area.
  322. * Note: called by TableRow.
  323. * We adjust the actual allocation height of the area by the value
  324. * of border separation (for separate borders) or border height
  325. * adjustment for collapse style (because current scheme makes cell
  326. * overestimate the allocation height).
  327. */
  328. public int getHeight() {
  329. return ((AreaContainer)areaContainerRef.get()).getHeight() + m_borderSeparation - borderHeight;
  330. }
  331. /**
  332. * Set the final size of cell content rectangles to the actual row height
  333. * and to vertically align the actual content within the cell rectangle.
  334. * @param h Height of this row in the grid which is based on
  335. * the allocation height of all the cells in the row, including any
  336. * border separation values.
  337. */
  338. public void setRowHeight(int h) {
  339. int delta = h - getHeight();
  340. // cellArea.increaseHeight(h + borderHeight/2 - cellArea.getHeight());
  341. if (bRelativeAlign) {
  342. // Must get info for all cells starting in row!
  343. // verticalAlign can be BEFORE or BASELINE
  344. // For now just treat like "before"
  345. ((AreaContainer)areaContainerRef.get()).increaseHeight(delta);
  346. } else if (delta > 0) {
  347. BorderAndPadding cellBP = ((AreaContainer)areaContainerRef.get()).getBorderAndPadding();
  348. switch (verticalAlign) {
  349. case DisplayAlign.CENTER:
  350. // Increase cell padding before and after and change
  351. // "Y" position of content rectangle
  352. ((AreaContainer)areaContainerRef.get()).shiftYPosition(delta / 2);
  353. cellBP.setPaddingLength(BorderAndPadding.TOP,
  354. cellBP.getPaddingTop(false)
  355. + delta / 2);
  356. cellBP.setPaddingLength(BorderAndPadding.BOTTOM,
  357. cellBP.getPaddingBottom(false)
  358. + delta - delta / 2);
  359. break;
  360. case DisplayAlign.AFTER:
  361. // Increase cell padding before and change
  362. // "Y" position of content rectangle
  363. cellBP.setPaddingLength(BorderAndPadding.TOP,
  364. cellBP.getPaddingTop(false) + delta);
  365. ((AreaContainer)areaContainerRef.get()).shiftYPosition(delta);
  366. break;
  367. case DisplayAlign.BEFORE:
  368. // cellArea.increaseHeight(delta);
  369. cellBP.setPaddingLength(BorderAndPadding.BOTTOM,
  370. cellBP.getPaddingBottom(false)
  371. + delta);
  372. default: // OK
  373. break;
  374. }
  375. }
  376. }
  377. /**
  378. * Calculate cell border and padding, including offset of content
  379. * rectangle from the theoretical grid position.
  380. */
  381. private void calcBorders(BorderAndPadding bp) {
  382. if (this.bSepBorders) {
  383. /*
  384. * Easy case.
  385. * Cell border is the property specified directly on cell.
  386. * Offset content rect by half the border-separation value,
  387. * in addition to the border and padding values. Note:
  388. * border-separate should only be specified on the table object,
  389. * but it inherits.
  390. */
  391. int iSep =
  392. properties.get("border-separation.inline-progression-direction").getLength().mvalue();
  393. //border-spacing is a shorthand of border-separation
  394. int iSpacing =
  395. properties.get("border-spacing.inline-progression-direction").getLength().mvalue();
  396. if (iSpacing > iSep)
  397. iSep = iSpacing;
  398. this.startAdjust = iSep / 2 + bp.getBorderLeftWidth(false)
  399. + bp.getPaddingLeft(false);
  400. /*
  401. * int contentOffset = iSep + bp.getBorderStartWidth(false) +
  402. * bp.getPaddingStart(false);
  403. */
  404. this.widthAdjust = startAdjust + iSep - iSep / 2
  405. + bp.getBorderRightWidth(false)
  406. + bp.getPaddingRight(false);
  407. // bp.getBorderEndWidth(false) + bp.getPaddingEnd(false);
  408. // Offset of content rectangle in the block-progression direction
  409. m_borderSeparation =
  410. properties.get("border-separation.block-progression-direction").getLength().mvalue();
  411. int m_borderSpacing =
  412. properties.get("border-spacing.block-progression-direction").getLength().mvalue();
  413. if (m_borderSpacing > m_borderSeparation)
  414. m_borderSeparation = m_borderSpacing;
  415. this.beforeOffset = m_borderSeparation / 2
  416. + bp.getBorderTopWidth(false)
  417. + bp.getPaddingTop(false);
  418. // bp.getBorderBeforeWidth(false) + bp.getPaddingBefore(false);
  419. } else {
  420. // System.err.println("Collapse borders");
  421. /*
  422. * Hard case.
  423. * Cell border is combination of other cell borders, or table
  424. * border for edge cells. Also seems to border values specified
  425. * on row and column FO in the table (if I read CR correclty.)
  426. */
  427. // Set up before and after borders, taking into account row
  428. // and table border properties.
  429. // ??? What about table-body, header,footer
  430. /*
  431. * We can't calculate before and after because we aren't sure
  432. * whether this row will be the first or last in its area, due
  433. * to redoing break decisions (at least in the "new" architecture.)
  434. * So in the general case, we will calculate two possible values:
  435. * the first/last one and the "middle" one.
  436. * Example: border-before
  437. * 1. If the cell is in the first row in the first table body, it
  438. * will combine with the last row of the header, or with the
  439. * top (before) table border if there is no header.
  440. * 2. Otherwise there are two cases:
  441. * a. the row is first in its (non-first) Area.
  442. * The border can combine with either:
  443. * i. the last row of table-header and its cells, or
  444. * ii. the table before border (no table-header or it is
  445. * omitted on non-first Areas).
  446. * b. the row isn't first in its Area.
  447. * The border combines with the border of the previous
  448. * row and the cells which end in that row.
  449. */
  450. /*
  451. * if-first
  452. * Calculate the effective border of the cell before-border,
  453. * it's parent row before-border, the last header row after-border,
  454. * the after border of the cell(s) which end in the last header
  455. * row.
  456. */
  457. /*
  458. * if-not-first
  459. * Calculate the effective border of the cell before-border,
  460. * it's parent row before-border, the previous row after-border,
  461. * the after border of the cell(s) which end in the previous
  462. * row.
  463. */
  464. /* ivan demakov */
  465. int borderStart = bp.getBorderLeftWidth(false);
  466. int borderEnd = bp.getBorderRightWidth(false);
  467. int borderBefore = bp.getBorderTopWidth(false);
  468. int borderAfter = bp.getBorderBottomWidth(false);
  469. this.startAdjust = borderStart / 2 + bp.getPaddingLeft(false);
  470. this.widthAdjust = startAdjust + borderEnd / 2
  471. + bp.getPaddingRight(false);
  472. this.beforeOffset = borderBefore / 2 + bp.getPaddingTop(false);
  473. // Half border height to fix overestimate of area size!
  474. this.borderHeight = (borderBefore + borderAfter) / 2;
  475. }
  476. }
  477. }