| /* |
| * 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.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.fop.datatypes.PercentBaseContext; |
| import org.apache.fop.fo.Constants; |
| import org.apache.fop.fo.FObj; |
| import org.apache.fop.fo.flow.Marker; |
| import org.apache.fop.fo.flow.table.EffRow; |
| import org.apache.fop.fo.flow.table.PrimaryGridUnit; |
| import org.apache.fop.fo.flow.table.Table; |
| import org.apache.fop.fo.flow.table.TableBody; |
| import org.apache.fop.fo.flow.table.TablePart; |
| import org.apache.fop.layoutmgr.BreakElement; |
| import org.apache.fop.layoutmgr.ElementListUtils; |
| import org.apache.fop.layoutmgr.FootenoteUtil; |
| import org.apache.fop.layoutmgr.FootnoteBodyLayoutManager; |
| import org.apache.fop.layoutmgr.Keep; |
| import org.apache.fop.layoutmgr.KnuthBlockBox; |
| import org.apache.fop.layoutmgr.KnuthBox; |
| import org.apache.fop.layoutmgr.KnuthElement; |
| import org.apache.fop.layoutmgr.KnuthGlue; |
| import org.apache.fop.layoutmgr.KnuthPossPosIter; |
| import org.apache.fop.layoutmgr.LayoutContext; |
| import org.apache.fop.layoutmgr.ListElement; |
| import org.apache.fop.layoutmgr.PageBreaker; |
| import org.apache.fop.layoutmgr.Position; |
| import org.apache.fop.layoutmgr.PositionIterator; |
| import org.apache.fop.layoutmgr.SpaceResolver.SpaceHandlingBreakPosition; |
| import org.apache.fop.util.BreakUtil; |
| |
| /** |
| * Layout manager for table contents, particularly managing the creation of combined element lists. |
| */ |
| public class TableContentLayoutManager implements PercentBaseContext { |
| |
| /** Logger **/ |
| private static final Log LOG = LogFactory.getLog(TableContentLayoutManager.class); |
| |
| private TableLayoutManager tableLM; |
| private TableRowIterator bodyIter; |
| private TableRowIterator headerIter; |
| private TableRowIterator footerIter; |
| private LinkedList headerList; |
| private LinkedList footerList; |
| private int headerNetHeight; |
| private int footerNetHeight; |
| |
| private int startXOffset; |
| private int usedBPD; |
| |
| private TableStepper stepper; |
| |
| private boolean headerIsBeingRepeated; |
| private boolean atLeastOnce; |
| |
| /** |
| * Main constructor |
| * @param parent Parent layout manager |
| */ |
| TableContentLayoutManager(TableLayoutManager parent) { |
| this.tableLM = parent; |
| Table table = getTableLM().getTable(); |
| this.bodyIter = new TableRowIterator(table, TableRowIterator.BODY); |
| if (table.getTableHeader() != null) { |
| headerIter = new TableRowIterator(table, TableRowIterator.HEADER); |
| } |
| if (table.getTableFooter() != null) { |
| footerIter = new TableRowIterator(table, TableRowIterator.FOOTER); |
| } |
| stepper = new TableStepper(this); |
| } |
| |
| /** |
| * @return the table layout manager |
| */ |
| TableLayoutManager getTableLM() { |
| return this.tableLM; |
| } |
| |
| /** @return true if the table uses the separate border model. */ |
| boolean isSeparateBorderModel() { |
| return getTableLM().getTable().isSeparateBorderModel(); |
| } |
| |
| /** |
| * @return the column setup of this table |
| */ |
| ColumnSetup getColumns() { |
| return getTableLM().getColumns(); |
| } |
| |
| /** @return the net header height */ |
| protected int getHeaderNetHeight() { |
| return this.headerNetHeight; |
| } |
| |
| /** @return the net footer height */ |
| protected int getFooterNetHeight() { |
| return this.footerNetHeight; |
| } |
| |
| /** @return the header element list */ |
| protected LinkedList getHeaderElements() { |
| return this.headerList; |
| } |
| |
| /** @return the footer element list */ |
| protected LinkedList getFooterElements() { |
| return this.footerList; |
| } |
| |
| /** |
| * Get a sequence of KnuthElements representing the content |
| * of the node assigned to the LM. |
| * |
| * @param context the LayoutContext used to store layout information |
| * @param alignment the desired text alignment |
| * @return the list of KnuthElements |
| * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(LayoutContext, int) |
| */ |
| public List getNextKnuthElements(LayoutContext context, int alignment) { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("==> Columns: " + getTableLM().getColumns()); |
| } |
| KnuthBox headerAsFirst = null; |
| KnuthBox headerAsSecondToLast = null; |
| KnuthBox footerAsLast = null; |
| LinkedList returnList = new LinkedList(); |
| int headerFootnoteBPD = 0; |
| if (headerIter != null && headerList == null) { |
| this.headerList = getKnuthElementsForRowIterator( |
| headerIter, context, alignment, TableRowIterator.HEADER); |
| this.headerNetHeight |
| = ElementListUtils.calcContentLength(this.headerList); |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("==> Header: " |
| + headerNetHeight + " - " + this.headerList); |
| } |
| TableHeaderFooterPosition pos = new TableHeaderFooterPosition( |
| getTableLM(), true, this.headerList); |
| List<FootnoteBodyLayoutManager> footnoteList = FootenoteUtil.getFootnotes(headerList); |
| KnuthBox box = (footnoteList.isEmpty() || !getTableLM().getTable().omitHeaderAtBreak()) |
| ? new KnuthBox(headerNetHeight, pos, false) |
| : new KnuthBlockBox(headerNetHeight, footnoteList, pos, false); |
| if (getTableLM().getTable().omitHeaderAtBreak()) { |
| //We can simply add the table header at the start |
| //of the whole list |
| headerAsFirst = box; |
| } else { |
| if (!footnoteList.isEmpty()) { |
| List<List<KnuthElement>> footnotes = PageBreaker.getFootnoteKnuthElements( |
| getTableLM().getPSLM().getFlowLayoutManager(), context, footnoteList); |
| getTableLM().setHeaderFootnotes(footnotes); |
| headerFootnoteBPD = getFootnotesBPD(footnotes); |
| returnList.add(new KnuthBlockBox(-headerFootnoteBPD, footnoteList, |
| new Position(getTableLM()), true)); |
| headerNetHeight += headerFootnoteBPD; |
| } |
| headerAsSecondToLast = box; |
| } |
| } |
| if (footerIter != null && footerList == null) { |
| this.footerList = getKnuthElementsForRowIterator( |
| footerIter, context, alignment, TableRowIterator.FOOTER); |
| this.footerNetHeight |
| = ElementListUtils.calcContentLength(this.footerList); |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("==> Footer: " |
| + footerNetHeight + " - " + this.footerList); |
| } |
| //We can simply add the table footer at the end of the whole list |
| TableHeaderFooterPosition pos = new TableHeaderFooterPosition( |
| getTableLM(), false, this.footerList); |
| List<FootnoteBodyLayoutManager> footnoteList = FootenoteUtil.getFootnotes(footerList); |
| footerAsLast = footnoteList.isEmpty() |
| ? new KnuthBox(footerNetHeight, pos, false) |
| : new KnuthBlockBox(footerNetHeight, footnoteList, pos, false); |
| if (!(getTableLM().getTable().omitFooterAtBreak() || footnoteList.isEmpty())) { |
| List<List<KnuthElement>> footnotes = PageBreaker.getFootnoteKnuthElements( |
| getTableLM().getPSLM().getFlowLayoutManager(), context, footnoteList); |
| getTableLM().setFooterFootnotes(footnotes); |
| footerNetHeight += getFootnotesBPD(footnotes); |
| } |
| } |
| returnList.addAll(getKnuthElementsForRowIterator( |
| bodyIter, context, alignment, TableRowIterator.BODY)); |
| if (headerAsFirst != null) { |
| int insertionPoint = 0; |
| if (returnList.size() > 0 && ((ListElement)returnList.getFirst()).isForcedBreak()) { |
| insertionPoint++; |
| } |
| returnList.add(insertionPoint, headerAsFirst); |
| } else if (headerAsSecondToLast != null) { |
| int insertionPoint = returnList.size(); |
| if (returnList.size() > 0 && ((ListElement)returnList.getLast()).isForcedBreak()) { |
| insertionPoint--; |
| } |
| returnList.add(insertionPoint, headerAsSecondToLast); |
| } |
| if (footerAsLast != null) { |
| int insertionPoint = returnList.size(); |
| if (returnList.size() > 0 && ((ListElement)returnList.getLast()).isForcedBreak()) { |
| insertionPoint--; |
| } |
| returnList.add(insertionPoint, footerAsLast); |
| } |
| if (headerFootnoteBPD != 0) { |
| returnList.add(new KnuthBox(headerFootnoteBPD, new Position(getTableLM()), true)); |
| } |
| return returnList; |
| } |
| |
| private int getFootnotesBPD(List<List<KnuthElement>> footnotes) { |
| int bpd = 0; |
| for (List<KnuthElement> footnote : footnotes) { |
| bpd += ElementListUtils.calcContentLength(footnote); |
| } |
| return bpd; |
| } |
| |
| /** |
| * Creates Knuth elements by iterating over a TableRowIterator. |
| * @param iter TableRowIterator instance to fetch rows from |
| * @param context Active LayoutContext |
| * @param alignment alignment indicator |
| * @param bodyType Indicates what kind of body is being processed |
| * (BODY, HEADER or FOOTER) |
| * @return An element list |
| */ |
| private LinkedList getKnuthElementsForRowIterator(TableRowIterator iter, |
| LayoutContext context, int alignment, int bodyType) { |
| LinkedList returnList = new LinkedList(); |
| EffRow[] rowGroup = iter.getNextRowGroup(); |
| // TODO homogenize the handling of keeps and breaks |
| context.clearKeepsPending(); |
| context.setBreakBefore(Constants.EN_AUTO); |
| context.setBreakAfter(Constants.EN_AUTO); |
| Keep keepWithPrevious = Keep.KEEP_AUTO; |
| int breakBefore = Constants.EN_AUTO; |
| if (rowGroup != null) { |
| RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup, |
| stepper); |
| List nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType); |
| keepWithPrevious = keepWithPrevious.compare(context.getKeepWithPreviousPending()); |
| breakBefore = context.getBreakBefore(); |
| int breakBetween = context.getBreakAfter(); |
| returnList.addAll(nextRowGroupElems); |
| while ((rowGroup = iter.getNextRowGroup()) != null) { |
| rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup, stepper); |
| |
| //Note previous pending keep-with-next and clear the strength |
| //(as the layout context is reused) |
| Keep keepWithNextPending = context.getKeepWithNextPending(); |
| context.clearKeepWithNextPending(); |
| |
| //Get elements for next row group |
| nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType); |
| /* |
| * The last break element produced by TableStepper (for the previous row |
| * group) may be used to represent the break between the two row groups. |
| * Its penalty value and break class must just be overridden by the |
| * characteristics of the keep or break between the two. |
| * |
| * However, we mustn't forget that if the after border of the last row of |
| * the row group is thicker in the normal case than in the trailing case, |
| * an additional glue will be appended to the element list. So we may have |
| * to go two steps backwards in the list. |
| */ |
| |
| //Determine keep constraints |
| Keep keep = keepWithNextPending.compare(context.getKeepWithPreviousPending()); |
| context.clearKeepWithPreviousPending(); |
| keep = keep.compare(getTableLM().getKeepTogether()); |
| int penaltyValue = keep.getPenalty(); |
| int breakClass = keep.getContext(); |
| |
| breakBetween = BreakUtil.compareBreakClasses(breakBetween, |
| context.getBreakBefore()); |
| if (breakBetween != Constants.EN_AUTO) { |
| penaltyValue = -KnuthElement.INFINITE; |
| breakClass = breakBetween; |
| } |
| BreakElement breakElement; |
| ListIterator elemIter = returnList.listIterator(returnList.size()); |
| ListElement elem = (ListElement) elemIter.previous(); |
| if (elem instanceof KnuthGlue) { |
| breakElement = (BreakElement) elemIter.previous(); |
| } else { |
| breakElement = (BreakElement) elem; |
| } |
| breakElement.setPenaltyValue(penaltyValue); |
| breakElement.setBreakClass(breakClass); |
| returnList.addAll(nextRowGroupElems); |
| breakBetween = context.getBreakAfter(); |
| } |
| } |
| /* |
| * The last break produced for the last row-group of this table part must be |
| * removed, because the breaking after the table will be handled by TableLM. |
| * Unless the element list ends with a glue, which must be kept to accurately |
| * represent the content. In such a case the break is simply disabled by setting |
| * its penalty to infinite. |
| */ |
| ListIterator elemIter = returnList.listIterator(returnList.size()); |
| ListElement elem = (ListElement) elemIter.previous(); |
| if (elem instanceof KnuthGlue) { |
| BreakElement breakElement = (BreakElement) elemIter.previous(); |
| breakElement.setPenaltyValue(KnuthElement.INFINITE); |
| } else { |
| elemIter.remove(); |
| } |
| context.updateKeepWithPreviousPending(keepWithPrevious); |
| context.setBreakBefore(breakBefore); |
| |
| //fox:widow-content-limit |
| int widowContentLimit = getTableLM().getTable().getWidowContentLimit().getValue(); |
| if (widowContentLimit != 0 && bodyType == TableRowIterator.BODY) { |
| ElementListUtils.removeLegalBreaks(returnList, widowContentLimit); |
| } |
| //fox:orphan-content-limit |
| int orphanContentLimit = getTableLM().getTable().getOrphanContentLimit().getValue(); |
| if (orphanContentLimit != 0 && bodyType == TableRowIterator.BODY) { |
| ElementListUtils.removeLegalBreaksFromEnd(returnList, orphanContentLimit); |
| } |
| |
| return returnList; |
| } |
| |
| /** |
| * Returns the X offset of the given grid unit. |
| * @param gu the grid unit |
| * @return the requested X offset |
| */ |
| protected int getXOffsetOfGridUnit(PrimaryGridUnit gu) { |
| return getXOffsetOfGridUnit(gu.getColIndex(), gu.getCell().getNumberColumnsSpanned()); |
| } |
| |
| /** |
| * Returns the X offset of the grid unit in the given column. |
| * @param colIndex the column index (zero-based) |
| * @param nrColSpan number columns spanned |
| * @return the requested X offset |
| */ |
| protected int getXOffsetOfGridUnit(int colIndex, int nrColSpan) { |
| return startXOffset + getTableLM().getColumns().getXOffset(colIndex + 1, nrColSpan, getTableLM()); |
| } |
| |
| /** |
| * Adds the areas generated by this layout manager to the area tree. |
| * @param parentIter the position iterator |
| * @param layoutContext the layout context for adding areas |
| */ |
| void addAreas(PositionIterator parentIter, LayoutContext layoutContext) { |
| this.usedBPD = 0; |
| RowPainter painter = new RowPainter(this, layoutContext); |
| |
| List tablePositions = new java.util.ArrayList(); |
| List headerElements = null; |
| List footerElements = null; |
| Position firstPos = null; |
| Position lastPos = null; |
| Position lastCheckPos = null; |
| while (parentIter.hasNext()) { |
| Position pos = parentIter.next(); |
| if (pos instanceof SpaceHandlingBreakPosition) { |
| //This position has only been needed before addAreas was called, now we need the |
| //original one created by the layout manager. |
| pos = ((SpaceHandlingBreakPosition)pos).getOriginalBreakPosition(); |
| } |
| if (pos == null) { |
| continue; |
| } |
| if (firstPos == null) { |
| firstPos = pos; |
| } |
| lastPos = pos; |
| if (pos.getIndex() >= 0) { |
| lastCheckPos = pos; |
| } |
| if (pos instanceof TableHeaderFooterPosition) { |
| TableHeaderFooterPosition thfpos = (TableHeaderFooterPosition)pos; |
| //these positions need to be unpacked |
| if (thfpos.header) { |
| //Positions for header will be added first |
| headerElements = thfpos.nestedElements; |
| } else { |
| //Positions for footers are simply added at the end |
| footerElements = thfpos.nestedElements; |
| } |
| } else if (pos instanceof TableHFPenaltyPosition) { |
| //ignore for now, see special handling below if break is at a penalty |
| //Only if the last position in this part/page us such a position it will be used |
| } else if (pos instanceof TableContentPosition) { |
| tablePositions.add(pos); |
| } else { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Ignoring position: " + pos); |
| } |
| } |
| } |
| boolean treatFooterAsArtifact = layoutContext.treatAsArtifact(); |
| if (lastPos instanceof TableHFPenaltyPosition) { |
| TableHFPenaltyPosition penaltyPos = (TableHFPenaltyPosition)lastPos; |
| LOG.debug("Break at penalty!"); |
| if (penaltyPos.headerElements != null) { |
| //Header positions for the penalty position are in the last element and need to |
| //be handled first before all other TableContentPositions |
| headerElements = penaltyPos.headerElements; |
| } |
| if (penaltyPos.footerElements != null) { |
| footerElements = penaltyPos.footerElements; |
| treatFooterAsArtifact = true; |
| } |
| } |
| |
| // there may be table fragment markers stored; clear them since we are starting a new fragment |
| tableLM.clearTableFragmentMarkers(); |
| |
| // note: markers at table level are to be retrieved by the page, not by the table itself |
| Map<String, Marker> markers = getTableLM().getTable().getMarkers(); |
| if (markers != null) { |
| getTableLM().getCurrentPV().registerMarkers(markers, |
| true, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); |
| } |
| |
| if (headerElements != null) { |
| boolean ancestorTreatAsArtifact = layoutContext.treatAsArtifact(); |
| if (headerIsBeingRepeated) { |
| layoutContext.setTreatAsArtifact(true); |
| if (!getTableLM().getHeaderFootnotes().isEmpty()) { |
| getTableLM().getPSLM().addTableHeaderFootnotes(getTableLM().getHeaderFootnotes()); |
| } |
| } |
| //header positions for the last part are the second-to-last element and need to |
| //be handled first before all other TableContentPositions |
| addHeaderFooterAreas(headerElements, tableLM.getTable().getTableHeader(), painter, |
| false); |
| if (!ancestorTreatAsArtifact) { |
| headerIsBeingRepeated = true; |
| } |
| layoutContext.setTreatAsArtifact(ancestorTreatAsArtifact); |
| } |
| |
| if (tablePositions.isEmpty()) { |
| // TODO make sure this actually never happens |
| LOG.error("tablePositions empty." |
| + " Please send your FO file to fop-users@xmlgraphics.apache.org"); |
| } else { |
| // Here we are sure that posIter iterates only over TableContentPosition instances |
| addBodyAreas(tablePositions.iterator(), painter, footerElements == null); |
| } |
| |
| // if there are TCLMs saved because they have a RetrieveTableMarker, we repeat the header areas now; |
| // this can also be done after the areas for the footer are added but should be the same as here |
| tableLM.setRepeateHeader(atLeastOnce); |
| tableLM.repeatAddAreasForSavedTableHeaderTableCellLayoutManagers(); |
| atLeastOnce = true; |
| |
| if (footerElements != null) { |
| boolean ancestorTreatAsArtifact = layoutContext.treatAsArtifact(); |
| layoutContext.setTreatAsArtifact(treatFooterAsArtifact); |
| //Positions for footers are simply added at the end |
| addHeaderFooterAreas(footerElements, tableLM.getTable().getTableFooter(), painter, true); |
| if (lastPos instanceof TableHFPenaltyPosition && !tableLM.getFooterFootnotes().isEmpty()) { |
| tableLM.getPSLM().addTableFooterFootnotes(getTableLM().getFooterFootnotes()); |
| } |
| layoutContext.setTreatAsArtifact(ancestorTreatAsArtifact); |
| } |
| |
| this.usedBPD += painter.getAccumulatedBPD(); |
| |
| if (markers != null) { |
| getTableLM().getCurrentPV().registerMarkers(markers, |
| false, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); |
| } |
| } |
| |
| private void addHeaderFooterAreas(List elements, TablePart part, RowPainter painter, |
| boolean lastOnPage) { |
| List lst = new java.util.ArrayList(elements.size()); |
| for (Iterator iter = new KnuthPossPosIter(elements); iter.hasNext();) { |
| Position pos = (Position) iter.next(); |
| /* |
| * Unlike for the body the Positions associated to the glues generated by |
| * TableStepper haven't been removed yet. |
| */ |
| if (pos instanceof TableContentPosition) { |
| lst.add((TableContentPosition) pos); |
| } |
| } |
| addTablePartAreas(lst, painter, part, true, true, true, lastOnPage); |
| } |
| |
| /** |
| * Iterates over the positions corresponding to the table's body (which may contain |
| * several table-body elements!) and adds the corresponding areas. |
| * |
| * @param iterator iterator over TableContentPosition elements. Those positions |
| * correspond to the elements of the body present on the current page |
| * @param painter |
| * @param lastOnPage true if the table has no footer (then the last line of the table |
| * that will be present on the page belongs to the body) |
| */ |
| private void addBodyAreas(Iterator iterator, RowPainter painter, |
| boolean lastOnPage) { |
| painter.startBody(); |
| List lst = new java.util.ArrayList(); |
| TableContentPosition pos = (TableContentPosition) iterator.next(); |
| boolean isFirstPos = pos.getFlag(TableContentPosition.FIRST_IN_ROWGROUP) |
| && pos.getRow().getFlag(EffRow.FIRST_IN_PART); |
| TablePart part = pos.getTablePart(); |
| lst.add(pos); |
| while (iterator.hasNext()) { |
| pos = (TableContentPosition) iterator.next(); |
| if (pos.getTablePart() != part) { |
| addTablePartAreas(lst, painter, part, isFirstPos, true, false, false); |
| isFirstPos = true; |
| lst.clear(); |
| part = pos.getTablePart(); |
| } |
| lst.add(pos); |
| } |
| boolean isLastPos = pos.getFlag(TableContentPosition.LAST_IN_ROWGROUP) |
| && pos.getRow().getFlag(EffRow.LAST_IN_PART); |
| addTablePartAreas(lst, painter, part, isFirstPos, isLastPos, true, lastOnPage); |
| painter.endBody(); |
| } |
| |
| /** |
| * Adds the areas corresponding to a single fo:table-header/footer/body element. |
| */ |
| private void addTablePartAreas(List positions, RowPainter painter, TablePart body, |
| boolean isFirstPos, boolean isLastPos, boolean lastInBody, boolean lastOnPage) { |
| getTableLM().getCurrentPV().registerMarkers(body.getMarkers(), |
| true, isFirstPos, isLastPos); |
| if (body instanceof TableBody) { |
| getTableLM().registerMarkers(body.getMarkers(), true, isFirstPos, isLastPos); |
| } |
| painter.startTablePart(body); |
| for (Iterator iter = positions.iterator(); iter.hasNext();) { |
| painter.handleTableContentPosition((TableContentPosition) iter.next()); |
| } |
| getTableLM().getCurrentPV().registerMarkers(body.getMarkers(), |
| false, isFirstPos, isLastPos); |
| if (body instanceof TableBody) { |
| getTableLM().registerMarkers(body.getMarkers(), false, isFirstPos, isLastPos); |
| } |
| painter.endTablePart(lastInBody, lastOnPage); |
| } |
| |
| /** |
| * Sets the overall starting x-offset. Used for proper placement of cells. |
| * @param startXOffset starting x-offset (table's start-indent) |
| */ |
| void setStartXOffset(int startXOffset) { |
| this.startXOffset = startXOffset; |
| } |
| |
| /** |
| * @return the amount of block-progression-dimension used by the content |
| */ |
| int getUsedBPD() { |
| return this.usedBPD; |
| } |
| |
| // --------- Property Resolution related functions --------- // |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int getBaseLength(int lengthBase, FObj fobj) { |
| return tableLM.getBaseLength(lengthBase, fobj); |
| } |
| |
| } |