From: Chris Bowditch Date: Tue, 10 Jan 2012 16:14:05 +0000 (+0000) Subject: Bugzilla #50391: X-Git-Tag: fop-1_1rc1old~151 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=fb1489b30e69043c94908c6bd6898d97c697a8b5;p=xmlgraphics-fop.git Bugzilla #50391: Add support for different flow-name of fo:region-body in FOP Submitted by: Peter Hancock git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1229622 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/fop/fo/FOElementMapping.java b/src/java/org/apache/fop/fo/FOElementMapping.java index 8069880c6..495cd274b 100644 --- a/src/java/org/apache/fop/fo/FOElementMapping.java +++ b/src/java/org/apache/fop/fo/FOElementMapping.java @@ -24,6 +24,8 @@ import java.util.HashMap; import org.apache.xmlgraphics.util.QName; +import org.apache.fop.layoutmgr.BlockLevelEventProducer; + /** * Element mapping class for all XSL-FO elements. */ @@ -205,7 +207,9 @@ public class FOElementMapping extends ElementMapping { static class PageSequenceMasterMaker extends ElementMapping.Maker { public FONode make(FONode parent) { - return new org.apache.fop.fo.pagination.PageSequenceMaster(parent); + return new org.apache.fop.fo.pagination.PageSequenceMaster(parent, + BlockLevelEventProducer.Provider.get( + parent.getUserAgent().getEventBroadcaster())); } } diff --git a/src/java/org/apache/fop/fo/pagination/ConditionalPageMasterReference.java b/src/java/org/apache/fop/fo/pagination/ConditionalPageMasterReference.java index 7953731f1..da92c7439 100644 --- a/src/java/org/apache/fop/fo/pagination/ConditionalPageMasterReference.java +++ b/src/java/org/apache/fop/fo/pagination/ConditionalPageMasterReference.java @@ -27,6 +27,7 @@ import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; +import org.apache.fop.layoutmgr.BlockLevelEventProducer; /** * Class modelling the @@ -41,6 +42,8 @@ import org.apache.fop.fo.ValidationException; public class ConditionalPageMasterReference extends FObj { // The value of properties relevant for fo:conditional-page-master-reference. private String masterReference; + // The simple page master referenced + private SimplePageMaster master; private int pagePosition; private int oddOrEven; private int blankOrNotBlank; @@ -127,8 +130,8 @@ public class ConditionalPageMasterReference extends FObj { * Get the value for the master-reference property. * @return the "master-reference" property */ - public String getMasterReference() { - return masterReference; + public SimplePageMaster getMaster() { + return master; } /** @@ -151,4 +154,19 @@ public class ConditionalPageMasterReference extends FObj { public int getNameId() { return FO_CONDITIONAL_PAGE_MASTER_REFERENCE; } + + /** + * called by the parent RepeatablePageMasterAlternatives to resolve object references + * from simple page master reference names + * @param layoutMasterSet the layout-master-set + * @throws ValidationException when a named reference cannot be resolved + * */ + public void resolveReferences(LayoutMasterSet layoutMasterSet) throws ValidationException { + master = layoutMasterSet.getSimplePageMaster(masterReference); + if (master == null) { + BlockLevelEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()) + .noMatchingPageMaster(this, parent.getName(), masterReference, getLocator()); + } + } } diff --git a/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java b/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java index c4189d0c4..533b113d2 100644 --- a/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java +++ b/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java @@ -20,7 +20,6 @@ package org.apache.fop.fo.pagination; // Java -import java.util.Iterator; import java.util.Map; import org.xml.sax.Locator; @@ -75,6 +74,7 @@ public class LayoutMasterSet extends FObj { missingChildElementError("(simple-page-master|page-sequence-master)+"); } checkRegionNames(); + resolveSubSequenceReferences(); } /** @@ -104,7 +104,7 @@ public class LayoutMasterSet extends FObj { for (Region region : spmRegions.values()) { if (allRegions.containsKey(region.getRegionName())) { String defaultRegionName - = allRegions.get(region.getRegionName()); + = allRegions.get(region.getRegionName()); if (!defaultRegionName.equals(region.getDefaultRegionName())) { getFOValidationEventProducer().regionNameMappedToMultipleRegionClasses(this, region.getRegionName(), @@ -118,6 +118,14 @@ public class LayoutMasterSet extends FObj { } } + private void resolveSubSequenceReferences() throws ValidationException { + for (PageSequenceMaster psm : pageSequenceMasters.values()) { + for (SubSequenceSpecifier subSequenceSpecifier : psm.getSubSequenceSpecifier()) { + subSequenceSpecifier.resolveReferences(this); + } + } + } + /** * Add a simple page master. * The name is checked to throw an error if already added. @@ -150,7 +158,7 @@ public class LayoutMasterSet extends FObj { * @return the requested simple-page-master */ public SimplePageMaster getSimplePageMaster(String masterName) { - return this.simplePageMasters.get(masterName); + return simplePageMasters.get(masterName); } /** diff --git a/src/java/org/apache/fop/fo/pagination/PageProductionException.java b/src/java/org/apache/fop/fo/pagination/PageProductionException.java index 39060f3d4..c64bdada3 100644 --- a/src/java/org/apache/fop/fo/pagination/PageProductionException.java +++ b/src/java/org/apache/fop/fo/pagination/PageProductionException.java @@ -25,8 +25,8 @@ import org.xml.sax.Locator; import org.xml.sax.helpers.LocatorImpl; import org.apache.fop.events.Event; -import org.apache.fop.events.EventFormatter; import org.apache.fop.events.EventExceptionManager.ExceptionFactory; +import org.apache.fop.events.EventFormatter; /** * Exception thrown by FOP if there is a problem while producing new pages. @@ -38,6 +38,15 @@ public class PageProductionException extends RuntimeException { private String localizedMessage; private Locator locator; + + /** + * Creates a new PageProductionException. + * @param message the message + */ + public PageProductionException(String message) { + super(message); + } + /** * Creates a new PageProductionException. * @param message the message @@ -48,12 +57,13 @@ public class PageProductionException extends RuntimeException { setLocator(locator); } + /** * Set a location associated with the exception. * @param locator the locator holding the location. */ public void setLocator(Locator locator) { - this.locator = new LocatorImpl(locator); + this.locator = locator != null ? new LocatorImpl(locator) : null; } diff --git a/src/java/org/apache/fop/fo/pagination/PageSequence.java b/src/java/org/apache/fop/fo/pagination/PageSequence.java index ee78bb8ba..1c3b33fa7 100644 --- a/src/java/org/apache/fop/fo/pagination/PageSequence.java +++ b/src/java/org/apache/fop/fo/pagination/PageSequence.java @@ -48,7 +48,7 @@ public class PageSequence extends AbstractPageSequence { // the set of flows includes StaticContent flows also /** Map of flows to their flow name (flow-name, Flow) */ - private Map flowMap; + private Map flowMap; /** * The currentSimplePageMaster is either the page master for the @@ -96,7 +96,7 @@ public class PageSequence extends AbstractPageSequence { /** {@inheritDoc} */ protected void startOfNode() throws FOPException { super.startOfNode(); - flowMap = new java.util.HashMap(); + flowMap = new java.util.HashMap(); this.simplePageMaster = getRoot().getLayoutMasterSet().getSimplePageMaster(masterReference); @@ -239,7 +239,7 @@ public class PageSequence extends AbstractPageSequence { } /** @return the flow map for this page-sequence */ - public Map getFlowMap() { + public Map getFlowMap() { return this.flowMap; } @@ -270,7 +270,7 @@ public class PageSequence extends AbstractPageSequence { + " isBlank=" + isBlank + ")"); } return pageSequenceMaster.getNextSimplePageMaster(isOddPage, - isFirstPage, isLastPage, isBlank); + isFirstPage, isLastPage, isBlank, getMainFlow().getFlowName()); } /** diff --git a/src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java b/src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java index 5b71525d3..5eb3d3259 100644 --- a/src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java +++ b/src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java @@ -20,6 +20,7 @@ package org.apache.fop.fo.pagination; // Java +import java.util.Collections; import java.util.List; import org.xml.sax.Locator; @@ -47,6 +48,7 @@ public class PageSequenceMaster extends FObj { private List subSequenceSpecifiers; private SubSequenceSpecifier currentSubSequence; private int currentSubSequenceNumber = -1; + private BlockLevelEventProducer blockLevelEventProducer; // The terminology may be confusing. A 'page-sequence-master' consists // of a sequence of what the XSL spec refers to as @@ -60,9 +62,11 @@ public class PageSequenceMaster extends FObj { * given {@link FONode}. * * @param parent {@link FONode} that is the parent of this object + * @param blockLevelEventProducer event producer */ - public PageSequenceMaster(FONode parent) { + public PageSequenceMaster(FONode parent, BlockLevelEventProducer blockLevelEventProducer) { super(parent); + this.blockLevelEventProducer = blockLevelEventProducer; } /** {@inheritDoc} */ @@ -126,6 +130,10 @@ public class PageSequenceMaster extends FObj { return null; } + List getSubSequenceSpecifier() { + return Collections.unmodifiableList(subSequenceSpecifiers); + } + /** * Resets the subsequence specifiers subsystem. */ @@ -177,52 +185,58 @@ public class PageSequenceMaster extends FObj { * @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 + * @param mainFlowName the name of the main flow of the page sequence * @return the requested page master * @throws PageProductionException if there's a problem determining the next page master */ public SimplePageMaster getNextSimplePageMaster(boolean isOddPage, boolean isFirstPage, boolean isLastPage, - boolean isBlankPage) + boolean isBlankPage, + String mainFlowName) throws PageProductionException { if (currentSubSequence == null) { currentSubSequence = getNextSubSequence(); if (currentSubSequence == null) { - BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.missingSubsequencesInPageSequenceMaster(this, + blockLevelEventProducer.missingSubsequencesInPageSequenceMaster(this, masterName, getLocator()); } + if (currentSubSequence.isInfinite() && !currentSubSequence.canProcess(mainFlowName)) { + throw new PageProductionException( + "The current sub-sequence will not terminate whilst processing then main flow"); + } } - String pageMasterName = currentSubSequence - .getNextPageMasterName(isOddPage, isFirstPage, isLastPage, isBlankPage); + + SimplePageMaster pageMaster = currentSubSequence + .getNextPageMaster(isOddPage, isFirstPage, isLastPage, isBlankPage); + boolean canRecover = true; - while (pageMasterName == null) { + + while (pageMaster == null) { SubSequenceSpecifier nextSubSequence = getNextSubSequence(); + if (nextSubSequence == null) { - BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.pageSequenceMasterExhausted(this, + //Sub-sequence exhausted so attempt to reuse it + blockLevelEventProducer.pageSequenceMasterExhausted(this, masterName, canRecover, getLocator()); currentSubSequence.reset(); + if (!currentSubSequence.canProcess(mainFlowName)) { + throw new PageProductionException( + "The last simple-page-master does not reference the main flow"); + } canRecover = false; } else { currentSubSequence = nextSubSequence; } - pageMasterName = currentSubSequence - .getNextPageMasterName(isOddPage, isFirstPage, isLastPage, isBlankPage); - } - SimplePageMaster pageMaster = this.layoutMasterSet - .getSimplePageMaster(pageMasterName); - if (pageMaster == null) { - BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.noMatchingPageMaster(this, - masterName, pageMasterName, getLocator()); + + pageMaster = currentSubSequence + .getNextPageMaster(isOddPage, isFirstPage, isLastPage, isBlankPage); } + return pageMaster; } + /** {@inheritDoc} */ public String getLocalName() { return "page-sequence-master"; @@ -235,5 +249,7 @@ public class PageSequenceMaster extends FObj { public int getNameId() { return FO_PAGE_SEQUENCE_MASTER; } + + } diff --git a/src/java/org/apache/fop/fo/pagination/RepeatablePageMasterAlternatives.java b/src/java/org/apache/fop/fo/pagination/RepeatablePageMasterAlternatives.java index 629d7d59d..2ad8a3cfc 100644 --- a/src/java/org/apache/fop/fo/pagination/RepeatablePageMasterAlternatives.java +++ b/src/java/org/apache/fop/fo/pagination/RepeatablePageMasterAlternatives.java @@ -20,6 +20,7 @@ package org.apache.fop.fo.pagination; // Java +import java.util.ArrayList; import java.util.List; import org.xml.sax.Locator; @@ -114,25 +115,24 @@ public class RepeatablePageMasterAlternatives extends FObj } /** {@inheritDoc} */ - public String getNextPageMasterName(boolean isOddPage, + public SimplePageMaster getNextPageMaster(boolean isOddPage, boolean isFirstPage, boolean isLastPage, boolean isBlankPage) { - if (getMaximumRepeats() != INFINITE) { - if (numberConsumed < getMaximumRepeats()) { - numberConsumed++; - } else { - return null; - } - } else { - numberConsumed++; + + if (!isInfinite() && numberConsumed >= getMaximumRepeats()) { + return null; } + numberConsumed++; + for (ConditionalPageMasterReference cpmr : conditionalPageMasterRefs) { if (cpmr.isValid(isOddPage, isFirstPage, isLastPage, isBlankPage)) { - return cpmr.getMasterReference(); + return cpmr.getMaster(); } } + + return null; } @@ -189,4 +189,50 @@ public class RepeatablePageMasterAlternatives extends FObj return FO_REPEATABLE_PAGE_MASTER_ALTERNATIVES; } + + + /** {@inheritDoc} */ + public void resolveReferences(LayoutMasterSet layoutMasterSet) throws ValidationException { + for (ConditionalPageMasterReference conditionalPageMasterReference + : conditionalPageMasterRefs) { + conditionalPageMasterReference.resolveReferences(layoutMasterSet); + } + + } + + /** {@inheritDoc} */ + public boolean canProcess(String flowName) { + + boolean willTerminate = true; + + + //Look for rest spm that cannot terminate + ArrayList rest + = new ArrayList(); + for (ConditionalPageMasterReference cpmr + : conditionalPageMasterRefs) { + if (cpmr.isValid(true, false, false, false) + || cpmr.isValid(false, false, false, false)) { + rest.add(cpmr); + } + } + if (!rest.isEmpty()) { + willTerminate = false; + for (ConditionalPageMasterReference cpmr : rest) { + willTerminate |= cpmr.getMaster().getRegion(FO_REGION_BODY).getRegionName() + .equals(flowName); + } + } + + + return willTerminate; + } + + /** {@inheritDoc} */ + public boolean isInfinite() { + return getMaximumRepeats() == INFINITE; + } + + + } diff --git a/src/java/org/apache/fop/fo/pagination/RepeatablePageMasterReference.java b/src/java/org/apache/fop/fo/pagination/RepeatablePageMasterReference.java index 9bbe55939..83207885a 100644 --- a/src/java/org/apache/fop/fo/pagination/RepeatablePageMasterReference.java +++ b/src/java/org/apache/fop/fo/pagination/RepeatablePageMasterReference.java @@ -28,6 +28,7 @@ import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; import org.apache.fop.fo.properties.Property; +import org.apache.fop.layoutmgr.BlockLevelEventProducer; /** * Class modelling the @@ -40,6 +41,8 @@ public class RepeatablePageMasterReference extends FObj // The value of properties relevant for fo:repeatable-page-master-reference. private String masterReference; + // The simple page master referenced + private SimplePageMaster master; private Property maximumRepeats; // End of property values @@ -87,18 +90,15 @@ public class RepeatablePageMasterReference extends FObj } /** {@inheritDoc} */ - public String getNextPageMasterName(boolean isOddPage, + public SimplePageMaster getNextPageMaster(boolean isOddPage, boolean isFirstPage, boolean isLastPage, boolean isEmptyPage) { - if (getMaximumRepeats() != INFINITE) { - if (numberConsumed < getMaximumRepeats()) { - numberConsumed++; - } else { - return null; - } + if (getMaximumRepeats() != INFINITE && numberConsumed >= getMaximumRepeats()) { + return null; } - return masterReference; + numberConsumed++; + return master; } /** @@ -159,4 +159,27 @@ public class RepeatablePageMasterReference extends FObj } + /** {@inheritDoc} */ + public void resolveReferences(LayoutMasterSet layoutMasterSet) throws ValidationException { + master = layoutMasterSet.getSimplePageMaster(masterReference); + if (master == null) { + BlockLevelEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()) + .noMatchingPageMaster(this, parent.getName(), masterReference, getLocator()); + } + + } + + /** {@inheritDoc} */ + public boolean canProcess(String flowName) { + return master.getRegion(FO_REGION_BODY).getRegionName().equals(flowName); + } + + /** {@inheritDoc} */ + public boolean isInfinite() { + return getMaximumRepeats() == INFINITE; + } + + + } diff --git a/src/java/org/apache/fop/fo/pagination/SimplePageMaster.java b/src/java/org/apache/fop/fo/pagination/SimplePageMaster.java index bd186db78..e38993487 100644 --- a/src/java/org/apache/fop/fo/pagination/SimplePageMaster.java +++ b/src/java/org/apache/fop/fo/pagination/SimplePageMaster.java @@ -21,7 +21,6 @@ package org.apache.fop.fo.pagination; // Java import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import org.xml.sax.Locator; @@ -29,8 +28,8 @@ import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Length; import org.apache.fop.datatypes.Numeric; -import org.apache.fop.datatypes.SimplePercentBaseContext; import org.apache.fop.datatypes.PercentBaseContext; +import org.apache.fop.datatypes.SimplePercentBaseContext; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; diff --git a/src/java/org/apache/fop/fo/pagination/SinglePageMasterReference.java b/src/java/org/apache/fop/fo/pagination/SinglePageMasterReference.java index be13455d7..a39949347 100644 --- a/src/java/org/apache/fop/fo/pagination/SinglePageMasterReference.java +++ b/src/java/org/apache/fop/fo/pagination/SinglePageMasterReference.java @@ -27,6 +27,7 @@ import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; +import org.apache.fop.layoutmgr.BlockLevelEventProducer; /** * Class modelling the @@ -39,6 +40,10 @@ public class SinglePageMasterReference extends FObj // The value of properties relevant for fo:single-page-master-reference. private String masterReference; + + // The simple page master referenced + private SimplePageMaster master; + // End of property values private static final int FIRST = 0; @@ -83,13 +88,13 @@ public class SinglePageMasterReference extends FObj } /** {@inheritDoc} */ - public String getNextPageMasterName(boolean isOddPage, + public SimplePageMaster getNextPageMaster(boolean isOddPage, boolean isFirstPage, boolean isLastPage, boolean isBlankPage) { if (this.state == FIRST) { this.state = DONE; - return masterReference; + return master; } else { return null; } @@ -133,5 +138,25 @@ public class SinglePageMasterReference extends FObj return FO_SINGLE_PAGE_MASTER_REFERENCE; } + /** {@inheritDoc} */ + public void resolveReferences(LayoutMasterSet layoutMasterSet) throws ValidationException { + master = layoutMasterSet.getSimplePageMaster(masterReference); + if (master == null) { + BlockLevelEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()) + .noMatchingPageMaster(this, parent.getName(), masterReference, getLocator()); + } + } + + /** {@inheritDoc} */ + public boolean canProcess(String flowName) { + return master.getRegion(FO_REGION_BODY).getRegionName().equals(flowName); + } + + /** {@inheritDoc} */ + public boolean isInfinite() { + return false; + } + } diff --git a/src/java/org/apache/fop/fo/pagination/SubSequenceSpecifier.java b/src/java/org/apache/fop/fo/pagination/SubSequenceSpecifier.java index 2bb891cd9..330db3b94 100644 --- a/src/java/org/apache/fop/fo/pagination/SubSequenceSpecifier.java +++ b/src/java/org/apache/fop/fo/pagination/SubSequenceSpecifier.java @@ -19,6 +19,7 @@ package org.apache.fop.fo.pagination; +import org.apache.fop.fo.ValidationException; /** * Classes that implement this interface can be added to a {@link PageSequenceMaster}, @@ -36,7 +37,7 @@ public interface SubSequenceSpecifier { * @return the page master name * @throws PageProductionException if there's a problem determining the next page master */ - String getNextPageMasterName(boolean isOddPage, + SimplePageMaster getNextPageMaster(boolean isOddPage, boolean isFirstPage, boolean isLastPage, boolean isBlankPage) @@ -60,5 +61,26 @@ public interface SubSequenceSpecifier { /** @return true if the subsequence has a page master for page-position "only" */ boolean hasPagePositionOnly(); + /** + * called by the parent LayoutMasterSet to resolve object references + * from simple page master reference names + * @param layoutMasterSet the layout-master-set + * @throws ValidationException when a named reference cannot be resolved + * */ + void resolveReferences(LayoutMasterSet layoutMasterSet) throws ValidationException; + + /** + * + * @param flowName name of the main flow + * @return true iff page sequence is a finite sequence or can process the entire main flow + */ + boolean canProcess(String flowName); + + /** + * Test that this is a finite sequence + * @return true iff this is a finite sequence + */ + boolean isInfinite(); + } diff --git a/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java index fba571df3..f36cde158 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java @@ -276,10 +276,9 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa * Makes a new page * * @param isBlank whether this page is blank or not - * @param isLast whether this page is the last page or not * @return a new page */ - protected Page makeNewPage(boolean isBlank, boolean isLast) { + protected Page makeNewPage(boolean isBlank) { if (curPage != null) { finishPage(); } @@ -360,19 +359,19 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa if (forcePageCount == Constants.EN_EVEN) { if ((currentPageNum - startPageNum + 1) % 2 != 0) { // we have an odd number of pages - curPage = makeNewPage(true, false); + curPage = makeNewPage(true); } } else if (forcePageCount == Constants.EN_ODD) { if ((currentPageNum - startPageNum + 1) % 2 == 0) { // we have an even number of pages - curPage = makeNewPage(true, false); + curPage = makeNewPage(true); } } else if (forcePageCount == Constants.EN_END_ON_EVEN) { if (currentPageNum % 2 != 0) { // we are now on an odd page - curPage = makeNewPage(true, false); + curPage = makeNewPage(true); } } else if (forcePageCount == Constants.EN_END_ON_ODD) { if (currentPageNum % 2 == 0) { // we are now on an even page - curPage = makeNewPage(true, false); + curPage = makeNewPage(true); } } else if (forcePageCount == Constants.EN_NO_FORCE) { // i hope: nothing special at all diff --git a/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java index 9fb832da3..c4aa1a39b 100644 --- a/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java @@ -167,7 +167,7 @@ public class ExternalDocumentLayoutManager extends AbstractPageSequenceLayoutMan private void makePageForImage(ImageInfo info, ImageLayout layout) { this.imageLayout = layout; - curPage = makeNewPage(false, false); + curPage = makeNewPage(false); fillPage(info.getOriginalURI()); finishPage(); } diff --git a/src/java/org/apache/fop/layoutmgr/PageBreaker.java b/src/java/org/apache/fop/layoutmgr/PageBreaker.java index 90e1b3e51..8fd131a73 100644 --- a/src/java/org/apache/fop/layoutmgr/PageBreaker.java +++ b/src/java/org/apache/fop/layoutmgr/PageBreaker.java @@ -412,7 +412,7 @@ public class PageBreaker extends AbstractBreaker { addAreas(alg, restartPoint, partCount - restartPoint, originalList, effectiveList); //...and add a blank last page setLastPageIndex(currentPageNum + 1); - pslm.setCurrentPage(pslm.makeNewPage(true, true)); + pslm.setCurrentPage(pslm.makeNewPage(true)); return; } } @@ -535,14 +535,14 @@ public class PageBreaker extends AbstractBreaker { if (forceNewPageWithSpan) { log.trace("Forcing new page with span"); - curPage = pslm.makeNewPage(false, false); + curPage = pslm.makeNewPage(false); curPage.getPageViewport().createSpan(true); } else if (pv.getCurrentSpan().hasMoreFlows()) { log.trace("Moving to next flow"); pv.getCurrentSpan().moveToNextFlow(); } else { log.trace("Making new page"); - /*curPage = */pslm.makeNewPage(false, false); + /*curPage = */pslm.makeNewPage(false); } return; default: @@ -550,11 +550,11 @@ public class PageBreaker extends AbstractBreaker { + " breakVal=" + getBreakClassName(breakVal)); if (needBlankPageBeforeNew(breakVal)) { log.trace("Inserting blank page"); - /*curPage = */pslm.makeNewPage(true, false); + /*curPage = */pslm.makeNewPage(true); } if (needNewPage(breakVal)) { log.trace("Making new page"); - /*curPage = */pslm.makeNewPage(false, false); + /*curPage = */pslm.makeNewPage(false); } } } diff --git a/src/java/org/apache/fop/layoutmgr/PageProvider.java b/src/java/org/apache/fop/layoutmgr/PageProvider.java index 8caafa72b..364839f8a 100644 --- a/src/java/org/apache/fop/layoutmgr/PageProvider.java +++ b/src/java/org/apache/fop/layoutmgr/PageProvider.java @@ -27,7 +27,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.area.AreaTreeHandler; import org.apache.fop.fo.Constants; import org.apache.fop.fo.pagination.PageSequence; -import org.apache.fop.fo.pagination.Region; import org.apache.fop.fo.pagination.SimplePageMaster; /** @@ -52,7 +51,7 @@ public class PageProvider implements Constants { private int startPageOfCurrentElementList; private int startColumnOfCurrentElementList; private boolean spanAllForCurrentElementList; - private List cachedPages = new java.util.ArrayList(); + private List cachedPages = new java.util.ArrayList(); private int lastPageIndex = -1; private int indexOfCachedLastPage = -1; @@ -298,7 +297,7 @@ public class PageProvider implements Constants { } cacheNextPage(index, isBlank, isLastPage, this.spanAllForCurrentElementList); } - Page page = (Page)cachedPages.get(intIndex); + Page page = cachedPages.get(intIndex); boolean replace = false; if (page.getPageViewport().isBlank() != isBlank) { log.debug("blank condition doesn't match. Replacing PageViewport."); @@ -332,15 +331,6 @@ public class PageProvider implements Constants { SimplePageMaster spm = pageSeq.getNextSimplePageMaster( index, isFirstPage, isLastPage, isBlank); - 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. - BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get( - pageSeq.getUserAgent().getEventBroadcaster()); - eventProducer.flowNotMappingToRegionBody(this, - pageSeq.getMainFlow().getFlowName(), spm.getMasterName(), spm.getLocator()); - } Page page = new Page(spm, index, pageNumberString, isBlank, spanAll); //Set unique key obtained from the AreaTreeHandler page.getPageViewport().setKey(areaTreeHandler.generatePageViewportKey()); diff --git a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java index 2e09166c7..1b2b5d7c5 100644 --- a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java @@ -101,7 +101,7 @@ public class PageSequenceLayoutManager extends AbstractPageSequenceLayoutManager log.debug("Starting layout"); } - curPage = makeNewPage(false, false); + curPage = makeNewPage(false); PageBreaker breaker = new PageBreaker(this); int flowBPD = getCurrentPV().getBodyRegion().getRemainingBPD(); @@ -141,6 +141,18 @@ public class PageSequenceLayoutManager extends AbstractPageSequenceLayoutManager pageNumber, PageProvider.RELTO_PAGE_SEQUENCE); } + @Override + protected Page makeNewPage(boolean isBlank) { + Page newPage; + + do { + newPage = super.makeNewPage(isBlank); + } while (!getPageSequence().getMainFlow().getFlowName() + .equals(newPage.getSimplePageMaster().getRegion(FO_REGION_BODY).getRegionName())); + + return newPage; + } + private void layoutSideRegion(int regionID) { SideRegion reg = (SideRegion)curPage.getSimplePageMaster().getRegion(regionID); if (reg == null) { diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java index 56bc0287f..9abde32ce 100644 --- a/src/java/org/apache/fop/render/rtf/RTFHandler.java +++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java @@ -32,7 +32,6 @@ import java.util.Iterator; import java.util.Map; import org.w3c.dom.Document; - import org.xml.sax.SAXException; import org.apache.commons.io.IOUtils; @@ -118,13 +117,13 @@ import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfFootnote; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfHyperLink; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfList; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem; +import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem.RtfListItemLabel; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfPage; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfSection; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTable; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableCell; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableRow; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTextrun; -import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem.RtfListItemLabel; import org.apache.fop.render.rtf.rtflib.tools.BuilderContext; import org.apache.fop.render.rtf.rtflib.tools.PercentContext; import org.apache.fop.render.rtf.rtflib.tools.TableContext; @@ -218,7 +217,7 @@ public class RTFHandler extends FOEventHandler { PageSequenceMaster master = pageSeq.getRoot().getLayoutMasterSet().getPageSequenceMaster(reference); this.pagemaster = master.getNextSimplePageMaster( - false, false, false, false); + false, false, false, false, pageSeq.getMainFlow().getFlowName()); } } diff --git a/status.xml b/status.xml index 5006a20cc..df40973f4 100644 --- a/status.xml +++ b/status.xml @@ -61,6 +61,9 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> + + Add support for different flow-name of fo:region-body in FOP + Tagged PDF performance improvement plus tests diff --git a/test/java/org/apache/fop/fo/flow/table/AllTests.java b/test/java/org/apache/fop/fo/flow/table/AllTests.java new file mode 100644 index 000000000..5b5c32a18 --- /dev/null +++ b/test/java/org/apache/fop/fo/flow/table/AllTests.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.flow.table; + +import org.junit.runners.Suite; + +/** + * All test to be added in FOTreeTestSuite + * + */ +@Suite.SuiteClasses({ CollapsedConditionalBorderTestCase.class, IllegalRowSpanTestCase.class, + RowGroupBuilderTestCase.class, TableColumnColumnNumberTestCase.class, + TooManyColumnsTestCase.class }) + +public final class AllTests { +} + diff --git a/test/java/org/apache/fop/fo/pagination/AllTests.java b/test/java/org/apache/fop/fo/pagination/AllTests.java new file mode 100644 index 000000000..a91203251 --- /dev/null +++ b/test/java/org/apache/fop/fo/pagination/AllTests.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.pagination; + +import org.junit.runners.Suite; +import org.junit.runner.RunWith; + +/** + * All test to be added in FOTreeTestSuite + * + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ PageSequenceMasterTestCase.class, + RepeatablePageMasterAlternativesTestCase.class}) + +public final class AllTests { + +} diff --git a/test/java/org/apache/fop/fo/pagination/PageSequenceMasterTestCase.java b/test/java/org/apache/fop/fo/pagination/PageSequenceMasterTestCase.java new file mode 100644 index 000000000..23c0522e6 --- /dev/null +++ b/test/java/org/apache/fop/fo/pagination/PageSequenceMasterTestCase.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.pagination; + +import static org.junit.Assert.fail; + +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.fop.fo.FONode; +import org.apache.fop.layoutmgr.BlockLevelEventProducer; + +import org.junit.Test; + + +/** + * Unit Test for PageSequenceMaster + * + */ +public class PageSequenceMasterTestCase { + + /** + * Test that PageProductionException is thrown if the final simple-page-master + * cannot handle the main-flow of the page sequence + * @throws Exception exception + */ + @Test + public void testGetNextSimplePageMasterException() throws Exception { + + final String mainFlowRegionName = "main"; + final String emptyFlowRegionName = "empty"; + // Create stubs + + FONode mockParent = mock(FONode.class); + Root mockRoot = mock(Root.class); + LayoutMasterSet mockLayoutMasterSet = mock(LayoutMasterSet.class); + + // This will represent a page master that does not map to the main flow + // of the page sequence + SimplePageMaster mockEmptySPM = mock(SimplePageMaster.class); + Region mockRegion = mock(Region.class); + SinglePageMasterReference mockSinglePageMasterReference + = mock(SinglePageMasterReference.class); + BlockLevelEventProducer mockBlockLevelEventProducer = mock(BlockLevelEventProducer.class); + + //Stub behaviour + when(mockParent.getRoot()).thenReturn(mockRoot); + when(mockRoot.getLayoutMasterSet()).thenReturn(mockLayoutMasterSet); + + //The layout master set should return the empty page master + when(mockLayoutMasterSet.getSimplePageMaster(anyString())).thenReturn(mockEmptySPM); + when(mockEmptySPM.getRegion(anyInt())).thenReturn(mockRegion); + + when(mockRegion.getRegionName()).thenReturn(emptyFlowRegionName); + + when(mockSinglePageMasterReference.getNextPageMaster(anyBoolean(), anyBoolean(), + anyBoolean(), anyBoolean())) + .thenReturn(null, mockEmptySPM); + + PageSequenceMaster pageSequenceMaster = new PageSequenceMaster(mockParent, + mockBlockLevelEventProducer); + pageSequenceMaster.startOfNode(); + pageSequenceMaster.addSubsequenceSpecifier(mockSinglePageMasterReference); + + try { + pageSequenceMaster.getNextSimplePageMaster(false, false, false, false, + mainFlowRegionName); + fail("The next simple page master does not refer to the main flow"); + } catch (PageProductionException ppe) { + //Passed test + } + } + +} + diff --git a/test/java/org/apache/fop/fo/pagination/RepeatablePageMasterAlternativesTestCase.java b/test/java/org/apache/fop/fo/pagination/RepeatablePageMasterAlternativesTestCase.java new file mode 100644 index 000000000..d2c5b3f13 --- /dev/null +++ b/test/java/org/apache/fop/fo/pagination/RepeatablePageMasterAlternativesTestCase.java @@ -0,0 +1,171 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.pagination; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; + +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.expr.NumericProperty; +import org.apache.fop.fo.properties.Property; + + + +/** + * Unit Test for RepeatablePageMasterAlternatives + * + */ +public class RepeatablePageMasterAlternativesTestCase +implements Constants { + + /** + * + * @throws Exception exception + */ + @Test + public void testIsInfinite1() throws Exception { + // Create fixture + Property maximumRepeats = mock(Property.class); + ConditionalPageMasterReference cpmr = createCPMR("empty"); + + when(maximumRepeats.getEnum()).thenReturn(EN_NO_LIMIT); + + RepeatablePageMasterAlternatives objectUnderTest + = createRepeatablePageMasterAlternatives(cpmr, maximumRepeats); + + assertTrue("is infinite", objectUnderTest.isInfinite()); + } + + /** + * + * @throws Exception exception + */ + @Test + public void testIsInfinite2() throws Exception { + // Create fixture + Property maximumRepeats = mock(Property.class); + ConditionalPageMasterReference cpmr = createCPMR("empty"); + + NumericProperty numericProperty = mock(NumericProperty.class); + + final int maxRepeatNum = 0; + assertTrue(maxRepeatNum != EN_NO_LIMIT); + + when(maximumRepeats.getEnum()).thenReturn(maxRepeatNum); + when(maximumRepeats.getNumeric()).thenReturn(numericProperty); + + RepeatablePageMasterAlternatives objectUnderTest + = createRepeatablePageMasterAlternatives(createCPMR("empty"), + maximumRepeats); + + assertTrue("is infinite", !objectUnderTest.isInfinite()); + } + + /** + * Test that an infinite sequence of empty page masters has + * willTerminiate() returning false + * @throws Exception exception + */ + @Test + public void testCanProcess1() throws Exception { + // Create fixture + Property maximumRepeats = mock(Property.class); + ConditionalPageMasterReference cpmr = createCPMR("empty"); + + when(maximumRepeats.getEnum()).thenReturn(EN_NO_LIMIT); + when(cpmr.isValid(anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean())) + .thenReturn(true); + + RepeatablePageMasterAlternatives objectUnderTest + = createRepeatablePageMasterAlternatives(cpmr, maximumRepeats); + + //Fixture assertion + assertTrue("Should be infinite", objectUnderTest.isInfinite()); + + //Test assertion + assertTrue("Infinite sequences that do not process the main flow will " + + " not terminate", + !objectUnderTest.canProcess("main-flow")); + } + /** + * Test that a finite sequence of simple page masters has + * willTerminate() returning true + * + * @throws Exception exception + */ + @Test + public void testCanProcess2() throws Exception { + // Create fixture + Property maximumRepeats = mock(Property.class); + NumericProperty numericProperty = mock(NumericProperty.class); + + final int maxRepeatNum = 0; + + when(maximumRepeats.getEnum()).thenReturn(maxRepeatNum); + when(maximumRepeats.getNumeric()).thenReturn(numericProperty); + + RepeatablePageMasterAlternatives objectUnderTest + = createRepeatablePageMasterAlternatives(createCPMR("empty"), + maximumRepeats); + + //Fixture assertion + assertTrue("Should be finite sequence", !objectUnderTest.isInfinite()); + + //Test assertion + assertTrue("Finite sequences will terminate", + objectUnderTest.canProcess("main-flow")); + } + + private ConditionalPageMasterReference createCPMR(String regionName) { + ConditionalPageMasterReference cpmr = mock(ConditionalPageMasterReference.class); + SimplePageMaster master = mock(SimplePageMaster.class); + Region region = mock(Region.class); + when(master.getRegion(anyInt())).thenReturn(region); + when(region.getRegionName()).thenReturn(regionName); + when(cpmr.getMaster()).thenReturn(master); + + return cpmr; + } + + private RepeatablePageMasterAlternatives createRepeatablePageMasterAlternatives( + ConditionalPageMasterReference cpmr, Property maximumRepeats) throws Exception { + + PropertyList pList = mock(PropertyList.class); + + when(pList.get(anyInt())).thenReturn(maximumRepeats); + + PageSequenceMaster parent = mock(PageSequenceMaster.class); + + RepeatablePageMasterAlternatives sut = new RepeatablePageMasterAlternatives(parent); + + sut.startOfNode(); + sut.bind(pList); + sut.addConditionalPageMasterReference(cpmr); + return sut; + } + +} + diff --git a/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java b/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java index f128055ac..4a77ca000 100644 --- a/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java +++ b/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java @@ -22,22 +22,14 @@ package org.apache.fop.fotreetest; import org.junit.runner.RunWith; import org.junit.runners.Suite; -import org.apache.fop.fo.flow.table.CollapsedConditionalBorderTestCase; -import org.apache.fop.fo.flow.table.IllegalRowSpanTestCase; -import org.apache.fop.fo.flow.table.RowGroupBuilderTestCase; -import org.apache.fop.fo.flow.table.TableColumnColumnNumberTestCase; -import org.apache.fop.fo.flow.table.TooManyColumnsTestCase; - /** * JUnit test suit for running layout engine test under JUnit control. */ @RunWith(Suite.class) @Suite.SuiteClasses({ - TooManyColumnsTestCase.class, - IllegalRowSpanTestCase.class, - RowGroupBuilderTestCase.class, - TableColumnColumnNumberTestCase.class, - CollapsedConditionalBorderTestCase.class, + org.apache.fop.fo.flow.table.AllTests.class, + org.apache.fop.fo.pagination.AllTests.class, FOTreeTestCase.class }) + public final class FOTreeTestSuite { }