summaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
authorSimon Steiner <ssteiner@apache.org>2015-06-16 11:46:50 +0000
committerSimon Steiner <ssteiner@apache.org>2015-06-16 11:46:50 +0000
commitde3d77870e5a82489148229014839cb435978c71 (patch)
tree25e0de5d6b56ef73878c3f4517dbcf19c2f0a09a /src/java
parent638c1501b9f607304217d401952d91a6bd4dff1b (diff)
downloadxmlgraphics-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')
-rw-r--r--src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java14
-rw-r--r--src/java/org/apache/fop/apps/FOUserAgent.java9
-rw-r--r--src/java/org/apache/fop/fo/flow/BasicLink.java11
-rw-r--r--src/java/org/apache/fop/pdf/PDFMetadata.java8
-rw-r--r--src/java/org/apache/fop/pdf/PDFProfile.java38
-rw-r--r--src/java/org/apache/fop/pdf/PDFRoot.java5
-rw-r--r--src/java/org/apache/fop/pdf/PDFStructElem.java8
-rw-r--r--src/java/org/apache/fop/pdf/PDFUAMode.java85
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFPainter.java40
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRendererConfig.java2
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRendererOption.java7
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java6
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java2
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java21
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")));