Skip to content

Commit

Permalink
FOP-3224: Add alt text to link dictionary
Browse files Browse the repository at this point in the history
  • Loading branch information
simonsteiner1984 committed Dec 4, 2024
1 parent 2f18585 commit fd08436
Show file tree
Hide file tree
Showing 14 changed files with 112 additions and 26 deletions.
10 changes: 8 additions & 2 deletions fop-core/src/main/java/org/apache/fop/area/Trait.java
Original file line number Diff line number Diff line change
Expand Up @@ -420,16 +420,18 @@ public static class ExternalLink implements Serializable {

private String destination;
private boolean newWindow;
private String altText;

/**
* Constructs an ExternalLink object with the given destination
*
* @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;
}

/**
Expand All @@ -452,7 +454,7 @@ protected static ExternalLink makeFromTraitValue(String traitValue) {
"Malformed trait value for Trait.ExternalLink: " + traitValue);
}
}
return new ExternalLink(dest, newWindow);
return new ExternalLink(dest, newWindow, null);
}

/**
Expand Down Expand Up @@ -483,6 +485,10 @@ public String toString() {
sb.append(",dest=").append(this.destination);
return sb.toString();
}

public String getAltText() {
return altText;
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ private void setupBasicLinkArea(InlineArea area) {
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()));
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ public PDFLink makeLink(Rectangle2D rect, String destination,
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);
Expand All @@ -583,7 +583,7 @@ public PDFLink makeLink(Rectangle2D rect, String destination,
* 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();
Expand All @@ -595,7 +595,7 @@ public PDFAction getExternalAction(String target, boolean newWindow) {
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")) {
Expand All @@ -619,16 +619,16 @@ public PDFAction getExternalAction(String target, boolean newWindow) {
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) {
Expand Down
14 changes: 10 additions & 4 deletions fop-core/src/main/java/org/apache/fop/pdf/PDFLink.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,21 @@ public String toPDFString() {
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;
}

/*
Expand Down
8 changes: 7 additions & 1 deletion fop-core/src/main/java/org/apache/fop/pdf/PDFUri.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@
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;
}

/**
Expand All @@ -57,4 +59,8 @@ public String toPDFString() {
//TODO Convert this class into a dictionary
return getDictString();
}

public String getAltText() {
return altText;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ public void renderInlineParent(InlineParent ip) {
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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,9 @@ public void startElement(String uri, String localName, String qName, Attributes
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down Expand Up @@ -97,6 +99,9 @@ public void toSAX(ContentHandler handler) throws SAXException {
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");
}
Expand All @@ -106,4 +111,7 @@ public void toSAX(ContentHandler handler) throws SAXException {
GOTO_URI.getLocalName(), GOTO_URI.getQName());
}

public String getAltText() {
return altText;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private PDFAction getAction(AbstractAction action) throws IFException {
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void testAddEmbeddedFile() throws IFException {
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"));
Expand All @@ -76,7 +76,7 @@ public void testAddEmbeddedFileGermanUmlaut() throws IFException {
"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 "
Expand All @@ -99,7 +99,7 @@ public void testAddEmbeddedFileParenthesis() throws IFException {
"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"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ public void testGetExternalAction() {
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>>";
Expand All @@ -281,4 +281,16 @@ public void testMakeLink() {

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)"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ public void testLinks() throws IFException {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
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()));
}
Expand Down
47 changes: 47 additions & 0 deletions fop/test/intermediate/basic-link_alttext.xml
Original file line number Diff line number Diff line change
@@ -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>

0 comments on commit fd08436

Please sign in to comment.