private boolean clip = false;
private String pageNumberString = null;
private SimplePageMaster spm = null;
+ private boolean blank;
// list of id references and the rectangle on the page
private Map idReferences = null;
/**
* Create a page viewport.
* @param spm SimplePageMaster indicating the page and region dimensions
+ * @param pageStr String representation of the page number
+ * @param blank true if this is a blank page
*/
- public PageViewport(SimplePageMaster spm, String pageStr) {
+ public PageViewport(SimplePageMaster spm, String pageStr, boolean blank) {
this.spm = spm;
+ this.blank = blank;
int pageWidth = spm.getPageWidth().getValue();
int pageHeight = spm.getPageHeight().getValue();
pageNumberString = pageStr;
if (marks == null) {
return;
}
+ if (log.isDebugEnabled()) {
+ log.debug("--" + marks.keySet() + ": "
+ + (starting ? "starting" : "ending")
+ + (isfirst ? ", first" : "")
+ + (islast ? ", last" : ""));
+ }
// at the start of the area, register is-first and any areas
if (starting) {
}
break;
}
- log.trace("page " + pageNumberString + ": " + "Retrieving marker " + name + "at position " + posName);
+ if (log.isTraceEnabled()) {
+ log.trace("page " + pageNumberString + ": " + "Retrieving marker " + name
+ + " at position " + posName);
+ }
return mark;
}
+ /** Dumps the current marker data to the logger. */
+ public void dumpMarkers() {
+ if (log.isTraceEnabled()) {
+ log.trace("FirstAny: " + this.markerFirstAny);
+ log.trace("FirstStart: " + this.markerFirstStart);
+ log.trace("LastAny: " + this.markerLastAny);
+ log.trace("LastEnd: " + this.markerLastEnd);
+ log.trace("LastStart: " + this.markerLastStart);
+ }
+ }
+
/**
* Save the page contents to an object stream.
* The map of unresolved references are set on the page so that
return spm;
}
+ /** @return True if this is a blank page. */
+ public boolean isBlank() {
+ return this.blank;
+ }
+
/**
* Convenience method to get BodyRegion of this PageViewport
* @return BodyRegion object
private int blankOrNotBlank;
// End of property values
- private RepeatablePageMasterAlternatives repeatablePageMasterAlternatives;
-
/**
* @see org.apache.fop.fo.FONode#FONode(FONode)
*/
* @see org.apache.fop.fo.FONode#startOfNode
*/
protected void startOfNode() throws FOPException {
- this.repeatablePageMasterAlternatives =
- (RepeatablePageMasterAlternatives) parent;
- this.repeatablePageMasterAlternatives.addConditionalPageMasterReference(this);
+ getConcreteParent().addConditionalPageMasterReference(this);
}
+ private RepeatablePageMasterAlternatives getConcreteParent() {
+ return (RepeatablePageMasterAlternatives) parent;
+ }
+
/**
* @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String)
* XSL Content Model: empty
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
- throws ValidationException {
+ throws ValidationException {
invalidChildError(loc, nsURI, localName);
}
}
/**
- * Public accessor for determining the page master to use for any given
- * page within this page sequence
- * @param pageCount = the page number of the page to be created
- * @param bIsFirstPage = indicator whether this page is the first page of the
+ * Public accessor for determining the next page master to use within this page sequence.
+ * @param page the page number of the page to be created
+ * @param bIsFirstPage indicator whether this page is the first page of the
* page sequence
- * @param bIsBlank = indicator whether the page will be blank
+ * @param bIsBlank indicator whether the page will be blank
* @return the SimplePageMaster to use for this page
+ * @throws FOPException if there's a problem determining the page master
*/
- public SimplePageMaster getSimplePageMasterToUse(int pageCount, boolean bIsFirstPage,
- boolean bIsBlank) throws FOPException {
+ public SimplePageMaster getNextSimplePageMaster(int page,
+ boolean bIsFirstPage,
+ boolean bIsBlank) throws FOPException {
if (pageSequenceMaster == null) {
return simplePageMaster;
}
- boolean isOddPage = ((pageCount % 2) == 1);
+ boolean isOddPage = ((page % 2) == 1);
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("getNextSimplePageMaster(page=" + page
+ + " isOdd=" + isOddPage
+ + " isFirst=" + bIsFirstPage
+ + " isBlank=" + bIsBlank + ")");
+ }
return pageSequenceMaster.getNextSimplePageMaster(isOddPage,
bIsFirstPage, bIsBlank);
}
+ /**
+ * Used to set the "cursor position" for the page masters to the previous item.
+ * @return true if there is a previous item, false if the current one was the first one.
+ */
+ public boolean goToPreviousSimplePageMaster() {
+ if (pageSequenceMaster == null) {
+ return true;
+ } else {
+ return pageSequenceMaster.goToPreviousSimplePageMaster();
+ }
+ }
+
/**
* Retrieves the string representation of a page number applicable
* for this page sequence
*/
protected void endOfNode() throws FOPException {
if (childNodes == null) {
- missingChildElementError("(single-page-master-reference|" +
- "repeatable-page-master-reference|repeatable-page-master-alternatives)+");
+ missingChildElementError("(single-page-master-reference|"
+ + "repeatable-page-master-reference|repeatable-page-master-alternatives)+");
}
}
private SubSequenceSpecifier getNextSubSequence() {
currentSubSequenceNumber++;
if (currentSubSequenceNumber >= 0
- && currentSubSequenceNumber < subSequenceSpecifiers.size()) {
+ && currentSubSequenceNumber < subSequenceSpecifiers.size()) {
return (SubSequenceSpecifier)subSequenceSpecifiers
.get(currentSubSequenceNumber);
}
}
}
+ /**
+ * Used to set the "cursor position" for the page masters to the previous item.
+ * @return true if there is a previous item, false if the current one was the first one.
+ */
+ public boolean goToPreviousSimplePageMaster() {
+ if (currentSubSequence != null) {
+ boolean success = currentSubSequence.goToPrevious();
+ if (!success) {
+ if (currentSubSequenceNumber > 0) {
+ currentSubSequenceNumber--;
+ currentSubSequence = (SubSequenceSpecifier)subSequenceSpecifiers
+ .get(currentSubSequenceNumber);
+ } else {
+ currentSubSequence = null;
+ }
+ }
+ }
+ return (currentSubSequence != null);
+ }
+
/**
* Returns the next simple-page-master.
* @param isOddPage True if the next page number is odd
/*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
package org.apache.fop.fo.pagination;
// Java
-import java.util.ArrayList;
+import java.util.List;
import org.xml.sax.Locator;
private int numberConsumed = 0;
- private ArrayList conditionalPageMasterRefs;
+ private List conditionalPageMasterRefs;
/**
* @see org.apache.fop.fo.FONode#FONode(FONode)
* @see org.apache.fop.fo.FONode#startOfNode
*/
protected void startOfNode() throws FOPException {
- conditionalPageMasterRefs = new ArrayList();
+ conditionalPageMasterRefs = new java.util.ArrayList();
if (parent.getName().equals("fo:page-sequence-master")) {
PageSequenceMaster pageSequenceMaster = (PageSequenceMaster)parent;
}
}
- /**
- * Return the "maximum-repeats" property.
- */
+ /** @return the "maximum-repeats" property. */
public int getMaximumRepeats() {
if (maximumRepeats.getEnum() == EN_NO_LIMIT) {
return INFINITE;
this.conditionalPageMasterRefs.add(cpmr);
}
- /**
- * @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset()
- */
+ /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset() */
public void reset() {
this.numberConsumed = 0;
}
+ /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#goToPrevious() */
+ public boolean goToPrevious() {
+ if (numberConsumed == 0) {
+ return false;
+ } else {
+ numberConsumed--;
+ return true;
+ }
+ }
+
+ /** @see org.apache.fop.fo.FONode#getName() */
public String getName() {
return "fo:repeatable-page-master-alternatives";
}
- /**
- * @see org.apache.fop.fo.FObj#getNameId()
- */
+ /** @see org.apache.fop.fo.FObj#getNameId() */
public int getNameId() {
return FO_REPEATABLE_PAGE_MASTER_ALTERNATIVES;
}
private static final int INFINITE = -1;
- private PageSequenceMaster pageSequenceMaster;
private int numberConsumed = 0;
/**
return masterReference;
}
- /**
- * Return the "maximum-repeats" property.
- */
+ /** @return the "maximum-repeats" property. */
public int getMaximumRepeats() {
if (maximumRepeats.getEnum() == EN_NO_LIMIT) {
return INFINITE;
}
}
- /**
- * @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset()
- */
+ /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset() */
public void reset() {
this.numberConsumed = 0;
}
- /**
- * @see org.apache.fop.fo.FObj#getName()
- */
+
+ /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#goToPrevious() */
+ public boolean goToPrevious() {
+ if (numberConsumed == 0) {
+ return false;
+ } else {
+ numberConsumed--;
+ return true;
+ }
+ }
+
+ /** @see org.apache.fop.fo.FObj#getName() */
public String getName() {
return "fo:repeatable-page-master-reference";
}
- /**
- * @see org.apache.fop.fo.FObj#getNameId()
- */
+ /** @see org.apache.fop.fo.FObj#getNameId() */
public int getNameId() {
return FO_REPEATABLE_PAGE_MASTER_REFERENCE;
}
invalidChildError(loc, nsURI, localName);
}
- /**
- * @see org.apache.fop.fo.pagination.SubSequenceSpecifier
- */
+ /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier */
public String getNextPageMasterName(boolean isOddPage,
boolean isFirstPage,
boolean isEmptyPage) {
}
}
- /**
- * @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset()
- */
+ /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset() */
public void reset() {
this.state = FIRST;
}
+
+
+ /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#goToPrevious() */
+ public boolean goToPrevious() {
+ if (state == FIRST) {
+ return false;
+ } else {
+ this.state = FIRST;
+ return true;
+ }
+ }
+
+ /** @see org.apache.fop.fo.FONode#getName() */
public String getName() {
return "fo:single-page-master-reference";
}
- /**
- * @see org.apache.fop.fo.FObj#getNameId()
- */
+ /** @see org.apache.fop.fo.FObj#getNameId() */
public int getNameId() {
return FO_SINGLE_PAGE_MASTER_REFERENCE;
}
/*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
void reset();
+ /**
+ * Used to set the "cursor position" to the previous item.
+ * @return true if there is a previous item, false if the current one was the first one.
+ */
+ boolean goToPrevious();
+
}
protected abstract LayoutManager getTopLevelLM();
protected abstract LayoutManager getCurrentChildLM();
+ /**
+ * Returns the PageViewportProvider if any. PageBreaker overrides this method because each
+ * page may have a different available BPD which needs to be accessible to the breaking
+ * algorithm.
+ * @return the applicable PageViewportProvider, or null if not applicable
+ */
+ protected PageSequenceLayoutManager.PageViewportProvider getPageViewportProvider() {
+ return null;
+ }
+
/*
* This method is to contain the logic to determine the LM's
* getNextKnuthElements() implementation(s) that are to be called.
log.debug("PLM> start of algorithm (" + this.getClass().getName()
+ "), flow BPD =" + flowBPD);
PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(),
+ getPageViewportProvider(),
alignment, alignmentLast, footnoteSeparatorLength);
int iOptPageNumber;
}
//iOptPageNumber = alg.firstFit(effectiveList, flowBPD, 1, true);
- iOptPageNumber = alg.findBreakingPoints(effectiveList, flowBPD, 1,
- true, true);
+ alg.setConstantLineWidth(flowBPD);
+ iOptPageNumber = alg.findBreakingPoints(effectiveList, /*flowBPD,*/
+ 1, true, true);
log.debug("PLM> iOptPageNumber= " + iOptPageNumber
+ " pageBreaks.size()= " + alg.getPageBreaks().size());
*/
private BlockSequence justifyBoxes(BlockSequence blockList, PageBreakingAlgorithm alg, int availableBPD) {
int iOptPageNumber;
- iOptPageNumber = alg.findBreakingPoints(blockList, availableBPD, 1,
- true, true);
+ alg.setConstantLineWidth(availableBPD);
+ iOptPageNumber = alg.findBreakingPoints(blockList, /*availableBPD,*/
+ 1, true, true);
log.debug("PLM> iOptPageNumber= " + iOptPageNumber);
//
protected KnuthSequence par;
/**
- * The width of a line.
+ * The width of a line (or height of a column in page-breaking mode).
+ * -1 indicates that the line widths are different for each line.
*/
- protected int lineWidth = 0;
+ protected int lineWidth = -1;
private boolean force = false;
protected KnuthNode lastDeactivatedNode = null;
KnuthSequence sequence,
int total) ;
- public int findBreakingPoints(KnuthSequence par, int lineWidth,
+ public void setConstantLineWidth(int lineWidth) {
+ this.lineWidth = lineWidth;
+ }
+
+ public int findBreakingPoints(KnuthSequence par, /*int lineWidth,*/
double threshold, boolean force,
boolean hyphenationAllowed) {
this.par = par;
this.threshold = threshold;
this.force = force;
- this.lineWidth = lineWidth;
+ //this.lineWidth = lineWidth;
initialize();
activeLines = new KnuthNode[20];
if (element.isPenalty()) {
actualWidth += element.getW();
}
- return lineWidth - actualWidth;
+ return getLineWidth() - actualWidth;
}
/**
return positions[line].position;
}
+ protected int getLineWidth(int line) {
+ if (this.lineWidth < 0) {
+ throw new IllegalStateException("lineWidth must be set");
+ } else {
+ return this.lineWidth;
+ }
+ }
+
+ protected int getLineWidth() {
+ return this.lineWidth;
+ }
+
/**
* Return a string representation of a MinOptMax in the form of a
* "width+stretch-shrink". Useful only for debugging.
}
}
- public int findBreakingPoints(Paragraph par, int lineWidth,
+ public int findBreakingPoints(Paragraph par, /*int lineWidth,*/
double threshold, boolean force,
boolean hyphenationAllowed) {
- return super.findBreakingPoints(par, lineWidth, threshold, force, hyphenationAllowed);
+ return super.findBreakingPoints(par, /*lineWidth,*/
+ threshold, force, hyphenationAllowed);
}
protected int filterActiveNodes() {
// first try
boolean bHyphenationAllowed = false;
+ alg.setConstantLineWidth(iLineWidth);
iBPcount = alg.findBreakingPoints(currPar,
- iLineWidth,
maxAdjustment, false, bHyphenationAllowed);
if (iBPcount == 0 || alignment == EN_JUSTIFY) {
// if the first try found a set of breaking points, save them
if ((iBPcount
= alg.findBreakingPoints(currPar,
- iLineWidth,
maxAdjustment, false, bHyphenationAllowed)) == 0) {
// the second try failed too, try with a huge threshold
// and force the algorithm to find
maxAdjustment = 20;
iBPcount
= alg.findBreakingPoints(currPar,
- iLineWidth,
maxAdjustment, true, bHyphenationAllowed);
}
// try with shorter lines
int savedLineWidth = iLineWidth;
iLineWidth = (int) (iLineWidth * 0.95);
- iBPcount
- = alg.findBreakingPoints(currPar,
- iLineWidth,
- maxAdjustment, true, bHyphenationAllowed);
- // use normal lines, when possible
- lineLayouts.restorePossibilities();
- iLineWidth = savedLineWidth;
+ iBPcount = alg.findBreakingPoints(currPar,
+ maxAdjustment, true, bHyphenationAllowed);
+ // use normal lines, when possible
+ lineLayouts.restorePossibilities();
+ iLineWidth = savedLineWidth;
}
if (!lineLayouts.canUseLessLines()) {
alg.resetAlgorithm();
// try with longer lines
int savedLineWidth = iLineWidth;
iLineWidth = (int) (iLineWidth * 1.05);
- iBPcount
- = alg.findBreakingPoints(currPar,
- iLineWidth,
- maxAdjustment, true, bHyphenationAllowed);
- // use normal lines, when possible
- lineLayouts.restorePossibilities();
- iLineWidth = savedLineWidth;
+ alg.setConstantLineWidth(iLineWidth);
+ iBPcount = alg.findBreakingPoints(currPar,
+ maxAdjustment, true, bHyphenationAllowed);
+ // use normal lines, when possible
+ lineLayouts.restorePossibilities();
+ iLineWidth = savedLineWidth;
}
//System.out.println("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
//System.out.println(" now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
import java.util.LinkedList;
import java.util.ListIterator;
+import org.apache.fop.area.PageViewport;
import org.apache.fop.layoutmgr.AbstractBreaker.PageBreakPosition;
import org.apache.fop.traits.MinOptMax;
class PageBreakingAlgorithm extends BreakingAlgorithm {
private LayoutManager topLevelLM;
+ private PageSequenceLayoutManager.PageViewportProvider pvProvider;
private LinkedList pageBreaks = null;
private ArrayList footnotesList = null;
private boolean storedValue = false;
public PageBreakingAlgorithm(LayoutManager topLevelLM,
+ PageSequenceLayoutManager.PageViewportProvider pvProvider,
int alignment, int alignmentLast,
MinOptMax fnSeparatorLength) {
super(alignment, alignmentLast, true);
this.topLevelLM = topLevelLM;
+ this.pvProvider = pvProvider;
best = new BestPageRecords();
footnoteSeparatorLength = (MinOptMax) fnSeparatorLength.clone();
// add some stretch, to avoid a restart for every page containing footnotes
// this page contains some footnote citations
// add the footnote separator width
actualWidth += footnoteSeparatorLength.opt;
- if (actualWidth + allFootnotes <= lineWidth) {
+ if (actualWidth + allFootnotes <= getLineWidth()) {
// there is enough space to insert all footnotes:
// add the whole allFootnotes length
actualWidth += allFootnotes;
} else if (((bCanDeferOldFootnotes = canDeferOldFootnotes((KnuthPageNode) activeNode, elementIndex))
|| bNewFootnotes)
&& (footnoteSplit = getFootnoteSplit((KnuthPageNode) activeNode,
- lineWidth - actualWidth,
+ getLineWidth() - actualWidth,
bCanDeferOldFootnotes)) > 0) {
// it is allowed to break or even defer footnotes if either:
// - there are new footnotes in the last piece of content, and
} else {
// there are no footnotes
}
- return lineWidth - actualWidth;
+ return getLineWidth(activeNode.line) - actualWidth;
}
private boolean canDeferOldFootnotes(KnuthPageNode node, int contentElementIndex) {
insertedFootnotesLength = lastNode.totalFootnotes;
footnoteListIndex = lastNode.footnoteListIndex;
footnoteElementIndex = lastNode.footnoteElementIndex;
- int availableBPD = lineWidth;
+ int availableBPD = getLineWidth();
int split = 0;
KnuthPageNode prevNode = lastNode;
removeNode(prevNode.line, prevNode);
prevNode = node;
- availableBPD = lineWidth;
+ availableBPD = getLineWidth();
}
}
// create the last node
public LinkedList getFootnoteList(int index) {
return (LinkedList) footnotesList.get(index);
}
+
+ /** @see org.apache.fop.layoutmgr.BreakingAlgorithm#getLineWidth(int) */
+ protected int getLineWidth(int line) {
+ int bpd;
+ if (pvProvider != null) {
+ PageViewport pv = pvProvider.getPageViewport(
+ false, line,
+ PageSequenceLayoutManager.PageViewportProvider.RELTO_CURRENT_ELEMENT_LIST);
+ bpd = pv.getBodyRegion().getBPD();
+ } else {
+ bpd = super.getLineWidth(line);
+ }
+ return bpd;
+ }
+
}
*/
private PageSequence pageSeq;
+ private PageViewportProvider pvProvider;
+
/**
* Current page-viewport-area being filled by
* the PSLM.
super(pseq);
this.areaTreeHandler = ath;
this.pageSeq = pseq;
+ this.pvProvider = new PageViewportProvider(this.pageSeq);
}
/**
areaTreeHandler.getAreaTreeModel().startPageSequence(title);
log.debug("Starting layout");
- curPV = makeNewPage(false, true, false);
+ curPV = makeNewPage(false, false);
Flow mainFlow = pageSeq.getMainFlow();
childFLM = getLayoutManagerMaker().
return null; // unneeded for PSLM
}
+ /** @see org.apache.fop.layoutmgr.AbstractBreaker#getPageViewportProvider() */
+ protected PageSequenceLayoutManager.PageViewportProvider getPageViewportProvider() {
+ return pvProvider;
+ }
+
protected LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
LinkedList contentList = null;
handleBreakTrait(bIsFirstPage ? list.getStartOn() : Constants.EN_PAGE);
}
}
+ pvProvider.setStartPageOfNextElementList(currentPageNum);
}
// add static areas and resolve any new id areas
// finish page and add to area tree
}
}
- private PageViewport makeNewPage(boolean bIsBlank, boolean bIsFirst, boolean bIsLast) {
+ private PageViewport makeNewPage(boolean bIsBlank, boolean bIsLast) {
if (curPV != null) {
finishPage();
}
currentPageNum++;
- String pageNumberString = pageSeq.makeFormattedPageNumber(currentPageNum);
- try {
- // create a new page
- SimplePageMaster spm = pageSeq.getSimplePageMasterToUse(
- currentPageNum, bIsFirst, bIsBlank);
-
- Region body = spm.getRegion(FO_REGION_BODY);
- if (!pageSeq.getMainFlow().getFlowName().equals(body.getRegionName())) {
- // this is fine by the XSL Rec (fo:flow's flow-name can be mapped to
- // any region), but we don't support it yet.
- throw new FOPException("Flow '" + pageSeq.getMainFlow().getFlowName()
- + "' does not map to the region-body in page-master '"
- + spm.getMasterName() + "'. FOP presently "
- + "does not support this.");
- }
- curPV = new PageViewport(spm, pageNumberString);
- } catch (FOPException fopex) {
- throw new IllegalArgumentException("Cannot create page: " + fopex.getMessage());
- }
+ curPV = pvProvider.getPageViewport(bIsBlank,
+ currentPageNum, PageViewportProvider.RELTO_PAGE_SEQUENCE);
if (log.isDebugEnabled()) {
log.debug("[" + curPV.getPageNumberString() + (bIsBlank ? "*" : "") + "]");
}
private void finishPage() {
+ curPV.dumpMarkers();
// Layout side regions
layoutSideRegion(FO_REGION_BEFORE);
layoutSideRegion(FO_REGION_AFTER);
if (curPV.getCurrentSpan().hasMoreFlows()) {
curPV.getCurrentSpan().moveToNextFlow();
} else {
- curPV = makeNewPage(false, false, false);
+ curPV = makeNewPage(false, false);
}
return;
}
log.debug("handling break-before after page " + currentPageNum
+ " breakVal=" + breakVal);
if (needBlankPageBeforeNew(breakVal)) {
- curPV = makeNewPage(true, false, false);
+ curPV = makeNewPage(true, false);
}
if (needNewPage(breakVal)) {
- curPV = makeNewPage(false, false, false);
+ curPV = makeNewPage(false, false);
}
}
return true;
}
}
+
+
+ public class PageViewportProvider {
+
+ public static final int RELTO_PAGE_SEQUENCE = 0;
+ public static final int RELTO_CURRENT_ELEMENT_LIST = 1;
+
+ private int startPageOfPageSequence;
+ private int startPageOfCurrentElementList;
+ private List cachedPageViewports = new java.util.ArrayList();
+
+ public PageViewportProvider(PageSequence ps) {
+ this.startPageOfPageSequence = ps.getStartingPageNumber();
+ }
+
+ public void setStartPageOfNextElementList(int startPage) {
+ log.debug("start page of the next element list is: " + startPage);
+ this.startPageOfCurrentElementList = startPage;
+ }
+
+ public PageViewport getPageViewport(boolean bIsBlank, int index, int relativeTo) {
+ if (relativeTo == RELTO_PAGE_SEQUENCE) {
+ return getPageViewport(bIsBlank, index);
+ } else if (relativeTo == RELTO_CURRENT_ELEMENT_LIST) {
+ int effIndex = startPageOfCurrentElementList + index;
+ effIndex += startPageOfPageSequence;
+ return getPageViewport(bIsBlank, effIndex);
+ } else {
+ throw new IllegalArgumentException(
+ "Illegal value for relativeTo: " + relativeTo);
+ }
+ }
+
+ private PageViewport getPageViewport(boolean bIsBlank, int index) {
+ //System.out.println("getPageViewport(" + index + " " + bIsBlank);
+ log.debug("getPageViewport(" + index + " " + bIsBlank);
+ int intIndex = index - startPageOfPageSequence;
+ if (bIsBlank) {
+ log.debug("blank page requested: " + index);
+ }
+ while (intIndex >= cachedPageViewports.size()) {
+ //System.out.println("Caching " + index);
+ log.debug("Caching " + index);
+ cacheNextPageViewport(index, bIsBlank);
+ }
+ PageViewport pv = (PageViewport)cachedPageViewports.get(intIndex);
+ if (pv.isBlank() != bIsBlank) {
+ log.debug("blank condition doesn't match. Replacing PageViewport.");
+ while (intIndex < cachedPageViewports.size()) {
+ this.cachedPageViewports.remove(cachedPageViewports.size() - 1);
+ if (!pageSeq.goToPreviousSimplePageMaster()) {
+ log.warn("goToPreviousSimplePageMaster() on the first page called!");
+ }
+ }
+ cacheNextPageViewport(index, bIsBlank);
+ //throw new IllegalStateException("blank condition doesn't match. Check code!");
+ }
+ return pv;
+ }
+
+ private void cacheNextPageViewport(int index, boolean bIsBlank) {
+ try {
+ String pageNumberString = pageSeq.makeFormattedPageNumber(index);
+ SimplePageMaster spm = pageSeq.getNextSimplePageMaster(
+ index, (startPageOfPageSequence == index), bIsBlank);
+
+ Region body = spm.getRegion(FO_REGION_BODY);
+ if (!pageSeq.getMainFlow().getFlowName().equals(body.getRegionName())) {
+ // this is fine by the XSL Rec (fo:flow's flow-name can be mapped to
+ // any region), but we don't support it yet.
+ throw new FOPException("Flow '" + pageSeq.getMainFlow().getFlowName()
+ + "' does not map to the region-body in page-master '"
+ + spm.getMasterName() + "'. FOP presently "
+ + "does not support this.");
+ }
+ PageViewport pv = new PageViewport(spm, pageNumberString, bIsBlank);
+ cachedPageViewports.add(pv);
+ } catch (FOPException e) {
+ //TODO Maybe improve. It'll mean to propagate this exception up several
+ //methods calls.
+ throw new IllegalStateException(e.getMessage());
+ }
+ }
+
+ }
}