private final Stack<FOEventHandler> converters = new Stack<FOEventHandler>();
- private final Stack<FOEventRecorder> tableFooterRecorders = new Stack<FOEventRecorder>();
-
private final FOEventHandler structureTreeEventTrigger;
/** The descendants of some elements like fo:leader must be ignored. */
super.endPageNumberCitationLast(pageLast);
}
+ @Override
+ public void startStatic(StaticContent staticContent) {
+ handleStartArtifact(staticContent);
+ converter.startStatic(staticContent);
+ super.startStatic(staticContent);
+ }
+
+ @Override
+ public void endStatic(StaticContent staticContent) {
+ converter.endStatic(staticContent);
+ handleEndArtifact(staticContent);
+ super.endStatic(staticContent);
+ }
+
@Override
public void startFlow(Flow fl) {
converter.startFlow(fl);
@Override
public void startTable(Table tbl) {
converter.startTable(tbl);
- tableFooterRecorders.push(null);
super.startTable(tbl);
}
@Override
public void endTable(Table tbl) {
- FOEventRecorder tableFooterRecorder = tableFooterRecorders.pop();
- if (tableFooterRecorder != null) {
- tableFooterRecorder.replay(converter);
- }
converter.endTable(tbl);
super.endTable(tbl);
}
@Override
public void startFooter(TableFooter footer) {
- converters.push(converter);
- converter = new FOEventRecorder();
converter.startFooter(footer);
super.startFooter(footer);
}
@Override
public void endFooter(TableFooter footer) {
converter.endFooter(footer);
- /* Replace the dummy table footer with the real one. */
- tableFooterRecorders.pop();
- tableFooterRecorders.push((FOEventRecorder) converter);
- converter = converters.pop();
super.endFooter(footer);
}
super.endListBody(listItemBody);
}
- @Override
- public void startStatic(StaticContent staticContent) {
- handleStartArtifact(staticContent);
- converter.startStatic(staticContent);
- super.startStatic(staticContent);
- }
-
- @Override
- public void endStatic(StaticContent statisContent) {
- converter.endStatic(statisContent);
- handleEndArtifact(statisContent);
- super.endStatic(statisContent);
- }
-
@Override
public void startMarkup() {
converter.startMarkup();
+++ /dev/null
-/*
- * 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.accessibility.fo;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.fop.fo.FOEventHandler;
-import org.apache.fop.fo.FOText;
-import org.apache.fop.fo.flow.BasicLink;
-import org.apache.fop.fo.flow.Block;
-import org.apache.fop.fo.flow.BlockContainer;
-import org.apache.fop.fo.flow.Character;
-import org.apache.fop.fo.flow.ExternalGraphic;
-import org.apache.fop.fo.flow.Footnote;
-import org.apache.fop.fo.flow.FootnoteBody;
-import org.apache.fop.fo.flow.Inline;
-import org.apache.fop.fo.flow.InstreamForeignObject;
-import org.apache.fop.fo.flow.Leader;
-import org.apache.fop.fo.flow.ListBlock;
-import org.apache.fop.fo.flow.ListItem;
-import org.apache.fop.fo.flow.ListItemBody;
-import org.apache.fop.fo.flow.ListItemLabel;
-import org.apache.fop.fo.flow.PageNumber;
-import org.apache.fop.fo.flow.PageNumberCitation;
-import org.apache.fop.fo.flow.PageNumberCitationLast;
-import org.apache.fop.fo.flow.Wrapper;
-import org.apache.fop.fo.flow.table.Table;
-import org.apache.fop.fo.flow.table.TableBody;
-import org.apache.fop.fo.flow.table.TableCell;
-import org.apache.fop.fo.flow.table.TableColumn;
-import org.apache.fop.fo.flow.table.TableFooter;
-import org.apache.fop.fo.flow.table.TableHeader;
-import org.apache.fop.fo.flow.table.TableRow;
-
-final class FOEventRecorder extends FOEventHandler {
-
- private interface Event {
- void replay(FOEventHandler target);
- }
-
- private final List<Event> events = new ArrayList<Event>();
-
- public void replay(FOEventHandler target) {
- for (Event event : events) {
- event.replay(target);
- }
- }
-
- @Override
- public void startPageNumber(final PageNumber pagenum) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startPageNumber(pagenum);
- }
- });
- }
-
- @Override
- public void endPageNumber(final PageNumber pagenum) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endPageNumber(pagenum);
- }
- });
- }
-
- @Override
- public void startPageNumberCitation(final PageNumberCitation pageCite) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startPageNumberCitation(pageCite);
- }
- });
- }
-
- @Override
- public void endPageNumberCitation(final PageNumberCitation pageCite) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endPageNumberCitation(pageCite);
- }
- });
- }
-
- @Override
- public void startPageNumberCitationLast(final PageNumberCitationLast pageLast) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startPageNumberCitationLast(pageLast);
- }
- });
- }
-
- @Override
- public void endPageNumberCitationLast(final PageNumberCitationLast pageLast) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endPageNumberCitationLast(pageLast);
- }
- });
- }
-
- @Override
- public void startBlock(final Block bl) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startBlock(bl);
- }
- });
- }
-
- @Override
- public void endBlock(final Block bl) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endBlock(bl);
- }
- });
- }
-
- @Override
- public void startBlockContainer(final BlockContainer blc) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startBlockContainer(blc);
- }
- });
- }
-
- @Override
- public void endBlockContainer(final BlockContainer blc) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endBlockContainer(blc);
- }
- });
- }
-
- @Override
- public void startInline(final Inline inl) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startInline(inl);
- }
- });
- }
-
- @Override
- public void endInline(final Inline inl) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endInline(inl);
- }
- });
- }
-
- @Override
- public void startTable(final Table tbl) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startTable(tbl);
- }
- });
- }
-
- @Override
- public void endTable(final Table tbl) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endTable(tbl);
- }
- });
- }
-
- @Override
- public void startColumn(final TableColumn tc) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startColumn(tc);
- }
- });
- }
-
- @Override
- public void endColumn(final TableColumn tc) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endColumn(tc);
- }
- });
- }
-
- @Override
- public void startHeader(final TableHeader header) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startHeader(header);
- }
- });
- }
-
- @Override
- public void endHeader(final TableHeader header) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endHeader(header);
- }
- });
- }
-
- @Override
- public void startFooter(final TableFooter footer) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startFooter(footer);
- }
- });
- }
-
- @Override
- public void endFooter(final TableFooter footer) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endFooter(footer);
- }
- });
- }
-
- @Override
- public void startBody(final TableBody body) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startBody(body);
- }
- });
- }
-
- @Override
- public void endBody(final TableBody body) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endBody(body);
- }
- });
- }
-
- @Override
- public void startRow(final TableRow tr) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startRow(tr);
- }
- });
- }
-
- @Override
- public void endRow(final TableRow tr) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endRow(tr);
- }
- });
- }
-
- @Override
- public void startCell(final TableCell tc) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startCell(tc);
- }
- });
- }
-
- @Override
- public void endCell(final TableCell tc) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endCell(tc);
- }
- });
- }
-
- @Override
- public void startList(final ListBlock lb) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startList(lb);
- }
- });
- }
-
- @Override
- public void endList(final ListBlock lb) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endList(lb);
- }
- });
- }
-
- @Override
- public void startListItem(final ListItem li) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startListItem(li);
- }
- });
- }
-
- @Override
- public void endListItem(final ListItem li) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endListItem(li);
- }
- });
- }
-
- @Override
- public void startListLabel(final ListItemLabel listItemLabel) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startListLabel(listItemLabel);
- }
- });
- }
-
- @Override
- public void endListLabel(final ListItemLabel listItemLabel) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endListLabel(listItemLabel);
- }
- });
- }
-
- @Override
- public void startListBody(final ListItemBody listItemBody) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startListBody(listItemBody);
- }
- });
- }
-
- @Override
- public void endListBody(final ListItemBody listItemBody) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endListBody(listItemBody);
- }
- });
- }
-
- @Override
- public void startLink(final BasicLink basicLink) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startLink(basicLink);
- }
- });
- }
-
- @Override
- public void endLink(final BasicLink basicLink) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endLink(basicLink);
- }
- });
- }
-
- @Override
- public void image(final ExternalGraphic eg) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.image(eg);
- }
- });
- }
-
- @Override
- public void startInstreamForeignObject(final InstreamForeignObject ifo) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startInstreamForeignObject(ifo);
- }
- });
- }
-
- @Override
- public void endInstreamForeignObject(final InstreamForeignObject ifo) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endInstreamForeignObject(ifo);
- }
- });
- }
-
- @Override
- public void startFootnote(final Footnote footnote) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startFootnote(footnote);
- }
- });
- }
-
- @Override
- public void endFootnote(final Footnote footnote) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endFootnote(footnote);
- }
- });
- }
-
- @Override
- public void startFootnoteBody(final FootnoteBody body) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startFootnoteBody(body);
- }
- });
- }
-
- @Override
- public void endFootnoteBody(final FootnoteBody body) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endFootnoteBody(body);
- }
- });
- }
-
- @Override
- public void startLeader(final Leader l) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startLeader(l);
- }
- });
- }
-
- @Override
- public void endLeader(final Leader l) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endLeader(l);
- }
- });
- }
-
- @Override
- public void startWrapper(final Wrapper wrapper) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.startWrapper(wrapper);
- }
- });
- }
-
- @Override
- public void endWrapper(final Wrapper wrapper) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.endWrapper(wrapper);
- }
- });
- }
-
- @Override
- public void character(final Character c) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.character(c);
- }
- });
- }
-
- @Override
- public void characters(final FOText foText) {
- events.add(new Event() {
- public void replay(FOEventHandler target) {
- target.characters(foText);
- }
- });
- }
-
-}
import org.apache.fop.fo.flow.table.TableHeader;
import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.pagination.Flow;
+import org.apache.fop.fo.pagination.LayoutMasterSet;
import org.apache.fop.fo.pagination.PageSequence;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fo.properties.CommonAccessibilityHolder;
private StructureTreeEventHandler structureTreeEventHandler;
+ private LayoutMasterSet layoutMasterSet;
+
public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) {
this.structureTreeEventHandler = structureTreeEventHandler;
}
@Override
public void startPageSequence(PageSequence pageSeq) {
+ if (layoutMasterSet == null) {
+ layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet();
+ }
Locale locale = null;
if (pageSeq.getLanguage() != null) {
if (pageSeq.getCountry() != null) {
endElement(pageLast);
}
+ @Override
+ public void startStatic(StaticContent staticContent) {
+ AttributesImpl flowName = createFlowNameAttribute(staticContent.getFlowName());
+ startElement(staticContent, flowName);
+ }
+
+ private AttributesImpl createFlowNameAttribute(String flowName) {
+ String regionName = layoutMasterSet.getDefaultRegionNameFor(flowName);
+ AttributesImpl attribute = new AttributesImpl();
+ addNoNamespaceAttribute(attribute, Flow.FLOW_NAME, regionName);
+ return attribute;
+ }
+
+ @Override
+ public void endStatic(StaticContent staticContent) {
+ endElement(staticContent);
+ }
+
@Override
public void startFlow(Flow fl) {
- startElement(fl);
+ AttributesImpl flowName = createFlowNameAttribute(fl.getFlowName());
+ startElement(fl, flowName);
}
@Override
endElement(listItemBody);
}
- @Override
- public void startStatic(StaticContent staticContent) {
- startElement(staticContent);
- }
-
- @Override
- public void endStatic(StaticContent statisContent) {
- endElement(statisContent);
- }
-
@Override
public void startLink(BasicLink basicLink) {
startElementWithID(basicLink);
delegate.endPageNumberCitationLast(pageLast);
}
+ @Override
+ public void startStatic(StaticContent staticContent) {
+ delegate.startStatic(staticContent);
+ }
+
+ @Override
+ public void endStatic(StaticContent statisContent) {
+ delegate.endStatic(statisContent);
+ }
+
@Override
public void startFlow(Flow fl) {
delegate.startFlow(fl);
delegate.endListBody(listItemBody);
}
- @Override
- public void startStatic(StaticContent staticContent) {
- delegate.startStatic(staticContent);
- }
-
- @Override
- public void endStatic(StaticContent statisContent) {
- delegate.endStatic(statisContent);
- }
-
@Override
public void startMarkup() {
delegate.startMarkup();
public void endPageNumberCitationLast(PageNumberCitationLast pageLast) {
}
+ /**
+ * Process start of a Static.
+ * @param staticContent StaticContent that is starting
+ */
+ public void startStatic(StaticContent staticContent) {
+ }
+
+ /**
+ * Process end of a Static.
+ * @param staticContent StaticContent that is ending
+ */
+ public void endStatic(StaticContent staticContent) {
+ }
+
/**
* This method is called to indicate the start of a new fo:flow
* or fo:static-content.
public void endListBody(ListItemBody listItemBody) {
}
- // Static Regions
- /**
- * Process start of a Static.
- * @param staticContent StaticContent that is starting
- */
- public void startStatic(StaticContent staticContent) {
- }
-
- /**
- * Process end of a Static.
- * @param staticContent StaticContent that is ending
- */
- public void endStatic(StaticContent staticContent) {
- }
-
-
/**
* Process start of a Markup.
*/
import org.apache.fop.datatypes.LengthBase;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.flow.table.TableFObj.ColumnNumberPropertyMaker;
+import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.fo.properties.BackgroundPositionShorthand;
import org.apache.fop.fo.properties.BorderSpacingShorthandParser;
import org.apache.fop.fo.properties.BorderWidthPropertyMaker;
m = new StringProperty.Maker(PR_FLOW_NAME);
m.setInherited(false);
m.setDefault("");
- addPropertyMaker("flow-name", m);
+ addPropertyMaker(Flow.FLOW_NAME, m);
// force-page-count
m = new EnumProperty.Maker(PR_FORCE_PAGE_COUNT);
*/
public class Flow extends FObj implements CommonAccessibilityHolder {
+ /** The "flow-name" property name. */
+ public static final String FLOW_NAME = "flow-name";
+
private String flowName;
private CommonAccessibility commonAccessibility;
/** {@inheritDoc} */
protected void startOfNode() throws FOPException {
if (flowName == null || flowName.equals("")) {
- missingPropertyError("flow-name");
+ missingPropertyError(FLOW_NAME);
}
// according to communication from Paul Grosso (XSL-List,
public int getNameId() {
return FO_LAYOUT_MASTER_SET;
}
+
+ /**
+ * Returns the default name of the region to which the flow or static-content having
+ * the given flow-name is assigned.
+ *
+ * @param flowName the value of the flow-name property
+ * @return the default region name ("xsl-region-body", "xsl-region-before", etc.)
+ */
+ public String getDefaultRegionNameFor(String flowName) {
+ for (SimplePageMaster spm : simplePageMasters.values()) {
+ for (Region region : spm.getRegions().values()) {
+ if (region.getRegionName().equals(flowName)) {
+ return region.getDefaultRegionName();
+ }
+ }
+ }
+ assert flowName.equals("xsl-before-float-separator") || flowName.equals("xsl-footnote-separator");
+ return flowName;
+ }
}
/** {@inheritDoc} */
protected void startOfNode() throws FOPException {
if (getFlowName() == null || getFlowName().equals("")) {
- missingPropertyError("flow-name");
+ missingPropertyError(FLOW_NAME);
}
getFOEventHandler().startStatic(this);
}
}
/**
- * Creates and returns a structure element.
- *
- * @param structureType the structure type of the new element (value for the
- * S entry)
- * @param parent the parent of the new structure element in the structure
- * hierarchy
- * @return a dictionary of type StructElem
+ * Adds the given element to the structure tree.
*/
- public PDFStructElem makeStructureElement(StructureType structureType, PDFObject parent) {
- PDFStructElem structElem = new PDFStructElem(parent, structureType);
+ public void registerStructureElement(PDFStructElem structElem) {
assignObjectNumber(structElem);
structureTreeElements.add(structElem);
- return structElem;
}
/**
- * Creates and returns a structure element.
- *
- * @param structureType the structure type of the new element (value for the
- * S entry)
- * @param parent the parent of the new structure element in the structure
- * hierarchy
- * @param scope the scope of the given table header element
- * @return a dictionary of type StructElem
+ * Assigns the given scope to the given element and adds it to the structure tree. The
+ * scope may not be added if it's not compatible with this document's PDF version.
*/
- public PDFStructElem makeStructureElement(StructureType structureType, PDFObject parent,
- Scope scope) {
- PDFStructElem structElem = makeStructureElement(structureType, parent);
+ public void registerStructureElement(PDFStructElem structElem, Scope scope) {
+ registerStructureElement(structElem);
versionController.addTableHeaderScopeAttribute(structElem, scope);
- return structElem;
}
/**
/**
* Class representing a PDF Structure Element.
*/
-public class PDFStructElem extends PDFDictionary implements StructureTreeElement, CompressedObject {
+public class PDFStructElem extends StructureHierarchyMember
+ implements StructureTreeElement, CompressedObject {
private StructureType structureType;
* @param parent parent of this element
* @param structureType the structure type of this element
*/
- PDFStructElem(PDFObject parent, StructureType structureType) {
+ public PDFStructElem(PDFObject parent, StructureType structureType) {
this(parent);
this.structureType = structureType;
put("S", structureType.getName());
*
* @param kid element to be added
*/
+ @Override
public void addKid(PDFObject kid) {
if (kids == null) {
kids = new ArrayList<PDFObject>();
/**
* Class representing a PDF /StructTreeRoot dictionary.
*/
-public class PDFStructTreeRoot extends PDFDictionary {
+public class PDFStructTreeRoot extends StructureHierarchyMember {
/**
* Creates a new /StructTreeRoot dictionary.
*
* @param kid an object to be added to the K entry
*/
+ @Override
public void addKid(PDFObject kid) {
getKids().add(kid);
}
return name;
}
+ @Override
+ public String toString() {
+ return name.toString().substring(1);
+ }
+
}
private static final Map<String, StructureType> STRUCTURE_TYPES = new HashMap<String, StructureType>();
--- /dev/null
+/*
+ * 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.pdf;
+
+/**
+ * An element in the document's structure tree. This can be either the structure tree root
+ * or a structure element.
+ *
+ * @see "Section 10.6, <q>Logical Structure</q> of the PDF Reference, 4th edition (PDF 1.5)"
+ */
+public abstract class StructureHierarchyMember extends PDFDictionary {
+
+ /**
+ * Adds the given object to the array of kids.
+ *
+ * @param kid an object to be added to the K entry
+ */
+ public abstract void addKid(PDFObject kid);
+
+}
+++ /dev/null
-/*
- * 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.render.pdf;
-
-import java.util.Map;
-
-import org.apache.fop.events.EventBroadcaster;
-import org.apache.fop.pdf.PDFObject;
-import org.apache.fop.pdf.PDFStructElem;
-import org.apache.fop.pdf.StandardStructureTypes;
-import org.apache.fop.pdf.StructureType;
-
-/**
- * This class provides the standard mappings from Formatting Objects to PDF structure types.
- */
-final class FOToPDFRoleMap {
-
- private static final Map<String, Mapper> DEFAULT_MAPPINGS = new java.util.HashMap<String, Mapper>();
-
- static {
- // Create the standard mappings
- // Declarations and Pagination and Layout Formatting Objects
- addMapping("root", StandardStructureTypes.Grouping.DOCUMENT);
- addMapping("page-sequence", StandardStructureTypes.Grouping.PART);
- addMapping("flow", StandardStructureTypes.Grouping.SECT);
- addMapping("static-content", StandardStructureTypes.Grouping.SECT);
- // Block-level Formatting Objects
- addMapping("block", StandardStructureTypes.Paragraphlike.P);
- addMapping("block-container", StandardStructureTypes.Grouping.DIV);
- // Inline-level Formatting Objects
- addMapping("character", StandardStructureTypes.InlineLevelStructure.SPAN);
- addMapping("external-graphic", StandardStructureTypes.Illustration.FIGURE);
- addMapping("instream-foreign-object", StandardStructureTypes.Illustration.FIGURE);
- addMapping("inline", StandardStructureTypes.InlineLevelStructure.SPAN);
- addMapping("inline-container", StandardStructureTypes.Grouping.DIV);
- addMapping("page-number", StandardStructureTypes.InlineLevelStructure.QUOTE);
- addMapping("page-number-citation", StandardStructureTypes.InlineLevelStructure.QUOTE);
- addMapping("page-number-citation-last", StandardStructureTypes.InlineLevelStructure.QUOTE);
- // Formatting Objects for Tables
- addMapping("table-and-caption", StandardStructureTypes.Grouping.DIV);
- addMapping("table", StandardStructureTypes.Table.TABLE);
- addMapping("table-caption", StandardStructureTypes.Grouping.CAPTION);
- addMapping("table-header", StandardStructureTypes.Table.THEAD);
- addMapping("table-footer", StandardStructureTypes.Table.TFOOT);
- addMapping("table-body", StandardStructureTypes.Table.TBODY);
- addMapping("table-row", StandardStructureTypes.Table.TR);
- addMapping("table-cell", new TableCellMapper());
- // Formatting Objects for Lists
- addMapping("list-block", StandardStructureTypes.List.L);
- addMapping("list-item", StandardStructureTypes.List.LI);
- addMapping("list-item-body", StandardStructureTypes.List.LBODY);
- addMapping("list-item-label", StandardStructureTypes.List.LBL);
- // Dynamic Effects: Link and Multi Formatting Objects
- addMapping("basic-link", StandardStructureTypes.InlineLevelStructure.LINK);
- // Out-of-Line Formatting Objects
- addMapping("float", StandardStructureTypes.Grouping.DIV);
- addMapping("footnote", StandardStructureTypes.InlineLevelStructure.NOTE);
- addMapping("footnote-body", StandardStructureTypes.Grouping.SECT);
- addMapping("wrapper", StandardStructureTypes.InlineLevelStructure.SPAN);
- addMapping("marker", StandardStructureTypes.Grouping.PRIVATE);
- }
-
- private static void addMapping(String fo, StructureType structureType) {
- addMapping(fo, new SimpleMapper(structureType));
- }
-
- private static void addMapping(String fo, Mapper mapper) {
- DEFAULT_MAPPINGS.put(fo, mapper);
- }
-
-
- /**
- * Maps a Formatting Object to a PDFName representing the associated structure type.
- * @param fo the formatting object's local name
- * @param role the value of the formatting object's role property
- * @param parent the parent of the structure element to be mapped
- * @param eventBroadcaster the event broadcaster
- * @return the structure type or null if no match could be found
- */
- public static StructureType mapFormattingObject(String fo, String role,
- PDFObject parent, EventBroadcaster eventBroadcaster) {
- StructureType type = null;
- if (role == null) {
- type = getDefaultMappingFor(fo, parent);
- } else {
- type = StandardStructureTypes.get(role);
- if (type == null) {
- type = getDefaultMappingFor(fo, parent);
- PDFEventProducer.Provider.get(eventBroadcaster).nonStandardStructureType(fo,
- fo, role, type.toString().substring(1));
- }
- }
- assert type != null;
- 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 StructureType getDefaultMappingFor(String fo, PDFObject parent) {
- Mapper mapper = DEFAULT_MAPPINGS.get(fo);
- if (mapper != null) {
- return mapper.getStructureType(parent);
- } else {
- return StandardStructureTypes.Grouping.NON_STRUCT;
- }
- }
-
- private interface Mapper {
- StructureType getStructureType(PDFObject parent);
- }
-
- private static class SimpleMapper implements Mapper {
-
- private StructureType structureType;
-
- public SimpleMapper(StructureType structureType) {
- this.structureType = structureType;
- }
-
- public StructureType getStructureType(PDFObject parent) {
- return structureType;
- }
-
- }
-
- private static class TableCellMapper implements Mapper {
-
- public StructureType getStructureType(PDFObject parent) {
- 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) {
- return StandardStructureTypes.Table.TH;
- } else {
- return StandardStructureTypes.Table.TD;
- }
- }
-
- }
-
- private FOToPDFRoleMap() { }
-}
* Custom structure type is not standard as per the PDF reference.
*
* @param source the event source
- * @param fo the local name of the formatting object having the custom type
* @param type custom structure type
* @param fallback default structure type used as a fallback
* @event.severity WARN
*/
- void nonStandardStructureType(Object source, String fo, String type, String fallback);
+ void nonStandardStructureType(Object source, String type, String fallback);
/**
* The encryption length must be a multiple of 8 between 40 and 128.
import java.util.LinkedList;
import java.util.Locale;
+import java.util.Map;
import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributesImpl;
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.pagination.Flow;
import org.apache.fop.pdf.PDFFactory;
-import org.apache.fop.pdf.PDFObject;
import org.apache.fop.pdf.PDFParentTree;
import org.apache.fop.pdf.PDFStructElem;
import org.apache.fop.pdf.PDFStructTreeRoot;
import org.apache.fop.pdf.StandardStructureAttributes.Table.Scope;
+import org.apache.fop.pdf.StandardStructureTypes;
+import org.apache.fop.pdf.StandardStructureTypes.Grouping;
import org.apache.fop.pdf.StandardStructureTypes.Table;
+import org.apache.fop.pdf.StructureHierarchyMember;
import org.apache.fop.pdf.StructureType;
+import org.apache.fop.util.XMLUtil;
class PDFStructureTreeBuilder implements StructureTreeEventHandler {
+ private static final String ROLE = "role";
+
+ private static final Map<String, StructureElementBuilder> BUILDERS
+ = new java.util.HashMap<String, StructureElementBuilder>();
+
+ private static final StructureElementBuilder DEFAULT_BUILDER
+ = new DefaultStructureElementBuilder(Grouping.NON_STRUCT);
+
+ static {
+ // Declarations and Pagination and Layout Formatting Objects
+ StructureElementBuilder regionBuilder = new RegionBuilder();
+ addBuilder("root", StandardStructureTypes.Grouping.DOCUMENT);
+ addBuilder("page-sequence", new PageSequenceBuilder());
+ addBuilder("static-content", regionBuilder);
+ addBuilder("flow", regionBuilder);
+ // Block-level Formatting Objects
+ addBuilder("block", StandardStructureTypes.Paragraphlike.P);
+ addBuilder("block-container", StandardStructureTypes.Grouping.DIV);
+ // Inline-level Formatting Objects
+ addBuilder("character", StandardStructureTypes.InlineLevelStructure.SPAN);
+ addBuilder("external-graphic", new ImageBuilder());
+ addBuilder("instream-foreign-object", new ImageBuilder());
+ addBuilder("inline", StandardStructureTypes.InlineLevelStructure.SPAN);
+ addBuilder("inline-container", StandardStructureTypes.Grouping.DIV);
+ addBuilder("page-number", StandardStructureTypes.InlineLevelStructure.QUOTE);
+ addBuilder("page-number-citation", StandardStructureTypes.InlineLevelStructure.QUOTE);
+ addBuilder("page-number-citation-last", StandardStructureTypes.InlineLevelStructure.QUOTE);
+ // Formatting Objects for Tables
+ addBuilder("table-and-caption", StandardStructureTypes.Grouping.DIV);
+ addBuilder("table", new TableBuilder());
+ addBuilder("table-caption", StandardStructureTypes.Grouping.CAPTION);
+ addBuilder("table-header", StandardStructureTypes.Table.THEAD);
+ addBuilder("table-footer", new TableFooterBuilder());
+ addBuilder("table-body", StandardStructureTypes.Table.TBODY);
+ addBuilder("table-row", StandardStructureTypes.Table.TR);
+ addBuilder("table-cell", new TableCellBuilder());
+ // Formatting Objects for Lists
+ addBuilder("list-block", StandardStructureTypes.List.L);
+ addBuilder("list-item", StandardStructureTypes.List.LI);
+ addBuilder("list-item-body", StandardStructureTypes.List.LBODY);
+ addBuilder("list-item-label", StandardStructureTypes.List.LBL);
+ // Dynamic Effects: Link and Multi Formatting Objects
+ addBuilder("basic-link", StandardStructureTypes.InlineLevelStructure.LINK);
+ // Out-of-Line Formatting Objects
+ addBuilder("float", StandardStructureTypes.Grouping.DIV);
+ addBuilder("footnote", StandardStructureTypes.InlineLevelStructure.NOTE);
+ addBuilder("footnote-body", StandardStructureTypes.Grouping.SECT);
+ addBuilder("wrapper", StandardStructureTypes.InlineLevelStructure.SPAN);
+ addBuilder("marker", StandardStructureTypes.Grouping.PRIVATE);
+
+ addBuilder("#PCDATA", new PlaceholderBuilder());
+ }
+
+ private static void addBuilder(String fo, StructureType structureType) {
+ addBuilder(fo, new DefaultStructureElementBuilder(structureType));
+ }
+
+ private static void addBuilder(String fo, StructureElementBuilder mapper) {
+ BUILDERS.put(fo, mapper);
+ }
+
+ private interface StructureElementBuilder {
+
+ PDFStructElem build(StructureHierarchyMember parent, Attributes attributes, PDFFactory pdfFactory,
+ EventBroadcaster eventBroadcaster);
+
+ }
+
+ private static class DefaultStructureElementBuilder implements StructureElementBuilder {
+
+ private final StructureType defaultStructureType;
+
+ DefaultStructureElementBuilder(StructureType structureType) {
+ this.defaultStructureType = structureType;
+ }
+
+ public final PDFStructElem build(StructureHierarchyMember parent, Attributes attributes,
+ PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) {
+ String role = attributes.getValue(ROLE);
+ StructureType structureType;
+ if (role == null) {
+ structureType = defaultStructureType;
+ } else {
+ structureType = StandardStructureTypes.get(role);
+ if (structureType == null) {
+ structureType = defaultStructureType;
+ PDFEventProducer.Provider.get(eventBroadcaster).nonStandardStructureType(role, role,
+ structureType.toString());
+ }
+ }
+ PDFStructElem structElem = createStructureElement(parent, structureType);
+ setAttributes(structElem, attributes);
+ addKidToParent(structElem, parent, attributes);
+ registerStructureElement(structElem, pdfFactory);
+ return structElem;
+ }
+
+ protected PDFStructElem createStructureElement(StructureHierarchyMember parent,
+ StructureType structureType) {
+ return new PDFStructElem(parent, structureType);
+ }
+
+ protected void setAttributes(PDFStructElem structElem, Attributes attributes) {
+ }
+
+ protected void addKidToParent(PDFStructElem kid, StructureHierarchyMember parent,
+ Attributes attributes) {
+ parent.addKid(kid);
+ }
+
+ protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory) {
+ pdfFactory.getDocument().registerStructureElement(structureElement);
+ }
+
+ }
+
+ private static class PageSequenceBuilder extends DefaultStructureElementBuilder {
+
+ PageSequenceBuilder() {
+ super(StandardStructureTypes.Grouping.PART);
+ }
+
+ @Override
+ protected PDFStructElem createStructureElement(StructureHierarchyMember parent,
+ StructureType structureType) {
+ return new PageSequenceStructElem(parent, structureType);
+ }
+
+ }
+
+ private static class RegionBuilder extends DefaultStructureElementBuilder {
+
+ RegionBuilder() {
+ super(StandardStructureTypes.Grouping.SECT);
+ }
+
+ @Override
+ protected void addKidToParent(PDFStructElem kid, StructureHierarchyMember parent,
+ Attributes attributes) {
+ String flowName = attributes.getValue(Flow.FLOW_NAME);
+ ((PageSequenceStructElem) parent).addContent(flowName, kid);
+ }
+
+ }
+
+ private static class ImageBuilder extends DefaultStructureElementBuilder {
+
+ ImageBuilder() {
+ super(StandardStructureTypes.Illustration.FIGURE);
+ }
+
+ @Override
+ protected void setAttributes(PDFStructElem structElem, Attributes attributes) {
+ String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text");
+ if (altTextNode == null) {
+ altTextNode = "No alternate text specified";
+ }
+ structElem.put("Alt", altTextNode);
+ }
+
+ }
+
+ private static class TableBuilder extends DefaultStructureElementBuilder {
+
+ TableBuilder() {
+ super(StandardStructureTypes.Table.TABLE);
+ }
+
+ @Override
+ protected PDFStructElem createStructureElement(StructureHierarchyMember parent,
+ StructureType structureType) {
+ return new TableStructElem(parent, structureType);
+ }
+ }
+
+ private static class TableFooterBuilder extends DefaultStructureElementBuilder {
+
+ public TableFooterBuilder() {
+ super(StandardStructureTypes.Table.TFOOT);
+ }
+
+ @Override
+ protected void addKidToParent(PDFStructElem kid, StructureHierarchyMember parent,
+ Attributes attributes) {
+ ((TableStructElem) parent).addTableFooter(kid);
+ }
+ }
+
+ private static class TableCellBuilder extends DefaultStructureElementBuilder {
+
+ TableCellBuilder() {
+ super(StandardStructureTypes.Table.TD);
+ }
+
+ @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) {
+ if (structureElement.getStructureType() == Table.TH) {
+ pdfFactory.getDocument().registerStructureElement(structureElement, Scope.COLUMN);
+ } else {
+ pdfFactory.getDocument().registerStructureElement(structureElement);
+ }
+ }
+
+ @Override
+ protected void setAttributes(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));
+ }
+ }
+
+ }
+
+ private static class PlaceholderBuilder implements StructureElementBuilder {
+
+ public PDFStructElem build(StructureHierarchyMember parent, Attributes attributes,
+ PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) {
+ PDFStructElem elem = new PDFStructElem.Placeholder(parent);
+ parent.addKid(elem);
+ return elem;
+ }
+
+ }
+
private PDFFactory pdfFactory;
private EventBroadcaster eventBroadcaster;
this.pdfFactory = pdfFactory;
}
+ void setEventBroadcaster(EventBroadcaster eventBroadcaster) {
+ this.eventBroadcaster = eventBroadcaster;
+ }
+
void setLogicalStructureHandler(PDFLogicalStructureHandler logicalStructureHandler) {
createRootStructureElement(logicalStructureHandler);
}
assert rootStructureElement == null;
PDFParentTree parentTree = logicalStructureHandler.getParentTree();
PDFStructTreeRoot structTreeRoot = pdfFactory.getDocument().makeStructTreeRoot(parentTree);
- rootStructureElement = createStructureElement("root", structTreeRoot, null);
- structTreeRoot.addKid(rootStructureElement);
+ rootStructureElement = createStructureElement("root", structTreeRoot,
+ new AttributesImpl(), pdfFactory, eventBroadcaster);
}
- void setEventBroadcaster(EventBroadcaster eventBroadcaster) {
- this.eventBroadcaster = eventBroadcaster;
- }
+ private static PDFStructElem createStructureElement(String name, StructureHierarchyMember parent,
+ Attributes attributes, PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) {
+ StructureElementBuilder builder = BUILDERS.get(name);
+ if (builder == null) {
+ // TODO is a fallback really necessary?
+ builder = DEFAULT_BUILDER;
+ }
+ return builder.build(parent, attributes, pdfFactory, eventBroadcaster);
+ }
public void startPageSequence(Locale language, String role) {
ancestors = new LinkedList<PDFStructElem>();
- PDFStructElem structElem = createStructureElement("page-sequence", rootStructureElement, role);
+ AttributesImpl attributes = new AttributesImpl();
+ attributes.addAttribute("", ROLE, ROLE, XMLUtil.CDATA, role);
+ PDFStructElem structElem = createStructureElement("page-sequence",
+ rootStructureElement, attributes, pdfFactory, eventBroadcaster);
if (language != null) {
structElem.setLanguage(language);
}
- rootStructureElement.addKid(structElem);
ancestors.add(structElem);
}
- private PDFStructElem createStructureElement(String name, PDFObject parent, String role) {
- StructureType structureType = FOToPDFRoleMap.mapFormattingObject(name, role, parent,
- eventBroadcaster);
- if (structureType == Table.TH) {
- return pdfFactory.getDocument().makeStructureElement(structureType, parent, Scope.COLUMN);
- } else {
- return pdfFactory.getDocument().makeStructureElement(structureType, parent);
- }
- }
-
public void endPageSequence() {
}
public StructureTreeElement startNode(String name, Attributes attributes) {
PDFStructElem parent = ancestors.getFirst();
- String role = attributes.getValue("role");
- PDFStructElem structElem = createStructureElement(name, parent, role);
- setSpanAttributes(structElem, attributes);
- parent.addKid(structElem);
+ PDFStructElem structElem = createStructureElement(name, parent, attributes,
+ pdfFactory, eventBroadcaster);
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();
- }
-
- private void removeFirstAncestor() {
ancestors.removeFirst();
}
public StructureTreeElement startImageNode(String name, Attributes attributes) {
- PDFStructElem parent = ancestors.getFirst();
- String role = attributes.getValue("role");
- PDFStructElem structElem = createStructureElement(name, parent, role);
- parent.addKid(structElem);
- String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text");
- if (altTextNode != null) {
- structElem.put("Alt", altTextNode);
- } else {
- structElem.put("Alt", "No alternate text specified");
- }
- ancestors.addFirst(structElem);
- return structElem;
+ return startNode(name, attributes);
}
public StructureTreeElement startReferencedNode(String name, Attributes attributes) {
- PDFStructElem parent = ancestors.getFirst();
- String role = attributes.getValue("role");
- PDFStructElem structElem;
- if ("#PCDATA".equals(name)) {
- structElem = new PDFStructElem.Placeholder(parent);
- } else {
- structElem = createStructureElement(name, parent, role);
- }
- parent.addKid(structElem);
- ancestors.addFirst(structElem);
- return structElem;
+ return startNode(name, attributes);
}
}
--- /dev/null
+/*
+ * 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.render.pdf;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.fop.pdf.PDFArray;
+import org.apache.fop.pdf.PDFObject;
+import org.apache.fop.pdf.PDFStructElem;
+import org.apache.fop.pdf.StructureType;
+
+class PageSequenceStructElem extends PDFStructElem {
+
+ private List<PDFStructElem> regionBefores = new ArrayList<PDFStructElem>();
+
+ private List<PDFStructElem> regionAfters = new ArrayList<PDFStructElem>();
+
+ private List<PDFStructElem> regionStarts = new ArrayList<PDFStructElem>();
+
+ private List<PDFStructElem> regionEnds = new ArrayList<PDFStructElem>();
+
+ PageSequenceStructElem(PDFObject parent, StructureType structureType) {
+ super(parent, structureType);
+ }
+
+ void addContent(String flowName, PDFStructElem content) {
+ if (flowName.equals("xsl-region-before")) {
+ regionBefores.add(content);
+ } else if (flowName.equals("xsl-region-after")) {
+ regionAfters.add(content);
+ } else if (flowName.equals("xsl-region-start")) {
+ regionStarts.add(content);
+ } else if (flowName.equals("xsl-region-end")) {
+ regionEnds.add(content);
+ } else {
+ addKid(content);
+ }
+ }
+
+ @Override
+ protected boolean attachKids() {
+ assert !kids.isEmpty();
+ PDFArray k = new PDFArray();
+ addRegions(k, regionBefores);
+ addRegions(k, regionStarts);
+ addRegions(k, kids);
+ addRegions(k, regionEnds);
+ addRegions(k, regionAfters);
+ put("K", k);
+ return true;
+ }
+
+ private void addRegions(PDFArray k, List<? extends PDFObject> regions) {
+ if (!regions.isEmpty()) {
+ for (PDFObject kid : regions) {
+ k.add(kid);
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.render.pdf;
+
+import org.apache.fop.pdf.PDFObject;
+import org.apache.fop.pdf.PDFStructElem;
+import org.apache.fop.pdf.StructureType;
+
+class TableStructElem extends PDFStructElem {
+
+ private PDFStructElem tableFooter;
+
+ public TableStructElem(PDFObject parent, StructureType structureType) {
+ super(parent, structureType);
+ }
+
+ void addTableFooter(PDFStructElem footer) {
+ assert tableFooter == null;
+ tableFooter = footer;
+ }
+
+ @Override
+ protected boolean attachKids() {
+ assert !kids.isEmpty();
+ if (tableFooter != null) {
+ kids.add(tableFooter);
+ }
+ return super.attachKids();
+ }
+
+}
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="fix" fixes-bug="53778">
+ When PDF accessibility is enabled, the contents for the different regions must appear in the
+ proper order in the structure tree.
+ </action>
<action context="Renderers" dev="MH" type="fix" fixes-bug="53766" due-to="Robert Meyer">
Remove StandardEncoding as the encoding type from fonts used in the PDF renderer
</action>
package org.apache.fop.accessibility.fo;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
-import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.custommonkey.xmlunit.Diff;
public class FO2StructureTreeConverterTestCase {
- private interface FOLoader {
+ private static class FOLoader {
- InputStream getFoInputStream();
+ private final String resourceName;
+
+ FOLoader(String resourceName) {
+ this.resourceName = resourceName;
+ }
+
+ public InputStream getFoInputStream() {
+ return getResource(resourceName);
+ }
}
private static final String STRUCTURE_TREE_SEQUENCE_NAME = "structure-tree-sequence";
@Test
public void testCompleteDocument() throws Exception {
- foLoader = new FOLoader() {
- public InputStream getFoInputStream() {
- return getResource("/org/apache/fop/fo/complete_document.fo");
- }
- };
- testConverter();
+ testConverter("/org/apache/fop/fo/complete_document.fo");
}
@Test
public void testTableFooters() throws Exception {
- foLoader = new FOLoader() {
- public InputStream getFoInputStream() {
- return getResource("table-footers.fo");
- }
- };
- testConverter();
- }
-
- @Test
- public void testCompleteContentWrappedInTableFooter() throws Exception {
- Source xslt = new StreamSource(getResource("wrapCompleteDocumentInTableFooter.xsl"));
- Transformer transformer = createTransformer(xslt);
- InputStream originalFO = getResource("/org/apache/fop/fo/complete_document.fo");
- ByteArrayOutputStream transformedFoOutput = new ByteArrayOutputStream();
- transformer.transform(new StreamSource(originalFO), new StreamResult(transformedFoOutput));
- final byte[] transformedFoOutputBytes = transformedFoOutput.toByteArray();
- foLoader = new FOLoader() {
- public InputStream getFoInputStream() {
- return new ByteArrayInputStream(transformedFoOutputBytes);
- }
- };
- testConverter();
+ testConverter("table-footers.fo");
}
@Test
public void testArtifact() throws Exception {
- foLoader = new FOLoader() {
-
- public InputStream getFoInputStream() {
- return getResource("artifact.fo");
- }
- };
- testConverter();
+ testConverter("artifact.fo");
}
- private Transformer createTransformer(Source xslt) throws TransformerFactoryConfigurationError,
- TransformerConfigurationException {
- TransformerFactory transformerFactory = TransformerFactory.newInstance();
- return transformerFactory.newTransformer(xslt);
+ @Test
+ public void testSideRegions() throws Exception {
+ testConverter("/org/apache/fop/fo/pagination/side-regions.fo");
}
private static InputStream getResource(String name) {
return FO2StructureTreeConverterTestCase.class.getResourceAsStream(name);
}
- private void testConverter() throws Exception {
+ private void testConverter(String foResourceName) throws Exception {
+ foLoader = new FOLoader(foResourceName);
DOMResult expectedStructureTree = loadExpectedStructureTree();
DOMResult actualStructureTree = buildActualStructureTree();
final Diff diff = createDiff(expectedStructureTree, actualStructureTree);
<xsl:call-template name="copy"/>
</xsl:template>
+ <xsl:template match="fo:static-content/@flow-name|fo:flow/@flow-name">
+ <xsl:choose>
+ <xsl:when test=". = 'xsl-region-body' or
+ . = 'xsl-region-before' or
+ . = 'xsl-region-after' or
+ . = 'xsl-region-start' or
+ . = 'xsl-region-end' or
+ . = 'xsl-before-float-separator' or
+ . = 'xsl-footnote-separator'">
+ <xsl:copy/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="{local-name()}">
+ <xsl:value-of select="concat('xsl-', local-name(//*[@region-name = current()]))"/>
+ </xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
<!-- Block-level Formatting Objects -->
<xsl:template match="fo:block|fo:block-container">
<xsl:call-template name="copy"/>
<xsl:call-template name="copy"/>
</xsl:template>
- <xsl:template match="fo:table">
- <xsl:copy>
- <xsl:apply-templates select="@*"/>
- <xsl:apply-templates select="*[name() != 'fo:table-footer']"/>
- <xsl:apply-templates select="fo:table-footer"/>
- </xsl:copy>
- </xsl:template>
-
- <xsl:template match="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|fo:table-cell">
<xsl:call-template name="copy"/>
</xsl:template>
+++ /dev/null
-<?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$ -->
-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:fo="http://www.w3.org/1999/XSL/Format">
-
- <xsl:template match="@*|node()" name="copy">
- <xsl:copy>
- <xsl:apply-templates select="@*|node()"/>
- </xsl:copy>
- </xsl:template>
-
-
- <xsl:template match="/">
- <fo:root>
- <fo:layout-master-set>
- <fo:simple-page-master master-name="page"
- page-height="500pt" page-width="300pt" margin="20pt">
- <fo:region-body margin-top="20pt"/>
- </fo:simple-page-master>
- </fo:layout-master-set>
- <xsl:apply-templates select="//fo:page-sequence"/>
- </fo:root>
- </xsl:template>
-
- <xsl:template match="fo:page-sequence">
- <fo:page-sequence master-reference="page">
- <xsl:apply-templates select="fo:flow"/>
- </fo:page-sequence>
- </xsl:template>
-
- <xsl:template match="fo:flow">
- <xsl:copy>
- <xsl:apply-templates select="@*[not(starts-with(name(), 'space-before'))]"/>
- <fo:table width="100%" table-layout="fixed">
- <fo:table-footer>
- <fo:table-cell background-color="#F0F0F0">
- <xsl:apply-templates select="@*[starts-with(name(), 'space-before')]"/>
- <xsl:apply-templates select="*"/>
- </fo:table-cell>
- </fo:table-footer>
- <fo:table-body>
- <fo:table-cell>
- <fo:block>The content below is in the table footer.</fo:block>
- </fo:table-cell>
- </fo:table-body>
- </fo:table>
- </xsl:copy>
- </xsl:template>
-
-</xsl:stylesheet>
--- /dev/null
+/*
+ * 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.pagination;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fo.FODocumentParser;
+import org.apache.fop.fo.FODocumentParser.FOEventHandlerFactory;
+import org.apache.fop.fo.FOEventHandler;
+
+public class LayoutMasterSetTestCase {
+
+ private static class FlowMappingTester extends FOEventHandler {
+
+ private static final String[][] FLOW_MAPPINGS = {
+
+ {"first-page-before", "xsl-region-before"},
+ {"first-page-after", "xsl-region-after"},
+ {"first-page-start", "xsl-region-start"},
+ {"first-page-end", "xsl-region-end"},
+
+ {"odd-page-before", "xsl-region-before"},
+ {"odd-page-after", "xsl-region-after"},
+ {"odd-page-start", "xsl-region-start"},
+ {"odd-page-end", "xsl-region-end"},
+
+ {"odd-page-before", "xsl-region-before"},
+ {"odd-page-after", "xsl-region-after"},
+ {"odd-page-start", "xsl-region-start"},
+ {"odd-page-end", "xsl-region-end"},
+
+ {"blank-page-before", "xsl-region-before"},
+ {"blank-page-after", "xsl-region-after"},
+ {"blank-page-start", "xsl-region-start"},
+ {"blank-page-end", "xsl-region-end"},
+
+ {"last-page-before", "xsl-region-before"},
+ {"last-page-after", "xsl-region-after"},
+ {"last-page-start", "xsl-region-start"},
+ {"last-page-end", "xsl-region-end"},
+
+ {"xsl-footnote-separator", "xsl-footnote-separator"}
+
+ };
+
+ FlowMappingTester(FOUserAgent userAgent) {
+ super(userAgent);
+ }
+
+ @Override
+ public void startPageSequence(PageSequence pageSeq) {
+ super.startPageSequence(pageSeq);
+ LayoutMasterSet layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet();
+ for (String[] mapping : FLOW_MAPPINGS) {
+ assertEquals(mapping[1], layoutMasterSet.getDefaultRegionNameFor(mapping[0]));
+ }
+ }
+
+ }
+
+ /**
+ * Tests the {@link LayoutMasterSet#getDefaultRegionNameFor(String)} method.
+ */
+ @Test
+ public void testFlowMapping() throws Exception {
+ FODocumentParser foDocumentParser = FODocumentParser.newInstance(new FOEventHandlerFactory() {
+
+ public FOEventHandler newFOEventHandler(FOUserAgent foUserAgent) {
+ return new FlowMappingTester(foUserAgent);
+ }
+ });
+ foDocumentParser.parse(getClass().getResourceAsStream("side-regions.fo"));
+ }
+
+}
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="first-page"
+ page-height="100pt" page-width="150pt">
+ <fo:region-body margin="12pt" display-align="center" background-color="#FFF0F0"/>
+ <fo:region-before region-name="first-page-before" extent="10pt" precedence="true"
+ display-align="after"/>
+ <fo:region-after region-name="first-page-after" extent="10pt" precedence="true"/>
+ <fo:region-start region-name="first-page-start" extent="10pt" reference-orientation="90"
+ display-align="after"/>
+ <fo:region-end region-name="first-page-end" extent="10pt" reference-orientation="-90"
+ display-align="after"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="odd-page"
+ page-height="100pt" page-width="150pt">
+ <fo:region-body margin="12pt" display-align="center" background-color="#FFFFF0"/>
+ <fo:region-before region-name="odd-page-before" extent="10pt" precedence="true"
+ display-align="after"/>
+ <fo:region-after region-name="odd-page-after" extent="10pt" precedence="true"/>
+ <fo:region-start region-name="odd-page-start" extent="10pt" reference-orientation="90"
+ display-align="after"/>
+ <fo:region-end region-name="odd-page-end" extent="10pt" reference-orientation="-90"
+ display-align="after"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="even-page"
+ page-height="100pt" page-width="150pt">
+ <fo:region-body margin="12pt" display-align="center" background-color="#F0FFF0"/>
+ <fo:region-before region-name="even-page-before" extent="10pt" precedence="true"
+ display-align="after"/>
+ <fo:region-after region-name="even-page-after" extent="10pt" precedence="true"/>
+ <fo:region-start region-name="even-page-start" extent="10pt" reference-orientation="90"
+ display-align="after"/>
+ <fo:region-end region-name="even-page-end" extent="10pt" reference-orientation="-90"
+ display-align="after"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="blank-page"
+ page-height="100pt" page-width="150pt">
+ <fo:region-body margin="12pt" display-align="center" background-color="#F0F0F0"/>
+ <fo:region-before region-name="blank-page-before" extent="10pt" precedence="true"
+ display-align="after"/>
+ <fo:region-after region-name="blank-page-after" extent="10pt" precedence="true"/>
+ <fo:region-start region-name="blank-page-start" extent="10pt" reference-orientation="90"
+ display-align="after"/>
+ <fo:region-end region-name="blank-page-end" extent="10pt" reference-orientation="-90"
+ display-align="after"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="last-page"
+ page-height="100pt" page-width="150pt">
+ <fo:region-body margin="45pt 12pt" display-align="center" background-color="#F0F0FF"/>
+ <fo:region-before region-name="last-page-before" extent="10pt" precedence="true"
+ display-align="after"/>
+ <fo:region-after region-name="last-page-after" extent="10pt" precedence="true"/>
+ <fo:region-start region-name="last-page-start" extent="10pt" reference-orientation="90"
+ display-align="after"/>
+ <fo:region-end region-name="last-page-end" extent="10pt" reference-orientation="-90"
+ display-align="after"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="pages">
+ <fo:repeatable-page-master-alternatives>
+ <fo:conditional-page-master-reference page-position="first" master-reference="first-page"/>
+ <fo:conditional-page-master-reference page-position="last" master-reference="last-page"/>
+ <fo:conditional-page-master-reference blank-or-not-blank="blank"
+ master-reference="blank-page"/>
+ <fo:conditional-page-master-reference odd-or-even="odd" master-reference="odd-page"/>
+ <fo:conditional-page-master-reference odd-or-even="even" master-reference="even-page"/>
+ </fo:repeatable-page-master-alternatives>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="pages" force-page-count="even" font-size="4pt"
+ text-align="center">
+
+ <fo:static-content flow-name="first-page-before">
+ <fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid red"
+ padding-bottom="0.5pt">First Page Before.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="first-page-after">
+ <fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid red"
+ padding-top="0.5pt">First Page After.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="first-page-start">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid red"
+ padding-bottom="0.5pt">First Page Start.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="first-page-end">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid red"
+ padding-bottom="0.5pt">First Page End.</fo:block>
+ </fo:static-content>
+
+ <fo:static-content flow-name="odd-page-after">
+ <fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid orange"
+ padding-top="0.5pt">Odd Page After.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="odd-page-end">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid orange"
+ padding-bottom="0.5pt">Odd Page End.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="odd-page-start">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid orange"
+ padding-bottom="0.5pt">Odd Page Start.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="odd-page-before">
+ <fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid orange"
+ padding-bottom="0.5pt">Odd Page Before.</fo:block>
+ </fo:static-content>
+
+ <fo:static-content flow-name="even-page-end">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid green"
+ padding-bottom="0.5pt">Even Page End.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="even-page-start">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid green"
+ padding-bottom="0.5pt">Even Page Start.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="even-page-after">
+ <fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid green"
+ padding-top="0.5pt">Even Page After.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="even-page-before">
+ <fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid green"
+ padding-bottom="0.5pt">Even Page Before.</fo:block>
+ </fo:static-content>
+
+ <fo:static-content flow-name="blank-page-start">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid black"
+ padding-bottom="0.5pt">Blank Page Start.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="blank-page-after">
+ <fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid black"
+ padding-top="0.5pt">Blank Page After.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="blank-page-before">
+ <fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid black"
+ padding-bottom="0.5pt">Blank Page Before.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="blank-page-end">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid black"
+ padding-bottom="0.5pt">Blank Page End.</fo:block>
+ </fo:static-content>
+
+ <fo:static-content flow-name="last-page-before">
+ <fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid blue"
+ padding-bottom="0.5pt">Last Page Before.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="last-page-end">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid blue"
+ padding-bottom="0.5pt">Last Page End.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="last-page-after">
+ <fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid blue"
+ padding-top="0.5pt">Last Page After.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="last-page-start">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid blue"
+ padding-bottom="0.5pt">Last Page Start.</fo:block>
+ </fo:static-content>
+
+ <fo:static-content flow-name="xsl-footnote-separator">
+ <fo:block>
+ <fo:leader leader-pattern="rule" leader-length="40%" rule-thickness="0.5pt"/>
+ </fo:block>
+ </fo:static-content>
+
+ <fo:flow flow-name="xsl-region-body" font-size="8pt" line-height="10pt">
+ <fo:block>Apache™ FOP (Formatting Objects Processor) is a print formatter driven by XSL
+ formatting objects (XSL-FO) and an output independent formatter.</fo:block>
+ <fo:block break-before="page">It is an application<fo:footnote><fo:inline>*</fo:inline>
+ <fo:footnote-body><fo:block font-size="80%">* written in
+ Java</fo:block></fo:footnote-body></fo:footnote> that reads a formatting object (FO)
+ tree and renders the resulting pages to a specified output.</fo:block>
+ <fo:block break-before="page">The FOP project is part of the Apache Software Foundation, which
+ is a wider community of users and developers of open source projects.</fo:block>
+ <fo:block break-before="page">Apache™ FOP (Formatting Objects Processor) is a print formatter
+ driven by XSL formatting objects (XSL-FO) and an output independent formatter.</fo:block>
+ <fo:block break-before="page">It is a Java application that reads a formatting object (FO)
+ tree and renders the resulting pages to a specified output.</fo:block>
+ <fo:block break-before="page">The FOP project is part of the Apache Software Foundation, which
+ is a wider community of users and developers of open source projects.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>
VersionController controller = mock(VersionController.class);
PDFDocument document = new PDFDocument("Test", controller);
document.makeStructTreeRoot(null);
- document.makeStructureElement(Table.TH, null, scope);
+ PDFStructElem th = new PDFStructElem(null, Table.TH);
+ document.registerStructureElement(th, scope);
verify(controller).addTableHeaderScopeAttribute(any(PDFStructElem.class), eq(scope));
}
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="first-page"
+ page-height="100pt" page-width="150pt">
+ <fo:region-body margin="12pt" display-align="center" background-color="#FFF0F0"/>
+ <fo:region-before region-name="first-page-before" extent="10pt" precedence="true"
+ display-align="after"/>
+ <fo:region-after region-name="first-page-after" extent="10pt" precedence="true"/>
+ <fo:region-start region-name="first-page-start" extent="10pt" reference-orientation="90"
+ display-align="after"/>
+ <fo:region-end region-name="first-page-end" extent="10pt" reference-orientation="-90"
+ display-align="after"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="odd-page"
+ page-height="100pt" page-width="150pt">
+ <fo:region-body margin="12pt" display-align="center" background-color="#FFFFF0"/>
+ <fo:region-before region-name="odd-page-before" extent="10pt" precedence="true"
+ display-align="after"/>
+ <fo:region-after region-name="odd-page-after" extent="10pt" precedence="true"/>
+ <fo:region-start region-name="odd-page-start" extent="10pt" reference-orientation="90"
+ display-align="after"/>
+ <fo:region-end region-name="odd-page-end" extent="10pt" reference-orientation="-90"
+ display-align="after"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="even-page"
+ page-height="100pt" page-width="150pt">
+ <fo:region-body margin="12pt" display-align="center" background-color="#F0FFF0"/>
+ <fo:region-before region-name="even-page-before" extent="10pt" precedence="true"
+ display-align="after"/>
+ <fo:region-after region-name="even-page-after" extent="10pt" precedence="true"/>
+ <fo:region-start region-name="even-page-start" extent="10pt" reference-orientation="90"
+ display-align="after"/>
+ <fo:region-end region-name="even-page-end" extent="10pt" reference-orientation="-90"
+ display-align="after"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="blank-page"
+ page-height="100pt" page-width="150pt">
+ <fo:region-body margin="12pt" display-align="center" background-color="#F0F0F0"/>
+ <fo:region-before region-name="blank-page-before" extent="10pt" precedence="true"
+ display-align="after"/>
+ <fo:region-after region-name="blank-page-after" extent="10pt" precedence="true"/>
+ <fo:region-start region-name="blank-page-start" extent="10pt" reference-orientation="90"
+ display-align="after"/>
+ <fo:region-end region-name="blank-page-end" extent="10pt" reference-orientation="-90"
+ display-align="after"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="last-page"
+ page-height="100pt" page-width="150pt">
+ <fo:region-body margin="45pt 12pt" display-align="center" background-color="#F0F0FF"/>
+ <fo:region-before region-name="last-page-before" extent="10pt" precedence="true"
+ display-align="after"/>
+ <fo:region-after region-name="last-page-after" extent="10pt" precedence="true"/>
+ <fo:region-start region-name="last-page-start" extent="10pt" reference-orientation="90"
+ display-align="after"/>
+ <fo:region-end region-name="last-page-end" extent="10pt" reference-orientation="-90"
+ display-align="after"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="pages">
+ <fo:repeatable-page-master-alternatives>
+ <fo:conditional-page-master-reference page-position="first" master-reference="first-page"/>
+ <fo:conditional-page-master-reference page-position="last" master-reference="last-page"/>
+ <fo:conditional-page-master-reference blank-or-not-blank="blank"
+ master-reference="blank-page"/>
+ <fo:conditional-page-master-reference odd-or-even="odd" master-reference="odd-page"/>
+ <fo:conditional-page-master-reference odd-or-even="even" master-reference="even-page"/>
+ </fo:repeatable-page-master-alternatives>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="pages" force-page-count="even" font-size="4pt"
+ text-align="center">
+
+ <fo:static-content flow-name="first-page-before">
+ <fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid red"
+ padding-bottom="0.5pt">First Page Before.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="first-page-after">
+ <fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid red"
+ padding-top="0.5pt">First Page After.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="first-page-start">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid red"
+ padding-bottom="0.5pt">First Page Start.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="first-page-end">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid red"
+ padding-bottom="0.5pt">First Page End.</fo:block>
+ </fo:static-content>
+
+ <fo:static-content flow-name="odd-page-after">
+ <fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid orange"
+ padding-top="0.5pt">Odd Page After.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="odd-page-end">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid orange"
+ padding-bottom="0.5pt">Odd Page End.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="odd-page-start">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid orange"
+ padding-bottom="0.5pt">Odd Page Start.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="odd-page-before">
+ <fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid orange"
+ padding-bottom="0.5pt">Odd Page Before.</fo:block>
+ </fo:static-content>
+
+ <fo:static-content flow-name="even-page-end">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid green"
+ padding-bottom="0.5pt">Even Page End.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="even-page-start">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid green"
+ padding-bottom="0.5pt">Even Page Start.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="even-page-after">
+ <fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid green"
+ padding-top="0.5pt">Even Page After.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="even-page-before">
+ <fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid green"
+ padding-bottom="0.5pt">Even Page Before.</fo:block>
+ </fo:static-content>
+
+ <fo:static-content flow-name="blank-page-start">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid black"
+ padding-bottom="0.5pt">Blank Page Start.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="blank-page-after">
+ <fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid black"
+ padding-top="0.5pt">Blank Page After.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="blank-page-before">
+ <fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid black"
+ padding-bottom="0.5pt">Blank Page Before.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="blank-page-end">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid black"
+ padding-bottom="0.5pt">Blank Page End.</fo:block>
+ </fo:static-content>
+
+ <fo:static-content flow-name="last-page-before">
+ <fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid blue"
+ padding-bottom="0.5pt">Last Page Before.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="last-page-end">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid blue"
+ padding-bottom="0.5pt">Last Page End.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="last-page-after">
+ <fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid blue"
+ padding-top="0.5pt">Last Page After.</fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="last-page-start">
+ <fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid blue"
+ padding-bottom="0.5pt">Last Page Start.</fo:block>
+ </fo:static-content>
+
+ <fo:static-content flow-name="xsl-footnote-separator">
+ <fo:block>
+ <fo:leader leader-pattern="rule" leader-length="40%" rule-thickness="0.5pt"/>
+ </fo:block>
+ </fo:static-content>
+
+ <fo:flow flow-name="xsl-region-body" font-size="8pt" line-height="10pt">
+ <fo:block>Apache™ FOP (Formatting Objects Processor) is a print formatter driven by XSL
+ formatting objects (XSL-FO) and an output independent formatter.</fo:block>
+ <fo:block break-before="page">It is an application<fo:footnote><fo:inline>*</fo:inline>
+ <fo:footnote-body><fo:block font-size="80%">* written in
+ Java</fo:block></fo:footnote-body></fo:footnote> that reads a formatting object (FO)
+ tree and renders the resulting pages to a specified output.</fo:block>
+ <fo:block break-before="page">The FOP project is part of the Apache Software Foundation, which
+ is a wider community of users and developers of open source projects.</fo:block>
+ <fo:block break-before="page">Apache™ FOP (Formatting Objects Processor) is a print formatter
+ driven by XSL formatting objects (XSL-FO) and an output independent formatter.</fo:block>
+ <fo:block break-before="page">It is a Java application that reads a formatting object (FO)
+ tree and renders the resulting pages to a specified output.</fo:block>
+ <fo:block break-before="page">The FOP project is part of the Apache Software Foundation, which
+ is a wider community of users and developers of open source projects.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>