diff --git a/fop-core/src/main/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java b/fop-core/src/main/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java index 3ba4babb75c..c7a8eb16465 100644 --- a/fop-core/src/main/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java +++ b/fop-core/src/main/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java @@ -29,6 +29,7 @@ import org.apache.fop.accessibility.StructureTreeEventHandler; import org.apache.fop.fo.DelegatingFOEventHandler; import org.apache.fop.fo.FOEventHandler; +import org.apache.fop.fo.FONode; import org.apache.fop.fo.FOText; import org.apache.fop.fo.extensions.ExternalDocument; import org.apache.fop.fo.flow.AbstractRetrieveMarker; @@ -786,6 +787,22 @@ public void run() { super.restoreState(retrieveMarker); } + @Override + public void endRestoreState(RetrieveMarker retrieveMarker) { + boolean isInsideArtifact = false; + FONode obj = retrieveMarker.getParent(); + while (obj != null && !isInsideArtifact) { + if (obj instanceof CommonAccessibilityHolder && isArtifact((CommonAccessibilityHolder)obj)) { + isInsideArtifact = true; + } else { + obj = obj.getParent(); + } + } + if (isInsideArtifact && !converters.isEmpty()) { + converter = converters.pop(); + } + } + @SuppressWarnings("unchecked") private void restoreRetrieveMarkerState(AbstractRetrieveMarker retrieveMarker) { State state = states.get(retrieveMarker); diff --git a/fop-core/src/main/java/org/apache/fop/fo/FOEventHandler.java b/fop-core/src/main/java/org/apache/fop/fo/FOEventHandler.java index 1f1611fb4e2..f71509cd716 100644 --- a/fop-core/src/main/java/org/apache/fop/fo/FOEventHandler.java +++ b/fop-core/src/main/java/org/apache/fop/fo/FOEventHandler.java @@ -571,6 +571,9 @@ public void endRetrieveMarker(RetrieveMarker retrieveMarker) { public void restoreState(RetrieveMarker retrieveMarker) { } + public void endRestoreState(RetrieveMarker retrieveMarker) { + } + /** * Process the start of a retrieve-table-marker. * diff --git a/fop-core/src/main/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java b/fop-core/src/main/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java index f6964911099..e5839fafe40 100644 --- a/fop-core/src/main/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java +++ b/fop-core/src/main/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java @@ -212,6 +212,7 @@ public void bindMarker(Marker marker) { try { restoreFOEventHandlerState(); cloneFromMarker(marker); + endRestoreFOEventHandlerState(); } catch (FOPException exc) { getFOValidationEventProducer().markerCloningFailed(this, marker.getMarkerClassName(), exc, getLocator()); @@ -223,6 +224,8 @@ public void bindMarker(Marker marker) { protected abstract void restoreFOEventHandlerState(); + protected abstract void endRestoreFOEventHandlerState(); + /** * Return the value for the retrieve-class-name * property diff --git a/fop-core/src/main/java/org/apache/fop/fo/flow/RetrieveMarker.java b/fop-core/src/main/java/org/apache/fop/fo/flow/RetrieveMarker.java index 2f2b7e5a404..3c6a7e98a15 100644 --- a/fop-core/src/main/java/org/apache/fop/fo/flow/RetrieveMarker.java +++ b/fop-core/src/main/java/org/apache/fop/fo/flow/RetrieveMarker.java @@ -126,4 +126,8 @@ protected void restoreFOEventHandlerState() { getFOEventHandler().restoreState(this); } + @Override + protected void endRestoreFOEventHandlerState() { + getFOEventHandler().endRestoreState(this); + } } diff --git a/fop-core/src/main/java/org/apache/fop/fo/flow/RetrieveTableMarker.java b/fop-core/src/main/java/org/apache/fop/fo/flow/RetrieveTableMarker.java index 8340736c7c7..ef0e027cdec 100644 --- a/fop-core/src/main/java/org/apache/fop/fo/flow/RetrieveTableMarker.java +++ b/fop-core/src/main/java/org/apache/fop/fo/flow/RetrieveTableMarker.java @@ -158,4 +158,8 @@ protected void restoreFOEventHandlerState() { getFOEventHandler().restoreState(this); } + @Override + protected void endRestoreFOEventHandlerState() { + + } } diff --git a/fop-core/src/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java b/fop-core/src/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java index cf8aaee98c7..5350fb560c7 100644 --- a/fop-core/src/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java @@ -20,10 +20,13 @@ package org.apache.fop.accessibility.fo; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.nio.charset.StandardCharsets; +import java.util.List; import javax.xml.transform.Result; import javax.xml.transform.Source; @@ -34,6 +37,7 @@ import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; @@ -46,15 +50,22 @@ import org.w3c.dom.Document; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; - +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.apache.commons.io.IOUtils; +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDMarkedContent; +import org.apache.pdfbox.text.PDFMarkedContentExtractor; import org.apache.fop.accessibility.StructureTree2SAXEventAdapter; import org.apache.fop.accessibility.StructureTreeEventHandler; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.MimeConstants; import org.apache.fop.fo.FODocumentParser; import org.apache.fop.fo.FODocumentParser.FOEventHandlerFactory; import org.apache.fop.fo.FOEventHandler; @@ -242,6 +253,83 @@ public void testSVGArtifact() throws Exception { + ""); } + @Test + public void testMultipleStaticContentArtifact() throws FOPException, + TransformerException, IOException { + FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); + FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); + foUserAgent.setAccessibility(true); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out); + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); + + String fo = "" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " A\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2\n" + + " B\n" + + " \n" + + " \n" + + " \n" + + ""; + Source src = new StreamSource(new ByteArrayInputStream(fo.getBytes())); + Result res = new SAXResult(fop.getDefaultHandler()); + + try { + transformer.transform(src, res); + } finally { + out.close(); + } + + try (PDDocument pdfDocument = Loader.loadPDF(out.toByteArray())) { + PDFMarkedContentExtractor extractor = new PDFMarkedContentExtractor(); + assertEquals(2, pdfDocument.getPages().getCount()); + extractor.processPage(pdfDocument.getPages().get(0)); + extractor.processPage(pdfDocument.getPages().get(1)); + + List markedContents = extractor.getMarkedContents(); + assertEquals(4, markedContents.size()); + + assertEquals("Artifact", markedContents.get(0).getTag()); + assertEquals("1", markedContents.get(0).getContents().get(0).toString()); + + assertEquals("P", markedContents.get(1).getTag()); + assertEquals("A", markedContents.get(1).getContents().get(0).toString()); + + assertEquals("Artifact", markedContents.get(2).getTag()); + assertEquals("2", markedContents.get(2).getContents().get(0).toString()); + + assertEquals("P", markedContents.get(3).getTag()); + assertEquals("B", markedContents.get(3).getContents().get(0).toString()); + } + } + private void compare(final String fo, String tree) throws Exception { foLoader = new FOLoader("") { public InputStream getFoInputStream() {