org.apache.fop.layoutmgr.BlockContainerLayoutManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.fop Show documentation
Show all versions of org.apache.fop Show documentation
The core maven build properties
The 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: BlockContainerLayoutManager.java 1877372 2020-05-05 08:12:02Z ssteiner $ */
package org.apache.fop.layoutmgr;
import java.awt.Point;
import java.awt.geom.Rectangle2D;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
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.BlockViewport;
import org.apache.fop.area.CTM;
import org.apache.fop.area.Trait;
import org.apache.fop.datatypes.FODimension;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.properties.CommonAbsolutePosition;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;
/**
* LayoutManager for a block-container FO.
*/
public class BlockContainerLayoutManager extends SpacedBorderedPaddedBlockLayoutManager
implements BreakOpportunity {
/**
* logging instance
*/
private static Log log = LogFactory.getLog(BlockContainerLayoutManager.class);
private BlockViewport viewportBlockArea;
private Block referenceArea;
private CommonAbsolutePosition abProps;
private FODimension relDims;
private CTM absoluteCTM;
private Length width;
private Length height;
//private int vpContentIPD;
private int vpContentBPD;
// When viewport should grow with the content.
private boolean autoHeight = true;
private boolean inlineElementList;
/* holds the (one-time use) fo:block space-before
and -after properties. Large fo:blocks are split
into multiple Area.Blocks to accomodate the subsequent
regions (pages) they are placed on. space-before
is applied at the beginning of the first
Block and space-after at the end of the last Block
used in rendering the fo:block.
*/
//TODO space-before|after: handle space-resolution rules
private MinOptMax foBlockSpaceBefore;
private MinOptMax foBlockSpaceAfter;
private int horizontalOverflow;
private double contentRectOffsetX;
private double contentRectOffsetY;
/**
* Create a new block container layout manager.
* @param node block-container node to create the layout manager for.
*/
public BlockContainerLayoutManager(BlockContainer node) {
super(node);
setGeneratesBlockArea(true);
}
/** {@inheritDoc} */
@Override
public void initialize() {
abProps = getBlockContainerFO().getCommonAbsolutePosition();
foBlockSpaceBefore = new SpaceVal(getBlockContainerFO().getCommonMarginBlock()
.spaceBefore, this).getSpace();
foBlockSpaceAfter = new SpaceVal(getBlockContainerFO().getCommonMarginBlock()
.spaceAfter, this).getSpace();
startIndent = getBlockContainerFO().getCommonMarginBlock().startIndent.getValue(this);
endIndent = getBlockContainerFO().getCommonMarginBlock().endIndent.getValue(this);
if (blockProgressionDirectionChanges()) {
height = getBlockContainerFO().getInlineProgressionDimension()
.getOptimum(this).getLength();
width = getBlockContainerFO().getBlockProgressionDimension()
.getOptimum(this).getLength();
} else {
height = getBlockContainerFO().getBlockProgressionDimension()
.getOptimum(this).getLength();
width = getBlockContainerFO().getInlineProgressionDimension()
.getOptimum(this).getLength();
}
// use optimum space values
adjustedSpaceBefore = getBlockContainerFO().getCommonMarginBlock()
.spaceBefore.getSpace().getOptimum(this).getLength().getValue(this);
adjustedSpaceAfter = getBlockContainerFO().getCommonMarginBlock()
.spaceAfter.getSpace().getOptimum(this).getLength().getValue(this);
}
@Override
protected CommonBorderPaddingBackground getCommonBorderPaddingBackground() {
return getBlockContainerFO().getCommonBorderPaddingBackground();
}
private void resetSpaces() {
this.discardBorderBefore = false;
this.discardBorderAfter = false;
this.discardPaddingBefore = false;
this.discardPaddingAfter = false;
this.effSpaceBefore = null;
this.effSpaceAfter = null;
}
/** @return the content IPD */
protected int getRotatedIPD() {
return getBlockContainerFO().getInlineProgressionDimension()
.getOptimum(this).getLength().getValue(this);
}
private boolean needClip() {
int overflow = getBlockContainerFO().getOverflow();
return (overflow == EN_HIDDEN || overflow == EN_ERROR_IF_OVERFLOW);
}
private int getBPIndents() {
int indents = 0;
/* TODO This is wrong isn't it?
indents += getBlockContainerFO().getCommonMarginBlock()
.spaceBefore.getOptimum(this).getLength().getValue(this);
indents += getBlockContainerFO().getCommonMarginBlock()
.spaceAfter.getOptimum(this).getLength().getValue(this);
*/
indents += getBlockContainerFO().getCommonBorderPaddingBackground()
.getBPPaddingAndBorder(false, this);
return indents;
}
protected boolean isAbsoluteOrFixed() {
return (abProps.absolutePosition == EN_ABSOLUTE
|| abProps.absolutePosition == EN_FIXED);
}
private boolean isFixed() {
return (abProps.absolutePosition == EN_FIXED);
}
/** {@inheritDoc} */
@Override
public int getContentAreaBPD() {
if (autoHeight) {
return -1;
} else {
return this.vpContentBPD;
}
}
/** {@inheritDoc} */
@Override
public List getNextKnuthElements(LayoutContext context, int alignment) {
return getNextKnuthElements(context, alignment, null, null, null);
}
/**
* Overridden to handle writing-mode, and different stack limit
* setup.
* {@inheritDoc}
*/
@Override
protected LayoutContext makeChildLayoutContext(LayoutContext context) {
LayoutContext childLC = LayoutContext.newInstance();
childLC.setStackLimitBP(
context.getStackLimitBP().minus(MinOptMax.getInstance(relDims.bpd)));
childLC.setRefIPD(relDims.ipd);
childLC.setWritingMode(getBlockContainerFO().getWritingMode());
return childLC;
}
/** {@inheritDoc} */
@Override
public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
Position restartPosition, LayoutManager restartAtLM) {
resetSpaces();
// special treatment for position="absolute|fixed"
if (isAbsoluteOrFixed()) {
return getNextKnuthElementsAbsolute(context);
}
boolean isRestart = (lmStack != null);
boolean emptyStack = (!isRestart || lmStack.isEmpty());
setupAreaDimensions(context);
List returnedList;
List contentList = new LinkedList();
List returnList = new LinkedList();
if (!breakBeforeServed(context, returnList)) {
return returnList;
}
addFirstVisibleMarks(returnList, context, alignment);
if (autoHeight && inlineElementList) {
LayoutManager curLM; // currently active LM
LayoutManager prevLM = null; // previously active LM
LayoutContext childLC;
if (isRestart) {
if (emptyStack) {
assert restartAtLM != null && restartAtLM.getParent() == this;
curLM = restartAtLM;
} else {
curLM = (LayoutManager) lmStack.pop();
}
setCurrentChildLM(curLM);
} else {
curLM = getChildLM();
}
while (curLM != null) {
childLC = makeChildLayoutContext(context);
// get elements from curLM
if (!isRestart || emptyStack) {
if (isRestart) {
curLM.reset();
}
returnedList = getNextChildElements(curLM, context, childLC, alignment,
null, null, null);
} else {
returnedList = getNextChildElements(curLM, context, childLC, alignment,
lmStack, restartPosition, restartAtLM);
// once encountered, irrelevant for following child LMs
emptyStack = true;
}
if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
//Propagate keep-with-previous up from the first child
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
childLC.clearKeepWithPreviousPending();
}
if (returnedList.size() == 1
&& ElementListUtils.startsWithForcedBreak(returnedList)) {
// a descendant of this block has break-before
contentList.addAll(returnedList);
// "wrap" the Position inside each element
// moving the elements from contentList to returnList
wrapPositionElements(contentList, returnList);
return returnList;
} else {
if (prevLM != null) {
// 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 (ElementListUtils.endsWithForcedBreak(returnedList)) {
// a descendant of this block has break-after
if (curLM.isFinished() && !hasNextChildLM()) {
// there is no other content in this block;
// it's useless to add space after before a page break
setFinished(true);
}
wrapPositionElements(contentList, returnList);
return returnList;
}
}
// propagate and clear
context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
childLC.clearKeepsPending();
prevLM = curLM;
curLM = getChildLM();
}
wrapPositionElements(contentList, returnList);
} else {
returnList.add(generateNonInlinedBox());
}
addLastVisibleMarks(returnList, context, alignment);
addKnuthElementsForBreakAfter(returnList, context);
context.updateKeepWithNextPending(getKeepWithNext());
setFinished(true);
return returnList;
}
private void setupAreaDimensions(LayoutContext context) {
autoHeight = false;
int maxbpd = context.getStackLimitBP().getOpt();
int allocBPD;
BlockContainer fo = getBlockContainerFO();
if (height.getEnum() == EN_AUTO
|| (!height.isAbsolute() && getAncestorBlockAreaBPD() <= 0)) {
//auto height when height="auto" or "if that dimension is not specified explicitly
//(i.e., it depends on content's block-progression-dimension)" (XSL 1.0, 7.14.1)
allocBPD = maxbpd;
autoHeight = true;
//Cannot easily inline element list when ref-or<>"0"
inlineElementList = (fo.getReferenceOrientation() == 0);
} else {
allocBPD = height.getValue(this); //this is the content-height
allocBPD += getBPIndents();
}
vpContentBPD = allocBPD - getBPIndents();
referenceIPD = context.getRefIPD();
if (width.getEnum() == EN_AUTO) {
updateContentAreaIPDwithOverconstrainedAdjust();
} else {
int contentWidth = width.getValue(this);
updateContentAreaIPDwithOverconstrainedAdjust(contentWidth);
}
contentRectOffsetX = 0;
contentRectOffsetY = 0;
int level = fo.getBidiLevel();
if ((level < 0) || ((level & 1) == 0)) {
contentRectOffsetX += fo.getCommonMarginBlock().startIndent.getValue(this);
} else {
contentRectOffsetX += fo.getCommonMarginBlock().endIndent.getValue(this);
}
contentRectOffsetY += fo.getCommonBorderPaddingBackground().getBorderBeforeWidth(false);
contentRectOffsetY += fo.getCommonBorderPaddingBackground().getPaddingBefore(false, this);
updateRelDims();
int availableIPD = referenceIPD - getIPIndents();
if (getContentAreaIPD() > availableIPD) {
BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
fo.getUserAgent().getEventBroadcaster());
eventProducer.objectTooWide(this, fo.getName(),
getContentAreaIPD(), context.getRefIPD(),
fo.getLocator());
}
}
private KnuthBox generateNonInlinedBox() {
MinOptMax range = MinOptMax.getInstance(relDims.ipd);
BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
breaker.doLayout(relDims.bpd, autoHeight);
boolean contentOverflows = breaker.isOverflow();
if (autoHeight) {
//Update content BPD now that it is known
int newHeight = breaker.deferredAlg.totalWidth;
if (blockProgressionDirectionChanges()) {
setContentAreaIPD(newHeight);
} else {
vpContentBPD = newHeight;
}
updateRelDims();
}
Position bcPosition = new BlockContainerPosition(this, breaker);
KnuthBox knuthBox = new KnuthBox(vpContentBPD, notifyPos(bcPosition), false);
//TODO Handle min/opt/max for block-progression-dimension
/* These two elements will be used to add stretchability to the above box
returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE,
false, returnPosition, false));
returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
LINE_NUMBER_ADJUSTMENT, returnPosition, false));
*/
if (contentOverflows) {
BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
getBlockContainerFO().getUserAgent().getEventBroadcaster());
boolean canRecover = (getBlockContainerFO().getOverflow() != EN_ERROR_IF_OVERFLOW);
eventProducer.viewportBPDOverflow(this, getBlockContainerFO().getName(),
breaker.getOverflowAmount(), needClip(), canRecover,
getBlockContainerFO().getLocator());
}
return knuthBox;
}
private boolean blockProgressionDirectionChanges() {
return getBlockContainerFO().getReferenceOrientation() % 180 != 0;
}
/** {@inheritDoc} */
@Override
public boolean isRestartable() {
return true;
}
private List getNextKnuthElementsAbsolute(LayoutContext context) {
autoHeight = false;
boolean bpDirectionChanges = blockProgressionDirectionChanges();
Point offset = getAbsOffset();
int allocBPD;
int allocIPD;
if (height.getEnum() == EN_AUTO
|| (!height.isAbsolute() && getAncestorBlockAreaBPD() <= 0)) {
//auto height when height="auto" or "if that dimension is not specified explicitly
//(i.e., it depends on content's blockprogression-dimension)" (XSL 1.0, 7.14.1)
allocBPD = 0;
if (abProps.bottom.getEnum() != EN_AUTO) {
int availHeight;
if (isFixed()) {
availHeight = (int)getCurrentPV().getViewArea().getHeight();
} else {
availHeight = context.getStackLimitBP().getOpt();
}
allocBPD = availHeight;
allocBPD -= offset.y;
if (abProps.bottom.getEnum() != EN_AUTO) {
allocBPD -= abProps.bottom.getValue(this);
if (allocBPD < 0) {
//TODO Fix absolute b-c layout, layout may need to be defferred until
//after page breaking when the size of the containing box is known.
/* Warning disabled due to a interpretation mistake.
* See: http://marc.theaimsgroup.com/?l=fop-dev&m=113189981926163&w=2
log.error("The current combination of top and bottom properties results"
+ " in a negative extent for the block-container. 'bottom' may be"
+ " at most " + (allocBPD + abProps.bottom.getValue(this)) + " mpt,"
+ " but was actually " + abProps.bottom.getValue(this) + " mpt."
+ " The nominal available height is " + availHeight + " mpt.");
*/
allocBPD = 0;
}
} else {
if (allocBPD < 0) {
/* Warning disabled due to a interpretation mistake.
* See: http://marc.theaimsgroup.com/?l=fop-dev&m=113189981926163&w=2
log.error("The current combination of top and bottom properties results"
+ " in a negative extent for the block-container. 'top' may be"
+ " at most " + availHeight + " mpt,"
+ " but was actually " + offset.y + " mpt."
+ " The nominal available height is " + availHeight + " mpt.");
*/
allocBPD = 0;
}
}
} else {
allocBPD = context.getStackLimitBP().getOpt();
if (!bpDirectionChanges) {
autoHeight = true;
}
}
} else {
allocBPD = height.getValue(this); //this is the content-height
allocBPD += getBPIndents();
}
if (width.getEnum() == EN_AUTO) {
int availWidth;
if (isFixed()) {
availWidth = (int)getCurrentPV().getViewArea().getWidth();
} else {
availWidth = context.getRefIPD();
}
allocIPD = availWidth;
if (abProps.left.getEnum() != EN_AUTO) {
allocIPD -= abProps.left.getValue(this);
}
if (abProps.right.getEnum() != EN_AUTO) {
allocIPD -= abProps.right.getValue(this);
if (allocIPD < 0) {
/* Warning disabled due to a interpretation mistake.
* See: http://marc.theaimsgroup.com/?l=fop-dev&m=113189981926163&w=2
log.error("The current combination of left and right properties results"
+ " in a negative extent for the block-container. 'right' may be"
+ " at most " + (allocIPD + abProps.right.getValue(this)) + " mpt,"
+ " but was actually " + abProps.right.getValue(this) + " mpt."
+ " The nominal available width is " + availWidth + " mpt.");
*/
allocIPD = 0;
}
} else {
if (allocIPD < 0) {
/* Warning disabled due to a interpretation mistake.
* See: http://marc.theaimsgroup.com/?l=fop-dev&m=113189981926163&w=2
log.error("The current combination of left and right properties results"
+ " in a negative extent for the block-container. 'left' may be"
+ " at most " + allocIPD + " mpt,"
+ " but was actually " + abProps.left.getValue(this) + " mpt."
+ " The nominal available width is " + availWidth + " mpt.");
*/
allocIPD = 0;
}
if (bpDirectionChanges) {
autoHeight = true;
}
}
} else {
allocIPD = width.getValue(this); //this is the content-width
allocIPD += getIPIndents();
}
vpContentBPD = allocBPD - getBPIndents();
setContentAreaIPD(allocIPD - getIPIndents());
contentRectOffsetX = 0;
contentRectOffsetY = 0;
updateRelDims();
MinOptMax range = MinOptMax.getInstance(relDims.ipd);
BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
breaker.doLayout((autoHeight ? 0 : relDims.bpd), autoHeight);
boolean contentOverflows = breaker.isOverflow();
if (autoHeight) {
//Update content BPD now that it is known
int newHeight = breaker.deferredAlg.totalWidth;
if (bpDirectionChanges) {
setContentAreaIPD(newHeight);
} else {
vpContentBPD = newHeight;
}
updateRelDims();
}
List returnList = new LinkedList();
if (!breaker.isEmpty()) {
Position bcPosition = new BlockContainerPosition(this, breaker);
returnList.add(new KnuthBox(0, notifyPos(bcPosition), false));
//TODO Maybe check for page overflow when autoHeight=true
if (!autoHeight & (contentOverflows)) {
BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
getBlockContainerFO().getUserAgent().getEventBroadcaster());
boolean canRecover = (getBlockContainerFO().getOverflow() != EN_ERROR_IF_OVERFLOW);
eventProducer.viewportBPDOverflow(this, getBlockContainerFO().getName(),
breaker.getOverflowAmount(), needClip(), canRecover,
getBlockContainerFO().getLocator());
}
// this handles the IPD (horizontal) overflow
if (this.horizontalOverflow > 0) {
BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider
.get(getBlockContainerFO().getUserAgent().getEventBroadcaster());
boolean canRecover = (getBlockContainerFO().getOverflow() != EN_ERROR_IF_OVERFLOW);
eventProducer.viewportIPDOverflow(this, getBlockContainerFO().getName(),
this.horizontalOverflow, needClip(), canRecover, getBlockContainerFO().getLocator());
}
}
setFinished(true);
return returnList;
}
private void updateRelDims() {
Rectangle2D rect = new Rectangle2D.Double(
contentRectOffsetX, contentRectOffsetY,
getContentAreaIPD(),
this.vpContentBPD);
relDims = new FODimension(0, 0);
absoluteCTM = CTM.getCTMandRelDims(
getBlockContainerFO().getReferenceOrientation(),
getBlockContainerFO().getWritingMode(),
rect, relDims);
}
private class BlockContainerPosition extends NonLeafPosition {
private BlockContainerBreaker breaker;
public BlockContainerPosition(LayoutManager lm, BlockContainerBreaker breaker) {
super(lm, null);
this.breaker = breaker;
}
public BlockContainerBreaker getBreaker() {
return this.breaker;
}
}
private class BlockContainerBreaker extends AbstractBreaker {
private BlockContainerLayoutManager bclm;
private MinOptMax ipd;
//Info for deferred adding of areas
private PageBreakingAlgorithm deferredAlg;
private BlockSequence deferredOriginalList;
private BlockSequence deferredEffectiveList;
public BlockContainerBreaker(BlockContainerLayoutManager bclm, MinOptMax ipd) {
this.bclm = bclm;
this.ipd = ipd;
}
/** {@inheritDoc} */
protected void observeElementList(List elementList) {
ElementListObserver.observe(elementList, "block-container",
bclm.getBlockContainerFO().getId());
}
/** {@inheritDoc} */
protected boolean isPartOverflowRecoveryActivated() {
//For block-containers, this must be disabled because of wanted overflow.
return false;
}
/** {@inheritDoc} */
protected boolean isSinglePartFavored() {
return true;
}
public int getDifferenceOfFirstPart() {
PageBreakPosition pbp = this.deferredAlg.getPageBreaks().getFirst();
return pbp.difference;
}
public boolean isOverflow() {
return !isEmpty()
&& ((deferredAlg.getPageBreaks().size() > 1)
|| (deferredAlg.totalWidth - deferredAlg.totalShrink)
> deferredAlg.getLineWidth());
}
public int getOverflowAmount() {
return (deferredAlg.totalWidth - deferredAlg.totalShrink)
- deferredAlg.getLineWidth();
}
protected LayoutManager getTopLevelLM() {
return bclm;
}
protected LayoutContext createLayoutContext() {
LayoutContext lc = super.createLayoutContext();
lc.setRefIPD(ipd.getOpt());
lc.setWritingMode(getBlockContainerFO().getWritingMode());
return lc;
}
protected List getNextKnuthElements(LayoutContext context, int alignment) {
LayoutManager curLM; // currently active LM
List returnList = new LinkedList();
while ((curLM = getChildLM()) != null) {
LayoutContext childLC = makeChildLayoutContext(context);
List returnedList = null;
if (!curLM.isFinished()) {
returnedList = curLM.getNextKnuthElements(childLC, alignment);
}
if (returnedList != null) {
bclm.wrapPositionElements(returnedList, returnList);
}
}
SpaceResolver.resolveElementList(returnList);
setFinished(true);
return returnList;
}
protected int getCurrentDisplayAlign() {
return getBlockContainerFO().getDisplayAlign();
}
protected boolean hasMoreContent() {
return !isFinished();
}
protected void addAreas(PositionIterator posIter, LayoutContext context) {
AreaAdditionUtil.addAreas(bclm, posIter, context);
}
protected void doPhase3(PageBreakingAlgorithm alg, int partCount,
BlockSequence originalList, BlockSequence effectiveList) {
//Defer adding of areas until addAreas is called by the parent LM
this.deferredAlg = alg;
this.deferredOriginalList = originalList;
this.deferredEffectiveList = effectiveList;
}
protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
//nop for bclm
}
protected LayoutManager getCurrentChildLM() {
return curChildLM;
}
public void addContainedAreas(LayoutContext layoutContext) {
if (isEmpty()) {
return;
}
//Rendering all parts (not just the first) at once for the case where the parts that
//overflow should be visible.
this.deferredAlg.removeAllPageBreaks();
this.addAreas(this.deferredAlg,
0,
this.deferredAlg.getPageBreaks().size(),
this.deferredOriginalList, this.deferredEffectiveList,
LayoutContext.offspringOf(layoutContext));
}
}
private Point getAbsOffset() {
int x = 0;
int y = 0;
if (abProps.left.getEnum() != EN_AUTO) {
x = abProps.left.getValue(this);
} else if (abProps.right.getEnum() != EN_AUTO
&& width.getEnum() != EN_AUTO) {
x = getReferenceAreaIPD()
- abProps.right.getValue(this) - width.getValue(this);
}
if (abProps.top.getEnum() != EN_AUTO) {
y = abProps.top.getValue(this);
} else if (abProps.bottom.getEnum() != EN_AUTO
&& height.getEnum() != EN_AUTO) {
y = getReferenceAreaBPD()
- abProps.bottom.getValue(this) - height.getValue(this);
}
return new Point(x, y);
}
/** {@inheritDoc} */
@Override
public void addAreas(PositionIterator parentIter, LayoutContext layoutContext) {
getParentArea(null);
// if this will create the first block area in a page
// and display-align is bottom or center, add space before
if (layoutContext.getSpaceBefore() > 0) {
addBlockSpacing(0.0, MinOptMax.getInstance(layoutContext.getSpaceBefore()));
}
LayoutManager childLM;
LayoutManager lastLM = null;
LayoutContext lc = LayoutContext.offspringOf(layoutContext);
lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
// set space after in the LayoutContext for children
if (layoutContext.getSpaceAfter() > 0) {
lc.setSpaceAfter(layoutContext.getSpaceAfter());
}
BlockContainerPosition bcpos = null;
PositionIterator childPosIter;
// "unwrap" the NonLeafPositions stored in parentIter
// and put them in a new list;
List positionList = new LinkedList();
Position pos;
Position firstPos = null;
Position lastPos = null;
while (parentIter.hasNext()) {
pos = parentIter.next();
if (pos.getIndex() >= 0) {
if (firstPos == null) {
firstPos = pos;
}
lastPos = pos;
}
Position innerPosition = pos;
if (pos instanceof NonLeafPosition) {
innerPosition = pos.getPosition();
}
if (pos instanceof BlockContainerPosition) {
if (bcpos != null) {
throw new IllegalStateException("Only one BlockContainerPosition allowed");
}
bcpos = (BlockContainerPosition)pos;
//Add child areas inside the reference area
//bcpos.getBreaker().addContainedAreas();
} else if (innerPosition == null) {
//ignore (probably a Position for a simple penalty between blocks)
} else if (innerPosition.getLM() == this
&& !(innerPosition instanceof MappingPosition)) {
// pos was created by this BlockLM and was inside a penalty
// allowing or forbidding a page break
// nothing to do
} else {
// innerPosition was created by another LM
positionList.add(innerPosition);
lastLM = innerPosition.getLM();
}
}
addId();
registerMarkers(true, isFirst(firstPos), isLast(lastPos));
if (bcpos == null) {
// the Positions in positionList were inside the elements
// created by the LineLM
childPosIter = new PositionIterator(positionList.listIterator());
while ((childLM = childPosIter.getNextChildLM()) != null) {
// set last area flag
lc.setFlags(LayoutContext.LAST_AREA,
(layoutContext.isLastArea() && childLM == lastLM));
lc.setStackLimitBP(layoutContext.getStackLimitBP());
// Add the line areas to Area
childLM.addAreas(childPosIter, lc);
}
} else {
//Add child areas inside the reference area
bcpos.getBreaker().addContainedAreas(layoutContext);
}
registerMarkers(false, isFirst(firstPos), isLast(lastPos));
TraitSetter.addSpaceBeforeAfter(viewportBlockArea, layoutContext.getSpaceAdjust(),
effSpaceBefore, effSpaceAfter);
flush();
viewportBlockArea = null;
referenceArea = null;
resetSpaces();
notifyEndOfLayout();
}
/**
* Get the parent area for children of this block container.
* This returns the current block container area
* and creates it if required.
*
* {@inheritDoc}
*/
@Override
public Area getParentArea(Area childArea) {
if (referenceArea == null) {
boolean switchedProgressionDirection = blockProgressionDirectionChanges();
boolean allowBPDUpdate = autoHeight && !switchedProgressionDirection;
int level = getBlockContainerFO().getBidiLevel();
viewportBlockArea = new BlockViewport(allowBPDUpdate);
viewportBlockArea.setChangeBarList(getChangeBarList());
viewportBlockArea.addTrait(Trait.IS_VIEWPORT_AREA, Boolean.TRUE);
if (level >= 0) {
viewportBlockArea.setBidiLevel(level);
}
viewportBlockArea.setIPD(getContentAreaIPD());
if (allowBPDUpdate) {
viewportBlockArea.setBPD(0);
} else {
viewportBlockArea.setBPD(this.vpContentBPD);
}
transferForeignAttributes(viewportBlockArea);
TraitSetter.setProducerID(viewportBlockArea, getBlockContainerFO().getId());
TraitSetter.setLayer(viewportBlockArea, getBlockContainerFO().getLayer());
TraitSetter.addBorders(viewportBlockArea,
getBlockContainerFO().getCommonBorderPaddingBackground(),
discardBorderBefore, discardBorderAfter, false, false, this);
TraitSetter.addPadding(viewportBlockArea,
getBlockContainerFO().getCommonBorderPaddingBackground(),
discardPaddingBefore, discardPaddingAfter, false, false, this);
TraitSetter.addMargins(viewportBlockArea,
getBlockContainerFO().getCommonBorderPaddingBackground(),
startIndent, endIndent,
this);
viewportBlockArea.setCTM(absoluteCTM);
viewportBlockArea.setClip(needClip());
if (abProps.absolutePosition == EN_ABSOLUTE
|| abProps.absolutePosition == EN_FIXED) {
Point offset = getAbsOffset();
viewportBlockArea.setXOffset(offset.x);
viewportBlockArea.setYOffset(offset.y);
} else {
//nop
}
referenceArea = new Block();
referenceArea.setChangeBarList(getChangeBarList());
referenceArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
if (level >= 0) {
referenceArea.setBidiLevel(level);
}
TraitSetter.setProducerID(referenceArea, getBlockContainerFO().getId());
if (abProps.absolutePosition == EN_ABSOLUTE) {
viewportBlockArea.setPositioning(Block.ABSOLUTE);
} else if (abProps.absolutePosition == EN_FIXED) {
viewportBlockArea.setPositioning(Block.FIXED);
}
// Set up dimensions
// Must get dimensions from parent area
/*Area parentArea =*/ parentLayoutManager.getParentArea(referenceArea);
//int referenceIPD = parentArea.getIPD();
referenceArea.setIPD(relDims.ipd);
// Get reference IPD from parentArea
setCurrentArea(viewportBlockArea); // ??? for generic operations
}
return referenceArea;
}
/**
* Add the child to the block container.
*
* {@inheritDoc}
*/
@Override
public void addChildArea(Area childArea) {
if (referenceArea != null) {
referenceArea.addBlock((Block) childArea);
}
}
/**
* Force current area to be added to parent area.
* {@inheritDoc}
*/
@Override
protected void flush() {
viewportBlockArea.addBlock(referenceArea, autoHeight);
TraitSetter.addBackground(viewportBlockArea,
getBlockContainerFO().getCommonBorderPaddingBackground(),
this);
super.flush();
}
/** {@inheritDoc} */
@Override
public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
// TODO Auto-generated method stub
return 0;
}
/** {@inheritDoc} */
@Override
public void discardSpace(KnuthGlue spaceGlue) {
// TODO Auto-generated method stub
}
/** {@inheritDoc} */
@Override
public KeepProperty getKeepTogetherProperty() {
return getBlockContainerFO().getKeepTogether();
}
/** {@inheritDoc} */
@Override
public KeepProperty getKeepWithPreviousProperty() {
return getBlockContainerFO().getKeepWithPrevious();
}
/** {@inheritDoc} */
@Override
public KeepProperty getKeepWithNextProperty() {
return getBlockContainerFO().getKeepWithNext();
}
/**
* @return the BlockContainer node
*/
protected BlockContainer getBlockContainerFO() {
return (BlockContainer) fobj;
}
// --------- Property Resolution related functions --------- //
/** {@inheritDoc} */
@Override
public boolean getGeneratesReferenceArea() {
return true;
}
/** {@inheritDoc} */
@Override
public boolean getGeneratesBlockArea() {
return true;
}
/** {@inheritDoc} */
public boolean handleOverflow(int milliPoints) {
if (milliPoints > this.horizontalOverflow) {
this.horizontalOverflow = milliPoints;
}
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy