Преглед изворни кода

Initial support for page-position="last". Feedback requested!

See also: http://wiki.apache.org/xmlgraphics-fop/PagePositionLast

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@388182 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_92-beta
Jeremias Maerki пре 18 година
родитељ
комит
97564f21e1

+ 17
- 12
src/java/org/apache/fop/fo/pagination/ConditionalPageMasterReference.java Прегледај датотеку

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2005 The Apache Software Foundation.
* Copyright 1999-2006 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.
@@ -90,28 +90,32 @@ public class ConditionalPageMasterReference extends FObj {
* matches.
* @param isOddPage True if page number odd
* @param isFirstPage True if page is first page
* @param isLastPage True if page is last page
* @param isBlankPage True if page is blank
* @return True if the conditions for this reference are met
*/
protected boolean isValid(boolean isOddPage,
boolean isFirstPage,
boolean isLastPage,
boolean isBlankPage) {
// page-position
if (isFirstPage) {
if (pagePosition == EN_REST) {
return false;
} else if (pagePosition == EN_LAST) {
// ?? how can one know at this point?
getLogger().debug("LAST PagePosition NYI");
return false;
}
} else if (isLastPage) {
if (pagePosition == EN_REST) {
return false;
} else if (pagePosition == EN_FIRST) {
return false;
}
} else {
if (pagePosition == EN_FIRST) {
return false;
} else if (pagePosition == EN_LAST) {
// ?? how can one know at this point?
getLogger().debug("LAST PagePosition NYI");
// potentially valid, don't return
return false;
}
}

@@ -139,21 +143,22 @@ public class ConditionalPageMasterReference extends FObj {
return true;
}

/**
* Returns the "master-reference" property.
*/
/** @return the "master-reference" property. */
public String getMasterReference() {
return masterReference;
}
/** @return the page-position property value */
public int getPagePosition() {
return this.pagePosition;
}
/** @see org.apache.fop.fo.FONode#getLocalName() */
public String getLocalName() {
return "conditional-page-master-reference";
}
/**
* @see org.apache.fop.fo.FObj#getNameId()
*/
/** @see org.apache.fop.fo.FObj#getNameId() */
public int getNameId() {
return FO_CONDITIONAL_PAGE_MASTER_REFERENCE;
}

+ 20
- 7
src/java/org/apache/fop/fo/pagination/PageSequence.java Прегледај датотеку

@@ -436,15 +436,18 @@ public class PageSequence extends FObj {
/**
* 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
* @param isFirstPage indicator whether this page is the first page of the
* page sequence
* @param bIsBlank indicator whether the page will be blank
* @param isLastPage indicator whether this page is the last page of the
* page sequence
* @param isBlank 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 getNextSimplePageMaster(int page,
boolean bIsFirstPage,
boolean bIsBlank) throws FOPException {
boolean isFirstPage,
boolean isLastPage,
boolean isBlank) throws FOPException {

if (pageSequenceMaster == null) {
return simplePageMaster;
@@ -453,11 +456,12 @@ public class PageSequence extends FObj {
if (getLogger().isDebugEnabled()) {
getLogger().debug("getNextSimplePageMaster(page=" + page
+ " isOdd=" + isOddPage
+ " isFirst=" + bIsFirstPage
+ " isBlank=" + bIsBlank + ")");
+ " isFirst=" + isFirstPage
+ " isLast=" + isLastPage
+ " isBlank=" + isBlank + ")");
}
return pageSequenceMaster.getNextSimplePageMaster(isOddPage,
bIsFirstPage, bIsBlank);
isFirstPage, isLastPage, isBlank);
}

/**
@@ -472,6 +476,15 @@ public class PageSequence extends FObj {
}
}

/** @return true if the page-sequence has a page-master with page-position="last" */
public boolean hasPagePositionLast() {
if (pageSequenceMaster == null) {
return false;
} else {
return pageSequenceMaster.hasPagePositionLast();
}
}
/**
* Retrieves the string representation of a page number applicable
* for this page sequence

+ 14
- 3
src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java Прегледај датотеку

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2005 The Apache Software Foundation.
* Copyright 1999-2006 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.
@@ -159,16 +159,27 @@ public class PageSequenceMaster extends FObj {
return (currentSubSequence != null);
}
/** @return true if the page-sequence-master has a page-master with page-position="last" */
public boolean hasPagePositionLast() {
if (currentSubSequence != null) {
return currentSubSequence.hasPagePositionLast();
} else {
return false;
}
}
/**
* Returns the next simple-page-master.
* @param isOddPage True if the next page number is odd
* @param isFirstPage True if the next page is the first
* @param isLastPage True if the next page is the last
* @param isBlankPage True if the next page is blank
* @return the requested page master
* @throws FOPException if there's a problem determining the next page master
*/
public SimplePageMaster getNextSimplePageMaster(boolean isOddPage,
boolean isFirstPage,
boolean isLastPage,
boolean isBlankPage)
throws FOPException {
if (currentSubSequence == null) {
@@ -179,7 +190,7 @@ public class PageSequenceMaster extends FObj {
}
}
String pageMasterName = currentSubSequence
.getNextPageMasterName(isOddPage, isFirstPage, isBlankPage);
.getNextPageMasterName(isOddPage, isFirstPage, isLastPage, isBlankPage);
boolean canRecover = true;
while (pageMasterName == null) {
SubSequenceSpecifier nextSubSequence = getNextSubSequence();
@@ -198,7 +209,7 @@ public class PageSequenceMaster extends FObj {
currentSubSequence = nextSubSequence;
}
pageMasterName = currentSubSequence
.getNextPageMasterName(isOddPage, isFirstPage, isBlankPage);
.getNextPageMasterName(isOddPage, isFirstPage, isLastPage, isBlankPage);
}
SimplePageMaster pageMaster = this.layoutMasterSet
.getSimplePageMaster(pageMasterName);

+ 20
- 7
src/java/org/apache/fop/fo/pagination/RepeatablePageMasterAlternatives.java Прегледај датотеку

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2005 The Apache Software Foundation.
* Copyright 1999-2006 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.
@@ -47,6 +47,7 @@ public class RepeatablePageMasterAlternatives extends FObj
private int numberConsumed = 0;

private List conditionalPageMasterRefs;
private boolean hasPagePositionLast = false;

/**
* @see org.apache.fop.fo.FONode#FONode(FONode)
@@ -93,9 +94,9 @@ public class RepeatablePageMasterAlternatives extends FObj
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (!(FO_URI.equals(nsURI) &&
localName.equals("conditional-page-master-reference"))) {
invalidChildError(loc, nsURI, localName);
if (!(FO_URI.equals(nsURI)
&& localName.equals("conditional-page-master-reference"))) {
invalidChildError(loc, nsURI, localName);
}
}

@@ -121,6 +122,7 @@ public class RepeatablePageMasterAlternatives extends FObj
*/
public String getNextPageMasterName(boolean isOddPage,
boolean isFirstPage,
boolean isLastPage,
boolean isBlankPage) {
if (getMaximumRepeats() != INFINITE) {
if (numberConsumed < getMaximumRepeats()) {
@@ -128,12 +130,14 @@ public class RepeatablePageMasterAlternatives extends FObj
} else {
return null;
}
} else {
numberConsumed++;
}

for (int i = 0; i < conditionalPageMasterRefs.size(); i++) {
ConditionalPageMasterReference cpmr =
(ConditionalPageMasterReference)conditionalPageMasterRefs.get(i);
if (cpmr.isValid(isOddPage, isFirstPage, isBlankPage)) {
ConditionalPageMasterReference cpmr
= (ConditionalPageMasterReference)conditionalPageMasterRefs.get(i);
if (cpmr.isValid(isOddPage, isFirstPage, isLastPage, isBlankPage)) {
return cpmr.getMasterReference();
}
}
@@ -147,6 +151,9 @@ public class RepeatablePageMasterAlternatives extends FObj
*/
public void addConditionalPageMasterReference(ConditionalPageMasterReference cpmr) {
this.conditionalPageMasterRefs.add(cpmr);
if (cpmr.getPagePosition() == EN_LAST) {
this.hasPagePositionLast = true;
}
}

/** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset() */
@@ -164,6 +171,11 @@ public class RepeatablePageMasterAlternatives extends FObj
}
}
/** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#hasPagePositionLast() */
public boolean hasPagePositionLast() {
return this.hasPagePositionLast;
}
/** @see org.apache.fop.fo.FONode#getLocalName() */
public String getLocalName() {
return "repeatable-page-master-alternatives";
@@ -173,4 +185,5 @@ public class RepeatablePageMasterAlternatives extends FObj
public int getNameId() {
return FO_REPEATABLE_PAGE_MASTER_ALTERNATIVES;
}

}

+ 8
- 1
src/java/org/apache/fop/fo/pagination/RepeatablePageMasterReference.java Прегледај датотеку

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2005 The Apache Software Foundation.
* Copyright 1999-2006 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.
@@ -91,6 +91,7 @@ public class RepeatablePageMasterReference extends FObj
*/
public String getNextPageMasterName(boolean isOddPage,
boolean isFirstPage,
boolean isLastPage,
boolean isEmptyPage) {
if (getMaximumRepeats() != INFINITE) {
if (numberConsumed < getMaximumRepeats()) {
@@ -133,6 +134,11 @@ public class RepeatablePageMasterReference extends FObj
}
}
/** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#hasPagePositionLast() */
public boolean hasPagePositionLast() {
return false;
}

/** @see org.apache.fop.fo.FONode#getLocalName() */
public String getLocalName() {
return "repeatable-page-master-reference";
@@ -142,4 +148,5 @@ public class RepeatablePageMasterReference extends FObj
public int getNameId() {
return FO_REPEATABLE_PAGE_MASTER_REFERENCE;
}

}

+ 7
- 1
src/java/org/apache/fop/fo/pagination/SinglePageMasterReference.java Прегледај датотеку

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2005 The Apache Software Foundation.
* Copyright 1999-2006 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.
@@ -83,6 +83,7 @@ public class SinglePageMasterReference extends FObj
/** @see org.apache.fop.fo.pagination.SubSequenceSpecifier */
public String getNextPageMasterName(boolean isOddPage,
boolean isFirstPage,
boolean isLastPage,
boolean isEmptyPage) {
if (this.state == FIRST) {
this.state = DONE;
@@ -109,6 +110,11 @@ public class SinglePageMasterReference extends FObj
}
}
/** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#hasPagePositionLast() */
public boolean hasPagePositionLast() {
return false;
}

/** @see org.apache.fop.fo.FONode#getLocalName() */
public String getLocalName() {
return "single-page-master-reference";

+ 6
- 1
src/java/org/apache/fop/fo/pagination/SubSequenceSpecifier.java Прегледај датотеку

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2005 The Apache Software Foundation.
* Copyright 1999-2006 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.
@@ -30,12 +30,14 @@ public interface SubSequenceSpecifier {
* Returns the name of the next page master.
* @param isOddPage True if the next page number is odd
* @param isFirstPage True if the next page is the first
* @param isLastPage True if the next page is the last
* @param isBlankPage True if the next page is blank
* @return the page master name
* @throws FOPException if there's a problem determining the next page master
*/
String getNextPageMasterName(boolean isOddPage,
boolean isFirstPage,
boolean isLastPage,
boolean isBlankPage)
throws FOPException;

@@ -50,6 +52,9 @@ public interface SubSequenceSpecifier {
* @return true if there is a previous item, false if the current one was the first one.
*/
boolean goToPrevious();

/** @return true if the subsequence has a page master for page-position "last" */
boolean hasPagePositionLast();
}


+ 16
- 2
src/java/org/apache/fop/layoutmgr/AbstractBreaker.java Прегледај датотеку

@@ -318,13 +318,26 @@ public abstract class AbstractBreaker {
*/
protected void addAreas(PageBreakingAlgorithm alg, int partCount,
BlockSequence originalList, BlockSequence effectiveList) {
addAreas(alg, 0, partCount, originalList, effectiveList);
}
/**
* Phase 3 of Knuth algorithm: Adds the areas
* @param alg PageBreakingAlgorithm instance which determined the breaks
* @param startPart index of the first part (page) to be rendered
* @param partCount number of parts (pages) to be rendered
* @param originalList original Knuth element list
* @param effectiveList effective Knuth element list (after adjustments)
*/
protected void addAreas(PageBreakingAlgorithm alg, int startPart, int partCount,
BlockSequence originalList, BlockSequence effectiveList) {
LayoutContext childLC;
// add areas
ListIterator effectiveListIterator = effectiveList.listIterator();
int startElementIndex = 0;
int endElementIndex = 0;
int lastBreak = -1;
for (int p = 0; p < partCount; p++) {
for (int p = startPart; p < startPart + partCount; p++) {
PageBreakPosition pbp = (PageBreakPosition) alg.getPageBreaks().get(p);

//Check the last break position for forced breaks
@@ -426,7 +439,8 @@ public abstract class AbstractBreaker {

/* *** *** non-standard extension *** *** */
if (displayAlign == Constants.EN_X_FILL) {
int averageLineLength = optimizeLineLength(effectiveList, startElementIndex, endElementIndex);
int averageLineLength = optimizeLineLength(effectiveList,
startElementIndex, endElementIndex);
if (averageLineLength != 0) {
childLC.setStackLimit(new MinOptMax(averageLineLength));
}

+ 11
- 0
src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java Прегледај датотеку

@@ -991,4 +991,15 @@ public abstract class BreakingAlgorithm {
bestActiveNode = bestActiveNode.previous;
}
}
/** @return the alignment for normal lines/parts */
public int getAlignment() {
return this.alignment;
}

/** @return the alignment for the last line/part */
public int getAlignmentLast() {
return this.alignmentLast;
}

}

+ 167
- 62
src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java Прегледај датотеку

@@ -154,6 +154,9 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
finishPage();
}
/**
* Finished the page-sequence and notifies everyone about it.
*/
public void finishPageSequence() {
pageSeq.getRoot().notifyPageSequenceFinished(currentPageNum,
(currentPageNum - startPageNum) + 1);
@@ -318,62 +321,132 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
protected void doPhase3(PageBreakingAlgorithm alg, int partCount,
BlockSequence originalList, BlockSequence effectiveList) {
if (needColumnBalancing) {
AbstractBreaker.log.debug("Column balancing now!!!");
AbstractBreaker.log.debug("===================================================");
int restartPoint = pageProvider.getStartingPartIndexForLastPage(partCount);
if (restartPoint > 0) {
addAreas(alg, restartPoint, originalList, effectiveList);
}
int newStartPos;
if (restartPoint > 0) {
PageBreakPosition pbp = (PageBreakPosition)
alg.getPageBreaks().get(restartPoint - 1);
newStartPos = pbp.getLeafPos();
doPhase3WithColumnBalancing(alg, partCount, originalList, effectiveList);
} else {
if (!hasMoreContent() && pageSeq.hasPagePositionLast()) {
//last part is reached and we have a "last page" condition
doPhase3WithLastPage(alg, partCount, originalList, effectiveList);
} else {
newStartPos = 0;
//Directly add areas after finding the breaks
addAreas(alg, partCount, originalList, effectiveList);
}
AbstractBreaker.log.debug("Restarting at " + restartPoint
+ ", new start position: " + newStartPos);
}
}

private void doPhase3WithLastPage(PageBreakingAlgorithm alg, int partCount,
BlockSequence originalList, BlockSequence effectiveList) {
int newStartPos;
int restartPoint = pageProvider.getStartingPartIndexForLastPage(partCount);
if (restartPoint > 0) {
//Add definitive areas before last page
addAreas(alg, restartPoint, originalList, effectiveList);
//Get page break from which we restart
PageBreakPosition pbp = (PageBreakPosition)
alg.getPageBreaks().get(restartPoint - 1);
newStartPos = pbp.getLeafPos();
//Handle page break right here to avoid any side-effects
if (newStartPos > 0) {
handleBreakTrait(EN_PAGE);
}
pageBreakHandled = true;
//Update so the available BPD is reported correctly
pageProvider.setStartOfNextElementList(currentPageNum,
getCurrentPV().getCurrentSpan().getCurrentFlowIndex());
} else {
newStartPos = 0;
}
AbstractBreaker.log.debug("Last page handling now!!!");
AbstractBreaker.log.debug("===================================================");
AbstractBreaker.log.debug("Restarting at " + restartPoint
+ ", new start position: " + newStartPos);

//Restart last page
PageBreakingAlgorithm algRestart = new BalancingColumnBreakingAlgorithm(
getTopLevelLM(),
getPageProvider(),
alignment, Constants.EN_START, footnoteSeparatorLength,
isPartOverflowRecoveryActivated(),
getCurrentPV().getBodyRegion().getColumnCount());
//alg.setConstantLineWidth(flowBPD);
int iOptPageCount = algRestart.findBreakingPoints(effectiveList,
newStartPos,
1, true, BreakingAlgorithm.ALL_BREAKS);
AbstractBreaker.log.debug("restart: iOptPageCount= " + iOptPageCount
+ " pageBreaks.size()= " + algRestart.getPageBreaks().size());
if (iOptPageCount > getCurrentPV().getBodyRegion().getColumnCount()) {
AbstractBreaker.log.warn(
"Breaking algorithm produced more columns than are available.");
/* reenable when everything works
throw new IllegalStateException(
"Breaking algorithm must not produce more columns than available.");
*/
}
pageBreakHandled = true;
//Update so the available BPD is reported correctly
pageProvider.setStartOfNextElementList(currentPageNum,
getCurrentPV().getCurrentSpan().getCurrentFlowIndex());
pageProvider.setLastPageIndex(currentPageNum);

//Restart last page
PageBreakingAlgorithm algRestart = new PageBreakingAlgorithm(
getTopLevelLM(),
getPageProvider(),
alg.getAlignment(), alg.getAlignmentLast(),
footnoteSeparatorLength,
isPartOverflowRecoveryActivated(), false);
//alg.setConstantLineWidth(flowBPD);
int iOptPageCount = algRestart.findBreakingPoints(effectiveList,
newStartPos,
1, true, BreakingAlgorithm.ALL_BREAKS);
AbstractBreaker.log.debug("restart: iOptPageCount= " + iOptPageCount
+ " pageBreaks.size()= " + algRestart.getPageBreaks().size());
boolean replaceLastPage
= iOptPageCount <= getCurrentPV().getBodyRegion().getColumnCount();
if (replaceLastPage) {

//Replace last page
pslm.curPage = pageProvider.getPage(false, currentPageNum);
//Make sure we only add the areas we haven't added already
effectiveList.ignoreAtStart = newStartPos;
addAreas(algRestart, iOptPageCount, originalList, effectiveList);
AbstractBreaker.log.debug("===================================================");
} else {
//Directly add areas after finding the breaks
addAreas(alg, partCount, originalList, effectiveList);
effectiveList.ignoreAtStart = newStartPos;
addAreas(alg, restartPoint, partCount - restartPoint, originalList, effectiveList);
//Add blank last page
pageProvider.setLastPageIndex(currentPageNum + 1);
pslm.curPage = makeNewPage(true, true);
}
AbstractBreaker.log.debug("===================================================");
}

private void doPhase3WithColumnBalancing(PageBreakingAlgorithm alg, int partCount,
BlockSequence originalList, BlockSequence effectiveList) {
AbstractBreaker.log.debug("Column balancing now!!!");
AbstractBreaker.log.debug("===================================================");
int newStartPos;
int restartPoint = pageProvider.getStartingPartIndexForLastPage(partCount);
if (restartPoint > 0) {
//Add definitive areas
addAreas(alg, restartPoint, originalList, effectiveList);
//Get page break from which we restart
PageBreakPosition pbp = (PageBreakPosition)
alg.getPageBreaks().get(restartPoint - 1);
newStartPos = pbp.getLeafPos();
//Handle page break right here to avoid any side-effects
if (newStartPos > 0) {
handleBreakTrait(EN_PAGE);
}
} else {
newStartPos = 0;
}
AbstractBreaker.log.debug("Restarting at " + restartPoint
+ ", new start position: " + newStartPos);

pageBreakHandled = true;
//Update so the available BPD is reported correctly
pageProvider.setStartOfNextElementList(currentPageNum,
getCurrentPV().getCurrentSpan().getCurrentFlowIndex());

//Restart last page
PageBreakingAlgorithm algRestart = new BalancingColumnBreakingAlgorithm(
getTopLevelLM(),
getPageProvider(),
alignment, Constants.EN_START, footnoteSeparatorLength,
isPartOverflowRecoveryActivated(),
getCurrentPV().getBodyRegion().getColumnCount());
//alg.setConstantLineWidth(flowBPD);
int iOptPageCount = algRestart.findBreakingPoints(effectiveList,
newStartPos,
1, true, BreakingAlgorithm.ALL_BREAKS);
AbstractBreaker.log.debug("restart: iOptPageCount= " + iOptPageCount
+ " pageBreaks.size()= " + algRestart.getPageBreaks().size());
if (iOptPageCount > getCurrentPV().getBodyRegion().getColumnCount()) {
AbstractBreaker.log.warn(
"Breaking algorithm produced more columns than are available.");
/* reenable when everything works
throw new IllegalStateException(
"Breaking algorithm must not produce more columns than available.");
*/
}
//Make sure we only add the areas we haven't added already
effectiveList.ignoreAtStart = newStartPos;
addAreas(algRestart, iOptPageCount, originalList, effectiveList);
AbstractBreaker.log.debug("===================================================");
}
protected void startPart(BlockSequence list, int breakClass) {
@@ -728,6 +801,9 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
private int startColumnOfCurrentElementList;
private List cachedPages = new java.util.ArrayList();
private int lastPageIndex = -1;
private int indexOfCachedLastPage = -1;
//Cache to optimize getAvailableBPD() calls
private int lastRequestedIndex = -1;
private int lastReportedBPD = -1;
@@ -756,6 +832,15 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
this.lastReportedBPD = -1;
}
/**
* Sets the index of the last page. This is done as soon as the position of the last page
* is known or assumed.
* @param index the index relative to the first page in the page-sequence
*/
public void setLastPageIndex(int index) {
this.lastPageIndex = index;
}
/**
* Returns the available BPD for the part/page indicated by the index parameter.
* The index is the part/page relative to the start of the current element list.
@@ -823,60 +908,79 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {

/**
* Returns a Page.
* @param bIsBlank true if this page is supposed to be blank.
* @param isBlank true if this page is supposed to be blank.
* @param index Index of the page (see relativeTo)
* @param relativeTo Defines which value the index parameter should be evaluated relative
* to. (One of PageProvider.RELTO_*)
* @return the requested Page
*/
public Page getPage(boolean bIsBlank, int index, int relativeTo) {
public Page getPage(boolean isBlank, int index, int relativeTo) {
if (relativeTo == RELTO_PAGE_SEQUENCE) {
return getPage(bIsBlank, index);
return getPage(isBlank, index);
} else if (relativeTo == RELTO_CURRENT_ELEMENT_LIST) {
int effIndex = startPageOfCurrentElementList + index;
effIndex += startPageOfPageSequence - 1;
return getPage(bIsBlank, effIndex);
return getPage(isBlank, effIndex);
} else {
throw new IllegalArgumentException(
"Illegal value for relativeTo: " + relativeTo);
}
}
private Page getPage(boolean bIsBlank, int index) {
private Page getPage(boolean isBlank, int index) {
boolean isLastPage = (lastPageIndex >= 0) && (index == lastPageIndex);
if (log.isTraceEnabled()) {
log.trace("getPage(" + index + " " + bIsBlank);
log.trace("getPage(" + index + " " + (isBlank ? "blank" : "non-blank")
+ (isLastPage ? " <LAST>" : "") + ")");
}
int intIndex = index - startPageOfPageSequence;
if (log.isTraceEnabled()) {
if (bIsBlank) {
if (isBlank) {
log.trace("blank page requested: " + index);
}
if (isLastPage) {
log.trace("last page requested: " + index);
}
}
while (intIndex >= cachedPages.size()) {
if (log.isTraceEnabled()) {
log.trace("Caching " + index);
}
cacheNextPage(index, bIsBlank);
cacheNextPage(index, isBlank, isLastPage);
}
Page page = (Page)cachedPages.get(intIndex);
if (page.getPageViewport().isBlank() != bIsBlank) {
boolean replace = false;
if (page.getPageViewport().isBlank() != isBlank) {
log.debug("blank condition doesn't match. Replacing PageViewport.");
while (intIndex < cachedPages.size()) {
this.cachedPages.remove(cachedPages.size() - 1);
if (!pageSeq.goToPreviousSimplePageMaster()) {
log.warn("goToPreviousSimplePageMaster() on the first page called!");
}
}
cacheNextPage(index, bIsBlank);
replace = true;
}
if ((isLastPage && indexOfCachedLastPage != intIndex)
|| (!isLastPage && indexOfCachedLastPage >= 0)) {
log.debug("last page condition doesn't match. Replacing PageViewport.");
replace = true;
indexOfCachedLastPage = (isLastPage ? intIndex : -1);
}
if (replace) {
disardCacheStartingWith(intIndex);
page = cacheNextPage(index, isBlank, isLastPage);
}
return page;
}

private void disardCacheStartingWith(int index) {
while (index < cachedPages.size()) {
this.cachedPages.remove(cachedPages.size() - 1);
if (!pageSeq.goToPreviousSimplePageMaster()) {
log.warn("goToPreviousSimplePageMaster() on the first page called!");
}
}
}
private void cacheNextPage(int index, boolean bIsBlank) {
private Page cacheNextPage(int index, boolean isBlank, boolean isLastPage) {
try {
String pageNumberString = pageSeq.makeFormattedPageNumber(index);
SimplePageMaster spm = pageSeq.getNextSimplePageMaster(
index, (startPageOfPageSequence == index), bIsBlank);
index, (startPageOfPageSequence == index), isLastPage, isBlank);
Region body = spm.getRegion(FO_REGION_BODY);
if (!pageSeq.getMainFlow().getFlowName().equals(body.getRegionName())) {
@@ -887,8 +991,9 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
+ spm.getMasterName() + "'. FOP presently "
+ "does not support this.");
}
Page page = new Page(spm, index, pageNumberString, bIsBlank);
Page page = new Page(spm, index, pageNumberString, isBlank);
cachedPages.add(page);
return page;
} catch (FOPException e) {
//TODO Maybe improve. It'll mean to propagate this exception up several
//methods calls.

+ 1
- 1
src/java/org/apache/fop/render/rtf/RTFHandler.java Прегледај датотеку

@@ -186,7 +186,7 @@ public class RTFHandler extends FOEventHandler {
log.warn("Using default simple-page-master from page-sequence-master...");
PageSequenceMaster master
= pageSeq.getRoot().getLayoutMasterSet().getPageSequenceMaster(reference);
this.pagemaster = master.getNextSimplePageMaster(false, false, false);
this.pagemaster = master.getNextSimplePageMaster(false, false, false, false);
}
}


+ 3
- 0
status.xml Прегледај датотеку

@@ -27,6 +27,9 @@

<changes>
<release version="FOP Trunk">
<action context="Code" dev="JM" type="add">
Initial support for page-position="last" added.
</action>
<action context="Code" dev="JM" type="add">
Reenabled loading of user-supplied hyphenation patterns that was available in
FOP 0.20.5. (See "hyphenation-base" option in the user configuration)

+ 168
- 0
test/layoutengine/standard-testcases/page-position_last_1.xml Прегледај датотеку

@@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2006 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.
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$ -->
<testcase>
<info>
<p>
This test checks page-position="last".
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
<fo:region-body margin-bottom="1in" column-count="2" column-gap="10pt" background-color="lightgray"/>
<fo:region-after extent="1in" display-align="after"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="last" page-width="5in" page-height="5in">
<fo:region-body margin-bottom="3in" column-count="2" column-gap="10pt" background-color="rgb(250,250,240)"/>
<fo:region-after extent="1in" display-align="after"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="master">
<fo:repeatable-page-master-alternatives>
<fo:conditional-page-master-reference master-reference="last" page-position="last"/>
<fo:conditional-page-master-reference master-reference="normal" page-position="any"/>
</fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="master" id="replace-last">
<fo:static-content flow-name="xsl-region-after">
<fo:block text-align="end">page <fo:page-number/> of <fo:page-number-citation ref-id="eof"/></fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block-container id="boxA0" height="1.5in" background-color="yellow" text-align="center" display-align="center" break-after="page">
<fo:block>box0</fo:block>
</fo:block-container>
<fo:block-container id="boxA1" height="1.5in" background-color="yellow" text-align="center" display-align="center">
<fo:block>box1</fo:block>
</fo:block-container>
<fo:block-container id="boxA2" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box2</fo:block>
</fo:block-container>
<fo:block-container id="boxA3" height="1.5in" background-color="yellow" text-align="center" display-align="center">
<fo:block>box3</fo:block>
</fo:block-container>
<fo:block-container id="boxA4" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box4</fo:block>
</fo:block-container>
<fo:block-container id="boxA5" height="1.5in" background-color="yellow" text-align="center" display-align="center">
<fo:block>box5</fo:block>
</fo:block-container>
<fo:block-container id="boxA6" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box6</fo:block>
</fo:block-container>
<fo:block-container id="boxA7" height="1.5in" background-color="yellow" text-align="center" display-align="center">
<fo:block>box7</fo:block>
</fo:block-container>
<fo:block-container id="boxA8" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box8</fo:block>
</fo:block-container>
<fo:block-container id="boxA9" height="1.5in" background-color="yellow" text-align="center" display-align="center">
<fo:block>box9</fo:block>
</fo:block-container>
<fo:block-container id="boxA10" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box10</fo:block>
</fo:block-container>
<fo:block id="eof"/>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="master" id="blank-last">
<fo:static-content flow-name="xsl-region-after">
<fo:block text-align="end">page <fo:page-number/> of <fo:page-number-citation ref-id="eof"/></fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block-container id="boxB1" height="1.5in" background-color="yellow" text-align="center" display-align="center">
<fo:block>box1</fo:block>
</fo:block-container>
<fo:block-container id="boxB2" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box2</fo:block>
</fo:block-container>
<fo:block-container id="boxB3" height="1.5in" background-color="yellow" text-align="center" display-align="center">
<fo:block>box3</fo:block>
</fo:block-container>
<fo:block-container id="boxB4" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box4</fo:block>
</fo:block-container>
<fo:block-container id="boxB5" height="1.5in" background-color="yellow" text-align="center" display-align="center">
<fo:block>box5</fo:block>
</fo:block-container>
<fo:block-container id="boxB6" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box6</fo:block>
</fo:block-container>
<fo:block-container id="boxB7" height="1.5in" background-color="yellow" text-align="center" display-align="center">
<fo:block>box7</fo:block>
</fo:block-container>
<fo:block-container id="boxB8" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box8</fo:block>
</fo:block-container>
<fo:block-container id="boxB9" height="1.5in" background-color="yellow" text-align="center" display-align="center">
<fo:block>box9</fo:block>
</fo:block-container>
<fo:block-container id="boxB10" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box10</fo:block>
</fo:block-container>
<fo:block-container id="boxB11" height="1.5in" background-color="orange" text-align="center" display-align="center">
<fo:block>box11</fo:block>
</fo:block-container>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<eval expected="4" xpath="count(//pageSequence[1]/pageViewport)"/>
<eval expected="1" xpath="//block[@prod-id='boxA0']/ancestor::pageViewport/@nr"/>
<eval expected="2" xpath="//block[@prod-id='boxA1']/ancestor::pageViewport/@nr"/>
<eval expected="2" xpath="//block[@prod-id='boxA2']/ancestor::pageViewport/@nr"/>
<eval expected="2" xpath="//block[@prod-id='boxA3']/ancestor::pageViewport/@nr"/>
<eval expected="2" xpath="//block[@prod-id='boxA4']/ancestor::pageViewport/@nr"/>
<eval expected="3" xpath="//block[@prod-id='boxA5']/ancestor::pageViewport/@nr"/>
<eval expected="3" xpath="//block[@prod-id='boxA6']/ancestor::pageViewport/@nr"/>
<eval expected="3" xpath="//block[@prod-id='boxA7']/ancestor::pageViewport/@nr"/>
<eval expected="3" xpath="//block[@prod-id='boxA8']/ancestor::pageViewport/@nr"/>
<eval expected="4" xpath="//block[@prod-id='boxA9']/ancestor::pageViewport/@nr"/>
<eval expected="4" xpath="//block[@prod-id='boxA10']/ancestor::pageViewport/@nr"/>
<eval expected="288000" xpath="//pageViewport[@nr='1']/descendant::regionBody/@bpd"/>
<eval expected="288000" xpath="//pageViewport[@nr='2']/descendant::regionBody/@bpd"/>
<eval expected="288000" xpath="//pageViewport[@nr='3']/descendant::regionBody/@bpd"/>
<eval expected="144000" xpath="//pageViewport[@nr='4']/descendant::regionBody/@bpd"/>
<eval expected="normal" xpath="//pageViewport[@nr='1']/@simple-page-master-name"/>
<eval expected="normal" xpath="//pageViewport[@nr='2']/@simple-page-master-name"/>
<eval expected="normal" xpath="//pageViewport[@nr='3']/@simple-page-master-name"/>
<eval expected="last" xpath="//pageViewport[@nr='4']/@simple-page-master-name"/>

<eval expected="4" xpath="count(//pageSequence[2]/pageViewport)"/>
<eval expected="5" xpath="//block[@prod-id='boxB1']/ancestor::pageViewport/@nr"/>
<eval expected="5" xpath="//block[@prod-id='boxB2']/ancestor::pageViewport/@nr"/>
<eval expected="5" xpath="//block[@prod-id='boxB3']/ancestor::pageViewport/@nr"/>
<eval expected="5" xpath="//block[@prod-id='boxB4']/ancestor::pageViewport/@nr"/>
<eval expected="6" xpath="//block[@prod-id='boxB5']/ancestor::pageViewport/@nr"/>
<eval expected="6" xpath="//block[@prod-id='boxB6']/ancestor::pageViewport/@nr"/>
<eval expected="6" xpath="//block[@prod-id='boxB7']/ancestor::pageViewport/@nr"/>
<eval expected="6" xpath="//block[@prod-id='boxB8']/ancestor::pageViewport/@nr"/>
<eval expected="7" xpath="//block[@prod-id='boxB9']/ancestor::pageViewport/@nr"/>
<eval expected="7" xpath="//block[@prod-id='boxB10']/ancestor::pageViewport/@nr"/>
<eval expected="7" xpath="//block[@prod-id='boxB11']/ancestor::pageViewport/@nr"/>
<eval expected="288000" xpath="//pageViewport[@nr='5']/descendant::regionBody/@bpd"/>
<eval expected="288000" xpath="//pageViewport[@nr='6']/descendant::regionBody/@bpd"/>
<eval expected="288000" xpath="//pageViewport[@nr='7']/descendant::regionBody/@bpd"/>
<eval expected="144000" xpath="//pageViewport[@nr='8']/descendant::regionBody/@bpd"/>
<eval expected="normal" xpath="//pageViewport[@nr='5']/@simple-page-master-name"/>
<eval expected="normal" xpath="//pageViewport[@nr='6']/@simple-page-master-name"/>
<eval expected="normal" xpath="//pageViewport[@nr='7']/@simple-page-master-name"/>
<eval expected="last" xpath="//pageViewport[@nr='8']/@simple-page-master-name"/>
</checks>
</testcase>

Loading…
Откажи
Сачувај