From 20be3fe07bda82ab51d180744cba05ed707d8276 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Tue, 18 Oct 2005 16:06:31 +0000 Subject: [PATCH] Fix for internal forward references in PDF output (basic-link with internal-destination): Implemented by making out-of-order processing possible. The problem will still surface if supportsOutOfOrder() returns false. PDF library now supports the addition of pages in non-consecutive order. This is a backwards-compatible change. The old behaviour and the old method signatures are still in place. PageViewport now carries a page index which doesn't represent the page number but the overall index of the page within the current rendering run. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@326133 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/area/AreaTreeModel.java | 10 ++++- .../org/apache/fop/area/PageViewport.java | 17 +++++++ src/java/org/apache/fop/pdf/PDFFactory.java | 27 +++++++++--- src/java/org/apache/fop/pdf/PDFPage.java | 44 +++++++++++-------- src/java/org/apache/fop/pdf/PDFPages.java | 22 ++++++++-- .../apache/fop/render/pdf/PDFRenderer.java | 39 ++++++++-------- 6 files changed, 112 insertions(+), 47 deletions(-) diff --git a/src/java/org/apache/fop/area/AreaTreeModel.java b/src/java/org/apache/fop/area/AreaTreeModel.java index 34a4d39fa..75783def8 100644 --- a/src/java/org/apache/fop/area/AreaTreeModel.java +++ b/src/java/org/apache/fop/area/AreaTreeModel.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 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. @@ -38,6 +38,7 @@ import org.apache.commons.logging.LogFactory; */ public class AreaTreeModel { private List pageSequenceList = null; + private int currentPageSequenceIndex = -1; private List currentPageSequencePageList; private List offDocumentItems = new java.util.ArrayList(); @@ -57,6 +58,7 @@ public class AreaTreeModel { public void startPageSequence(LineArea title) { currentPageSequencePageList = new java.util.ArrayList(); pageSequenceList.add(currentPageSequencePageList); + currentPageSequenceIndex = pageSequenceList.size() - 1; } /** @@ -65,6 +67,12 @@ public class AreaTreeModel { */ public void addPage(PageViewport page) { currentPageSequencePageList.add(page); + int pageIndex = 0; + for (int i = 0; i < currentPageSequenceIndex; i++) { + pageIndex += ((List)pageSequenceList.get(i)).size(); + } + pageIndex += currentPageSequencePageList.size() - 1; + page.setPageIndex(pageIndex); } /** diff --git a/src/java/org/apache/fop/area/PageViewport.java b/src/java/org/apache/fop/area/PageViewport.java index 046bd4698..2cced4a5f 100644 --- a/src/java/org/apache/fop/area/PageViewport.java +++ b/src/java/org/apache/fop/area/PageViewport.java @@ -48,6 +48,7 @@ public class PageViewport implements Resolvable, Cloneable { private Rectangle2D viewArea; private boolean clip = false; private String pageNumberString = null; + private int pageIndex = -1; //-1 = undetermined private SimplePageMaster spm = null; private boolean blank; @@ -137,6 +138,22 @@ public class PageViewport implements Resolvable, Cloneable { return pageNumberString; } + /** + * Sets the page index of the page in this rendering run. + * @param index the page index (zero-based), -1 if it is undetermined + */ + public void setPageIndex(int index) { + this.pageIndex = index; + } + + /** + * @return the overall page index of the page in this rendering run (zero-based, + * -1 if it is undetermined). + */ + public int getPageIndex() { + return this.pageIndex; + } + /** * Get the key for this page viewport. * This is used so that a serializable key can be used to diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index 28a14e8ef..bacb3251c 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 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. @@ -133,26 +133,43 @@ public class PDFFactory { * PDFDocument later using addObject(). * * @param resources resources object to use - * @param pagewidth width of the page in points - * @param pageheight height of the page in points + * @param pageWidth width of the page in points + * @param pageHeight height of the page in points + * @param pageIndex index of the page (zero-based) * * @return the created /Page object */ public PDFPage makePage(PDFResources resources, - int pagewidth, int pageheight) { + int pageWidth, int pageHeight, int pageIndex) { /* * create a PDFPage with the next object number, the given * resources, contents and dimensions */ PDFPage page = new PDFPage(resources, - pagewidth, pageheight); + pageWidth, pageHeight, pageIndex); getDocument().assignObjectNumber(page); getDocument().getPages().addPage(page); return page; } + /** + * Make a /Page object. The page is assigned an object number immediately + * so references can already be made. The page must be added to the + * PDFDocument later using addObject(). + * + * @param resources resources object to use + * @param pageWidth width of the page in points + * @param pageHeight height of the page in points + * + * @return the created /Page object + */ + public PDFPage makePage(PDFResources resources, + int pageWidth, int pageHeight) { + return makePage(resources, pageWidth, pageHeight, -1); + } + /* ========================= functions ================================= */ /** diff --git a/src/java/org/apache/fop/pdf/PDFPage.java b/src/java/org/apache/fop/pdf/PDFPage.java index 74932403f..bd00cbd2d 100644 --- a/src/java/org/apache/fop/pdf/PDFPage.java +++ b/src/java/org/apache/fop/pdf/PDFPage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 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. @@ -48,6 +48,9 @@ public class PDFPage extends PDFResourceContext { */ protected int pageheight; + /** the page index (zero-based) */ + protected int pageIndex; + /** * Duration to display page */ @@ -59,41 +62,38 @@ public class PDFPage extends PDFResourceContext { protected TransitionDictionary trDictionary = null; /** - * create a /Page object + * Create a /Page object * * @param resources the /Resources object * @param contents the content stream - * @param pagewidth the page's width in points - * @param pageheight the page's height in points + * @param pageWidth the page's width in points + * @param pageHeight the page's height in points + * @param pageIndex the page's zero-based index (or -1 if the page number is auto-determined) */ public PDFPage(PDFResources resources, PDFStream contents, - int pagewidth, int pageheight) { + int pageWidth, int pageHeight, int pageIndex) { /* generic creation of object */ super(resources); /* set fields using parameters */ this.contents = contents; - this.pagewidth = pagewidth; - this.pageheight = pageheight; + this.pagewidth = pageWidth; + this.pageheight = pageHeight; + this.pageIndex = pageIndex; } /** - * create a /Page object + * Create a /Page object * * @param resources the /Resources object - * @param pagewidth the page's width in points - * @param pageheight the page's height in points + * @param pageWidth the page's width in points + * @param pageHeight the page's height in points + * @param pageIndex the page's zero-based index (or -1 if the page number is auto-determined) */ public PDFPage(PDFResources resources, - int pagewidth, int pageheight) { - - /* generic creation of object */ - super(resources); - - /* set fields using parameters */ - this.pagewidth = pagewidth; - this.pageheight = pageheight; + int pageWidth, int pageHeight, int pageIndex) { + this(resources, null, pageWidth, pageHeight, pageIndex); } /** @@ -143,6 +143,14 @@ public class PDFPage extends PDFResourceContext { return this.pageheight; } + /** + * @return the page Index of this page (zero-based), -1 if it the page index should + * automatically be determined. + */ + public int getPageIndex() { + return this.pageIndex; + } + /** * @see org.apache.fop.pdf.PDFObject#toPDFString() */ diff --git a/src/java/org/apache/fop/pdf/PDFPages.java b/src/java/org/apache/fop/pdf/PDFPages.java index aae5c6c90..6ce4830e1 100644 --- a/src/java/org/apache/fop/pdf/PDFPages.java +++ b/src/java/org/apache/fop/pdf/PDFPages.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 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. @@ -72,7 +72,19 @@ public class PDFPages extends PDFObject { * @param page the child page */ public void notifyKidRegistered(PDFPage page) { - this.kids.add(page.referencePDF()); + int idx = page.getPageIndex(); + if (idx >= 0) { + while (idx > this.kids.size() - 1) { + this.kids.add(null); + } + if (this.kids.get(idx) != null) { + throw new IllegalStateException("A page already exists at index " + + idx + " (zero-based)."); + } + this.kids.set(idx, page.referencePDF()); + } else { + this.kids.add(page.referencePDF()); + } } /** @@ -102,7 +114,11 @@ public class PDFPages extends PDFObject { append(this.getCount()). append("\n/Kids ["); for (int i = 0; i < kids.size(); i++) { - sb.append(kids.get(i)).append(" "); + Object kid = kids.get(i); + if (kid == null) { + throw new IllegalStateException("Gap in the kids list!"); + } + sb.append(kid).append(" "); } sb.append("] >>\nendobj\n"); return sb.toString(); diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index ba8b6796e..70beb20fb 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -283,7 +283,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { * @see org.apache.fop.render.Renderer#supportsOutOfOrder() */ public boolean supportsOutOfOrder() { - return false; + //return false; + return true; } /** @@ -402,6 +403,14 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { * @param page the page to prepare */ public void preparePage(PageViewport page) { + setupPage(page); + if (pages == null) { + pages = new java.util.HashMap(); + } + pages.put(page, currentPage); + } + + private void setupPage(PageViewport page) { this.pdfResources = this.pdfDoc.getResources(); Rectangle2D bounds = page.getViewArea(); @@ -409,15 +418,12 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { double h = bounds.getHeight(); currentPage = this.pdfDoc.getFactory().makePage( this.pdfResources, - (int) Math.round(w / 1000), (int) Math.round(h / 1000)); - if (pages == null) { - pages = new java.util.HashMap(); - } - pages.put(page, currentPage); + (int) Math.round(w / 1000), (int) Math.round(h / 1000), + page.getPageIndex()); pageReferences.put(page.getKey(), currentPage.referencePDF()); pvReferences.put(page.getKey(), page); } - + /** * This method creates a pdf stream for the current page * uses it as the contents of a new page. The page is written @@ -428,22 +434,15 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { throws IOException, FOPException { if (pages != null && (currentPage = (PDFPage) pages.get(page)) != null) { + //Retrieve previously prepared page (out-of-line rendering) pages.remove(page); - Rectangle2D bounds = page.getViewArea(); - double h = bounds.getHeight(); - pageHeight = (int) h; } else { - this.pdfResources = this.pdfDoc.getResources(); - Rectangle2D bounds = page.getViewArea(); - double w = bounds.getWidth(); - double h = bounds.getHeight(); - pageHeight = (int) h; - currentPage = this.pdfDoc.getFactory().makePage( - this.pdfResources, - (int) Math.round(w / 1000), (int) Math.round(h / 1000)); - pageReferences.put(page.getKey(), currentPage.referencePDF()); - pvReferences.put(page.getKey(), page); + setupPage(page); } + Rectangle2D bounds = page.getViewArea(); + double h = bounds.getHeight(); + pageHeight = (int) h; + currentStream = this.pdfDoc.getFactory() .makeStream(PDFFilterList.CONTENT_FILTER, false); -- 2.39.5