From 9263449d44a00d7f223d47a83630abb4bd5aaf84 Mon Sep 17 00:00:00 2001 From: "Andreas L. Delmelle" Date: Sat, 7 Jul 2007 00:04:25 +0000 Subject: [PATCH] Bugzilla 42089: Cleanup and restructuring (suggested by Adrian Cumiskey) git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@554094 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/area/AreaTreeHandler.java | 299 +++---- src/java/org/apache/fop/area/IDTracker.java | 203 +++++ .../org/apache/fop/area/RenderPagesModel.java | 21 +- src/java/org/apache/fop/fo/FObj.java | 28 +- .../fop/fo/flow/AbstractListItemPart.java | 16 +- .../org/apache/fop/fo/flow/BasicLink.java | 14 + src/java/org/apache/fop/fo/flow/Block.java | 34 +- .../apache/fop/fo/flow/BlockContainer.java | 12 +- .../org/apache/fop/fo/flow/Character.java | 12 +- .../apache/fop/fo/flow/ExternalGraphic.java | 2 +- .../fop/fo/flow/InitialPropertySet.java | 9 +- src/java/org/apache/fop/fo/flow/Inline.java | 15 +- .../apache/fop/fo/flow/InlineContainer.java | 17 +- .../org/apache/fop/fo/flow/InlineLevel.java | 1 + .../fop/fo/flow/InstreamForeignObject.java | 7 - src/java/org/apache/fop/fo/flow/Leader.java | 17 - .../org/apache/fop/fo/flow/ListBlock.java | 10 +- src/java/org/apache/fop/fo/flow/ListItem.java | 12 +- .../org/apache/fop/fo/flow/MultiCase.java | 9 +- .../apache/fop/fo/flow/MultiProperties.java | 23 - .../apache/fop/fo/flow/MultiPropertySet.java | 15 +- .../org/apache/fop/fo/flow/MultiSwitch.java | 14 +- .../org/apache/fop/fo/flow/PageNumber.java | 10 +- .../fop/fo/flow/PageNumberCitation.java | 10 +- src/java/org/apache/fop/fo/flow/Table.java | 11 +- .../apache/fop/fo/flow/TableAndCaption.java | 20 - .../org/apache/fop/fo/flow/TableCaption.java | 15 +- .../org/apache/fop/fo/flow/TableCell.java | 16 +- .../org/apache/fop/fo/flow/TableFObj.java | 1 + src/java/org/apache/fop/fo/flow/TableRow.java | 11 +- src/java/org/apache/fop/fo/flow/Wrapper.java | 20 - .../fop/fo/pagination/PageSequence.java | 10 +- .../fo/pagination/PageSequenceWrapper.java | 15 +- .../apache/fop/layoutmgr/AbstractBreaker.java | 18 +- .../BalancingColumnBreakingAlgorithm.java | 3 +- .../org/apache/fop/layoutmgr/PageBreaker.java | 542 ++++++++++++ .../fop/layoutmgr/PageBreakingAlgorithm.java | 4 +- .../apache/fop/layoutmgr/PageProvider.java | 279 +++++++ .../layoutmgr/PageSequenceLayoutManager.java | 789 ++---------------- .../inline/BasicLinkLayoutManager.java | 15 +- .../org/apache/fop/render/rtf/RTFHandler.java | 2 +- status.xml | 7 + 42 files changed, 1305 insertions(+), 1283 deletions(-) create mode 100644 src/java/org/apache/fop/area/IDTracker.java create mode 100644 src/java/org/apache/fop/layoutmgr/PageBreaker.java create mode 100644 src/java/org/apache/fop/layoutmgr/PageProvider.java diff --git a/src/java/org/apache/fop/area/AreaTreeHandler.java b/src/java/org/apache/fop/area/AreaTreeHandler.java index 0104d0688..6903510d0 100644 --- a/src/java/org/apache/fop/area/AreaTreeHandler.java +++ b/src/java/org/apache/fop/area/AreaTreeHandler.java @@ -21,12 +21,7 @@ package org.apache.fop.area; // Java import java.io.OutputStream; -import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.Set; -import java.util.HashSet; import java.util.Iterator; // XML @@ -65,34 +60,24 @@ import org.apache.fop.fo.extensions.destination.Destination; * type of renderer. */ public class AreaTreeHandler extends FOEventHandler { + + private static Log log = LogFactory.getLog(AreaTreeHandler.class); - /** debug statistics */ + // Recorder of debug statistics private Statistics statistics = null; - private static Log log = LogFactory.getLog(AreaTreeHandler.class); - - // the LayoutManager maker + // The LayoutManager maker private LayoutManagerMaker lmMaker; - /** AreaTreeModel in use */ + /** The AreaTreeModel in use */ protected AreaTreeModel model; + // Keeps track of all meaningful id references + private IDTracker idTracker; + // The fo:root node of the document private Root rootFObj; - - // HashMap of ID's whose area is located on one or more consecutive - // PageViewports. Each ID has an arraylist of PageViewports that - // form the defined area of this ID - private Map idLocations = new HashMap(); - - // idref's whose target PageViewports have yet to be identified - // Each idref has a HashSet of Resolvable objects containing that idref - private Map unresolvedIDRefs = new HashMap(); - - private Set unfinishedIDs = new HashSet(); - - private Set alreadyResolvedIDs = new HashSet(); - + // The formatting results to be handed back to the caller. private FormattingResults results = new FormattingResults(); @@ -120,6 +105,8 @@ public class AreaTreeHandler extends FOEventHandler { lmMaker = new LayoutManagerMapping(); } + idTracker = new IDTracker(); + if (log.isDebugEnabled()) { statistics = new Statistics(); } @@ -159,137 +146,12 @@ public class AreaTreeHandler extends FOEventHandler { } /** - * Tie a PageViewport with an ID found on a child area of the PV. Note that - * an area with a given ID may be on more than one PV, hence an ID may have - * more than one PV associated with it. + * Get the IDTracker for this area tree. * - * @param id the property ID of the area - * @param pv a page viewport that contains the area with this ID + * @return IDTracker used to track reference ids for items in this area tree */ - public void associateIDWithPageViewport(String id, PageViewport pv) { - if (log.isDebugEnabled()) { - log.debug("associateIDWithPageViewport(" + id + ", " + pv + ")"); - } - List pvList = (List) idLocations.get(id); - if (pvList == null) { // first time ID located - pvList = new ArrayList(); - idLocations.put(id, pvList); - pvList.add(pv); - // signal the PageViewport that it is the first PV to contain this id: - pv.setFirstWithID(id); - /* - * See if this ID is in the unresolved idref list, if so resolve - * Resolvable objects tied to it. - */ - if (!unfinishedIDs.contains(id)) { - tryIDResolution(id, pv, pvList); - } - } else { - pvList.add(pv); - } - } - - /** - * This method tie an ID to the areaTreeHandler until this one is ready to - * be processed. This is used in page-number-citation-last processing so we - * know when an id can be resolved. - * - * @param id the id of the object being processed - */ - public void signalPendingID(String id) { - if (log.isDebugEnabled()) { - log.debug("signalPendingID(" + id + ")"); - } - unfinishedIDs.add(id); - } - - /** - * Signals that all areas for the formatting object with the given ID have - * been generated. This is used to determine when page-number-citation-last - * ref-ids can be resolved. - * - * @param id the id of the formatting object which was just finished - */ - public void signalIDProcessed(String id) { - if (log.isDebugEnabled()) { - log.debug("signalIDProcessed(" + id + ")"); - } - - alreadyResolvedIDs.add(id); - if (!unfinishedIDs.contains(id)) { - return; - } - unfinishedIDs.remove(id); - - List pvList = (List) idLocations.get(id); - Set todo = (Set) unresolvedIDRefs.get(id); - if (todo != null) { - for (Iterator iter = todo.iterator(); iter.hasNext();) { - Resolvable res = (Resolvable) iter.next(); - res.resolveIDRef(id, pvList); - } - unresolvedIDRefs.remove(id); - } - } - - /** - * Check if an ID has already been resolved - * - * @param id the id to check - * @return true if the ID has been resolved - */ - public boolean alreadyResolvedID(String id) { - return (alreadyResolvedIDs.contains(id)); - } - - /** - * Tries to resolve all unresolved ID references on the given page. - * - * @param id ID to resolve - * @param pv page viewport whose ID refs to resolve - * @param List of PageViewports - */ - private void tryIDResolution(String id, PageViewport pv, List pvList) { - Set todo = (Set) unresolvedIDRefs.get(id); - if (todo != null) { - for (Iterator iter = todo.iterator(); iter.hasNext();) { - Resolvable res = (Resolvable) iter.next(); - if (!unfinishedIDs.contains(id)) { - res.resolveIDRef(id, pvList); - } else { - return; - } - } - alreadyResolvedIDs.add(id); - unresolvedIDRefs.remove(id); - } - } - - /** - * Tries to resolve all unresolved ID references on the given page. - * - * @param pv page viewport whose ID refs to resolve - */ - public void tryIDResolution(PageViewport pv) { - String[] ids = pv.getIDRefs(); - if (ids != null) { - for (int i = 0; i < ids.length; i++) { - List pvList = (List) idLocations.get(ids[i]); - if (pvList != null) { - tryIDResolution(ids[i], pv, pvList); - } - } - } - } - - /** - * Get the list of page viewports that have an area with a given id. - * - * @param id the id to lookup - * @return the list of PageViewports - */ - public List getPageViewportsContainingID(String id) { - return (List) idLocations.get(id); + public IDTracker getIDTracker() { + return idTracker; } /** @@ -301,22 +163,6 @@ public class AreaTreeHandler extends FOEventHandler { return this.results; } - /** - * Add an Resolvable object with an unresolved idref - * - * @param idref the idref whose target id has not yet been located - * @param res the Resolvable object needing the idref to be resolved - */ - public void addUnresolvedIDRef(String idref, Resolvable res) { - Set todo = (Set) unresolvedIDRefs.get(idref); - if (todo == null) { - todo = new HashSet(); - unresolvedIDRefs.put(idref, todo); - } - // add Resolvable object to this HashSet - todo.add(res); - } - /** * Prepare AreaTreeHandler for document processing This is called from * FOTreeBuilder.startDocument() @@ -453,12 +299,13 @@ public class AreaTreeHandler extends FOEventHandler { Resolvable res = (Resolvable) odi; String[] ids = res.getIDRefs(); for (int count = 0; count < ids.length; count++) { - if (idLocations.containsKey(ids[count])) { - res.resolveIDRef(ids[count], (List) idLocations.get(ids[count])); + List pageVPList = idTracker.getPageViewportsContainingID(ids[count]); + if (pageVPList != null) { + res.resolveIDRef(ids[count], pageVPList); } else { log.warn(odi.getName() + ": Unresolved id reference \"" + ids[count] + "\" found."); - addUnresolvedIDRef(ids[count], res); + idTracker.addUnresolvedIDRef(ids[count], res); } } // check to see if ODI is now fully resolved, if so process it @@ -481,9 +328,86 @@ public class AreaTreeHandler extends FOEventHandler { } /** - * Gather statistics when log is debug + * Tie a PageViewport with an ID found on a child area of the PV. Note that + * an area with a given ID may be on more than one PV, hence an ID may have + * more than one PV associated with it. + * + * @param id the property ID of the area + * @param pv a page viewport that contains the area with this ID + * @deprecated use getIdTracker().associateIDWithPageViewport(id, pv) instead + */ + public void associateIDWithPageViewport(String id, PageViewport pv) { + idTracker.associateIDWithPageViewport(id, pv); + } + + /** + * This method tie an ID to the areaTreeHandler until this one is ready to + * be processed. This is used in page-number-citation-last processing so we + * know when an id can be resolved. + * + * @param id the id of the object being processed + * @deprecated use getIdTracker().signalPendingID(id) instead + */ + public void signalPendingID(String id) { + idTracker.signalPendingID(id); + } + + /** + * Signals that all areas for the formatting object with the given ID have + * been generated. This is used to determine when page-number-citation-last + * ref-ids can be resolved. + * + * @param id the id of the formatting object which was just finished + * @deprecated use getIdTracker().signalIDProcessed(id) instead + */ + public void signalIDProcessed(String id) { + idTracker.signalIDProcessed(id); + } + + /** + * Check if an ID has already been resolved + * + * @param id the id to check + * @return true if the ID has been resolved + * @deprecated use getIdTracker().alreadyResolvedID(id) instead + */ + public boolean alreadyResolvedID(String id) { + return idTracker.alreadyResolvedID(id); + } + + /** + * Tries to resolve all unresolved ID references on the given page. + * + * @param pv page viewport whose ID refs to resolve + * @deprecated use getIdTracker().tryIDResolution(pv) instead + */ + public void tryIDResolution(PageViewport pv) { + idTracker.tryIDResolution(pv); + } + + /** + * Get the list of page viewports that have an area with a given id. + * + * @param id the id to lookup + * @return the list of PageViewports + * @deprecated use getIdTracker().getPageViewportsContainingID(id) instead + */ + public List getPageViewportsContainingID(String id) { + return idTracker.getPageViewportsContainingID(id); + } + + /** + * Add an Resolvable object with an unresolved idref + * + * @param idref the idref whose target id has not yet been located + * @param res the Resolvable object needing the idref to be resolved + * @deprecated use getIdTracker().addUnresolvedIDRef(idref, res) instead */ - private final class Statistics { + public void addUnresolvedIDRef(String idref, Resolvable res) { + idTracker.addUnresolvedIDRef(idref, res); + } + + private class Statistics { // for statistics gathering private Runtime runtime; @@ -493,21 +417,34 @@ public class AreaTreeHandler extends FOEventHandler { // time used in rendering (for statistics) private long startTime; - private Statistics() { - runtime = Runtime.getRuntime(); + /** + * Default constructor + * @param areaTreeHandler area tree handler + */ + protected Statistics() { + this.runtime = Runtime.getRuntime(); } - public void start() { - initialMemory = runtime.totalMemory() - runtime.freeMemory(); - startTime = System.currentTimeMillis(); + /** + * starts the area tree handler statistics gathering + */ + protected void start() { + this.initialMemory = runtime.totalMemory() - runtime.freeMemory(); + this.startTime = System.currentTimeMillis(); } - public void end() { + /** + * ends the area tree handler statistics gathering + */ + protected void end() { long memoryNow = runtime.totalMemory() - runtime.freeMemory(); log.debug("Current heap size: " + (memoryNow / 1024L) + "KB"); } - public void logResults() { + /** + * logs the results of the area tree handler statistics gathering + */ + protected void logResults() { long memoryNow = runtime.totalMemory() - runtime.freeMemory(); long memoryUsed = (memoryNow - initialMemory) / 1024L; long timeUsed = System.currentTimeMillis() - startTime; diff --git a/src/java/org/apache/fop/area/IDTracker.java b/src/java/org/apache/fop/area/IDTracker.java new file mode 100644 index 000000000..d073bdb94 --- /dev/null +++ b/src/java/org/apache/fop/area/IDTracker.java @@ -0,0 +1,203 @@ +/* + * 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.area; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Used by the AreaTreeHandler to keep track of ID reference usage + * on a PageViewport level. + */ +public class IDTracker { + + private static Log log = LogFactory.getLog(IDTracker.class); + + // HashMap of ID's whose area is located on one or more consecutive + // PageViewports. Each ID has an arraylist of PageViewports that + // form the defined area of this ID + private Map idLocations = new HashMap(); + + // idref's whose target PageViewports have yet to be identified + // Each idref has a HashSet of Resolvable objects containing that idref + private Map unresolvedIDRefs = new HashMap(); + + private Set unfinishedIDs = new HashSet(); + + private Set alreadyResolvedIDs = new HashSet(); + + /** + * Tie a PageViewport with an ID found on a child area of the PV. Note that + * an area with a given ID may be on more than one PV, hence an ID may have + * more than one PV associated with it. + * + * @param id the property ID of the area + * @param pv a page viewport that contains the area with this ID + */ + public void associateIDWithPageViewport(String id, PageViewport pv) { + if (log.isDebugEnabled()) { + log.debug("associateIDWithPageViewport(" + id + ", " + pv + ")"); + } + List pvList = (List) idLocations.get(id); + if (pvList == null) { // first time ID located + pvList = new ArrayList(); + idLocations.put(id, pvList); + pvList.add(pv); + // signal the PageViewport that it is the first PV to contain this id: + pv.setFirstWithID(id); + /* + * See if this ID is in the unresolved idref list, if so resolve + * Resolvable objects tied to it. + */ + if (!unfinishedIDs.contains(id)) { + tryIDResolution(id, pv, pvList); + } + } else { + pvList.add(pv); + } + } + + /** + * This method tie an ID to the areaTreeHandler until this one is ready to + * be processed. This is used in page-number-citation-last processing so we + * know when an id can be resolved. + * + * @param id the id of the object being processed + */ + public void signalPendingID(String id) { + if (log.isDebugEnabled()) { + log.debug("signalPendingID(" + id + ")"); + } + unfinishedIDs.add(id); + } + + /** + * Signals that all areas for the formatting object with the given ID have + * been generated. This is used to determine when page-number-citation-last + * ref-ids can be resolved. + * + * @param id the id of the formatting object which was just finished + */ + public void signalIDProcessed(String id) { + if (log.isDebugEnabled()) { + log.debug("signalIDProcessed(" + id + ")"); + } + + alreadyResolvedIDs.add(id); + if (!unfinishedIDs.contains(id)) { + return; + } + unfinishedIDs.remove(id); + + List pvList = (List) idLocations.get(id); + Set todo = (Set) unresolvedIDRefs.get(id); + if (todo != null) { + for (Iterator iter = todo.iterator(); iter.hasNext();) { + Resolvable res = (Resolvable) iter.next(); + res.resolveIDRef(id, pvList); + } + unresolvedIDRefs.remove(id); + } + } + + /** + * Check if an ID has already been resolved + * + * @param id the id to check + * @return true if the ID has been resolved + */ + public boolean alreadyResolvedID(String id) { + return (alreadyResolvedIDs.contains(id)); + } + + /** + * Tries to resolve all unresolved ID references on the given page. + * + * @param id ID to resolve + * @param pv page viewport whose ID refs to resolve + * @param List of PageViewports + */ + private void tryIDResolution(String id, PageViewport pv, List pvList) { + Set todo = (Set) unresolvedIDRefs.get(id); + if (todo != null) { + for (Iterator iter = todo.iterator(); iter.hasNext();) { + Resolvable res = (Resolvable) iter.next(); + if (!unfinishedIDs.contains(id)) { + res.resolveIDRef(id, pvList); + } else { + return; + } + } + alreadyResolvedIDs.add(id); + unresolvedIDRefs.remove(id); + } + } + + /** + * Tries to resolve all unresolved ID references on the given page. + * + * @param pv page viewport whose ID refs to resolve + */ + public void tryIDResolution(PageViewport pv) { + String[] ids = pv.getIDRefs(); + if (ids != null) { + for (int i = 0; i < ids.length; i++) { + List pvList = (List) idLocations.get(ids[i]); + if (pvList != null) { + tryIDResolution(ids[i], pv, pvList); + } + } + } + } + + /** + * Get the list of page viewports that have an area with a given id. + * + * @param id the id to lookup + * @return the list of PageViewports + */ + public List getPageViewportsContainingID(String id) { + return (List) idLocations.get(id); + } + + /** + * Add an Resolvable object with an unresolved idref + * + * @param idref the idref whose target id has not yet been located + * @param res the Resolvable object needing the idref to be resolved + */ + public void addUnresolvedIDRef(String idref, Resolvable res) { + Set todo = (Set) unresolvedIDRefs.get(idref); + if (todo == null) { + todo = new HashSet(); + unresolvedIDRefs.put(idref, todo); + } + // add Resolvable object to this HashSet + todo.add(res); + } +} diff --git a/src/java/org/apache/fop/area/RenderPagesModel.java b/src/java/org/apache/fop/area/RenderPagesModel.java index da9305fa1..ca2d51c8b 100644 --- a/src/java/org/apache/fop/area/RenderPagesModel.java +++ b/src/java/org/apache/fop/area/RenderPagesModel.java @@ -145,27 +145,28 @@ public class RenderPagesModel extends AreaTreeModel { /** * Check prepared pages * - * @param newpage the new page being added + * @param newPageViewport the new page being added * @param renderUnresolved render pages with unresolved idref's * (done at end-of-document processing) * @return true if the current page should be rendered * false if the renderer doesn't support out of order * rendering and there are pending pages */ - protected boolean checkPreparedPages(PageViewport newpage, boolean + protected boolean checkPreparedPages(PageViewport newPageViewport, boolean renderUnresolved) { for (Iterator iter = prepared.iterator(); iter.hasNext();) { - PageViewport p = (PageViewport)iter.next(); - if (p.isResolved() || renderUnresolved) { - if (!renderer.supportsOutOfOrder() && p.getPageSequence().isFirstPage(p)) { + PageViewport pageViewport = (PageViewport)iter.next(); + if (pageViewport.isResolved() || renderUnresolved) { + if (!renderer.supportsOutOfOrder() + && pageViewport.getPageSequence().isFirstPage(pageViewport)) { renderer.startPageSequence(this.currentPageSequence.getTitle()); } try { - renderer.renderPage(p); - if (!p.isResolved()) { - String[] idrefs = p.getIDRefs(); + renderer.renderPage(pageViewport); + if (!pageViewport.isResolved()) { + String[] idrefs = pageViewport.getIDRefs(); for (int count = 0; count < idrefs.length; count++) { - log.warn("Page " + p.getPageNumberString() + log.warn("Page " + pageViewport.getPageNumberString() + ": Unresolved id reference \"" + idrefs[count] + "\" found."); } @@ -174,7 +175,7 @@ public class RenderPagesModel extends AreaTreeModel { // use error handler to handle this FOP or IO Exception log.error(e); } - p.clear(); + pageViewport.clear(); iter.remove(); } else { // if keeping order then stop at first page not resolved diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java index 53ba255f8..75c16ec45 100644 --- a/src/java/org/apache/fop/fo/FObj.java +++ b/src/java/org/apache/fop/fo/FObj.java @@ -60,6 +60,10 @@ public abstract class FObj extends FONode implements Constants { /** Markers added to this element. */ private Map markers = null; + // The value of properties relevant for all fo objects + private String id = null; + // End of property values + /** * Create a new formatting object. * All formatting object classes extend this class. @@ -136,6 +140,17 @@ public abstract class FObj extends FONode implements Constants { * @throws FOPException if there is a problem binding the values */ public void bind(PropertyList pList) throws FOPException { + id = pList.get(PR_ID).getString(); + } + + /** + * @see org.apache.fop.fo.FONode#startOfNode + * @throws FOPException FOP Exception + */ + protected void startOfNode() throws FOPException { + if (id != null) { + checkId(id); + } } /** @@ -147,7 +162,7 @@ public abstract class FObj extends FONode implements Constants { * @throws ValidationException if the ID is already defined elsewhere * (strict validation only) */ - protected void checkId(String id) throws ValidationException { + private void checkId(String id) throws ValidationException { if (!inMarker() && !id.equals("")) { Set idrefs = getFOEventHandler().getIDReferences(); if (!idrefs.contains(id)) { @@ -190,7 +205,7 @@ public abstract class FObj extends FONode implements Constants { protected void addChildNode(FONode child) throws FOPException { if (canHaveMarkers() && child.getNameId() == FO_MARKER) { addMarker((Marker) child); - } else { + } else { ExtensionAttachment attachment = child.getExtensionAttachment(); if (attachment != null) { /* This removes the element from the normal children, @@ -469,7 +484,16 @@ public abstract class FObj extends FONode implements Constants { return -1; } + /** @return the "id" property. */ + public String getId() { + return id; + } + /** @return whether this object has an id set */ + public boolean hasId() { + return id != null && id.length() > 0; + } + /** @see org.apache.fop.fo.FONode#getNamespaceURI() */ public String getNamespaceURI() { return FOElementMapping.URI; diff --git a/src/java/org/apache/fop/fo/flow/AbstractListItemPart.java b/src/java/org/apache/fop/fo/flow/AbstractListItemPart.java index 39efce2cd..2996f5edd 100644 --- a/src/java/org/apache/fop/fo/flow/AbstractListItemPart.java +++ b/src/java/org/apache/fop/fo/flow/AbstractListItemPart.java @@ -34,7 +34,6 @@ import org.apache.fop.fo.properties.KeepProperty; */ public abstract class AbstractListItemPart extends FObj { // The value of properties relevant for fo:list-item-label and fo:list-item-body. - private String id; private KeepProperty keepTogether; // Valid properties, commented out for performance: // private CommonAccessibility commonAccessibility; @@ -54,17 +53,10 @@ public abstract class AbstractListItemPart extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { - id = pList.get(PR_ID).getString(); + super.bind(pList); keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep(); } - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } - /** * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) * XSL Content Model: marker* (%block;)+ @@ -106,11 +98,5 @@ public abstract class AbstractListItemPart extends FObj { public KeepProperty getKeepTogether() { return keepTogether; } - - /** @return the "id" property. */ - public String getId() { - return id; - } - } diff --git a/src/java/org/apache/fop/fo/flow/BasicLink.java b/src/java/org/apache/fop/fo/flow/BasicLink.java index c487e54e3..c07c31289 100644 --- a/src/java/org/apache/fop/fo/flow/BasicLink.java +++ b/src/java/org/apache/fop/fo/flow/BasicLink.java @@ -128,6 +128,20 @@ public class BasicLink extends Inline { return externalDestination; } + /** + * @return whether or not this basic link has an internal destination or not + */ + public boolean hasInternalDestination() { + return internalDestination != null && internalDestination.length() > 0; + } + + /** + * @return whether or not this basic link has an external destination or not + */ + public boolean hasExternalDestination() { + return externalDestination != null && externalDestination.length() > 0; + } + /** @see org.apache.fop.fo.FObj#getLocalName() */ public String getLocalName() { return "basic-link"; diff --git a/src/java/org/apache/fop/fo/flow/Block.java b/src/java/org/apache/fop/fo/flow/Block.java index 6beffdfe5..894339b8d 100644 --- a/src/java/org/apache/fop/fo/flow/Block.java +++ b/src/java/org/apache/fop/fo/flow/Block.java @@ -32,8 +32,6 @@ import org.apache.fop.fo.FObjMixed; import org.apache.fop.fo.NullCharIterator; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; -import org.apache.fop.fo.properties.CommonAccessibility; -import org.apache.fop.fo.properties.CommonAural; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonFont; import org.apache.fop.fo.properties.CommonHyphenation; @@ -52,8 +50,6 @@ public class Block extends FObjMixed { private boolean initialPropertySetFound = false; // The value of properties relevant for fo:block. - private CommonAccessibility commonAccessibility; - private CommonAural commonAural; private CommonBorderPaddingBackground commonBorderPaddingBackground; private CommonFont commonFont; private CommonHyphenation commonHyphenation; @@ -64,7 +60,6 @@ public class Block extends FObjMixed { private Color color; private int hyphenationKeep; private Numeric hyphenationLadderCount; - private String id; private int intrusionDisplace; private KeepProperty keepTogether; private KeepProperty keepWithNext; @@ -84,6 +79,8 @@ public class Block extends FObjMixed { private Numeric widows; private int wrapOption; // Unused but valid items, commented out for performance: + // private CommonAccessibility commonAccessibility; + // private CommonAural commonAural; // private Length textDepth; // private Length textAltitude; // private int visibility; @@ -101,8 +98,7 @@ public class Block extends FObjMixed { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { - commonAccessibility = pList.getAccessibilityProps(); - commonAural = pList.getAuralProps(); + super.bind(pList); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonFont = pList.getFontProps(); commonHyphenation = pList.getHyphenationProps(); @@ -114,7 +110,6 @@ public class Block extends FObjMixed { color = pList.get(PR_COLOR).getColor(getUserAgent()); hyphenationKeep = pList.get(PR_HYPHENATION_KEEP).getEnum(); hyphenationLadderCount = pList.get(PR_HYPHENATION_LADDER_COUNT).getNumeric(); - id = pList.get(PR_ID).getString(); intrusionDisplace = pList.get(PR_INTRUSION_DISPLACE).getEnum(); keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep(); keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep(); @@ -139,7 +134,7 @@ public class Block extends FObjMixed { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(id); + super.startOfNode(); getFOEventHandler().startBlock(this); } @@ -231,13 +226,6 @@ public class Block extends FObjMixed { return color; } - /** - * @return the "id" property. - */ - public String getId() { - return id; - } - /** * @return the "line-height" property. */ @@ -347,20 +335,6 @@ public class Block extends FObjMixed { return whiteSpaceCollapse; } - /** - * @return Returns the commonAccessibility. - */ - public CommonAccessibility getCommonAccessibility() { - return this.commonAccessibility; - } - - /** - * @return Returns the commonAural. - */ - public CommonAural getCommonAural() { - return this.commonAural; - } - /** * @return Returns the commonRelativePosition. */ diff --git a/src/java/org/apache/fop/fo/flow/BlockContainer.java b/src/java/org/apache/fop/fo/flow/BlockContainer.java index ea5aee51f..acffa083f 100644 --- a/src/java/org/apache/fop/fo/flow/BlockContainer.java +++ b/src/java/org/apache/fop/fo/flow/BlockContainer.java @@ -48,7 +48,6 @@ public class BlockContainer extends FObj { // private ToBeImplementedProperty clip; private int displayAlign; private Length height; - private String id; private LengthRangeProperty inlineProgressionDimension; private KeepProperty keepTogether; private KeepProperty keepWithNext; @@ -77,6 +76,7 @@ public class BlockContainer extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); commonAbsolutePosition = pList.getAbsolutePositionProps(); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonMarginBlock = pList.getMarginBlockProps(); @@ -86,7 +86,6 @@ public class BlockContainer extends FObj { // clip = pList.get(PR_CLIP); displayAlign = pList.get(PR_DISPLAY_ALIGN).getEnum(); height = pList.get(PR_HEIGHT).getLength(); - id = pList.get(PR_ID).getString(); inlineProgressionDimension = pList.get(PR_INLINE_PROGRESSION_DIMENSION).getLengthRange(); keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep(); keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep(); @@ -102,7 +101,7 @@ public class BlockContainer extends FObj { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(id); + super.startOfNode(); getFOEventHandler().startBlockContainer(this); } @@ -203,13 +202,6 @@ public class BlockContainer extends FObj { return keepTogether; } - /** - * @return the "id" property. - */ - public String getId() { - return id; - } - /** * @return the "inline-progression-dimension" property. */ diff --git a/src/java/org/apache/fop/fo/flow/Character.java b/src/java/org/apache/fop/fo/flow/Character.java index e83e37119..b93ccbea7 100644 --- a/src/java/org/apache/fop/fo/flow/Character.java +++ b/src/java/org/apache/fop/fo/flow/Character.java @@ -68,7 +68,6 @@ public class Character extends FObj { private int dominantBaseline; // private ToBeImplementedProperty glyphOrientationHorizontal; // private ToBeImplementedProperty glyphOrientationVertical; - private String id; private Property letterSpacing; private SpaceProperty lineHeight; /** Holds the text decoration values. May be null */ @@ -106,6 +105,7 @@ public class Character extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonFont = pList.getFontProps(); commonHyphenation = pList.getHyphenationProps(); @@ -118,7 +118,6 @@ public class Character extends FObj { dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); // glyphOrientationHorizontal = pList.get(PR_GLYPH_ORIENTATION_HORIZONTAL); // glyphOrientationVertical = pList.get(PR_GLYPH_ORIENTATION_VERTICAL); - id = pList.get(PR_ID).getString(); letterSpacing = pList.get(PR_LETTER_SPACING); lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); textDecoration = pList.getTextDecorationProps(); @@ -130,7 +129,7 @@ public class Character extends FObj { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(id); + super.startOfNode(); getFOEventHandler().character(this); } @@ -213,13 +212,6 @@ public class Character extends FObj { return dominantBaseline; } - /** - * @return the "id" property. - */ - public String getId() { - return id; - } - /** * @return the "letter-spacing" property. */ diff --git a/src/java/org/apache/fop/fo/flow/ExternalGraphic.java b/src/java/org/apache/fop/fo/flow/ExternalGraphic.java index f31c43abf..632812270 100644 --- a/src/java/org/apache/fop/fo/flow/ExternalGraphic.java +++ b/src/java/org/apache/fop/fo/flow/ExternalGraphic.java @@ -83,7 +83,7 @@ public class ExternalGraphic extends AbstractGraphics { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(getId()); + super.startOfNode(); getFOEventHandler().image(this); } diff --git a/src/java/org/apache/fop/fo/flow/InitialPropertySet.java b/src/java/org/apache/fop/fo/flow/InitialPropertySet.java index 9c28d57fb..637c54065 100644 --- a/src/java/org/apache/fop/fo/flow/InitialPropertySet.java +++ b/src/java/org/apache/fop/fo/flow/InitialPropertySet.java @@ -69,19 +69,12 @@ public class InitialPropertySet extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { - id = pList.get(PR_ID).getString(); + super.bind(pList); // letterSpacing = pList.get(PR_LETTER_SPACING); lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); // textShadow = pList.get(PR_TEXT_SHADOW); } - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } - /** * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) * XSL Content Model: empty diff --git a/src/java/org/apache/fop/fo/flow/Inline.java b/src/java/org/apache/fop/fo/flow/Inline.java index f4c29508a..d9ac5136b 100644 --- a/src/java/org/apache/fop/fo/flow/Inline.java +++ b/src/java/org/apache/fop/fo/flow/Inline.java @@ -42,7 +42,6 @@ public class Inline extends InlineLevel { private int alignmentBaseline; private Length baselineShift; private int dominantBaseline; - private String id; // Unused but valid items, commented out for performance: // private CommonRelativePosition commonRelativePosition; // private LengthRangeProperty blockProgressionDimension; @@ -74,13 +73,14 @@ public class Inline extends InlineLevel { alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum(); baselineShift = pList.get(PR_BASELINE_SHIFT).getLength(); dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); - id = pList.get(PR_ID).getString(); } /** * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { + super.startOfNode(); + /* Check to see if this node can have block-level children. * See validateChildNode() below. */ @@ -99,9 +99,7 @@ public class Inline extends InlineLevel { } } - checkId(id); - - getFOEventHandler().startInline(this); + getFOEventHandler().startInline(this); } /** @@ -140,13 +138,6 @@ public class Inline extends InlineLevel { } } - /** - * Return the "id" property. - */ - public String getId() { - return id; - } - /** * @return the "alignment-adjust" property */ diff --git a/src/java/org/apache/fop/fo/flow/InlineContainer.java b/src/java/org/apache/fop/fo/flow/InlineContainer.java index 85a91c27f..1d4f621b8 100644 --- a/src/java/org/apache/fop/fo/flow/InlineContainer.java +++ b/src/java/org/apache/fop/fo/flow/InlineContainer.java @@ -46,7 +46,6 @@ public class InlineContainer extends FObj { private Length baselineShift; // private ToBeImplementedProperty clip; private int dominantBaseline; - private String id; private SpaceProperty lineHeight; // Unused but valid items, commented out for performance: // private CommonBorderPaddingBackground commonBorderPaddingBackground; @@ -79,22 +78,15 @@ public class InlineContainer extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); alignmentAdjust = pList.get(PR_ALIGNMENT_ADJUST).getLength(); alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum(); baselineShift = pList.get(PR_BASELINE_SHIFT).getLength(); // clip = pList.get(PR_CLIP); dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); - id = pList.get(PR_ID).getString(); lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); } - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } - /** * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) * XSL Content Model: marker* (%block;)+ @@ -156,13 +148,6 @@ public class InlineContainer extends FObj { return lineHeight; } - /** - * @return the "id" property. - */ - public String getId() { - return id; - } - /** @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { return "inline-container"; diff --git a/src/java/org/apache/fop/fo/flow/InlineLevel.java b/src/java/org/apache/fop/fo/flow/InlineLevel.java index cae0fac1d..ed9d0abe9 100644 --- a/src/java/org/apache/fop/fo/flow/InlineLevel.java +++ b/src/java/org/apache/fop/fo/flow/InlineLevel.java @@ -60,6 +60,7 @@ public abstract class InlineLevel extends FObjMixed { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonAccessibility = pList.getAccessibilityProps(); commonMarginInline = pList.getMarginInlineProps(); diff --git a/src/java/org/apache/fop/fo/flow/InstreamForeignObject.java b/src/java/org/apache/fop/fo/flow/InstreamForeignObject.java index 43dcd575d..fa10b2946 100644 --- a/src/java/org/apache/fop/fo/flow/InstreamForeignObject.java +++ b/src/java/org/apache/fop/fo/flow/InstreamForeignObject.java @@ -49,13 +49,6 @@ public class InstreamForeignObject extends AbstractGraphics { super(parent); } - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(getId()); - } - /** * Make sure content model satisfied, if so then tell the * FOEventHandler that we are at the end of the flow. diff --git a/src/java/org/apache/fop/fo/flow/Leader.java b/src/java/org/apache/fop/fo/flow/Leader.java index cfc971256..403c6f8a2 100644 --- a/src/java/org/apache/fop/fo/flow/Leader.java +++ b/src/java/org/apache/fop/fo/flow/Leader.java @@ -41,7 +41,6 @@ public class Leader extends InlineLevel { private int alignmentBaseline; private Length baselineShift; private int dominantBaseline; - private String id; private int leaderAlignment; private LengthRangeProperty leaderLength; private int leaderPattern; @@ -75,7 +74,6 @@ public class Leader extends InlineLevel { alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum(); baselineShift = pList.get(PR_BASELINE_SHIFT).getLength(); dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); - id = pList.get(PR_ID).getString(); leaderAlignment = pList.get(PR_LEADER_ALIGNMENT).getEnum(); leaderLength = pList.get(PR_LEADER_LENGTH).getLengthRange(); leaderPattern = pList.get(PR_LEADER_PATTERN).getEnum(); @@ -103,21 +101,6 @@ public class Leader extends InlineLevel { // textShadow = pList.get(PR_TEXT_SHADOW); } - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } - - - /** - * @return the "id" property. - */ - public String getId() { - return id; - } - /** * @return the "rule-style" property. */ diff --git a/src/java/org/apache/fop/fo/flow/ListBlock.java b/src/java/org/apache/fop/fo/flow/ListBlock.java index 9e0ad1cb9..6c1321024 100644 --- a/src/java/org/apache/fop/fo/flow/ListBlock.java +++ b/src/java/org/apache/fop/fo/flow/ListBlock.java @@ -43,7 +43,6 @@ public class ListBlock extends FObj { private CommonMarginBlock commonMarginBlock; private int breakAfter; private int breakBefore; - private String id; private KeepProperty keepTogether; private KeepProperty keepWithNext; private KeepProperty keepWithPrevious; @@ -74,11 +73,11 @@ public class ListBlock extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonMarginBlock = pList.getMarginBlockProps(); breakAfter = pList.get(PR_BREAK_AFTER).getEnum(); breakBefore = pList.get(PR_BREAK_BEFORE).getEnum(); - id = pList.get(PR_ID).getString(); keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep(); keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep(); keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep(); @@ -91,7 +90,7 @@ public class ListBlock extends FObj { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(id); + super.startOfNode(); getFOEventHandler().startList(this); } @@ -177,11 +176,6 @@ public class ListBlock extends FObj { return orphanContentLimit; } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { return "list-block"; diff --git a/src/java/org/apache/fop/fo/flow/ListItem.java b/src/java/org/apache/fop/fo/flow/ListItem.java index 524ec1b7a..35a134571 100644 --- a/src/java/org/apache/fop/fo/flow/ListItem.java +++ b/src/java/org/apache/fop/fo/flow/ListItem.java @@ -42,7 +42,6 @@ public class ListItem extends FObj { private CommonMarginBlock commonMarginBlock; private int breakAfter; private int breakBefore; - private String id; private KeepProperty keepTogether; private KeepProperty keepWithNext; private KeepProperty keepWithPrevious; @@ -68,11 +67,11 @@ public class ListItem extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonMarginBlock = pList.getMarginBlockProps(); breakAfter = pList.get(PR_BREAK_AFTER).getEnum(); breakBefore = pList.get(PR_BREAK_BEFORE).getEnum(); - id = pList.get(PR_ID).getString(); keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep(); keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep(); keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep(); @@ -82,7 +81,7 @@ public class ListItem extends FObj { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(id); + super.startOfNode(); getFOEventHandler().startListItem(this); } @@ -183,13 +182,6 @@ public class ListItem extends FObj { return keepTogether; } - /** - * @return the "id" property. - */ - public String getId() { - return id; - } - /** * @return the label of the list item */ diff --git a/src/java/org/apache/fop/fo/flow/MultiCase.java b/src/java/org/apache/fop/fo/flow/MultiCase.java index ee87cfdc6..a5528a975 100644 --- a/src/java/org/apache/fop/fo/flow/MultiCase.java +++ b/src/java/org/apache/fop/fo/flow/MultiCase.java @@ -57,19 +57,12 @@ public class MultiCase extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { - id = pList.get(PR_ID).getString(); + super.bind(pList); startingState = pList.get(PR_STARTING_STATE).getEnum(); // caseName = pList.get(PR_CASE_NAME); // caseTitle = pList.get(PR_CASE_TITLE); } - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } - /** * Return the "starting-state" property. */ diff --git a/src/java/org/apache/fop/fo/flow/MultiProperties.java b/src/java/org/apache/fop/fo/flow/MultiProperties.java index 0443c786f..09b0747c0 100644 --- a/src/java/org/apache/fop/fo/flow/MultiProperties.java +++ b/src/java/org/apache/fop/fo/flow/MultiProperties.java @@ -25,7 +25,6 @@ import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; 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.fo.properties.CommonAccessibility; @@ -34,7 +33,6 @@ import org.apache.fop.fo.properties.CommonAccessibility; */ public class MultiProperties extends FObj { // The value of properties relevant for fo:multi-properties. - private String id; // Unused but valid items, commented out for performance: // private CommonAccessibility commonAccessibility; // End of property values @@ -57,20 +55,6 @@ public class MultiProperties extends FObj { } } - /** - * @see org.apache.fop.fo.FObj#bind(PropertyList) - */ - public void bind(PropertyList pList) throws FOPException { - id = pList.get(PR_ID).getString(); - } - - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } - /** * Make sure content model satisfied, if so then tell the * FOEventHandler that we are at the end of the flow. @@ -104,13 +88,6 @@ public class MultiProperties extends FObj { invalidChildError(loc, nsURI, localName); } } - - /** - * Return the "id" property. - */ - public String getId() { - return id; - } /** @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { diff --git a/src/java/org/apache/fop/fo/flow/MultiPropertySet.java b/src/java/org/apache/fop/fo/flow/MultiPropertySet.java index d15c6b07f..29ab86810 100644 --- a/src/java/org/apache/fop/fo/flow/MultiPropertySet.java +++ b/src/java/org/apache/fop/fo/flow/MultiPropertySet.java @@ -33,7 +33,6 @@ import org.apache.fop.fo.ValidationException; */ public class MultiPropertySet extends FObj { // The value of properties relevant for fo:multi-property-set. - private String id; // private ToBeImplementedProperty activeState; // End of property values @@ -55,17 +54,10 @@ public class MultiPropertySet extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { - id = pList.get(PR_ID).getString(); + super.bind(pList); // activeState = pList.get(PR_ACTIVE_STATE); } - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } - /** * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) * XSL Content Model: empty @@ -75,11 +67,6 @@ public class MultiPropertySet extends FObj { invalidChildError(loc, nsURI, localName); } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { return "multi-property-set"; diff --git a/src/java/org/apache/fop/fo/flow/MultiSwitch.java b/src/java/org/apache/fop/fo/flow/MultiSwitch.java index 22ba27e9a..2293459c7 100644 --- a/src/java/org/apache/fop/fo/flow/MultiSwitch.java +++ b/src/java/org/apache/fop/fo/flow/MultiSwitch.java @@ -36,7 +36,6 @@ import org.apache.fop.fo.properties.CommonAccessibility; public class MultiSwitch extends FObj { // The value of properties relevant for fo:multi-switch. // private ToBeImplementedProperty autoRestore; - private String id; // Unused but valid items, commented out for performance: // private CommonAccessibility commonAccessibility; // End of property values @@ -59,16 +58,10 @@ public class MultiSwitch extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); // autoRestore = pList.get(PR_AUTO_RESTORE); - id = pList.get(PR_ID).getString(); } - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } /** * Make sure content model satisfied. @@ -91,11 +84,6 @@ public class MultiSwitch extends FObj { } } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { return "multi-switch"; diff --git a/src/java/org/apache/fop/fo/flow/PageNumber.java b/src/java/org/apache/fop/fo/flow/PageNumber.java index 49b145871..989df2f88 100644 --- a/src/java/org/apache/fop/fo/flow/PageNumber.java +++ b/src/java/org/apache/fop/fo/flow/PageNumber.java @@ -51,7 +51,6 @@ public class PageNumber extends FObj { private int alignmentBaseline; private Length baselineShift; private int dominantBaseline; - private String id; // private ToBeImplementedProperty letterSpacing; private SpaceProperty lineHeight; /** Holds the text decoration values. May be null */ @@ -87,13 +86,13 @@ public class PageNumber extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonFont = pList.getFontProps(); alignmentAdjust = pList.get(PR_ALIGNMENT_ADJUST).getLength(); alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum(); baselineShift = pList.get(PR_BASELINE_SHIFT).getLength(); dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); - id = pList.get(PR_ID).getString(); // letterSpacing = pList.get(PR_LETTER_SPACING); lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); textDecoration = pList.getTextDecorationProps(); @@ -107,7 +106,7 @@ public class PageNumber extends FObj { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(id); + super.startOfNode(); getFOEventHandler().startPageNumber(this); } @@ -142,11 +141,6 @@ public class PageNumber extends FObj { return commonBorderPaddingBackground; } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** @return the "text-decoration" property. */ public CommonTextDecoration getTextDecoration() { return textDecoration; diff --git a/src/java/org/apache/fop/fo/flow/PageNumberCitation.java b/src/java/org/apache/fop/fo/flow/PageNumberCitation.java index 7a0d2ae9d..d72dd604e 100644 --- a/src/java/org/apache/fop/fo/flow/PageNumberCitation.java +++ b/src/java/org/apache/fop/fo/flow/PageNumberCitation.java @@ -54,7 +54,6 @@ public class PageNumberCitation extends FObj { private int alignmentBaseline; private Length baselineShift; private int dominantBaseline; - private String id; // private ToBeImplementedProperty letterSpacing; private SpaceProperty lineHeight; private String refId; @@ -91,13 +90,13 @@ public class PageNumberCitation extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonFont = pList.getFontProps(); alignmentAdjust = pList.get(PR_ALIGNMENT_ADJUST).getLength(); alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum(); baselineShift = pList.get(PR_BASELINE_SHIFT).getLength(); dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); - id = pList.get(PR_ID).getString(); // letterSpacing = pList.get(PR_LETTER_SPACING); lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); refId = pList.get(PR_REF_ID).getString(); @@ -112,7 +111,7 @@ public class PageNumberCitation extends FObj { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(id); + super.startOfNode(); if (refId.equals("")) { missingPropertyError("ref-id"); } @@ -182,11 +181,6 @@ public class PageNumberCitation extends FObj { return lineHeight; } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** @return the "ref-id" property. */ public String getRefId() { return refId; diff --git a/src/java/org/apache/fop/fo/flow/Table.java b/src/java/org/apache/fop/fo/flow/Table.java index 2fa46a75e..68fe126cf 100644 --- a/src/java/org/apache/fop/fo/flow/Table.java +++ b/src/java/org/apache/fop/fo/flow/Table.java @@ -54,7 +54,6 @@ public class Table extends TableFObj { private LengthPairProperty borderSeparation; private int breakAfter; private int breakBefore; - private String id; private LengthRangeProperty inlineProgressionDimension; private KeepProperty keepTogether; private KeepProperty keepWithNext; @@ -110,6 +109,7 @@ public class Table extends TableFObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonMarginBlock = pList.getMarginBlockProps(); blockProgressionDimension = pList.get(PR_BLOCK_PROGRESSION_DIMENSION).getLengthRange(); @@ -117,7 +117,6 @@ public class Table extends TableFObj { borderSeparation = pList.get(PR_BORDER_SEPARATION).getLengthPair(); breakAfter = pList.get(PR_BREAK_AFTER).getEnum(); breakBefore = pList.get(PR_BREAK_BEFORE).getEnum(); - id = pList.get(PR_ID).getString(); inlineProgressionDimension = pList.get(PR_INLINE_PROGRESSION_DIMENSION).getLengthRange(); keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep(); keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep(); @@ -125,7 +124,6 @@ public class Table extends TableFObj { tableLayout = pList.get(PR_TABLE_LAYOUT).getEnum(); tableOmitFooterAtBreak = pList.get(PR_TABLE_OMIT_FOOTER_AT_BREAK).getEnum(); tableOmitHeaderAtBreak = pList.get(PR_TABLE_OMIT_HEADER_AT_BREAK).getEnum(); - super.bind(pList); //Bind extension properties widowContentLimit = pList.get(PR_X_WIDOW_CONTENT_LIMIT).getLength(); @@ -161,7 +159,7 @@ public class Table extends TableFObj { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(id); + super.startOfNode(); getFOEventHandler().startTable(this); } @@ -466,11 +464,6 @@ public class Table extends TableFObj { return orphanContentLimit; } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { return "table"; diff --git a/src/java/org/apache/fop/fo/flow/TableAndCaption.java b/src/java/org/apache/fop/fo/flow/TableAndCaption.java index 748ee0cb3..d71f6530a 100644 --- a/src/java/org/apache/fop/fo/flow/TableAndCaption.java +++ b/src/java/org/apache/fop/fo/flow/TableAndCaption.java @@ -40,7 +40,6 @@ import org.apache.fop.fo.properties.KeepProperty; */ public class TableAndCaption extends FObj { // The value of properties relevant for fo:table-and-caption. - private String id; // Unused but valid items, commented out for performance: // private CommonAccessibility commonAccessibility; // private CommonAural commonAural; @@ -75,20 +74,6 @@ public class TableAndCaption extends FObj { } } - /** - * @see org.apache.fop.fo.FObj#bind(PropertyList) - */ - public void bind(PropertyList pList) throws FOPException { - id = pList.get(PR_ID).getString(); - } - - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } - /** * Make sure content model satisfied, if so then tell the * FOEventHandler that we are at the end of the flow. @@ -132,11 +117,6 @@ public class TableAndCaption extends FObj { } } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { return "table-and-caption"; diff --git a/src/java/org/apache/fop/fo/flow/TableCaption.java b/src/java/org/apache/fop/fo/flow/TableCaption.java index da516060f..e0227b9a1 100644 --- a/src/java/org/apache/fop/fo/flow/TableCaption.java +++ b/src/java/org/apache/fop/fo/flow/TableCaption.java @@ -44,7 +44,6 @@ public class TableCaption extends FObj { // The value of properties relevant for fo:table-caption. private CommonAccessibility commonAccessibility; private CommonBorderPaddingBackground commonBorderPaddingBackground; - private String id; // Unused but valid items, commented out for performance: // private CommonAural commonAural; // private CommonRelativePosition commonRelativePosition; @@ -77,16 +76,9 @@ public class TableCaption extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); commonAccessibility = pList.getAccessibilityProps(); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); - id = pList.get(PR_ID).getString(); - } - - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); } /** @@ -124,11 +116,6 @@ public class TableCaption extends FObj { } } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { return "table-caption"; diff --git a/src/java/org/apache/fop/fo/flow/TableCell.java b/src/java/org/apache/fop/fo/flow/TableCell.java index 066d6493a..8f1b48d54 100644 --- a/src/java/org/apache/fop/fo/flow/TableCell.java +++ b/src/java/org/apache/fop/fo/flow/TableCell.java @@ -46,7 +46,6 @@ public class TableCell extends TableFObj { private int displayAlign; private int emptyCells; private int endsRow; - private String id; private int numberColumnsSpanned; private int numberRowsSpanned; private int startsRow; @@ -77,26 +76,24 @@ public class TableCell extends TableFObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); blockProgressionDimension = pList.get(PR_BLOCK_PROGRESSION_DIMENSION).getLengthRange(); displayAlign = pList.get(PR_DISPLAY_ALIGN).getEnum(); emptyCells = pList.get(PR_EMPTY_CELLS).getEnum(); endsRow = pList.get(PR_ENDS_ROW).getEnum(); - id = pList.get(PR_ID).getString(); columnNumber = pList.get(PR_COLUMN_NUMBER).getNumeric().getValue(); numberColumnsSpanned = pList.get(PR_NUMBER_COLUMNS_SPANNED).getNumeric().getValue(); numberRowsSpanned = pList.get(PR_NUMBER_ROWS_SPANNED).getNumeric().getValue(); startsRow = pList.get(PR_STARTS_ROW).getEnum(); - width = pList.get(PR_WIDTH).getLength(); - - super.bind(pList); + width = pList.get(PR_WIDTH).getLength(); } /** * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(id); + super.startOfNode(); getFOEventHandler().startCell(this); } @@ -163,13 +160,6 @@ public class TableCell extends TableFObj { return (this.emptyCells == EN_SHOW); } - /** - * @return the "id" property. - */ - public String getId() { - return id; - } - /** * @return the "number-columns-spanned" property. */ diff --git a/src/java/org/apache/fop/fo/flow/TableFObj.java b/src/java/org/apache/fop/fo/flow/TableFObj.java index 359530cdc..980eaeb7c 100644 --- a/src/java/org/apache/fop/fo/flow/TableFObj.java +++ b/src/java/org/apache/fop/fo/flow/TableFObj.java @@ -83,6 +83,7 @@ public abstract class TableFObj extends FObj { * @see FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); borderAfterPrecedence = pList.get(PR_BORDER_AFTER_PRECEDENCE).getNumeric(); borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric(); borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric(); diff --git a/src/java/org/apache/fop/fo/flow/TableRow.java b/src/java/org/apache/fop/fo/flow/TableRow.java index 81d71e08b..1b5c05b05 100644 --- a/src/java/org/apache/fop/fo/flow/TableRow.java +++ b/src/java/org/apache/fop/fo/flow/TableRow.java @@ -47,7 +47,6 @@ public class TableRow extends TableFObj { private int breakAfter; private int breakBefore; private Length height; - private String id; private KeepProperty keepTogether; private KeepProperty keepWithNext; private KeepProperty keepWithPrevious; @@ -80,7 +79,6 @@ public class TableRow extends TableFObj { commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); breakAfter = pList.get(PR_BREAK_AFTER).getEnum(); breakBefore = pList.get(PR_BREAK_BEFORE).getEnum(); - id = pList.get(PR_ID).getString(); height = pList.get(PR_HEIGHT).getLength(); keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep(); keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep(); @@ -162,7 +160,7 @@ public class TableRow extends TableFObj { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { - checkId(id); + super.startOfNode(); getFOEventHandler().startRow(this); } @@ -192,13 +190,6 @@ public class TableRow extends TableFObj { } } - /** - * @return the "id" property. - */ - public String getId() { - return id; - } - /** @return the "break-after" property. */ public int getBreakAfter() { return breakAfter; diff --git a/src/java/org/apache/fop/fo/flow/Wrapper.java b/src/java/org/apache/fop/fo/flow/Wrapper.java index 61ec2c857..b75ff42cb 100644 --- a/src/java/org/apache/fop/fo/flow/Wrapper.java +++ b/src/java/org/apache/fop/fo/flow/Wrapper.java @@ -34,7 +34,6 @@ import org.xml.sax.Locator; */ public class Wrapper extends FObjMixed { // The value of properties relevant for fo:wrapper. - private String id; // End of property values // used for FO validation @@ -47,20 +46,6 @@ public class Wrapper extends FObjMixed { super(parent); } - /** - * @see org.apache.fop.fo.FObj#bind(PropertyList) - */ - public void bind(PropertyList pList) throws FOPException { - id = pList.get(PR_ID).getString(); - } - - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } - /** * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) * XSL Content Model: marker* (#PCDATA|%inline;|%block;)* @@ -82,11 +67,6 @@ public class Wrapper extends FObjMixed { } } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { return "wrapper"; diff --git a/src/java/org/apache/fop/fo/pagination/PageSequence.java b/src/java/org/apache/fop/fo/pagination/PageSequence.java index b61d3b8b7..135382800 100644 --- a/src/java/org/apache/fop/fo/pagination/PageSequence.java +++ b/src/java/org/apache/fop/fo/pagination/PageSequence.java @@ -43,7 +43,6 @@ public class PageSequence extends FObj { private int letterValue; private char groupingSeparator; private int groupingSize; - private String id; private Numeric initialPageNumber; private int forcePageCount; private String masterReference; @@ -96,13 +95,13 @@ public class PageSequence extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { + super.bind(pList); country = pList.get(PR_COUNTRY).getString(); format = pList.get(PR_FORMAT).getString(); language = pList.get(PR_LANGUAGE).getString(); letterValue = pList.get(PR_LETTER_VALUE).getEnum(); groupingSeparator = pList.get(PR_GROUPING_SEPARATOR).getCharacter(); groupingSize = pList.get(PR_GROUPING_SIZE).getNumber().intValue(); - id = pList.get(PR_ID).getString(); initialPageNumber = pList.get(PR_INITIAL_PAGE_NUMBER).getNumeric(); forcePageCount = pList.get(PR_FORCE_PAGE_COUNT).getEnum(); masterReference = pList.get(PR_MASTER_REFERENCE).getString(); @@ -116,6 +115,7 @@ public class PageSequence extends FObj { * @see org.apache.fop.fo.FONode#startOfNode() */ protected void startOfNode() throws FOPException { + super.startOfNode(); this.root = (Root) parent; flowMap = new java.util.HashMap(); @@ -133,7 +133,6 @@ public class PageSequence extends FObj { this.pageNumberGenerator = new PageNumberGenerator( format, groupingSeparator, groupingSize, letterValue); - checkId(id); getFOEventHandler().startPageSequence(this); } @@ -394,11 +393,6 @@ public class PageSequence extends FObj { return (StaticContent) flowMap.get(name); } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** * Accessor method for titleFO * @return titleFO for this object diff --git a/src/java/org/apache/fop/fo/pagination/PageSequenceWrapper.java b/src/java/org/apache/fop/fo/pagination/PageSequenceWrapper.java index 3f7cb66d1..b57befaba 100644 --- a/src/java/org/apache/fop/fo/pagination/PageSequenceWrapper.java +++ b/src/java/org/apache/fop/fo/pagination/PageSequenceWrapper.java @@ -34,7 +34,6 @@ import org.apache.fop.fo.ValidationException; */ public class PageSequenceWrapper extends FObj { // The value of properties relevant for this FO - private String id; private String indexClass; private String indexKey; // End of property values @@ -50,18 +49,11 @@ public class PageSequenceWrapper extends FObj { * @see org.apache.fop.fo.FObj#bind(PropertyList) */ public void bind(PropertyList pList) throws FOPException { - id = pList.get(PR_ID).getString(); + super.bind(pList); indexClass = pList.get(PR_INDEX_CLASS).getString(); indexKey = pList.get(PR_INDEX_KEY).getString(); } - /** - * @see org.apache.fop.fo.FONode#startOfNode - */ - protected void startOfNode() throws FOPException { - checkId(id); - } - /** * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) XSL/FOP: (bookmark+) @@ -74,11 +66,6 @@ public class PageSequenceWrapper extends FObj { } } - /** @return the "id" property. */ - public String getId() { - return id; - } - /** @return the "index-class" property. */ public String getIndexClass() { return indexClass; diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java index 24ee2e4da..f4e9cb633 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java @@ -192,7 +192,7 @@ public abstract class AbstractBreaker { * algorithm. * @return the applicable PageProvider, or null if not applicable */ - protected PageSequenceLayoutManager.PageProvider getPageProvider() { + protected PageProvider getPageProvider() { return null; } @@ -214,7 +214,7 @@ public abstract class AbstractBreaker { /** @return true if there's no content that could be handled. */ public boolean isEmpty() { - return (blockLists.size() == 0); + return (this.blockLists.size() == 0); } protected void startPart(BlockSequence list, int breakClass) { @@ -289,7 +289,7 @@ public abstract class AbstractBreaker { childLC.setBPAlignment(alignment); BlockSequence blockList; - blockLists = new java.util.ArrayList(); + this.blockLists = new java.util.ArrayList(); log.debug("PLM> flow BPD =" + flowBPD); @@ -298,7 +298,7 @@ public abstract class AbstractBreaker { while (hasMoreContent()) { blockLists.clear(); - nextSequenceStartsOn = getNextBlockList(childLC, nextSequenceStartsOn, blockLists); + nextSequenceStartsOn = getNextBlockList(childLC, nextSequenceStartsOn); //*** Phase 2: Alignment and breaking *** log.debug("PLM> blockLists.size() = " + blockLists.size()); @@ -539,19 +539,17 @@ public abstract class AbstractBreaker { * Gets the next block list (sequence) and adds it to a list of block lists if it's not empty. * @param childLC LayoutContext to use * @param nextSequenceStartsOn indicates on what page the next sequence should start - * @param blockLists list of block lists (sequences) * @return the page on which the next content should appear after a hard break */ protected int getNextBlockList(LayoutContext childLC, - int nextSequenceStartsOn, - List blockLists) { + int nextSequenceStartsOn) { updateLayoutContext(childLC); //Make sure the span change signal is reset childLC.signalSpanChange(Constants.NOT_SET); - LinkedList returnedList; BlockSequence blockList; - if ((returnedList = getNextKnuthElements(childLC, alignment)) != null) { + LinkedList returnedList = getNextKnuthElements(childLC, alignment); + if (returnedList != null) { if (returnedList.size() == 0) { nextSequenceStartsOn = handleSpanChange(childLC, nextSequenceStartsOn); return nextSequenceStartsOn; @@ -594,7 +592,7 @@ public abstract class AbstractBreaker { BlockSequence seq = null; seq = blockList.endBlockSequence(breakPosition); if (seq != null) { - blockLists.add(seq); + this.blockLists.add(seq); } } return nextSequenceStartsOn; diff --git a/src/java/org/apache/fop/layoutmgr/BalancingColumnBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BalancingColumnBreakingAlgorithm.java index 57e42aaf6..9f3207773 100644 --- a/src/java/org/apache/fop/layoutmgr/BalancingColumnBreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/BalancingColumnBreakingAlgorithm.java @@ -21,7 +21,6 @@ package org.apache.fop.layoutmgr; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener; import org.apache.fop.traits.MinOptMax; /** @@ -37,7 +36,7 @@ public class BalancingColumnBreakingAlgorithm extends PageBreakingAlgorithm { private int idealPartLen; public BalancingColumnBreakingAlgorithm(LayoutManager topLevelLM, - PageSequenceLayoutManager.PageProvider pageProvider, + PageProvider pageProvider, PageBreakingLayoutListener layoutListener, int alignment, int alignmentLast, MinOptMax footnoteSeparatorLength, diff --git a/src/java/org/apache/fop/layoutmgr/PageBreaker.java b/src/java/org/apache/fop/layoutmgr/PageBreaker.java new file mode 100644 index 000000000..ff3dfef31 --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/PageBreaker.java @@ -0,0 +1,542 @@ +/* + * 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.layoutmgr; + +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +import org.apache.fop.area.Block; +import org.apache.fop.area.Footnote; +import org.apache.fop.area.PageViewport; +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FObj; +import org.apache.fop.fo.pagination.PageSequence; +import org.apache.fop.fo.pagination.Region; +import org.apache.fop.fo.pagination.RegionBody; +import org.apache.fop.fo.pagination.StaticContent; +import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener; +import org.apache.fop.traits.MinOptMax; + +/** + * Handles the breaking of pages in an fo:flow + */ +public class PageBreaker extends AbstractBreaker { + + private PageSequenceLayoutManager pslm; + private boolean firstPart = true; + private boolean pageBreakHandled; + private boolean needColumnBalancing; + private PageProvider pageProvider; + private Block separatorArea; + + /** + * The FlowLayoutManager object, which processes + * the single fo:flow of the fo:page-sequence + */ + private FlowLayoutManager childFLM = null; + + private StaticContentLayoutManager footnoteSeparatorLM = null; + + public PageBreaker(PageSequenceLayoutManager pslm) { + this.pslm = pslm; + this.pageProvider = pslm.getPageProvider(); + this.childFLM = pslm.getLayoutManagerMaker().makeFlowLayoutManager( + pslm, pslm.getPageSequence().getMainFlow()); + } + + /** @see org.apache.fop.layoutmgr.AbstractBreaker */ + protected void updateLayoutContext(LayoutContext context) { + int flowIPD = pslm.getCurrentPV().getCurrentSpan().getColumnWidth(); + context.setRefIPD(flowIPD); + } + + /** @see org.apache.fop.layoutmgr.AbstractBreaker#getTopLevelLM() */ + protected LayoutManager getTopLevelLM() { + return pslm; + } + + /** @see org.apache.fop.layoutmgr.AbstractBreaker#getPageProvider() */ + protected PageProvider getPageProvider() { + return pslm.getPageProvider(); + } + + /** + * @see org.apache.fop.layoutmgr.AbstractBreaker#getLayoutListener() + */ + protected PageBreakingLayoutListener getLayoutListener() { + return new PageBreakingLayoutListener() { + + public void notifyOverflow(int part, FObj obj) { + Page p = pageProvider.getPage( + false, part, PageProvider.RELTO_CURRENT_ELEMENT_LIST); + RegionBody body = (RegionBody)p.getSimplePageMaster().getRegion( + Region.FO_REGION_BODY); + String err = FONode.decorateWithContextInfo( + "Content of the region-body on page " + + p.getPageViewport().getPageNumberString() + + " overflows the available area in block-progression dimension.", + obj); + if (body.getOverflow() == Constants.EN_ERROR_IF_OVERFLOW) { + throw new RuntimeException(err); + } else { + log.warn(err); + } + } + + }; + } + + /** @see org.apache.fop.layoutmgr.AbstractBreaker */ + protected int handleSpanChange(LayoutContext childLC, int nextSequenceStartsOn) { + needColumnBalancing = false; + if (childLC.getNextSpan() != Constants.NOT_SET) { + //Next block list will have a different span. + nextSequenceStartsOn = childLC.getNextSpan(); + needColumnBalancing = (childLC.getNextSpan() == Constants.EN_ALL); + } + if (needColumnBalancing) { + AbstractBreaker.log.debug( + "Column balancing necessary for the next element list!!!"); + } + return nextSequenceStartsOn; + } + + /** @see org.apache.fop.layoutmgr.AbstractBreaker */ + protected int getNextBlockList(LayoutContext childLC, + int nextSequenceStartsOn) { + if (!firstPart) { + // if this is the first page that will be created by + // the current BlockSequence, it could have a break + // condition that must be satisfied; + // otherwise, we may simply need a new page + handleBreakTrait(nextSequenceStartsOn); + } + firstPart = false; + pageBreakHandled = true; + pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(), + pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex()); + return super.getNextBlockList(childLC, nextSequenceStartsOn); + } + + /** @see org.apache.fop.layoutmgr.AbstractBreaker */ + protected LinkedList getNextKnuthElements(LayoutContext context, int alignment) { + LinkedList contentList = null; + + while (!childFLM.isFinished() && contentList == null) { + contentList = childFLM.getNextKnuthElements(context, alignment); + } + + // scan contentList, searching for footnotes + boolean bFootnotesPresent = false; + if (contentList != null) { + ListIterator contentListIterator = contentList.listIterator(); + while (contentListIterator.hasNext()) { + ListElement element = (ListElement) contentListIterator.next(); + if (element instanceof KnuthBlockBox + && ((KnuthBlockBox) element).hasAnchors()) { + // element represents a line with footnote citations + bFootnotesPresent = true; + LayoutContext footnoteContext = new LayoutContext(context); + footnoteContext.setStackLimit(context.getStackLimit()); + footnoteContext.setRefIPD(pslm.getCurrentPV() + .getRegionReference(Constants.FO_REGION_BODY).getIPD()); + LinkedList footnoteBodyLMs = ((KnuthBlockBox) element).getFootnoteBodyLMs(); + ListIterator footnoteBodyIterator = footnoteBodyLMs.listIterator(); + // store the lists of elements representing the footnote bodies + // in the box representing the line containing their references + while (footnoteBodyIterator.hasNext()) { + FootnoteBodyLayoutManager fblm + = (FootnoteBodyLayoutManager) footnoteBodyIterator.next(); + fblm.setParent(childFLM); + fblm.initialize(); + ((KnuthBlockBox) element).addElementList( + fblm.getNextKnuthElements(footnoteContext, alignment)); + } + } + } + } + + if (bFootnotesPresent) { + // handle the footnote separator + StaticContent footnoteSeparator; + footnoteSeparator = pslm.getPageSequence().getStaticContent("xsl-footnote-separator"); + if (footnoteSeparator != null) { + // the footnote separator can contain page-dependent content such as + // page numbers or retrieve markers, so its areas cannot simply be + // obtained now and repeated in each page; + // we need to know in advance the separator bpd: the actual separator + // could be different from page to page, but its bpd would likely be + // always the same + + // create a Block area that will contain the separator areas + separatorArea = new Block(); + separatorArea.setIPD(pslm.getCurrentPV() + .getRegionReference(Constants.FO_REGION_BODY).getIPD()); + // create a StaticContentLM for the footnote separator + footnoteSeparatorLM = (StaticContentLayoutManager) + pslm.getLayoutManagerMaker().makeStaticContentLayoutManager( + pslm, footnoteSeparator, separatorArea); + footnoteSeparatorLM.doLayout(); + + footnoteSeparatorLength = new MinOptMax(separatorArea.getBPD()); + } + } + return contentList; + } + + /** + * @return current display alignment + */ + protected int getCurrentDisplayAlign() { + return pslm.getCurrentPage().getSimplePageMaster().getRegion( + Constants.FO_REGION_BODY).getDisplayAlign(); + } + + /** + * @return whether or not this flow has more page break opportunities + */ + protected boolean hasMoreContent() { + return !childFLM.isFinished(); + } + + /** + * Adds an area to the flow layout manager + * @param posIter the position iterator + * @param context the layout context + */ + protected void addAreas(PositionIterator posIter, LayoutContext context) { + if (footnoteSeparatorLM != null) { + StaticContent footnoteSeparator = pslm.getPageSequence().getStaticContent( + "xsl-footnote-separator"); + // create a Block area that will contain the separator areas + separatorArea = new Block(); + separatorArea.setIPD( + pslm.getCurrentPV().getRegionReference(Constants.FO_REGION_BODY).getIPD()); + // create a StaticContentLM for the footnote separator + footnoteSeparatorLM = (StaticContentLayoutManager) + pslm.getLayoutManagerMaker().makeStaticContentLayoutManager( + pslm, footnoteSeparator, separatorArea); + footnoteSeparatorLM.doLayout(); + } + + childFLM.addAreas(posIter, context); + } + + /** + * Performs phase 3 operation + * + * @param alg page breaking algorithm + * @param partCount part count + * @param originalList the block sequence original list + * @param effectiveList the block sequence effective list + */ + protected void doPhase3(PageBreakingAlgorithm alg, int partCount, + BlockSequence originalList, BlockSequence effectiveList) { + if (needColumnBalancing) { + doPhase3WithColumnBalancing(alg, partCount, originalList, effectiveList); + } else { + if (!hasMoreContent() && pslm.getPageSequence().hasPagePositionLast()) { + //last part is reached and we have a "last page" condition + doPhase3WithLastPage(alg, partCount, originalList, effectiveList); + } else { + //Directly add areas after finding the breaks + addAreas(alg, partCount, originalList, effectiveList); + } + } + } + + 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(Constants.EN_PAGE); + } + } else { + newStartPos = 0; + } + AbstractBreaker.log.debug("Last page handling now!!!"); + AbstractBreaker.log.debug("==================================================="); + AbstractBreaker.log.debug("Restarting at " + restartPoint + + ", new start position: " + newStartPos); + + pageBreakHandled = true; + //Update so the available BPD is reported correctly + int currentPageNum = pslm.getCurrentPageNum(); + pageProvider.setStartOfNextElementList(currentPageNum, + pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex()); + pageProvider.setLastPageIndex(currentPageNum); + + //Restart last page + PageBreakingAlgorithm algRestart = new PageBreakingAlgorithm( + getTopLevelLM(), + getPageProvider(), getLayoutListener(), + alg.getAlignment(), alg.getAlignmentLast(), + footnoteSeparatorLength, + isPartOverflowRecoveryActivated(), false, 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 <= pslm.getCurrentPV().getBodyRegion().getColumnCount(); + if (replaceLastPage) { + //Replace last page + pslm.setCurrentPage(pageProvider.getPage(false, currentPageNum)); + //Make sure we only add the areas we haven't added already + effectiveList.ignoreAtStart = newStartPos; + addAreas(algRestart, iOptPageCount, originalList, effectiveList); + } else { + effectiveList.ignoreAtStart = newStartPos; + addAreas(alg, restartPoint, partCount - restartPoint, originalList, effectiveList); + //Add blank last page + pageProvider.setLastPageIndex(currentPageNum + 1); + pslm.setCurrentPage(pslm.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(Constants.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(pslm.getCurrentPageNum(), + pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex()); + + //Restart last page + PageBreakingAlgorithm algRestart = new BalancingColumnBreakingAlgorithm( + getTopLevelLM(), + getPageProvider(), getLayoutListener(), + alignment, Constants.EN_START, footnoteSeparatorLength, + isPartOverflowRecoveryActivated(), + pslm.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 > pslm.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) { + AbstractBreaker.log.debug("startPart() breakClass=" + breakClass); + if (pslm.getCurrentPage() == null) { + throw new IllegalStateException("curPage must not be null"); + } + if (!pageBreakHandled) { + + //firstPart is necessary because we need the first page before we start the + //algorithm so we have a BPD and IPD. This may subject to change later when we + //start handling more complex cases. + if (!firstPart) { + // if this is the first page that will be created by + // the current BlockSequence, it could have a break + // condition that must be satisfied; + // otherwise, we may simply need a new page + handleBreakTrait(breakClass); + } + pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(), + pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex()); + } + pageBreakHandled = false; + // add static areas and resolve any new id areas + // finish page and add to area tree + firstPart = false; + } + + /** @see org.apache.fop.layoutmgr.AbstractBreaker#handleEmptyContent() */ + protected void handleEmptyContent() { + pslm.getCurrentPV().getPage().fakeNonEmpty(); + } + + protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) { + // add footnote areas + if (pbp.footnoteFirstListIndex < pbp.footnoteLastListIndex + || pbp.footnoteFirstElementIndex <= pbp.footnoteLastElementIndex) { + // call addAreas() for each FootnoteBodyLM + for (int i = pbp.footnoteFirstListIndex; i <= pbp.footnoteLastListIndex; i++) { + LinkedList elementList = alg.getFootnoteList(i); + int firstIndex = (i == pbp.footnoteFirstListIndex + ? pbp.footnoteFirstElementIndex : 0); + int lastIndex = (i == pbp.footnoteLastListIndex + ? pbp.footnoteLastElementIndex : elementList.size() - 1); + + SpaceResolver.performConditionalsNotification(elementList, + firstIndex, lastIndex, -1); + LayoutContext childLC = new LayoutContext(0); + AreaAdditionUtil.addAreas(null, + new KnuthPossPosIter(elementList, firstIndex, lastIndex + 1), + childLC); + } + // set the offset from the top margin + Footnote parentArea = (Footnote) pslm.getCurrentPV().getBodyRegion().getFootnote(); + int topOffset = (int) pslm.getCurrentPV().getBodyRegion().getBPD() - parentArea.getBPD(); + if (separatorArea != null) { + topOffset -= separatorArea.getBPD(); + } + parentArea.setTop(topOffset); + parentArea.setSeparator(separatorArea); + } + pslm.getCurrentPV().getCurrentSpan().notifyFlowsFinished(); + } + + /** + * @return the current child flow layout manager + */ + protected LayoutManager getCurrentChildLM() { + return childFLM; + } + + /** @see org.apache.fop.layoutmgr.AbstractBreaker#observeElementList(java.util.List) */ + protected void observeElementList(List elementList) { + ElementListObserver.observe(elementList, "breaker", + ((PageSequence)pslm.getFObj()).getId()); + } + + /** + * Depending on the kind of break condition, move to next column + * or page. May need to make an empty page if next page would + * not have the desired "handedness". + * @param breakVal - value of break-before or break-after trait. + */ + private void handleBreakTrait(int breakVal) { + Page curPage = pslm.getCurrentPage(); + if (breakVal == Constants.EN_ALL) { + //break due to span change in multi-column layout + curPage.getPageViewport().createSpan(true); + return; + } else if (breakVal == Constants.EN_NONE) { + curPage.getPageViewport().createSpan(false); + return; + } else if (breakVal == Constants.EN_COLUMN || breakVal <= 0) { + PageViewport pv = curPage.getPageViewport(); + + //Check if previous page was spanned + boolean forceNewPageWithSpan = false; + RegionBody rb = (RegionBody)curPage.getSimplePageMaster().getRegion( + Constants.FO_REGION_BODY); + if (breakVal < 0 + && rb.getColumnCount() > 1 + && pv.getCurrentSpan().getColumnCount() == 1) { + forceNewPageWithSpan = true; + } + + if (forceNewPageWithSpan) { + curPage = pslm.makeNewPage(false, false); + curPage.getPageViewport().createSpan(true); + } else if (pv.getCurrentSpan().hasMoreFlows()) { + pv.getCurrentSpan().moveToNextFlow(); + } else { + curPage = pslm.makeNewPage(false, false); + } + return; + } + log.debug("handling break-before after page " + pslm.getCurrentPageNum() + + " breakVal=" + breakVal); + if (needBlankPageBeforeNew(breakVal)) { + curPage = pslm.makeNewPage(true, false); + } + if (needNewPage(breakVal)) { + curPage = pslm.makeNewPage(false, false); + } + } + + /** + * Check if a blank page is needed to accomodate + * desired even or odd page number. + * @param breakVal - value of break-before or break-after trait. + */ + private boolean needBlankPageBeforeNew(int breakVal) { + if (breakVal == Constants.EN_PAGE || (pslm.getCurrentPage().getPageViewport().getPage().isEmpty())) { + // any page is OK or we already have an empty page + return false; + } else { + /* IF we are on the kind of page we need, we'll need a new page. */ + if (pslm.getCurrentPageNum() % 2 == 0) { // even page + return (breakVal == Constants.EN_EVEN_PAGE); + } else { // odd page + return (breakVal == Constants.EN_ODD_PAGE); + } + } + } + + /** + * See if need to generate a new page + * @param breakVal - value of break-before or break-after trait. + */ + private boolean needNewPage(int breakVal) { + if (pslm.getCurrentPage().getPageViewport().getPage().isEmpty()) { + if (breakVal == Constants.EN_PAGE) { + return false; + } else if (pslm.getCurrentPageNum() % 2 == 0) { // even page + return (breakVal == Constants.EN_ODD_PAGE); + } else { // odd page + return (breakVal == Constants.EN_EVEN_PAGE); + } + } else { + return true; + } + } +} \ No newline at end of file diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java index cf12dffb9..2c2e96986 100644 --- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java @@ -38,7 +38,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { private static Log log = LogFactory.getLog(PageBreakingAlgorithm.class); private LayoutManager topLevelLM; - private PageSequenceLayoutManager.PageProvider pageProvider; + private PageProvider pageProvider; private PageBreakingLayoutListener layoutListener; /** List of PageBreakPosition elements. */ private LinkedList pageBreaks = null; @@ -94,7 +94,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { private boolean favorSinglePart = false; public PageBreakingAlgorithm(LayoutManager topLevelLM, - PageSequenceLayoutManager.PageProvider pageProvider, + PageProvider pageProvider, PageBreakingLayoutListener layoutListener, int alignment, int alignmentLast, MinOptMax footnoteSeparatorLength, diff --git a/src/java/org/apache/fop/layoutmgr/PageProvider.java b/src/java/org/apache/fop/layoutmgr/PageProvider.java new file mode 100644 index 000000000..94da60173 --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/PageProvider.java @@ -0,0 +1,279 @@ +/* + * 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.layoutmgr; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.FOPException; +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; + +/** + *

This class delivers Page instances. It also caches them as necessary. + *

+ *

Additional functionality makes sure that surplus instances that are requested by the + * page breaker are properly discarded, especially in situations where hard breaks cause + * blank pages. The reason for that: The page breaker sometimes needs to preallocate + * additional pages since it doesn't know exactly until the end how many pages it really needs. + *

+ */ +public class PageProvider implements Constants { + + private Log log = LogFactory.getLog(PageProvider.class); + + /** Indices are evaluated relative to the first page in the page-sequence. */ + public static final int RELTO_PAGE_SEQUENCE = 0; + /** Indices are evaluated relative to the first page in the current element list. */ + public static final int RELTO_CURRENT_ELEMENT_LIST = 1; + + private int startPageOfPageSequence; + private int startPageOfCurrentElementList; + 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; + + /** + * AreaTreeHandler which activates the PSLM and controls + * the rendering of its pages. + */ + private AreaTreeHandler areaTreeHandler; + + /** + * fo:page-sequence formatting object being + * processed by this class + */ + private PageSequence pageSeq; + + /** + * Main constructor. + * @param ps The page-sequence the provider operates on + */ + public PageProvider(AreaTreeHandler ath, PageSequence ps) { + this.areaTreeHandler = ath; + this.pageSeq = ps; + this.startPageOfPageSequence = ps.getStartingPageNumber(); + } + + /** + * The page breaker notifies the provider about the page number an element list starts + * on so it can later retrieve PageViewports relative to this first page. + * @param startPage the number of the first page for the element list. + * @param startColumn the starting column number for the element list. + */ + public void setStartOfNextElementList(int startPage, int startColumn) { + log.debug("start of the next element list is:" + + " page=" + startPage + " col=" + startColumn); + this.startPageOfCurrentElementList = startPage - startPageOfPageSequence + 1; + this.startColumnOfCurrentElementList = startColumn; + //Reset Cache + this.lastRequestedIndex = -1; + 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. + * This method takes multiple columns into account. + * @param index zero-based index of the requested part/page + * @return the available BPD + */ + public int getAvailableBPD(int index) { + //Special optimization: There may be many equal calls by the BreakingAlgorithm + if (this.lastRequestedIndex == index) { + if (log.isTraceEnabled()) { + log.trace("getAvailableBPD(" + index + ") -> (cached) " + lastReportedBPD); + } + return this.lastReportedBPD; + } + int c = index; + int pageIndex = 0; + int colIndex = startColumnOfCurrentElementList; + Page page = getPage( + false, pageIndex, RELTO_CURRENT_ELEMENT_LIST); + while (c > 0) { + colIndex++; + if (colIndex >= page.getPageViewport().getCurrentSpan().getColumnCount()) { + colIndex = 0; + pageIndex++; + page = getPage( + false, pageIndex, RELTO_CURRENT_ELEMENT_LIST); + } + c--; + } + this.lastRequestedIndex = index; + this.lastReportedBPD = page.getPageViewport().getBodyRegion().getRemainingBPD(); + if (log.isTraceEnabled()) { + log.trace("getAvailableBPD(" + index + ") -> " + lastReportedBPD); + } + return this.lastReportedBPD; + } + + /** + * Returns the part index (0= page.getPageViewport().getCurrentSpan().getColumnCount())) { + colIndex = 0; + pageIndex++; + page = getPage( + false, pageIndex, RELTO_CURRENT_ELEMENT_LIST); + result = idx; + } + colIndex++; + idx++; + } + return result; + } + + /** + * Returns a Page. + * @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 isBlank, int index, int relativeTo) { + if (relativeTo == RELTO_PAGE_SEQUENCE) { + return getPage(isBlank, index); + } else if (relativeTo == RELTO_CURRENT_ELEMENT_LIST) { + int effIndex = startPageOfCurrentElementList + index; + effIndex += startPageOfPageSequence - 1; + return getPage(isBlank, effIndex); + } else { + throw new IllegalArgumentException( + "Illegal value for relativeTo: " + relativeTo); + } + } + + /** + * + * @param isBlank + * @param index + * @return + */ + protected Page getPage(boolean isBlank, int index) { + boolean isLastPage = (lastPageIndex >= 0) && (index == lastPageIndex); + if (log.isTraceEnabled()) { + log.trace("getPage(" + index + " " + (isBlank ? "blank" : "non-blank") + + (isLastPage ? " " : "") + ")"); + } + int intIndex = index - startPageOfPageSequence; + if (log.isTraceEnabled()) { + 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, isBlank, isLastPage); + } + Page page = (Page)cachedPages.get(intIndex); + boolean replace = false; + if (page.getPageViewport().isBlank() != isBlank) { + log.debug("blank condition doesn't match. Replacing PageViewport."); + 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 Page cacheNextPage(int index, boolean isBlank, boolean isLastPage) { + try { + String pageNumberString = pageSeq.makeFormattedPageNumber(index); + SimplePageMaster spm = pageSeq.getNextSimplePageMaster( + index, (startPageOfPageSequence == index), 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. + 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."); + } + Page page = new Page(spm, index, pageNumberString, isBlank); + //Set unique key obtained from the AreaTreeHandler + page.getPageViewport().setKey(areaTreeHandler.generatePageViewportKey()); + page.getPageViewport().setForeignAttributes(spm.getForeignAttributes()); + cachedPages.add(page); + return page; + } catch (FOPException e) { + //TODO Maybe improve. It'll mean to propagate this exception up several + //methods calls. + throw new IllegalStateException(e.getMessage()); + } + } + +} \ No newline at end of file diff --git a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java index ac13cd3ad..a34ce7956 100644 --- a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java @@ -21,39 +21,26 @@ package org.apache.fop.layoutmgr; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Numeric; import org.apache.fop.area.AreaTreeHandler; import org.apache.fop.area.AreaTreeModel; -import org.apache.fop.area.Block; -import org.apache.fop.area.Footnote; +import org.apache.fop.area.IDTracker; import org.apache.fop.area.PageViewport; import org.apache.fop.area.LineArea; import org.apache.fop.area.Resolvable; import org.apache.fop.fo.Constants; -import org.apache.fop.fo.FONode; -import org.apache.fop.fo.FObj; import org.apache.fop.fo.flow.Marker; import org.apache.fop.fo.flow.RetrieveMarker; -import org.apache.fop.fo.pagination.Flow; import org.apache.fop.fo.pagination.PageSequence; import org.apache.fop.fo.pagination.PageSequenceMaster; -import org.apache.fop.fo.pagination.Region; -import org.apache.fop.fo.pagination.RegionBody; import org.apache.fop.fo.pagination.SideRegion; -import org.apache.fop.fo.pagination.SimplePageMaster; import org.apache.fop.fo.pagination.StaticContent; -import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener; import org.apache.fop.layoutmgr.inline.ContentLayoutManager; -import org.apache.fop.traits.MinOptMax; - -import java.util.LinkedList; import java.util.List; -import java.util.ListIterator; /** * LayoutManager for a PageSequence. This class is instantiated by @@ -77,23 +64,17 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { private PageSequence pageSeq; private PageProvider pageProvider; - + + private IDTracker idTracker; + /** * Current page with page-viewport-area being filled by * the PSLM. */ - private Page curPage = null; - - /** - * The FlowLayoutManager object, which processes - * the single fo:flow of the fo:page-sequence - */ - private FlowLayoutManager childFLM = null; + private Page curPage; private int startPageNum = 0; private int currentPageNum = 0; - - private Block separatorArea = null; /** * Constructor @@ -104,8 +85,9 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { public PageSequenceLayoutManager(AreaTreeHandler ath, PageSequence pseq) { super(pseq); this.areaTreeHandler = ath; + this.idTracker = ath.getIDTracker(); this.pageSeq = pseq; - this.pageProvider = new PageProvider(this.pageSeq); + this.pageProvider = new PageProvider(ath, pseq); } /** @@ -121,6 +103,13 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { return this.pageProvider; } + /** + * @return the PageSequence being managed by this layout manager + */ + protected PageSequence getPageSequence() { + return pageSeq; + } + /** * Activate the layout of this page sequence. * PageViewports corresponding to each page generated by this @@ -150,10 +139,6 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { curPage = makeNewPage(false, false); - Flow mainFlow = pageSeq.getMainFlow(); - childFLM = getLayoutManagerMaker(). - makeFlowLayoutManager(this, mainFlow); - PageBreaker breaker = new PageBreaker(this); int flowBPD = (int)getCurrentPV().getBodyRegion().getRemainingBPD(); breaker.doLayout(flowBPD); @@ -165,8 +150,8 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { * Finished the page-sequence and notifies everyone about it. */ public void finishPageSequence() { - if (!pageSeq.getId().equals("")) { - areaTreeHandler.signalIDProcessed(pageSeq.getId()); + if (pageSeq.hasId()) { + idTracker.signalIDProcessed(pageSeq.getId()); } pageSeq.getRoot().notifyPageSequenceFinished(currentPageNum, @@ -188,392 +173,6 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { log.debug("Ending layout"); } } - - - private class PageBreaker extends AbstractBreaker { - - private PageSequenceLayoutManager pslm; - private boolean firstPart = true; - private boolean pageBreakHandled; - private boolean needColumnBalancing; - - private StaticContentLayoutManager footnoteSeparatorLM = null; - - public PageBreaker(PageSequenceLayoutManager pslm) { - this.pslm = pslm; - } - - /** @see org.apache.fop.layoutmgr.AbstractBreaker */ - protected void updateLayoutContext(LayoutContext context) { - int flowIPD = getCurrentPV().getCurrentSpan().getColumnWidth(); - context.setRefIPD(flowIPD); - } - - /** @see org.apache.fop.layoutmgr.AbstractBreaker#getTopLevelLM() */ - protected LayoutManager getTopLevelLM() { - return pslm; - } - - /** @see org.apache.fop.layoutmgr.AbstractBreaker#getPageProvider() */ - protected PageSequenceLayoutManager.PageProvider getPageProvider() { - return pageProvider; - } - - /** - * @see org.apache.fop.layoutmgr.AbstractBreaker#getLayoutListener() - */ - protected PageBreakingLayoutListener getLayoutListener() { - return new PageBreakingLayoutListener() { - - public void notifyOverflow(int part, FObj obj) { - Page p = pageProvider.getPage( - false, part, PageProvider.RELTO_CURRENT_ELEMENT_LIST); - RegionBody body = (RegionBody)p.getSimplePageMaster().getRegion( - Region.FO_REGION_BODY); - String err = FONode.decorateWithContextInfo( - "Content of the region-body on page " - + p.getPageViewport().getPageNumberString() - + " overflows the available area in block-progression dimension.", - obj); - if (body.getOverflow() == Constants.EN_ERROR_IF_OVERFLOW) { - throw new RuntimeException(err); - } else { - PageSequenceLayoutManager.log.warn(err); - } - } - - }; - } - - /** @see org.apache.fop.layoutmgr.AbstractBreaker */ - protected int handleSpanChange(LayoutContext childLC, int nextSequenceStartsOn) { - needColumnBalancing = false; - if (childLC.getNextSpan() != Constants.NOT_SET) { - //Next block list will have a different span. - nextSequenceStartsOn = childLC.getNextSpan(); - needColumnBalancing = (childLC.getNextSpan() == Constants.EN_ALL); - } - if (needColumnBalancing) { - AbstractBreaker.log.debug( - "Column balancing necessary for the next element list!!!"); - } - return nextSequenceStartsOn; - } - - /** @see org.apache.fop.layoutmgr.AbstractBreaker */ - protected int getNextBlockList(LayoutContext childLC, - int nextSequenceStartsOn, - List blockLists) { - if (!firstPart) { - // if this is the first page that will be created by - // the current BlockSequence, it could have a break - // condition that must be satisfied; - // otherwise, we may simply need a new page - handleBreakTrait(nextSequenceStartsOn); - } - firstPart = false; - pageBreakHandled = true; - pageProvider.setStartOfNextElementList(currentPageNum, - getCurrentPV().getCurrentSpan().getCurrentFlowIndex()); - return super.getNextBlockList(childLC, nextSequenceStartsOn, blockLists); - } - - /** @see org.apache.fop.layoutmgr.AbstractBreaker */ - protected LinkedList getNextKnuthElements(LayoutContext context, int alignment) { - LinkedList contentList = null; - - while (!childFLM.isFinished() && contentList == null) { - contentList = childFLM.getNextKnuthElements(context, alignment); - } - - // scan contentList, searching for footnotes - boolean bFootnotesPresent = false; - if (contentList != null) { - ListIterator contentListIterator = contentList.listIterator(); - while (contentListIterator.hasNext()) { - ListElement element = (ListElement) contentListIterator.next(); - if (element instanceof KnuthBlockBox - && ((KnuthBlockBox) element).hasAnchors()) { - // element represents a line with footnote citations - bFootnotesPresent = true; - LayoutContext footnoteContext = new LayoutContext(context); - footnoteContext.setStackLimit(context.getStackLimit()); - footnoteContext.setRefIPD(getCurrentPV() - .getRegionReference(Constants.FO_REGION_BODY).getIPD()); - LinkedList footnoteBodyLMs = ((KnuthBlockBox) element).getFootnoteBodyLMs(); - ListIterator footnoteBodyIterator = footnoteBodyLMs.listIterator(); - // store the lists of elements representing the footnote bodies - // in the box representing the line containing their references - while (footnoteBodyIterator.hasNext()) { - FootnoteBodyLayoutManager fblm - = (FootnoteBodyLayoutManager) footnoteBodyIterator.next(); - fblm.setParent(childFLM); - fblm.initialize(); - ((KnuthBlockBox) element).addElementList( - fblm.getNextKnuthElements(footnoteContext, alignment)); - } - } - } - } - - // handle the footnote separator - StaticContent footnoteSeparator; - if (bFootnotesPresent - && (footnoteSeparator = pageSeq.getStaticContent( - "xsl-footnote-separator")) != null) { - // the footnote separator can contain page-dependent content such as - // page numbers or retrieve markers, so its areas cannot simply be - // obtained now and repeated in each page; - // we need to know in advance the separator bpd: the actual separator - // could be different from page to page, but its bpd would likely be - // always the same - - // create a Block area that will contain the separator areas - separatorArea = new Block(); - separatorArea.setIPD(pslm.getCurrentPV() - .getRegionReference(Constants.FO_REGION_BODY).getIPD()); - // create a StaticContentLM for the footnote separator - footnoteSeparatorLM = (StaticContentLayoutManager) - getLayoutManagerMaker().makeStaticContentLayoutManager( - pslm, footnoteSeparator, separatorArea); - footnoteSeparatorLM.doLayout(); - - footnoteSeparatorLength = new MinOptMax(separatorArea.getBPD()); - } - return contentList; - } - - protected int getCurrentDisplayAlign() { - return curPage.getSimplePageMaster().getRegion( - Constants.FO_REGION_BODY).getDisplayAlign(); - } - - protected boolean hasMoreContent() { - return !childFLM.isFinished(); - } - - protected void addAreas(PositionIterator posIter, LayoutContext context) { - if (footnoteSeparatorLM != null) { - StaticContent footnoteSeparator = pageSeq.getStaticContent( - "xsl-footnote-separator"); - // create a Block area that will contain the separator areas - separatorArea = new Block(); - separatorArea.setIPD( - getCurrentPV().getRegionReference(Constants.FO_REGION_BODY).getIPD()); - // create a StaticContentLM for the footnote separator - footnoteSeparatorLM = (StaticContentLayoutManager) - getLayoutManagerMaker().makeStaticContentLayoutManager( - pslm, footnoteSeparator, separatorArea); - footnoteSeparatorLM.doLayout(); - } - - childFLM.addAreas(posIter, context); - } - - protected void doPhase3(PageBreakingAlgorithm alg, int partCount, - BlockSequence originalList, BlockSequence effectiveList) { - if (needColumnBalancing) { - 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 { - //Directly add areas after finding the breaks - addAreas(alg, partCount, originalList, effectiveList); - } - } - } - - 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); - } - } else { - newStartPos = 0; - } - AbstractBreaker.log.debug("Last page handling now!!!"); - AbstractBreaker.log.debug("==================================================="); - 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()); - pageProvider.setLastPageIndex(currentPageNum); - - //Restart last page - PageBreakingAlgorithm algRestart = new PageBreakingAlgorithm( - getTopLevelLM(), - getPageProvider(), getLayoutListener(), - alg.getAlignment(), alg.getAlignmentLast(), - footnoteSeparatorLength, - isPartOverflowRecoveryActivated(), false, 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); - } else { - 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(), getLayoutListener(), - 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) { - AbstractBreaker.log.debug("startPart() breakClass=" + breakClass); - if (curPage == null) { - throw new IllegalStateException("curPage must not be null"); - } - if (!pageBreakHandled) { - - //firstPart is necessary because we need the first page before we start the - //algorithm so we have a BPD and IPD. This may subject to change later when we - //start handling more complex cases. - if (!firstPart) { - // if this is the first page that will be created by - // the current BlockSequence, it could have a break - // condition that must be satisfied; - // otherwise, we may simply need a new page - handleBreakTrait(breakClass); - } - pageProvider.setStartOfNextElementList(currentPageNum, - getCurrentPV().getCurrentSpan().getCurrentFlowIndex()); - } - pageBreakHandled = false; - // add static areas and resolve any new id areas - // finish page and add to area tree - firstPart = false; - } - - /** @see org.apache.fop.layoutmgr.AbstractBreaker#handleEmptyContent() */ - protected void handleEmptyContent() { - getCurrentPV().getPage().fakeNonEmpty(); - } - - protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) { - // add footnote areas - if (pbp.footnoteFirstListIndex < pbp.footnoteLastListIndex - || pbp.footnoteFirstElementIndex <= pbp.footnoteLastElementIndex) { - // call addAreas() for each FootnoteBodyLM - for (int i = pbp.footnoteFirstListIndex; i <= pbp.footnoteLastListIndex; i++) { - LinkedList elementList = alg.getFootnoteList(i); - int firstIndex = (i == pbp.footnoteFirstListIndex - ? pbp.footnoteFirstElementIndex : 0); - int lastIndex = (i == pbp.footnoteLastListIndex - ? pbp.footnoteLastElementIndex : elementList.size() - 1); - - SpaceResolver.performConditionalsNotification(elementList, - firstIndex, lastIndex, -1); - LayoutContext childLC = new LayoutContext(0); - AreaAdditionUtil.addAreas(null, - new KnuthPossPosIter(elementList, firstIndex, lastIndex + 1), - childLC); - } - // set the offset from the top margin - Footnote parentArea = (Footnote) getCurrentPV().getBodyRegion().getFootnote(); - int topOffset = (int) getCurrentPV().getBodyRegion().getBPD() - parentArea.getBPD(); - if (separatorArea != null) { - topOffset -= separatorArea.getBPD(); - } - parentArea.setTop(topOffset); - parentArea.setSeparator(separatorArea); - } - getCurrentPV().getCurrentSpan().notifyFlowsFinished(); - } - - protected LayoutManager getCurrentChildLM() { - return childFLM; - } - - /** @see org.apache.fop.layoutmgr.AbstractBreaker#observeElementList(java.util.List) */ - protected void observeElementList(List elementList) { - ElementListObserver.observe(elementList, "breaker", - ((PageSequence)pslm.getFObj()).getId()); - } - - } /** * Provides access to the current page. @@ -583,6 +182,22 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { return curPage; } + /** + * Provides access for setting the current page. + * @param currentPage the new current Page + */ + protected void setCurrentPage(Page currentPage) { + this.curPage = currentPage; + } + + /** + * Provides access to the current page number + * @return the current page number + */ + protected int getCurrentPageNum() { + return currentPageNum; + } + /** * Provides access to the current page viewport. * @return the current PageViewport @@ -607,7 +222,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { * @return the first PageViewport that contains the ID trait */ public PageViewport getFirstPVWithID(String idref) { - List list = areaTreeHandler.getPageViewportsContainingID(idref); + List list = idTracker.getPageViewportsContainingID(idref); if (list != null && list.size() > 0) { return (PageViewport) list.get(0); } @@ -622,7 +237,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { * @return the last PageViewport that contains the ID trait */ public PageViewport getLastPVWithID(String idref) { - List list = areaTreeHandler.getPageViewportsContainingID(idref); + List list = idTracker.getPageViewportsContainingID(idref); if (list != null && list.size() > 0) { return (PageViewport) list.get(list.size() - 1); } @@ -639,7 +254,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { */ public void addIDToPage(String id) { if (id != null && id.length() > 0) { - areaTreeHandler.associateIDWithPageViewport(id, curPage.getPageViewport()); + idTracker.associateIDWithPageViewport(id, curPage.getPageViewport()); } } @@ -654,8 +269,8 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { if (log.isDebugEnabled()) { log.debug("associateLayoutManagerID(" + id + ")"); } - if (!areaTreeHandler.alreadyResolvedID(id)) { - areaTreeHandler.signalPendingID(id); + if (!idTracker.alreadyResolvedID(id)) { + idTracker.signalPendingID(id); return false; } else { return true; @@ -668,7 +283,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { * @param id the id for which layout has finished */ public void notifyEndOfLayout(String id) { - areaTreeHandler.signalIDProcessed(id); + idTracker.signalIDProcessed(id); } /** @@ -676,7 +291,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { * resolved, e.g. the internal-destination of an fo:basic-link) * for both the AreaTreeHandler and PageViewport object. * - * The AreaTreeHandler keeps a document-wide list of idref's + * The IDTracker keeps a document-wide list of idref's * and the PV's needing them to be resolved. It uses this to * send notifications to the PV's when an id has been resolved. * @@ -689,7 +304,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { */ public void addUnresolvedArea(String id, Resolvable res) { curPage.getPageViewport().addUnresolvedIDRef(id, res); - areaTreeHandler.addUnresolvedIDRef(id, curPage.getPageViewport()); + idTracker.addUnresolvedIDRef(id, curPage.getPageViewport()); } /** @@ -750,7 +365,14 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { } } - private Page makeNewPage(boolean bIsBlank, boolean bIsLast) { + /** + * Makes a new page + * + * @param bIsBlank whether this page is blank or not + * @param bIsLast whether this page is the last page or not + * @return a new page + */ + protected Page makeNewPage(boolean bIsBlank, boolean bIsLast) { if (curPage != null) { finishPage(); } @@ -797,7 +419,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { // Try to resolve any unresolved IDs for the current page. // - areaTreeHandler.tryIDResolution(curPage.getPageViewport()); + idTracker.tryIDResolution(curPage.getPageViewport()); // Queue for ID resolution and rendering areaTreeHandler.getAreaTreeModel().addPage(curPage.getPageViewport()); if (log.isDebugEnabled()) { @@ -806,320 +428,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { } curPage = null; } - - /** - * Depending on the kind of break condition, move to next column - * or page. May need to make an empty page if next page would - * not have the desired "handedness". - * @param breakVal - value of break-before or break-after trait. - */ - private void handleBreakTrait(int breakVal) { - if (breakVal == Constants.EN_ALL) { - //break due to span change in multi-column layout - curPage.getPageViewport().createSpan(true); - return; - } else if (breakVal == Constants.EN_NONE) { - curPage.getPageViewport().createSpan(false); - return; - } else if (breakVal == Constants.EN_COLUMN || breakVal <= 0) { - PageViewport pv = curPage.getPageViewport(); - - //Check if previous page was spanned - boolean forceNewPageWithSpan = false; - RegionBody rb = (RegionBody)curPage.getSimplePageMaster().getRegion( - Constants.FO_REGION_BODY); - if (breakVal < 0 - && rb.getColumnCount() > 1 - && pv.getCurrentSpan().getColumnCount() == 1) { - forceNewPageWithSpan = true; - } - - if (forceNewPageWithSpan) { - curPage = makeNewPage(false, false); - curPage.getPageViewport().createSpan(true); - } else if (pv.getCurrentSpan().hasMoreFlows()) { - pv.getCurrentSpan().moveToNextFlow(); - } else { - curPage = makeNewPage(false, false); - } - return; - } - log.debug("handling break-before after page " + currentPageNum - + " breakVal=" + breakVal); - if (needBlankPageBeforeNew(breakVal)) { - curPage = makeNewPage(true, false); - } - if (needNewPage(breakVal)) { - curPage = makeNewPage(false, false); - } - } - - /** - * Check if a blank page is needed to accomodate - * desired even or odd page number. - * @param breakVal - value of break-before or break-after trait. - */ - private boolean needBlankPageBeforeNew(int breakVal) { - if (breakVal == Constants.EN_PAGE || (curPage.getPageViewport().getPage().isEmpty())) { - // any page is OK or we already have an empty page - return false; - } else { - /* IF we are on the kind of page we need, we'll need a new page. */ - if (currentPageNum % 2 == 0) { // even page - return (breakVal == Constants.EN_EVEN_PAGE); - } else { // odd page - return (breakVal == Constants.EN_ODD_PAGE); - } - } - } - - /** - * See if need to generate a new page - * @param breakVal - value of break-before or break-after trait. - */ - private boolean needNewPage(int breakVal) { - if (curPage.getPageViewport().getPage().isEmpty()) { - if (breakVal == Constants.EN_PAGE) { - return false; - } else if (currentPageNum % 2 == 0) { // even page - return (breakVal == Constants.EN_ODD_PAGE); - } else { // odd page - return (breakVal == Constants.EN_EVEN_PAGE); - } - } else { - return true; - } - } - - - /** - *

This class delivers Page instances. It also caches them as necessary. - *

- *

Additional functionality makes sure that surplus instances that are requested by the - * page breaker are properly discarded, especially in situations where hard breaks cause - * blank pages. The reason for that: The page breaker sometimes needs to preallocate - * additional pages since it doesn't know exactly until the end how many pages it really needs. - *

- */ - public class PageProvider { - - private Log log = LogFactory.getLog(PageProvider.class); - - /** Indices are evaluated relative to the first page in the page-sequence. */ - public static final int RELTO_PAGE_SEQUENCE = 0; - /** Indices are evaluated relative to the first page in the current element list. */ - public static final int RELTO_CURRENT_ELEMENT_LIST = 1; - - private int startPageOfPageSequence; - private int startPageOfCurrentElementList; - 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; - - /** - * Main constructor. - * @param ps The page-sequence the provider operates on - */ - public PageProvider(PageSequence ps) { - this.startPageOfPageSequence = ps.getStartingPageNumber(); - } - - /** - * The page breaker notifies the provider about the page number an element list starts - * on so it can later retrieve PageViewports relative to this first page. - * @param startPage the number of the first page for the element list. - * @param startColumn the starting column number for the element list. - */ - public void setStartOfNextElementList(int startPage, int startColumn) { - log.debug("start of the next element list is:" - + " page=" + startPage + " col=" + startColumn); - this.startPageOfCurrentElementList = startPage - startPageOfPageSequence + 1; - this.startColumnOfCurrentElementList = startColumn; - //Reset Cache - this.lastRequestedIndex = -1; - 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. - * This method takes multiple columns into account. - * @param index zero-based index of the requested part/page - * @return the available BPD - */ - public int getAvailableBPD(int index) { - //Special optimization: There may be many equal calls by the BreakingAlgorithm - if (this.lastRequestedIndex == index) { - if (log.isTraceEnabled()) { - log.trace("getAvailableBPD(" + index + ") -> (cached) " + lastReportedBPD); - } - return this.lastReportedBPD; - } - int c = index; - int pageIndex = 0; - int colIndex = startColumnOfCurrentElementList; - Page page = getPage( - false, pageIndex, RELTO_CURRENT_ELEMENT_LIST); - while (c > 0) { - colIndex++; - if (colIndex >= page.getPageViewport().getCurrentSpan().getColumnCount()) { - colIndex = 0; - pageIndex++; - page = getPage( - false, pageIndex, RELTO_CURRENT_ELEMENT_LIST); - } - c--; - } - this.lastRequestedIndex = index; - this.lastReportedBPD = page.getPageViewport().getBodyRegion().getRemainingBPD(); - if (log.isTraceEnabled()) { - log.trace("getAvailableBPD(" + index + ") -> " + lastReportedBPD); - } - return this.lastReportedBPD; - } - - /** - * Returns the part index (0= page.getPageViewport().getCurrentSpan().getColumnCount())) { - colIndex = 0; - pageIndex++; - page = getPage( - false, pageIndex, RELTO_CURRENT_ELEMENT_LIST); - result = idx; - } - colIndex++; - idx++; - } - return result; - } - - /** - * Returns a Page. - * @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 isBlank, int index, int relativeTo) { - if (relativeTo == RELTO_PAGE_SEQUENCE) { - return getPage(isBlank, index); - } else if (relativeTo == RELTO_CURRENT_ELEMENT_LIST) { - int effIndex = startPageOfCurrentElementList + index; - effIndex += startPageOfPageSequence - 1; - return getPage(isBlank, effIndex); - } else { - throw new IllegalArgumentException( - "Illegal value for relativeTo: " + relativeTo); - } - } - private Page getPage(boolean isBlank, int index) { - boolean isLastPage = (lastPageIndex >= 0) && (index == lastPageIndex); - if (log.isTraceEnabled()) { - log.trace("getPage(" + index + " " + (isBlank ? "blank" : "non-blank") - + (isLastPage ? " " : "") + ")"); - } - int intIndex = index - startPageOfPageSequence; - if (log.isTraceEnabled()) { - 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, isBlank, isLastPage); - } - Page page = (Page)cachedPages.get(intIndex); - boolean replace = false; - if (page.getPageViewport().isBlank() != isBlank) { - log.debug("blank condition doesn't match. Replacing PageViewport."); - 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 Page cacheNextPage(int index, boolean isBlank, boolean isLastPage) { - try { - String pageNumberString = pageSeq.makeFormattedPageNumber(index); - SimplePageMaster spm = pageSeq.getNextSimplePageMaster( - index, (startPageOfPageSequence == index), 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. - 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."); - } - Page page = new Page(spm, index, pageNumberString, isBlank); - //Set unique key obtained from the AreaTreeHandler - page.getPageViewport().setKey(areaTreeHandler.generatePageViewportKey()); - page.getPageViewport().setForeignAttributes(spm.getForeignAttributes()); - cachedPages.add(page); - return page; - } catch (FOPException e) { - //TODO Maybe improve. It'll mean to propagate this exception up several - //methods calls. - throw new IllegalStateException(e.getMessage()); - } - } - - } - /** * Act upon the force-page-count trait, * in relation to the initial-page-number trait of the following page-sequence. diff --git a/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java index 7e261d074..e60e38870 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java @@ -58,8 +58,8 @@ public class BasicLinkLayoutManager extends InlineLayoutManager { */ private void setupBasicLinkArea(LayoutManager parentLM, InlineArea area) { // internal destinations take precedence: - String idref = fobj.getInternalDestination(); - if (idref != null && idref.length() > 0) { + if (fobj.hasInternalDestination()) { + String idref = fobj.getInternalDestination(); PageSequenceLayoutManager pslm = getPSLM(); // the INTERNAL_LINK trait is added by the LinkResolver // if and when the link is resolved: @@ -68,13 +68,10 @@ public class BasicLinkLayoutManager extends InlineLayoutManager { if (!res.isResolved()) { pslm.addUnresolvedArea(idref, res); } - } else { - String extdest = fobj.getExternalDestination(); - if (extdest != null) { - String url = URISpecification.getURL(extdest); - if (url.length() > 0) { - area.addTrait(Trait.EXTERNAL_LINK, url); - } + } else if (fobj.hasExternalDestination()) { + String url = URISpecification.getURL(fobj.getExternalDestination()); + if (url.length() > 0) { + area.addTrait(Trait.EXTERNAL_LINK, url); } } } diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java index ac0363cb2..4a142cffe 100644 --- a/src/java/org/apache/fop/render/rtf/RTFHandler.java +++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java @@ -1093,7 +1093,7 @@ public class RTFHandler extends FOEventHandler { RtfHyperLink link = textrun.addHyperlink(new RtfAttributes()); - if (basicLink.getExternalDestination() != null) { + if (basicLink.hasExternalDestination()) { link.setExternalURL(basicLink.getExternalDestination()); } else { link.setInternalURL(basicLink.getInternalDestination()); diff --git a/status.xml b/status.xml index ff79d4998..24df14c88 100644 --- a/status.xml +++ b/status.xml @@ -28,6 +28,13 @@ + + Code cleanup and restructuring. + + + Slight improvement of relative font-weight handling in the properties + package. + Updated PDF/A-1b support according to ISO-19005-1:2005/Cor.1:2007. -- 2.39.5