From 6c6183d35af7ed373ac3c9613ea4e35e77ae3afc Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 24 Jul 2012 16:39:04 +0000 Subject: [PATCH] Bugzilla #53596: When PDF accessibility is enabled, the structure tree must contain information about the number of columns or rows spanned by a table cell. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1365162 13f79535-47bb-0310-9956-ffa450edef68 --- .../fo/StructureTreeEventTrigger.java | 13 +- src/java/org/apache/fop/pdf/PDFArray.java | 9 ++ .../org/apache/fop/pdf/PDFStructElem.java | 34 ++++ .../render/pdf/PDFStructureTreeBuilder.java | 12 ++ status.xml | 4 + .../accessibility/pdf/table_row-col-span.pdf | Bin 0 -> 18844 bytes test/pdf/accessibility/table_row-col-span.fo | 147 ++++++++++++++++++ 7 files changed, 214 insertions(+), 5 deletions(-) create mode 100644 test/pdf/accessibility/pdf/table_row-col-span.pdf create mode 100644 test/pdf/accessibility/table_row-col-span.fo diff --git a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java index 51f7f2bed..7e3ed0591 100644 --- a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java +++ b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java @@ -221,14 +221,17 @@ class StructureTreeEventTrigger extends FOEventHandler { @Override public void startCell(TableCell tc) { AttributesImpl attributes = new AttributesImpl(); - int colSpan = tc.getNumberColumnsSpanned(); - if (colSpan > 1) { - addNoNamespaceAttribute(attributes, "number-columns-spanned", - Integer.toString(colSpan)); - } + addSpanAttribute(attributes, "number-columns-spanned", tc.getNumberColumnsSpanned()); + addSpanAttribute(attributes, "number-rows-spanned", tc.getNumberRowsSpanned()); startElement(tc, attributes); } + private void addSpanAttribute(AttributesImpl attributes, String attributeName, int span) { + if (span > 1) { + addNoNamespaceAttribute(attributes, attributeName, Integer.toString(span)); + } + } + @Override public void endCell(TableCell tc) { endElement(tc); diff --git a/src/java/org/apache/fop/pdf/PDFArray.java b/src/java/org/apache/fop/pdf/PDFArray.java index 131830328..78f5d080b 100644 --- a/src/java/org/apache/fop/pdf/PDFArray.java +++ b/src/java/org/apache/fop/pdf/PDFArray.java @@ -99,6 +99,15 @@ public class PDFArray extends PDFObject { this(null, elements); } + /** + * Creates an array object made of the given elements. + * + * @param elements the array content + */ + public PDFArray(List elements) { + this(null, elements); + } + /** * Create the array object * @param parent the array's parent if any diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java index 8030e53db..2a756fe9b 100644 --- a/src/java/org/apache/fop/pdf/PDFStructElem.java +++ b/src/java/org/apache/fop/pdf/PDFStructElem.java @@ -33,6 +33,8 @@ import org.apache.fop.util.LanguageTags; */ public class PDFStructElem extends PDFDictionary implements StructureTreeElement, CompressedObject { + private static final PDFName TABLE = new PDFName("Table"); + private PDFStructElem parentElement; /** @@ -40,6 +42,8 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement */ protected List kids; + private List attributes; + /** * Creates a new structure element. * @@ -143,9 +147,21 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement @Override protected void writeDictionary(OutputStream out, StringBuilder textBuffer) throws IOException { attachKids(); + attachAttributes(); super.writeDictionary(out, textBuffer); } + private void attachAttributes() { + if (attributes != null) { + if (attributes.size() == 1) { + put("A", attributes.get(0)); + } else { + PDFArray array = new PDFArray(attributes); + put("A", array); + } + } + } + /** * Attaches all valid kids to the kids array. * @@ -175,6 +191,24 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement return kidsAttached; } + public void setTableAttributeColSpan(int colSpan) { + setTableAttributeRowColumnSpan("ColSpan", colSpan); + } + + public void setTableAttributeRowSpan(int rowSpan) { + setTableAttributeRowColumnSpan("RowSpan", rowSpan); + } + + private void setTableAttributeRowColumnSpan(String typeSpan, int span) { + PDFDictionary attribute = new PDFDictionary(); + attribute.put("O", TABLE); + attribute.put(typeSpan, span); + if (attributes == null) { + attributes = new ArrayList(2); + } + attributes.add(attribute); + } + /** * Class representing a placeholder for a PDF Structure Element. */ diff --git a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java index 3839d47bc..0f8e74515 100644 --- a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java +++ b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java @@ -90,11 +90,23 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { PDFStructElem parent = ancestors.getFirst(); String role = attributes.getValue("role"); PDFStructElem structElem = createStructureElement(name, parent, role); + setSpanAttributes(structElem, attributes); parent.addKid(structElem); ancestors.addFirst(structElem); return structElem; } + private void setSpanAttributes(PDFStructElem structElem, Attributes attributes) { + String columnSpan = attributes.getValue("number-columns-spanned"); + if (columnSpan != null) { + structElem.setTableAttributeColSpan(Integer.parseInt(columnSpan)); + } + String rowSpan = attributes.getValue("number-rows-spanned"); + if (rowSpan != null) { + structElem.setTableAttributeRowSpan(Integer.parseInt(rowSpan)); + } + } + public void endNode(String name) { removeFirstAncestor(); } diff --git a/status.xml b/status.xml index ff374e905..145cd15cb 100644 --- a/status.xml +++ b/status.xml @@ -62,6 +62,10 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> + + When PDF accessibility is enabled, the structure tree must contain information about the + number of columns or rows spanned by a table cell. + Removed a method call to the java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice() that could (in a headless environment) throw a java.awt.HeadlessException diff --git a/test/pdf/accessibility/pdf/table_row-col-span.pdf b/test/pdf/accessibility/pdf/table_row-col-span.pdf new file mode 100644 index 0000000000000000000000000000000000000000..65921fe5a63d28c01840bf82eba1c15b9b0fec65 GIT binary patch literal 18844 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 literal 0 HcmV?d00001 diff --git a/test/pdf/accessibility/table_row-col-span.fo b/test/pdf/accessibility/table_row-col-span.fo new file mode 100644 index 000000000..1d28d4406 --- /dev/null +++ b/test/pdf/accessibility/table_row-col-span.fo @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + Cells 1.1 and 1.2. + + + Cell 1.3. + + + Cell 1.4. + + + + + Cell 2.1. + + + Cells 2.2 and 2.3. + + + Cell 2.4. + + + + + Cell 3.1. + + + Cell 3.2. + + + Cells 3.3 and 3.4. + + + + + Cells 4.1, 4.2 and 4.3. + + + Cell 4.4. + + + + + Cells 5.1, 5.2, 5.3 and 5.4. + + + + + + + + + + Cells 1.1 + and 2.1. + + + Cell 1.2. + + + Cell 1.3. + + + Cells 1.4, + 2.4, + 3.4 + and 4.4. + + + + + Cells 2.2 + and 3.2. + + + Cells 2.3, + 3.3 + and 4.3. + + + + + Cell 3.1. + + + + + Cell 4.1. + + + Cell 4.2. + + + + + + + + + + Cells 1.1, 1.2, 1.3 + and 2.1, 2.2, 2.3. + + + Cell 1.4. + + + + + Cell 2.4. + + + + + Cell 3.1. + + + Cell 3.2. + + + Cell 3.3. + + + Cell 3.4. + + + + + + + + -- 2.39.5