123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.layoutmgr.table;
-
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
-
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
-
- import org.apache.fop.area.Area;
- import org.apache.fop.area.Block;
- import org.apache.fop.area.Trait;
- import org.apache.fop.fo.flow.Marker;
- import org.apache.fop.fo.flow.table.ConditionalBorder;
- import org.apache.fop.fo.flow.table.GridUnit;
- import org.apache.fop.fo.flow.table.PrimaryGridUnit;
- import org.apache.fop.fo.flow.table.Table;
- import org.apache.fop.fo.flow.table.TableCell;
- import org.apache.fop.fo.flow.table.TableColumn;
- import org.apache.fop.fo.flow.table.TableFooter;
- import org.apache.fop.fo.flow.table.TableHeader;
- import org.apache.fop.fo.flow.table.TablePart;
- import org.apache.fop.fo.flow.table.TableRow;
- import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
- import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
- import org.apache.fop.layoutmgr.AbstractLayoutManager;
- import org.apache.fop.layoutmgr.AreaAdditionUtil;
- import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
- import org.apache.fop.layoutmgr.ElementListObserver;
- import org.apache.fop.layoutmgr.ElementListUtils;
- import org.apache.fop.layoutmgr.Keep;
- import org.apache.fop.layoutmgr.KnuthBox;
- import org.apache.fop.layoutmgr.KnuthElement;
- import org.apache.fop.layoutmgr.KnuthGlue;
- import org.apache.fop.layoutmgr.KnuthPenalty;
- import org.apache.fop.layoutmgr.LayoutContext;
- import org.apache.fop.layoutmgr.LayoutManager;
- import org.apache.fop.layoutmgr.LocalBreaker;
- import org.apache.fop.layoutmgr.Position;
- import org.apache.fop.layoutmgr.PositionIterator;
- import org.apache.fop.layoutmgr.RetrieveTableMarkerLayoutManager;
- import org.apache.fop.layoutmgr.SpaceResolver;
- import org.apache.fop.layoutmgr.TraitSetter;
- import org.apache.fop.traits.BorderProps;
- import org.apache.fop.traits.MinOptMax;
- import org.apache.fop.util.ListUtil;
-
- /**
- * LayoutManager for a table-cell FO.
- * A cell contains blocks. These blocks fill the cell.
- */
- public class TableCellLayoutManager extends BlockStackingLayoutManager {
-
- /**
- * logging instance
- */
- private static Log log = LogFactory.getLog(TableCellLayoutManager.class);
-
- private PrimaryGridUnit primaryGridUnit;
-
- private Block curBlockArea;
-
- private int xoffset;
- private int yoffset;
- private int cellIPD;
- private int totalHeight;
- private int usedBPD;
- private boolean emptyCell = true;
- private boolean isDescendantOfTableFooter;
- private boolean isDescendantOfTableHeader;
- private boolean hasRetrieveTableMarker;
- private boolean hasRepeatedHeader;
-
- // place holder for the addAreas arguments
- private boolean savedAddAreasArguments;
- private PositionIterator savedParentIter;
- private LayoutContext savedLayoutContext;
- private int[] savedSpannedGridRowHeights;
- private int savedStartRow;
- private int savedEndRow;
- private int savedBorderBeforeWhich;
- private int savedBorderAfterWhich;
- private boolean savedFirstOnPage;
- private boolean savedLastOnPage;
- private RowPainter savedPainter;
- private int savedFirstRowHeight;
- // this is set to false when the table-cell has a retrieve-table-marker and is in the table-header
- private boolean flushArea = true;
-
- // this information is set by the RowPainter
- private boolean isLastTrait;
-
- /**
- * Create a new Cell layout manager.
- * @param node table-cell FO for which to create the LM
- * @param pgu primary grid unit for the cell
- */
- public TableCellLayoutManager(TableCell node, PrimaryGridUnit pgu) {
- super(node);
- setGeneratesBlockArea(true);
- this.primaryGridUnit = pgu;
- this.isDescendantOfTableHeader = node.getParent().getParent() instanceof TableHeader
- || node.getParent() instanceof TableHeader;
- this.isDescendantOfTableFooter = node.getParent().getParent() instanceof TableFooter
- || node.getParent() instanceof TableFooter;
- this.hasRetrieveTableMarker = node.hasRetrieveTableMarker();
- }
-
- /** @return the table-cell FO */
- public TableCell getTableCell() {
- return (TableCell)this.fobj;
- }
-
- private boolean isSeparateBorderModel() {
- return getTable().isSeparateBorderModel();
- }
-
- /**
- * @return the table owning this cell
- */
- public Table getTable() {
- return getTableCell().getTable();
- }
-
- public void setHasRepeatedHeader(boolean hasRepeatedHeader) {
- this.hasRepeatedHeader = hasRepeatedHeader;
- }
-
- /** {@inheritDoc} */
- protected int getIPIndents() {
- int[] startEndBorderWidths = primaryGridUnit.getStartEndBorderWidths();
- startIndent = startEndBorderWidths[0];
- endIndent = startEndBorderWidths[1];
- if (isSeparateBorderModel()) {
- int borderSep = getTable().getBorderSeparation().getLengthPair().getIPD().getLength()
- .getValue(this);
- startIndent += borderSep / 2;
- endIndent += borderSep / 2;
- } else {
- startIndent /= 2;
- endIndent /= 2;
- }
- startIndent += getTableCell().getCommonBorderPaddingBackground().getPaddingStart(false,
- this);
- endIndent += getTableCell().getCommonBorderPaddingBackground().getPaddingEnd(false, this);
- return startIndent + endIndent;
- }
-
- /**
- * {@inheritDoc}
- */
- public List getNextKnuthElements(LayoutContext context, int alignment) {
- MinOptMax stackLimit = context.getStackLimitBP();
-
- referenceIPD = context.getRefIPD();
- cellIPD = referenceIPD;
- cellIPD -= getIPIndents();
-
- List returnedList;
- List contentList = new LinkedList();
- List returnList = new LinkedList();
-
- LayoutManager curLM; // currently active LM
- LayoutManager prevLM = null; // previously active LM
- while ((curLM = getChildLM()) != null) {
- LayoutContext childLC = LayoutContext.newInstance();
- // curLM is a ?
- childLC.setStackLimitBP(context.getStackLimitBP().minus(stackLimit));
- childLC.setRefIPD(cellIPD);
-
- // get elements from curLM
- returnedList = curLM.getNextKnuthElements(childLC, alignment);
- if (childLC.isKeepWithNextPending()) {
- log.debug("child LM signals pending keep with next");
- }
- if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
- primaryGridUnit.setKeepWithPrevious(childLC.getKeepWithPreviousPending());
- childLC.clearKeepWithPreviousPending();
- }
-
- if (prevLM != null
- && !ElementListUtils.endsWithForcedBreak(contentList)) {
- // there is a block handled by prevLM
- // before the one handled by curLM
- addInBetweenBreak(contentList, context, childLC);
- }
- contentList.addAll(returnedList);
- if (returnedList.isEmpty()) {
- //Avoid NoSuchElementException below (happens with empty blocks)
- continue;
- }
- if (childLC.isKeepWithNextPending()) {
- //Clear and propagate
- context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
- childLC.clearKeepWithNextPending();
- }
- prevLM = curLM;
- }
- primaryGridUnit.setKeepWithNext(context.getKeepWithNextPending());
-
- returnedList = new LinkedList();
- if (!contentList.isEmpty()) {
- wrapPositionElements(contentList, returnList);
- } else {
- // In relaxed validation mode, table-cells having no children are authorised.
- // Add a zero-width block here to not have to take this special case into
- // account later
- // Copied from BlockStackingLM
- returnList.add(new KnuthBox(0, notifyPos(new Position(this)), true));
- }
- //Space resolution
- SpaceResolver.resolveElementList(returnList);
- if (((KnuthElement) returnList.get(0)).isForcedBreak()) {
- primaryGridUnit.setBreakBefore(((KnuthPenalty) returnList.get(0)).getBreakClass());
- returnList.remove(0);
- assert !returnList.isEmpty();
- }
- final KnuthElement lastItem = (KnuthElement) ListUtil
- .getLast(returnList);
- if (lastItem.isForcedBreak()) {
- KnuthPenalty p = (KnuthPenalty) lastItem;
- primaryGridUnit.setBreakAfter(p.getBreakClass());
- p.setPenalty(0);
- }
-
- setFinished(true);
- return returnList;
- }
-
- /**
- * Set the y offset of this cell.
- * This offset is used to set the absolute position of the cell.
- *
- * @param off the y direction offset
- */
- public void setYOffset(int off) {
- yoffset = off;
- }
-
- /**
- * Set the x offset of this cell (usually the same as its parent row).
- * This offset is used to determine the absolute position of the cell.
- *
- * @param off the x offset
- */
- public void setXOffset(int off) {
- xoffset = off;
- }
-
- /**
- * Set the content height for this cell. This method is used during
- * addAreas() stage.
- *
- * @param h the height of the contents of this cell
- */
- public void setContentHeight(int h) {
- usedBPD = h;
- }
-
- /**
- * Sets the total height of this cell on the current page. That is, the cell's bpd
- * plus before and after borders and paddings, plus the table's border-separation.
- *
- * @param h the height of cell
- */
- public void setTotalHeight(int h) {
- totalHeight = h;
- }
-
- private void clearRetrieveTableMarkerChildNodes(List<LayoutManager> childrenLMs) {
- if (childrenLMs == null) {
- return;
- }
- int n = childrenLMs.size();
- for (LayoutManager lm : childrenLMs) {
- if (lm == null) {
- return;
- } else if (lm instanceof RetrieveTableMarkerLayoutManager) {
- ((AbstractLayoutManager) lm).getFObj().clearChildNodes();
- } else {
- List<LayoutManager> lms = lm.getChildLMs();
- clearRetrieveTableMarkerChildNodes(lms);
- }
- }
- }
-
- /**
- * Checks whether the associated table cell of this LM is in a table header or footer.
- * @return true if descendant of table header or footer
- */
- private boolean isDescendantOfTableHeaderOrFooter() {
- return (isDescendantOfTableFooter || isDescendantOfTableHeader);
- }
-
- private void saveAddAreasArguments(PositionIterator parentIter, LayoutContext layoutContext,
- int[] spannedGridRowHeights, int startRow, int endRow, int borderBeforeWhich,
- int borderAfterWhich, boolean firstOnPage, boolean lastOnPage, RowPainter painter,
- int firstRowHeight) {
- // checks for savedAddAreasArguments and isDescendantOfTableHeader were already made but repeat them
- if (savedAddAreasArguments) {
- return;
- }
- if (isDescendantOfTableHeader) {
- savedAddAreasArguments = true;
- savedParentIter = null /* parentIter */;
- savedLayoutContext = null /* layoutContext */;
- savedSpannedGridRowHeights = spannedGridRowHeights;
- savedStartRow = startRow;
- savedEndRow = endRow;
- savedBorderBeforeWhich = borderBeforeWhich;
- savedBorderAfterWhich = borderAfterWhich;
- savedFirstOnPage = firstOnPage;
- savedLastOnPage = lastOnPage;
- savedPainter = painter;
- savedFirstRowHeight = firstRowHeight;
- TableLayoutManager parentTableLayoutManager = getTableLayoutManager();
- parentTableLayoutManager.saveTableHeaderTableCellLayoutManagers(this);
- // this saving is done the first time the addArea() is called; since the retrieve-table-markers
- // cannot be resolved at this time we do not want to flush the area; the area needs nevertheless
- // be built so that space is allocated for it.
- flushArea = false;
- }
- }
-
- private TableLayoutManager getTableLayoutManager() {
- LayoutManager parentLM = getParent();
- while (!(parentLM instanceof TableLayoutManager)) {
- parentLM = parentLM.getParent();
- }
- TableLayoutManager tlm = (TableLayoutManager) parentLM;
- return tlm;
- }
-
- /**
- * Calls the addAreas() using the original arguments.
- */
- protected void repeatAddAreas() {
- if (savedAddAreasArguments) {
- addAreas(savedParentIter, savedLayoutContext, savedSpannedGridRowHeights, savedStartRow,
- savedEndRow, savedBorderBeforeWhich, savedBorderAfterWhich, savedFirstOnPage,
- savedLastOnPage, savedPainter, savedFirstRowHeight);
- // so that the arguments of the next table fragment header can be saved
- savedAddAreasArguments = false;
- }
- }
-
- /**
- * Add the areas for the break points. The cell contains block stacking layout
- * managers that add block areas.
- *
- * <p>In the collapsing-border model, the borders of a cell that spans over several
- * rows or columns are drawn separately for each grid unit. Therefore we must know the
- * height of each grid row spanned over by the cell. Also, if the cell is broken over
- * two pages we must know which spanned grid rows are present on the current page.</p>
- *
- * @param parentIter the iterator of the break positions
- * @param layoutContext the layout context for adding the areas
- * @param spannedGridRowHeights in collapsing-border model for a spanning cell, height
- * of each spanned grid row
- * @param startRow first grid row on the current page spanned over by the cell,
- * inclusive
- * @param endRow last grid row on the current page spanned over by the cell, inclusive
- * @param borderBeforeWhich one of {@link ConditionalBorder#NORMAL},
- * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
- * @param borderAfterWhich one of {@link ConditionalBorder#NORMAL},
- * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
- * @param firstOnPage true if the cell will be the very first one on the page, in
- * which case collapsed before borders must be drawn in the outer mode
- * @param lastOnPage true if the cell will be the very last one on the page, in which
- * case collapsed after borders must be drawn in the outer mode
- * @param painter painter
- * @param firstRowHeight height of the first row spanned by this cell (may be zero if
- * this row is placed on a previous page). Used to calculate the placement of the
- * row's background image if any
- */
- public void addAreas(PositionIterator parentIter, LayoutContext layoutContext, int[] spannedGridRowHeights,
- int startRow, int endRow, int borderBeforeWhich, int borderAfterWhich,
- boolean firstOnPage, boolean lastOnPage, RowPainter painter, int firstRowHeight) {
- getParentArea(null);
-
- addId();
-
- int borderBeforeWidth = primaryGridUnit.getBeforeBorderWidth(startRow, borderBeforeWhich);
- int borderAfterWidth = primaryGridUnit.getAfterBorderWidth(endRow, borderAfterWhich);
-
- CommonBorderPaddingBackground padding = primaryGridUnit.getCell()
- .getCommonBorderPaddingBackground();
- int paddingRectBPD = totalHeight - borderBeforeWidth - borderAfterWidth;
- int cellBPD = paddingRectBPD;
- cellBPD -= padding.getPaddingBefore(borderBeforeWhich == ConditionalBorder.REST, this);
- cellBPD -= padding.getPaddingAfter(borderAfterWhich == ConditionalBorder.REST, this);
-
- addBackgroundAreas(painter, firstRowHeight, borderBeforeWidth, paddingRectBPD);
-
- if (isSeparateBorderModel()) {
- if (!emptyCell || getTableCell().showEmptyCells()) {
- if (borderBeforeWidth > 0) {
- int halfBorderSepBPD = getTableCell().getTable().getBorderSeparation().getBPD()
- .getLength().getValue() / 2;
- adjustYOffset(curBlockArea, halfBorderSepBPD);
- }
- TraitSetter.addBorders(curBlockArea,
- getTableCell().getCommonBorderPaddingBackground(),
- borderBeforeWidth == 0, borderAfterWidth == 0,
- false, false, this);
- }
- } else {
- boolean inFirstColumn = (primaryGridUnit.getColIndex() == 0);
- boolean inLastColumn = (primaryGridUnit.getColIndex()
- + getTableCell().getNumberColumnsSpanned() == getTable()
- .getNumberOfColumns());
- if (!primaryGridUnit.hasSpanning()) {
- adjustYOffset(curBlockArea, -borderBeforeWidth);
- //Can set the borders directly if there's no span
- boolean[] outer = new boolean[] {firstOnPage, lastOnPage, inFirstColumn,
- inLastColumn};
- TraitSetter.addCollapsingBorders(curBlockArea,
- primaryGridUnit.getBorderBefore(borderBeforeWhich),
- primaryGridUnit.getBorderAfter(borderAfterWhich),
- primaryGridUnit.getBorderStart(),
- primaryGridUnit.getBorderEnd(), outer);
- } else {
- adjustYOffset(curBlockArea, borderBeforeWidth);
- Block[][] blocks = new Block[getTableCell().getNumberRowsSpanned()][getTableCell()
- .getNumberColumnsSpanned()];
- GridUnit[] gridUnits = primaryGridUnit.getRows().get(startRow);
- int level = getTableCell().getBidiLevelRecursive();
- for (int x = 0; x < getTableCell().getNumberColumnsSpanned(); x++) {
- GridUnit gu = gridUnits[x];
- BorderInfo border = gu.getBorderBefore(borderBeforeWhich);
- int borderWidth = border.getRetainedWidth() / 2;
- if (borderWidth > 0) {
- addBorder(blocks, startRow, x, Trait.BORDER_BEFORE, border,
- firstOnPage, level);
- adjustYOffset(blocks[startRow][x], -borderWidth);
- adjustBPD(blocks[startRow][x], -borderWidth);
- }
- }
- gridUnits = primaryGridUnit.getRows().get(endRow);
- for (int x = 0; x < getTableCell().getNumberColumnsSpanned(); x++) {
- GridUnit gu = gridUnits[x];
- BorderInfo border = gu.getBorderAfter(borderAfterWhich);
- int borderWidth = border.getRetainedWidth() / 2;
- if (borderWidth > 0) {
- addBorder(blocks, endRow, x, Trait.BORDER_AFTER, border,
- lastOnPage, level);
- adjustBPD(blocks[endRow][x], -borderWidth);
- }
- }
- for (int y = startRow; y <= endRow; y++) {
- gridUnits = primaryGridUnit.getRows().get(y);
- BorderInfo border = gridUnits[0].getBorderStart();
- int borderWidth = border.getRetainedWidth() / 2;
- if (borderWidth > 0) {
- if (level == 1) {
- addBorder(blocks, y, gridUnits.length - 1, Trait.BORDER_START, border,
- inFirstColumn, level);
- adjustIPD(blocks[y][gridUnits.length - 1], -borderWidth);
- } else {
- addBorder(blocks, y, 0, Trait.BORDER_START, border,
- inFirstColumn, level);
- adjustXOffset(blocks[y][0], borderWidth);
- adjustIPD(blocks[y][0], -borderWidth);
- }
- }
- border = gridUnits[gridUnits.length - 1].getBorderEnd();
- borderWidth = border.getRetainedWidth() / 2;
- if (borderWidth > 0) {
- if (level == 1) {
- addBorder(blocks, y, 0, Trait.BORDER_END, border,
- inLastColumn, level);
- adjustXOffset(blocks[y][0], borderWidth);
- adjustIPD(blocks[y][0], -borderWidth);
- } else {
- addBorder(blocks, y, gridUnits.length - 1, Trait.BORDER_END, border,
- inLastColumn, level);
- adjustIPD(blocks[y][gridUnits.length - 1], -borderWidth);
- }
- }
- }
- int dy = yoffset;
- for (int y = startRow; y <= endRow; y++) {
- int bpd = spannedGridRowHeights[y - startRow];
- int dx = xoffset;
- for (int x = 0; x < gridUnits.length; x++) {
- int ipd = getTable().getColumn(primaryGridUnit.getColIndex() + x)
- .getColumnWidth().getValue(getParent());
- if (blocks[y][x] != null) {
- Block block = blocks[y][x];
- adjustYOffset(block, dy);
- adjustXOffset(block, dx);
- adjustIPD(block, ipd);
- adjustBPD(block, bpd);
- parentLayoutManager.addChildArea(block);
- }
- dx += ipd;
- }
- dy += bpd;
- }
- }
- }
-
- TraitSetter.addPadding(curBlockArea,
- padding,
- borderBeforeWhich == ConditionalBorder.REST,
- borderAfterWhich == ConditionalBorder.REST,
- false, false, this);
-
- //Handle display-align
- if (usedBPD < cellBPD) {
- if (getTableCell().getDisplayAlign() == EN_CENTER) {
- Block space = new Block();
- space.setChangeBarList(getChangeBarList());
- space.setBPD((cellBPD - usedBPD) / 2);
- space.setBidiLevel(getTableCell().getBidiLevelRecursive());
- curBlockArea.addBlock(space);
- } else if (getTableCell().getDisplayAlign() == EN_AFTER) {
- Block space = new Block();
- space.setChangeBarList(getChangeBarList());
- space.setBPD(cellBPD - usedBPD);
- space.setBidiLevel(getTableCell().getBidiLevelRecursive());
- curBlockArea.addBlock(space);
- }
- }
-
- if (isDescendantOfTableHeaderOrFooter()) {
- if (hasRetrieveTableMarker) {
- if (isDescendantOfTableHeader && !savedAddAreasArguments) {
- saveAddAreasArguments(parentIter, layoutContext, spannedGridRowHeights, startRow, endRow,
- borderBeforeWhich, borderAfterWhich, firstOnPage, lastOnPage, painter,
- firstRowHeight);
- }
- recreateChildrenLMs();
- int displayAlign = ((TableCell) this.getFObj()).getDisplayAlign();
- TableCellBreaker breaker = new TableCellBreaker(this, cellIPD, displayAlign);
- breaker.setDescendantOfTableFooter(isDescendantOfTableHeader);
- if (isDescendantOfTableHeader) {
- breaker.setRepeatedHeader(hasRepeatedHeader);
- } else {
- breaker.setRepeatedFooter(layoutContext.treatAsArtifact());
- }
- breaker.doLayout(usedBPD, false);
- // this is needed so the next time the LMs are recreated they look like the originals; this
- // is due to the fact that during the doLayout() above the FO tree changes when the
- // retrieve-table-markers are resolved
- clearRetrieveTableMarkerChildNodes(getChildLMs());
- }
- }
-
- // if hasRetrieveTableMarker == true the areas were already added when the re-layout was done above
- if (!hasRetrieveTableMarker) {
- AreaAdditionUtil.addAreas(this, parentIter, layoutContext);
- }
- // Re-adjust the cell's bpd as it may have been modified by the previous call
- // for some reason (?)
- curBlockArea.setBPD(cellBPD);
-
- // Add background after we know the BPD
- if (!isSeparateBorderModel() || !emptyCell || getTableCell().showEmptyCells()) {
- TraitSetter.addBackground(curBlockArea,
- getTableCell().getCommonBorderPaddingBackground(), this);
- }
-
- if (flushArea) {
- flush();
- } else {
- flushArea = true;
- }
-
- curBlockArea = null;
-
- notifyEndOfLayout();
- }
-
- /** Adds background areas for the column, body and row, if any. */
- private void addBackgroundAreas(RowPainter painter, int firstRowHeight, int borderBeforeWidth,
- int paddingRectBPD) {
- TableColumn column = getTable().getColumn(primaryGridUnit.getColIndex());
- if (column.getCommonBorderPaddingBackground().hasBackground()) {
- Block colBackgroundArea = getBackgroundArea(paddingRectBPD, borderBeforeWidth);
- ((TableLayoutManager) parentLayoutManager).registerColumnBackgroundArea(column,
- colBackgroundArea, -startIndent);
- }
-
- TablePart body = primaryGridUnit.getTablePart();
- if (body.getCommonBorderPaddingBackground().hasBackground()) {
- painter.registerPartBackgroundArea(
- getBackgroundArea(paddingRectBPD, borderBeforeWidth));
- }
-
- TableRow row = primaryGridUnit.getRow();
- if (row != null && row.getCommonBorderPaddingBackground().hasBackground()) {
- Block rowBackgroundArea = getBackgroundArea(paddingRectBPD, borderBeforeWidth);
- ((TableLayoutManager) parentLayoutManager).addBackgroundArea(rowBackgroundArea);
- TraitSetter.addBackground(rowBackgroundArea, row.getCommonBorderPaddingBackground(),
- parentLayoutManager,
- -xoffset - startIndent, -borderBeforeWidth,
- parentLayoutManager.getContentAreaIPD(), firstRowHeight);
- }
- }
-
- private void addBorder(Block[][] blocks, int i, int j, Integer side, BorderInfo border,
- boolean outer, int level) {
- if (blocks[i][j] == null) {
- blocks[i][j] = new Block();
- blocks[i][j].setChangeBarList(getChangeBarList());
- blocks[i][j].addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
- blocks[i][j].setPositioning(Block.ABSOLUTE);
- blocks[i][j].setBidiLevel(level);
- }
- blocks[i][j].addTrait(side, BorderProps.makeRectangular(border.getStyle(),
- border.getRetainedWidth(), border.getColor(),
- outer ? BorderProps.Mode.COLLAPSE_OUTER : BorderProps.Mode.COLLAPSE_INNER));
- }
-
- private static void adjustXOffset(Block block, int amount) {
- block.setXOffset(block.getXOffset() + amount);
- }
-
- private static void adjustYOffset(Block block, int amount) {
- block.setYOffset(block.getYOffset() + amount);
- }
-
- private static void adjustIPD(Block block, int amount) {
- block.setIPD(block.getIPD() + amount);
- }
-
- private static void adjustBPD(Block block, int amount) {
- block.setBPD(block.getBPD() + amount);
- }
-
- private Block getBackgroundArea(int bpd, int borderBeforeWidth) {
- CommonBorderPaddingBackground padding = getTableCell().getCommonBorderPaddingBackground();
- int paddingStart = padding.getPaddingStart(false, this);
- int paddingEnd = padding.getPaddingEnd(false, this);
-
- Block block = new Block();
- block.setChangeBarList(getChangeBarList());
- TraitSetter.setProducerID(block, getTable().getId());
- block.setPositioning(Block.ABSOLUTE);
- block.setIPD(cellIPD + paddingStart + paddingEnd);
- block.setBPD(bpd);
- block.setXOffset(xoffset + startIndent - paddingStart);
- block.setYOffset(yoffset + borderBeforeWidth);
- block.setBidiLevel(getTableCell().getBidiLevelRecursive());
- return block;
- }
-
- /**
- * Return an Area which can contain the passed childArea. The childArea
- * may not yet have any content, but it has essential traits set.
- * In general, if the LayoutManager already has an Area it simply returns
- * it. Otherwise, it makes a new Area of the appropriate class.
- * It gets a parent area for its area by calling its parent LM.
- * Finally, based on the dimensions of the parent area, it initializes
- * its own area. This includes setting the content IPD and the maximum
- * BPD.
- *
- * @param childArea the child area to get the parent for
- * @return the parent area
- */
- public Area getParentArea(Area childArea) {
- if (curBlockArea == null) {
- curBlockArea = new Block();
- curBlockArea.setChangeBarList(getChangeBarList());
- curBlockArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
- TraitSetter.setProducerID(curBlockArea, getTableCell().getId());
- curBlockArea.setPositioning(Block.ABSOLUTE);
- curBlockArea.setXOffset(xoffset + startIndent);
- curBlockArea.setYOffset(yoffset);
- curBlockArea.setIPD(cellIPD);
- curBlockArea.setBidiLevel(getTableCell().getBidiLevelRecursive());
-
- /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
- // Get reference IPD from parentArea
- setCurrentArea(curBlockArea); // ??? for generic operations
- }
- return curBlockArea;
- }
-
- /**
- * Add the child to the cell block area.
- *
- * @param childArea the child to add to the cell
- */
- public void addChildArea(Area childArea) {
- if (curBlockArea != null) {
- curBlockArea.addBlock((Block) childArea);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
- // TODO Auto-generated method stub
- return 0;
- }
-
- /**
- * {@inheritDoc}
- */
- public void discardSpace(KnuthGlue spaceGlue) {
- // TODO Auto-generated method stub
- }
-
- /** {@inheritDoc} */
- public Keep getKeepTogether() {
- // keep-together does not apply to fo:table-cell
- return Keep.KEEP_AUTO;
- }
-
- /** {@inheritDoc} */
- public Keep getKeepWithNext() {
- return Keep.KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-next!)
- }
-
- /** {@inheritDoc} */
- public Keep getKeepWithPrevious() {
- return Keep.KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-previous!)
- }
-
- // --------- Property Resolution related functions --------- //
-
- /**
- * Returns the IPD of the content area
- * @return the IPD of the content area
- */
- public int getContentAreaIPD() {
- return cellIPD;
- }
-
- /**
- * Returns the BPD of the content area
- * @return the BPD of the content area
- */
- public int getContentAreaBPD() {
- if (curBlockArea != null) {
- return curBlockArea.getBPD();
- } else {
- log.error("getContentAreaBPD called on unknown BPD");
- return -1;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean getGeneratesReferenceArea() {
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean getGeneratesBlockArea() {
- return true;
- }
-
- private static class TableCellBreaker extends LocalBreaker {
-
- public TableCellBreaker(TableCellLayoutManager lm, int ipd, int displayAlign) {
- super(lm, ipd, displayAlign);
- }
-
- /**
- * {@inheritDoc}
- */
- protected void observeElementList(List elementList) {
- String elementListID = lm.getParent().getFObj().getId() + "-" + lm.getFObj().getId();
- ElementListObserver.observe(elementList, "table-cell", elementListID);
- }
-
- }
-
- /**
- * Registers the FO's markers on the current PageViewport and parent Table.
- *
- * @param isStarting boolean indicating whether the markers qualify as 'starting'
- * @param isFirst boolean indicating whether the markers qualify as 'first'
- * @param isLast boolean indicating whether the markers qualify as 'last'
- */
- protected void registerMarkers(boolean isStarting, boolean isFirst, boolean isLast) {
- Map<String, Marker> markers = getTableCell().getMarkers();
- if (markers != null) {
- getCurrentPV().registerMarkers(markers, isStarting, isFirst, isLast && isLastTrait);
- if (!isDescendantOfTableHeaderOrFooter()) {
- getTableLayoutManager().registerMarkers(markers, isStarting, isFirst, isLast && isLastTrait);
- }
- }
- }
-
- void setLastTrait(boolean isLast) {
- isLastTrait = isLast;
- }
-
- /** {@inheritDoc} */
- public void setParent(LayoutManager lm) {
- this.parentLayoutManager = lm;
- if (this.hasRetrieveTableMarker) {
- this.getTableLayoutManager().flagAsHavingRetrieveTableMarker();
- }
- }
-
- }
|