From 89b98e43e014d7045a548b7f88be265c2621a328 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 25 May 2012 15:15:28 +0000 Subject: [PATCH] Added support for the role property on fo:page-sequence, fo:flow and fo:static-content. This allows to change the mapping of those FOs to PDF structure types when enabling accessibility. Suggested by Martin Koegler as part of Bugzilla #50852 git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1342680 13f79535-47bb-0310-9956-ffa450edef68 --- .../DummyStructureTreeEventHandler.java | 2 +- .../StructureTree2SAXEventAdapter.java | 10 ++- .../StructureTreeEventHandler.java | 3 +- .../fo/StructureTreeEventTrigger.java | 3 +- .../fo/pagination/AbstractPageSequence.java | 15 +++-- .../org/apache/fop/fo/pagination/Flow.java | 14 +++- .../fop/render/intermediate/IFParser.java | 12 +++- .../intermediate/IFStructureTreeBuilder.java | 4 +- .../apache/fop/render/pdf/FOToPDFRoleMap.java | 49 +++++++------- .../pdf/PDFLogicalStructureHandler.java | 21 +----- .../render/pdf/PDFStructureTreeBuilder.java | 67 ++++++++++++------- status.xml | 5 ++ .../IFStructureTreeBuilderTestCase.java | 6 +- test/pdf/accessibility/role.fo | 13 ++-- 14 files changed, 132 insertions(+), 92 deletions(-) diff --git a/src/java/org/apache/fop/accessibility/DummyStructureTreeEventHandler.java b/src/java/org/apache/fop/accessibility/DummyStructureTreeEventHandler.java index 66eaece89..c63c721e5 100644 --- a/src/java/org/apache/fop/accessibility/DummyStructureTreeEventHandler.java +++ b/src/java/org/apache/fop/accessibility/DummyStructureTreeEventHandler.java @@ -34,7 +34,7 @@ public final class DummyStructureTreeEventHandler implements StructureTreeEventH private DummyStructureTreeEventHandler() { } /** {@inheritDoc} */ - public void startPageSequence(Locale locale) { + public void startPageSequence(Locale locale, String role) { } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/accessibility/StructureTree2SAXEventAdapter.java b/src/java/org/apache/fop/accessibility/StructureTree2SAXEventAdapter.java index 79c589f9b..7a375ef20 100644 --- a/src/java/org/apache/fop/accessibility/StructureTree2SAXEventAdapter.java +++ b/src/java/org/apache/fop/accessibility/StructureTree2SAXEventAdapter.java @@ -30,6 +30,7 @@ import org.apache.fop.fo.FOElementMapping; import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.fo.extensions.InternalElementMapping; import org.apache.fop.render.intermediate.IFConstants; +import org.apache.fop.util.XMLConstants; /** * Converts structure tree events to SAX events. @@ -52,16 +53,19 @@ public final class StructureTree2SAXEventAdapter implements StructureTreeEventHa } /** {@inheritDoc} */ - public void startPageSequence(Locale locale) { + public void startPageSequence(Locale locale, String role) { try { - + AttributesImpl attributes = new AttributesImpl(); + if (role != null) { + attributes.addAttribute("", "type", "type", XMLConstants.CDATA, role); + } contentHandler.startPrefixMapping( InternalElementMapping.STANDARD_PREFIX, InternalElementMapping.URI); contentHandler.startPrefixMapping( ExtensionElementMapping.STANDARD_PREFIX, ExtensionElementMapping.URI); contentHandler.startElement(IFConstants.NAMESPACE, IFConstants.EL_STRUCTURE_TREE, IFConstants.EL_STRUCTURE_TREE, - new AttributesImpl()); + attributes); } catch (SAXException e) { throw new RuntimeException(e); } diff --git a/src/java/org/apache/fop/accessibility/StructureTreeEventHandler.java b/src/java/org/apache/fop/accessibility/StructureTreeEventHandler.java index 4b94d61f1..46b724626 100644 --- a/src/java/org/apache/fop/accessibility/StructureTreeEventHandler.java +++ b/src/java/org/apache/fop/accessibility/StructureTreeEventHandler.java @@ -34,8 +34,9 @@ public interface StructureTreeEventHandler { * Starts a page sequence structure tree node. * * @param locale The locale of the page sequence + * @param role the value of the role property. May be null. */ - void startPageSequence(Locale locale); + void startPageSequence(Locale locale, String role); /** * Starts a structure tree node. diff --git a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java index 957f40870..51f7f2bed 100644 --- a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java +++ b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java @@ -89,7 +89,8 @@ class StructureTreeEventTrigger extends FOEventHandler { locale = new Locale(pageSeq.getLanguage()); } } - structureTreeEventHandler.startPageSequence(locale); + String role = pageSeq.getCommonAccessibility().getRole(); + structureTreeEventHandler.startPageSequence(locale, role); } @Override diff --git a/src/java/org/apache/fop/fo/pagination/AbstractPageSequence.java b/src/java/org/apache/fop/fo/pagination/AbstractPageSequence.java index 8640ab19b..d1ccf7273 100644 --- a/src/java/org/apache/fop/fo/pagination/AbstractPageSequence.java +++ b/src/java/org/apache/fop/fo/pagination/AbstractPageSequence.java @@ -24,6 +24,8 @@ import org.apache.fop.datatypes.Numeric; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.properties.CommonAccessibility; +import org.apache.fop.fo.properties.CommonAccessibilityHolder; /** * Abstract base class for the @@ -31,9 +33,8 @@ import org.apache.fop.fo.PropertyList; * * fox:external-document extension object. */ -public abstract class AbstractPageSequence extends FObj { +public abstract class AbstractPageSequence extends FObj implements CommonAccessibilityHolder { - // The value of properties relevant for fo:page-sequence. /** initial page number */ protected Numeric initialPageNumber; /** forced page count */ @@ -42,11 +43,12 @@ public abstract class AbstractPageSequence extends FObj { private int letterValue; private char groupingSeparator; private int groupingSize; - private Numeric referenceOrientation; //XSL 1.1 + private Numeric referenceOrientation; private String language; private String country; private String numberConversionFeatures; - // End of property values + + private CommonAccessibility commonAccessibility; private PageNumberGenerator pageNumberGenerator; @@ -76,6 +78,7 @@ public abstract class AbstractPageSequence extends FObj { language = pList.get(PR_LANGUAGE).getString(); country = pList.get(PR_COUNTRY).getString(); numberConversionFeatures = pList.get(PR_X_NUMBER_CONVERSION_FEATURES).getString(); + commonAccessibility = CommonAccessibility.getInstance(pList); } /** {@inheritDoc} */ @@ -130,6 +133,10 @@ public abstract class AbstractPageSequence extends FObj { return pageNumberGenerator.makeFormattedPageNumber(pageNumber); } + public CommonAccessibility getCommonAccessibility() { + return commonAccessibility; + } + /** * Public accessor for the ancestor Root. * @return the ancestor Root diff --git a/src/java/org/apache/fop/fo/pagination/Flow.java b/src/java/org/apache/fop/fo/pagination/Flow.java index 153f06fc1..981485e32 100644 --- a/src/java/org/apache/fop/fo/pagination/Flow.java +++ b/src/java/org/apache/fop/fo/pagination/Flow.java @@ -26,16 +26,19 @@ import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.properties.CommonAccessibility; +import org.apache.fop.fo.properties.CommonAccessibilityHolder; /** * Class modelling the * fo:flow object. * */ -public class Flow extends FObj { - // The value of properties relevant for fo:flow. +public class Flow extends FObj implements CommonAccessibilityHolder { + private String flowName; - // End of property values + + private CommonAccessibility commonAccessibility; /** used for FO validation */ private boolean blockItemFound = false; @@ -52,6 +55,7 @@ public class Flow extends FObj { public void bind(PropertyList pList) throws FOPException { super.bind(pList); flowName = pList.get(PR_FLOW_NAME).getString(); + commonAccessibility = CommonAccessibility.getInstance(pList); } /** {@inheritDoc} */ @@ -120,6 +124,10 @@ public class Flow extends FObj { return flowName; } + public CommonAccessibility getCommonAccessibility() { + return commonAccessibility; + } + /** {@inheritDoc} */ public String getLocalName() { return "flow"; diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 33e6931de..827eec820 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -156,7 +156,7 @@ public class IFParser implements IFConstants { private ContentHandler navParser; - private ContentHandler structureTreeHandler; + private StructureTreeHandler structureTreeHandler; private Attributes pageSequenceAttributes; @@ -165,12 +165,18 @@ public class IFParser implements IFConstants { private final class StructureTreeHandler extends DefaultHandler { + private final Locale pageSequenceLanguage; + private final StructureTreeEventHandler structureTreeEventHandler; private StructureTreeHandler(StructureTreeEventHandler structureTreeEventHandler, Locale pageSequenceLanguage) throws SAXException { + this.pageSequenceLanguage = pageSequenceLanguage; this.structureTreeEventHandler = structureTreeEventHandler; - structureTreeEventHandler.startPageSequence(pageSequenceLanguage); + } + + void startStructureTree(String type) { + structureTreeEventHandler.startPageSequence(pageSequenceLanguage, type); } public void endDocument() throws SAXException { @@ -263,6 +269,8 @@ public class IFParser implements IFConstants { } else if (localName.equals(EL_STRUCTURE_TREE)) { if (userAgent.isAccessibilityEnabled()) { + String type = attributes.getValue("type"); + structureTreeHandler.startStructureTree(type); delegate = structureTreeHandler; } else { /* Delegate to a handler that does nothing */ diff --git a/src/java/org/apache/fop/render/intermediate/IFStructureTreeBuilder.java b/src/java/org/apache/fop/render/intermediate/IFStructureTreeBuilder.java index 3d9885914..9ba9afd81 100644 --- a/src/java/org/apache/fop/render/intermediate/IFStructureTreeBuilder.java +++ b/src/java/org/apache/fop/render/intermediate/IFStructureTreeBuilder.java @@ -189,11 +189,11 @@ final class IFStructureTreeBuilder implements StructureTreeEventHandler { pageSequenceEventRecorders.get(pageSequenceIndex).replay(handler); } - public void startPageSequence(Locale locale) { + public void startPageSequence(Locale locale, String role) { SAXEventRecorder eventRecorder = new SAXEventRecorder(); pageSequenceEventRecorders.add(eventRecorder); delegate = StructureTree2SAXEventAdapter.newInstance(eventRecorder); - delegate.startPageSequence(locale); + delegate.startPageSequence(locale, role); } public void endPageSequence() { diff --git a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java index 9b76d0620..0f752e886 100644 --- a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java +++ b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java @@ -103,9 +103,9 @@ final class FOToPDFRoleMap { addStructureType("Formula"); addStructureType("Form"); - NON_STRUCT = (PDFName) STANDARD_STRUCTURE_TYPES.get("NonStruct"); + NON_STRUCT = STANDARD_STRUCTURE_TYPES.get("NonStruct"); assert NON_STRUCT != null; - THEAD = (PDFName) STANDARD_STRUCTURE_TYPES.get("THead"); + THEAD = STANDARD_STRUCTURE_TYPES.get("THead"); assert THEAD != null; // Create the standard mappings @@ -155,7 +155,7 @@ final class FOToPDFRoleMap { } private static void addMapping(String fo, String structureType) { - PDFName type = (PDFName) STANDARD_STRUCTURE_TYPES.get(structureType); + PDFName type = STANDARD_STRUCTURE_TYPES.get(structureType); assert type != null; addMapping(fo, new SimpleMapper(type)); } @@ -165,21 +165,6 @@ final class FOToPDFRoleMap { } - /** - * Maps a Formatting Object to a PDFName representing the associated structure type. - * @param fo the formatting object's local name - * @param parent the parent of the structure element to be mapped - * @return the structure type or null if no match could be found - */ - public static PDFName mapFormattingObject(String fo, PDFObject parent) { - Mapper mapper = (Mapper) DEFAULT_MAPPINGS.get(fo); - if (mapper != null) { - return mapper.getStructureType(parent); - } else { - return NON_STRUCT; - } - } - /** * Maps a Formatting Object to a PDFName representing the associated structure type. * @param fo the formatting object's local name @@ -192,11 +177,11 @@ final class FOToPDFRoleMap { PDFObject parent, EventBroadcaster eventBroadcaster) { PDFName type = null; if (role == null) { - type = mapFormattingObject(fo, parent); + type = getDefaultMappingFor(fo, parent); } else { - type = (PDFName) STANDARD_STRUCTURE_TYPES.get(role); + type = STANDARD_STRUCTURE_TYPES.get(role); if (type == null) { - type = mapFormattingObject(fo, parent); + type = getDefaultMappingFor(fo, parent); PDFEventProducer.Provider.get(eventBroadcaster).nonStandardStructureType(fo, fo, role, type.toString().substring(1)); } @@ -205,6 +190,21 @@ final class FOToPDFRoleMap { return type; } + /** + * Maps a Formatting Object to a PDFName representing the associated structure type. + * @param fo the formatting object's local name + * @param parent the parent of the structure element to be mapped + * @return the structure type or NonStruct if no match could be found + */ + private static PDFName getDefaultMappingFor(String fo, PDFObject parent) { + Mapper mapper = DEFAULT_MAPPINGS.get(fo); + if (mapper != null) { + return mapper.getStructureType(parent); + } else { + return NON_STRUCT; + } + } + private interface Mapper { PDFName getStructureType(PDFObject parent); } @@ -226,14 +226,13 @@ final class FOToPDFRoleMap { private static class TableCellMapper implements Mapper { public PDFName getStructureType(PDFObject parent) { - PDFStructElem grandParent = (PDFStructElem) - ((PDFStructElem) parent).getParentStructElem(); + PDFStructElem grandParent = ((PDFStructElem) parent).getParentStructElem(); //TODO What to do with cells from table-footer? Currently they are mapped on TD. PDFName type; if (THEAD.equals(grandParent.getStructureType())) { - type = (PDFName) STANDARD_STRUCTURE_TYPES.get("TH"); + type = STANDARD_STRUCTURE_TYPES.get("TH"); } else { - type = (PDFName) STANDARD_STRUCTURE_TYPES.get("TD"); + type = STANDARD_STRUCTURE_TYPES.get("TD"); } assert type != null; return type; diff --git a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java index 1c9f9b49d..6559e8d56 100644 --- a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java @@ -19,8 +19,6 @@ package org.apache.fop.render.pdf; -import java.util.Locale; - import org.apache.fop.pdf.PDFArray; import org.apache.fop.pdf.PDFDictionary; import org.apache.fop.pdf.PDFDocument; @@ -29,7 +27,6 @@ import org.apache.fop.pdf.PDFName; import org.apache.fop.pdf.PDFPage; import org.apache.fop.pdf.PDFParentTree; import org.apache.fop.pdf.PDFStructElem; -import org.apache.fop.pdf.PDFStructTreeRoot; /** @@ -59,8 +56,6 @@ class PDFLogicalStructureHandler { */ private PDFArray pageParentTreeArray; - private PDFStructElem rootStructureElement; - /** * Class providing the necessary information for bracketing content * associated to a structure element as a marked-content sequence. @@ -95,22 +90,10 @@ class PDFLogicalStructureHandler { */ PDFLogicalStructureHandler(PDFDocument pdfDoc) { this.pdfDoc = pdfDoc; - PDFStructTreeRoot structTreeRoot = pdfDoc.makeStructTreeRoot(parentTree); - rootStructureElement = pdfDoc.makeStructureElement( - FOToPDFRoleMap.mapFormattingObject("root", structTreeRoot), structTreeRoot); - structTreeRoot.addKid(rootStructureElement); } - - PDFStructElem createPageSequence(Locale language) { - PDFStructElem structElemPart = pdfDoc.makeStructureElement( - FOToPDFRoleMap.mapFormattingObject("page-sequence", rootStructureElement), - rootStructureElement); - rootStructureElement.addKid(structElemPart); - if (language != null) { - structElemPart.setLanguage(language); - } - return structElemPart; + PDFParentTree getParentTree() { + return parentTree; } private int getNextParentTreeKey() { diff --git a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java index 2a2a4a392..3839d47bc 100644 --- a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java +++ b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java @@ -29,7 +29,11 @@ import org.apache.fop.accessibility.StructureTreeEventHandler; import org.apache.fop.events.EventBroadcaster; import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.pdf.PDFFactory; +import org.apache.fop.pdf.PDFName; +import org.apache.fop.pdf.PDFObject; +import org.apache.fop.pdf.PDFParentTree; import org.apache.fop.pdf.PDFStructElem; +import org.apache.fop.pdf.PDFStructTreeRoot; class PDFStructureTreeBuilder implements StructureTreeEventHandler { @@ -41,21 +45,42 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { private LinkedList ancestors = new LinkedList(); + private PDFStructElem rootStructureElement; + void setPdfFactory(PDFFactory pdfFactory) { this.pdfFactory = pdfFactory; } void setLogicalStructureHandler(PDFLogicalStructureHandler logicalStructureHandler) { this.logicalStructureHandler = logicalStructureHandler; + createRootStructureElement(); + } + + private void createRootStructureElement() { + assert rootStructureElement == null; + PDFParentTree parentTree = logicalStructureHandler.getParentTree(); + PDFStructTreeRoot structTreeRoot = pdfFactory.getDocument().makeStructTreeRoot(parentTree); + rootStructureElement = createStructureElement("root", structTreeRoot, null); + structTreeRoot.addKid(rootStructureElement); } void setEventBroadcaster(EventBroadcaster eventBroadcaster) { this.eventBroadcaster = eventBroadcaster; } - public void startPageSequence(Locale locale) { + public void startPageSequence(Locale language, String role) { ancestors = new LinkedList(); - ancestors.add(logicalStructureHandler.createPageSequence(locale)); + PDFStructElem structElem = createStructureElement("page-sequence", rootStructureElement, role); + if (language != null) { + structElem.setLanguage(language); + } + rootStructureElement.addKid(structElem); + ancestors.add(structElem); + } + + private PDFStructElem createStructureElement(String name, PDFObject parent, String role) { + PDFName structureType = FOToPDFRoleMap.mapFormattingObject(name, role, parent, eventBroadcaster); + return pdfFactory.getDocument().makeStructureElement(structureType, parent); } public void endPageSequence() { @@ -64,12 +89,10 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { public StructureTreeElement startNode(String name, Attributes attributes) { PDFStructElem parent = ancestors.getFirst(); String role = attributes.getValue("role"); - PDFStructElem created; - created = pdfFactory.getDocument().makeStructureElement( - FOToPDFRoleMap.mapFormattingObject(name, role, parent, eventBroadcaster), parent); - parent.addKid(created); - ancestors.addFirst(created); - return created; + PDFStructElem structElem = createStructureElement(name, parent, role); + parent.addKid(structElem); + ancestors.addFirst(structElem); + return structElem; } public void endNode(String name) { @@ -83,34 +106,30 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { public StructureTreeElement startImageNode(String name, Attributes attributes) { PDFStructElem parent = ancestors.getFirst(); String role = attributes.getValue("role"); - PDFStructElem created; - created = pdfFactory.getDocument().makeStructureElement( - FOToPDFRoleMap.mapFormattingObject(name, role, parent, eventBroadcaster), parent); - parent.addKid(created); + PDFStructElem structElem = createStructureElement(name, parent, role); + parent.addKid(structElem); String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text"); if (altTextNode != null) { - created.put("Alt", altTextNode); + structElem.put("Alt", altTextNode); } else { - created.put("Alt", "No alternate text specified"); + structElem.put("Alt", "No alternate text specified"); } - ancestors.addFirst(created); - return created; + ancestors.addFirst(structElem); + return structElem; } public StructureTreeElement startReferencedNode(String name, Attributes attributes) { PDFStructElem parent = ancestors.getFirst(); String role = attributes.getValue("role"); - PDFStructElem created; + PDFStructElem structElem; if ("#PCDATA".equals(name)) { - created = new PDFStructElem.Placeholder(parent, name); + structElem = new PDFStructElem.Placeholder(parent, name); } else { - created = pdfFactory.getDocument().makeStructureElement( - FOToPDFRoleMap.mapFormattingObject(name, role, parent, - eventBroadcaster), parent); + structElem = createStructureElement(name, parent, role); } - parent.addKid(created); - ancestors.addFirst(created); - return created; + parent.addKid(structElem); + ancestors.addFirst(structElem); + return structElem; } } diff --git a/status.xml b/status.xml index f7186e095..fc5b5c630 100644 --- a/status.xml +++ b/status.xml @@ -63,6 +63,11 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> + + Added support for the role property on fo:page-sequence, fo:flow and fo:static-content. This + allows to change the mapping of those FOs to PDF structure types when enabling + accessibility. + Stop outputting the Type entry for structure elements in order to create a smaller PDF ouptut when accessibility is enabled. diff --git a/test/java/org/apache/fop/render/intermediate/IFStructureTreeBuilderTestCase.java b/test/java/org/apache/fop/render/intermediate/IFStructureTreeBuilderTestCase.java index 65c6b25a6..6819fed79 100644 --- a/test/java/org/apache/fop/render/intermediate/IFStructureTreeBuilderTestCase.java +++ b/test/java/org/apache/fop/render/intermediate/IFStructureTreeBuilderTestCase.java @@ -61,7 +61,7 @@ public class IFStructureTreeBuilderTestCase { // Expected } - sut.startPageSequence(null); + sut.startPageSequence(null, null); sut.endPageSequence(); sut.replayEventsForPageSequence(handler, 0); @@ -89,7 +89,7 @@ public class IFStructureTreeBuilderTestCase { final String nodeName = "block"; final ContentHandler handler = mock(ContentHandler.class); - sut.startPageSequence(null); + sut.startPageSequence(null, null); sut.startNode(nodeName, createSimpleAttributes(attributes)); sut.endPageSequence(); @@ -105,7 +105,7 @@ public class IFStructureTreeBuilderTestCase { final String nodeName = "block"; final ContentHandler handler = mock(ContentHandler.class); - sut.startPageSequence(null); + sut.startPageSequence(null, null); sut.endNode(nodeName); sut.endPageSequence(); diff --git a/test/pdf/accessibility/role.fo b/test/pdf/accessibility/role.fo index ced8a4d44..885638592 100644 --- a/test/pdf/accessibility/role.fo +++ b/test/pdf/accessibility/role.fo @@ -19,12 +19,17 @@ - + page-height="240pt" page-width="320pt" margin="10pt" margin-bottom="8pt"> + + - - + + + + +