package org.apache.fop.layoutmgr;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
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.LineArea;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
import org.apache.fop.layoutmgr.inline.LineLayoutManager;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;
public class BlockLayoutManager extends SpacedBorderedPaddedBlockLayoutManager
implements BreakOpportunity {
private static Log log = LogFactory.getLog(BlockLayoutManager.class);
private Block curBlockArea;
protected ListIterator<LayoutManager> proxyLMiter;
private int lead = 12000;
private Length lineHeight;
private int follow = 2000;
public BlockLayoutManager(org.apache.fop.fo.flow.Block inBlock) {
super(inBlock);
proxyLMiter = new ProxyLMiter();
}
@Override
public void initialize() {
super.initialize();
org.apache.fop.fo.flow.Block fo = getBlockFO();
FontInfo fi = fo.getFOEventHandler().getFontInfo();
FontTriplet[] fontkeys = fo.getCommonFont().getFontState(fi);
Font initFont = fi.getFontInstance(fontkeys[0],
getBlockFO().getCommonFont().fontSize.getValue(this));
lead = initFont.getAscender();
follow = -initFont.getDescender();
lineHeight = fo.getLineHeight().getOptimum(this).getLength();
startIndent = fo.getCommonMarginBlock().startIndent.getValue(this);
endIndent = fo.getCommonMarginBlock().endIndent.getValue(this);
foSpaceBefore = new SpaceVal(fo.getCommonMarginBlock().spaceBefore, this).getSpace();
foSpaceAfter = new SpaceVal(fo.getCommonMarginBlock().spaceAfter, this).getSpace();
adjustedSpaceBefore = fo.getCommonMarginBlock().spaceBefore.getSpace()
.getOptimum(this).getLength().getValue(this);
adjustedSpaceAfter = fo.getCommonMarginBlock().spaceAfter.getSpace()
.getOptimum(this).getLength().getValue(this);
}
@Override
protected CommonBorderPaddingBackground getCommonBorderPaddingBackground() {
return getBlockFO().getCommonBorderPaddingBackground();
}
@Override
public List getNextKnuthElements(LayoutContext context, int alignment) {
return getNextKnuthElements(context, alignment, null, null, null);
}
@Override
public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
Position restartPosition, LayoutManager restartAtLM) {
resetSpaces();
return super.getNextKnuthElements(
context, alignment, lmStack, restartPosition, restartAtLM);
}
@Override
protected List<ListElement> getNextChildElements(LayoutManager childLM, LayoutContext context,
LayoutContext childLC, int alignment, Stack lmStack, Position restartPosition,
LayoutManager restartAtLM) {
childLC.copyPendingMarksFrom(context);
if (childLM instanceof LineLayoutManager) {
childLC.setRefIPD(getContentAreaIPD());
} else {
}
if (childLM == this.childLMs.get(0)) {
childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
}
if (lmStack == null) {
return childLM.getNextKnuthElements(childLC, alignment);
} else {
if (childLM instanceof LineLayoutManager) {
assert (restartPosition instanceof LeafPosition);
return ((LineLayoutManager) childLM).getNextKnuthElements(childLC, alignment,
(LeafPosition) restartPosition);
} else {
return childLM.getNextKnuthElements(childLC, alignment,
lmStack, restartPosition, restartAtLM);
}
}
}
private void resetSpaces() {
this.discardBorderBefore = false;
this.discardBorderAfter = false;
this.discardPaddingBefore = false;
this.discardPaddingAfter = false;
this.effSpaceBefore = null;
this.effSpaceAfter = null;
}
protected class ProxyLMiter extends LMiter {
public ProxyLMiter() {
super(BlockLayoutManager.this);
listLMs = new java.util.ArrayList<LayoutManager>(10);
}
public boolean hasNext() {
return (curPos < listLMs.size()) || createNextChildLMs(curPos);
}
protected boolean createNextChildLMs(int pos) {
List<LayoutManager> newLMs = createChildLMs(pos + 1 - listLMs.size());
if (newLMs != null) {
listLMs.addAll(newLMs);
}
return pos < listLMs.size();
}
}
@Override
public boolean createNextChildLMs(int pos) {
while (proxyLMiter.hasNext()) {
LayoutManager lm = proxyLMiter.next();
if (lm instanceof InlineLevelLayoutManager) {
LineLayoutManager lineLM = createLineManager(lm);
addChildLM(lineLM);
} else {
addChildLM(lm);
}
if (pos < childLMs.size()) {
return true;
}
}
return false;
}
private LineLayoutManager createLineManager(LayoutManager firstlm) {
LineLayoutManager llm;
llm = new LineLayoutManager(getBlockFO(), lineHeight, lead, follow);
List<LayoutManager> inlines = new java.util.ArrayList<LayoutManager>();
inlines.add(firstlm);
while (proxyLMiter.hasNext()) {
LayoutManager lm = proxyLMiter.next();
if (lm instanceof InlineLevelLayoutManager) {
inlines.add(lm);
} else {
proxyLMiter.previous();
break;
}
}
llm.addChildLMs(inlines);
return llm;
}
@Override
public KeepProperty getKeepTogetherProperty() {
return getBlockFO().getKeepTogether();
}
@Override
public KeepProperty getKeepWithPreviousProperty() {
return getBlockFO().getKeepWithPrevious();
}
@Override
public KeepProperty getKeepWithNextProperty() {
return getBlockFO().getKeepWithNext();
}
@Override
public void addAreas(PositionIterator parentIter, LayoutContext layoutContext) {
getParentArea(null);
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());
if (layoutContext.getSpaceAfter() > 0) {
lc.setSpaceAfter(layoutContext.getSpaceAfter());
}
PositionIterator childPosIter;
LinkedList<Position> positionList = new LinkedList<Position>();
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 (innerPosition != null
&& (innerPosition.getLM() != this
|| innerPosition instanceof MappingPosition)) {
positionList.add(innerPosition);
lastLM = innerPosition.getLM();
}
}
addId();
registerMarkers(true, isFirst(firstPos), isLast(lastPos));
childPosIter = new PositionIterator(positionList.listIterator());
while ((childLM = childPosIter.getNextChildLM()) != null) {
lc.setFlags(LayoutContext.LAST_AREA,
(layoutContext.isLastArea() && childLM == lastLM));
lc.setStackLimitBP(layoutContext.getStackLimitBP());
childLM.addAreas(childPosIter, lc);
}
registerMarkers(false, isFirst(firstPos), isLast(lastPos));
TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(),
effSpaceBefore, effSpaceAfter);
TraitSetter.setVisibility(curBlockArea, getBlockFO().getVisibility());
flush();
curBlockArea = null;
resetSpaces();
checkEndOfLayout(lastPos);
}
@Override
public Area getParentArea(Area childArea) {
if (curBlockArea == null) {
curBlockArea = new Block();
curBlockArea.setIPD(super.getContentAreaIPD());
curBlockArea.setBidiLevel(getBlockFO().getBidiLevelRecursive());
TraitSetter.addBreaks(curBlockArea,
getBlockFO().getBreakBefore(), getBlockFO().getBreakAfter());
parentLayoutManager.getParentArea(curBlockArea);
TraitSetter.setProducerID(curBlockArea, getBlockFO().getId());
TraitSetter.addBorders(curBlockArea,
getBlockFO().getCommonBorderPaddingBackground(),
discardBorderBefore, discardBorderAfter, false, false, this);
TraitSetter.addPadding(curBlockArea,
getBlockFO().getCommonBorderPaddingBackground(),
discardPaddingBefore, discardPaddingAfter, false, false, this);
TraitSetter.addMargins(curBlockArea,
getBlockFO().getCommonBorderPaddingBackground(),
startIndent, endIndent,
this);
TraitSetter.setLayer(curBlockArea, getBlockFO().getLayer());
curBlockArea.setLocale(getBlockFO().getCommonHyphenation().getLocale());
curBlockArea.setLocation(FONode.getLocatorString(getBlockFO().getLocator()));
setCurrentArea(curBlockArea);
}
return curBlockArea;
}
@Override
public void addChildArea(Area childArea) {
if (curBlockArea != null) {
if (childArea instanceof LineArea) {
curBlockArea.addLineArea((LineArea) childArea);
} else {
curBlockArea.addBlock((Block) childArea);
}
}
}
@Override
protected void flush() {
if (curBlockArea != null) {
TraitSetter.addBackground(curBlockArea,
getBlockFO().getCommonBorderPaddingBackground(),
this);
super.flush();
}
}
protected org.apache.fop.fo.flow.Block getBlockFO() {
return (org.apache.fop.fo.flow.Block) fobj;
}
@Override
public int getContentAreaIPD() {
if (curBlockArea != null) {
return curBlockArea.getIPD();
}
return super.getContentAreaIPD();
}
@Override
public int getContentAreaBPD() {
if (curBlockArea != null) {
return curBlockArea.getBPD();
}
return -1;
}
@Override
public boolean getGeneratesBlockArea() {
return true;
}
@Override
public boolean isRestartable() {
return true;
}
}