aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Steiner <ssteiner@apache.org>2024-12-04 16:32:26 +0000
committerSimon Steiner <ssteiner@apache.org>2024-12-04 16:32:26 +0000
commitfd084368f8c81c6a6b5aa4e94d443f4f0ad6e5ad (patch)
tree273d29aa28468a9bbcf9945a715848a85a015fcf
parent2f1858567a8d68bd9c09eb33955d2cbae2aa03ac (diff)
downloadxmlgraphics-fop-fd084368f8c81c6a6b5aa4e94d443f4f0ad6e5ad.tar.gz
xmlgraphics-fop-fd084368f8c81c6a6b5aa4e94d443f4f0ad6e5ad.zip
FOP-3224: Add alt text to link dictionary
-rw-r--r--fop-core/src/main/java/org/apache/fop/area/Trait.java10
-rw-r--r--fop-core/src/main/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java2
-rw-r--r--fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java12
-rw-r--r--fop-core/src/main/java/org/apache/fop/pdf/PDFLink.java14
-rw-r--r--fop-core/src/main/java/org/apache/fop/pdf/PDFUri.java8
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/intermediate/IFRenderer.java2
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java3
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/URIAction.java10
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java2
-rw-r--r--fop-core/src/test/java/org/apache/fop/pdf/PDFAttachmentTestCase.java6
-rw-r--r--fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java14
-rw-r--r--fop-core/src/test/java/org/apache/fop/pdf/PDFLinkTestCase.java2
-rw-r--r--fop-core/src/test/java/org/apache/fop/render/intermediate/URIActionTestCase.java6
-rw-r--r--fop/test/intermediate/basic-link_alttext.xml47
14 files changed, 112 insertions, 26 deletions
diff --git a/fop-core/src/main/java/org/apache/fop/area/Trait.java b/fop-core/src/main/java/org/apache/fop/area/Trait.java
index 445beedd3..5f846f3b4 100644
--- a/fop-core/src/main/java/org/apache/fop/area/Trait.java
+++ b/fop-core/src/main/java/org/apache/fop/area/Trait.java
@@ -420,6 +420,7 @@ public final class Trait implements Serializable {
private String destination;
private boolean newWindow;
+ private String altText;
/**
* Constructs an ExternalLink object with the given destination
@@ -427,9 +428,10 @@ public final class Trait implements Serializable {
* @param destination target of the link
* @param newWindow true if the target should be opened in a new window
*/
- public ExternalLink(String destination, boolean newWindow) {
+ public ExternalLink(String destination, boolean newWindow, String altText) {
this.destination = destination;
this.newWindow = newWindow;
+ this.altText = altText;
}
/**
@@ -452,7 +454,7 @@ public final class Trait implements Serializable {
"Malformed trait value for Trait.ExternalLink: " + traitValue);
}
}
- return new ExternalLink(dest, newWindow);
+ return new ExternalLink(dest, newWindow, null);
}
/**
@@ -483,6 +485,10 @@ public final class Trait implements Serializable {
sb.append(",dest=").append(this.destination);
return sb.toString();
}
+
+ public String getAltText() {
+ return altText;
+ }
}
/**
diff --git a/fop-core/src/main/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java b/fop-core/src/main/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java
index 3a630f9be..76cda73e3 100644
--- a/fop-core/src/main/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java
+++ b/fop-core/src/main/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java
@@ -81,7 +81,7 @@ public class BasicLinkLayoutManager extends InlineLayoutManager {
boolean newWindow = (fobj.getShowDestination() == Constants.EN_NEW);
if (url.length() > 0) {
area.addTrait(Trait.EXTERNAL_LINK,
- new Trait.ExternalLink(url, newWindow));
+ new Trait.ExternalLink(url, newWindow, fobj.getAltText()));
}
}
}
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java
index 12a6c3e09..16b1e80bc 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java
@@ -556,7 +556,7 @@ public class PDFFactory {
PDFLink link = new PDFLink(rect);
if (linkType == PDFLink.EXTERNAL) {
- link.setAction(getExternalAction(destination, false));
+ link.setAction(getExternalAction(destination, false, null));
} else {
// linkType is internal
String goToReference = getGoToReference(destination, yoffset);
@@ -583,7 +583,7 @@ public class PDFFactory {
* displayed in a new window
* @return the PDFAction thus created or found
*/
- public PDFAction getExternalAction(String target, boolean newWindow) {
+ public PDFAction getExternalAction(String target, boolean newWindow, String altText) {
URI uri = getTargetUri(target);
if (uri != null) {
String scheme = uri.getScheme();
@@ -595,7 +595,7 @@ public class PDFFactory {
scheme = "file";
}
if (scheme == null) {
- return new PDFUri(uri.toASCIIString());
+ return new PDFUri(uri.toASCIIString(), altText);
} else if (scheme.equalsIgnoreCase("embedded-file")) {
return getActionForEmbeddedFile(filename, newWindow);
} else if (scheme.equalsIgnoreCase("file")) {
@@ -619,16 +619,16 @@ public class PDFFactory {
return getGoToPDFAction(filename, dest, page, newWindow);
} else {
if (uri.getQuery() != null || uri.getFragment() != null) {
- return new PDFUri(uri.toASCIIString());
+ return new PDFUri(uri.toASCIIString(), altText);
} else {
return getLaunchAction(filename, newWindow);
}
}
} else {
- return new PDFUri(uri.toASCIIString());
+ return new PDFUri(uri.toASCIIString(), altText);
}
}
- return new PDFUri(target);
+ return new PDFUri(target, altText);
}
private URI getTargetUri(String target) {
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFLink.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFLink.java
index 21e989999..e0426a454 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFLink.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFLink.java
@@ -93,15 +93,21 @@ public class PDFLink extends PDFObject {
f |= 1 << (5 - 1); //NoRotate, bit 5
fFlag = "/F " + f;
}
- String s = "<< /Type /Annot\n" + "/Subtype /Link\n" + "/Rect [ "
+ String dict = "<< /Type /Annot\n" + "/Subtype /Link\n" + "/Rect [ "
+ (ulx) + " " + (uly) + " "
+ (brx) + " " + (bry) + " ]\n" + "/C [ "
+ this.color + " ]\n" + "/Border [ 0 0 0 ]\n" + "/A "
+ this.action.getAction() + "\n" + "/H /I\n"
+ (this.structParent != null
- ? "/StructParent " + this.structParent.toString() + "\n" : "")
- + fFlag + "\n>>";
- return s;
+ ? "/StructParent " + this.structParent.toString() + "\n" : "");
+ if (action instanceof PDFUri) {
+ String altText = ((PDFUri) action).getAltText();
+ if (altText != null && !altText.isEmpty()) {
+ dict += "/Contents " + PDFText.escapeText(altText) + "\n";
+ }
+ }
+ dict += fFlag + "\n>>";
+ return dict;
}
/*
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFUri.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFUri.java
index a4c75ee10..686ab1d84 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFUri.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFUri.java
@@ -25,14 +25,16 @@ package org.apache.fop.pdf;
public class PDFUri extends PDFAction {
private String uri;
+ private String altText;
/**
* create a Uri instance.
*
* @param uri the uri to which the link should point
*/
- public PDFUri(String uri) {
+ public PDFUri(String uri, String altText) {
this.uri = uri;
+ this.altText = altText;
}
/**
@@ -57,4 +59,8 @@ public class PDFUri extends PDFAction {
//TODO Convert this class into a dictionary
return getDictString();
}
+
+ public String getAltText() {
+ return altText;
+ }
}
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 84e4e3a2c..d4a25ad0b 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
@@ -965,7 +965,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
String extDest = extLink.getDestination();
if (extDest != null && extDest.length() > 0) {
linkTraitFound = true;
- action = new URIAction(extDest, extLink.newWindow());
+ action = new URIAction(extDest, extLink.newWindow(), extLink.getAltText());
action = 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 f654ef37e..0abcd8acd 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
@@ -165,8 +165,9 @@ public class DocumentNavigationHandler extends DefaultHandler
String id = attributes.getValue("id");
String gotoURI = attributes.getValue("uri");
String showDestination = attributes.getValue("show-destination");
+ String altText = attributes.getValue("alt-text");
boolean newWindow = "new".equals(showDestination);
- URIAction action = new URIAction(gotoURI, newWindow);
+ URIAction action = new URIAction(gotoURI, newWindow, altText);
if (id != null) {
action.setID(id);
}
diff --git a/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/URIAction.java b/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/URIAction.java
index 774f27b43..9a4960bb9 100644
--- a/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/URIAction.java
+++ b/fop-core/src/main/java/org/apache/fop/render/intermediate/extensions/URIAction.java
@@ -33,18 +33,20 @@ public class URIAction extends AbstractAction implements DocumentNavigationExten
private String uri;
private boolean newWindow;
+ private String altText;
/**
* Creates a new instance.
* @param uri the target URI
* @param newWindow true if the link should be opened in a new window
*/
- public URIAction(String uri, boolean newWindow) {
+ public URIAction(String uri, boolean newWindow, String altText) {
if (uri == null) {
throw new NullPointerException("uri must not be null");
}
this.uri = uri;
this.newWindow = newWindow;
+ this.altText = altText;
setID(getIDPrefix() + (uri + newWindow).hashCode());
}
@@ -97,6 +99,9 @@ public class URIAction extends AbstractAction implements DocumentNavigationExten
atts.addAttribute("", "id", "id", XMLUtil.CDATA, getID());
}
atts.addAttribute("", "uri", "uri", XMLUtil.CDATA, getURI());
+ if (altText != null && !altText.isEmpty()) {
+ atts.addAttribute("", "alt-text", "alt-text", XMLUtil.CDATA, altText);
+ }
if (isNewWindow()) {
atts.addAttribute("", "show-destination", "show-destination", XMLUtil.CDATA, "new");
}
@@ -106,4 +111,7 @@ public class URIAction extends AbstractAction implements DocumentNavigationExten
GOTO_URI.getLocalName(), GOTO_URI.getQName());
}
+ public String getAltText() {
+ return altText;
+ }
}
diff --git a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java
index 552139980..657d81899 100644
--- a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java
+++ b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java
@@ -171,7 +171,7 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler
assert u.isComplete();
String uri = u.getURI();
PDFFactory factory = getPDFDoc().getFactory();
- pdfAction = factory.getExternalAction(uri, u.isNewWindow());
+ pdfAction = factory.getExternalAction(uri, u.isNewWindow(), u.getAltText());
if (!pdfAction.hasObjectNumber()) {
//Some PDF actions are pooled
getPDFDoc().registerObject(pdfAction);
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFAttachmentTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFAttachmentTestCase.java
index 2d7e659e3..a690a9d84 100644
--- a/fop-core/src/test/java/org/apache/fop/pdf/PDFAttachmentTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFAttachmentTestCase.java
@@ -53,7 +53,7 @@ public class PDFAttachmentTestCase {
docHandler.startPage(0, "", "", new Dimension());
docHandler.handleExtensionObject(new PDFEmbeddedFileAttachment("filename", "src", "desc"));
docHandler.getDocumentNavigationHandler().renderLink(new Link(
- new URIAction("embedded-file:filename", false), new Rectangle()));
+ new URIAction("embedded-file:filename", false, null), new Rectangle()));
docHandler.endDocument();
Assert.assertTrue(out.toString().contains(
"<<\n /Type /Filespec\n /F (filename)\n /UF (filename)\n /AFRelationship /Data"));
@@ -76,7 +76,7 @@ public class PDFAttachmentTestCase {
"src", "desc");
docHandler.handleExtensionObject(fileAtt);
docHandler.getDocumentNavigationHandler().renderLink(new Link(
- new URIAction("embedded-file:" + unicodeFilename, false), new Rectangle()));
+ new URIAction("embedded-file:" + unicodeFilename, false, null), new Rectangle()));
docHandler.endDocument();
Assert.assertTrue(out.toString().contains(
"<<\n /Type /Filespec\n /F (" + fileAtt.getFilename() + ")\n /UF "
@@ -99,7 +99,7 @@ public class PDFAttachmentTestCase {
"src", "desc");
docHandler.handleExtensionObject(fileAtt);
docHandler.getDocumentNavigationHandler().renderLink(new Link(
- new URIAction("embedded-file:" + unicodeFilename, false), new Rectangle()));
+ new URIAction("embedded-file:" + unicodeFilename, false, null), new Rectangle()));
docHandler.endDocument();
Assert.assertTrue(out.toString().contains(
"<<\n /Type /Filespec\n /F (t\\(st)\n /UF (t\\(st)\n /AFRelationship /Data"));
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
index 14745cdee..9aeef7807 100644
--- a/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
@@ -259,7 +259,7 @@ public class PDFFactoryTestCase {
PDFFactory pdfFactory = new PDFFactory(doc);
String target = "embedded-file:" + unicodeFilename;
PDFJavaScriptLaunchAction pdfAction = (PDFJavaScriptLaunchAction)
- pdfFactory.getExternalAction(target, false);
+ pdfFactory.getExternalAction(target, false, null);
String expectedString = "<<\n/S /JavaScript\n/JS (this.exportDataObject\\({cName:\""
+ fileSpec.getFilename() + "\", nLaunch:2}\\);)\n>>";
@@ -281,4 +281,16 @@ public class PDFFactoryTestCase {
assertEquals(expectedString, link.toPDFString());
}
+
+ @Test
+ public void testLinkAltText() throws IOException {
+ PDFDocument doc = new PDFDocument("");
+ PDFFactory pdfFactory = new PDFFactory(doc);
+ PDFAction action = pdfFactory.getExternalAction("a", false, "b");
+ PDFLink link = pdfFactory.makeLink(new Rectangle(), "a", 0, 0);
+ link.setAction(action);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ link.output(bos);
+ assertTrue(bos.toString().contains("/Contents (b)"));
+ }
}
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFLinkTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFLinkTestCase.java
index 988a14668..2d2e8110c 100644
--- a/fop-core/src/test/java/org/apache/fop/pdf/PDFLinkTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFLinkTestCase.java
@@ -413,7 +413,7 @@ public class PDFLinkTestCase {
docHandler.startDocument();
docHandler.startPage(0, "", "", new Dimension());
docHandler.getDocumentNavigationHandler().renderLink(new Link(
- new URIAction(target, false), new Rectangle()));
+ new URIAction(target, false, null), new Rectangle()));
docHandler.endDocument();
// Normalize spaces between word for easier testing
diff --git a/fop-core/src/test/java/org/apache/fop/render/intermediate/URIActionTestCase.java b/fop-core/src/test/java/org/apache/fop/render/intermediate/URIActionTestCase.java
index d6c30d4c7..42675f8a0 100644
--- a/fop-core/src/test/java/org/apache/fop/render/intermediate/URIActionTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/render/intermediate/URIActionTestCase.java
@@ -26,9 +26,9 @@ import org.apache.fop.render.intermediate.extensions.URIAction;
public class URIActionTestCase {
@Test
public void testID() {
- URIAction action = new URIAction("uri", true);
- URIAction action2 = new URIAction("uri", true);
- URIAction action3 = new URIAction("uri2", true);
+ URIAction action = new URIAction("uri", true, null);
+ URIAction action2 = new URIAction("uri", true, null);
+ URIAction action3 = new URIAction("uri2", true, null);
Assert.assertEquals(action.getID(), action2.getID());
Assert.assertFalse(action.getID().equals(action3.getID()));
}
diff --git a/fop/test/intermediate/basic-link_alttext.xml b/fop/test/intermediate/basic-link_alttext.xml
new file mode 100644
index 000000000..2ae776db6
--- /dev/null
+++ b/fop/test/intermediate/basic-link_alttext.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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$ -->
+<testcase>
+ <info>
+ <p>
+ This test checks a fo:basic-link in a span
+ </p>
+ </info>
+ <cfg>
+ <accessibility>true</accessibility>
+ </cfg>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+ <fo:layout-master-set>
+ <fo:simple-page-master page-width="8.5in" page-height="11in" master-name="Page">
+ <fo:region-body region-name="Body"/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="Page">
+ <fo:flow flow-name="Body">
+ <fo:block>
+ <fo:basic-link external-destination="www.a.com" fox:alt-text="xxx">www.a.com</fo:basic-link>
+ </fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <if-checks xmlns:nav="http://xmlgraphics.apache.org/fop/intermediate/document-navigation">
+ <eval expected="xxx" xpath="//nav:link/nav:goto-uri/@alt-text"/>
+ </if-checks>
+</testcase>