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.

RowGroupLayoutManager.java 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.layoutmgr.table;
  19. import java.util.Iterator;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import org.apache.commons.logging.Log;
  23. import org.apache.commons.logging.LogFactory;
  24. import org.apache.fop.fo.Constants;
  25. import org.apache.fop.fo.flow.table.EffRow;
  26. import org.apache.fop.fo.flow.table.GridUnit;
  27. import org.apache.fop.fo.flow.table.PrimaryGridUnit;
  28. import org.apache.fop.fo.flow.table.TableColumn;
  29. import org.apache.fop.fo.flow.table.TableRow;
  30. import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
  31. import org.apache.fop.fo.properties.LengthRangeProperty;
  32. import org.apache.fop.layoutmgr.ElementListObserver;
  33. import org.apache.fop.layoutmgr.LayoutContext;
  34. import org.apache.fop.traits.MinOptMax;
  35. import org.apache.fop.util.BreakUtil;
  36. class RowGroupLayoutManager {
  37. private static Log log = LogFactory.getLog(RowGroupLayoutManager.class);
  38. private static final MinOptMax MAX_STRETCH = MinOptMax.getInstance(0, 0, Integer.MAX_VALUE);
  39. private EffRow[] rowGroup;
  40. private TableLayoutManager tableLM;
  41. private TableStepper tableStepper;
  42. RowGroupLayoutManager(TableLayoutManager tableLM, EffRow[] rowGroup,
  43. TableStepper tableStepper) {
  44. this.tableLM = tableLM;
  45. this.rowGroup = rowGroup;
  46. this.tableStepper = tableStepper;
  47. }
  48. public LinkedList getNextKnuthElements(LayoutContext context, int alignment, int bodyType) {
  49. LinkedList returnList = new LinkedList();
  50. createElementsForRowGroup(context, alignment, bodyType, returnList);
  51. context.updateKeepWithPreviousPending(rowGroup[0].getKeepWithPrevious());
  52. context.updateKeepWithNextPending(rowGroup[rowGroup.length - 1].getKeepWithNext());
  53. int breakBefore = Constants.EN_AUTO;
  54. TableRow firstRow = rowGroup[0].getTableRow();
  55. if (firstRow != null) {
  56. breakBefore = firstRow.getBreakBefore();
  57. }
  58. context.setBreakBefore(BreakUtil.compareBreakClasses(breakBefore,
  59. rowGroup[0].getBreakBefore()));
  60. int breakAfter = Constants.EN_AUTO;
  61. TableRow lastRow = rowGroup[rowGroup.length - 1].getTableRow();
  62. if (lastRow != null) {
  63. breakAfter = lastRow.getBreakAfter();
  64. }
  65. context.setBreakAfter(BreakUtil.compareBreakClasses(breakAfter,
  66. rowGroup[rowGroup.length - 1].getBreakAfter()));
  67. return returnList;
  68. }
  69. /**
  70. * Creates Knuth elements for a row group (see TableRowIterator.getNextRowGroup()).
  71. * @param context Active LayoutContext
  72. * @param alignment alignment indicator
  73. * @param bodyType Indicates what kind of body is being processed (BODY, HEADER or FOOTER)
  74. * @param returnList List to received the generated elements
  75. */
  76. private void createElementsForRowGroup(LayoutContext context, int alignment,
  77. int bodyType, LinkedList returnList) {
  78. log.debug("Handling row group with " + rowGroup.length + " rows...");
  79. EffRow row;
  80. for (EffRow aRowGroup : rowGroup) {
  81. row = aRowGroup;
  82. for (Object o : row.getGridUnits()) {
  83. GridUnit gu = (GridUnit) o;
  84. if (gu.isPrimary()) {
  85. PrimaryGridUnit primary = gu.getPrimary();
  86. // TODO a new LM must be created for every new static-content
  87. primary.createCellLM();
  88. primary.getCellLM().setParent(tableLM);
  89. //Calculate width of cell
  90. int spanWidth = 0;
  91. Iterator colIter = tableLM.getTable().getColumns().listIterator(
  92. primary.getColIndex());
  93. for (int i = 0, c = primary.getCell().getNumberColumnsSpanned(); i < c; i++) {
  94. spanWidth += ((TableColumn) colIter.next()).getColumnWidth().getValue(
  95. tableLM);
  96. }
  97. LayoutContext childLC = LayoutContext.newInstance();
  98. childLC.setStackLimitBP(context.getStackLimitBP()); //necessary?
  99. childLC.setRefIPD(spanWidth);
  100. //Get the element list for the cell contents
  101. List elems = primary.getCellLM().getNextKnuthElements(
  102. childLC, alignment);
  103. ElementListObserver.observe(elems, "table-cell", primary.getCell().getId());
  104. primary.setElements(elems);
  105. }
  106. }
  107. }
  108. computeRowHeights();
  109. List elements = tableStepper.getCombinedKnuthElementsForRowGroup(context,
  110. rowGroup, bodyType);
  111. returnList.addAll(elements);
  112. }
  113. /**
  114. * Calculate the heights of the rows in the row group, see CSS21, 17.5.3 Table height
  115. * algorithms.
  116. *
  117. * TODO this method will need to be adapted once clarification has been made by the
  118. * W3C regarding whether borders or border-separation must be included or not
  119. */
  120. private void computeRowHeights() {
  121. log.debug("rowGroup:");
  122. MinOptMax[] rowHeights = new MinOptMax[rowGroup.length];
  123. EffRow row;
  124. for (int rgi = 0; rgi < rowGroup.length; rgi++) {
  125. row = rowGroup[rgi];
  126. // The BPD of the biggest cell in the row
  127. // int maxCellBPD = 0;
  128. MinOptMax explicitRowHeight;
  129. TableRow tableRowFO = rowGroup[rgi].getTableRow();
  130. if (tableRowFO == null) {
  131. rowHeights[rgi] = MAX_STRETCH;
  132. explicitRowHeight = MAX_STRETCH;
  133. } else {
  134. LengthRangeProperty rowBPD = tableRowFO.getBlockProgressionDimension();
  135. rowHeights[rgi] = rowBPD.toMinOptMax(tableLM);
  136. explicitRowHeight = rowBPD.toMinOptMax(tableLM);
  137. }
  138. for (Object o : row.getGridUnits()) {
  139. GridUnit gu = (GridUnit) o;
  140. if (!gu.isEmpty() && gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan()) {
  141. PrimaryGridUnit primary = gu.getPrimary();
  142. int effectiveCellBPD = 0;
  143. LengthRangeProperty cellBPD = primary.getCell().getBlockProgressionDimension();
  144. if (!cellBPD.getMinimum(tableLM).isAuto()) {
  145. effectiveCellBPD = cellBPD.getMinimum(tableLM).getLength()
  146. .getValue(tableLM);
  147. }
  148. if (!cellBPD.getOptimum(tableLM).isAuto()) {
  149. effectiveCellBPD = cellBPD.getOptimum(tableLM).getLength()
  150. .getValue(tableLM);
  151. }
  152. if (gu.getRowSpanIndex() == 0) {
  153. effectiveCellBPD = Math.max(effectiveCellBPD, explicitRowHeight.getOpt());
  154. }
  155. effectiveCellBPD = Math.max(effectiveCellBPD, primary.getContentLength());
  156. int borderWidths = primary.getBeforeAfterBorderWidth();
  157. int padding = 0;
  158. CommonBorderPaddingBackground cbpb = primary.getCell()
  159. .getCommonBorderPaddingBackground();
  160. padding += cbpb.getPaddingBefore(false, primary.getCellLM());
  161. padding += cbpb.getPaddingAfter(false, primary.getCellLM());
  162. int effRowHeight = effectiveCellBPD + padding + borderWidths;
  163. for (int prev = rgi - 1; prev >= rgi - gu.getRowSpanIndex(); prev--) {
  164. effRowHeight -= rowHeights[prev].getOpt();
  165. }
  166. if (effRowHeight > rowHeights[rgi].getMin()) {
  167. // This is the new height of the (grid) row
  168. rowHeights[rgi] = rowHeights[rgi].extendMinimum(effRowHeight);
  169. }
  170. }
  171. }
  172. row.setHeight(rowHeights[rgi]);
  173. row.setExplicitHeight(explicitRowHeight);
  174. // TODO re-enable and improve after clarification
  175. //See http://markmail.org/message/h25ycwwu7qglr4k4
  176. // if (maxCellBPD > row.getExplicitHeight().max) {
  177. //old:
  178. // log.warn(FONode.decorateWithContextInfo(
  179. // "The contents of row " + (row.getIndex() + 1)
  180. // + " are taller than they should be (there is a"
  181. // + " block-progression-dimension or height constraint
  182. // + " on the indicated row)."
  183. // + " Due to its contents the row grows"
  184. // + " to " + maxCellBPD + " millipoints, but the row shouldn't get"
  185. // + " any taller than " + row.getExplicitHeight() + " millipoints.",
  186. // row.getTableRow()));
  187. //new (with events):
  188. // BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Factory.create(
  189. // tableRow.getUserAgent().getEventBroadcaster());
  190. // eventProducer.rowTooTall(this, row.getIndex() + 1,
  191. // maxCellBPD, row.getExplicitHeight().max, tableRow.getLocator());
  192. // }
  193. }
  194. }
  195. }