1 17 18 19 20 package org.apache.fop.layoutmgr.table; 21 22 import java.util.Arrays ; 23 import java.util.Iterator ; 24 import java.util.LinkedList ; 25 import java.util.List ; 26 import java.util.Map ; 27 28 import org.apache.commons.logging.Log; 29 import org.apache.commons.logging.LogFactory; 30 import org.apache.fop.area.Block; 31 import org.apache.fop.area.Trait; 32 import org.apache.fop.datatypes.PercentBaseContext; 33 import org.apache.fop.fo.Constants; 34 import org.apache.fop.fo.FONode; 35 import org.apache.fop.fo.FObj; 36 import org.apache.fop.fo.flow.Table; 37 import org.apache.fop.fo.flow.TableBody; 38 import org.apache.fop.fo.flow.TableRow; 39 import org.apache.fop.fo.properties.CommonBorderPaddingBackground; 40 import org.apache.fop.fo.properties.LengthRangeProperty; 41 import org.apache.fop.layoutmgr.BreakElement; 42 import org.apache.fop.layoutmgr.ElementListObserver; 43 import org.apache.fop.layoutmgr.ElementListUtils; 44 import org.apache.fop.layoutmgr.KnuthBox; 45 import org.apache.fop.layoutmgr.KnuthElement; 46 import org.apache.fop.layoutmgr.KnuthPenalty; 47 import org.apache.fop.layoutmgr.KnuthPossPosIter; 48 import org.apache.fop.layoutmgr.LayoutContext; 49 import org.apache.fop.layoutmgr.LayoutManager; 50 import org.apache.fop.layoutmgr.ListElement; 51 import org.apache.fop.layoutmgr.MinOptMaxUtil; 52 import org.apache.fop.layoutmgr.Position; 53 import org.apache.fop.layoutmgr.PositionIterator; 54 import org.apache.fop.layoutmgr.SpaceResolver; 55 import org.apache.fop.layoutmgr.TraitSetter; 56 import org.apache.fop.layoutmgr.SpaceResolver.SpaceHandlingBreakPosition; 57 import org.apache.fop.traits.MinOptMax; 58 59 62 public class TableContentLayoutManager implements PercentBaseContext { 63 64 65 private static Log log = LogFactory.getLog(TableContentLayoutManager.class); 66 67 private TableLayoutManager tableLM; 68 private TableRowIterator bodyIter; 69 private TableRowIterator headerIter; 70 private TableRowIterator footerIter; 71 private LinkedList headerList; 72 private LinkedList footerList; 73 private int headerNetHeight = 0; 74 private int footerNetHeight = 0; 75 private boolean firstBreakBeforeServed = false; 76 77 private int startXOffset; 78 private int usedBPD; 79 80 private TableStepper stepper = new TableStepper(this); 81 82 86 public TableContentLayoutManager(TableLayoutManager parent) { 87 this.tableLM = parent; 88 Table table = getTableLM().getTable(); 89 this.bodyIter = new TableRowIterator(table, getTableLM().getColumns(), 90 TableRowIterator.BODY); 91 if (table.getTableHeader() != null) { 92 headerIter = new TableRowIterator(table, 93 getTableLM().getColumns(), TableRowIterator.HEADER); 94 } 95 if (table.getTableFooter() != null) { 96 footerIter = new TableRowIterator(table, 97 getTableLM().getColumns(), TableRowIterator.FOOTER); 98 } 99 } 100 101 104 public TableLayoutManager getTableLM() { 105 return this.tableLM; 106 } 107 108 109 private boolean isSeparateBorderModel() { 110 return getTableLM().getTable().isSeparateBorderModel(); 111 } 112 113 116 public ColumnSetup getColumns() { 117 return getTableLM().getColumns(); 118 } 119 120 121 protected int getHeaderNetHeight() { 122 return this.headerNetHeight; 123 } 124 125 126 protected int getFooterNetHeight() { 127 return this.footerNetHeight; 128 } 129 130 131 protected LinkedList getHeaderElements() { 132 return this.headerList; 133 } 134 135 136 protected LinkedList getFooterElements() { 137 return this.footerList; 138 } 139 140 141 public LinkedList getNextKnuthElements(LayoutContext context, int alignment) { 142 log.debug("==> Columns: " + getTableLM().getColumns()); 143 KnuthBox headerAsFirst = null; 144 KnuthBox headerAsSecondToLast = null; 145 KnuthBox footerAsLast = null; 146 if (headerIter != null && headerList == null) { 147 this.headerList = getKnuthElementsForRowIterator( 148 headerIter, context, alignment, TableRowIterator.HEADER); 149 ElementListUtils.removeLegalBreaks(this.headerList); 150 this.headerNetHeight 151 = ElementListUtils.calcContentLength(this.headerList); 152 if (log.isDebugEnabled()) { 153 log.debug("==> Header: " 154 + headerNetHeight + " - " + this.headerList); 155 } 156 TableHeaderFooterPosition pos = new TableHeaderFooterPosition( 157 getTableLM(), true, this.headerList); 158 KnuthBox box = new KnuthBox(headerNetHeight, pos, false); 159 if (getTableLM().getTable().omitHeaderAtBreak()) { 160 headerAsFirst = box; 163 } else { 164 headerAsSecondToLast = box; 165 } 166 } 167 if (footerIter != null && footerList == null) { 168 this.footerList = getKnuthElementsForRowIterator( 169 footerIter, context, alignment, TableRowIterator.FOOTER); 170 ElementListUtils.removeLegalBreaks(this.footerList); 171 this.footerNetHeight 172 = ElementListUtils.calcContentLength(this.footerList); 173 if (log.isDebugEnabled()) { 174 log.debug("==> Footer: " 175 + footerNetHeight + " - " + this.footerList); 176 } 177 TableHeaderFooterPosition pos = new TableHeaderFooterPosition( 179 getTableLM(), false, this.footerList); 180 KnuthBox box = new KnuthBox(footerNetHeight, pos, false); 181 footerAsLast = box; 182 } 183 LinkedList returnList = getKnuthElementsForRowIterator( 184 bodyIter, context, alignment, TableRowIterator.BODY); 185 if (headerAsFirst != null) { 186 returnList.add(0, headerAsFirst); 187 } else if (headerAsSecondToLast != null) { 188 returnList.add(headerAsSecondToLast); 189 } 190 if (footerAsLast != null) { 191 returnList.add(footerAsLast); 192 } 193 return returnList; 194 } 195 196 205 private LinkedList getKnuthElementsForRowIterator(TableRowIterator iter, 206 LayoutContext context, int alignment, int bodyType) { 207 LinkedList returnList = new LinkedList (); 208 EffRow[] rowGroup = null; 209 while ((rowGroup = iter.getNextRowGroup()) != null) { 210 TableRow rowFO = rowGroup[0].getTableRow(); 212 if (rowFO != null && rowFO.getBreakBefore() != Constants.EN_AUTO) { 213 log.info("break-before found"); 214 if (returnList.size() > 0) { 215 ListElement last = (ListElement)returnList.getLast(); 216 if (last.isPenalty()) { 217 KnuthPenalty pen = (KnuthPenalty)last; 218 pen.setP(-KnuthPenalty.INFINITE); 219 pen.setBreakClass(rowFO.getBreakBefore()); 220 } else if (last instanceof BreakElement) { 221 BreakElement breakPoss = (BreakElement) last; 222 breakPoss.setPenaltyValue(-KnuthPenalty.INFINITE); 223 breakPoss.setBreakClass(rowFO.getBreakBefore()); 224 } 225 } else { 226 if (!firstBreakBeforeServed) { 227 returnList.add(new BreakElement(new Position(getTableLM()), 228 0, -KnuthPenalty.INFINITE, rowFO.getBreakBefore(), context)); 229 iter.backToPreviousRow(); 230 firstBreakBeforeServed = true; 231 break; 232 } 233 } 234 } 235 firstBreakBeforeServed = true; 236 237 if (!isSeparateBorderModel()) { 239 resolveNormalBeforeAfterBordersForRowGroup(rowGroup, iter); 240 } 241 242 createElementsForRowGroup(context, alignment, bodyType, 244 returnList, rowGroup); 245 246 if (context.isKeepWithNextPending()) { 248 log.debug("child LM (row group) signals pending keep-with-next"); 249 } 250 if (context.isKeepWithPreviousPending()) { 251 log.debug("child LM (row group) signals pending keep-with-previous"); 252 if (returnList.size() > 0) { 253 ListElement last = (ListElement)returnList.getLast(); 255 if (last.isPenalty()) { 256 BreakElement breakPoss = (BreakElement)last; 257 if (!breakPoss.isForcedBreak()) { 259 breakPoss.setPenaltyValue(KnuthPenalty.INFINITE); 260 } 261 } 262 } 263 } 264 265 rowFO = rowGroup[rowGroup.length - 1].getTableRow(); 267 if (rowFO != null && rowFO.getBreakAfter() != Constants.EN_AUTO) { 268 if (returnList.size() > 0) { 269 ListElement last = (ListElement)returnList.getLast(); 270 if (last instanceof KnuthPenalty) { 271 KnuthPenalty pen = (KnuthPenalty)last; 272 pen.setP(-KnuthPenalty.INFINITE); 273 pen.setBreakClass(rowFO.getBreakAfter()); 274 } else if (last instanceof BreakElement) { 275 BreakElement breakPoss = (BreakElement)last; 276 breakPoss.setPenaltyValue(-KnuthPenalty.INFINITE); 277 breakPoss.setBreakClass(rowFO.getBreakAfter()); 278 } 279 } 280 } 281 } 282 283 if (returnList.size() > 0) { 284 ListElement last = (ListElement)returnList.getLast(); 286 if (last.isPenalty() || last instanceof BreakElement) { 287 if (!last.isForcedBreak()) { 288 returnList.removeLast(); 290 } 291 } 292 } 293 294 int widowContentLimit = getTableLM().getTable().getWidowContentLimit().getValue(); 296 if (widowContentLimit != 0 && bodyType == TableRowIterator.BODY) { 297 ElementListUtils.removeLegalBreaks(returnList, widowContentLimit); 298 } 299 int orphanContentLimit = getTableLM().getTable().getOrphanContentLimit().getValue(); 301 if (orphanContentLimit != 0 && bodyType == TableRowIterator.BODY) { 302 ElementListUtils.removeLegalBreaksFromEnd(returnList, orphanContentLimit); 303 } 304 305 return returnList; 306 } 307 308 312 private void resolveNormalBeforeAfterBordersForRowGroup(EffRow[] rowGroup, 313 TableRowIterator iter) { 314 for (int rgi = 0; rgi < rowGroup.length; rgi++) { 315 EffRow row = rowGroup[rgi]; 316 EffRow prevRow = iter.getPrecedingRow(row); 317 EffRow nextRow = iter.getFollowingRow(row); 318 if ((prevRow == null) && (iter == this.bodyIter) && (this.headerIter != null)) { 319 prevRow = this.headerIter.getLastRow(); 320 } 321 if ((nextRow == null) && (iter == this.headerIter)) { 322 nextRow = this.bodyIter.getFirstRow(); 323 } 324 if ((nextRow == null) && (iter == this.bodyIter) && (this.footerIter != null)) { 325 nextRow = this.footerIter.getFirstRow(); 326 } 327 if ((prevRow == null) && (iter == this.footerIter)) { 328 prevRow = this.bodyIter.getLastRow(); 331 } 332 log.debug(prevRow + " - " + row + " - " + nextRow); 333 334 int guCount = row.getGridUnits().size(); 336 if (prevRow != null) { 337 guCount = Math.max(guCount, prevRow.getGridUnits().size()); 338 } 339 if (nextRow != null) { 340 guCount = Math.max(guCount, nextRow.getGridUnits().size()); 341 } 342 GridUnit gu = row.getGridUnit(0); 343 for (int i = 0; i < guCount - row.getGridUnits().size(); i++) { 346 int pos = row.getGridUnits().size() + i; 348 row.getGridUnits().add(new EmptyGridUnit(gu.getRow(), 349 this.tableLM.getColumns().getColumn(pos + 1), gu.getBody(), 350 pos)); 351 } 352 353 if (getTableLM().getTable().isSeparateBorderModel()) { 355 } else { 357 for (int i = 0; i < row.getGridUnits().size(); i++) { 358 gu = row.getGridUnit(i); 359 GridUnit other; 360 int flags = 0; 361 if (prevRow != null && i < prevRow.getGridUnits().size()) { 362 other = prevRow.getGridUnit(i); 363 } else { 364 other = null; 365 } 366 if (other == null 367 || other.isEmpty() 368 || gu.isEmpty() 369 || gu.getPrimary() != other.getPrimary()) { 370 if ((iter == this.bodyIter) 371 && gu.getFlag(GridUnit.FIRST_IN_TABLE) 372 && (this.headerIter == null)) { 373 flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE; 374 } 375 if ((iter == this.headerIter) 376 && gu.getFlag(GridUnit.FIRST_IN_TABLE)) { 377 flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE; 378 } 379 gu.resolveBorder(other, 380 CommonBorderPaddingBackground.BEFORE, flags); 381 } 382 383 flags = 0; 384 if (nextRow != null && i < nextRow.getGridUnits().size()) { 385 other = nextRow.getGridUnit(i); 386 } else { 387 other = null; 388 } 389 if (other == null 390 || other.isEmpty() 391 || gu.isEmpty() 392 || gu.getPrimary() != other.getPrimary()) { 393 if ((iter == this.bodyIter) 394 && gu.getFlag(GridUnit.LAST_IN_TABLE) 395 && (this.footerIter == null)) { 396 flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE; 397 } 398 if ((iter == this.footerIter) 399 && gu.getFlag(GridUnit.LAST_IN_TABLE)) { 400 flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE; 401 } 402 gu.resolveBorder(other, 403 CommonBorderPaddingBackground.AFTER, flags); 404 } 405 } 406 407 } 408 } 409 } 410 411 419 private void createElementsForRowGroup(LayoutContext context, int alignment, 420 int bodyType, LinkedList returnList, 421 EffRow[] rowGroup) { 422 log.debug("Handling row group with " + rowGroup.length + " rows..."); 423 MinOptMax[] rowHeights = new MinOptMax[rowGroup.length]; 424 MinOptMax[] explicitRowHeights = new MinOptMax[rowGroup.length]; 425 EffRow row; 426 int maxColumnCount = 0; 427 List pgus = new java.util.ArrayList (); for (int rgi = 0; rgi < rowGroup.length; rgi++) { 429 row = rowGroup[rgi]; 430 rowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE); 431 explicitRowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE); 432 433 pgus.clear(); 434 TableRow tableRow = null; 435 int minContentHeight = 0; 436 int maxCellHeight = 0; 437 int effRowContentHeight = 0; 438 for (int j = 0; j < row.getGridUnits().size(); j++) { 439 maxColumnCount = Math.max(maxColumnCount, row.getGridUnits().size()); 440 GridUnit gu = row.getGridUnit(j); 441 if ((gu.isPrimary() || (gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan())) 442 && !gu.isEmpty()) { 443 PrimaryGridUnit primary = gu.getPrimary(); 444 445 if (gu.isPrimary()) { 446 primary.getCellLM().setParent(getTableLM()); 447 448 if (tableRow == null && primary.getRow() != null) { 450 tableRow = primary.getRow(); 451 452 LengthRangeProperty bpd = tableRow.getBlockProgressionDimension(); 454 if (!bpd.getMinimum(getTableLM()).isAuto()) { 455 minContentHeight = Math.max( 456 minContentHeight, 457 bpd.getMinimum( 458 getTableLM()).getLength().getValue(getTableLM())); 459 } 460 MinOptMaxUtil.restrict(explicitRowHeights[rgi], bpd, getTableLM()); 461 462 } 463 464 int spanWidth = 0; 466 for (int i = primary.getStartCol(); 467 i < primary.getStartCol() 468 + primary.getCell().getNumberColumnsSpanned(); 469 i++) { 470 if (getTableLM().getColumns().getColumn(i + 1) != null) { 471 spanWidth += getTableLM().getColumns().getColumn(i + 1) 472 .getColumnWidth().getValue(getTableLM()); 473 } 474 } 475 LayoutContext childLC = new LayoutContext(0); 476 childLC.setStackLimit(context.getStackLimit()); childLC.setRefIPD(spanWidth); 478 479 LinkedList elems = primary.getCellLM().getNextKnuthElements( 481 childLC, alignment); 482 while (!primary.getCellLM().isFinished()) { 485 LinkedList additionalElems = primary.getCellLM().getNextKnuthElements( 486 childLC, alignment); 487 elems.addAll(additionalElems); 488 } 489 ElementListObserver.observe(elems, "table-cell", primary.getCell().getId()); 490 491 if ((elems.size() > 0) 492 && ((KnuthElement)elems.getLast()).isForcedBreak()) { 493 log.debug("Descendant of table-cell signals break: " 495 + primary.getCellLM().isFinished()); 496 } 497 498 primary.setElements(elems); 499 500 if (childLC.isKeepWithNextPending()) { 501 log.debug("child LM signals pending keep-with-next"); 502 primary.setFlag(GridUnit.KEEP_WITH_NEXT_PENDING, true); 503 } 504 if (childLC.isKeepWithPreviousPending()) { 505 log.debug("child LM signals pending keep-with-previous"); 506 primary.setFlag(GridUnit.KEEP_WITH_PREVIOUS_PENDING, true); 507 } 508 } 509 510 511 primary.setContentLength(ElementListUtils.calcContentLength( 513 primary.getElements())); 514 maxCellHeight = Math.max(maxCellHeight, primary.getContentLength()); 515 516 if (gu.isLastGridUnitRowSpan()) { 518 int effCellContentHeight = minContentHeight; 519 LengthRangeProperty bpd = primary.getCell().getBlockProgressionDimension(); 520 if (!bpd.getMinimum(getTableLM()).isAuto()) { 521 effCellContentHeight = Math.max( 522 effCellContentHeight, 523 bpd.getMinimum(getTableLM()).getLength().getValue(getTableLM())); 524 } 525 if (!bpd.getOptimum(getTableLM()).isAuto()) { 526 effCellContentHeight = Math.max( 527 effCellContentHeight, 528 bpd.getOptimum(getTableLM()).getLength().getValue(getTableLM())); 529 } 530 if (gu.getRowSpanIndex() == 0) { 531 MinOptMaxUtil.restrict(explicitRowHeights[rgi], bpd, tableLM); 533 } 534 effCellContentHeight = Math.max(effCellContentHeight, 535 primary.getContentLength()); 536 537 int borderWidths; 538 if (isSeparateBorderModel()) { 539 borderWidths = primary.getBorders().getBorderBeforeWidth(false) 540 + primary.getBorders().getBorderAfterWidth(false); 541 } else { 542 borderWidths = primary.getHalfMaxBorderWidth(); 543 } 544 int padding = 0; 545 effRowContentHeight = Math.max(effRowContentHeight, 546 effCellContentHeight); 547 CommonBorderPaddingBackground cbpb 548 = primary.getCell().getCommonBorderPaddingBackground(); 549 padding += cbpb.getPaddingBefore(false, primary.getCellLM()); 550 padding += cbpb.getPaddingAfter(false, primary.getCellLM()); 551 int effRowHeight = effCellContentHeight 552 + padding + borderWidths 553 + 2 * getTableLM().getHalfBorderSeparationBPD(); 554 for (int previous = 0; previous < gu.getRowSpanIndex(); previous++) { 555 effRowHeight -= rowHeights[rgi - previous - 1].opt; 556 } 557 if (effRowHeight > rowHeights[rgi].min) { 558 MinOptMaxUtil.extendMinimum(rowHeights[rgi], effRowHeight, false); 560 } 561 } 562 563 if (gu.isPrimary()) { 564 pgus.add(primary); 565 } 566 } 567 } 568 569 row.setHeight(rowHeights[rgi]); 570 row.setExplicitHeight(explicitRowHeights[rgi]); 571 if (effRowContentHeight > row.getExplicitHeight().max) { 572 log.warn(FONode.decorateWithContextInfo( 573 "The contents of row " + (row.getIndex() + 1) 574 + " are taller than they should be (there is a" 575 + " block-progression-dimension or height constraint on the indicated row)." 576 + " Due to its contents the row grows" 577 + " to " + effRowContentHeight + " millipoints, but the row shouldn't get" 578 + " any taller than " + row.getExplicitHeight() + " millipoints.", 579 row.getTableRow())); 580 } 581 } 582 if (log.isDebugEnabled()) { 583 log.debug("rowGroup:"); 584 for (int i = 0; i < rowHeights.length; i++) { 585 log.debug(" height=" + rowHeights[i] + " explicit=" + explicitRowHeights[i]); 586 } 587 } 588 LinkedList returnedList = this.stepper.getCombinedKnuthElementsForRowGroup( 589 context, rowGroup, maxColumnCount, bodyType); 590 if (returnedList != null) { 591 returnList.addAll(returnedList); 592 } 593 594 } 595 596 601 protected int getXOffsetOfGridUnit(GridUnit gu) { 602 int col = gu.getStartCol(); 603 return startXOffset + getTableLM().getColumns().getXOffset(col + 1, getTableLM()); 604 } 605 606 611 public void addAreas(PositionIterator parentIter, LayoutContext layoutContext) { 612 this.usedBPD = 0; 613 RowPainter painter = new RowPainter(layoutContext); 614 615 List positions = new java.util.ArrayList (); 616 List headerElements = null; 617 List footerElements = null; 618 int nestedPenaltyArea = 0; 619 Position firstPos = null; 620 Position lastPos = null; 621 Position lastCheckPos = null; 622 while (parentIter.hasNext()) { 623 Position pos = (Position)parentIter.next(); 624 if (pos instanceof SpaceHandlingBreakPosition) { 625 pos = ((SpaceHandlingBreakPosition)pos).getOriginalBreakPosition(); 628 } 629 if (pos == null) { 630 continue; 631 } 632 if (firstPos == null) { 633 firstPos = pos; 634 } 635 lastPos = pos; 636 if (pos.getIndex() >= 0) { 637 lastCheckPos = pos; 638 } 639 if (pos instanceof TableHeaderFooterPosition) { 640 TableHeaderFooterPosition thfpos = (TableHeaderFooterPosition)pos; 641 if (thfpos.header) { 643 headerElements = thfpos.nestedElements; 645 } else { 646 footerElements = thfpos.nestedElements; 648 } 649 } else if (pos instanceof TableHFPenaltyPosition) { 650 } else { 653 positions.add(pos); 655 } 656 } 657 if (lastPos instanceof TableHFPenaltyPosition) { 658 TableHFPenaltyPosition penaltyPos = (TableHFPenaltyPosition)lastPos; 659 log.debug("Break at penalty!"); 660 if (penaltyPos.headerElements != null) { 661 headerElements = penaltyPos.headerElements; 664 } 665 if (penaltyPos.footerElements != null) { 666 footerElements = penaltyPos.footerElements; 667 } 668 nestedPenaltyArea = penaltyPos.nestedPenaltyLength; 669 } 670 671 Map markers = getTableLM().getTable().getMarkers(); 672 if (markers != null) { 673 getTableLM().getCurrentPV().addMarkers(markers, 674 true, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); 675 } 676 677 if (headerElements != null) { 678 PositionIterator nestedIter = new KnuthPossPosIter(headerElements); 681 iterateAndPaintPositions(nestedIter, painter); 682 painter.addAreasAndFlushRow(true); 683 } 684 685 Iterator posIter = positions.iterator(); 687 iterateAndPaintPositions(posIter, painter); 688 painter.addAreasAndFlushRow(true); 689 690 painter.notifyNestedPenaltyArea(nestedPenaltyArea); 691 if (footerElements != null) { 692 PositionIterator nestedIter = new KnuthPossPosIter(footerElements); 694 iterateAndPaintPositions(nestedIter, painter); 695 painter.addAreasAndFlushRow(true); 696 } 697 698 painter.notifyEndOfSequence(); 699 this.usedBPD += painter.getAccumulatedBPD(); 700 701 if (markers != null) { 702 getTableLM().getCurrentPV().addMarkers(markers, 703 false, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); 704 } 705 } 706 707 private void iterateAndPaintPositions(Iterator iterator, RowPainter painter) { 708 List lst = new java.util.ArrayList (); 709 boolean firstPos = false; 710 boolean lastPos = false; 711 TableBody body = null; 712 while (iterator.hasNext()) { 713 Position pos = (Position)iterator.next(); 714 if (pos instanceof TableContentPosition) { 715 TableContentPosition tcpos = (TableContentPosition)pos; 716 lst.add(tcpos); 717 GridUnitPart part = (GridUnitPart)tcpos.gridUnitParts.get(0); 718 if (body == null) { 719 body = part.pgu.getBody(); 720 } 721 if (tcpos.getFlag(TableContentPosition.FIRST_IN_ROWGROUP) 722 && tcpos.row.getFlag(EffRow.FIRST_IN_PART)) { 723 firstPos = true; 724 725 } 726 if (tcpos.getFlag(TableContentPosition.LAST_IN_ROWGROUP) 727 && tcpos.row.getFlag(EffRow.LAST_IN_PART)) { 728 lastPos = true; 729 getTableLM().getCurrentPV().addMarkers(body.getMarkers(), 730 true, firstPos, lastPos); 731 int size = lst.size(); 732 for (int i = 0; i < size; i++) { 733 painter.handleTableContentPosition((TableContentPosition)lst.get(i)); 734 } 735 getTableLM().getCurrentPV().addMarkers(body.getMarkers(), 736 false, firstPos, lastPos); 737 firstPos = false; 739 lastPos = false; 740 body = null; 741 lst.clear(); 742 } 743 } else { 744 if (log.isDebugEnabled()) { 745 log.debug("Ignoring position: " + pos); 746 } 747 } 748 } 749 if (body != null) { 750 getTableLM().getCurrentPV().addMarkers(body.getMarkers(), 751 true, firstPos, lastPos); 752 int size = lst.size(); 753 for (int i = 0; i < size; i++) { 754 painter.handleTableContentPosition((TableContentPosition)lst.get(i)); 755 } 756 getTableLM().getCurrentPV().addMarkers(body.getMarkers(), 757 false, firstPos, lastPos); 758 } 759 } 760 761 private class RowPainter { 762 763 private TableRow rowFO = null; 764 private int colCount = getColumns().getColumnCount(); 765 private int yoffset = 0; 766 private int accumulatedBPD = 0; 767 private EffRow lastRow = null; 768 private LayoutContext layoutContext; 769 private int lastRowHeight = 0; 770 private int[] firstRow = new int[3]; 771 private Map [] rowOffsets = new Map [] {new java.util.HashMap (), 772 new java.util.HashMap (), new java.util.HashMap ()}; 773 774 private PrimaryGridUnit[] gridUnits = new PrimaryGridUnit[colCount]; 776 private int[] start = new int[colCount]; 777 private int[] end = new int[colCount]; 778 private int[] partLength = new int[colCount]; 779 780 public RowPainter(LayoutContext layoutContext) { 781 this.layoutContext = layoutContext; 782 Arrays.fill(firstRow, -1); 783 Arrays.fill(end, -1); 784 } 785 786 public int getAccumulatedBPD() { 787 return this.accumulatedBPD; 788 } 789 790 public void notifyEndOfSequence() { 791 this.accumulatedBPD += lastRowHeight; } 793 794 public void notifyNestedPenaltyArea(int length) { 795 this.lastRowHeight += length; 796 } 797 798 public void handleTableContentPosition(TableContentPosition tcpos) { 799 if (lastRow != tcpos.row && lastRow != null) { 800 addAreasAndFlushRow(false); 801 yoffset += lastRowHeight; 802 this.accumulatedBPD += lastRowHeight; 803 } 804 if (log.isDebugEnabled()) { 805 log.debug("===handleTableContentPosition(" + tcpos); 806 } 807 rowFO = tcpos.row.getTableRow(); 808 lastRow = tcpos.row; 809 Iterator partIter = tcpos.gridUnitParts.iterator(); 810 while (partIter.hasNext()) { 812 GridUnitPart gup = (GridUnitPart)partIter.next(); 813 if (log.isDebugEnabled()) { 814 log.debug(">" + gup); 815 } 816 int colIndex = gup.pgu.getStartCol(); 817 if (gridUnits[colIndex] != gup.pgu) { 818 if (gridUnits[colIndex] != null) { 819 log.warn("Replacing GU in slot " + colIndex 820 + ". Some content may not be painted."); 821 } 822 gridUnits[colIndex] = gup.pgu; 823 start[colIndex] = gup.start; 824 end[colIndex] = gup.end; 825 } else { 826 if (gup.end < end[colIndex]) { 827 throw new IllegalStateException ("Internal Error: stepper problem"); 828 } 829 end[colIndex] = gup.end; 830 } 831 } 832 } 833 834 public int addAreasAndFlushRow(boolean forcedFlush) { 835 int actualRowHeight = 0; 836 int readyCount = 0; 837 838 int bt = lastRow.getBodyType(); 839 if (log.isDebugEnabled()) { 840 log.debug("Remembering yoffset for row " + lastRow.getIndex() + ": " + yoffset); 841 } 842 rowOffsets[bt].put(new Integer (lastRow.getIndex()), new Integer (yoffset)); 843 844 for (int i = 0; i < gridUnits.length; i++) { 845 if ((gridUnits[i] != null) 846 && (forcedFlush || (end[i] == gridUnits[i].getElements().size() - 1))) { 847 if (log.isTraceEnabled()) { 848 log.trace("getting len for " + i + " " 849 + start[i] + "-" + end[i]); 850 } 851 readyCount++; 852 int len = ElementListUtils.calcContentLength( 853 gridUnits[i].getElements(), start[i], end[i]); 854 partLength[i] = len; 855 if (log.isTraceEnabled()) { 856 log.trace("len of part: " + len); 857 } 858 859 if (start[i] == 0) { 860 LengthRangeProperty bpd = gridUnits[i].getCell() 861 .getBlockProgressionDimension(); 862 if (!bpd.getMinimum(getTableLM()).isAuto()) { 863 int min = bpd.getMinimum(getTableLM()) 864 .getLength().getValue(getTableLM()); 865 if (min > 0) { 866 len = Math.max(len, bpd.getMinimum(getTableLM()) 867 .getLength().getValue(getTableLM())); 868 } 869 } 870 if (!bpd.getOptimum(getTableLM()).isAuto()) { 871 int opt = bpd.getOptimum(getTableLM()) 872 .getLength().getValue(getTableLM()); 873 if (opt > 0) { 874 len = Math.max(len, opt); 875 } 876 } 877 if (gridUnits[i].getRow() != null) { 878 bpd = gridUnits[i].getRow().getBlockProgressionDimension(); 879 if (!bpd.getMinimum(getTableLM()).isAuto()) { 880 int min = bpd.getMinimum(getTableLM()).getLength() 881 .getValue(getTableLM()); 882 if (min > 0) { 883 len = Math.max(len, min); 884 } 885 } 886 } 887 } 888 889 len += gridUnits[i].getBorders() 891 .getPaddingBefore(false, gridUnits[i].getCellLM()); 892 len += gridUnits[i].getBorders() 893 .getPaddingAfter(false, gridUnits[i].getCellLM()); 894 895 if (isSeparateBorderModel()) { 897 len += gridUnits[i].getBorders().getBorderBeforeWidth(false); 898 len += gridUnits[i].getBorders().getBorderAfterWidth(false); 899 } 900 int startRow = Math.max(gridUnits[i].getStartRow(), firstRow[bt]); 901 Integer storedOffset = (Integer )rowOffsets[bt].get(new Integer (startRow)); 902 int effYOffset; 903 if (storedOffset != null) { 904 effYOffset = storedOffset.intValue(); 905 } else { 906 effYOffset = yoffset; 907 } 908 len -= yoffset - effYOffset; 909 actualRowHeight = Math.max(actualRowHeight, len); 910 } 911 } 912 if (readyCount == 0) { 913 return 0; 914 } 915 actualRowHeight += 2 * getTableLM().getHalfBorderSeparationBPD(); 916 lastRowHeight = actualRowHeight; 917 918 addRowBackgroundArea(rowFO, actualRowHeight, layoutContext.getRefIPD(), yoffset); 920 for (int i = 0; i < gridUnits.length; i++) { 921 GridUnit currentGU = lastRow.safelyGetGridUnit(i); 922 if ((gridUnits[i] != null) 923 && (forcedFlush || ((end[i] == gridUnits[i].getElements().size() - 1)) 924 && (currentGU == null || currentGU.isLastGridUnitRowSpan())) 925 || (gridUnits[i] == null && currentGU != null)) { 926 if (log.isDebugEnabled()) { 931 log.debug((forcedFlush ? "FORCED " : "") + "flushing..." + i + " " 932 + start[i] + "-" + end[i]); 933 } 934 PrimaryGridUnit gu = gridUnits[i]; 935 if (gu == null 936 && !currentGU.isEmpty() 937 && currentGU.getColSpanIndex() == 0 938 && currentGU.isLastGridUnitColSpan() 939 && (forcedFlush || currentGU.isLastGridUnitRowSpan())) { 940 gu = currentGU.getPrimary(); 941 } 942 if (gu != null) { 943 addAreasForCell(gu, start[i], end[i], 944 lastRow, 945 partLength[i], actualRowHeight); 946 gridUnits[i] = null; 947 start[i] = 0; 948 end[i] = -1; 949 partLength[i] = 0; 950 } 951 } 952 } 953 return actualRowHeight; 954 } 955 956 private void addAreasForCell(PrimaryGridUnit pgu, int startPos, int endPos, 957 EffRow row, int contentHeight, int rowHeight) { 958 int bt = row.getBodyType(); 959 if (firstRow[bt] < 0) { 960 firstRow[bt] = row.getIndex(); 961 } 962 int startRow = Math.max(pgu.getStartRow(), firstRow[bt]); 964 Integer offset = (Integer )rowOffsets[bt].get(new Integer (startRow)); 966 while (offset == null) { 967 startRow--; 968 offset = (Integer )rowOffsets[bt].get(new Integer (startRow)); 969 } 970 int effYOffset = offset.intValue(); 971 int effCellHeight = rowHeight; 972 effCellHeight += yoffset - effYOffset; 973 if (log.isDebugEnabled()) { 974 log.debug("Creating area for cell:"); 975 log.debug(" current row: " + row.getIndex()); 976 log.debug(" start row: " + pgu.getStartRow() + " " + yoffset + " " + effYOffset); 977 log.debug(" contentHeight: " + contentHeight + " rowHeight=" + rowHeight 978 + " effCellHeight=" + effCellHeight); 979 } 980 TableCellLayoutManager cellLM = pgu.getCellLM(); 981 cellLM.setXOffset(getXOffsetOfGridUnit(pgu)); 982 cellLM.setYOffset(effYOffset); 983 cellLM.setContentHeight(contentHeight); 984 cellLM.setRowHeight(effCellHeight); 985 int prevBreak = ElementListUtils.determinePreviousBreak(pgu.getElements(), startPos); 987 if (endPos >= 0) { 988 SpaceResolver.performConditionalsNotification(pgu.getElements(), 989 startPos, endPos, prevBreak); 990 } 991 cellLM.addAreas(new KnuthPossPosIter(pgu.getElements(), 992 startPos, endPos + 1), layoutContext); 993 } 994 995 } 996 997 1002 public Block getRowArea(TableRow row) { 1003 if (row == null || !row.getCommonBorderPaddingBackground().hasBackground()) { 1004 return null; 1005 } else { 1006 Block block = new Block(); 1007 block.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE); 1008 block.setPositioning(Block.ABSOLUTE); 1009 return block; 1010 } 1011 } 1012 1013 1020 public void addRowBackgroundArea(TableRow row, int bpd, int ipd, int yoffset) { 1021 Block rowBackground = getRowArea(row); 1023 if (rowBackground != null) { 1024 rowBackground.setBPD(bpd); 1025 rowBackground.setIPD(ipd); 1026 rowBackground.setXOffset(this.startXOffset); 1027 rowBackground.setYOffset(yoffset); 1028 getTableLM().addChildArea(rowBackground); 1029 TraitSetter.addBackground(rowBackground, 1030 row.getCommonBorderPaddingBackground(), getTableLM()); 1031 } 1032 } 1033 1034 1035 1039 public void setStartXOffset(int startXOffset) { 1040 this.startXOffset = startXOffset; 1041 } 1042 1043 1046 public int getUsedBPD() { 1047 return this.usedBPD; 1048 } 1049 1050 1053 protected static class GridUnitPart { 1054 1055 1056 protected PrimaryGridUnit pgu; 1057 1058 protected int start; 1059 1060 protected int end; 1061 1062 1068 protected GridUnitPart(PrimaryGridUnit pgu, int start, int end) { 1069 this.pgu = pgu; 1070 this.start = start; 1071 this.end = end; 1072 } 1073 1074 1075 public boolean isFirstPart() { 1076 return (start == 0); 1077 } 1078 1079 1080 public boolean isLastPart() { 1081 return (end >= 0 && end == pgu.getElements().size() - 1); 1082 } 1083 1084 1085 public String toString() { 1086 StringBuffer sb = new StringBuffer ("Part: "); 1087 sb.append(start).append("-").append(end); 1088 sb.append(" [").append(isFirstPart() ? "F" : "-").append(isLastPart() ? "L" : "-"); 1089 sb.append("] ").append(pgu); 1090 return sb.toString(); 1091 } 1092 1093 } 1094 1095 1099 public static class TableContentPosition extends Position { 1100 1101 1102 public static final int FIRST_IN_ROWGROUP = 1; 1103 1104 public static final int LAST_IN_ROWGROUP = 2; 1105 1106 1107 protected List gridUnitParts; 1108 1109 protected EffRow row; 1110 1111 protected int flags; 1112 1113 1119 protected TableContentPosition(LayoutManager lm, List gridUnitParts, 1120 EffRow row) { 1121 super(lm); 1122 this.gridUnitParts = gridUnitParts; 1123 this.row = row; 1124 } 1125 1126 1131 public boolean getFlag(int which) { 1132 return (flags & (1 << which)) != 0; 1133 } 1134 1135 1140 public void setFlag(int which, boolean value) { 1141 if (value) { 1142 flags |= (1 << which); } else { 1144 flags &= ~(1 << which); } 1146 } 1147 1148 1149 public boolean generatesAreas() { 1150 return true; 1151 } 1152 1153 1154 public String toString() { 1155 StringBuffer sb = new StringBuffer ("TableContentPosition:"); 1156 sb.append(getIndex()); 1157 sb.append("["); 1158 sb.append(row.getIndex()).append("/"); 1159 sb.append(getFlag(FIRST_IN_ROWGROUP) ? "F" : "-"); 1160 sb.append(getFlag(LAST_IN_ROWGROUP) ? "L" : "-").append("]"); 1161 sb.append("("); 1162 sb.append(gridUnitParts); 1163 sb.append(")"); 1164 return sb.toString(); 1165 } 1166 } 1167 1168 1172 public static class TableHeaderFooterPosition extends Position { 1173 1174 1175 protected boolean header; 1176 1177 protected List nestedElements; 1178 1179 1185 protected TableHeaderFooterPosition(LayoutManager lm, 1186 boolean header, List nestedElements) { 1187 super(lm); 1188 this.header = header; 1189 this.nestedElements = nestedElements; 1190 } 1191 1192 1193 public String toString() { 1194 StringBuffer sb = new StringBuffer ("Table"); 1195 sb.append(header ? "Header" : "Footer"); 1196 sb.append("Position:"); 1197 sb.append(getIndex()).append("("); 1198 sb.append(nestedElements); 1199 sb.append(")"); 1200 return sb.toString(); 1201 } 1202 } 1203 1204 1208 public static class TableHFPenaltyPosition extends Position { 1209 1210 1211 protected List headerElements; 1212 1213 protected List footerElements; 1214 1215 protected int nestedPenaltyLength; 1216 1217 1221 protected TableHFPenaltyPosition(LayoutManager lm) { 1222 super(lm); 1223 } 1224 1225 1226 public String toString() { 1227 StringBuffer sb = new StringBuffer ("TableHFPenaltyPosition:"); 1228 sb.append(getIndex()).append("("); 1229 sb.append("header:"); 1230 sb.append(headerElements); 1231 sb.append(", footer:"); 1232 sb.append(footerElements); 1233 sb.append(", inner penalty length:"); 1234 sb.append(nestedPenaltyLength); 1235 sb.append(")"); 1236 return sb.toString(); 1237 } 1238 } 1239 1240 1242 1245 public int getBaseLength(int lengthBase, FObj fobj) { 1246 return tableLM.getBaseLength(lengthBase, fobj); 1247 } 1248 1249} 1250 | Popular Tags |