From c28cc8e161b799f47000530cdf2779f6f2e7d735 Mon Sep 17 00:00:00 2001 From: Simon Steiner Date: Mon, 2 Jul 2018 14:13:54 +0000 Subject: [PATCH] FOP-2800: IF Links point to current page instead of earlier page git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1834850 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/render/intermediate/IFRenderer.java | 10 ++-- .../extensions/DocumentNavigationHandler.java | 9 +++- .../intermediate/extensions/GoToXYAction.java | 17 ++++++- .../org/apache/fop/pdf/PDFVTTestCase.java | 2 +- .../DocumentNavigationHandlerTestCase.java | 49 +++++++++++++++++++ .../fop-intermediate-format-ng-nav.xsd | 1 + 6 files changed, 80 insertions(+), 8 deletions(-) diff --git a/fop-core/src/main/java/org/apache/fop/render/intermediate/IFRenderer.java b/fop-core/src/main/java/org/apache/fop/render/intermediate/IFRenderer.java index 3ea7fc2cd..aeafc45a9 100644 --- a/fop-core/src/main/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/fop-core/src/main/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -396,7 +396,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { this.documentMetadata = metadata.getMetadata(); } - private GoToXYAction getGoToActionForID(String targetID, int pageIndex) { + private GoToXYAction getGoToActionForID(String targetID, final int pageIndex) { // Already a GoToXY present for this target? If not, create. GoToXYAction action = (GoToXYAction)actionSet.get(targetID); //GoToXYAction action = (GoToXYAction)idGoTos.get(targetID); @@ -407,10 +407,14 @@ public class IFRenderer extends AbstractPathOrientedRenderer { Point position = (Point)idPositions.get(targetID); // can the GoTo already be fully filled in? if (pageIndex >= 0 && position != null) { - action = new GoToXYAction(targetID, pageIndex, position); + action = new GoToXYAction(targetID, pageIndex, position, new GoToXYAction.PageIndexRelative() { + public int getPageIndexRelative() { + return pageIndex - documentHandler.getContext().getPageIndex(); + } + }); } else { // Not complete yet, can't use getPDFGoTo: - action = new GoToXYAction(targetID, pageIndex, null); + action = new GoToXYAction(targetID, pageIndex, null, null); unfinishedGoTos.add(action); } action = (GoToXYAction)actionSet.put(action); diff --git a/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java b/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java index 5221ad04b..c0b78d977 100644 --- a/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java +++ b/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java @@ -119,11 +119,12 @@ public class DocumentNavigationHandler extends DefaultHandler } else { String id = attributes.getValue("id"); int pageIndex = XMLUtil.getAttributeAsInt(attributes, "page-index"); + final int pageIndexRelative = XMLUtil.getAttributeAsInt(attributes, "page-index-relative", 0); final Point location; if (pageIndex < 0) { location = null; } else { - if (hasNavigation() && !inBookmark()) { + if (hasNavigation() && !inBookmark() && pageIndexRelative >= 0) { int currentPageIndex = navHandler.getPageIndex(); if (currentPageIndex >= 0) { pageIndex = currentPageIndex; @@ -135,7 +136,11 @@ public class DocumentNavigationHandler extends DefaultHandler .getAttributeAsInt(attributes, "y"); location = new Point(x, y); } - action = new GoToXYAction(id, pageIndex, location); + action = new GoToXYAction(id, pageIndex, location, new GoToXYAction.PageIndexRelative() { + public int getPageIndexRelative() { + return pageIndexRelative; + } + }); } if (structureTreeElement != null) { action.setStructureTreeElement(structureTreeElement); diff --git a/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/GoToXYAction.java b/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/GoToXYAction.java index 06dc4a5a7..6fdee58da 100644 --- a/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/GoToXYAction.java +++ b/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/GoToXYAction.java @@ -33,6 +33,7 @@ import org.apache.fop.util.XMLUtil; public class GoToXYAction extends AbstractAction implements DocumentNavigationExtensionConstants { private int pageIndex = -1; + private PageIndexRelative pageIndexRelative; private Point targetLocation; /** @@ -40,7 +41,7 @@ public class GoToXYAction extends AbstractAction implements DocumentNavigationEx * @param id the identifier for this action */ public GoToXYAction(String id) { - this(id, -1, null); + this(id, -1, null, null); } /** @@ -51,7 +52,7 @@ public class GoToXYAction extends AbstractAction implements DocumentNavigationEx * @param targetLocation the absolute location on the page (coordinates in millipoints), * or null, if the position isn't known, yet */ - public GoToXYAction(String id, int pageIndex, Point targetLocation) { + public GoToXYAction(String id, int pageIndex, Point targetLocation, PageIndexRelative pageIndexRelative) { setID(id); if (pageIndex < 0 && targetLocation != null) { throw new IllegalArgumentException( @@ -59,6 +60,11 @@ public class GoToXYAction extends AbstractAction implements DocumentNavigationEx } setPageIndex(pageIndex); setTargetLocation(targetLocation); + this.pageIndexRelative = pageIndexRelative; + } + + public interface PageIndexRelative { + int getPageIndexRelative(); } /** @@ -147,6 +153,13 @@ public class GoToXYAction extends AbstractAction implements DocumentNavigationEx atts.addAttribute("", "id", "id", XMLUtil.CDATA, getID()); atts.addAttribute("", "page-index", "page-index", XMLUtil.CDATA, Integer.toString(pageIndex)); + if (pageIndexRelative != null) { + int pageIndexRelativeInt = pageIndexRelative.getPageIndexRelative(); + if (pageIndexRelativeInt < 0) { + atts.addAttribute("", "page-index-relative", "page-index-relative", + XMLUtil.CDATA, Integer.toString(pageIndexRelativeInt)); + } + } atts.addAttribute("", "x", "x", XMLUtil.CDATA, Integer.toString(reportedTargetLocation.x)); atts.addAttribute("", "y", "y", XMLUtil.CDATA, diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFVTTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFVTTestCase.java index 63deaffba..312750f36 100644 --- a/fop-core/src/test/java/org/apache/fop/pdf/PDFVTTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFVTTestCase.java @@ -183,7 +183,7 @@ public class PDFVTTestCase { throw new IOException(name + " not found " + firstObj); } - private String getObj(Collection objs, String x) { + public static String getObj(Collection objs, String x) { for (StringBuilder s : objs) { if (s.toString().contains(x)) { return s.toString(); diff --git a/fop-core/src/test/java/org/apache/fop/render/extensions/DocumentNavigationHandlerTestCase.java b/fop-core/src/test/java/org/apache/fop/render/extensions/DocumentNavigationHandlerTestCase.java index 523da388f..327f31aa5 100644 --- a/fop-core/src/test/java/org/apache/fop/render/extensions/DocumentNavigationHandlerTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/extensions/DocumentNavigationHandlerTestCase.java @@ -19,10 +19,13 @@ package org.apache.fop.render.extensions; import java.awt.Dimension; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -43,6 +46,8 @@ import org.apache.fop.accessibility.StructureTreeElement; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FopFactory; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.pdf.PDFLinearizationTestCase; +import org.apache.fop.pdf.PDFVTTestCase; import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.extensions.AbstractAction; @@ -90,6 +95,50 @@ public class DocumentNavigationHandlerTestCase { Assert.assertEquals(goToXYActions.get(0).getPageIndex(), currentPage); } + @Test + public void testGotoXYPrevousPage() throws SAXException, IFException, IOException { + FOUserAgent ua = FopFactory.newInstance(new File(".").toURI()).newFOUserAgent(); + PDFDocumentHandler documentHandler = new PDFDocumentHandler(new IFContext(ua)); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + documentHandler.setResult(new StreamResult(bos)); + documentHandler.setFontInfo(new FontInfo()); + documentHandler.startDocument(); + + documentHandler.startPage(0, "", "", new Dimension()); + documentHandler.endPage(); + + documentHandler.startPage(1, "", "", new Dimension()); + final List goToXYActions = new ArrayList(); + PDFDocumentNavigationHandler pdfDocumentNavigationHandler = new PDFDocumentNavigationHandler(documentHandler) { + public void addResolvedAction(AbstractAction action) throws IFException { + super.addResolvedAction(action); + goToXYActions.add((GoToXYAction) action); + } + }; + DocumentNavigationHandler navigationHandler = new DocumentNavigationHandler(pdfDocumentNavigationHandler, + new HashMap()); + QName xy = DocumentNavigationExtensionConstants.GOTO_XY; + Attributes attributes = mock(Attributes.class); + when(attributes.getValue("page-index")).thenReturn("0"); + when(attributes.getValue("page-index-relative")).thenReturn("-1"); + when(attributes.getValue("x")).thenReturn("0"); + when(attributes.getValue("y")).thenReturn("0"); + navigationHandler.startElement(xy.getNamespaceURI(), xy.getLocalName(), null, attributes); + navigationHandler.endElement(xy.getNamespaceURI(), xy.getLocalName(), null); + documentHandler.endPage(); + documentHandler.endDocument(); + + Assert.assertEquals(goToXYActions.get(0).getPageIndex(), 0); + + Collection objs = PDFLinearizationTestCase.readObjs( + new ByteArrayInputStream(bos.toByteArray())).values(); + String pages = PDFVTTestCase.getObj(objs, "/Type /Pages"); + String action = PDFVTTestCase.getObj(objs, "/Type /Action"); + String pageRef = action.split("\\[")[1].split(" /XYZ")[0]; + Assert.assertTrue(pageRef.endsWith(" 0 R")); + Assert.assertTrue(pages.contains("/Kids [" + pageRef)); + } + @Test public void testGotoXYUniqueLinks() throws IFException, SAXException { FOUserAgent ua = FopFactory.newInstance(new File(".").toURI()).newFOUserAgent(); diff --git a/fop/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-nav.xsd b/fop/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-nav.xsd index ff6697cdf..49851f302 100644 --- a/fop/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-nav.xsd +++ b/fop/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-nav.xsd @@ -106,6 +106,7 @@ + -- 2.39.5