All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.fop.layoutmgr.table.TableCellLayoutManager Maven / Gradle / Ivy

There is a newer version: 1.2.2.1-jre17
Show newest version
/*
 * 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: TableCellLayoutManager.java 1835810 2018-07-13 10:29:57Z ssteiner $ */

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 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 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.
     *
     * 

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.

* * @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 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(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy