diff options
author | Simon Steiner <ssteiner@apache.org> | 2015-06-16 11:46:50 +0000 |
---|---|---|
committer | Simon Steiner <ssteiner@apache.org> | 2015-06-16 11:46:50 +0000 |
commit | de3d77870e5a82489148229014839cb435978c71 (patch) | |
tree | 25e0de5d6b56ef73878c3f4517dbcf19c2f0a09a /src/java | |
parent | 638c1501b9f607304217d401952d91a6bd4dff1b (diff) | |
download | xmlgraphics-fop-de3d77870e5a82489148229014839cb435978c71.tar.gz xmlgraphics-fop-de3d77870e5a82489148229014839cb435978c71.zip |
FOP-2488: Support PDF/UA
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1685770 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
14 files changed, 236 insertions, 20 deletions
diff --git a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java index 6b8c048ae..8def8a4d4 100644 --- a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java +++ b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java @@ -33,9 +33,9 @@ import org.apache.fop.accessibility.StructureTreeEventHandler; import org.apache.fop.fo.FOEventHandler; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FOText; +import org.apache.fop.fo.FObj; import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.fo.extensions.InternalElementMapping; -import org.apache.fop.fo.flow.AbstractGraphics; import org.apache.fop.fo.flow.AbstractRetrieveMarker; import org.apache.fop.fo.flow.BasicLink; import org.apache.fop.fo.flow.Block; @@ -384,7 +384,7 @@ class StructureTreeEventTrigger extends FOEventHandler { @Override public void startLink(BasicLink basicLink) { - startElementWithID(basicLink); + startElementWithIDAndAltText(basicLink, basicLink.getAltText()); } @Override @@ -394,13 +394,13 @@ class StructureTreeEventTrigger extends FOEventHandler { @Override public void image(ExternalGraphic eg) { - startElementWithIDAndAltText(eg); + startElementWithIDAndAltText(eg, eg.getAltText()); endElement(eg); } @Override public void startInstreamForeignObject(InstreamForeignObject ifo) { - startElementWithIDAndAltText(ifo); + startElementWithIDAndAltText(ifo, ifo.getAltText()); } @Override @@ -523,12 +523,12 @@ class StructureTreeEventTrigger extends FOEventHandler { node.getParent().getStructureTreeElement())); } - private void startElementWithIDAndAltText(AbstractGraphics node) { + private void startElementWithIDAndAltText(FObj node, String altText) { AttributesImpl attributes = new AttributesImpl(); String localName = node.getLocalName(); - addRole(node, attributes); + addRole((CommonAccessibilityHolder)node, attributes); addAttribute(attributes, ExtensionElementMapping.URI, "alt-text", - ExtensionElementMapping.STANDARD_PREFIX, node.getAltText()); + ExtensionElementMapping.STANDARD_PREFIX, altText); node.setStructureTreeElement( structureTreeEventHandler.startImageNode(localName, attributes, node.getParent().getStructureTreeElement())); diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index 239261b84..dca7def7b 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -106,6 +106,7 @@ public class FOUserAgent { private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster(); private StructureTreeEventHandler structureTreeEventHandler = DummyStructureTreeEventHandler.INSTANCE; + private boolean pdfUAEnabled; /** Producer: Metadata element for the system/software that produces * the document. (Some renderers can store this in the document.) @@ -580,6 +581,14 @@ public class FOUserAgent { return this.eventBroadcaster; } + public boolean isPdfUAEnabled() { + return pdfUAEnabled; + } + + public void setPdfUAEnabled(boolean pdfUAEnabled) { + this.pdfUAEnabled = pdfUAEnabled; + } + private class FOPEventBroadcaster extends DefaultEventBroadcaster { private EventListener rootListener; diff --git a/src/java/org/apache/fop/fo/flow/BasicLink.java b/src/java/org/apache/fop/fo/flow/BasicLink.java index 9a490c58b..3b59659e7 100644 --- a/src/java/org/apache/fop/fo/flow/BasicLink.java +++ b/src/java/org/apache/fop/fo/flow/BasicLink.java @@ -50,6 +50,7 @@ public class BasicLink extends InlineLevel implements StructureTreeElementHolder // private ToBeImplementedProperty indicateDestination; private String internalDestination; private int showDestination; + private String altText; // private ToBeImplementedProperty targetProcessingContext; // private ToBeImplementedProperty targetPresentationContext; // private ToBeImplementedProperty targetStylesheet; @@ -93,6 +94,12 @@ public class BasicLink extends InlineLevel implements StructureTreeElementHolder // slightly stronger than spec "should be specified" getFOValidationEventProducer().missingLinkDestination(this, getName(), locator); } + if (getUserAgent().isAccessibilityEnabled()) { + altText = pList.get(PR_X_ALT_TEXT).getString(); + if (altText.equals("") && getUserAgent().isPdfUAEnabled()) { + getFOValidationEventProducer().altTextMissing(this, getLocalName(), getLocator()); + } + } } /** {@inheritDoc} */ @@ -212,4 +219,8 @@ public class BasicLink extends InlineLevel implements StructureTreeElementHolder public int getNameId() { return FO_BASIC_LINK; } + + public String getAltText() { + return altText; + } } diff --git a/src/java/org/apache/fop/pdf/PDFMetadata.java b/src/java/org/apache/fop/pdf/PDFMetadata.java index 370c0017a..58b164c8d 100644 --- a/src/java/org/apache/fop/pdf/PDFMetadata.java +++ b/src/java/org/apache/fop/pdf/PDFMetadata.java @@ -38,6 +38,8 @@ import org.apache.xmlgraphics.xmp.schemas.pdf.AdobePDFAdapter; import org.apache.xmlgraphics.xmp.schemas.pdf.AdobePDFSchema; import org.apache.xmlgraphics.xmp.schemas.pdf.PDFAAdapter; import org.apache.xmlgraphics.xmp.schemas.pdf.PDFAXMPSchema; +import org.apache.xmlgraphics.xmp.schemas.pdf.PDFUAAdapter; +import org.apache.xmlgraphics.xmp.schemas.pdf.PDFUAXMPSchema; import org.apache.xmlgraphics.xmp.schemas.pdf.PDFVTAdapter; import org.apache.xmlgraphics.xmp.schemas.pdf.PDFVTXMPSchema; import org.apache.xmlgraphics.xmp.schemas.pdf.PDFXAdapter; @@ -161,6 +163,12 @@ public class PDFMetadata extends PDFStream { //Somewhat redundant but some PDF/A checkers issue a warning without this. dc.setFormat("application/pdf"); + PDFUAMode pdfuaMode = pdfDoc.getProfile().getPDFUAMode(); + if (pdfuaMode.isEnabled()) { + PDFUAAdapter pdfua = PDFUAXMPSchema.getAdapter(meta); + pdfua.setPart(pdfuaMode.getPart()); + } + //PDF/A identification PDFAMode pdfaMode = pdfDoc.getProfile().getPDFAMode(); if (pdfaMode.isEnabled()) { diff --git a/src/java/org/apache/fop/pdf/PDFProfile.java b/src/java/org/apache/fop/pdf/PDFProfile.java index 219623842..18140a596 100644 --- a/src/java/org/apache/fop/pdf/PDFProfile.java +++ b/src/java/org/apache/fop/pdf/PDFProfile.java @@ -37,6 +37,8 @@ public class PDFProfile { */ protected PDFAMode pdfAMode = PDFAMode.DISABLED; + protected PDFUAMode pdfUAMode = PDFUAMode.DISABLED; + /** * Indicates the PDF/X mode currently active. Defaults to "no restrictions", i.e. * PDF/X not active. @@ -82,6 +84,10 @@ public class PDFProfile { return this.pdfAMode; } + public PDFUAMode getPDFUAMode() { + return this.pdfUAMode; + } + /** @return true if any PDF/A mode is active */ public boolean isPDFAActive() { return getPDFAMode() != PDFAMode.DISABLED; @@ -99,6 +105,14 @@ public class PDFProfile { validateProfileCombination(); } + public void setPDFUAMode(PDFUAMode mode) { + if (mode == null) { + mode = PDFUAMode.DISABLED; + } + this.pdfUAMode = mode; + validateProfileCombination(); + } + /** @return the PDF/X mode */ public PDFXMode getPDFXMode() { return this.pdfXMode; @@ -150,6 +164,8 @@ public class PDFProfile { sb.append(getPDFAMode()); } else if (isPDFXActive()) { sb.append(getPDFXMode()); + } else if (getPDFUAMode().isEnabled()) { + sb.append(getPDFUAMode()); } else { sb.append(super.toString()); } @@ -234,25 +250,28 @@ public class PDFProfile { * Checks a few things required for tagged PDF. */ public void verifyTaggedPDF() { - if (getPDFAMode().isLevelA()) { + if (getPDFAMode().isLevelA() || getPDFUAMode().isEnabled()) { final String err = "{0} requires the {1} dictionary entry to be set"; + String mode = getPDFAMode().toString(); + if (getPDFUAMode().isEnabled()) { + mode = getPDFUAMode().toString(); + } PDFDictionary markInfo = getDocument().getRoot().getMarkInfo(); if (markInfo == null) { throw new PDFConformanceException(format( - "{0} requires that the accessibility option in the configuration file be enabled", - getPDFAMode())); + "{0} requires that the accessibility option in the configuration file be enabled", mode)); } if (!Boolean.TRUE.equals(markInfo.get("Marked"))) { throw new PDFConformanceException(format(err, - new Object[] {getPDFAMode(), "Marked"})); + new Object[] {mode, "Marked"})); } if (getDocument().getRoot().getStructTreeRoot() == null) { throw new PDFConformanceException(format(err, - new Object[] {getPDFAMode(), "StructTreeRoot"})); + new Object[] {mode, "StructTreeRoot"})); } if (getDocument().getRoot().getLanguage() == null) { throw new PDFConformanceException(format(err, - new Object[] {getPDFAMode(), "Lang"})); + new Object[] {mode, "Lang"})); } } } @@ -264,13 +283,16 @@ public class PDFProfile { /** @return true if all fonts need to be embedded. */ public boolean isFontEmbeddingRequired() { - return isPDFAActive() || isPDFXActive(); + return isPDFAActive() || isPDFXActive() || getPDFUAMode().isEnabled(); } /** Checks if a title may be absent. */ public void verifyTitleAbsent() { + final String err = "{0} requires the title to be set."; + if (getPDFUAMode().isEnabled()) { + throw new PDFConformanceException(format(err, getPDFUAMode())); + } if (isPDFXActive()) { - final String err = "{0} requires the title to be set."; throw new PDFConformanceException(format(err, getPDFXMode())); } } diff --git a/src/java/org/apache/fop/pdf/PDFRoot.java b/src/java/org/apache/fop/pdf/PDFRoot.java index 66e58c5f0..32edc34fc 100644 --- a/src/java/org/apache/fop/pdf/PDFRoot.java +++ b/src/java/org/apache/fop/pdf/PDFRoot.java @@ -82,6 +82,11 @@ public class PDFRoot extends PDFDictionary { /** {@inheritDoc} */ public int output(OutputStream stream) throws IOException { + if (document.getProfile().getPDFUAMode().isEnabled()) { + PDFDictionary d = new PDFDictionary(); + d.put("DisplayDocTitle", true); + put("ViewerPreferences", d); + } getDocument().getProfile().verifyTaggedPDF(); return super.output(stream); } diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java index f9a182ceb..ac755bd4b 100644 --- a/src/java/org/apache/fop/pdf/PDFStructElem.java +++ b/src/java/org/apache/fop/pdf/PDFStructElem.java @@ -243,6 +243,14 @@ public class PDFStructElem extends StructureHierarchyMember return this.kids; } + public int output(OutputStream stream) throws IOException { + if (getDocument().getProfile().getPDFUAMode().isEnabled() + && entries.containsKey("Alt") && "".equals(get("Alt"))) { + put("Alt", "No alternate text specified"); + } + return super.output(stream); + } + /** * Class representing a placeholder for a PDF Structure Element. */ diff --git a/src/java/org/apache/fop/pdf/PDFUAMode.java b/src/java/org/apache/fop/pdf/PDFUAMode.java new file mode 100644 index 000000000..5f17aa392 --- /dev/null +++ b/src/java/org/apache/fop/pdf/PDFUAMode.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.pdf; + +/** Enum class for PDF/UA modes. */ +public enum PDFUAMode { + + /** PDF/UA disabled. */ + DISABLED("PDF/UA disabled"), + /** PDF/UA-1 enabled. */ + PDFUA_1(1); + + private final String name; + + private final int part; + + /** + * Constructor to add a new named item. + * @param name Name of the item. + */ + private PDFUAMode(String name) { + this.name = name; + this.part = 0; + } + + private PDFUAMode(int part) { + this.name = "PDF/UA-" + part; + this.part = part; + } + + /** @return the name of the enum */ + public String getName() { + return this.name; + } + + public int getPart() { + return part; + } + + /** + * Returns {@code true} if this enum corresponds to one of the available PDF/A modes. + * + * @return {@code true} if this is not DISABLED + */ + public boolean isEnabled() { + return this != DISABLED; + } + + /** + * Returns the mode enum object given a String. + * @param s the string + * @return the PDFAMode enum object (DISABLED will be returned if no match is found) + */ + public static PDFUAMode getValueOf(String s) { + for (PDFUAMode mode : values()) { + if (mode.name.equalsIgnoreCase(s)) { + return mode; + } + } + return DISABLED; + } + + /** {@inheritDoc} */ + public String toString() { + return name; + } + +} diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index 998dc3ade..6bbb2fff5 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -44,6 +44,9 @@ import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.LazyFont; import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; +import org.apache.fop.pdf.PDFArray; +import org.apache.fop.pdf.PDFDictionary; +import org.apache.fop.pdf.PDFName; import org.apache.fop.pdf.PDFNumber; import org.apache.fop.pdf.PDFStructElem; import org.apache.fop.pdf.PDFTextUtil; @@ -173,6 +176,7 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> { placeImage(rect, xobject); } } else { + addStructTreeBBox(rect); drawImageUsingURI(uri, rect); if (!getDocumentHandler().getPDFDocument().isLinearizationEnabled()) { flushPDFDoc(); @@ -180,6 +184,20 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> { } } + private void addStructTreeBBox(Rectangle rect) { + if (accessEnabled && getDocumentHandler().getPDFDocument().getProfile().getPDFUAMode().isEnabled()) { + PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement(); + PDFDictionary d = new PDFDictionary(); + int x = rect.x / 1000; + int y = rect.y / 1000; + int w = rect.width / 1000; + int h = rect.height / 1000; + d.put("BBox", new PDFArray(x, y, w, h)); + d.put("O", new PDFName("Layout")); + structElem.put("A", d); + } + } + @Override protected void drawImageUsingURI(String uri, Rectangle rect) { ImageManager manager = getUserAgent().getImageManager(); @@ -263,6 +281,7 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> { if (accessEnabled) { PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement(); prepareImageMCID(structElem); + addStructTreeBBox(rect); } drawImageUsingDocument(doc, rect); if (!getDocumentHandler().getPDFDocument().isLinearizationEnabled()) { @@ -315,6 +334,9 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> { } if (rect.width != 0 && rect.height != 0) { generator.endTextObject(); + if (accessEnabled && getUserAgent().isPdfUAEnabled()) { + generator.beginMarkedContentSequence(null, 0, null); + } if (fill != null) { if (fill instanceof Color) { generator.updateColor((Color)fill, true, null); @@ -336,6 +358,9 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> { }*/ sb.append('\n'); generator.add(sb.toString()); + if (accessEnabled && getUserAgent().isPdfUAEnabled()) { + generator.endMarkedContentSequence(); + } } } @@ -345,23 +370,32 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> { BorderProps left, BorderProps right, Color innerBackgroundColor) throws IFException { if (top != null || bottom != null || left != null || right != null) { generator.endTextObject(); + if (accessEnabled && getUserAgent().isPdfUAEnabled()) { + generator.beginMarkedContentSequence(null, 0, null); + } this.borderPainter.drawBorders(rect, top, bottom, left, right, innerBackgroundColor); + if (accessEnabled && getUserAgent().isPdfUAEnabled()) { + generator.endMarkedContentSequence(); + } } } - - - /** {@inheritDoc} */ @Override public void drawLine(Point start, Point end, int width, Color color, RuleStyle style) throws IFException { generator.endTextObject(); + if (accessEnabled && getUserAgent().isPdfUAEnabled()) { + generator.beginMarkedContentSequence(null, 0, null); + } try { this.graphicsPainter.drawLine(start, end, width, color, style); } catch (IOException ioe) { throw new IFException("Cannot draw line", ioe); } + if (accessEnabled && getUserAgent().isPdfUAEnabled()) { + generator.endMarkedContentSequence(); + } } private Typeface getTypeface(String fontName) { diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java index bbfb8a9b3..5e7447888 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java @@ -60,6 +60,7 @@ import static org.apache.fop.render.pdf.PDFRendererOption.LINEARIZATION; import static org.apache.fop.render.pdf.PDFRendererOption.MERGE_FONTS; import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE; +import static org.apache.fop.render.pdf.PDFRendererOption.PDF_UA_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_VT_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.VERSION; @@ -134,6 +135,7 @@ public final class PDFRendererConfig implements RendererConfig { try { buildFilterMapFromConfiguration(cfg); parseAndPut(PDF_A_MODE, cfg); + parseAndPut(PDF_UA_MODE, cfg); parseAndPut(PDF_X_MODE, cfg); parseAndPut(PDF_VT_MODE, cfg); configureEncryptionParams(cfg, userAgent, strict); diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererOption.java b/src/java/org/apache/fop/render/pdf/PDFRendererOption.java index 8874f566d..422a5d0ac 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererOption.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererOption.java @@ -24,6 +24,7 @@ import java.net.URISyntaxException; import org.apache.fop.apps.io.InternalResourceResolver; import org.apache.fop.pdf.PDFAMode; +import org.apache.fop.pdf.PDFUAMode; import org.apache.fop.pdf.PDFVTMode; import org.apache.fop.pdf.PDFXMode; import org.apache.fop.pdf.Version; @@ -43,6 +44,12 @@ public enum PDFRendererOption implements RendererConfigOption { return PDFAMode.getValueOf(value); } }, + PDF_UA_MODE("pdf-ua-mode", PDFUAMode.DISABLED) { + @Override + PDFUAMode deserialize(String value) { + return PDFUAMode.getValueOf(value); + } + }, /** Rendering Options key for the PDF/X mode, default: {@link PDFXMode#DISABLED} */ PDF_X_MODE("pdf-x-mode", PDFXMode.DISABLED) { @Override diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java b/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java index e4cf2480b..54d236db8 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java @@ -26,6 +26,7 @@ import java.util.Map; import org.apache.fop.pdf.PDFAMode; import org.apache.fop.pdf.PDFEncryptionParams; +import org.apache.fop.pdf.PDFUAMode; import org.apache.fop.pdf.PDFVTMode; import org.apache.fop.pdf.PDFXMode; import org.apache.fop.pdf.Version; @@ -36,6 +37,7 @@ import static org.apache.fop.render.pdf.PDFRendererOption.LINEARIZATION; import static org.apache.fop.render.pdf.PDFRendererOption.MERGE_FONTS; import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE; +import static org.apache.fop.render.pdf.PDFRendererOption.PDF_UA_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_VT_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.VERSION; @@ -105,6 +107,10 @@ public final class PDFRendererOptionsConfig { return (PDFAMode) properties.get(PDF_A_MODE); } + public PDFUAMode getPDFUAMode() { + return (PDFUAMode) properties.get(PDF_UA_MODE); + } + public PDFXMode getPDFXMode() { return (PDFXMode) properties.get(PDF_X_MODE); } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java index df6f26c65..18a804b5d 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java @@ -164,6 +164,8 @@ class PDFRenderingUtil { private void updatePDFProfiles() { pdfDoc.getProfile().setPDFAMode(rendererConfig.getPDFAMode()); + pdfDoc.getProfile().setPDFUAMode(rendererConfig.getPDFUAMode()); + userAgent.setPdfUAEnabled(pdfDoc.getProfile().getPDFUAMode().isEnabled()); pdfDoc.getProfile().setPDFXMode(rendererConfig.getPDFXMode()); pdfDoc.getProfile().setPDFVTMode(rendererConfig.getPDFVTMode()); } diff --git a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java index b00c60a9b..790f97468 100644 --- a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java +++ b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java @@ -91,7 +91,7 @@ public class PDFStructureTreeBuilder implements StructureTreeEventHandler { addBuilder("list-item-body", StandardStructureTypes.List.LBODY); addBuilder("list-item-label", StandardStructureTypes.List.LBL); // Dynamic Effects: Link and Multi Formatting Objects - addBuilder("basic-link", StandardStructureTypes.InlineLevelStructure.LINK); + addBuilder("basic-link", new LinkBuilder()); // Out-of-Line Formatting Objects addBuilder("float", StandardStructureTypes.Grouping.DIV); addBuilder("footnote", StandardStructureTypes.InlineLevelStructure.NOTE); @@ -247,6 +247,22 @@ public class PDFStructureTreeBuilder implements StructureTreeEventHandler { } + private static class LinkBuilder extends DefaultStructureElementBuilder { + LinkBuilder() { + super(StandardStructureTypes.InlineLevelStructure.LINK); + } + + @Override + protected void setAttributes(PDFStructElem structElem, Attributes attributes) { + super.setAttributes(structElem, attributes); + String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text"); + if (altTextNode == null) { + altTextNode = "No alternate text specified"; + } + structElem.put("Alt", altTextNode); + } + } + private static class TableBuilder extends DefaultStructureElementBuilder { TableBuilder() { @@ -391,7 +407,8 @@ public class PDFStructureTreeBuilder implements StructureTreeEventHandler { } private boolean isPDFA1Safe(String name) { - return !(pdfFactory.getDocument().getProfile().getPDFAMode().isPart1() + return !((pdfFactory.getDocument().getProfile().getPDFAMode().isPart1() + || pdfFactory.getDocument().getProfile().getPDFUAMode().isEnabled()) && (name.equals("table-body") || name.equals("table-header") || name.equals("table-footer"))); |