Procházet zdrojové kódy

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
tags/fop-2_0
Vincent Hennebert před 11 roky
rodič
revize
a1af0b2481

+ 33
- 0
src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java Zobrazit soubor

package org.apache.fop.accessibility.fo; package org.apache.fop.accessibility.fo;


import java.util.Locale; import java.util.Locale;
import java.util.Stack;


import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.AttributesImpl;
import org.apache.fop.fo.FONode; import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FOText; import org.apache.fop.fo.FOText;
import org.apache.fop.fo.extensions.ExtensionElementMapping; 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.AbstractGraphics;
import org.apache.fop.fo.flow.BasicLink; import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.fo.flow.Block; import org.apache.fop.fo.flow.Block;


private LayoutMasterSet layoutMasterSet; private LayoutMasterSet layoutMasterSet;


private final Stack<Table> tables = new Stack<Table>();

private final Stack<Boolean> inTableHeader = new Stack<Boolean>();

public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) { public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) {
this.structureTreeEventHandler = structureTreeEventHandler; this.structureTreeEventHandler = structureTreeEventHandler;
} }


@Override @Override
public void startTable(Table tbl) { public void startTable(Table tbl) {
tables.push(tbl);
startElement(tbl); startElement(tbl);
} }


@Override @Override
public void endTable(Table tbl) { public void endTable(Table tbl) {
endElement(tbl); endElement(tbl);
tables.pop();
} }


@Override @Override
public void startHeader(TableHeader header) { public void startHeader(TableHeader header) {
inTableHeader.push(Boolean.TRUE);
startElement(header); startElement(header);
} }


@Override @Override
public void endHeader(TableHeader header) { public void endHeader(TableHeader header) {
endElement(header); endElement(header);
inTableHeader.pop();
} }


@Override @Override
public void startFooter(TableFooter footer) { public void startFooter(TableFooter footer) {
// TODO Shouldn't it be true?
inTableHeader.push(Boolean.FALSE);
startElement(footer); startElement(footer);
} }


@Override @Override
public void endFooter(TableFooter footer) { public void endFooter(TableFooter footer) {
endElement(footer); endElement(footer);
inTableHeader.pop();
} }


@Override @Override
public void startBody(TableBody body) { public void startBody(TableBody body) {
inTableHeader.push(Boolean.FALSE);
startElement(body); startElement(body);
} }


@Override @Override
public void endBody(TableBody body) { public void endBody(TableBody body) {
endElement(body); endElement(body);
inTableHeader.pop();
} }


@Override @Override
AttributesImpl attributes = new AttributesImpl(); AttributesImpl attributes = new AttributesImpl();
addSpanAttribute(attributes, "number-columns-spanned", tc.getNumberColumnsSpanned()); addSpanAttribute(attributes, "number-columns-spanned", tc.getNumberColumnsSpanned());
addSpanAttribute(attributes, "number-rows-spanned", tc.getNumberRowsSpanned()); 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); startElement(tc, attributes);
} }



+ 4
- 1
src/java/org/apache/fop/fo/Constants.java Zobrazit soubor

*/ */
int PR_X_NUMBER_CONVERSION_FEATURES = 276; int PR_X_NUMBER_CONVERSION_FEATURES = 276;


/** Scope for table header */
int PR_X_HEADER_COLUMN = 277;

/** Number of property constants defined */ /** Number of property constants defined */
int PROPERTY_COUNT = 276;
int PROPERTY_COUNT = 277;


// compound property constants // compound property constants



+ 6
- 0
src/java/org/apache/fop/fo/FOPropertyMapping.java Zobrazit soubor

m.setInherited(false); m.setInherited(false);
m.setDefault("false"); m.setDefault("false");
addPropertyMaker("table-omit-header-at-break", m); 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() { private void createWritingModeProperties() {

+ 1
- 0
src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java Zobrazit soubor

PROPERTY_ATTRIBUTES.add("disable-column-balancing"); PROPERTY_ATTRIBUTES.add("disable-column-balancing");
//These are FOP's extension properties for accessibility //These are FOP's extension properties for accessibility
PROPERTY_ATTRIBUTES.add("alt-text"); PROPERTY_ATTRIBUTES.add("alt-text");
PROPERTY_ATTRIBUTES.add("header");
} }


/** /**

+ 3
- 0
src/java/org/apache/fop/fo/extensions/InternalElementMapping.java Zobrazit soubor

/** The "struct-ref" attribute, to refer to a structure tree element. */ /** The "struct-ref" attribute, to refer to a structure tree element. */
public static final String STRUCT_REF = "struct-ref"; 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>(); private static final Set<String> PROPERTY_ATTRIBUTES = new java.util.HashSet<String>();


static { static {
//These are FOP's extension properties for accessibility //These are FOP's extension properties for accessibility
PROPERTY_ATTRIBUTES.add(STRUCT_ID); PROPERTY_ATTRIBUTES.add(STRUCT_ID);
PROPERTY_ATTRIBUTES.add(STRUCT_REF); PROPERTY_ATTRIBUTES.add(STRUCT_REF);
PROPERTY_ATTRIBUTES.add(SCOPE);
} }


/** /**

+ 12
- 0
src/java/org/apache/fop/fo/flow/table/TableColumn.java Zobrazit soubor



import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length; import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FONode; import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException; import org.apache.fop.fo.ValidationException;
private Length columnWidth; private Length columnWidth;
private int numberColumnsRepeated; private int numberColumnsRepeated;
private int numberColumnsSpanned; private int numberColumnsSpanned;
private boolean isHeader;
// Unused but valid items, commented out for performance: // Unused but valid items, commented out for performance:
// private int visibility; // private int visibility;
// End of property values // End of property values
if (!this.implicitColumn) { if (!this.implicitColumn) {
this.pList = pList; this.pList = pList;
} }
isHeader = (pList.get(Constants.PR_X_HEADER_COLUMN).getEnum() == Constants.EN_TRUE);
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
this.pList = null; 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;
}

} }

+ 12
- 17
src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java Zobrazit soubor

import org.apache.fop.accessibility.StructureTreeEventHandler; import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.events.EventBroadcaster; import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.fo.extensions.ExtensionElementMapping; 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.fo.pagination.Flow;
import org.apache.fop.pdf.PDFFactory; import org.apache.fop.pdf.PDFFactory;
import org.apache.fop.pdf.PDFParentTree; import org.apache.fop.pdf.PDFParentTree;
PDFStructElem structElem = createStructureElement(parent, structureType); PDFStructElem structElem = createStructureElement(parent, structureType);
setAttributes(structElem, attributes); setAttributes(structElem, attributes);
addKidToParent(structElem, parent, attributes); addKidToParent(structElem, parent, attributes);
registerStructureElement(structElem, pdfFactory);
registerStructureElement(structElem, pdfFactory, attributes);
return structElem; return structElem;
} }


parent.addKid(kid); parent.addKid(kid);
} }


protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory) {
protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory,
Attributes attributes) {
pdfFactory.getDocument().registerStructureElement(structureElement); pdfFactory.getDocument().registerStructureElement(structureElement);
} }


} }


@Override @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) { 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 { } else {
pdfFactory.getDocument().registerStructureElement(structureElement); pdfFactory.getDocument().registerStructureElement(structureElement);
} }

+ 5
- 0
status.xml Zobrazit soubor

documents. Example: the fix of marks layering will be such a case when it's done. documents. Example: the fix of marks layering will be such a case when it's done.
--> -->
<release version="FOP Trunk" date="TBD"> <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"> <action context="Fonts" dev="MH" type="add" fixes-bug="53868" importance="low" due-to="Luis Bernardo">
Full font embedding in PDF Full font embedding in PDF
</action> </action>

+ 5
- 0
test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java Zobrazit soubor

testConverter("/org/apache/fop/fo/pagination/side-regions.fo"); 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) { private static InputStream getResource(String name) {
return FO2StructureTreeConverterTestCase.class.getResourceAsStream(name); return FO2StructureTreeConverterTestCase.class.getResourceAsStream(name);
} }

+ 29
- 2
test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl Zobrazit soubor

xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
xmlns:foi="http://xmlgraphics.apache.org/fop/internal"> 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:template name="copy">
<xsl:copy> <xsl:copy>
<xsl:call-template name="copy"/> <xsl:call-template name="copy"/>
</xsl:template> </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:call-template name="copy"/>
</xsl:template> </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 --> <!-- Formatting Objects for Lists -->
<xsl:template match="fo:list-block|fo:list-item|fo:list-item-label|fo:list-item-body"> <xsl:template match="fo:list-block|fo:list-item|fo:list-item-label|fo:list-item-body">
<xsl:call-template name="copy"/> <xsl:call-template name="copy"/>

+ 57
- 0
test/java/org/apache/fop/accessibility/fo/table-header_scope.fo Zobrazit soubor

<?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>

+ 24
- 6
test/java/org/apache/fop/fo/FONodeMocks.java Zobrazit soubor



package org.apache.fop.fo; package org.apache.fop.fo;


import java.io.IOException;

import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;


import java.io.IOException;

import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageException;
import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.ImageSessionContext; import org.apache.xmlgraphics.image.loader.ImageSessionContext;


import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory; 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. * A helper class for creating mocks of {@link FONode} and its descendants.
public static FONode mockFONode() { public static FONode mockFONode() {
FONode mockFONode = mock(FONode.class); FONode mockFONode = mock(FONode.class);
mockGetFOEventHandler(mockFONode); mockGetFOEventHandler(mockFONode);
mockGetImageManager(mockFONode.getFOEventHandler().getUserAgent());
return mockFONode; return mockFONode;
} }


private static void mockGetFOEventHandler(FONode mockFONode) {
public static FOEventHandler mockGetFOEventHandler(FONode mockFONode) {
FOEventHandler mockFOEventHandler = mock(FOEventHandler.class); FOEventHandler mockFOEventHandler = mock(FOEventHandler.class);
mockGetUserAgent(mockFOEventHandler); mockGetUserAgent(mockFOEventHandler);
when(mockFONode.getFOEventHandler()).thenReturn(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); FOUserAgent mockFOUserAgent = mock(FOUserAgent.class);
mockGetImageManager(mockFOUserAgent);
when(mockFOEventHandler.getUserAgent()).thenReturn(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 { try {
ImageManager mockImageManager = mock(ImageManager.class); ImageManager mockImageManager = mock(ImageManager.class);
when(mockImageManager.getImageInfo(anyString(), any(ImageSessionContext.class))) when(mockImageManager.getImageInfo(anyString(), any(ImageSessionContext.class)))
.thenReturn(null); .thenReturn(null);
when(mockFOUserAgent.getImageManager()).thenReturn(mockImageManager); when(mockFOUserAgent.getImageManager()).thenReturn(mockImageManager);
return mockImageManager;
} catch (ImageException e) { } catch (ImageException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (IOException e) { } catch (IOException e) {
} }
} }


public static ColumnNumberManager mockGetColumnNumberManager(ColumnNumberManagerHolder mock) {
ColumnNumberManager mockColumnNumberManager = mock(ColumnNumberManager.class);
when(mock.getColumnNumberManager()).thenReturn(mockColumnNumberManager);
return mockColumnNumberManager;
}

} }

+ 112
- 0
test/java/org/apache/fop/fo/flow/table/HeaderColumnTestCase.java Zobrazit soubor

/*
* 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;
}

}

binární
test/pdf/accessibility/pdf/background-image_svg_repeat.pdf Zobrazit soubor


binární
test/pdf/accessibility/pdf/background-image_svg_single.pdf Zobrazit soubor


binární
test/pdf/accessibility/pdf/image_svg.pdf Zobrazit soubor


binární
test/pdf/accessibility/pdf/image_wmf.pdf Zobrazit soubor


binární
test/pdf/accessibility/pdf/text_font-embedding.pdf Zobrazit soubor


binární
test/pdf/accessibility/pdf/th_scope.pdf Zobrazit soubor


+ 68
- 0
test/pdf/accessibility/th_scope.fo Zobrazit soubor

<?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>

Načítá se…
Zrušit
Uložit