diff options
author | Vincent Hennebert <vhennebert@apache.org> | 2012-09-26 11:31:40 +0000 |
---|---|---|
committer | Vincent Hennebert <vhennebert@apache.org> | 2012-09-26 11:31:40 +0000 |
commit | a1af0b2481adf1d4bdb1279972a9d4e51e381f6a (patch) | |
tree | 00f0840c0593e48cc1c49878a6e2a1a78e20a9e9 | |
parent | 182bbad662b45ecc15e2cc3d3de6cde7bdc77bea (diff) | |
download | xmlgraphics-fop-a1af0b2481adf1d4bdb1279972a9d4e51e381f6a.tar.gz xmlgraphics-fop-a1af0b2481adf1d4bdb1279972a9d4e51e381f6a.zip |
Bugzilla #53902: Added possibility to define 'header' table columns (the same way as fo:table-header allows to define header rows).
When accessibility is enabled, this allows to set the appropriate Scope attribute on the corresponding TH cells.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1390412 13f79535-47bb-0310-9956-ffa450edef68
20 files changed, 371 insertions, 26 deletions
diff --git a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java index 93b815d30..09a814ef5 100644 --- a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java +++ b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java @@ -20,6 +20,7 @@ package org.apache.fop.accessibility.fo; import java.util.Locale; +import java.util.Stack; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; @@ -30,6 +31,7 @@ import org.apache.fop.fo.FOEventHandler; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FOText; 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.BasicLink; import org.apache.fop.fo.flow.Block; @@ -70,6 +72,10 @@ class StructureTreeEventTrigger extends FOEventHandler { private LayoutMasterSet layoutMasterSet; + private final Stack<Table> tables = new Stack<Table>(); + + private final Stack<Boolean> inTableHeader = new Stack<Boolean>(); + public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) { this.structureTreeEventHandler = structureTreeEventHandler; } @@ -195,42 +201,51 @@ class StructureTreeEventTrigger extends FOEventHandler { @Override public void startTable(Table tbl) { + tables.push(tbl); startElement(tbl); } @Override public void endTable(Table tbl) { endElement(tbl); + tables.pop(); } @Override public void startHeader(TableHeader header) { + inTableHeader.push(Boolean.TRUE); startElement(header); } @Override public void endHeader(TableHeader header) { endElement(header); + inTableHeader.pop(); } @Override public void startFooter(TableFooter footer) { + // TODO Shouldn't it be true? + inTableHeader.push(Boolean.FALSE); startElement(footer); } @Override public void endFooter(TableFooter footer) { endElement(footer); + inTableHeader.pop(); } @Override public void startBody(TableBody body) { + inTableHeader.push(Boolean.FALSE); startElement(body); } @Override public void endBody(TableBody body) { endElement(body); + inTableHeader.pop(); } @Override @@ -248,6 +263,24 @@ class StructureTreeEventTrigger extends FOEventHandler { AttributesImpl attributes = new AttributesImpl(); addSpanAttribute(attributes, "number-columns-spanned", tc.getNumberColumnsSpanned()); addSpanAttribute(attributes, "number-rows-spanned", tc.getNumberRowsSpanned()); + boolean rowHeader = inTableHeader.peek(); + boolean columnHeader = tables.peek().getColumn(tc.getColumnNumber() - 1).isHeader(); + if (rowHeader || columnHeader) { + final String th = "TH"; + String role = tc.getCommonAccessibility().getRole(); + /* Do not override a custom role */ + if (role == null) { + role = th; + addNoNamespaceAttribute(attributes, "role", th); + } + if (role.equals(th)) { + if (columnHeader) { + String scope = rowHeader ? "Both" : "Row"; + addAttribute(attributes, InternalElementMapping.URI, InternalElementMapping.SCOPE, + InternalElementMapping.STANDARD_PREFIX, scope); + } + } + } startElement(tc, attributes); } diff --git a/src/java/org/apache/fop/fo/Constants.java b/src/java/org/apache/fop/fo/Constants.java index 2d10dcdd9..6688042e2 100644 --- a/src/java/org/apache/fop/fo/Constants.java +++ b/src/java/org/apache/fop/fo/Constants.java @@ -785,8 +785,11 @@ public interface Constants { */ int PR_X_NUMBER_CONVERSION_FEATURES = 276; + /** Scope for table header */ + int PR_X_HEADER_COLUMN = 277; + /** Number of property constants defined */ - int PROPERTY_COUNT = 276; + int PROPERTY_COUNT = 277; // compound property constants diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java index d0d13fc17..a92b71ef9 100644 --- a/src/java/org/apache/fop/fo/FOPropertyMapping.java +++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java @@ -2513,6 +2513,12 @@ public final class FOPropertyMapping implements Constants { m.setInherited(false); m.setDefault("false"); addPropertyMaker("table-omit-header-at-break", m); + + // fox:scope + m = new EnumProperty.Maker(PR_X_HEADER_COLUMN); + m.useGeneric(genericBoolean); + m.setDefault("false"); + addPropertyMaker("fox:header", m); } private void createWritingModeProperties() { diff --git a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java index f0e03399f..a040edf1a 100644 --- a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java @@ -52,6 +52,7 @@ public class ExtensionElementMapping extends ElementMapping { PROPERTY_ATTRIBUTES.add("disable-column-balancing"); //These are FOP's extension properties for accessibility PROPERTY_ATTRIBUTES.add("alt-text"); + PROPERTY_ATTRIBUTES.add("header"); } /** diff --git a/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java b/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java index 687952d25..f257dd79d 100644 --- a/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java @@ -43,12 +43,15 @@ public class InternalElementMapping extends ElementMapping { /** The "struct-ref" attribute, to refer to a structure tree element. */ public static final String STRUCT_REF = "struct-ref"; + public static final String SCOPE = "scope"; + private static final Set<String> PROPERTY_ATTRIBUTES = new java.util.HashSet<String>(); static { //These are FOP's extension properties for accessibility PROPERTY_ATTRIBUTES.add(STRUCT_ID); PROPERTY_ATTRIBUTES.add(STRUCT_REF); + PROPERTY_ATTRIBUTES.add(SCOPE); } /** diff --git a/src/java/org/apache/fop/fo/flow/table/TableColumn.java b/src/java/org/apache/fop/fo/flow/table/TableColumn.java index 5047822da..33cbff884 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableColumn.java +++ b/src/java/org/apache/fop/fo/flow/table/TableColumn.java @@ -24,6 +24,7 @@ import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Length; +import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; @@ -44,6 +45,7 @@ public class TableColumn extends TableFObj { private Length columnWidth; private int numberColumnsRepeated; private int numberColumnsSpanned; + private boolean isHeader; // Unused but valid items, commented out for performance: // private int visibility; // End of property values @@ -120,6 +122,7 @@ public class TableColumn extends TableFObj { if (!this.implicitColumn) { this.pList = pList; } + isHeader = (pList.get(Constants.PR_X_HEADER_COLUMN).getEnum() == Constants.EN_TRUE); } /** {@inheritDoc} */ @@ -263,4 +266,13 @@ public class TableColumn extends TableFObj { this.pList = null; } + /** + * Returns {@code true} if this column is made of header cells. + * + * @return {@code true} if cells in this column are like TH cells in HTML + */ + public boolean isHeader() { + return isHeader; + } + } diff --git a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java index 0d4a6b7fb..031224ffb 100644 --- a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java +++ b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java @@ -30,6 +30,7 @@ import org.apache.fop.accessibility.StructureTreeElement; import org.apache.fop.accessibility.StructureTreeEventHandler; import org.apache.fop.events.EventBroadcaster; import org.apache.fop.fo.extensions.ExtensionElementMapping; +import org.apache.fop.fo.extensions.InternalElementMapping; import org.apache.fop.fo.pagination.Flow; import org.apache.fop.pdf.PDFFactory; import org.apache.fop.pdf.PDFParentTree; @@ -138,7 +139,7 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { PDFStructElem structElem = createStructureElement(parent, structureType); setAttributes(structElem, attributes); addKidToParent(structElem, parent, attributes); - registerStructureElement(structElem, pdfFactory); + registerStructureElement(structElem, pdfFactory, attributes); return structElem; } @@ -155,7 +156,8 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { parent.addKid(kid); } - protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory) { + protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory, + Attributes attributes) { pdfFactory.getDocument().registerStructureElement(structureElement); } @@ -240,22 +242,15 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { } @Override - protected PDFStructElem createStructureElement(StructureHierarchyMember parent, - StructureType structureType) { - PDFStructElem grandParent = ((PDFStructElem) parent).getParentStructElem(); - //TODO What to do with cells from table-footer? Currently they are mapped on TD. - if (grandParent.getStructureType() == StandardStructureTypes.Table.THEAD) { - structureType = StandardStructureTypes.Table.TH; - } else { - structureType = StandardStructureTypes.Table.TD; - } - return super.createStructureElement(parent, structureType); - } - - @Override - protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory) { + protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory, + Attributes attributes) { if (structureElement.getStructureType() == Table.TH) { - pdfFactory.getDocument().registerStructureElement(structureElement, Scope.COLUMN); + String scopeAttribute = attributes.getValue(InternalElementMapping.URI, + InternalElementMapping.SCOPE); + Scope scope = (scopeAttribute == null) + ? Scope.COLUMN + : Scope.valueOf(scopeAttribute.toUpperCase(Locale.ENGLISH)); + pdfFactory.getDocument().registerStructureElement(structureElement, scope); } else { pdfFactory.getDocument().registerStructureElement(structureElement); } diff --git a/status.xml b/status.xml index 7571ddfda..40e4c8db6 100644 --- a/status.xml +++ b/status.xml @@ -62,6 +62,11 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> <release version="FOP Trunk" date="TBD"> + <action context="Renderers" dev="VH" type="add" fixes-bug="53902"> + Added possibility to define ‘header’ table columns (the same way as fo:table-header allows + to define header rows). When accessibility is enabled, this allows to set the appropriate + Scope attribute on the corresponding TH cells. + </action> <action context="Fonts" dev="MH" type="add" fixes-bug="53868" importance="low" due-to="Luis Bernardo"> Full font embedding in PDF </action> diff --git a/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java b/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java index 6092912f9..87b970576 100644 --- a/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java +++ b/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java @@ -91,6 +91,11 @@ public class FO2StructureTreeConverterTestCase { testConverter("/org/apache/fop/fo/pagination/side-regions.fo"); } + @Test + public void headerTableCellMustPropagateScope() throws Exception { + testConverter("table-header_scope.fo"); + } + private static InputStream getResource(String name) { return FO2StructureTreeConverterTestCase.class.getResourceAsStream(name); } diff --git a/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl b/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl index c739462e4..90d74a7c4 100644 --- a/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl +++ b/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl @@ -21,7 +21,7 @@ xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" xmlns:foi="http://xmlgraphics.apache.org/fop/internal"> - <xsl:output method="xml" indent="no"/> + <xsl:output method="xml" indent="yes"/> <xsl:template name="copy"> <xsl:copy> @@ -92,10 +92,37 @@ <xsl:call-template name="copy"/> </xsl:template> - <xsl:template match="fo:table|fo:table-header|fo:table-footer|fo:table-body|fo:table-row|fo:table-cell"> + <xsl:template match="fo:table|fo:table-header|fo:table-footer|fo:table-body|fo:table-row"> <xsl:call-template name="copy"/> </xsl:template> + <xsl:template name="get.column.header"> + <xsl:value-of select="ancestor::fo:table/fo:table-column[ + count(preceding-sibling::fo:table-column) = count(current()/preceding-sibling::fo:table-cell)]/@fox:header"/> + </xsl:template> + + <xsl:template match="fo:table-cell"> + <xsl:variable name="header"><xsl:call-template name="get.column.header"/></xsl:variable> + <xsl:copy> + <xsl:if test="$header = 'true'"> + <xsl:attribute name="role">TH</xsl:attribute> + <xsl:attribute name="scope" namespace="http://xmlgraphics.apache.org/fop/internal">Row</xsl:attribute> + </xsl:if> + <xsl:apply-templates select="@*|node()"/> + </xsl:copy> + </xsl:template> + + <xsl:template match="fo:table-header/fo:table-cell|fo:table-header/fo:table-row/fo:table-cell"> + <xsl:variable name="header"><xsl:call-template name="get.column.header"/></xsl:variable> + <xsl:copy> + <xsl:attribute name="role">TH</xsl:attribute> + <xsl:if test="$header = 'true'"> + <xsl:attribute name="scope" namespace="http://xmlgraphics.apache.org/fop/internal">Both</xsl:attribute> + </xsl:if> + <xsl:apply-templates select="@*|node()"/> + </xsl:copy> + </xsl:template> + <!-- Formatting Objects for Lists --> <xsl:template match="fo:list-block|fo:list-item|fo:list-item-label|fo:list-item-body"> <xsl:call-template name="copy"/> diff --git a/test/java/org/apache/fop/accessibility/fo/table-header_scope.fo b/test/java/org/apache/fop/accessibility/fo/table-header_scope.fo new file mode 100644 index 000000000..c6272d546 --- /dev/null +++ b/test/java/org/apache/fop/accessibility/fo/table-header_scope.fo @@ -0,0 +1,57 @@ +<?xml version="1.0" standalone="no"?> +<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" + xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" + font-family="sans-serif"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" + page-height="120pt" page-width="220pt" margin="10pt"> + <fo:region-body display-align="center"/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page"> + <fo:flow flow-name="xsl-region-body" line-height="10pt" font-size="8pt"> + <fo:table width="100%" table-layout="fixed"> + <fo:table-column fox:header="true" column-width="proportional-column-width(1)"/> + <fo:table-column column-width="proportional-column-width(1)"/> + <fo:table-column column-width="proportional-column-width(1)"/> + <fo:table-header font-weight="bold"> + <fo:table-row> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Table Header</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Column 1</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Column 2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-header> + <fo:table-body> + <fo:table-row> + <fo:table-cell id="Row1" border="1pt solid black" padding-left="1pt" font-weight="bold"> + <fo:block>Row 1</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Cell 1.1</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Cell 1.2</fo:block> + </fo:table-cell> + </fo:table-row> + <fo:table-row> + <fo:table-cell border="1pt solid black" padding-left="1pt" font-weight="bold" role="TH"> + <fo:block>Row 2</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Cell 2.1</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Cell 2.2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + </fo:flow> + </fo:page-sequence> +</fo:root> diff --git a/test/java/org/apache/fop/fo/FONodeMocks.java b/test/java/org/apache/fop/fo/FONodeMocks.java index 001173179..ba969b9fa 100644 --- a/test/java/org/apache/fop/fo/FONodeMocks.java +++ b/test/java/org/apache/fop/fo/FONodeMocks.java @@ -19,19 +19,22 @@ package org.apache.fop.fo; +import java.io.IOException; + import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import java.io.IOException; - import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.image.loader.ImageSessionContext; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FopFactory; +import org.apache.fop.events.EventBroadcaster; +import org.apache.fop.fo.flow.table.ColumnNumberManager; +import org.apache.fop.fo.flow.table.ColumnNumberManagerHolder; /** * A helper class for creating mocks of {@link FONode} and its descendants. @@ -51,27 +54,36 @@ public final class FONodeMocks { public static FONode mockFONode() { FONode mockFONode = mock(FONode.class); mockGetFOEventHandler(mockFONode); + mockGetImageManager(mockFONode.getFOEventHandler().getUserAgent()); return mockFONode; } - private static void mockGetFOEventHandler(FONode mockFONode) { + public static FOEventHandler mockGetFOEventHandler(FONode mockFONode) { FOEventHandler mockFOEventHandler = mock(FOEventHandler.class); mockGetUserAgent(mockFOEventHandler); when(mockFONode.getFOEventHandler()).thenReturn(mockFOEventHandler); + return mockFOEventHandler; } - private static void mockGetUserAgent(FOEventHandler mockFOEventHandler) { + public static FOUserAgent mockGetUserAgent(FOEventHandler mockFOEventHandler) { FOUserAgent mockFOUserAgent = mock(FOUserAgent.class); - mockGetImageManager(mockFOUserAgent); when(mockFOEventHandler.getUserAgent()).thenReturn(mockFOUserAgent); + return mockFOUserAgent; } - private static void mockGetImageManager(FOUserAgent mockFOUserAgent) { + public static EventBroadcaster mockGetEventBroadcaster(FOUserAgent mockFOUserAgent) { + EventBroadcaster mockBroadcaster = mock(EventBroadcaster.class); + when(mockFOUserAgent.getEventBroadcaster()).thenReturn(mockBroadcaster); + return mockBroadcaster; + } + + public static ImageManager mockGetImageManager(FOUserAgent mockFOUserAgent) { try { ImageManager mockImageManager = mock(ImageManager.class); when(mockImageManager.getImageInfo(anyString(), any(ImageSessionContext.class))) .thenReturn(null); when(mockFOUserAgent.getImageManager()).thenReturn(mockImageManager); + return mockImageManager; } catch (ImageException e) { throw new RuntimeException(e); } catch (IOException e) { @@ -79,4 +91,10 @@ public final class FONodeMocks { } } + public static ColumnNumberManager mockGetColumnNumberManager(ColumnNumberManagerHolder mock) { + ColumnNumberManager mockColumnNumberManager = mock(ColumnNumberManager.class); + when(mock.getColumnNumberManager()).thenReturn(mockColumnNumberManager); + return mockColumnNumberManager; + } + } diff --git a/test/java/org/apache/fop/fo/flow/table/HeaderColumnTestCase.java b/test/java/org/apache/fop/fo/flow/table/HeaderColumnTestCase.java new file mode 100644 index 000000000..4cc94b5e0 --- /dev/null +++ b/test/java/org/apache/fop/fo/flow/table/HeaderColumnTestCase.java @@ -0,0 +1,112 @@ +/* + * 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.fo.flow.table; + +import org.junit.Test; +import org.xml.sax.Attributes; +import org.xml.sax.Locator; +import org.xml.sax.helpers.AttributesImpl; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.events.EventBroadcaster; +import org.apache.fop.fo.ElementMappingRegistry; +import org.apache.fop.fo.FOEventHandler; +import org.apache.fop.fo.FONodeMocks; +import org.apache.fop.fo.FOValidationEventProducer; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.StaticPropertyList; +import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.expr.PropertyException; +import org.apache.fop.fo.extensions.ExtensionElementMapping; +import org.apache.fop.util.XMLUtil; + +/** + * Tests that the fox:header property is correctly parsed and set up at the FO tree level. + */ +public class HeaderColumnTestCase { + + @Test + public void testWrongValue() throws ValidationException { + Table parent = createTableParent(); + EventBroadcaster mockEventBroadcaster = FONodeMocks.mockGetEventBroadcaster( + parent.getFOEventHandler().getUserAgent()); + FOValidationEventProducer eventProducer = mockGetEventProducerFor(mockEventBroadcaster); + TableColumn column = new TableColumn(parent); + PropertyList propertyList = new StaticPropertyList(column, null); + Attributes atts = createScopeAttribute("blah"); + propertyList.addAttributesToList(atts); + verify(eventProducer).invalidPropertyValue(any(), eq("fo:table-column"), + eq("fox:header"), eq("blah"), any(PropertyException.class), any(Locator.class)); + } + + @Test + public void testCorrectValue() throws Exception { + testCorrectValue(true); + testCorrectValue(false); + } + + private void testCorrectValue(boolean expectedValue) throws Exception { + Table parent = createTableParent(); + FONodeMocks.mockGetColumnNumberManager(parent); + TableColumn column = new TableColumn(parent, true); + PropertyList propertyList = new StaticPropertyList(column, null); + Attributes atts = createScopeAttribute(String.valueOf(expectedValue)); + propertyList.addAttributesToList(atts); + column.bind(propertyList); + assertEquals(expectedValue, column.isHeader()); + } + + private Table createTableParent() { + Table parent = mock(Table.class); + FOEventHandler mockFOEventHandler = FONodeMocks.mockGetFOEventHandler(parent); + FOUserAgent mockUserAgent = mockFOEventHandler.getUserAgent(); + mockGetElementMappingRegistry(mockUserAgent); + return parent; + } + + private Attributes createScopeAttribute(String value) { + AttributesImpl atts = new AttributesImpl(); + atts.addAttribute(ExtensionElementMapping.URI, "header", "fox:header", XMLUtil.CDATA, value); + return atts; + } + + private ElementMappingRegistry mockGetElementMappingRegistry(FOUserAgent mockUserAgent) { + ElementMappingRegistry mockRegistry = mock(ElementMappingRegistry.class); + when(mockRegistry.getElementMapping(anyString())).thenReturn(new ExtensionElementMapping()); + when(mockUserAgent.getElementMappingRegistry()).thenReturn(mockRegistry); + return mockRegistry; + } + + private FOValidationEventProducer mockGetEventProducerFor(EventBroadcaster mockEventBroadcaster) { + FOValidationEventProducer mockEventProducer = mock(FOValidationEventProducer.class); + when(mockEventBroadcaster.getEventProducerFor(eq(FOValidationEventProducer.class))) + .thenReturn(mockEventProducer); + return mockEventProducer; + } + +} diff --git a/test/pdf/accessibility/pdf/background-image_svg_repeat.pdf b/test/pdf/accessibility/pdf/background-image_svg_repeat.pdf Binary files differindex 41c2ee500..0921d734f 100644 --- a/test/pdf/accessibility/pdf/background-image_svg_repeat.pdf +++ b/test/pdf/accessibility/pdf/background-image_svg_repeat.pdf diff --git a/test/pdf/accessibility/pdf/background-image_svg_single.pdf b/test/pdf/accessibility/pdf/background-image_svg_single.pdf Binary files differindex 8c2dc1006..9c8af4fb6 100644 --- a/test/pdf/accessibility/pdf/background-image_svg_single.pdf +++ b/test/pdf/accessibility/pdf/background-image_svg_single.pdf diff --git a/test/pdf/accessibility/pdf/image_svg.pdf b/test/pdf/accessibility/pdf/image_svg.pdf Binary files differindex a9428fd3f..cc0a3ebba 100644 --- a/test/pdf/accessibility/pdf/image_svg.pdf +++ b/test/pdf/accessibility/pdf/image_svg.pdf diff --git a/test/pdf/accessibility/pdf/image_wmf.pdf b/test/pdf/accessibility/pdf/image_wmf.pdf Binary files differindex c15a05223..368afe60d 100644 --- a/test/pdf/accessibility/pdf/image_wmf.pdf +++ b/test/pdf/accessibility/pdf/image_wmf.pdf diff --git a/test/pdf/accessibility/pdf/text_font-embedding.pdf b/test/pdf/accessibility/pdf/text_font-embedding.pdf Binary files differindex d1e4c6e28..47ca60bdb 100644 --- a/test/pdf/accessibility/pdf/text_font-embedding.pdf +++ b/test/pdf/accessibility/pdf/text_font-embedding.pdf diff --git a/test/pdf/accessibility/pdf/th_scope.pdf b/test/pdf/accessibility/pdf/th_scope.pdf Binary files differnew file mode 100644 index 000000000..596ffb7db --- /dev/null +++ b/test/pdf/accessibility/pdf/th_scope.pdf diff --git a/test/pdf/accessibility/th_scope.fo b/test/pdf/accessibility/th_scope.fo new file mode 100644 index 000000000..4e22b9160 --- /dev/null +++ b/test/pdf/accessibility/th_scope.fo @@ -0,0 +1,68 @@ +<?xml version="1.0" standalone="no"?> +<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" + xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" + font-family="sans-serif"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" + page-height="120pt" page-width="220pt" margin="10pt"> + <fo:region-body display-align="center"/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page"> + <fo:flow flow-name="xsl-region-body" line-height="10pt" font-size="8pt"> + <fo:table width="100%" table-layout="fixed"> + <fo:table-column fox:header="true" column-width="proportional-column-width(1)"/> + <fo:table-column column-width="proportional-column-width(1)"/> + <fo:table-column column-width="proportional-column-width(1)"/> + <fo:table-header font-weight="bold"> + <fo:table-row> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Table Header</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Column 1</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Column 2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-header> + <fo:table-body> + <fo:table-row> + <fo:table-cell id="Row1" border="1pt solid black" padding-left="1pt" font-weight="bold"> + <fo:block>Row 1</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Cell 1.1</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Cell 1.2</fo:block> + </fo:table-cell> + </fo:table-row> + <fo:table-row> + <fo:table-cell border="1pt solid black" padding-left="1pt" font-weight="bold" role="TH"> + <fo:block>Row 2</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Cell 2.1</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Cell 2.2</fo:block> + </fo:table-cell> + </fo:table-row> + <fo:table-row> + <fo:table-cell border="1pt solid black" padding-left="1pt" role="TD"> + <fo:block>Non-header</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Cell 3.1</fo:block> + </fo:table-cell> + <fo:table-cell border="1pt solid black" padding-left="1pt"> + <fo:block>Cell 3.2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + </fo:flow> + </fo:page-sequence> +</fo:root> |