From fcfb10d2ec7797f769ff911e64aaade9de2faf1e Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Sun, 23 Apr 2006 09:31:08 +0000 Subject: [PATCH] Bugzilla #39118: Initial support for page-number-citation-last (XSL 1.1). Works without problems only for page-sequence so far. Submitted by: Pierre-Henri Kraus Modifications to the patch by jeremias during review: - Tab character removed - Some style fixes and javadoc enhancements - Renamed some methods in AreaTreeHandler to some more speaking names - Changed the ..._basic.xml testcase so it shows a remaining problem: Forward references are not properly resolved, yet. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@396243 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/area/AreaTreeHandler.java | 63 +++++++- .../fop/area/inline/UnresolvedPageNumber.java | 36 ++++- src/java/org/apache/fop/fo/Constants.java | 6 +- .../org/apache/fop/fo/FOElementMapping.java | 10 +- src/java/org/apache/fop/fo/FObj.java | 1 + src/java/org/apache/fop/fo/PropertySets.java | 42 +++++- .../fop/fo/flow/PageNumberCitationLast.java | 49 ++++++ .../BlockContainerLayoutManager.java | 2 + .../fop/layoutmgr/BlockLayoutManager.java | 3 + .../fop/layoutmgr/LayoutManagerMapping.java | 11 ++ .../layoutmgr/PageSequenceLayoutManager.java | 54 ++++++- .../PageNumberCitationLastLayoutManager.java | 83 +++++++++++ .../PageNumberCitationLayoutManager.java | 44 +++--- .../list/ListBlockLayoutManager.java | 2 + .../list/ListItemContentLayoutManager.java | 2 + .../layoutmgr/list/ListItemLayoutManager.java | 2 + .../table/TableCellLayoutManager.java | 2 + .../layoutmgr/table/TableLayoutManager.java | 3 + status.xml | 4 + test/layoutengine/disabled-testcases.xml | 5 + .../page-number-citation-last_basic.xml | 92 ++++++++++++ .../page-number-citation-last_complex.xml | 113 ++++++++++++++ ...age-number-citation-last_page-sequence.xml | 140 ++++++++++++++++++ .../page-position_last_1.xml | 4 +- 24 files changed, 733 insertions(+), 40 deletions(-) create mode 100644 src/java/org/apache/fop/fo/flow/PageNumberCitationLast.java create mode 100644 src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java create mode 100644 test/layoutengine/standard-testcases/page-number-citation-last_basic.xml create mode 100644 test/layoutengine/standard-testcases/page-number-citation-last_complex.xml create mode 100644 test/layoutengine/standard-testcases/page-number-citation-last_page-sequence.xml diff --git a/src/java/org/apache/fop/area/AreaTreeHandler.java b/src/java/org/apache/fop/area/AreaTreeHandler.java index 82a4ba234..8e165a99e 100644 --- a/src/java/org/apache/fop/area/AreaTreeHandler.java +++ b/src/java/org/apache/fop/area/AreaTreeHandler.java @@ -95,6 +95,9 @@ public class AreaTreeHandler extends FOEventHandler { // 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(); @@ -180,11 +183,62 @@ public class AreaTreeHandler extends FOEventHandler { * See if this ID is in the unresolved idref list, if so * resolve Resolvable objects tied to it. */ - tryIDResolution(id, pv, pvList); + 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. @@ -197,8 +251,13 @@ public class AreaTreeHandler extends FOEventHandler { if (todo != null) { for (Iterator iter = todo.iterator(); iter.hasNext();) { Resolvable res = (Resolvable) iter.next(); - res.resolveIDRef(id, pvList); + if (!unfinishedIDs.contains(id)) { + res.resolveIDRef(id, pvList); + } else { + return; + } } + alreadyResolvedIDs.add(id); unresolvedIDRefs.remove(id); } } diff --git a/src/java/org/apache/fop/area/inline/UnresolvedPageNumber.java b/src/java/org/apache/fop/area/inline/UnresolvedPageNumber.java index 99978e7c6..fc28bda49 100644 --- a/src/java/org/apache/fop/area/inline/UnresolvedPageNumber.java +++ b/src/java/org/apache/fop/area/inline/UnresolvedPageNumber.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,20 +34,39 @@ public class UnresolvedPageNumber extends TextArea implements Resolvable { private boolean resolved = false; private String pageIDRef; private String text; + private boolean pageType; + /** Indicates that the reference refers to the first area generated by a formatting object. */ + public static final boolean FIRST = true; + /** Indicates that the reference refers to the last area generated by a formatting object. */ + public static final boolean LAST = false; + //Transient fields private transient Font font; /** - * Create a new unresolvable page number. + * Create a new unresolved page number. * * @param id the id reference for resolving this * @param f the font for formatting the page number */ public UnresolvedPageNumber(String id, Font f) { + this(id, f, FIRST); + } + + /** + * Create a new unresolved page number. + * + * @param id the id reference for resolving this + * @param f the font for formatting the page number + * @param type indicates whether the reference refers to the first or last area generated by + * a formatting object + */ + public UnresolvedPageNumber(String id, Font f, boolean type) { pageIDRef = id; font = f; text = "?"; + pageType = type; } /** @@ -70,9 +89,17 @@ public class UnresolvedPageNumber extends TextArea implements Resolvable { * @param pages the list of PageViewports associated with this ID */ public void resolveIDRef(String id, List pages) { + if (log.isDebugEnabled()) { + log.debug("Resolving pageNumber: " + id); + } if (pageIDRef.equals(id) && pages != null) { resolved = true; - PageViewport page = (PageViewport)pages.get(0); + PageViewport page; + if (pageType == FIRST) { + page = (PageViewport)pages.get(0); + } else { + page = (PageViewport)pages.get(pages.size() - 1); + } // replace the text removeText(); addWord(page.getPageNumberString(), 0); @@ -83,7 +110,7 @@ public class UnresolvedPageNumber extends TextArea implements Resolvable { font = null; } else { log.warn("Cannot update the IPD of an unresolved page number." - + " No font information avilable."); + + " No font information available."); } } } @@ -108,5 +135,4 @@ public class UnresolvedPageNumber extends TextArea implements Resolvable { int lineStretch, int lineShrink) { return true; } - } diff --git a/src/java/org/apache/fop/fo/Constants.java b/src/java/org/apache/fop/fo/Constants.java index 737d54854..b28a350fc 100644 --- a/src/java/org/apache/fop/fo/Constants.java +++ b/src/java/org/apache/fop/fo/Constants.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -156,8 +156,10 @@ public interface Constants { int FO_BOOKMARK_TITLE = 59; /** FO element constant - XSL 1.1 */ int FO_PAGE_SEQUENCE_WRAPPER = 60; + /** FO element constant - XSL 1.1 */ + int FO_PAGE_NUMBER_CITATION_LAST = 61; /** Number of FO element constants defined */ - int FRM_OBJ_COUNT = 60; + int FRM_OBJ_COUNT = 61; // Masks /** diff --git a/src/java/org/apache/fop/fo/FOElementMapping.java b/src/java/org/apache/fop/fo/FOElementMapping.java index bf376de2a..609cfcc34 100644 --- a/src/java/org/apache/fop/fo/FOElementMapping.java +++ b/src/java/org/apache/fop/fo/FOElementMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -93,6 +93,8 @@ public class FOElementMapping extends ElementMapping { foObjs.put("page-number", new PageNumberMaker()); foObjs.put("page-number-citation", new PageNumberCitationMaker()); + foObjs.put("page-number-citation-last", + new PageNumberCitationLastMaker()); // Formatting Objects for Tables foObjs.put("table-and-caption", new TableAndCaptionMaker()); @@ -343,6 +345,12 @@ public class FOElementMapping extends ElementMapping { } } + static class PageNumberCitationLastMaker extends ElementMapping.Maker { + public FONode make(FONode parent) { + return new org.apache.fop.fo.flow.PageNumberCitationLast(parent); + } + } + static class TableAndCaptionMaker extends ElementMapping.Maker { public FONode make(FONode parent) { return new org.apache.fop.fo.flow.TableAndCaption(parent); diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java index 549f03c58..af45735e6 100644 --- a/src/java/org/apache/fop/fo/FObj.java +++ b/src/java/org/apache/fop/fo/FObj.java @@ -378,6 +378,7 @@ public abstract class FObj extends FONode implements Constants { || lName.equals("leader") || lName.equals("page-number") || lName.equals("page-number-citation") + || lName.equals("page-number-citation-last") || lName.equals("basic-link") || (lName.equals("multi-toggle") && (getNameId() == FO_MULTI_CASE diff --git a/src/java/org/apache/fop/fo/PropertySets.java b/src/java/org/apache/fop/fo/PropertySets.java index 61bc15a08..c0dbe4a19 100644 --- a/src/java/org/apache/fop/fo/PropertySets.java +++ b/src/java/org/apache/fop/fo/PropertySets.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ /* $Id$ */ - package org.apache.fop.fo; import org.apache.fop.fo.Constants; @@ -28,7 +27,7 @@ public class PropertySets { private static BitSet can_have_markers = null; private static BitSet no_inline_areas = null; - private Element[] elements = new Element[Constants.FRM_OBJ_COUNT+1]; + private Element[] elements = new Element[Constants.FRM_OBJ_COUNT + 1]; private BitSet block_elems = new BitSet(); private BitSet inline_elems = new BitSet(); @@ -58,6 +57,7 @@ public class PropertySets { inline_elems.set(Constants.FO_LEADER); inline_elems.set(Constants.FO_PAGE_NUMBER); inline_elems.set(Constants.FO_PAGE_NUMBER_CITATION); + inline_elems.set(Constants.FO_PAGE_NUMBER_CITATION_LAST); inline_elems.set(Constants.FO_BASIC_LINK); inline_elems.set(Constants.FO_MULTI_TOGGLE); } @@ -679,6 +679,34 @@ public class PropertySets { elem.addProperty(Constants.PR_VISIBILITY); elem.addProperty(Constants.PR_WORD_SPACING); elem.addProperty(Constants.PR_WRAP_OPTION); + + elem = elements[Constants.FO_PAGE_NUMBER_CITATION_LAST]; + elem.addProperties(CommonAccessibilityProperties); + elem.addProperties(CommonAuralProperties); + elem.addProperties(CommonBorderPaddingBackgroundProperties); + elem.addProperties(CommonFontProperties); + elem.addProperties(CommonMarginPropertiesInline); + elem.addProperties(CommonRelativePositionProperties); + elem.addProperty(Constants.PR_VERTICAL_ALIGN); + elem.addProperty(Constants.PR_ALIGNMENT_ADJUST); + elem.addProperty(Constants.PR_ALIGNMENT_BASELINE); + elem.addProperty(Constants.PR_BASELINE_SHIFT); + elem.addProperty(Constants.PR_DOMINANT_BASELINE); + elem.addProperty(Constants.PR_ID); + elem.addProperty(Constants.PR_KEEP_WITH_NEXT); + elem.addProperty(Constants.PR_KEEP_WITH_PREVIOUS); + elem.addProperty(Constants.PR_LETTER_SPACING); + elem.addProperty(Constants.PR_LINE_HEIGHT); + elem.addProperty(Constants.PR_REF_ID); + elem.addProperty(Constants.PR_SCORE_SPACES); + elem.addProperty(Constants.PR_TEXT_ALTITUDE); + elem.addProperty(Constants.PR_TEXT_DECORATION); + elem.addProperty(Constants.PR_TEXT_DEPTH); + elem.addProperty(Constants.PR_TEXT_SHADOW); + elem.addProperty(Constants.PR_TEXT_TRANSFORM); + elem.addProperty(Constants.PR_VISIBILITY); + elem.addProperty(Constants.PR_WORD_SPACING); + elem.addProperty(Constants.PR_WRAP_OPTION); elem = elements[Constants.FO_TABLE_AND_CAPTION]; elem.addProperties(CommonAccessibilityProperties); @@ -992,7 +1020,7 @@ public class PropertySets { elem.addProperty(Constants.PR_RETRIEVE_BOUNDARY); // Merge the attributes from the children into the parent. - for (boolean dirty = true; dirty; ) { + for (boolean dirty = true; dirty;) { dirty = false; for (int i = 1; i < elements.length; i++) { dirty = dirty || elements[i].merge(); @@ -1009,9 +1037,9 @@ public class PropertySets { * on the array the number of set bits in the BitSet. */ private static short[] makeSparseIndices(BitSet set) { - short[] indices = new short[Constants.PROPERTY_COUNT+1]; + short[] indices = new short[Constants.PROPERTY_COUNT + 1]; int j = 1; - for (int i = 0; i < Constants.PROPERTY_COUNT+1; i++) { + for (int i = 0; i < Constants.PROPERTY_COUNT + 1; i++) { if (set.get(i)) { indices[i] = (short) j++; } @@ -1022,7 +1050,7 @@ public class PropertySets { public static short[] getPropertySet(int elementId) { if (mapping == null) { - mapping = new short[Constants.FRM_OBJ_COUNT+1][]; + mapping = new short[Constants.FRM_OBJ_COUNT + 1][]; PropertySets ps = new PropertySets(); ps.initializeElements(); ps.initializeCommon(); diff --git a/src/java/org/apache/fop/fo/flow/PageNumberCitationLast.java b/src/java/org/apache/fop/fo/flow/PageNumberCitationLast.java new file mode 100644 index 000000000..89817e4ef --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/PageNumberCitationLast.java @@ -0,0 +1,49 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.flow; + +import org.apache.fop.fo.FONode; + +/** + * Class modelling the fo:page-number-citation-last object from XSL 1.1. + * This inline fo is replaced with the text for a page number. + * The page number used is the page that contains the end of the + * block referenced with the ref-id attribute. + * @since XSL 1.1 + */ +public class PageNumberCitationLast extends PageNumberCitation { + + /** + * Main constructor + * @param parent the parent FO node + */ + public PageNumberCitationLast(FONode parent) { + super(parent); + } + + /** @see org.apache.fop.fo.FONode#getLocalName() */ + public String getLocalName() { + return "page-number-citation-last"; + } + + /** @see org.apache.fop.fo.FObj#getNameId() */ + public int getNameId() { + return FO_PAGE_NUMBER_CITATION_LAST; + } +} diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java index 2c593fd02..1af26cb4d 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java @@ -837,6 +837,8 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager viewportBlockArea = null; referenceArea = null; resetSpaces(); + + getPSLM().notifyEndOfLayout(((BlockContainer)getFObj()).getId()); } /** diff --git a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java index a303f18fd..4e6d3750a 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java @@ -395,6 +395,9 @@ public class BlockLayoutManager extends BlockStackingLayoutManager curBlockArea = null; resetSpaces(); + + // Notify end of block layout manager to the PSLM + getPSLM().notifyEndOfLayout(getBlockFO().getId()); } /** diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java index 783c6a604..9a812e016 100644 --- a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java +++ b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java @@ -15,6 +15,7 @@ */ /* $Id$ */ + package org.apache.fop.layoutmgr; import java.util.ArrayList; @@ -45,6 +46,7 @@ import org.apache.fop.fo.flow.ListBlock; import org.apache.fop.fo.flow.ListItem; import org.apache.fop.fo.flow.PageNumber; import org.apache.fop.fo.flow.PageNumberCitation; +import org.apache.fop.fo.flow.PageNumberCitationLast; import org.apache.fop.fo.flow.RetrieveMarker; import org.apache.fop.fo.flow.Table; import org.apache.fop.fo.flow.TableBody; @@ -73,6 +75,7 @@ import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager; import org.apache.fop.layoutmgr.inline.InstreamForeignObjectLM; import org.apache.fop.layoutmgr.inline.LeaderLayoutManager; import org.apache.fop.layoutmgr.inline.PageNumberCitationLayoutManager; +import org.apache.fop.layoutmgr.inline.PageNumberCitationLastLayoutManager; import org.apache.fop.layoutmgr.inline.PageNumberLayoutManager; import org.apache.fop.layoutmgr.inline.TextLayoutManager; import org.apache.fop.layoutmgr.inline.WrapperLayoutManager; @@ -123,6 +126,8 @@ public class LayoutManagerMapping implements LayoutManagerMaker { makers.put(PageNumber.class, new PageNumberLayoutManagerMaker()); makers.put(PageNumberCitation.class, new PageNumberCitationLayoutManagerMaker()); + makers.put(PageNumberCitationLast.class, + new PageNumberCitationLastLayoutManagerMaker()); makers.put(Table.class, new TableLayoutManagerMaker()); makers.put(TableBody.class, new Maker()); makers.put(TableColumn.class, new Maker()); @@ -349,6 +354,12 @@ public class LayoutManagerMapping implements LayoutManagerMaker { } } + public static class PageNumberCitationLastLayoutManagerMaker extends Maker { + public void make(FONode node, List lms) { + lms.add(new PageNumberCitationLastLayoutManager((PageNumberCitationLast) node)); + } + } + public static class TableLayoutManagerMaker extends Maker { public void make(FONode node, List lms) { Table table = (Table) node; diff --git a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java index a410e1838..9c1693a59 100644 --- a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java @@ -142,7 +142,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { curPage = makeNewPage(false, false); - addIDToPage(pageSeq.getId()); + Flow mainFlow = pageSeq.getMainFlow(); childFLM = getLayoutManagerMaker(). makeFlowLayoutManager(this, mainFlow); @@ -158,6 +158,10 @@ 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()); + } + pageSeq.getRoot().notifyPageSequenceFinished(currentPageNum, (currentPageNum - startPageNum) + 1); areaTreeHandler.notifyPageSequenceFinished(pageSeq, @@ -165,6 +169,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { log.debug("Ending layout"); } + private class PageBreaker extends AbstractBreaker { private PageSequenceLayoutManager pslm; @@ -562,6 +567,21 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { return null; } + /** + * This returns the last PageViewport that contains an id trait + * matching the idref argument, or null if no such PV exists. + * + * @param idref the idref trait needing to be resolved + * @return the last PageViewport that contains the ID trait + */ + public PageViewport getLastPVWithID(String idref) { + List list = areaTreeHandler.getPageViewportsContainingID(idref); + if (list != null && list.size() > 0) { + return (PageViewport) list.get(list.size() - 1); + } + return null; + } + /** * Add an ID reference to the current page. * When adding areas the area adds its ID reference. @@ -575,7 +595,35 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { areaTreeHandler.associateIDWithPageViewport(id, curPage.getPageViewport()); } } - + + /** + * Add an id reference of the layout manager in the AreaTreeHandler, + * if the id hasn't been resolved yet + * @param id the id to track + * @return a boolean indicating if the id has already been resolved + * TODO Maybe give this a better name + */ + public boolean associateLayoutManagerID(String id) { + if (log.isDebugEnabled()) { + log.debug("associateLayoutManagerID(" + id + ")"); + } + if (!areaTreeHandler.alreadyResolvedID(id)) { + areaTreeHandler.signalPendingID(id); + return false; + } else { + return true; + } + } + + /** + * Notify the areaTreeHandler that the LayoutManagers containing + * idrefs have finished creating areas + * @param id the id for which layout has finished + */ + public void notifyEndOfLayout(String id) { + areaTreeHandler.signalIDProcessed(id); + } + /** * Identify an unresolved area (one needing an idref to be * resolved, e.g. the internal-destination of an fo:basic-link) @@ -669,6 +717,8 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { log.debug("[" + curPage.getPageViewport().getPageNumberString() + (bIsBlank ? "*" : "") + "]"); } + + addIDToPage(pageSeq.getId()); return curPage; } diff --git a/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java new file mode 100644 index 000000000..f55c00fec --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java @@ -0,0 +1,83 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.layoutmgr.inline; + +import org.apache.fop.fo.flow.PageNumberCitationLast; +import org.apache.fop.area.PageViewport; +import org.apache.fop.area.Resolvable; +import org.apache.fop.area.inline.InlineArea; +import org.apache.fop.area.inline.UnresolvedPageNumber; +import org.apache.fop.area.inline.TextArea; +import org.apache.fop.layoutmgr.LayoutContext; +import org.apache.fop.layoutmgr.LayoutManager; + +/** + * LayoutManager for the fo:page-number-citation-last formatting object + */ +public class PageNumberCitationLastLayoutManager extends PageNumberCitationLayoutManager { + + private PageNumberCitationLast fobj; + + /** + * Constructor + * + * @param node the formatting object that creates this area + * @todo better retrieval of font info + */ + public PageNumberCitationLastLayoutManager(PageNumberCitationLast node) { + super(node); + fobj = node; + } + + /** @see org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager#get(LayoutContext) */ + public InlineArea get(LayoutContext context) { + curArea = getPageNumberCitationLastInlineArea(parentLM); + return curArea; + } + + /** + * if id can be resolved then simply return a word, otherwise + * return a resolvable area + */ + private InlineArea getPageNumberCitationLastInlineArea(LayoutManager parentLM) { + TextArea text = null; + resolved = false; + if (!getPSLM().associateLayoutManagerID(fobj.getRefId())) { + text = new UnresolvedPageNumber(fobj.getRefId(), font, UnresolvedPageNumber.LAST); + getPSLM().addUnresolvedArea(fobj.getRefId(), (Resolvable)text); + String str = "MMM"; // reserve three spaces for page number + int width = getStringWidth(str); + text.setIPD(width); + } else { + PageViewport page = getPSLM().getLastPVWithID(fobj.getRefId()); + String str = page.getPageNumberString(); + // get page string from parent, build area + text = new TextArea(); + int width = getStringWidth(str); + text.addWord(str, 0); + text.setIPD(width); + + resolved = true; + } + + updateTextAreaTraits(text); + + return text; + } +} diff --git a/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java index 79c2d487d..729e9c939 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java @@ -37,10 +37,11 @@ import org.apache.fop.layoutmgr.TraitSetter; public class PageNumberCitationLayoutManager extends LeafNodeLayoutManager { private PageNumberCitation fobj; - private Font font; + /** Font for the page-number-citation */ + protected Font font; - // whether the page referred to by the citation has been resolved yet - private boolean resolved = false; + /** Indicates whether the page referred to by the citation has been resolved yet */ + protected boolean resolved = false; /** * Constructor @@ -97,40 +98,45 @@ public class PageNumberCitationLayoutManager extends LeafNodeLayoutManager { */ private InlineArea getPageNumberCitationInlineArea(LayoutManager parentLM) { PageViewport page = getPSLM().getFirstPVWithID(fobj.getRefId()); - TextArea inline = null; + TextArea text = null; if (page != null) { String str = page.getPageNumberString(); // get page string from parent, build area - TextArea text = new TextArea(); - inline = text; + text = new TextArea(); int width = getStringWidth(str); text.addWord(str, 0); - inline.setIPD(width); - + text.setIPD(width); resolved = true; } else { resolved = false; - inline = new UnresolvedPageNumber(fobj.getRefId(), font); + text = new UnresolvedPageNumber(fobj.getRefId(), font); String str = "MMM"; // reserve three spaces for page number int width = getStringWidth(str); - inline.setIPD(width); - + text.setIPD(width); } - TraitSetter.setProducerID(inline, fobj.getId()); - inline.setBPD(font.getAscender() - font.getDescender()); - inline.setBaselineOffset(font.getAscender()); - TraitSetter.addFontTraits(inline, font); - inline.addTrait(Trait.COLOR, fobj.getColor()); - TraitSetter.addTextDecoration(inline, fobj.getTextDecoration()); + updateTextAreaTraits(text); - return inline; + return text; + } + + /** + * Updates the traits for the generated text area. + * @param text the text area + */ + protected void updateTextAreaTraits(TextArea text) { + TraitSetter.setProducerID(text, fobj.getId()); + text.setBPD(font.getAscender() - font.getDescender()); + text.setBaselineOffset(font.getAscender()); + TraitSetter.addFontTraits(text, font); + text.addTrait(Trait.COLOR, fobj.getColor()); + TraitSetter.addTextDecoration(text, fobj.getTextDecoration()); } /** * @param str string to be measured * @return width (in millipoints ??) of the string */ - private int getStringWidth(String str) { + protected int getStringWidth(String str) { int width = 0; for (int count = 0; count < str.length(); count++) { width += font.getCharWidth(str.charAt(count)); diff --git a/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java index e23639e0d..5704ae99d 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java @@ -207,6 +207,8 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager curBlockArea = null; resetSpaces(); + + getPSLM().notifyEndOfLayout(((ListBlock)getFObj()).getId()); } /** diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java index 23ba4dd52..d894a0aeb 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java @@ -171,6 +171,8 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager { flush(); curBlockArea = null; + + getPSLM().notifyEndOfLayout(((AbstractListItemPart)getFObj()).getId()); } /** diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java index d9bbd18f6..7f3794bb6 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java @@ -535,6 +535,8 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager curBlockArea = null; resetSpaces(); + + getPSLM().notifyEndOfLayout(((ListItem)getFObj()).getId()); } /** diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java index 8ec1b8e16..61d2d3701 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java @@ -252,6 +252,8 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager //Space resolution SpaceResolver.resolveElementList(returnList); + getPSLM().notifyEndOfLayout(((TableCell)getFObj()).getId()); + setFinished(true); return returnList; } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java index 83ac2a937..a50cf1317 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java @@ -20,6 +20,7 @@ package org.apache.fop.layoutmgr.table; import org.apache.fop.datatypes.Length; import org.apache.fop.fo.flow.Table; +import org.apache.fop.fo.flow.TableFObj; import org.apache.fop.fo.flow.TableColumn; import org.apache.fop.fo.properties.TableColLength; import org.apache.fop.layoutmgr.BlockLevelLayoutManager; @@ -376,6 +377,8 @@ public class TableLayoutManager extends BlockStackingLayoutManager resetSpaces(); curBlockArea = null; + + getPSLM().notifyEndOfLayout(((Table)getFObj()).getId()); } /** diff --git a/status.xml b/status.xml index 65e38f051..329c808da 100644 --- a/status.xml +++ b/status.xml @@ -27,6 +27,10 @@ + + Initial support for page-number-citation-last (XSL 1.1). Works without problems + only for page-sequence so far. + diff --git a/test/layoutengine/disabled-testcases.xml b/test/layoutengine/disabled-testcases.xml index 84f8bc5cd..03fd4e64c 100644 --- a/test/layoutengine/disabled-testcases.xml +++ b/test/layoutengine/disabled-testcases.xml @@ -230,6 +230,11 @@ page-number-citation_forward-ref.xml Forward references are not properly adjusted when they are resolved. + + page-number-citation-last: FOs spanning multiple pages are not properly handled. + page-number-citation-last_basic.xml + Resolution of forward references does not wait until an FO is fully finished when an FO spans multiple pages. + IDs are not working on all FO elements page-number-citation_complex_1.xml diff --git a/test/layoutengine/standard-testcases/page-number-citation-last_basic.xml b/test/layoutengine/standard-testcases/page-number-citation-last_basic.xml new file mode 100644 index 000000000..b038aae03 --- /dev/null +++ b/test/layoutengine/standard-testcases/page-number-citation-last_basic.xml @@ -0,0 +1,92 @@ + + + + + +

+ This test checks fo:page-number-citation-last. +

+
+ + + + + + + + + + page: of + bof3's last area is on page + test + test + test + test + test + test + test + + page: + bof3's last area is on page + page eof1: of + page eof2: of + + + + + + page: of + bof3's last area is on page + page: + page: + page eof1: of + page eof2: of + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/layoutengine/standard-testcases/page-number-citation-last_complex.xml b/test/layoutengine/standard-testcases/page-number-citation-last_complex.xml new file mode 100644 index 000000000..39cf3b3c3 --- /dev/null +++ b/test/layoutengine/standard-testcases/page-number-citation-last_complex.xml @@ -0,0 +1,113 @@ + + + + + +

+ This test checks page-number-citations with all combinations of + definition-level and block-level IDs. +

+

+ TODO: + Test table-and-caption and table-caption once implemented. +

+
+ + + + + + + + + + block1 + + + + • + + + here is text in the list item body + + + + + + + + + header + + + + + + + footer + + + + + + + body-content + + + + + + block-container-content + + + + + + page-sequence= + block= + list= + item= + item-label= + item-body= + table= + table-header= + table-footer= + table-body= + table-row= + table-cell= + block-container= + + + + + + + + + + + + + + + + +
diff --git a/test/layoutengine/standard-testcases/page-number-citation-last_page-sequence.xml b/test/layoutengine/standard-testcases/page-number-citation-last_page-sequence.xml new file mode 100644 index 000000000..51fc27f57 --- /dev/null +++ b/test/layoutengine/standard-testcases/page-number-citation-last_page-sequence.xml @@ -0,0 +1,140 @@ + + + + + +

+ This test checks fo:page-number-citation-last associated to a page-sequence id. +

+
+ + + + + + + + + + + + + + + + + + + + + page of + + + + box0 + + + box1 + + + box2 + + + box3 + + + box4 + + + box5 + + + box6 + + + box7 + + + box8 + + + box9 + + + box10 + + + + + + + page of + + + + box1 + + + box2 + + + box3 + + + box4 + + + box5 + + + box6 + + + box7 + + + box8 + + + box9 + + + box10 + + + box11 + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/layoutengine/standard-testcases/page-position_last_1.xml b/test/layoutengine/standard-testcases/page-position_last_1.xml index bb83c2808..793ff851d 100644 --- a/test/layoutengine/standard-testcases/page-position_last_1.xml +++ b/test/layoutengine/standard-testcases/page-position_last_1.xml @@ -41,7 +41,7 @@ - page of + page of @@ -82,7 +82,7 @@ - page of + page of -- 2.39.5