From 744fc68524387a0a685e0983fec783a8387ea095 Mon Sep 17 00:00:00 2001 From: Keiron Liddle Date: Wed, 10 Jan 2001 23:56:20 +0000 Subject: [PATCH] adds footnote support this adds footnotes as they appear and adjusts main area accordingly multi column support still pending Code changes sponsored by Dresdner Bank, Germany git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@193962 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/fo/StandardElementMapping.java | 2 + src/org/apache/fop/fo/flow/Block.java | 14 +- src/org/apache/fop/fo/flow/Flow.java | 14 +- src/org/apache/fop/fo/flow/Footnote.java | 162 ++++++++++++++++++ src/org/apache/fop/fo/flow/FootnoteBody.java | 131 ++++++++++++++ .../fop/fo/pagination/PageSequence.java | 7 +- src/org/apache/fop/layout/BlockArea.java | 22 +++ .../apache/fop/layout/BodyAreaContainer.java | 61 ++++++- src/org/apache/fop/layout/Page.java | 29 ++++ 9 files changed, 434 insertions(+), 8 deletions(-) create mode 100644 src/org/apache/fop/fo/flow/Footnote.java create mode 100644 src/org/apache/fop/fo/flow/FootnoteBody.java diff --git a/src/org/apache/fop/fo/StandardElementMapping.java b/src/org/apache/fop/fo/StandardElementMapping.java index 0aade4fff..ce5cc4eff 100644 --- a/src/org/apache/fop/fo/StandardElementMapping.java +++ b/src/org/apache/fop/fo/StandardElementMapping.java @@ -108,5 +108,7 @@ public class StandardElementMapping implements ElementMapping { builder.addMapping(uri, "instream-foreign-object", InstreamForeignObject.maker()); builder.addMapping(uri, "leader", Leader.maker()); builder.addMapping(uri, "character", org.apache.fop.fo.flow.Character.maker()); + builder.addMapping(uri, "footnote", Footnote.maker()); + builder.addMapping(uri, "footnote-body", FootnoteBody.maker()); } } diff --git a/src/org/apache/fop/fo/flow/Block.java b/src/org/apache/fop/fo/flow/Block.java index 6b261cc73..b4c10d109 100644 --- a/src/org/apache/fop/fo/flow/Block.java +++ b/src/org/apache/fop/fo/flow/Block.java @@ -259,7 +259,8 @@ public class Block extends FObjMixed { startIndent += bodyIndent + distanceBetweenStarts; } - area.getIDReferences().createID(id); + if(area.getIDReferences() != null) + area.getIDReferences().createID(id); this.marker = 0; @@ -286,6 +287,10 @@ public class Block extends FObjMixed { if (((FOText) fo).willCreateArea()) { fo.setWidows(blockWidows); break; + } else { + children.removeElementAt(i); + numChildren = this.children.size(); + i--; } } else { fo.setWidows(blockWidows); @@ -293,7 +298,7 @@ public class Block extends FObjMixed { } } - for (int i = numChildren - 1; i > 0; i--) { + for (int i = numChildren - 1; i >= 0; i--) { FONode fo = (FONode) children.elementAt(i); if (fo instanceof FOText) { if (((FOText) fo).willCreateArea()) { @@ -315,10 +320,11 @@ public class Block extends FObjMixed { this.textIndent = 0; } - if (marker == 0) { + if (marker == 0 && area.getIDReferences() != null) { area.getIDReferences().configureID(id, area); } + int spaceLeft = area.spaceLeft(); this.blockArea = new BlockArea(fs, area.getAllocationWidth(), area.spaceLeft(), startIndent, endIndent, textIndent, align, alignLast, lineHeight); @@ -367,6 +373,7 @@ public class Block extends FObjMixed { if ((i != 0)) { status = new Status(Status.AREA_FULL_SOME); area.addChild(blockArea); + area.setMaxHeight(area.getMaxHeight() - spaceLeft + blockArea.getMaxHeight()); area.increaseHeight(blockArea.getHeight()); area.setAbsoluteHeight( blockArea.getAbsoluteHeight()); @@ -382,6 +389,7 @@ public class Block extends FObjMixed { //blockArea.end(); area.addChild(blockArea); + area.setMaxHeight(area.getMaxHeight() - spaceLeft + blockArea.getMaxHeight()); area.increaseHeight(blockArea.getHeight()); area.setAbsoluteHeight(blockArea.getAbsoluteHeight()); anythingLaidOut = true; diff --git a/src/org/apache/fop/fo/flow/Flow.java b/src/org/apache/fop/fo/flow/Flow.java index 91b69503b..8b86bfef7 100644 --- a/src/org/apache/fop/fo/flow/Flow.java +++ b/src/org/apache/fop/fo/flow/Flow.java @@ -148,9 +148,10 @@ public class Flow extends FObj { // flow is *always* laid out into a BodyAreaContainer BodyAreaContainer bac = (BodyAreaContainer)area; - + boolean prevChildMustKeepWithNext = false; - + Vector pageMarker = this.getMarkerSnapshot(new Vector()); + int numChildren = this.children.size(); for (int i = this.marker; i < numChildren; i++) { FObj fo = (FObj) children.elementAt(i); @@ -177,6 +178,15 @@ public class Flow extends FObj { } _status = fo.layout(currentArea); + +/* if((_status.isPageBreak() || i == numChildren - 1) && bac.needsFootnoteAdjusting()) { + bac.adjustFootnoteArea(); + this.rollback(pageMarker); + i = this.marker - 1; + Area mainReferenceArea = bac.getMainReferenceArea(); + // remove areas + continue; + }*/ if (_status.isIncomplete()) { if ((prevChildMustKeepWithNext) && (_status.laidOutNone())) { this.marker = i - 1; diff --git a/src/org/apache/fop/fo/flow/Footnote.java b/src/org/apache/fop/fo/flow/Footnote.java new file mode 100644 index 000000000..76da2d0a5 --- /dev/null +++ b/src/org/apache/fop/fo/flow/Footnote.java @@ -0,0 +1,162 @@ +/*-- $Id$ -- + + ============================================================================ + The Apache Software License, Version 1.1 + ============================================================================ + + Copyright (C) 1999 The Apache Software Foundation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modifica- + tion, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The end-user documentation included with the redistribution, if any, must + include the following acknowledgment: "This product includes software + developed by the Apache Software Foundation (http://www.apache.org/)." + Alternately, this acknowledgment may appear in the software itself, if + and wherever such third-party acknowledgments normally appear. + + 4. The names "FOP" and "Apache Software Foundation" must not be used to + endorse or promote products derived from this software without prior + written permission. For written permission, please contact + apache@apache.org. + + 5. Products derived from this software may not be called "Apache", nor may + "Apache" appear in their name, without prior written permission of the + Apache Software Foundation. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + This software consists of voluntary contributions made by many individuals + on behalf of the Apache Software Foundation and was originally created by + James Tauber . For more information on the Apache + Software Foundation, please see . + + */ + +package org.apache.fop.fo.flow; + +// FOP +import org.apache.fop.fo.*; +import org.apache.fop.layout.*; +import org.apache.fop.apps.FOPException; +import org.apache.fop.fo.properties.*; +import org.apache.fop.messaging.*; + +// Java +import java.util.Enumeration; +import java.util.Vector; + +public class Footnote extends FObj { + + public static class Maker extends FObj.Maker { + public FObj make(FObj parent, PropertyList propertyList) + throws FOPException { + return new Footnote(parent, propertyList); + } + } + + public static FObj.Maker maker() { + return new Footnote.Maker(); + } + + public Footnote(FObj parent, PropertyList propertyList) + throws FOPException { + super(parent, propertyList); + this.name = "fo:footnote"; + } + + public Status layout(Area area) throws FOPException { + FONode inline = null; + FONode fbody = null; + if(this.marker == START) { + this.marker = 0; + } + int numChildren = this.children.size(); + for (int i = this.marker; i < numChildren; i++) { + FONode fo = (FONode) children.elementAt(i); + if(fo instanceof Inline) { + inline = fo; + Status status = fo.layout(area); + if(status.isIncomplete()) { + return status; + } + } else if(inline != null && fo instanceof FootnoteBody) { + // add footnote to current page or next if it can't fit + fbody = fo; + if(area instanceof BlockArea) { + ((BlockArea)area).addFootnote((FootnoteBody)fbody); + } else { + Page page = area.getPage(); + layoutFootnote(page, (FootnoteBody)fbody, area); + } + } + } + if(fbody == null) { + MessageHandler.errorln("WARNING: no footnote-body in footnote"); + } + if (area instanceof BlockArea) { + } + return new Status(Status.OK); + } + + public static boolean layoutFootnote(Page p, FootnoteBody fb, Area area) + { + try { + BodyAreaContainer bac = p.getBody(); + AreaContainer footArea = bac.getFootnoteReferenceArea(); + int basePos = footArea.getCurrentYPosition() - footArea.getHeight(); + int oldHeight = footArea.getHeight(); + if(area != null) { + footArea.setMaxHeight(area.getMaxHeight() - area.getHeight() + footArea.getHeight()); + } else { + footArea.setMaxHeight(bac.getMaxHeight() + footArea.getHeight()); + } + Status status = fb.layout(footArea); + if(status.isIncomplete()) { + // add as a pending footnote + return false; + } else { + if(area != null) { + area.setMaxHeight(area.getMaxHeight() - footArea.getHeight()); + } + //bac.setMaxHeight(bac.getMaxHeight() - footArea.getHeight() + oldHeight); + if(bac.getFootnoteState() == 0) { + Area ar = bac.getMainReferenceArea(); + decreaseMaxHeight(ar, footArea.getHeight() - oldHeight); + footArea.setYPosition(basePos + footArea.getHeight()); + } + } + } catch(FOPException fope) { + return false; + } + return true; + } + + protected static void decreaseMaxHeight(Area ar, int change) { + ar.setMaxHeight(ar.getMaxHeight() - change); + Vector childs = ar.getChildren(); + for(Enumeration en = childs.elements(); en.hasMoreElements(); ) { + Object obj = en.nextElement(); + if(obj instanceof Area) { + Area childArea = (Area)obj; + decreaseMaxHeight(childArea, change); + } + } + } +} diff --git a/src/org/apache/fop/fo/flow/FootnoteBody.java b/src/org/apache/fop/fo/flow/FootnoteBody.java new file mode 100644 index 000000000..91f6eb8b0 --- /dev/null +++ b/src/org/apache/fop/fo/flow/FootnoteBody.java @@ -0,0 +1,131 @@ +/*-- $Id$ -- + + ============================================================================ + The Apache Software License, Version 1.1 + ============================================================================ + + Copyright (C) 1999 The Apache Software Foundation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modifica- + tion, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The end-user documentation included with the redistribution, if any, must + include the following acknowledgment: "This product includes software + developed by the Apache Software Foundation (http://www.apache.org/)." + Alternately, this acknowledgment may appear in the software itself, if + and wherever such third-party acknowledgments normally appear. + + 4. The names "FOP" and "Apache Software Foundation" must not be used to + endorse or promote products derived from this software without prior + written permission. For written permission, please contact + apache@apache.org. + + 5. Products derived from this software may not be called "Apache", nor may + "Apache" appear in their name, without prior written permission of the + Apache Software Foundation. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + This software consists of voluntary contributions made by many individuals + on behalf of the Apache Software Foundation and was originally created by + James Tauber . For more information on the Apache + Software Foundation, please see . + + */ + +package org.apache.fop.fo.flow; + +// FOP +import org.apache.fop.fo.*; +import org.apache.fop.layout.Area; +import org.apache.fop.apps.FOPException; +import org.apache.fop.fo.properties.*; +import org.apache.fop.layout.*; + +// Java +import java.util.Enumeration; + +public class FootnoteBody extends FObj { + FontState fs; + int align; + int alignLast; + int lineHeight; + int startIndent; + int endIndent; + int textIndent; + + public static class Maker extends FObj.Maker { + public FObj make(FObj parent, PropertyList propertyList) + throws FOPException { + return new FootnoteBody(parent, propertyList); + } + } + + public static FObj.Maker maker() { + return new FootnoteBody.Maker(); + } + + public FootnoteBody(FObj parent, PropertyList propertyList) + throws FOPException { + super(parent, propertyList); + this.name = "fo:footnote-body"; + } + + public Status layout(Area area) throws FOPException { + if(this.marker == START) { + this.marker = 0; + } + String fontFamily = + this.properties.get("font-family").getString(); + String fontStyle = + this.properties.get("font-style").getString(); + String fontWeight = + this.properties.get("font-weight").getString(); + int fontSize = + this.properties.get("font-size").getLength().mvalue(); + + FontState fs = new FontState(area.getFontInfo(), fontFamily, + fontStyle, fontWeight, fontSize); + + BlockArea blockArea = new BlockArea(fs, area.getAllocationWidth(), + area.spaceLeft(), startIndent, endIndent, textIndent, + align, alignLast, lineHeight); + blockArea.setPage(area.getPage()); + blockArea.start(); + + blockArea.setAbsoluteHeight(area.getAbsoluteHeight()); + blockArea.setIDReferences(area.getIDReferences()); + + blockArea.setTableCellXOffset(area.getTableCellXOffset()); + + int numChildren = this.children.size(); + for ( int i = this.marker; i < numChildren; i++ ) { + FONode fo = (FONode) children.elementAt(i); + Status status; + if ( (status = fo.layout(blockArea)).isIncomplete() ) { + this.resetMarker(); + return status; + } + } + blockArea.end(); + area.addChild(blockArea); + area.increaseHeight(blockArea.getHeight()); + return new Status(Status.OK); + } +} diff --git a/src/org/apache/fop/fo/pagination/PageSequence.java b/src/org/apache/fop/fo/pagination/PageSequence.java index 8538ed799..060ccc894 100644 --- a/src/org/apache/fop/fo/pagination/PageSequence.java +++ b/src/org/apache/fop/fo/pagination/PageSequence.java @@ -354,7 +354,12 @@ public class PageSequence extends FObj { throw new FOPException("page masters exhausted. Cannot recover."); } - return pageMaster.makePage(areaTree); + Page p = pageMaster.makePage(areaTree); + if(currentPage != null) { + Vector foots = currentPage.getPendingFootnotes(); + p.setPendingFootnotes(foots); + } + return p; } /** diff --git a/src/org/apache/fop/layout/BlockArea.java b/src/org/apache/fop/layout/BlockArea.java index 9f65f5bdc..20e877f9b 100644 --- a/src/org/apache/fop/layout/BlockArea.java +++ b/src/org/apache/fop/layout/BlockArea.java @@ -52,6 +52,9 @@ package org.apache.fop.layout; // FOP import org.apache.fop.render.Renderer; +import org.apache.fop.fo.flow.*; +import org.apache.fop.fo.*; +import org.apache.fop.apps.*; // Java import java.util.Vector; @@ -92,6 +95,8 @@ public class BlockArea extends Area { protected String language; protected String country; + protected Vector pendingFootnotes = null; + public BlockArea(FontState fontState, int allocationWidth, int maxHeight, int startIndent, int endIndent, int textIndent, int align, int alignLastLine, int lineHeight) { @@ -122,6 +127,17 @@ public class BlockArea extends Area { this.increaseHeight(size); this.addDisplaySpace(this.halfLeading); } + // add pending footnotes + if(pendingFootnotes != null) { + for(Enumeration e = pendingFootnotes.elements(); e.hasMoreElements(); ) { + FootnoteBody fb = (FootnoteBody)e.nextElement(); + Page page = getPage(); + if(!Footnote.layoutFootnote(page, fb, this)) { + page.addPendingFootnote(fb); + } + } + pendingFootnotes = null; + } } public int addPageNumberCitation(FontState fontState, float red, @@ -369,4 +385,10 @@ public class BlockArea extends Area { this.hyphenationRemainCharacterCount = hyphenationRemainCharacterCount; } + public void addFootnote(FootnoteBody fb) { + if(pendingFootnotes == null) { + pendingFootnotes = new Vector(); + } + pendingFootnotes.addElement(fb); + } } diff --git a/src/org/apache/fop/layout/BodyAreaContainer.java b/src/org/apache/fop/layout/BodyAreaContainer.java index 798724db8..8362e37d2 100644 --- a/src/org/apache/fop/layout/BodyAreaContainer.java +++ b/src/org/apache/fop/layout/BodyAreaContainer.java @@ -92,7 +92,10 @@ public class BodyAreaContainer extends Area { // the start FO in case of rollback private FObj startFO; private boolean isNewSpanArea; - + + // keeps track of footnote state for multiple layouts + private int footnoteState = 0; + public BodyAreaContainer(FontState fontState, int xPosition, int yPosition, int allocationWidth, int maxHeight, int position, int columnCount, int columnGap) { @@ -374,11 +377,65 @@ public class BodyAreaContainer extends Area { { return isNewSpanArea; } - + public AreaContainer getCurrentColumnArea() { Vector spanAreas = this.mainReferenceArea.getChildren(); SpanArea spanArea = (SpanArea)spanAreas.elementAt(spanAreas.size()-1); return spanArea.getCurrentColumnArea(); } + + public int getFootnoteState() + { + return footnoteState; + } + + public boolean needsFootnoteAdjusting() + { + footnoteYPosition = footnoteReferenceArea.getYPosition(); + switch(footnoteState) { + case 0: + resetHeights(); + if(footnoteReferenceArea.getHeight() > 0 + && mainYPosition + mainReferenceArea.getHeight() > footnoteYPosition) { + return true; + } + case 1: + break; + } + return false; + } + + public void adjustFootnoteArea() + { + footnoteState++; + if(footnoteState == 1) { + mainReferenceArea.setMaxHeight(footnoteReferenceArea.getYPosition() - mainYPosition); + footnoteYPosition = footnoteReferenceArea.getYPosition(); + footnoteReferenceArea.setMaxHeight(footnoteReferenceArea.getHeight()); + + Vector childs = footnoteReferenceArea.getChildren(); + for(Enumeration en = childs.elements(); en.hasMoreElements(); ) { + Object obj = en.nextElement(); + if(obj instanceof Area) { + Area childArea = (Area)obj; + footnoteReferenceArea.removeChild(childArea); + } + } + + getPage().setPendingFootnotes(null); + } + } + + protected static void resetMaxHeight(Area ar, int change) { + ar.setMaxHeight(change); + Vector childs = ar.getChildren(); + for(Enumeration en = childs.elements(); en.hasMoreElements(); ) { + Object obj = en.nextElement(); + if(obj instanceof Area) { + Area childArea = (Area)obj; + resetMaxHeight(childArea, change); + } + } + } } diff --git a/src/org/apache/fop/layout/Page.java b/src/org/apache/fop/layout/Page.java index a53094406..c58ebe115 100644 --- a/src/org/apache/fop/layout/Page.java +++ b/src/org/apache/fop/layout/Page.java @@ -53,6 +53,9 @@ package org.apache.fop.layout; // FOP import org.apache.fop.render.Renderer; +import org.apache.fop.fo.flow.*; +import org.apache.fop.fo.*; +import org.apache.fop.apps.*; // Java import java.util.Vector; @@ -77,6 +80,8 @@ public class Page { private Vector idList = new Vector(); + private Vector footnotes = null; + Page(AreaTree areaTree, int height, int width) { this.areaTree = areaTree; this.height = height; @@ -171,4 +176,28 @@ public class Page { public Vector getIDList(){ return idList; } + + public Vector getPendingFootnotes() { + return footnotes; + } + + public void setPendingFootnotes(Vector v) { + footnotes = v; + if(footnotes != null) { + for(Enumeration e = footnotes.elements(); e.hasMoreElements(); ) { + FootnoteBody fb = (FootnoteBody)e.nextElement(); + if(!Footnote.layoutFootnote(this, fb, null)) { + // footnotes are too large to fit on empty page + } + } + footnotes = null; + } + } + + public void addPendingFootnote(FootnoteBody fb) { + if(footnotes == null) { + footnotes = new Vector(); + } + footnotes.addElement(fb); + } } -- 2.39.5