Merged in trunk@1387627


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_XGC_URI_Resolution@1387628 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/xmlgraphics-commons-1.5svn.jar b/lib/xmlgraphics-commons-1.5svn.jar
index 42cc139..3edaf80 100644
--- a/lib/xmlgraphics-commons-1.5svn.jar
+++ b/lib/xmlgraphics-commons-1.5svn.jar
Binary files differ
diff --git a/src/documentation/content/xdocs/dev/index.xml b/src/documentation/content/xdocs/dev/index.xml
index 3574020..27f1b2c 100644
--- a/src/documentation/content/xdocs/dev/index.xml
+++ b/src/documentation/content/xdocs/dev/index.xml
@@ -97,7 +97,7 @@
               <li>The <link href="http://marc.theaimsgroup.com/?l=fop-dev&amp;r=1&amp;w=2">Mailing list ARChives</link> (MARC) at the AIMS group (search).</li>
               <li><link href="http://www.mail-archive.com/fop-dev%40xmlgraphics.apache.org/">The Mail Archive</link>.</li>
               <li>The <link href="http://dir.gmane.org/gmane.text.xml.fop.devel">GMANE</link> archive.</li>
-              <li>The <link href="http://www.nabble.com/FOP---Dev-f352.html">Nabble</link> archive.</li>
+              <li>The <link href="http://apache-fop.1065347.n5.nabble.com/">Nabble</link> archive.</li>
               <li>The <link href="http://fop-dev.markmail.org">MarkMail</link> archive.</li>
             </ul>
           </li>
diff --git a/src/documentation/content/xdocs/maillist.xml b/src/documentation/content/xdocs/maillist.xml
index b241664..406ccf3 100644
--- a/src/documentation/content/xdocs/maillist.xml
+++ b/src/documentation/content/xdocs/maillist.xml
@@ -43,17 +43,17 @@
         <title>Archives</title>
         <p>To review the archives, you have several options:</p>
         <ul>
-        
+
           <li>The <link href="http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-users/">Apache Mailing List archive</link> (mod_mbox archive, no full-text search, yet).</li>
           <li>The <link href="http://xmlgraphics.apache.org/mail/fop-users/">Apache Mailing List archive</link> (gzipped mbox files).</li>
           <li>The <jump href="http://marc.theaimsgroup.com/?l=fop-user&amp;r=1&amp;w=2">Mailing list ARChives </jump> (MARC) at the AIMS group.</li>
           <li><jump href="http://www.mail-archive.com/fop-users%40xmlgraphics.apache.org/">The Mail Archive</jump>.</li>
           <li>The <jump href="http://dir.gmane.org/gmane.text.xml.fop.user">GMANE archive</jump>.</li>
-          <li>The <jump href="http://www.nabble.com/FOP---Users-f353.html">Nabble archive</jump> (only posts after May 2005).</li>
+          <li>The <jump href="http://apache-fop.1065347.n5.nabble.com/FOP-Users-f3.html">Nabble archive</jump> (only posts after May 2005).</li>
           <li>The <jump href="http://fop-users.markmail.org/">MarkMail archive</jump>.</li>
         </ul>
         <note>
-          If you don't like mailing lists and prefer a forum-like system, have a look at 
+          If you don't like mailing lists and prefer a forum-like system, have a look at
           <jump href="http://dir.gmane.org/gmane.text.xml.fop.user">GMANE</jump> or
           <jump href="http://www.nabble.com/FOP---Users-f353.html">Nabble</jump>. They
           allow you to post to the mailing list without having to subscribe.
diff --git a/src/documentation/content/xdocs/trunk/output.xml b/src/documentation/content/xdocs/trunk/output.xml
index 7c4ace7..5de820c 100644
--- a/src/documentation/content/xdocs/trunk/output.xml
+++ b/src/documentation/content/xdocs/trunk/output.xml
@@ -971,7 +971,8 @@
      xmlns:afp="http://xmlgraphics.apache.org/fop/extensions/afp">
       <fo:layout-master-set>
         <fo:simple-page-master master-name="simple">
-          <afp:tag-logical-element name="The TLE Name" value="The TLE Value" />
+          <afp:tag-logical-element name="The TLE Name" value="The TLE Value"
+            encoding="500" />
           <fo:region-body/>
         </fo:simple-page-master>
       </fo:layout-master-set>
@@ -985,7 +986,7 @@
           The tag-logical-element extension element can appear within a simple-page-master
           (page level) or it can appear as child of page-sequence (page group level).
           Multiple tag-logical-element extension elements within a simple-page-master or
-          page-sequence are allowed. The name and value attributes are mandatory.
+          page-sequence are allowed. The name and value attributes are mandatory.  The encoding attribute specifying a CCSID encoding is optional.  
         </p>
       </section>
       <section id="afp-no-operation">
@@ -1269,6 +1270,7 @@
 <source><![CDATA[<renderer mime="image/tiff">
   <transparent-page-background>true</transparent-page-background>
   <compression>CCITT T.6</compression>
+  <single-strip>true</single-strip>
   <fonts><!-- described elsewhere --></fonts>
 </renderer>]]></source>
       <p>
@@ -1302,6 +1304,10 @@
         added separately. The internal TIFF codec from XML Graphics Commons only supports PackBits,
         Deflate and JPEG compression for writing.
       </note>
+      <p>
+          The default value for the <code>"single-strip"</code> is <code>"false"</code> resulting in the RowsPerStrip Tiff Tag equal to the number of rows.
+          If set to <code>true</code> RowsPerStrip is set to 1.
+      </p>
     </section>
     <section id="bitmap-rendering-options">
       <title>Runtime Rendering Options</title>
diff --git a/src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java b/src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java
index 27469d6..aaf112c 100644
--- a/src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java
+++ b/src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java
@@ -72,8 +72,6 @@
 
     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. */
@@ -166,6 +164,20 @@
     }
 
     @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);
         super.startFlow(fl);
@@ -216,16 +228,11 @@
     @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);
     }
@@ -256,8 +263,6 @@
 
     @Override
     public void startFooter(TableFooter footer) {
-        converters.push(converter);
-        converter = new FOEventRecorder();
         converter.startFooter(footer);
         super.startFooter(footer);
     }
@@ -265,10 +270,6 @@
     @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);
     }
 
@@ -357,20 +358,6 @@
     }
 
     @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();
         super.startMarkup();
diff --git a/src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java b/src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java
deleted file mode 100644
index b2b1804..0000000
--- a/src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * 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);
-            }
-        });
-    }
-
-}
diff --git a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java
index 7e3ed05..93b815d 100644
--- a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java
+++ b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java
@@ -55,6 +55,7 @@
 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;
@@ -67,6 +68,8 @@
 
     private StructureTreeEventHandler structureTreeEventHandler;
 
+    private LayoutMasterSet layoutMasterSet;
+
     public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) {
         this.structureTreeEventHandler = structureTreeEventHandler;
     }
@@ -81,6 +84,9 @@
 
     @Override
     public void startPageSequence(PageSequence pageSeq) {
+        if (layoutMasterSet == null) {
+            layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet();
+        }
         Locale locale = null;
         if (pageSeq.getLanguage() != null) {
             if (pageSeq.getCountry() != null) {
@@ -129,8 +135,27 @@
     }
 
     @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
@@ -278,16 +303,6 @@
     }
 
     @Override
-    public void startStatic(StaticContent staticContent) {
-        startElement(staticContent);
-    }
-
-    @Override
-    public void endStatic(StaticContent statisContent) {
-        endElement(statisContent);
-    }
-
-    @Override
     public void startLink(BasicLink basicLink) {
         startElementWithID(basicLink);
     }
diff --git a/src/java/org/apache/fop/afp/AFPEventProducer.java b/src/java/org/apache/fop/afp/AFPEventProducer.java
index 93eb9c0..01d5c4a 100644
--- a/src/java/org/apache/fop/afp/AFPEventProducer.java
+++ b/src/java/org/apache/fop/afp/AFPEventProducer.java
@@ -113,4 +113,13 @@
      * @event.severity ERROR
      */
     void invalidConfiguration(Object source, Exception e);
+
+    /**
+     * The characterset is missing metric information for the specified character
+     * @param source the event source
+     * @param character the character with missing metric information.
+     * @param charSet the character set containing missing metric information
+     * @event.severity WARN
+     */
+    void charactersetMissingMetrics(Object source, char character, String charSet);
 }
diff --git a/src/java/org/apache/fop/afp/AFPEventProducer.xml b/src/java/org/apache/fop/afp/AFPEventProducer.xml
index 042eb5e..e17a4ea 100644
--- a/src/java/org/apache/fop/afp/AFPEventProducer.xml
+++ b/src/java/org/apache/fop/afp/AFPEventProducer.xml
@@ -8,4 +8,5 @@
   <message key="fontConfigMissing">The mandatory configuation node: '{missingConfig}' was not found at {location}.</message>
   <message key="characterSetNameInvalid">The character set given has an invalid name. [ Reason: {msg} ]</message>
   <message key="codePageNotFound">The code page for an AFP font cannot be found.[ Reason: {e}]</message>
+  <message key="charactersetMissingMetrics">Metric information is missing for the glyph `{character}` in the characterset `{charSet}`. Using space increment width.</message>
 </catalogue>
diff --git a/src/java/org/apache/fop/afp/DataStream.java b/src/java/org/apache/fop/afp/DataStream.java
index 2794ae9..272c000 100644
--- a/src/java/org/apache/fop/afp/DataStream.java
+++ b/src/java/org/apache/fop/afp/DataStream.java
@@ -40,7 +40,7 @@
 import org.apache.fop.afp.modca.PageGroup;
 import org.apache.fop.afp.modca.PageObject;
 import org.apache.fop.afp.modca.ResourceGroup;
-import org.apache.fop.afp.modca.TagLogicalElementBean;
+import org.apache.fop.afp.modca.TagLogicalElement;
 import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet;
 import org.apache.fop.afp.ptoca.PtocaBuilder;
 import org.apache.fop.afp.ptoca.PtocaProducer;
@@ -85,12 +85,9 @@
     /** The current page */
     private AbstractPageObject currentPage = null;
 
-    /** Sequence number for TLE's.*/
-    private int tleSequence = 0;
-
     /** The MO:DCA interchange set in use (default to MO:DCA-P IS/2 set) */
     private InterchangeSet interchangeSet
-        = InterchangeSet.valueOf(InterchangeSet.MODCA_PRESENTATION_INTERCHANGE_SET_2);
+    = InterchangeSet.valueOf(InterchangeSet.MODCA_PRESENTATION_INTERCHANGE_SET_2);
 
     private final Factory factory;
 
@@ -544,17 +541,19 @@
         currentPage.createIncludePageSegment(name, xOrigin, yOrigin, createHardPageSegments);
     }
 
+
+
     /**
      * Creates a TagLogicalElement on the current page.
      *
      * @param attributes
      *            the array of key value pairs.
      */
-    public void createPageTagLogicalElement(TagLogicalElementBean[] attributes) {
+
+    public void createPageTagLogicalElement(TagLogicalElement.State[] attributes) {
         for (int i = 0; i < attributes.length; i++) {
-            String name = attributes[i].getKey();
-            String value = attributes[i].getValue();
-            currentPage.createTagLogicalElement(name, value, tleSequence++);
+
+            currentPage.createTagLogicalElement(attributes[i]);
         }
     }
 
@@ -564,11 +563,9 @@
      * @param attributes
      *            the array of key value pairs.
      */
-    public void createPageGroupTagLogicalElement(TagLogicalElementBean[] attributes) {
+    public void createPageGroupTagLogicalElement(TagLogicalElement.State[] attributes) {
         for (int i = 0; i < attributes.length; i++) {
-            String name = attributes[i].getKey();
-            String value = attributes[i].getValue();
-            currentPageGroup.createTagLogicalElement(name, value);
+            currentPageGroup.createTagLogicalElement(attributes[i]);
         }
     }
 
@@ -579,12 +576,17 @@
      *            The tag name
      * @param value
      *            The tag value
+     * @param encoding The CCSID character set encoding
      */
-    public void createTagLogicalElement(String name, String value) {
+    public void createTagLogicalElement(String name, String value, int encoding) {
+
+        TagLogicalElement.State tleState = new  TagLogicalElement.State(name, value, encoding);
         if (currentPage != null) {
-            currentPage.createTagLogicalElement(name, value, tleSequence++);
+
+            currentPage.createTagLogicalElement(tleState);
+
         } else {
-            currentPageGroup.createTagLogicalElement(name, value);
+            currentPageGroup.createTagLogicalElement(tleState);
         }
     }
 
@@ -632,7 +634,7 @@
      */
     public void startPageGroup() throws IOException {
         endPageGroup();
-        this.currentPageGroup = factory.createPageGroup(tleSequence);
+        this.currentPageGroup = factory.createPageGroup();
     }
 
     /**
@@ -643,7 +645,6 @@
     public void endPageGroup() throws IOException {
         if (currentPageGroup != null) {
             currentPageGroup.endPageGroup();
-            tleSequence = currentPageGroup.getTleSequence();
             document.addPageGroup(currentPageGroup);
             currentPageGroup = null;
         }
diff --git a/src/java/org/apache/fop/afp/Factory.java b/src/java/org/apache/fop/afp/Factory.java
index ef68a22..f3e75c1 100644
--- a/src/java/org/apache/fop/afp/Factory.java
+++ b/src/java/org/apache/fop/afp/Factory.java
@@ -214,13 +214,12 @@
 
     /**
      * Creates a new MO:DCA {@link PageGroup}
-     * @param tleSequence current start tle sequence number within stream
      * @return a new {@link PageGroup}
      */
-    public PageGroup createPageGroup(int tleSequence) {
+    public PageGroup createPageGroup() {
         String name = PAGE_GROUP_NAME_PREFIX
         + StringUtils.lpad(String.valueOf(++pageGroupCount), '0', 5);
-        return new PageGroup(this, name, tleSequence);
+        return new PageGroup(this, name);
     }
 
     /**
@@ -374,13 +373,11 @@
     /**
      * Creates a MO:DCA {@link TagLogicalElement}
      *
-     * @param name name of the element
-     * @param value value of the element
-     * @param tleSequence current start tle sequence number within stream*
+     * @param state the attribute state for the TLE
      * @return a new {@link TagLogicalElement}
      */
-    public TagLogicalElement createTagLogicalElement(String name, String value, int tleSequence) {
-        TagLogicalElement tle = new TagLogicalElement(name, value, tleSequence);
+    public TagLogicalElement createTagLogicalElement(TagLogicalElement.State state) {
+        TagLogicalElement tle = new TagLogicalElement(state);
         return tle;
     }
 
diff --git a/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java b/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java
index 1a2611d..7b57a2b 100644
--- a/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java
+++ b/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java
@@ -19,6 +19,8 @@
 
 package org.apache.fop.afp.fonts;
 
+import org.apache.fop.afp.AFPEventProducer;
+
 /**
  * A font defined as a set of lines and curves as opposed to a bitmap font. An
  * outline font can be scaled to any size and otherwise transformed more easily
@@ -29,16 +31,25 @@
     /** The character set for this font */
     protected CharacterSet charSet = null;
 
+    private final AFPEventProducer eventProducer;
+
     /**
      * Constructor for an outline font.
      *
      * @param name the name of the font
      * @param embeddable sets whether or not this font is to be embedded
      * @param charSet the chracter set
+     * @param eventProducer The object to handle any events which occur from the object.
      */
-    public AbstractOutlineFont(String name, boolean embeddable, CharacterSet charSet) {
+    public AbstractOutlineFont(String name, boolean embeddable, CharacterSet charSet,
+            AFPEventProducer eventProducer) {
         super(name, embeddable);
         this.charSet = charSet;
+        this.eventProducer = eventProducer;
+    }
+
+    AFPEventProducer getAFPEventProducer() {
+        return eventProducer;
     }
 
     /**
diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSet.java b/src/java/org/apache/fop/afp/fonts/CharacterSet.java
index 49e7f99..d54d478 100644
--- a/src/java/org/apache/fop/afp/fonts/CharacterSet.java
+++ b/src/java/org/apache/fop/afp/fonts/CharacterSet.java
@@ -363,4 +363,12 @@
         return getCharacterSetOrientation().getEmSpaceIncrement();
     }
 
+    /**
+     * Returns the nominal character increment.
+     * @return the nominal character increment
+     */
+    public int getNominalCharIncrement() {
+        return getCharacterSetOrientation().getNominalCharIncrement();
+    }
+
 }
diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java b/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
index 7331178..2565942 100644
--- a/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
+++ b/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
@@ -236,9 +236,9 @@
             CharacterSetType charsetType, AFPResourceAccessor accessor, AFPEventProducer eventProducer)
             throws IOException {
         // check for cached version of the characterset
-        String descriptor = characterSetName + "_" + encoding + "_" + codePageName;
-        CharacterSet characterSet = (CharacterSet) characterSetsCache.get(descriptor);
-
+        URI charSetURI = accessor.resolveURI(characterSetName);
+        String cacheKey = charSetURI.toASCIIString() + "_" + characterSetName + "_" + codePageName;
+        CharacterSet characterSet = (CharacterSet) characterSetsCache.get(cacheKey);
         if (characterSet != null) {
             return characterSet;
         }
@@ -257,6 +257,8 @@
              * chracter global identifier.
              */
             Map<String, String> codePage;
+            // TODO: This could have performance implications if several threads want to use the
+            // codePagesCache to retrieve different codepages.
             synchronized (codePagesCache) {
                 codePage = codePagesCache.get(codePageName);
 
@@ -308,7 +310,7 @@
         } finally {
             closeInputStream(inputStream);
         }
-        characterSetsCache.put(descriptor, characterSet);
+        characterSetsCache.put(cacheKey, characterSet);
         return characterSet;
     }
 
@@ -446,20 +448,15 @@
             position++;
 
             if (position == 26) {
-
                 position = 0;
 
                 int orientation = determineOrientation(fnoData[2]);
-                //  Space Increment
-                int space = ((fnoData[8] & 0xFF ) << 8) + (fnoData[9] & 0xFF);
-                //  Em-Space Increment
-                int em = ((fnoData[14] & 0xFF ) << 8) + (fnoData[15] & 0xFF);
+                int spaceIncrement = getUBIN(fnoData, 8);
+                int emIncrement = getUBIN(fnoData, 14);
+                int nominalCharacterIncrement = getUBIN(fnoData, 20);
 
-                CharacterSetOrientation cso = new CharacterSetOrientation(orientation);
-                cso.setSpaceIncrement(space);
-                cso.setEmSpaceIncrement(em);
-                orientations.add(cso);
-
+                orientations.add(new CharacterSetOrientation(orientation, spaceIncrement,
+                        emIncrement, nominalCharacterIncrement));
             }
         }
         return orientations.toArray(EMPTY_CSO_ARRAY);
diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java b/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java
index 7ac8ae9..a730525 100644
--- a/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java
+++ b/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java
@@ -60,7 +60,7 @@
     /**
      * The character widths in the character set (indexed using Unicode codepoints)
      */
-    private int[] charsWidths = null;
+    private int[] charsWidths;
 
     /**
      * The height of lowercase letters
@@ -77,25 +77,26 @@
      */
     private char lastChar;
 
-
-    /**
-     * The character set orientation
-     */
-    private int orientation = 0;
-
+    /** The character set orientation */
+    private final int orientation;
     /** space increment */
-    private int spaceIncrement;
+    private final int spaceIncrement;
     /** em space increment */
-    private int emSpaceIncrement = -1;
-
+    private final int emSpaceIncrement;
+    /** Nominal Character Increment */
+    private final int nomCharIncrement;
 
     /**
      * Constructor for the CharacterSetOrientation, the orientation is
      * expressed as the degrees rotation (i.e 0, 90, 180, 270)
      * @param orientation the character set orientation
      */
-    public CharacterSetOrientation(int orientation) {
+    public CharacterSetOrientation(int orientation, int spaceIncrement, int emSpaceIncrement,
+            int nomCharIncrement) {
         this.orientation = orientation;
+        this.spaceIncrement = spaceIncrement;
+        this.emSpaceIncrement = emSpaceIncrement;
+        this.nomCharIncrement = nomCharIncrement;
         charsWidths = new int[256];
         Arrays.fill(charsWidths, -1);
     }
@@ -284,14 +285,6 @@
     }
 
     /**
-     * Sets the space increment.
-     * @param value the space increment
-     */
-    public void setSpaceIncrement(int value) {
-        this.spaceIncrement = value;
-    }
-
-    /**
      * Returns the em space increment.
      * @return the em space increment
      */
@@ -300,11 +293,10 @@
     }
 
     /**
-     * Sets the em space increment.
-     * @param value the em space increment
+     * Returns the nominal character increment.
+     * @return the nominal character increment
      */
-    public void setEmSpaceIncrement(int value) {
-        this.emSpaceIncrement = value;
+    public int getNominalCharIncrement() {
+        return this.nomCharIncrement;
     }
-
 }
diff --git a/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java b/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java
index a81805b..78da6ea 100644
--- a/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java
+++ b/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java
@@ -23,6 +23,11 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.afp.AFPEventProducer;
+
 /**
  * Implementation of AbstractOutlineFont that supports double-byte fonts (CID Keyed font (Type 0)).
  * The width of characters that are not prescribed a width metrics in the font resource use
@@ -31,7 +36,9 @@
  */
 public class DoubleByteFont extends AbstractOutlineFont {
 
-    //private static final Log LOG = LogFactory.getLog(DoubleByteFont.class);
+    private static final Log log = LogFactory.getLog(DoubleByteFont.class);
+
+    private final Set<Integer> charsProcessed;
 
     //See also http://unicode.org/reports/tr11/ which we've not closely looked at, yet
     //TODO the Unicode block listed here is probably not complete (ex. Hiragana, Katakana etc.)
@@ -49,9 +56,12 @@
      * @param name the name of the font
      * @param embeddable whether or not this font is embeddable
      * @param charSet the character set
+     * @param eventProducer Handles any AFP related events
      */
-    public DoubleByteFont(String name, boolean embeddable, CharacterSet charSet) {
-        super(name, embeddable, charSet);
+    public DoubleByteFont(String name, boolean embeddable, CharacterSet charSet,
+            AFPEventProducer eventProducer) {
+        super(name, embeddable, charSet, eventProducer);
+        charsProcessed = new HashSet<Integer>();
     }
 
     /** {@inheritDoc} */
@@ -60,16 +70,30 @@
         try {
             charWidth = charSet.getWidth(toUnicodeCodepoint(character));
         } catch (IllegalArgumentException e) {
+            if (!charsProcessed.contains(character)) {
+                charsProcessed.add(character);
+                getAFPEventProducer().charactersetMissingMetrics(this, (char)character,
+                        charSet.getName().trim());
+            }
             //  We shall try and handle characters that have no mapped width metric in font resource
             charWidth = -1;
         }
 
         if (charWidth == -1) {
-            charWidth = inferCharWidth(character);
+            charWidth = getDefaultCharacterWidth(character);
         }
         return charWidth * size;
     }
 
+    private int getDefaultCharacterWidth(int character) {
+        int nominalCharIncrement = charSet.getNominalCharIncrement();
+        if (nominalCharIncrement > 0) {
+            return nominalCharIncrement;
+        } else {
+            return inferCharWidth(character);
+        }
+    }
+
     private int inferCharWidth(int character) {
 
         //Is this character an ideograph?
diff --git a/src/java/org/apache/fop/afp/fonts/OutlineFont.java b/src/java/org/apache/fop/afp/fonts/OutlineFont.java
index 103d96e..e9cdf5b 100644
--- a/src/java/org/apache/fop/afp/fonts/OutlineFont.java
+++ b/src/java/org/apache/fop/afp/fonts/OutlineFont.java
@@ -19,6 +19,8 @@
 
 package org.apache.fop.afp.fonts;
 
+import org.apache.fop.afp.AFPEventProducer;
+
 /**
  * Default implementation of AbstractOutlineFont.
  */
@@ -29,9 +31,11 @@
      * @param name font's name
      * @param embeddable whether or not this font is embeddable
      * @param charSet font's character set
+     * @param eventProducer Handles any AFP related events
      */
-    public OutlineFont(String name, boolean embeddable, CharacterSet charSet) {
-        super(name, embeddable, charSet);
+    public OutlineFont(String name, boolean embeddable, CharacterSet charSet,
+            AFPEventProducer eventProducer) {
+        super(name, embeddable, charSet, eventProducer);
     }
 
 }
diff --git a/src/java/org/apache/fop/afp/modca/AbstractPageObject.java b/src/java/org/apache/fop/afp/modca/AbstractPageObject.java
index e8b8bc1..f429af2 100644
--- a/src/java/org/apache/fop/afp/modca/AbstractPageObject.java
+++ b/src/java/org/apache/fop/afp/modca/AbstractPageObject.java
@@ -223,19 +223,15 @@
     /**
      * Creates a TagLogicalElement on the page.
      *
-     * @param name
-     *            the name of the tag
-     * @param value
-     *            the value of the tag
-     * @param tleID
-     *            unique ID within AFP stream
+     * @param state the state of the TLE
      */
-    public void createTagLogicalElement(String name, String value, int tleID) {
-        TagLogicalElement tle = new TagLogicalElement(name, value, tleID);
+    public void createTagLogicalElement(TagLogicalElement.State state) {
+        TagLogicalElement tle = new TagLogicalElement(state);
         List list = getTagLogicalElements();
         list.add(tle);
     }
 
+
     /**
      * Creates a NoOperation on the page.
      *
diff --git a/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java b/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java
index 9ab84a6..8bfcf46 100644
--- a/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java
+++ b/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java
@@ -34,7 +34,7 @@
  */
 public class IncludedResourceObject extends AbstractNamedAFPObject {
 
-    private AFPResourceAccessor resourceAccessor;
+    private final AFPResourceAccessor resourceAccessor;
     private URI uri;
 
     /**
diff --git a/src/java/org/apache/fop/afp/modca/PageGroup.java b/src/java/org/apache/fop/afp/modca/PageGroup.java
index e7c18d7..7d472a2 100644
--- a/src/java/org/apache/fop/afp/modca/PageGroup.java
+++ b/src/java/org/apache/fop/afp/modca/PageGroup.java
@@ -36,35 +36,25 @@
 public class PageGroup extends AbstractResourceEnvironmentGroupContainer {
 
     /**
-     * Sequence number for TLE's.
-     */
-    private int tleSequence = 0;
-
-    /**
      * Constructor for the PageGroup.
      *
      * @param factory the resource manager
      * @param name the name of the page group
-     * @param tleSequence current start tle sequence number within stream
      */
-    public PageGroup(Factory factory, String name, int tleSequence) {
+    public PageGroup(Factory factory, String name) {
         super(factory, name);
-        this.tleSequence = tleSequence;
     }
 
     /**
      * Creates a TagLogicalElement on the page.
      *
-     * @param name
-     *            the name of the tag
-     * @param value
-     *            the value of the tag
+     * @param state
+     *              the state of the TLE
      */
-    public void createTagLogicalElement(String name, String value) {
-        TagLogicalElement tle = factory.createTagLogicalElement(name, value, tleSequence);
+    public void createTagLogicalElement(TagLogicalElement.State state) {
+        TagLogicalElement tle = factory.createTagLogicalElement(state);
         if (!getTagLogicalElements().contains(tle)) {
             getTagLogicalElements().add(tle);
-            tleSequence++;
         }
     }
 
@@ -93,9 +83,4 @@
     public String toString() {
         return this.getName();
     }
-
-    /** @return the TLE sequence number */
-    public int getTleSequence() {
-        return tleSequence;
-    }
 }
diff --git a/src/java/org/apache/fop/afp/modca/TagLogicalElement.java b/src/java/org/apache/fop/afp/modca/TagLogicalElement.java
index 706ceae..9ae88b4 100644
--- a/src/java/org/apache/fop/afp/modca/TagLogicalElement.java
+++ b/src/java/org/apache/fop/afp/modca/TagLogicalElement.java
@@ -24,6 +24,7 @@
 
 import org.apache.fop.afp.modca.triplets.AttributeQualifierTriplet;
 import org.apache.fop.afp.modca.triplets.AttributeValueTriplet;
+import org.apache.fop.afp.modca.triplets.EncodingTriplet;
 import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet;
 import org.apache.fop.afp.util.BinaryUtils;
 
@@ -49,42 +50,30 @@
 public class TagLogicalElement extends AbstractTripletStructuredObject {
 
     /**
-     * Name of the key, used within the TLE
+     * the params of the TLE
      */
-    private String name = null;
-
-    /**
-     * Value returned by the key
-     */
-    private String value = null;
-
-    /**
-     * Sequence of TLE within document
-     */
-    private int tleID;
+    private State state;
 
     /**
      * Construct a tag logical element with the name and value specified.
      *
-     * @param name the name of the tag logical element
-     * @param value the value of the tag logical element
-     * @param tleID unique identifier for TLE within AFP stream
+     * @param state the state of the tag logical element
      */
-    public TagLogicalElement(String name, String value, int tleID) {
-        this.name = name;
-        this.value = value;
-        this.tleID = tleID;
+
+    public TagLogicalElement(State state) {
+        this.state = state;
     }
 
-    /**
-     * Sets the attribute value of this structured field
-     *
-     * @param value the attribute value
-     */
-    public void setAttributeValue(String value) {
+    private void setAttributeValue(String value) {
         addTriplet(new AttributeValueTriplet(value));
     }
 
+    private void setEncoding(int encoding) {
+        if (encoding != State.ENCODING_NONE) {
+            addTriplet(new EncodingTriplet(encoding));
+        }
+    }
+
     /**
      * Sets the attribute qualifier of this structured field
      *
@@ -100,9 +89,9 @@
         setFullyQualifiedName(
                 FullyQualifiedNameTriplet.TYPE_ATTRIBUTE_GID,
                 FullyQualifiedNameTriplet.FORMAT_CHARSTR,
-                name);
-        setAttributeValue(value);
-        setAttributeQualifier(tleID, 1);
+                state.key);
+        setAttributeValue(state.value);
+        setEncoding(state.encoding);
 
         byte[] data = new byte[SF_HEADER_LENGTH];
         copySF(data, Type.ATTRIBUTE, Category.PROCESS_ELEMENT);
@@ -115,4 +104,51 @@
 
         writeTriplets(os);
     }
+
+    /**
+     *
+     * Holds the attribute state of a TLE
+     *
+     */
+    public static class State {
+
+        /**
+         *  value  interpreted as no encoding
+         */
+        public static final int ENCODING_NONE = -1;
+        /** The key attribute */
+        private String key;
+
+        /** The value attribute */
+        private String value;
+
+        /** The CCSID character et encoding attribute */
+        private int encoding =  ENCODING_NONE;
+
+
+        /**
+         * Constructor
+         *
+         * @param key the key attribute
+         * @param value the value attribute
+         */
+        public State(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        /**
+         *
+         * @param key the key attribute
+         * @param value the value attribute
+         * @param encoding the CCSID character set encoding attribute
+         */
+        public State(String key, String value, int encoding) {
+            this.key = key;
+            this.value = value;
+            this.encoding = encoding;
+        }
+
+
+    }
 }
diff --git a/src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java b/src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java
deleted file mode 100644
index 923a5d5..0000000
--- a/src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.afp.modca;
-
-/**
- * The TagLogicalElementBean provides a bean for holding the attributes of
- * a tag logical element as key value pairs.
- * <p/>
- */
-public class TagLogicalElementBean {
-
-    /** The key attribute */
-    private String key;
-
-    /** The value attribute */
-    private String value;
-
-    /**
-     * Constructor for the TagLogicalElementBean.
-     *
-     * @param key the key attribute
-     * @param value the value attribute
-     */
-    public TagLogicalElementBean(String key, String value) {
-        this.key = key;
-        this.value = value;
-    }
-
-    /**
-     * Getter for the key attribute.
-     *
-     * @return the key
-     */
-    public String getKey() {
-        return key;
-    }
-
-    /**
-     * Getter for the value attribute.
-     *
-     * @return the value
-     */
-    public String getValue() {
-        return value;
-    }
-
-}
diff --git a/src/java/org/apache/fop/afp/modca/triplets/EncodingTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/EncodingTriplet.java
new file mode 100644
index 0000000..05e56e5
--- /dev/null
+++ b/src/java/org/apache/fop/afp/modca/triplets/EncodingTriplet.java
@@ -0,0 +1,63 @@
+/*
+ * 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.afp.modca.triplets;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.fop.afp.util.BinaryUtils;
+/**
+ *
+ * Represents a CCSID encoding triplet.
+ *
+ */
+public class EncodingTriplet extends AbstractTriplet {
+
+
+    private int encoding;
+    /**
+     * @param encoding the CCSID character set encoding
+     */
+    public EncodingTriplet( int encoding) {
+        super(CODED_GRAPHIC_CHARACTER_SET_GLOBAL_IDENTIFIER);
+        this.encoding = encoding;
+    }
+    /** {@inheritDoc} */
+    public void writeToStream(OutputStream os) throws IOException {
+
+        // [len,id,0,0,0,0]
+        byte[] data = getData();
+
+        byte[] encodingBytes = BinaryUtils.convert(encoding, 2);
+
+        // [len,id,0,0,0,0] -> [len.id,0,0,encodingBytes[0],encodingBytes[1]]
+        System.arraycopy(encodingBytes, 0, data, 4, encodingBytes.length);
+
+        os.write(data);
+
+    }
+
+    /** {@inheritDoc} */
+    public int getDataLength() {
+        //len(1b) + id(1b) + 0x0000 (2b) + encoding (2b) = 6b
+        return 6;
+    }
+
+}
diff --git a/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java b/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java
index 1663bbe..f760e6c 100644
--- a/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java
+++ b/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java
@@ -24,6 +24,9 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 import org.apache.fop.apps.io.InternalResourceResolver;
 
 /**
@@ -31,8 +34,11 @@
  */
 public final class AFPResourceAccessor {
 
+    private static final Log log = LogFactory.getLog(AFPResourceAccessor.class);
+
     private final InternalResourceResolver resourceResolver;
-    private final String baseURI;
+    private final URI baseURI;
+    private final URIResolver uriResolver;
 
     /**
      * Constructor for resource to be accessed via the {@link org.apache.fop.apps.FOUserAgent}. This
@@ -45,7 +51,23 @@
      */
     public AFPResourceAccessor(InternalResourceResolver resourceResolver, String baseURI) {
         this.resourceResolver = resourceResolver;
-        this.baseURI = baseURI;
+        URI actualBaseURI = null;
+        URIResolver uriResolver;
+        if (baseURI == null) {
+            actualBaseURI = null;
+            uriResolver = new NullBaseURIResolver();
+        } else {
+            try {
+                actualBaseURI = InternalResourceResolver.getBaseURI(baseURI);
+                uriResolver = new BaseURIResolver();
+            } catch (URISyntaxException use) {
+                log.error("The URI given \"" + baseURI + "\" is invalid: " + use.getMessage());
+                actualBaseURI = null;
+                uriResolver = new NullBaseURIResolver();
+            }
+        }
+        this.baseURI = actualBaseURI;
+        this.uriResolver = uriResolver;
     }
 
     /**
@@ -57,18 +79,6 @@
         this(resourceResolver, null);
     }
 
-    private URI getResourceURI(URI uri) {
-        if (baseURI == null) {
-            return uri;
-        }
-        try {
-            URI baseURI = InternalResourceResolver.getBaseURI(this.baseURI);
-            return baseURI.resolve(uri);
-        } catch (URISyntaxException use) {
-            return uri;
-        }
-    }
-
     /**
      * Creates an {@link InputStream} given a URI.
      *
@@ -77,6 +87,44 @@
      * @throws IOException if an I/O error occurs while creating the InputStream.
      */
     public InputStream createInputStream(URI uri) throws IOException {
-        return resourceResolver.getResource(getResourceURI(uri));
+        return resourceResolver.getResource(uriResolver.resolveURI(uri));
+    }
+
+    /**
+     * Returns the resolved URI, given the URI of a resource.
+     *
+     * @param uri the resource URI
+     * @return the resolved URI
+     */
+    public URI resolveURI(String uri) {
+        return uriResolver.resolveURI(uri);
+    }
+
+    private interface URIResolver {
+        URI resolveURI(URI uri);
+
+        URI resolveURI(String uri);
+    }
+
+    private static final class NullBaseURIResolver implements URIResolver {
+
+        public URI resolveURI(URI uri) {
+            return uri;
+        }
+
+        public URI resolveURI(String uri) {
+            return URI.create("./" + uri.trim());
+        }
+    }
+
+    private final class BaseURIResolver implements URIResolver {
+
+        public URI resolveURI(URI uri) {
+            return baseURI.resolve(uri);
+        }
+
+        public URI resolveURI(String uri) {
+            return baseURI.resolve(uri.trim());
+        }
     }
 }
diff --git a/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java b/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java
index 2c8300f..72eac45 100644
--- a/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java
+++ b/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java
@@ -83,6 +83,15 @@
         return new TempAwareResourceResolver(tempResourceResolver, defaultResourceResolver);
     }
 
+    /**
+     * This creates the builder class for binding URI schemas to implementations of
+     * {@link ResourceResolver}. This allows users to define their own URI schemas such that they
+     * have finer control over the acquisition of resources.
+     *
+     * @param defaultResolver the default resource resolver that should be used in the event that
+     * none of the other registered resolvers match the schema
+     * @return the schema aware {@link ResourceResolver} builder
+     */
     public static SchemaAwareResourceResolverBuilder createSchemaAwareResourceResolverBuilder(
             ResourceResolver defaultResolver) {
         return new SchemaAwareResourceResolverBuilderImpl(defaultResolver);
@@ -99,10 +108,12 @@
                     new NormalResourceResolver());
         }
 
+        /** {@inheritDoc} */
         public Resource getResource(URI uri) throws IOException {
             return delegate.getResource(uri);
         }
 
+        /** {@inheritDoc} */
         public OutputStream getOutputStream(URI uri) throws IOException {
             return delegate.getOutputStream(uri);
         }
@@ -125,6 +136,7 @@
             return TempResourceURIGenerator.isTempUri(uri);
         }
 
+        /** {@inheritDoc} */
         public Resource getResource(URI uri) throws IOException {
             if (isTempUri(uri)) {
                 return tempResourceResolver.getResource(uri.getPath());
@@ -133,6 +145,7 @@
             }
         }
 
+        /** {@inheritDoc} */
         public OutputStream getOutputStream(URI uri) throws IOException {
             if (isTempUri(uri)) {
                 return tempResourceResolver.getOutputStream(uri.getPath());
@@ -140,7 +153,6 @@
                 return defaultResourceResolver.getOutputStream(uri);
             }
         }
-
     }
 
     private static class DefaultTempResourceResolver implements TempResourceResolver {
@@ -150,10 +162,12 @@
             return file;
         }
 
+        /** {@inheritDoc} */
         public Resource getResource(String id) throws IOException {
             return new Resource(getTempFile(id).toURI().toURL().openStream());
         }
 
+        /** {@inheritDoc} */
         public OutputStream getOutputStream(String id) throws IOException {
             File file = getTempFile(id);
             if (file.createNewFile()) {
@@ -196,19 +210,52 @@
             }
         }
 
+        /** {@inheritDoc} */
         public Resource getResource(URI uri) throws IOException {
             return getResourceResolverForSchema(uri).getResource(uri);
         }
 
+        /** {@inheritDoc} */
         public OutputStream getOutputStream(URI uri) throws IOException {
             return getResourceResolverForSchema(uri).getOutputStream(uri);
         }
     }
 
+    /**
+     * Implementations of this interface will be builders for {@link ResourceResolver}, they bind
+     * URI schemas to their respective resolver. This gives users more control over the mechanisms
+     * by which URIs are resolved.
+     * <p>
+     * Here is an example of how this could be used:
+     * </p>
+     * <p><code>
+     * SchemaAwareResourceResolverBuilder builder
+     *      = ResourceResolverFactory.createSchemaAwareResourceResolverBuilder(defaultResolver);
+     * builder.registerResourceResolverForSchema("test", testResolver);
+     * builder.registerResourceResolverForSchema("anotherTest", test2Resolver);
+     * ResourceResolver resolver = builder.build();
+     * </code></p>
+     * This will result in all URIs for the form "test:///..." will be resolved using the
+     * <code>testResolver</code> object; URIs of the form "anotherTest:///..." will be resolved
+     * using <code>test2Resolver</code>; all other URIs will be resolved from the defaultResolver.
+     */
     public interface SchemaAwareResourceResolverBuilder {
 
+        /**
+         * Register a schema with its respective {@link ResourceResolver}. This resolver will be
+         * used as the only resolver for the specified schema.
+         *
+         * @param schema the schema to be used with the given resolver
+         * @param resourceResolver the resource resolver
+         */
         void registerResourceResolverForSchema(String schema, ResourceResolver resourceResolver);
 
+        /**
+         * Builds a {@link ResourceResolver} that will delegate to the respective resource resolver
+         * when a registered URI schema is given
+         *
+         * @return a resolver that delegates to the appropriate schema resolver
+         */
         ResourceResolver build();
     }
 
@@ -218,10 +265,12 @@
         private static final SchemaAwareResourceResolverBuilder INSTANCE
                 = new CompletedSchemaAwareResourceResolverBuilder();
 
+        /** {@inheritDoc} */
         public ResourceResolver build() {
             throw new IllegalStateException("Resource resolver already built");
         }
 
+        /** {@inheritDoc} */
         public void registerResourceResolverForSchema(String schema,
                 ResourceResolver resourceResolver) {
             throw new IllegalStateException("Resource resolver already built");
@@ -240,11 +289,13 @@
             this.defaultResolver = defaultResolver;
         }
 
+        /** {@inheritDoc} */
         public void registerResourceResolverForSchema(String schema,
                 ResourceResolver resourceResolver) {
             schemaHandlingResourceResolvers.put(schema, resourceResolver);
         }
 
+        /** {@inheritDoc} */
         public ResourceResolver build() {
             return new SchemaAwareResourceResolver(
                     Collections.unmodifiableMap(schemaHandlingResourceResolvers), defaultResolver);
@@ -261,11 +312,13 @@
             this.delegate = new ActiveSchemaAwareResourceResolverBuilder(defaultResolver);
         }
 
+        /** {@inheritDoc} */
         public void registerResourceResolverForSchema(String schema,
                 ResourceResolver resourceResolver) {
             delegate.registerResourceResolverForSchema(schema, resourceResolver);
         }
 
+        /** {@inheritDoc} */
         public ResourceResolver build() {
             ResourceResolver resourceResolver = delegate.build();
             delegate = CompletedSchemaAwareResourceResolverBuilder.INSTANCE;
diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java
index 03a9cfa..7a11df7 100644
--- a/src/java/org/apache/fop/cli/CommandLineOptions.java
+++ b/src/java/org/apache/fop/cli/CommandLineOptions.java
@@ -43,6 +43,7 @@
 import org.apache.fop.apps.FopConfParser;
 import org.apache.fop.apps.FopFactory;
 import org.apache.fop.apps.FopFactoryBuilder;
+import org.apache.fop.apps.FopFactoryConfig;
 import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.pdf.PDFAMode;
 import org.apache.fop.pdf.PDFEncryptionManager;
@@ -117,7 +118,7 @@
     /* rendering options (for the user agent) */
     private Map renderingOptions = new java.util.HashMap();
     /* target resolution (for the user agent) */
-    private int targetResolution = 0;
+    private float targetResolution = FopFactoryConfig.DEFAULT_TARGET_RESOLUTION;
 
     private boolean strictValidation = true;
     /* control memory-conservation policy */
@@ -138,7 +139,7 @@
 
     private boolean flushCache = false;
 
-    private URI baseURI = new File(".").toURI();
+    private URI baseURI = new File(".").getAbsoluteFile().toURI();
 
     /**
      * Construct a command line option object.
@@ -420,7 +421,7 @@
             throw new FOPException("if you use '-cache', you must specify "
               + "the name of the font cache file");
         } else {
-            factory.getFontManager().setCacheFile(new File(args[i + 1]));
+            factory.getFontManager().setCacheFile(URI.create(args[i + 1]));
             return 1;
         }
     }
@@ -468,7 +469,7 @@
                 this.useStdIn = true;
             } else {
                 fofile = new File(filename);
-                baseURI = fofile.toURI();
+                baseURI = getBaseURI(fofile);
             }
             return 1;
         }
@@ -498,12 +499,16 @@
                 this.useStdIn = true;
             } else {
                 xmlfile = new File(filename);
-                baseURI = xmlfile.toURI();
+                baseURI = getBaseURI(xmlfile);
             }
             return 1;
         }
     }
 
+    private URI getBaseURI(File file) {
+        return file.getAbsoluteFile().getParentFile().toURI();
+    }
+
     private int parseAWTOutputOption(String[] args, int i) throws FOPException {
         setOutputMode(MimeConstants.MIME_FOP_AWT_PREVIEW);
         return 0;
@@ -730,7 +735,7 @@
                 this.useStdIn = true;
             } else {
                 fofile = new File(filename);
-                baseURI = fofile.toURI();
+                baseURI = getBaseURI(fofile);
             }
         } else if (outputmode == null) {
             outputmode = MimeConstants.MIME_PDF;
@@ -789,7 +794,7 @@
                 this.useStdIn = true;
             } else {
                 areatreefile = new File(filename);
-                baseURI = areatreefile.toURI();
+                baseURI = getBaseURI(areatreefile);
             }
             return 1;
         }
@@ -806,7 +811,7 @@
                 this.useStdIn = true;
             } else {
                 iffile = new File(filename);
-                baseURI = iffile.toURI();
+                baseURI = getBaseURI(iffile);
             }
             return 1;
         }
@@ -823,7 +828,7 @@
                 this.useStdIn = true;
             } else {
                 imagefile = new File(filename);
-                baseURI = imagefile.toURI();
+                baseURI = getBaseURI(imagefile);
             }
             return 1;
         }
diff --git a/src/java/org/apache/fop/events/CompositeEventListener.java b/src/java/org/apache/fop/events/CompositeEventListener.java
index 2b5cbff..c2bef32 100644
--- a/src/java/org/apache/fop/events/CompositeEventListener.java
+++ b/src/java/org/apache/fop/events/CompositeEventListener.java
@@ -19,6 +19,7 @@
 
 package org.apache.fop.events;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -26,7 +27,7 @@
  */
 public class CompositeEventListener implements EventListener {
 
-    private List listeners = new java.util.ArrayList();
+    private List<EventListener> listeners = new ArrayList<EventListener>();
 
     /**
      * Adds an event listener to the broadcaster. It is appended to the list of previously
@@ -46,22 +47,17 @@
         this.listeners.remove(listener);
     }
 
-    private synchronized int getListenerCount() {
-        return this.listeners.size();
-    }
-
     /**
      * Indicates whether any listeners have been registered with the broadcaster.
      * @return true if listeners are present, false otherwise
      */
-    public boolean hasEventListeners() {
-        return (getListenerCount() > 0);
+    public synchronized boolean hasEventListeners() {
+        return !listeners.isEmpty();
     }
 
-    /** {@inheritDoc} */
+    /** {@inheritDoc } */
     public synchronized void processEvent(Event event) {
-        for (int i = 0, c = getListenerCount(); i < c; i++) {
-            EventListener listener = (EventListener)this.listeners.get(i);
+        for (EventListener listener : listeners) {
             listener.processEvent(event);
         }
     }
diff --git a/src/java/org/apache/fop/fo/DelegatingFOEventHandler.java b/src/java/org/apache/fop/fo/DelegatingFOEventHandler.java
index 50026c9..bb0a1ba 100644
--- a/src/java/org/apache/fop/fo/DelegatingFOEventHandler.java
+++ b/src/java/org/apache/fop/fo/DelegatingFOEventHandler.java
@@ -143,6 +143,16 @@
     }
 
     @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);
     }
@@ -293,16 +303,6 @@
     }
 
     @Override
-    public void startStatic(StaticContent staticContent) {
-        delegate.startStatic(staticContent);
-    }
-
-    @Override
-    public void endStatic(StaticContent statisContent) {
-        delegate.endStatic(statisContent);
-    }
-
-    @Override
     public void startMarkup() {
         delegate.startMarkup();
     }
diff --git a/src/java/org/apache/fop/fo/FOEventHandler.java b/src/java/org/apache/fop/fo/FOEventHandler.java
index 11b6d4a..ad647e4 100644
--- a/src/java/org/apache/fop/fo/FOEventHandler.java
+++ b/src/java/org/apache/fop/fo/FOEventHandler.java
@@ -193,6 +193,20 @@
     }
 
     /**
+     * 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.
      * This method also handles fo:static-content tags, because the
@@ -409,22 +423,6 @@
     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.
      */
diff --git a/src/java/org/apache/fop/fo/FONode.java b/src/java/org/apache/fop/fo/FONode.java
index c66259f..8b55e6d 100644
--- a/src/java/org/apache/fop/fo/FONode.java
+++ b/src/java/org/apache/fop/fo/FONode.java
@@ -38,6 +38,7 @@
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.complexscripts.bidi.DelimitedTextRange;
+import org.apache.fop.fo.expr.PropertyException;
 import org.apache.fop.fo.extensions.ExtensionAttachment;
 import org.apache.fop.fo.extensions.ExtensionElementMapping;
 import org.apache.fop.fo.extensions.InternalElementMapping;
@@ -601,6 +602,22 @@
         getFOValidationEventProducer().missingProperty(this, getName(), propertyName, locator);
     }
 
+
+
+    /**
+     * Helper function to throw an error caused by an invalid property
+     *
+     * @param propertyName the name of the property.
+     * @param propertyValue the value of the property.
+     * * @param e optional property parsing exception.
+     * @throws ValidationException the validation error provoked by the method call
+     */
+    protected void invalidPropertyValueError(String propertyName, String propertyValue, Exception e)
+                throws ValidationException {
+        getFOValidationEventProducer().invalidPropertyValue(this, getName(), propertyName,
+                propertyValue,  new PropertyException(e), locator);
+    }
+
     /**
      * Helper function to return "Error(line#/column#)" string for
      * above exception messages
diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java
index b29571b..d0d13fc 100644
--- a/src/java/org/apache/fop/fo/FOPropertyMapping.java
+++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java
@@ -26,6 +26,7 @@
 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;
@@ -2267,7 +2268,7 @@
         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);
diff --git a/src/java/org/apache/fop/fo/pagination/Flow.java b/src/java/org/apache/fop/fo/pagination/Flow.java
index 981485e..45c8f78 100644
--- a/src/java/org/apache/fop/fo/pagination/Flow.java
+++ b/src/java/org/apache/fop/fo/pagination/Flow.java
@@ -36,6 +36,9 @@
  */
 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;
@@ -61,7 +64,7 @@
     /** {@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,
diff --git a/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java b/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java
index 533b113..8b109dd 100644
--- a/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java
+++ b/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java
@@ -217,5 +217,24 @@
     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;
+    }
 }
 
diff --git a/src/java/org/apache/fop/fo/pagination/StaticContent.java b/src/java/org/apache/fop/fo/pagination/StaticContent.java
index e70c80c..412cdbc 100644
--- a/src/java/org/apache/fop/fo/pagination/StaticContent.java
+++ b/src/java/org/apache/fop/fo/pagination/StaticContent.java
@@ -42,7 +42,7 @@
     /** {@inheritDoc} */
     protected void startOfNode() throws FOPException {
         if (getFlowName() == null || getFlowName().equals("")) {
-            missingPropertyError("flow-name");
+            missingPropertyError(FLOW_NAME);
         }
         getFOEventHandler().startStatic(this);
     }
diff --git a/src/java/org/apache/fop/fonts/CIDFont.java b/src/java/org/apache/fop/fonts/CIDFont.java
index 82213dd..dc39826 100644
--- a/src/java/org/apache/fop/fonts/CIDFont.java
+++ b/src/java/org/apache/fop/fonts/CIDFont.java
@@ -29,7 +29,7 @@
 public abstract class CIDFont extends CustomFont {
 
     /** Contains the character widths for all characters in the font */
-    protected int[] width = null;
+    protected int[] width;
 
     /**
      * @param resourceResolver the URI resolver for controlling file access
@@ -69,7 +69,7 @@
      * Returns the subset information for this font.
      * @return the subset information
      */
-    public abstract CIDSubset getCIDSubset();
+    public abstract CIDSet getCIDSet();
 
     // ---- Optional ----
     /**
diff --git a/src/java/org/apache/fop/fonts/CIDFull.java b/src/java/org/apache/fop/fonts/CIDFull.java
new file mode 100644
index 0000000..ee062a2
--- /dev/null
+++ b/src/java/org/apache/fop/fonts/CIDFull.java
@@ -0,0 +1,113 @@
+/*
+ * 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.fonts;
+
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.fop.util.CharUtilities;
+
+/**
+ * Provides methods to get font information.
+ * Naming:
+ * glyph index: original index of the glyph in the non-subset font (!= unicode index)
+ * character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset
+ * fonts, this is the same as the glyph index.
+ * Unicode index: The Unicode codepoint of a character.
+ * Glyph name: the Adobe glyph name (as found in Glyphs.java)
+ */
+public class CIDFull implements CIDSet {
+
+    private BitSet glyphIndices;
+    private final MultiByteFont font;
+
+    public CIDFull(MultiByteFont mbf) {
+        font = mbf;
+    }
+
+    private void initGlyphIndices() {
+        // this cannot be called in the constructor since the font is not ready...
+        if (glyphIndices == null) {
+            glyphIndices = font.getGlyphIndices();
+        }
+    }
+
+    /** {@inheritDoc} */
+    public int getOriginalGlyphIndex(int index) {
+        return index;
+    }
+
+    /** {@inheritDoc} */
+    public char getUnicode(int index) {
+        initGlyphIndices();
+        if (glyphIndices.get(index)) {
+            return (char) index;
+        } else {
+            return CharUtilities.NOT_A_CHARACTER;
+        }
+    }
+
+    /** {@inheritDoc} */
+    public int mapChar(int glyphIndex, char unicode) {
+        return (char) glyphIndex;
+    }
+
+    /** {@inheritDoc} */
+    public Map<Integer, Integer> getGlyphs() {
+        // this is never really called for full embedded fonts but the equivalent map would be the identity
+        initGlyphIndices();
+        Map<Integer, Integer> glyphs = new HashMap<Integer, Integer>();
+        int nextBitSet = 0;
+        for (int j = 0; j < glyphIndices.cardinality(); j++) {
+            nextBitSet = glyphIndices.nextSetBit(nextBitSet);
+            glyphs.put(Integer.valueOf(nextBitSet), Integer.valueOf(nextBitSet));
+            nextBitSet++;
+        }
+        return Collections.unmodifiableMap(glyphs);
+    }
+
+    /** {@inheritDoc} */
+    public char[] getChars() {
+        return font.getChars();
+    }
+
+    /** {@inheritDoc} */
+    public int getNumberOfGlyphs() {
+        initGlyphIndices();
+        // note: the real number of glyphs is given by the cardinality() method (not the length()) but since
+        // we will pad gaps in the indices with zeros we really want the length() here. this method is only
+        // called when embedding a font in PostScript and this will be the value of the CIDCount entry
+        return glyphIndices.length();
+    }
+
+    /** {@inheritDoc} */
+    public BitSet getGlyphIndices() {
+        initGlyphIndices();
+        return glyphIndices;
+    }
+
+    /** {@inheritDoc} */
+    public int[] getWidths() {
+        return font.getWidths();
+    }
+
+}
diff --git a/src/java/org/apache/fop/fonts/CIDSet.java b/src/java/org/apache/fop/fonts/CIDSet.java
new file mode 100644
index 0000000..30d1a5e
--- /dev/null
+++ b/src/java/org/apache/fop/fonts/CIDSet.java
@@ -0,0 +1,90 @@
+/*
+ * 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.fonts;
+
+import java.util.BitSet;
+import java.util.Map;
+
+/**
+ * Declares methods to retrieve font information (glyph indices, widths, unicode values) from a CID font.
+ */
+public interface CIDSet {
+
+    /**
+     * Returns the original index of the glyph inside the (non-subset) font's glyph list. This
+     * index can be used to access the character width information, for example.
+     * @param index the subset index (character selector) to access the glyph
+     * @return the original index (or -1 if no glyph index is available for the subset index)
+     */
+    int getOriginalGlyphIndex(int index);
+
+    /**
+     * Returns the Unicode value for a subset index (character selector). If there's no such
+     * Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned.
+     * @param subsetIndex the subset index (character selector)
+     * @return the Unicode value or "NOT A CHARACTER" (0xFFFF)
+     */
+    char getUnicode(int index);
+
+    /**
+     * Maps a character to a character selector for a font subset. If the character isn't in the
+     * subset, yet, it is added and a new character selector returned. Otherwise, the already
+     * allocated character selector is returned from the existing map/subset.
+     * @param glyphIndex the glyph index of the character
+     * @param unicode the Unicode index of the character
+     * @return the subset index
+     */
+    int mapChar(int glyphIndex, char unicode);
+
+    /**
+     * Returns an unmodifiable Map of the font subset. It maps from glyph index to
+     * character selector (i.e. the subset index in this case).
+     * @return Map Map&lt;Integer, Integer&gt; of the font subset
+     */
+    Map<Integer, Integer> getGlyphs();
+
+    /**
+     * Returns a char array containing all Unicode characters that are in the subset.
+     * @return a char array with all used Unicode characters
+     */
+    char[] getChars();
+
+    /**
+     * Returns the number of glyphs in the subset.
+     * @return the number of glyphs in the subset
+     */
+    int getNumberOfGlyphs();
+
+    /**
+     * Returns a BitSet with bits set for each available glyph index in the subset.
+     * @return a BitSet indicating available glyph indices
+     */
+    BitSet getGlyphIndices();
+
+    /**
+     * Return the array of widths.
+     * <p>
+     * This is used to get an array for inserting in an output format.
+     * It should not be used for lookup.
+     * @return an array of widths
+     */
+    int[] getWidths();
+
+}
diff --git a/src/java/org/apache/fop/fonts/CIDSubset.java b/src/java/org/apache/fop/fonts/CIDSubset.java
index 372a638..f442c13 100644
--- a/src/java/org/apache/fop/fonts/CIDSubset.java
+++ b/src/java/org/apache/fop/fonts/CIDSubset.java
@@ -26,18 +26,16 @@
 
 import org.apache.fop.util.CharUtilities;
 
-//Naming:
-//glyph index: original index of the glyph in the non-subset font (!= unicode index)
-//character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For
-//  non-subset fonts, this is the same as the glyph index.
-//Unicode index: The Unicode codepoint of a character.
-//Glyph name: the Adobe glyph name (as found in Glyphs.java)
-
 /**
- * Keeps track of the glyphs used in a document. This information is later used to build
- * a subset of a font.
+ * Provides methods to get font information.
+ * Naming:
+ * glyph index: original index of the glyph in the non-subset font (!= unicode index)
+ * character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset
+ * fonts, this is the same as the glyph index.
+ * Unicode index: The Unicode codepoint of a character.
+ * Glyph name: the Adobe glyph name (as found in Glyphs.java)
  */
-public class CIDSubset {
+public class CIDSubset implements CIDSet {
 
     /**
      * usedGlyphs contains orginal, new glyph index (glyph index -> char selector)
@@ -48,51 +46,36 @@
      * usedGlyphsIndex contains new glyph, original index (char selector -> glyph index)
      */
     private Map<Integer, Integer> usedGlyphsIndex = new HashMap<Integer, Integer>();
-    private int usedGlyphsCount = 0;
+    private int usedGlyphsCount;
 
     /**
      * usedCharsIndex contains new glyph, original char (char selector -> Unicode)
      */
     private Map<Integer, Character> usedCharsIndex = new HashMap<Integer, Character>();
 
-    /**
-     * Default constructor.
-     */
-    public CIDSubset() {
-    }
+    private final MultiByteFont font;
 
-    /**
-     * Adds the first glyph which is reserved for .notdef for all CID subsets.
-     */
-    public void setupFirstGlyph() {
-        usedGlyphs.put(Integer.valueOf(0), Integer.valueOf(0));
-        usedGlyphsIndex.put(Integer.valueOf(0), Integer.valueOf(0));
+    public CIDSubset(MultiByteFont mbf) {
+        font = mbf;
+        // The zeroth value is reserved for .notdef
+        usedGlyphs.put(0, 0);
+        usedGlyphsIndex.put(0, 0);
         usedGlyphsCount++;
     }
 
-    /**
-     * Returns the original index of the glyph inside the (non-subset) font's glyph list. This
-     * index can be used to access the character width information, for example.
-     * @param subsetIndex the subset index (character selector) to access the glyph
-     * @return the original index (or -1 if no glyph index is available for the subset index)
-     */
-    public int getGlyphIndexForSubsetIndex(int subsetIndex) {
-        Integer glyphIndex = usedGlyphsIndex.get(Integer.valueOf(subsetIndex));
+    /** {@inheritDoc} */
+    public int getOriginalGlyphIndex(int index) {
+        Integer glyphIndex = usedGlyphsIndex.get(index);
         if (glyphIndex != null) {
-            return glyphIndex.intValue();
+            return glyphIndex;
         } else {
             return -1;
         }
     }
 
-    /**
-     * Returns the Unicode value for a subset index (character selector). If there's no such
-     * Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned.
-     * @param subsetIndex the subset index (character selector)
-     * @return the Unicode value or "NOT A CHARACTER" (0xFFFF)
-     */
-    public char getUnicodeForSubsetIndex(int subsetIndex) {
-        Character mapValue = usedCharsIndex.get(Integer.valueOf(subsetIndex));
+    /** {@inheritDoc} */
+    public char getUnicode(int index) {
+        Character mapValue = usedCharsIndex.get(index);
         if (mapValue != null) {
             return mapValue.charValue();
         } else {
@@ -100,72 +83,60 @@
         }
     }
 
-    /**
-     * Maps a character to a character selector for a font subset. If the character isn't in the
-     * subset, yet, it is added and a new character selector returned. Otherwise, the already
-     * allocated character selector is returned from the existing map/subset.
-     * @param glyphIndex the glyph index of the character
-     * @param unicode the Unicode index of the character
-     * @return the subset index
-     */
-    public int mapSubsetChar(int glyphIndex, char unicode) {
+    /** {@inheritDoc} */
+    public int mapChar(int glyphIndex, char unicode) {
         // Reencode to a new subset font or get the reencoded value
         // IOW, accumulate the accessed characters and build a character map for them
-        Integer subsetCharSelector = usedGlyphs.get(Integer.valueOf(glyphIndex));
+        Integer subsetCharSelector = usedGlyphs.get(glyphIndex);
         if (subsetCharSelector == null) {
             int selector = usedGlyphsCount;
-            usedGlyphs.put(Integer.valueOf(glyphIndex),
-                           Integer.valueOf(selector));
-            usedGlyphsIndex.put(Integer.valueOf(selector),
-                                Integer.valueOf(glyphIndex));
-            usedCharsIndex.put(Integer.valueOf(selector),
-                                Character.valueOf(unicode));
+            usedGlyphs.put(glyphIndex, selector);
+            usedGlyphsIndex.put(selector, glyphIndex);
+            usedCharsIndex.put(selector, unicode);
             usedGlyphsCount++;
             return selector;
         } else {
-            return subsetCharSelector.intValue();
+            return subsetCharSelector;
         }
     }
 
-    /**
-     * Returns an unmodifiable Map of the font subset. It maps from glyph index to
-     * character selector (i.e. the subset index in this case).
-     * @return Map Map&lt;Integer, Integer&gt; of the font subset
-     */
-    public Map<Integer, Integer> getSubsetGlyphs() {
+    /** {@inheritDoc} */
+    public Map<Integer, Integer> getGlyphs() {
         return Collections.unmodifiableMap(this.usedGlyphs);
     }
 
-    /**
-     * Returns a char array containing all Unicode characters that are in the subset.
-     * @return a char array with all used Unicode characters
-     */
-    public char[] getSubsetChars() {
+    /** {@inheritDoc} */
+    public char[] getChars() {
         char[] charArray = new char[usedGlyphsCount];
         for (int i = 0; i < usedGlyphsCount; i++) {
-            charArray[i] = getUnicodeForSubsetIndex(i);
+            charArray[i] = getUnicode(i);
         }
         return charArray;
     }
 
-    /**
-     * Returns the number of glyphs in the subset.
-     * @return the number of glyphs in the subset
-     */
-    public int getSubsetSize() {
+    /** {@inheritDoc} */
+    public int getNumberOfGlyphs() {
         return this.usedGlyphsCount;
     }
 
-    /**
-     * Returns a BitSet with bits set for each available glyph index in the subset.
-     * @return a BitSet indicating available glyph indices
-     */
-    public BitSet getGlyphIndexBitSet() {
+    /** {@inheritDoc} */
+    public BitSet getGlyphIndices() {
         BitSet bitset = new BitSet();
         for (Integer cid : usedGlyphs.keySet()) {
-            bitset.set(cid.intValue());
+            bitset.set(cid);
         }
         return bitset;
     }
 
+    /** {@inheritDoc} */
+    public int[] getWidths() {
+        int[] widths = font.getWidths();
+        int[] tmpWidth = new int[getNumberOfGlyphs()];
+        for (int i = 0, c = getNumberOfGlyphs(); i < c; i++) {
+            int nwx = Math.max(0, getOriginalGlyphIndex(i));
+            tmpWidth[i] = widths[nwx];
+        }
+        return tmpWidth;
+    }
+
 }
diff --git a/src/java/org/apache/fop/fonts/DefaultFontConfig.java b/src/java/org/apache/fop/fonts/DefaultFontConfig.java
index 6c5cebb..375db34 100644
--- a/src/java/org/apache/fop/fonts/DefaultFontConfig.java
+++ b/src/java/org/apache/fop/fonts/DefaultFontConfig.java
@@ -89,7 +89,7 @@
             } else {
                 this.strict = strict;
                 this.fontInfoCfg = cfg.getChild("fonts", false);
-                instance = new DefaultFontConfig(cfg.getChild("auto-detect", false) != null);
+                instance = new DefaultFontConfig(fontInfoCfg.getChild("auto-detect", false) != null);
                 parse();
             }
         }
diff --git a/src/java/org/apache/fop/fonts/FontCache.java b/src/java/org/apache/fop/fonts/FontCache.java
index 8eceda3..52db98f 100644
--- a/src/java/org/apache/fop/fonts/FontCache.java
+++ b/src/java/org/apache/fop/fonts/FontCache.java
@@ -53,7 +53,7 @@
      * Serialization Version UID. Change this value if you want to make sure the
      * user's cache file is purged after an update.
      */
-    private static final long serialVersionUID = 605232520271754719L;
+    private static final long serialVersionUID = 9129238336422194339L;
 
     /** logging instance */
     private static Log log = LogFactory.getLog(FontCache.class);
@@ -65,7 +65,7 @@
     private static final String DEFAULT_CACHE_FILENAME = "fop-fonts.cache";
 
     /** has this cache been changed since it was last read? */
-    private transient boolean changed = false;
+    private transient boolean changed;
 
     /** change lock */
     private final boolean[] changeLock = new boolean[1];
@@ -73,12 +73,14 @@
     /**
      * master mapping of font url -> font info. This needs to be a list, since a
      * TTC file may contain more than 1 font.
+     * @serial
      */
     private Map<String, CachedFontFile> fontfileMap = null;
 
     /**
      * mapping of font url -> file modified date (for all fonts that have failed
      * to load)
+     * @serial
      */
     private Map<String, Long> failedFontMap = null;
 
@@ -139,6 +141,7 @@
      *
      * @return the font cache deserialized from the file (or null if no cache
      *         file exists or if it could not be read)
+     * @deprecated use {@link #loadFrom(File)} instead
      */
     public static FontCache load() {
         return loadFrom(getDefaultCacheFile(false));
@@ -190,8 +193,8 @@
     /**
      * Writes the font cache to disk.
      *
-     * @throws FOPException
-     *             fop exception
+     * @throws FOPException fop exception
+     * @deprecated use {@link #saveTo(File)} instead
      */
     public void save() throws FOPException {
         saveTo(getDefaultCacheFile(true));
diff --git a/src/java/org/apache/fop/fonts/FontCacheManager.java b/src/java/org/apache/fop/fonts/FontCacheManager.java
index fb0a032..a4acd43 100644
--- a/src/java/org/apache/fop/fonts/FontCacheManager.java
+++ b/src/java/org/apache/fop/fonts/FontCacheManager.java
@@ -19,7 +19,7 @@
 
 package org.apache.fop.fonts;
 
-import java.io.File;
+import java.net.URI;
 
 import org.apache.fop.apps.FOPException;
 
@@ -30,24 +30,26 @@
 public interface FontCacheManager {
 
     /**
+     * Sets the font cache file given the URI pointing to the file.
+     * @param fontCacheURI the font cache URI
+     */
+    void setCacheFile(URI fontCacheURI);
+
+    /**
      * Loads the font cache into memory from the given file.
-     * @param file the serialized font cache
      * @return the de-serialized font cache
      */
-    FontCache load(File file);
+    FontCache load();
 
     /**
      * Serializes the font cache to file.
-     * @param file the file to serialize the font cache to
      * @throws FOPException if an error occurs serializing the font cache
      */
-    void save(File file) throws FOPException;
+    void save() throws FOPException;
 
     /**
      * Deletes the font cache from the file-system.
-     * @param file delete the serialized font cache
      * @throws FOPException if an error occurs deleting the font cache
      */
-    void delete(File file) throws FOPException;
-
+    void delete() throws FOPException;
 }
diff --git a/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java b/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java
index 0236eff..c1d736b 100644
--- a/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java
+++ b/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java
@@ -20,6 +20,7 @@
 package org.apache.fop.fonts;
 
 import java.io.File;
+import java.net.URI;
 
 import org.apache.fop.apps.FOPException;
 
@@ -50,11 +51,14 @@
 
     private static final class FontCacheManagerImpl implements FontCacheManager {
 
+        /** Provides a font cache file path **/
+        private File cacheFile;
+
         private FontCache fontCache;
 
-        public FontCache load(File cacheFile) {
+        public FontCache load() {
             if (fontCache == null) {
-                fontCache = FontCache.loadFrom(cacheFile);
+                fontCache = FontCache.loadFrom(getCacheFile(false));
                 if (fontCache == null) {
                     fontCache = new FontCache();
                 }
@@ -62,31 +66,46 @@
             return fontCache;
         }
 
-        public void save(File cacheFile) throws FOPException {
+        public void save() throws FOPException {
             if (fontCache != null && fontCache.hasChanged()) {
-                fontCache.saveTo(cacheFile);
+                fontCache.saveTo(getCacheFile(true));
             }
         }
 
-        public void delete(File cacheFile) throws FOPException {
-            if (!cacheFile.delete()) {
+        public void delete() throws FOPException {
+            if (!getCacheFile(true).delete()) {
                 throw new FOPException("Failed to flush the font cache file '" + cacheFile + "'.");
             }
         }
+
+        private File getCacheFile(boolean forWriting) {
+            if (cacheFile != null) {
+                return cacheFile;
+            }
+            return FontCache.getDefaultCacheFile(forWriting);
+        }
+
+        public void setCacheFile(URI fontCacheURI) {
+            cacheFile = new File(fontCacheURI);
+        }
     }
 
     private static final class DisabledFontCacheManager implements FontCacheManager {
 
-        public FontCache load(File cacheFile) {
+        public FontCache load() {
             return null;
         }
 
-        public void save(File cacheFile) throws FOPException {
+        public void save() throws FOPException {
             // nop
         }
 
-        public void delete(File cacheFile) throws FOPException {
+        public void delete() throws FOPException {
             throw new FOPException("Font Cache disabled");
         }
+
+        public void setCacheFile(URI fontCacheURI) {
+            // nop
+        }
     }
 }
diff --git a/src/java/org/apache/fop/fonts/FontManager.java b/src/java/org/apache/fop/fonts/FontManager.java
index bff001f..3df8a90 100644
--- a/src/java/org/apache/fop/fonts/FontManager.java
+++ b/src/java/org/apache/fop/fonts/FontManager.java
@@ -19,7 +19,7 @@
 
 package org.apache.fop.fonts;
 
-import java.io.File;
+import java.net.URI;
 import java.util.List;
 
 import org.apache.fop.apps.FOPException;
@@ -52,9 +52,6 @@
     /** FontTriplet matcher for fonts that shall be referenced rather than embedded. */
     private FontTriplet.Matcher referencedFontsMatcher;
 
-    /** Provides a font cache file path **/
-    private File cacheFile;
-
     /**
      * Main constructor
      *
@@ -115,25 +112,10 @@
 
     /**
      * Sets the font cache file
-     * @param cacheFile the font cache file
+     * @param cacheFileURI the URI of the font cache file
      */
-    public void setCacheFile(File cacheFile) {
-        this.cacheFile = cacheFile;
-    }
-
-    /**
-     * Returns the font cache file
-     * @return the font cache file
-     */
-    public File getCacheFile() {
-        return getCacheFile(false);
-    }
-
-    private File getCacheFile(boolean writable) {
-        if (cacheFile != null) {
-            return cacheFile;
-        }
-        return FontCache.getDefaultCacheFile(writable);
+    public void setCacheFile(URI cacheFileURI) {
+        fontCacheManager.setCacheFile(resourceResolver.resolveFromBase(cacheFileURI));
     }
 
     /**
@@ -148,7 +130,7 @@
      * @return the font cache
      */
     public FontCache getFontCache() {
-        return fontCacheManager.load(getCacheFile());
+        return fontCacheManager.load();
     }
 
     /**
@@ -157,7 +139,7 @@
      * @throws FOPException fop exception
      */
     public void saveCache() throws FOPException {
-        fontCacheManager.save(getCacheFile());
+        fontCacheManager.save();
     }
 
     /**
@@ -165,7 +147,7 @@
      * @throws FOPException if an error was thrown while deleting the cache
      */
     public void deleteCache() throws FOPException {
-        fontCacheManager.delete(getCacheFile(true));
+        fontCacheManager.delete();
     }
 
     /**
diff --git a/src/java/org/apache/fop/fonts/FontManagerConfigurator.java b/src/java/org/apache/fop/fonts/FontManagerConfigurator.java
index c4fe194..cf92968 100644
--- a/src/java/org/apache/fop/fonts/FontManagerConfigurator.java
+++ b/src/java/org/apache/fop/fonts/FontManagerConfigurator.java
@@ -19,7 +19,6 @@
 
 package org.apache.fop.fonts;
 
-import java.io.File;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.List;
@@ -72,24 +71,10 @@
      * @throws FOPException if an exception occurs while processing the configuration
      */
     public void configure(FontManager fontManager, boolean strict) throws FOPException {
-        // caching (fonts)
-        if (cfg.getChild("use-cache", false) != null) {
-            try {
-                if (!cfg.getChild("use-cache").getValueAsBoolean()) {
-                    fontManager.disableFontCache();
-                } else {
-                    if (cfg.getChild("cache-file", false) != null) {
-                        fontManager.setCacheFile(new File(cfg.getChild("cache-file").getValue()));
-                    }
-                }
-            } catch (ConfigurationException mfue) {
-                LogUtil.handleException(log, mfue, true);
-            }
-        }
         if (cfg.getChild("font-base", false) != null) {
             try {
-                URI fontBase = InternalResourceResolver.getBaseURI(cfg.getChild("font-base").getValue(
-                        null));
+                URI fontBase = InternalResourceResolver.getBaseURI(cfg.getChild("font-base")
+                                                                      .getValue(null));
                 fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver(
                         defaultBaseUri.resolve(fontBase), resourceResolver));
             } catch (URISyntaxException use) {
@@ -99,7 +84,21 @@
             fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver(
                     defaultBaseUri, resourceResolver));
         }
+        // caching (fonts)
+        if (cfg.getChild("use-cache", false) != null) {
+            try {
+                if (!cfg.getChild("use-cache").getValueAsBoolean()) {
+                    fontManager.disableFontCache();
+                } else {
+                    if (cfg.getChild("cache-file", false) != null) {
 
+                        fontManager.setCacheFile(URI.create(cfg.getChild("cache-file").getValue()));
+                    }
+                }
+            } catch (ConfigurationException mfue) {
+                LogUtil.handleException(log, mfue, true);
+            }
+        }
         // [GA] permit configuration control over base14 kerning; without this,
         // there is no way for a user to enable base14 kerning other than by
         // programmatic API;
diff --git a/src/java/org/apache/fop/fonts/FontReader.java b/src/java/org/apache/fop/fonts/FontReader.java
index 68c5c71..0448c31 100644
--- a/src/java/org/apache/fop/fonts/FontReader.java
+++ b/src/java/org/apache/fop/fonts/FontReader.java
@@ -157,7 +157,7 @@
             throws SAXException {
         if (localName.equals("font-metrics")) {
             if ("TYPE0".equals(attributes.getValue("type"))) {
-                multiFont = new MultiByteFont(resourceResolver);
+                multiFont = new MultiByteFont(resourceResolver, EmbeddingMode.AUTO);
                 returnFont = multiFont;
                 isCID = true;
                 TTFReader.checkMetricsVersion(attributes);
diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java
index 4c42387..fef42f7 100644
--- a/src/java/org/apache/fop/fonts/LazyFont.java
+++ b/src/java/org/apache/fop/fonts/LazyFont.java
@@ -438,6 +438,9 @@
      */
     public boolean isSubsetEmbedded() {
         load(true);
+        if (realFont.isMultiByte() && this.embeddingMode == EmbeddingMode.FULL) {
+            return false;
+        }
         return realFont.isMultiByte();
     }
 
diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java
index a460140..da454c5 100644
--- a/src/java/org/apache/fop/fonts/MultiByteFont.java
+++ b/src/java/org/apache/fop/fonts/MultiByteFont.java
@@ -21,6 +21,7 @@
 
 import java.nio.CharBuffer;
 import java.nio.IntBuffer;
+import java.util.BitSet;
 import java.util.Map;
 
 import org.apache.commons.logging.Log;
@@ -44,13 +45,13 @@
     private static final Log log // CSOK: ConstantNameCheck
         = LogFactory.getLog(MultiByteFont.class);
 
-    private String ttcName = null;
+    private String ttcName;
     private String encoding = "Identity-H";
 
-    private int defaultWidth = 0;
+    private int defaultWidth;
     private CIDFontType cidType = CIDFontType.CIDTYPE2;
 
-    private CIDSubset subset = new CIDSubset();
+    private final CIDSet cidSet;
 
     /* advanced typographic support */
     private GlyphDefinitionTable gdef;
@@ -69,10 +70,15 @@
     /**
      * Default constructor
      */
-    public MultiByteFont(InternalResourceResolver resourceResolver) {
+    public MultiByteFont(InternalResourceResolver resourceResolver, EmbeddingMode embeddingMode) {
         super(resourceResolver);
-        subset.setupFirstGlyph();
         setFontType(FontType.TYPE0);
+        setEmbeddingMode(embeddingMode);
+        if (embeddingMode != EmbeddingMode.FULL) {
+            cidSet = new CIDSubset(this);
+        } else {
+            cidSet = new CIDFull(this);
+        }
     }
 
     /** {@inheritDoc} */
@@ -129,13 +135,16 @@
     }
 
     public boolean isSubsetEmbedded() {
+        if (getEmbeddingMode() == EmbeddingMode.FULL) {
+            return false;
+        }
         return true;
     }
 
     /** {@inheritDoc} */
     @Override
-    public CIDSubset getCIDSubset() {
-        return this.subset;
+    public CIDSet getCIDSet() {
+        return this.cidSet;
     }
 
     /** {@inheritDoc} */
@@ -147,7 +156,7 @@
     /** {@inheritDoc} */
     public int getWidth(int i, int size) {
         if (isEmbeddable()) {
-            int glyphIndex = subset.getGlyphIndexForSubsetIndex(i);
+            int glyphIndex = cidSet.getOriginalGlyphIndex(i);
             return size * width[glyphIndex];
         } else {
             return size * width[i];
@@ -283,9 +292,39 @@
             glyphIndex = findGlyphIndex(Typeface.NOT_FOUND);
         }
         if (isEmbeddable()) {
-            glyphIndex = subset.mapSubsetChar(glyphIndex, c);
+            glyphIndex = cidSet.mapChar(glyphIndex, c);
         }
-        return (char)glyphIndex;
+        return (char) glyphIndex;
+    }
+
+    protected BitSet getGlyphIndices() {
+        BitSet bitset = new BitSet();
+        bitset.set(0);
+        bitset.set(1);
+        bitset.set(2);
+        for (int i = 0; i < cmap.length; i++) {
+            int start = cmap[i].getUnicodeStart();
+            int end = cmap[i].getUnicodeEnd();
+            int glyphIndex = cmap[i].getGlyphStartIndex();
+            while (start++ < end + 1) {
+                bitset.set(glyphIndex++);
+            }
+        }
+        return bitset;
+    }
+
+    protected char[] getChars() {
+        // the width array is set when the font is built
+        char[] chars = new char[width.length];
+        for (int i = 0; i < cmap.length; i++) {
+            int start = cmap[i].getUnicodeStart();
+            int end = cmap[i].getUnicodeEnd();
+            int glyphIndex = cmap[i].getGlyphStartIndex();
+            while (start < end + 1) {
+                chars[glyphIndex++] = (char) start++;
+            }
+        }
+        return chars;
     }
 
     /** {@inheritDoc} */
@@ -331,15 +370,7 @@
      * @return Map Map of used Glyphs
      */
     public Map<Integer, Integer> getUsedGlyphs() {
-        return subset.getSubsetGlyphs();
-    }
-
-    /** @return an array of the chars used */
-    public char[] getCharsUsed() {
-        if (!isEmbeddable()) {
-            return null;
-        }
-        return subset.getSubsetChars();
+        return cidSet.getGlyphs();
     }
 
     /**
diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
index c97b172..a427fe5 100644
--- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
+++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
@@ -127,7 +127,7 @@
         }
 
         if (isCid) {
-            multiFont = new MultiByteFont(resourceResolver);
+            multiFont = new MultiByteFont(resourceResolver, embeddingMode);
             returnFont = multiFont;
             multiFont.setTTCName(ttcFontName);
         } else {
diff --git a/src/java/org/apache/fop/layoutmgr/BreakElement.java b/src/java/org/apache/fop/layoutmgr/BreakElement.java
index 77e7f14..f3f173d 100644
--- a/src/java/org/apache/fop/layoutmgr/BreakElement.java
+++ b/src/java/org/apache/fop/layoutmgr/BreakElement.java
@@ -21,6 +21,8 @@
 
 import java.util.List;
 
+import org.apache.fop.fo.Constants;
+
 /**
  * This class represents an unresolved break possibility.
  */
@@ -28,7 +30,7 @@
 
     private int penaltyWidth;
     private int penaltyValue;
-    private int breakClass = -1;
+    private int breakClass;
     private List pendingBeforeMarks;
     private List pendingAfterMarks;
 
@@ -39,7 +41,7 @@
      * @param context the layout context which contains the pending conditional elements
      */
     public BreakElement(Position position, int penaltyValue, LayoutContext context) {
-        this(position, penaltyValue, -1, context);
+        this(position, penaltyValue, Constants.EN_AUTO, context);
     }
 
     /**
@@ -80,7 +82,7 @@
         super(position);
         this.penaltyWidth = penaltyWidth;
         this.penaltyValue = penaltyValue;
-        this.breakClass = breakClass;
+        setBreakClass(breakClass);
         this.pendingBeforeMarks = context.getPendingBeforeMarks();
         this.pendingAfterMarks = context.getPendingAfterMarks();
     }
@@ -142,13 +144,24 @@
      *
      * @param breakClass one of
      *   {@link org.apache.fop.fo.Constants#EN_AUTO},
+     *   {@link org.apache.fop.fo.Constants#EN_LINE},
      *   {@link org.apache.fop.fo.Constants#EN_COLUMN},
      *   {@link org.apache.fop.fo.Constants#EN_PAGE},
      *   {@link org.apache.fop.fo.Constants#EN_EVEN_PAGE},
      *   {@link org.apache.fop.fo.Constants#EN_ODD_PAGE}.
      */
     public void setBreakClass(int breakClass) {
-        this.breakClass = breakClass;
+        switch (breakClass) {
+        case Constants.EN_AUTO:
+        case Constants.EN_LINE:
+        case Constants.EN_COLUMN:
+        case Constants.EN_PAGE:
+        case Constants.EN_EVEN_PAGE:
+        case Constants.EN_ODD_PAGE:
+            this.breakClass = breakClass;
+            break;
+        default: throw new IllegalArgumentException("Illegal value for break class: " + breakClass);
+        }
     }
 
     /** @return the pending border and padding elements at the before edge */
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreaker.java b/src/java/org/apache/fop/layoutmgr/PageBreaker.java
index 58cb0ae..309f4e3 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreaker.java
@@ -95,8 +95,7 @@
         return new PageBreakingLayoutListener() {
 
             public void notifyOverflow(int part, int amount, FObj obj) {
-                Page p = pageProvider.getPage(
-                            false, part, PageProvider.RELTO_CURRENT_ELEMENT_LIST);
+                Page p = pageProvider.getPageFromColumnIndex(part);
                 RegionBody body = (RegionBody)p.getSimplePageMaster().getRegion(
                         Region.FO_REGION_BODY);
                 BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
diff --git a/src/java/org/apache/fop/layoutmgr/PageProvider.java b/src/java/org/apache/fop/layoutmgr/PageProvider.java
index 0ad9908..8117d54 100644
--- a/src/java/org/apache/fop/layoutmgr/PageProvider.java
+++ b/src/java/org/apache/fop/layoutmgr/PageProvider.java
@@ -151,28 +151,26 @@
         return this.lastReportedBPD;
     }
 
-    // Wish there were a more elegant way to do this in Java
-    private int[] getColIndexAndColCount(int index) {
-        int columnCount = 0;
-        int colIndex = startColumnOfCurrentElementList + index;
-        int pageIndex = -1;
-        do {
-            colIndex -= columnCount;
-            pageIndex++;
-            Page page = getPage(false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
-            columnCount = page.getPageViewport().getCurrentSpan().getColumnCount();
-        } while (colIndex >= columnCount);
-        return new int[] {colIndex, columnCount};
+    private static class Column {
+
+        final Page page;
+
+        final int pageIndex;
+
+        final int colIndex;
+
+        final int columnCount;
+
+        Column(Page page, int pageIndex, int colIndex, int columnCount) {
+            this.page = page;
+            this.pageIndex = pageIndex;
+            this.colIndex = colIndex;
+            this.columnCount = columnCount;
+        }
+
     }
 
-    /**
-     * Compares the IPD of the given part with the following one.
-     *
-     * @param index index of the current part
-     * @return a negative integer, zero or a positive integer as the current IPD is less
-     * than, equal to or greater than the IPD of the following part
-     */
-    public int compareIPDs(int index) {
+    private Column getColumn(int index) {
         int columnCount = 0;
         int colIndex = startColumnOfCurrentElementList + index;
         int pageIndex = -1;
@@ -183,12 +181,24 @@
             page = getPage(false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
             columnCount = page.getPageViewport().getCurrentSpan().getColumnCount();
         } while (colIndex >= columnCount);
-        if (colIndex + 1 < columnCount) {
+        return new Column(page, pageIndex, colIndex, columnCount);
+    }
+
+    /**
+     * Compares the IPD of the given part with the following one.
+     *
+     * @param index index of the current part
+     * @return a negative integer, zero or a positive integer as the current IPD is less
+     * than, equal to or greater than the IPD of the following part
+     */
+    public int compareIPDs(int index) {
+        Column column = getColumn(index);
+        if (column.colIndex + 1 < column.columnCount) {
             // Next part is a column on same page => same IPD
             return 0;
         } else {
-            Page nextPage = getPage(false, pageIndex + 1, RELTO_CURRENT_ELEMENT_LIST);
-            return page.getPageViewport().getBodyRegion().getIPD()
+            Page nextPage = getPage(false, column.pageIndex + 1, RELTO_CURRENT_ELEMENT_LIST);
+            return column.page.getPageViewport().getBodyRegion().getIPD()
                     - nextPage.getPageViewport().getBodyRegion().getIPD();
         }
     }
@@ -199,7 +209,7 @@
      * @return  {@code true} if the break starts a new page
      */
     boolean startPage(int index) {
-        return getColIndexAndColCount(index)[0] == 0;
+        return getColumn(index).colIndex == 0;
     }
 
     /**
@@ -208,8 +218,8 @@
      * @return  {@code true} if the break ends a page
      */
     boolean endPage(int index) {
-        int[] colIndexAndColCount = getColIndexAndColCount(index);
-        return colIndexAndColCount[0] == colIndexAndColCount[1] - 1;
+        Column column = getColumn(index);
+        return column.colIndex == column.columnCount - 1;
     }
 
     /**
@@ -219,7 +229,7 @@
      * @return  the number of columns
      */
     int getColumnCount(int index) {
-        return getColIndexAndColCount(index)[1];
+        return getColumn(index).columnCount;
     }
 
     /**
@@ -229,24 +239,12 @@
      * @return the requested part index
      */
     public int getStartingPartIndexForLastPage(int partCount) {
-        int result = 0;
-        int idx = 0;
-        int pageIndex = 0;
-        int colIndex = startColumnOfCurrentElementList;
-        Page page = getPage(
-                false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
-        while (idx < partCount) {
-            if ((colIndex >= page.getPageViewport().getCurrentSpan().getColumnCount())) {
-                colIndex = 0;
-                pageIndex++;
-                page = getPage(
-                        false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
-                result = idx;
-            }
-            colIndex++;
-            idx++;
-        }
-        return result;
+        int lastPartIndex = partCount - 1;
+        return lastPartIndex - getColumn(lastPartIndex).colIndex;
+    }
+
+    Page getPageFromColumnIndex(int columnIndex) {
+        return getColumn(columnIndex).page;
     }
 
     /**
@@ -291,7 +289,9 @@
                 log.trace("last page requested: " + index);
             }
         }
-        while (intIndex >= cachedPages.size()) {
+        if (intIndex > cachedPages.size()) {
+            throw new UnsupportedOperationException("Cannot handle holes in page cache");
+        } else if (intIndex == cachedPages.size()) {
             if (log.isTraceEnabled()) {
                 log.trace("Caching " + index);
             }
diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
index 00cd427..ac3f8f8 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
@@ -649,6 +649,10 @@
         log.trace("Restarting line breaking from index " + restartPosition.getIndex());
         int parIndex = restartPosition.getLeafPos();
         KnuthSequence paragraph = knuthParagraphs.get(parIndex);
+        if (paragraph instanceof Paragraph) {
+            ((Paragraph) paragraph).ignoreAtStart = 0;
+            isFirstInBlock = false;
+        }
         paragraph.subList(0, restartPosition.getIndex() + 1).clear();
         Iterator<KnuthElement> iter = paragraph.iterator();
         while (iter.hasNext() && !iter.next().isBox()) {
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
index 5a4152c..928be43 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
@@ -39,6 +39,7 @@
 import org.apache.fop.layoutmgr.BlockLevelEventProducer;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
 import org.apache.fop.layoutmgr.BreakElement;
+import org.apache.fop.layoutmgr.BreakOpportunity;
 import org.apache.fop.layoutmgr.ConditionalElementListener;
 import org.apache.fop.layoutmgr.KnuthElement;
 import org.apache.fop.layoutmgr.KnuthGlue;
@@ -62,7 +63,7 @@
  * the render background.
  */
 public class TableLayoutManager extends BlockStackingLayoutManager
-                implements ConditionalElementListener {
+                implements ConditionalElementListener, BreakOpportunity {
 
     /**
      * logging instance
diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java
index dad404d..0b41284 100644
--- a/src/java/org/apache/fop/pdf/PDFDocument.java
+++ b/src/java/org/apache/fop/pdf/PDFDocument.java
@@ -37,6 +37,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import org.apache.fop.pdf.StandardStructureAttributes.Table.Scope;
 import org.apache.fop.pdf.xref.CrossReferenceStream;
 import org.apache.fop.pdf.xref.CrossReferenceTable;
 import org.apache.fop.pdf.xref.TrailerDictionary;
@@ -354,19 +355,20 @@
     }
 
     /**
-     * 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(PDFName structureType, PDFObject parent) {
-        PDFStructElem structElem = new PDFStructElem(parent, structureType);
+    public void registerStructureElement(PDFStructElem structElem) {
         assignObjectNumber(structElem);
         structureTreeElements.add(structElem);
-        return 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 void registerStructureElement(PDFStructElem structElem, Scope scope) {
+        registerStructureElement(structElem);
+        versionController.addTableHeaderScopeAttribute(structElem, scope);
     }
 
     /**
diff --git a/src/java/org/apache/fop/pdf/PDFEncoding.java b/src/java/org/apache/fop/pdf/PDFEncoding.java
index bf2799c..64fd6f8 100644
--- a/src/java/org/apache/fop/pdf/PDFEncoding.java
+++ b/src/java/org/apache/fop/pdf/PDFEncoding.java
@@ -23,6 +23,9 @@
 import java.util.Collections;
 import java.util.Set;
 
+import org.apache.fop.fonts.CodePointMapping;
+import org.apache.fop.fonts.SingleByteEncoding;
+
 /**
  * Class representing an /Encoding object.
  *
@@ -74,6 +77,38 @@
     }
 
     /**
+     * Creates a PDFEncoding instance from a CodePointMapping instance.
+     * @param encoding the code point mapping (encoding)
+     * @param fontName ...
+     * @return the PDF Encoding dictionary (or a String with the predefined encoding)
+     */
+    static Object createPDFEncoding(SingleByteEncoding encoding, String fontName) {
+        //If encoding type is null, return null which causes /Encoding to be omitted.
+        if (encoding == null) {
+            return null;
+        }
+        String encodingName = null;
+        SingleByteEncoding baseEncoding;
+        if (fontName.indexOf("Symbol") >= 0) {
+            baseEncoding = CodePointMapping.getMapping(CodePointMapping.SYMBOL_ENCODING);
+            encodingName = baseEncoding.getName();
+        } else {
+            baseEncoding = CodePointMapping.getMapping(CodePointMapping.STANDARD_ENCODING);
+        }
+        PDFEncoding pdfEncoding = new PDFEncoding(encodingName);
+        PDFEncoding.DifferencesBuilder builder = pdfEncoding.createDifferencesBuilder();
+        PDFArray differences = builder.buildDifferencesArray(baseEncoding, encoding);
+        // TODO This method should not be returning an Object with two different outcomes
+        // resulting in subsequent `if (X instanceof Y)` statements.
+        if (differences.length() > 0) {
+            pdfEncoding.setDifferences(differences);
+            return pdfEncoding;
+        } else {
+            return encodingName;
+        }
+    }
+
+    /**
      * Indicates whether a given encoding is one of the predefined encodings.
      * @param name the encoding name (ex. "StandardEncoding")
      * @return true if it is a predefined encoding
@@ -83,6 +118,15 @@
     }
 
     /**
+     * Indicates whether the given encoding type is that of standard encoding
+     * @param name The encoding name
+     * @return Returns true if it is of type standard encoding
+     */
+    static boolean hasStandardEncoding(String encodingName) {
+        return encodingName.equals(STANDARD_ENCODING);
+    }
+
+    /**
      * Creates and returns a new DifferencesBuilder instance for constructing the Differences
      * array.
      * @return the DifferencesBuilder
@@ -104,18 +148,44 @@
      */
     public class DifferencesBuilder {
 
-        private PDFArray differences = new PDFArray();
         private int currentCode = -1;
 
         /**
+         * Creates an array containing the differences between two single-byte.
+         * font encodings.
+         * @param encodingA The first single-byte encoding
+         * @param encodingB The second single-byte encoding
+         * @return The PDFArray of differences between encodings
+         */
+        public PDFArray buildDifferencesArray(SingleByteEncoding encodingA,
+                SingleByteEncoding encodingB) {
+            PDFArray differences = new PDFArray();
+            int start = -1;
+            String[] baseNames = encodingA.getCharNameMap();
+            String[] charNameMap = encodingB.getCharNameMap();
+            for (int i = 0, ci = charNameMap.length; i < ci; i++) {
+                String basec = baseNames[i];
+                String c = charNameMap[i];
+                if (!basec.equals(c)) {
+                    if (start != i) {
+                        addDifference(i, differences);
+                        start = i;
+                    }
+                    addName(c, differences);
+                    start++;
+                }
+            }
+            return differences;
+        }
+
+        /**
          * Start a new difference.
          * @param code the starting code index inside the encoding
          * @return this builder instance
          */
-        public DifferencesBuilder addDifference(int code) {
+        private void addDifference(int code, PDFArray differences) {
             this.currentCode = code;
-            this.differences.add(new Integer(code));
-            return this;
+            differences.add(Integer.valueOf(code));
         }
 
         /**
@@ -123,28 +193,11 @@
          * @param name the character name
          * @return this builder instance
          */
-        public DifferencesBuilder addName(String name) {
+        private void addName(String name, PDFArray differences) {
             if (this.currentCode < 0) {
                 throw new IllegalStateException("addDifference(int) must be called first");
             }
-            this.differences.add(new PDFName(name));
-            return this;
-        }
-
-        /**
-         * Indicates whether any differences have been recorded.
-         * @return true if there are differences.
-         */
-        public boolean hasDifferences() {
-            return (this.differences.length() > 0);
-        }
-
-        /**
-         * Creates and returns the PDFArray representing the Differences entry.
-         * @return the Differences entry
-         */
-        public PDFArray toPDFArray() {
-            return this.differences;
+            differences.add(new PDFName(name));
         }
     }
 
diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java
index 633ce9d..31be73a 100644
--- a/src/java/org/apache/fop/pdf/PDFFactory.java
+++ b/src/java/org/apache/fop/pdf/PDFFactory.java
@@ -44,9 +44,9 @@
 import org.apache.xmlgraphics.xmp.Metadata;
 
 import org.apache.fop.fonts.CIDFont;
-import org.apache.fop.fonts.CIDSubset;
 import org.apache.fop.fonts.CodePointMapping;
 import org.apache.fop.fonts.CustomFont;
+import org.apache.fop.fonts.EmbeddingMode;
 import org.apache.fop.fonts.FontDescriptor;
 import org.apache.fop.fonts.FontMetrics;
 import org.apache.fop.fonts.FontType;
@@ -1369,23 +1369,14 @@
                 } else {
                     cidMetrics = (CIDFont)metrics;
                 }
-                PDFCIDSystemInfo sysInfo
-                    = new PDFCIDSystemInfo(cidMetrics.getRegistry(),
-                                         cidMetrics.getOrdering(),
-                                         cidMetrics.getSupplement());
-                PDFCIDFont cidFont = new PDFCIDFont(subsetFontName,
-                                   cidMetrics.getCIDType(),
-                                   cidMetrics.getDefaultWidth(),
-                                   getSubsetWidths(cidMetrics), sysInfo,
-                                   (PDFCIDFontDescriptor)pdfdesc);
+                PDFCIDSystemInfo sysInfo = new PDFCIDSystemInfo(cidMetrics.getRegistry(),
+                        cidMetrics.getOrdering(), cidMetrics.getSupplement());
+                PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, cidMetrics.getCIDType(),
+                        cidMetrics.getDefaultWidth(), getFontWidths(cidMetrics), sysInfo,
+                        (PDFCIDFontDescriptor) pdfdesc);
                 getDocument().registerObject(cidFont);
-
-                PDFCMap cmap = new PDFToUnicodeCMap(
-                        cidMetrics.getCIDSubset().getSubsetChars(),
-                        "fop-ucs-H",
-                        new PDFCIDSystemInfo("Adobe",
-                            "Identity",
-                            0), false);
+                PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics.getCIDSet().getChars(), "fop-ucs-H",
+                        new PDFCIDSystemInfo("Adobe", "Identity", 0), false);
                 getDocument().registerObject(cmap);
                 ((PDFFontType0)font).setCMAP(cmap);
                 ((PDFFontType0)font).setDescendantFonts(cidFont);
@@ -1469,61 +1460,18 @@
     /**
      * Creates a PDFEncoding instance from a CodePointMapping instance.
      * @param encoding the code point mapping (encoding)
-     * @param fontNameHint ...
+     * @param fontName ...
      * @return the PDF Encoding dictionary (or a String with the predefined encoding)
      */
-    public Object createPDFEncoding(SingleByteEncoding encoding, String fontNameHint) {
-        SingleByteEncoding baseEncoding;
-        if (fontNameHint.indexOf("Symbol") >= 0) {
-            baseEncoding = CodePointMapping.getMapping(
-                    CodePointMapping.SYMBOL_ENCODING);
-        } else {
-            baseEncoding = CodePointMapping.getMapping(
-                    CodePointMapping.STANDARD_ENCODING);
-        }
-        PDFEncoding pdfEncoding = new PDFEncoding(baseEncoding.getName());
-        PDFEncoding.DifferencesBuilder builder
-                = pdfEncoding.createDifferencesBuilder();
-        int start = -1;
-        String[] baseNames = baseEncoding.getCharNameMap();
-        String[] charNameMap = encoding.getCharNameMap();
-        for (int i = 0, ci = charNameMap.length; i < ci; i++) {
-            String basec = baseNames[i];
-            String c = charNameMap[i];
-            if (!basec.equals(c)) {
-                if (start != i) {
-                    builder.addDifference(i);
-                    start = i;
-                }
-                builder.addName(c);
-                start++;
-            }
-        }
-        if (builder.hasDifferences()) {
-            pdfEncoding.setDifferences(builder.toPDFArray());
-            return pdfEncoding;
-        } else {
-            return baseEncoding.getName();
-        }
+    public Object createPDFEncoding(SingleByteEncoding encoding, String fontName) {
+        return PDFEncoding.createPDFEncoding(encoding, fontName);
     }
 
-    /**
-     * Creates and returns a width array with the widths of all the characters in the subset.
-     * @param cidFont the font
-     * @return the width array
-     */
-    public PDFWArray getSubsetWidths(CIDFont cidFont) {
+    private PDFWArray getFontWidths(CIDFont cidFont) {
         // Create widths for reencoded chars
         PDFWArray warray = new PDFWArray();
-        int[] widths = cidFont.getWidths();
-        CIDSubset subset = cidFont.getCIDSubset();
-        int[] tmpWidth = new int[subset.getSubsetSize()];
-
-        for (int i = 0, c = subset.getSubsetSize(); i < c; i++) {
-            int nwx = Math.max(0, subset.getGlyphIndexForSubsetIndex(i));
-            tmpWidth[i] = widths[nwx];
-        }
-        warray.addEntry(0, tmpWidth);
+        int[] widths = cidFont.getCIDSet().getWidths();
+        warray.addEntry(0, widths);
         return warray;
     }
 
@@ -1591,13 +1539,13 @@
     }
 
     private void buildCIDSet(PDFFontDescriptor descriptor, CIDFont cidFont) {
-        BitSet cidSubset = cidFont.getCIDSubset().getGlyphIndexBitSet();
-        PDFStream cidSet = makeStream(null, true);
-        ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSubset.length() / 8 + 1);
+        BitSet cidSet = cidFont.getCIDSet().getGlyphIndices();
+        PDFStream pdfStream = makeStream(null, true);
+        ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSet.length() / 8 + 1);
         int value = 0;
-        for (int i = 0, c = cidSubset.length(); i < c; i++) {
+        for (int i = 0, c = cidSet.length(); i < c; i++) {
             int shift = i % 8;
-            boolean b = cidSubset.get(i);
+            boolean b = cidSet.get(i);
             if (b) {
                 value |= 1 << 7 - shift;
             }
@@ -1608,8 +1556,8 @@
         }
         baout.write(value);
         try {
-            cidSet.setData(baout.toByteArray());
-            descriptor.setCIDSet(cidSet);
+            pdfStream.setData(baout.toByteArray());
+            descriptor.setCIDSet(pdfStream);
         } catch (IOException ioe) {
             log.error(
                     "Failed to write CIDSet [" + cidFont + "] "
@@ -1640,14 +1588,16 @@
                 if (desc.getFontType() == FontType.TYPE0) {
                     MultiByteFont mbfont = (MultiByteFont) font;
                     FontFileReader reader = new FontFileReader(in);
-
-                    TTFSubSetFile subset = new TTFSubSetFile();
-                    subset.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs());
-                    byte[] subsetFont = subset.getFontSubset();
-                    // Only TrueType CID fonts are supported now
-
-                    embeddedFont = new PDFTTFStream(subsetFont.length);
-                    ((PDFTTFStream) embeddedFont).setData(subsetFont, subsetFont.length);
+                    byte[] fontBytes;
+                    if (font.getEmbeddingMode() == EmbeddingMode.FULL) {
+                        fontBytes = reader.getAllBytes();
+                    } else {
+                        TTFSubSetFile ttfFile = new TTFSubSetFile();
+                        ttfFile.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs());
+                        fontBytes = ttfFile.getFontSubset();
+                    }
+                    embeddedFont = new PDFTTFStream(fontBytes.length);
+                    ((PDFTTFStream) embeddedFont).setData(fontBytes, fontBytes.length);
                 } else if (desc.getFontType() == FontType.TYPE1) {
                     PFBParser parser = new PFBParser();
                     PFBData pfb = parser.parsePFB(in);
diff --git a/src/java/org/apache/fop/pdf/PDFFont.java b/src/java/org/apache/fop/pdf/PDFFont.java
index 191fd22..9b9d1c1 100644
--- a/src/java/org/apache/fop/pdf/PDFFont.java
+++ b/src/java/org/apache/fop/pdf/PDFFont.java
@@ -70,7 +70,7 @@
      * @param encoding the encoding
      */
     public void setEncoding(String encoding) {
-        if (encoding != null) {
+        if (encoding != null && !PDFEncoding.hasStandardEncoding(encoding)) {
             put("Encoding", new PDFName(encoding));
         }
     }
diff --git a/src/java/org/apache/fop/pdf/PDFProfile.java b/src/java/org/apache/fop/pdf/PDFProfile.java
index 580a9a7..98005e4 100644
--- a/src/java/org/apache/fop/pdf/PDFProfile.java
+++ b/src/java/org/apache/fop/pdf/PDFProfile.java
@@ -202,7 +202,8 @@
             PDFDictionary markInfo = getDocument().getRoot().getMarkInfo();
             if (markInfo == null) {
                 throw new PDFConformanceException(format(
-                        "{0} requires the MarkInfo dictionary to be present", getPDFAMode()));
+                        "{0} requires that the accessibility option in the configuration file be enabled",
+                        getPDFAMode()));
             }
             if (!Boolean.TRUE.equals(markInfo.get("Marked"))) {
                 throw new PDFConformanceException(format(err,
diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java
index 2a756fe..8250318 100644
--- a/src/java/org/apache/fop/pdf/PDFStructElem.java
+++ b/src/java/org/apache/fop/pdf/PDFStructElem.java
@@ -26,14 +26,16 @@
 import java.util.Locale;
 
 import org.apache.fop.accessibility.StructureTreeElement;
+import org.apache.fop.pdf.StandardStructureAttributes.Table;
 import org.apache.fop.util.LanguageTags;
 
 /**
  * Class representing a PDF Structure Element.
  */
-public class PDFStructElem extends PDFDictionary implements StructureTreeElement, CompressedObject {
+public class PDFStructElem extends StructureHierarchyMember
+        implements StructureTreeElement, CompressedObject {
 
-    private static final PDFName TABLE = new PDFName("Table");
+    private StructureType structureType;
 
     private PDFStructElem parentElement;
 
@@ -50,12 +52,17 @@
      * @param parent parent of this element
      * @param structureType the structure type of this element
      */
-    PDFStructElem(PDFObject parent, PDFName structureType) {
+    public PDFStructElem(PDFObject parent, StructureType structureType) {
+        this(parent);
+        this.structureType = structureType;
+        put("S", structureType.getName());
+        setParent(parent);
+    }
+
+    private PDFStructElem(PDFObject parent) {
         if (parent instanceof PDFStructElem) {
             parentElement = (PDFStructElem) parent;
         }
-        put("S", structureType);
-        setParent(parent);
     }
 
     /**
@@ -80,6 +87,7 @@
      *
      * @param kid element to be added
      */
+    @Override
     public void addKid(PDFObject kid) {
         if (kids == null) {
             kids = new ArrayList<PDFObject>();
@@ -113,8 +121,8 @@
      *
      * @return the value of the S entry
      */
-    public PDFName getStructureType() {
-        return (PDFName) get("S");
+    public StructureType getStructureType() {
+        return structureType;
     }
 
     /**
@@ -201,7 +209,7 @@
 
     private void setTableAttributeRowColumnSpan(String typeSpan, int span) {
         PDFDictionary attribute = new PDFDictionary();
-        attribute.put("O", TABLE);
+        attribute.put("O", Table.NAME);
         attribute.put(typeSpan, span);
         if (attributes == null) {
             attributes = new ArrayList<PDFDictionary>(2);
@@ -228,13 +236,8 @@
             }
         }
 
-        /**
-         * Constructor
-         * @param parent -
-         * @param name -
-         */
-        public Placeholder(PDFObject parent, String name) {
-            super(parent, new PDFName(name));
+        public Placeholder(PDFObject parent) {
+            super(parent);
         }
     }
 
diff --git a/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java
index 5f19bb2..ca6d82d 100644
--- a/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java
+++ b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java
@@ -22,7 +22,7 @@
 /**
  * Class representing a PDF /StructTreeRoot dictionary.
  */
-public class PDFStructTreeRoot extends PDFDictionary {
+public class PDFStructTreeRoot extends StructureHierarchyMember {
 
     /**
      * Creates a new /StructTreeRoot dictionary.
@@ -49,6 +49,7 @@
      *
      * @param kid an object to be added to the K entry
      */
+    @Override
     public void addKid(PDFObject kid) {
         getKids().add(kid);
     }
diff --git a/src/java/org/apache/fop/pdf/StandardStructureAttributes.java b/src/java/org/apache/fop/pdf/StandardStructureAttributes.java
new file mode 100644
index 0000000..0a93d46
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/StandardStructureAttributes.java
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+/**
+ * Standard attributes, as defined in section 10.7.5 of the PDF Reference, Fourth edition (PDF 1.5).
+ */
+public final class StandardStructureAttributes {
+
+    public static final class Table {
+
+        /**
+         * The name to use as an attribute owner. This is the value of the 'O' entry in
+         * the attribute's dictionary.
+         */
+        public static final PDFName NAME = new PDFName("Table");
+
+        public static enum Scope {
+            ROW("Row"),
+            COLUMN("Column"),
+            BOTH("Both");
+
+            private final PDFName name;
+
+            private Scope(String name) {
+                this.name = new PDFName(name);
+            }
+
+            /**
+             * Returns the name of this attribute.
+             *
+             * @return a name suitable for use as a value in the attribute's dictionary
+             */
+            public PDFName getName() {
+                return name;
+            }
+
+            /**
+             * Sets the given scope on the given table header element.
+             */
+            static void addScopeAttribute(PDFStructElem th, Scope scope) {
+                PDFDictionary scopeAttribute = new PDFDictionary();
+                scopeAttribute.put("O", Table.NAME);
+                scopeAttribute.put("Scope", scope.getName());
+                th.put("A", scopeAttribute);
+            }
+        }
+    }
+
+    private StandardStructureAttributes() { }
+
+}
diff --git a/src/java/org/apache/fop/pdf/StandardStructureTypes.java b/src/java/org/apache/fop/pdf/StandardStructureTypes.java
new file mode 100644
index 0000000..6955011
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/StandardStructureTypes.java
@@ -0,0 +1,137 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Standard structure types, as defined in section 10.7.4 of the PDF Reference, Fourth Edition (PDF 1.5).
+ */
+public final class StandardStructureTypes {
+
+    public static final class Grouping {
+
+        public static final StructureType DOCUMENT = new StructureTypeImpl("Document");
+        public static final StructureType PART = new StructureTypeImpl("Part");
+        public static final StructureType ART = new StructureTypeImpl("Art");
+        public static final StructureType SECT = new StructureTypeImpl("Sect");
+        public static final StructureType DIV = new StructureTypeImpl("Div");
+        public static final StructureType BLOCK_QUOTE = new StructureTypeImpl("BlockQuote");
+        public static final StructureType CAPTION = new StructureTypeImpl("Caption");
+        public static final StructureType TOC = new StructureTypeImpl("TOC");
+        public static final StructureType TOCI = new StructureTypeImpl("TOCI");
+        public static final StructureType INDEX = new StructureTypeImpl("Index");
+        public static final StructureType NON_STRUCT = new StructureTypeImpl("NonStruct");
+        public static final StructureType PRIVATE = new StructureTypeImpl("Private");
+    }
+
+    public static final class Paragraphlike {
+        public static final StructureType H = new StructureTypeImpl("H");
+        public static final StructureType H1 = new StructureTypeImpl("H1");
+        public static final StructureType H2 = new StructureTypeImpl("H2");
+        public static final StructureType H3 = new StructureTypeImpl("H3");
+        public static final StructureType H4 = new StructureTypeImpl("H4");
+        public static final StructureType H5 = new StructureTypeImpl("H5");
+        public static final StructureType H6 = new StructureTypeImpl("H6");
+        public static final StructureType P = new StructureTypeImpl("P");
+    }
+
+    public static final class List {
+        public static final StructureType L = new StructureTypeImpl("L");
+        public static final StructureType LI = new StructureTypeImpl("LI");
+        public static final StructureType LBL = new StructureTypeImpl("Lbl");
+        public static final StructureType LBODY = new StructureTypeImpl("LBody");
+    }
+
+    public static final class Table {
+        public static final StructureType TABLE = new StructureTypeImpl("Table");
+        public static final StructureType TR = new StructureTypeImpl("TR");
+        public static final StructureType TH = new StructureTypeImpl("TH");
+        public static final StructureType TD = new StructureTypeImpl("TD");
+        public static final StructureType THEAD = new StructureTypeImpl("THead");
+        public static final StructureType TBODY = new StructureTypeImpl("TBody");
+        public static final StructureType TFOOT = new StructureTypeImpl("TFoot");
+    }
+
+    public static final class InlineLevelStructure {
+        public static final StructureType SPAN = new StructureTypeImpl("Span");
+        public static final StructureType QUOTE = new StructureTypeImpl("Quote");
+        public static final StructureType NOTE = new StructureTypeImpl("Note");
+        public static final StructureType REFERENCE = new StructureTypeImpl("Reference");
+        public static final StructureType BIB_ENTRY = new StructureTypeImpl("BibEntry");
+        public static final StructureType CODE = new StructureTypeImpl("Code");
+        public static final StructureType LINK = new StructureTypeImpl("Link");
+        public static final StructureType ANNOT = new StructureTypeImpl("Annot");
+    }
+
+    public static final class RubyOrWarichu {
+        public static final StructureType RUBY = new StructureTypeImpl("Ruby");
+        public static final StructureType RB = new StructureTypeImpl("RB");
+        public static final StructureType RT = new StructureTypeImpl("RT");
+        public static final StructureType RP = new StructureTypeImpl("RP");
+        public static final StructureType WARICHU = new StructureTypeImpl("Warichu");
+        public static final StructureType WT = new StructureTypeImpl("WT");
+        public static final StructureType WP = new StructureTypeImpl("WP");
+    }
+
+    public static final class Illustration {
+        public static final StructureType FIGURE = new StructureTypeImpl("Figure");
+        public static final StructureType FORMULA = new StructureTypeImpl("Formula");
+        public static final StructureType FORM = new StructureTypeImpl("Form");
+    }
+
+    private static class StructureTypeImpl implements StructureType {
+
+        private final PDFName name;
+
+        protected StructureTypeImpl(String name) {
+            this.name = new PDFName(name);
+            StandardStructureTypes.STRUCTURE_TYPES.put(name, this);
+        }
+
+        public PDFName getName() {
+            return name;
+        }
+
+        @Override
+        public String toString() {
+            return name.toString().substring(1);
+        }
+
+    }
+
+    private static final Map<String, StructureType> STRUCTURE_TYPES = new HashMap<String, StructureType>();
+
+    private StandardStructureTypes() { }
+
+    /**
+     * Returns the standard structure type of the given name.
+     *
+     * @param name the name of a structure type, case sensitive. For example, Document,
+     * Sect, H1, etc.
+     * @return the corresponding {@code StructureType} instance, or {@code null} if the given
+     * name does not correspond to a standard structure type
+     */
+    public static StructureType get(String name) {
+        return STRUCTURE_TYPES.get(name);
+    }
+
+}
diff --git a/src/java/org/apache/fop/pdf/StructureHierarchyMember.java b/src/java/org/apache/fop/pdf/StructureHierarchyMember.java
new file mode 100644
index 0000000..e3be921
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/StructureHierarchyMember.java
@@ -0,0 +1,37 @@
+/*
+ * 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);
+
+}
diff --git a/src/java/org/apache/fop/pdf/StructureType.java b/src/java/org/apache/fop/pdf/StructureType.java
new file mode 100644
index 0000000..7b9b4c1
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/StructureType.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * A structure type, as defined in Section 10.6.2 of the PDF Reference, fourth edition (PDF 1.5).
+ */
+public interface StructureType {
+
+    /**
+     * Returns the name of this structure type.
+     *
+     * @return the name object identifying this structure type
+     */
+    PDFName getName();
+
+}
diff --git a/src/java/org/apache/fop/pdf/VersionController.java b/src/java/org/apache/fop/pdf/VersionController.java
index 4a92f49..bd5e4d2 100644
--- a/src/java/org/apache/fop/pdf/VersionController.java
+++ b/src/java/org/apache/fop/pdf/VersionController.java
@@ -19,6 +19,8 @@
 
 package org.apache.fop.pdf;
 
+import org.apache.fop.pdf.StandardStructureAttributes.Table.Scope;
+
 /**
  * An abstraction that controls the mutability of the PDF version for a document.
  */
@@ -47,6 +49,8 @@
      */
     public abstract void setPDFVersion(Version version);
 
+    abstract void addTableHeaderScopeAttribute(PDFStructElem th, Scope scope);
+
     @Override
     public String toString() {
         return version.toString();
@@ -67,6 +71,13 @@
         public void setPDFVersion(Version version) {
             throw new IllegalStateException("Cannot change the version of this PDF document.");
         }
+
+        @Override
+        void addTableHeaderScopeAttribute(PDFStructElem th, Scope scope) {
+            if (super.version.compareTo(Version.V1_4) > 0) {
+                Scope.addScopeAttribute(th, scope);
+            }
+        }
     }
 
     /**
@@ -91,6 +102,12 @@
                 doc.getRoot().setVersion(version);
             }
         }
+
+        @Override
+        void addTableHeaderScopeAttribute(PDFStructElem th, Scope scope) {
+            setPDFVersion(Version.V1_5);
+            Scope.addScopeAttribute(th, scope);
+        }
     }
 
     /**
diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
index a0b1e99..35db42a 100644
--- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
+++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
@@ -318,7 +318,8 @@
                 case IN_PAGE_HEADER:
                     String name = aps.getName();
                     String value = aps.getValue();
-                    dataStream.createTagLogicalElement(name, value);
+                    int encoding = aps.getEncoding();
+                    dataStream.createTagLogicalElement(name, value, encoding);
                     break;
                 default:
                     throw new IFException(
diff --git a/src/java/org/apache/fop/render/afp/AFPFontConfig.java b/src/java/org/apache/fop/render/afp/AFPFontConfig.java
index eca7607..aef0b66 100644
--- a/src/java/org/apache/fop/render/afp/AFPFontConfig.java
+++ b/src/java/org/apache/fop/render/afp/AFPFontConfig.java
@@ -329,8 +329,8 @@
             AFPResourceAccessor accessor = getAccessor(resourceResolver);
             CharacterSet characterSet = CharacterSetBuilder.getDoubleByteInstance().buildDBCS(
                     characterset, super.codePage, super.encoding, charsetType, accessor, eventProducer);
-            return getFontInfo(new DoubleByteFont(super.codePage, super.embeddable, characterSet),
-                    this);
+            return getFontInfo(new DoubleByteFont(super.codePage, super.embeddable, characterSet,
+                    eventProducer), this);
         }
     }
 
@@ -365,7 +365,8 @@
                 characterSet = CharacterSetBuilder.getSingleByteInstance().buildSBCS(
                         characterset, super.codePage, super.encoding, accessor, eventProducer);
             }
-            return getFontInfo(new OutlineFont(super.name, super.embeddable, characterSet), this);
+            return getFontInfo(new OutlineFont(super.name, super.embeddable, characterSet,
+                    eventProducer), this);
         }
     }
 
diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java b/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java
index 14a34a0..abf6e35 100644
--- a/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java
+++ b/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java
@@ -144,6 +144,12 @@
                 if (placement != null && placement.length() > 0) {
                     pageSetupExtn.setPlacement(ExtensionPlacement.fromXMLValue(placement));
                 }
+
+                String encoding =  lastAttributes.getValue("encoding");
+                if (encoding != null && pageSetupExtn != null) {
+                    pageSetupExtn.setEncoding(Integer.parseInt(encoding));
+                }
+
                 if (content.length() > 0 && pageSetupExtn != null) {
                     pageSetupExtn.setContent(content.toString());
                     content.setLength(0); //Reset text buffer (see characters())
diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java
index 2d30f3a..27db41d 100644
--- a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java
+++ b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java
@@ -23,6 +23,8 @@
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.AttributesImpl;
 
+import org.apache.fop.afp.modca.TagLogicalElement;
+
 /**
  * This is the pass-through value object for the AFP extension.
  */
@@ -48,6 +50,27 @@
     protected ExtensionPlacement placement = ExtensionPlacement.DEFAULT;
 
     /**
+     * the CCSID character set encoding
+     */
+    protected int encoding = TagLogicalElement.State.ENCODING_NONE;
+
+    /**
+     *
+     * @return CCSID character set encoding
+     */
+    public int getEncoding() {
+        return encoding;
+    }
+
+    /**
+     *
+     * @param encoding CCSID character set encoding
+     */
+    public void setEncoding(int encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
      * Default constructor.
      *
      * @param elementName the name of the setup code object, may be null
diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java
index 42be9bf..9b325c5 100644
--- a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java
+++ b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java
@@ -35,6 +35,7 @@
  */
 public class AFPPageSetupElement extends AbstractAFPExtensionObject {
 
+    private static final String ATT_ENCODING = "encoding";
     private static final String ATT_SRC = "src";
 
     /**
@@ -105,6 +106,16 @@
             } else {
                 missingPropertyError(AFPPageSetup.ATT_VALUE);
             }
+            attr = attlist.getValue(ATT_ENCODING);
+            if (attr != null) {
+                try {
+                    pageSetup.setEncoding(Integer.parseInt(attr));
+                } catch (NumberFormatException nfe) {
+                    invalidPropertyValueError(ATT_ENCODING, attr, nfe);
+                }
+
+            }
+
         }
         String placement = attlist.getValue(AFPPageSetup.ATT_PLACEMENT);
         if (placement != null && placement.length() > 0) {
diff --git a/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java b/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java
index 262caa5..8d0ce14 100644
--- a/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java
+++ b/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java
@@ -84,7 +84,7 @@
         super(context);
         //Set target resolution
         int dpi = Math.round(context.getUserAgent().getTargetResolution());
-        getSettings().getWriterParams().setResolution(dpi);
+        getSettings().setResolution(dpi);
 
         Map renderingOptions = getUserAgent().getRendererOptions();
         setTargetBitmapSize((Dimension)renderingOptions.get(TARGET_BITMAP_SIZE));
diff --git a/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java b/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java
index d239fe0..4363f1d 100644
--- a/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java
+++ b/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java
@@ -107,4 +107,27 @@
         return this.qualityRendering;
     }
 
+    /**
+     * Sets the compression method for the image writer.
+     * @param compressionMethod the compression method name
+     */
+    public void setCompressionMethod(String compressionMethod) {
+        writerParams.setCompressionMethod(compressionMethod);
+    }
+
+    /**
+     * Returns the compression method being used by the image writer.
+     * @return the compression method in use
+     */
+    public String getCompressionMethod() {
+        return writerParams.getCompressionMethod();
+    }
+
+    /**
+     * Sets the resolution of the output image.
+     * @param dpi the dots-per-inch of the image
+     */
+    public void setResolution(int dpi) {
+        writerParams.setResolution(dpi);
+    }
 }
diff --git a/src/java/org/apache/fop/render/bitmap/TIFFCompressionValue.java b/src/java/org/apache/fop/render/bitmap/TIFFCompressionValue.java
new file mode 100644
index 0000000..4e9c3bd
--- /dev/null
+++ b/src/java/org/apache/fop/render/bitmap/TIFFCompressionValue.java
@@ -0,0 +1,98 @@
+/*
+ * 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.bitmap;
+
+import java.awt.image.BufferedImage;
+
+/**
+ * Compression constants for TIFF image output.
+ */
+public enum TIFFCompressionValue {
+    /** No compression */
+    NONE("NONE"),
+    /** JPEG compression */
+    JPEG("JPEG"),
+    /** Packbits (RLE) compression */
+    PACKBITS("PackBits"),
+    /** Deflate compression */
+    DEFLATE("Deflate"),
+    /** LZW compression */
+    LZW("LZW"),
+    /** ZLib compression */
+    ZLIB("ZLib"),
+    /** CCITT Group 3 (T.4) compression */
+    CCITT_T4("CCITT T.4", BufferedImage.TYPE_BYTE_BINARY, true),
+    /** CCITT Group 4 (T.6) compression */
+    CCITT_T6("CCITT T.6", BufferedImage.TYPE_BYTE_BINARY, true);
+
+    private final String name;
+    private final int imageType;
+    private boolean isCcitt;
+
+    private TIFFCompressionValue(String name, int imageType, boolean isCcitt) {
+        this.name = name;
+        this.imageType = imageType;
+        this.isCcitt = isCcitt;
+    }
+
+    private TIFFCompressionValue(String name) {
+        this(name, BufferedImage.TYPE_INT_ARGB, false);
+    }
+
+    /**
+     * Returns the name of this compression type.
+     * @return the compression name
+     */
+    String getName() {
+        return name;
+    }
+
+    /**
+     * Returns an image type for this compression type, a constant from {@link BufferedImage} e.g.
+     * {@link BufferedImage#TYPE_INT_ARGB} for {@link #ZLIB}
+     * @return the image type
+     */
+    int getImageType() {
+        return imageType;
+    }
+
+    /**
+     * Returns whether or not this compression type is a CCITT type.
+     * @return true if the compression type is CCITT
+     */
+    boolean hasCCITTCompression() {
+        return isCcitt;
+    }
+
+    /**
+     * Return the TIFF compression constant given the string representing the type. In the case that
+     * the name doesn't match any of the compression values, <code>null</code> is returned.
+     * @param name the compression type name
+     * @return the compression constant
+     */
+    static TIFFCompressionValue getType(String name) {
+        for (TIFFCompressionValue tiffConst : TIFFCompressionValue.values()) {
+            if (tiffConst.name.equalsIgnoreCase(name)) {
+                return tiffConst;
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/java/org/apache/fop/render/bitmap/TIFFCompressionValues.java b/src/java/org/apache/fop/render/bitmap/TIFFCompressionValues.java
deleted file mode 100644
index 7164902..0000000
--- a/src/java/org/apache/fop/render/bitmap/TIFFCompressionValues.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.bitmap;
-
-/**
- * Constants for TIFF output.
- */
-public enum TIFFCompressionValues {
-    /** No compression */
-    NONE("NONE"),
-    /** JPEG compression */
-    JPEG("JPEG"),
-    /** Packbits (RLE) compression */
-    PACKBITS("PackBits"),
-    /** Deflate compression */
-    DEFLATE("Deflate"),
-    /** LZW compression */
-    LZW("LZW"),
-    /** ZLib compression */
-    ZLIB("ZLib"),
-    /** CCITT Group 4 (T.6) compression */
-    CCITT_T6("CCITT T.6"), //CCITT Group 4
-    /** CCITT Group 3 (T.4) compression */
-    CCITT_T4("CCITT T.4"); //CCITT Group 3
-
-    private final String name;
-
-    private TIFFCompressionValues(String name) {
-        this.name = name;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public static TIFFCompressionValues getValue(String name) {
-        for (TIFFCompressionValues tiffConst : TIFFCompressionValues.values()) {
-            if (tiffConst.name.equalsIgnoreCase(name)) {
-                return tiffConst;
-            }
-        }
-        return null;
-    }
-}
diff --git a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java
index 48e7952..0de02c7 100644
--- a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java
+++ b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java
@@ -19,6 +19,8 @@
 
 package org.apache.fop.render.bitmap;
 
+import org.apache.xmlgraphics.image.writer.ResolutionUnit;
+
 import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser;
 import org.apache.fop.render.intermediate.IFContext;
@@ -32,6 +34,7 @@
 
     TIFFDocumentHandler(IFContext context) {
         super(context);
+        getSettings().getWriterParams().setResolutionUnit(ResolutionUnit.CENTIMETER);
     }
 
     /** {@inheritDoc} */
diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java b/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java
index 5b75a37..48da62e 100644
--- a/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java
+++ b/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java
@@ -38,7 +38,6 @@
 import org.apache.xmlgraphics.image.GraphicsUtil;
 import org.apache.xmlgraphics.image.rendered.FormatRed;
 import org.apache.xmlgraphics.image.writer.ImageWriter;
-import org.apache.xmlgraphics.image.writer.ImageWriterParams;
 import org.apache.xmlgraphics.image.writer.ImageWriterRegistry;
 import org.apache.xmlgraphics.image.writer.MultiImageWriter;
 
@@ -47,9 +46,9 @@
 import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.render.java2d.Java2DRenderer;
 
-import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T4;
-import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T6;
-import static org.apache.fop.render.bitmap.TIFFCompressionValues.PACKBITS;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.CCITT_T4;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.CCITT_T6;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.PACKBITS;
 
 /**
  * <p>
@@ -74,11 +73,7 @@
  */
 public class TIFFRenderer extends Java2DRenderer {
 
-    /** ImageWriter parameters */
-    private ImageWriterParams writerParams;
-
-    /** Image Type as parameter for the BufferedImage constructor (see BufferedImage.TYPE_*) */
-    private int bufferedImageType = BufferedImage.TYPE_INT_ARGB;
+    private BitmapRenderingSettings imageSettings;
 
     private OutputStream outputStream;
 
@@ -94,11 +89,11 @@
      */
     public TIFFRenderer(FOUserAgent userAgent) {
         super(userAgent);
-        writerParams = new ImageWriterParams();
-        writerParams.setCompressionMethod(PACKBITS.getName());
-
+        imageSettings = new BitmapRenderingSettings();
+        imageSettings.setCompressionMethod(PACKBITS.getName());
+        imageSettings.setBufferedImageType(BufferedImage.TYPE_INT_ARGB);
         int dpi = Math.round(userAgent.getTargetResolution());
-        writerParams.setResolution(dpi);
+        imageSettings.setResolution(dpi);
     }
 
     /** {@inheritDoc} */
@@ -129,7 +124,7 @@
                 // Write all pages/images
                 while (pageImagesItr.hasNext()) {
                     RenderedImage img = (RenderedImage) pageImagesItr.next();
-                    multiWriter.writeImage(img, writerParams);
+                    multiWriter.writeImage(img, imageSettings.getWriterParams());
                 }
             } finally {
                 multiWriter.close();
@@ -139,7 +134,7 @@
             if (pageImagesItr.hasNext()) {
                 renderedImage = (RenderedImage) pageImagesItr.next();
             }
-            writer.writeImage(renderedImage, outputStream, writerParams);
+            writer.writeImage(renderedImage, outputStream, imageSettings.getWriterParams());
             if (pageImagesItr.hasNext()) {
                 BitmapRendererEventProducer eventProducer
                     = BitmapRendererEventProducer.Provider.get(
@@ -156,7 +151,7 @@
 
     /** {@inheritDoc} */
     protected BufferedImage getBufferedImage(int bitmapWidth, int bitmapHeight) {
-        return new BufferedImage(bitmapWidth, bitmapHeight, bufferedImageType);
+        return new BufferedImage(bitmapWidth, bitmapHeight, imageSettings.getBufferedImageType());
     }
 
     /** Private inner class to lazy page rendering. */
@@ -195,7 +190,7 @@
                 throw new NoSuchElementException(e.getMessage());
             }
 
-            TIFFCompressionValues compression = TIFFCompressionValues.getValue(writerParams.getCompressionMethod());
+            TIFFCompressionValue compression = TIFFCompressionValue.getType(imageSettings.getCompressionMethod());
             if (compression == CCITT_T4 || compression == CCITT_T6) {
                 return pageImage;
             } else {
@@ -226,11 +221,14 @@
 
     /** @param bufferedImageType an image type */
     public void setBufferedImageType(int bufferedImageType) {
-        this.bufferedImageType = bufferedImageType;
+        imageSettings.setBufferedImageType(bufferedImageType);
     }
 
-    /** @return image writer parameters */
-    public ImageWriterParams getWriterParams() {
-        return writerParams;
+    /**
+     * Returns the settings for the image rendering.
+     * @return the image rendering settings
+     */
+    public BitmapRenderingSettings getRenderingSettings() {
+        return imageSettings;
     }
 }
diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java
index 5417ecc..1e44397 100644
--- a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java
+++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java
@@ -23,21 +23,24 @@
 
 import org.apache.avalon.framework.configuration.Configuration;
 
-import org.apache.xmlgraphics.util.MimeConstants;
-
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.fonts.DefaultFontConfig;
 import org.apache.fop.fonts.DefaultFontConfig.DefaultFontConfigParser;
 import org.apache.fop.render.RendererConfigOption;
 
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.PACKBITS;
+
 /**
  * The renderer configuration object for the TIFF renderer.
  */
 public final class TIFFRendererConfig extends BitmapRendererConfig {
 
     public enum TIFFRendererOption implements RendererConfigOption {
-        COMPRESSION("compression", TIFFCompressionValues.PACKBITS);
+        COMPRESSION("compression", PACKBITS),
+        /** option to encode one row per strip or a all rows in a single strip*/
+        SINGLE_STRIP("single-strip", Boolean.FALSE);
 
         private final String name;
         private final Object defaultValue;
@@ -63,8 +66,16 @@
         super(fontConfig);
     }
 
-    public TIFFCompressionValues getCompressionType() {
-        return (TIFFCompressionValues) params.get(TIFFRendererOption.COMPRESSION);
+    public TIFFCompressionValue getCompressionType() {
+        return (TIFFCompressionValue) params.get(TIFFRendererOption.COMPRESSION);
+    }
+
+    /**
+     * @return True if all rows are contained in a single strip, False each strip contains one row or null
+     * if not set.
+     */
+    public Boolean isSingleStrip() {
+        return (Boolean) params.get(TIFFRendererOption.SINGLE_STRIP);
     }
 
     /**
@@ -92,9 +103,10 @@
                     .parse(cfg, userAgent.validateStrictly()));
             super.build(config, userAgent, cfg);
             if (cfg != null) {
-            setParam(TIFFRendererOption.COMPRESSION,
-                        TIFFCompressionValues.getValue(getValue(cfg,
-                                TIFFRendererOption.COMPRESSION)));
+                setParam(TIFFRendererOption.COMPRESSION,
+                        TIFFCompressionValue.getType(getValue(cfg, TIFFRendererOption.COMPRESSION)));
+                setParam(TIFFRendererOption.SINGLE_STRIP, Boolean.valueOf(getValue(cfg,
+                                TIFFRendererOption.SINGLE_STRIP)));
             }
             return config;
         }
diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java
index b10f2a3..19abb81 100644
--- a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java
+++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java
@@ -19,13 +19,9 @@
 
 package org.apache.fop.render.bitmap;
 
-import java.awt.image.BufferedImage;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import org.apache.xmlgraphics.image.writer.ImageWriterParams;
-
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.render.Renderer;
@@ -33,9 +29,7 @@
 import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser;
 import org.apache.fop.render.intermediate.IFDocumentHandler;
 
-import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T4;
-import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T6;
-import static org.apache.fop.render.bitmap.TIFFCompressionValues.NONE;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.NONE;
 
 /**
  * TIFF Renderer configurator
@@ -62,43 +56,40 @@
         final TIFFRendererConfig config = (TIFFRendererConfig) getRendererConfig(renderer);
         if (config != null) {
             TIFFRenderer tiffRenderer = (TIFFRenderer) renderer;
-            //set compression
-            tiffRenderer.setBufferedImageType(getCompressionType(config, tiffRenderer.getWriterParams()));
+            setCompressionMethod(config.getCompressionType(), tiffRenderer.getRenderingSettings());
         }
         super.configure(renderer);
     }
 
-    private int getCompressionType(TIFFRendererConfig config, ImageWriterParams writerParms)
-            throws FOPException {
-        //Some compression formats need a special image format:
-        TIFFCompressionValues compression = config.getCompressionType();
+    private void setCompressionMethod(TIFFCompressionValue compression,
+            BitmapRenderingSettings settings) throws FOPException {
         if (compression != null) {
             if (compression != NONE) {
-                writerParms.setCompressionMethod(compression.getName());
+                settings.setCompressionMethod(compression.getName());
             }
             if (LOG.isInfoEnabled()) {
                 LOG.info("TIFF compression set to " + compression.getName());
             }
-        }
-        return getBufferedImageTypeFor(compression);
-    }
-
-    private int getBufferedImageTypeFor(TIFFCompressionValues compressionType) {
-        if (compressionType == CCITT_T6 || compressionType == CCITT_T4) {
-            return BufferedImage.TYPE_BYTE_BINARY;
-        } else {
-            return BufferedImage.TYPE_INT_ARGB;
+            if (compression.hasCCITTCompression()) {
+                settings.setBufferedImageType(compression.getImageType());
+            }
         }
     }
 
-    /** {@inheritDoc} */
+    private boolean isSingleStrip(TIFFRendererConfig config) {
+        Boolean singleRowPerStrip = config.isSingleStrip();
+        return singleRowPerStrip == null ? false : singleRowPerStrip;
+    }
+
+    @Override
     public void configure(IFDocumentHandler documentHandler) throws FOPException {
-        final TIFFRendererConfig tiffConfig = (TIFFRendererConfig) getRendererConfig(documentHandler);
-        if (tiffConfig != null) {
+        final TIFFRendererConfig config = (TIFFRendererConfig) getRendererConfig(documentHandler);
+        if (config != null) {
             TIFFDocumentHandler tiffHandler = (TIFFDocumentHandler) documentHandler;
             BitmapRenderingSettings settings = tiffHandler.getSettings();
             configure(documentHandler, settings, new TIFFRendererConfigParser());
-            settings.setBufferedImageType(getCompressionType(tiffConfig, settings.getWriterParams()));
+            setCompressionMethod(config.getCompressionType(), settings);
+            settings.getWriterParams().setSingleStrip(isSingleStrip(config));
         }
     }
 
diff --git a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java
deleted file mode 100644
index 0f752e8..0000000
--- a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * 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.HashMap;
-import java.util.Map;
-
-import org.apache.fop.events.EventBroadcaster;
-import org.apache.fop.pdf.PDFName;
-import org.apache.fop.pdf.PDFObject;
-import org.apache.fop.pdf.PDFStructElem;
-
-/**
- * This class provides the standard mappings from Formatting Objects to PDF structure types.
- */
-final class FOToPDFRoleMap {
-
-    /**
-     * Standard structure types defined by the PDF Reference, Fourth Edition (PDF 1.5).
-     */
-    private static final Map<String, PDFName> STANDARD_STRUCTURE_TYPES
-            = new HashMap<String, PDFName>();
-
-    private static final Map<String, Mapper> DEFAULT_MAPPINGS
-            = new java.util.HashMap<String, Mapper>();
-
-    private static final PDFName THEAD;
-    private static final PDFName NON_STRUCT;
-
-    static {
-        // Create PDFNames for the standard structure types
-        // Table 10.18: Grouping elements
-        addStructureType("Document");
-        addStructureType("Part");
-        addStructureType("Art");
-        addStructureType("Sect");
-        addStructureType("Div");
-        addStructureType("BlockQuote");
-        addStructureType("Caption");
-        addStructureType("TOC");
-        addStructureType("TOCI");
-        addStructureType("Index");
-        addStructureType("NonStruct");
-        addStructureType("Private");
-        // Table 10.20: Paragraphlike elements
-        addStructureType("H");
-        addStructureType("H1");
-        addStructureType("H2");
-        addStructureType("H3");
-        addStructureType("H4");
-        addStructureType("H5");
-        addStructureType("H6");
-        addStructureType("P");
-        // Table 10.21: List elements
-        addStructureType("L");
-        addStructureType("LI");
-        addStructureType("Lbl");
-        addStructureType("LBody");
-        // Table 10.22: Table elements
-        addStructureType("Table");
-        addStructureType("TR");
-        addStructureType("TH");
-        addStructureType("TD");
-        addStructureType("THead");
-        addStructureType("TBody");
-        addStructureType("TFoot");
-        // Table 10.23: Inline-level structure elements
-        addStructureType("Span");
-        addStructureType("Quote");
-        addStructureType("Note");
-        addStructureType("Reference");
-        addStructureType("BibEntry");
-        addStructureType("Code");
-        addStructureType("Link");
-        addStructureType("Annot");
-        // Table 10.24: Ruby and Warichu elements
-        addStructureType("Ruby");
-        addStructureType("RB");
-        addStructureType("RT");
-        addStructureType("RP");
-        addStructureType("Warichu");
-        addStructureType("WT");
-        addStructureType("WP");
-        // Table 10.25: Illustration elements
-        addStructureType("Figure");
-        addStructureType("Formula");
-        addStructureType("Form");
-
-        NON_STRUCT = STANDARD_STRUCTURE_TYPES.get("NonStruct");
-        assert NON_STRUCT != null;
-        THEAD = STANDARD_STRUCTURE_TYPES.get("THead");
-        assert THEAD != null;
-
-        // Create the standard mappings
-        // Declarations and Pagination and Layout Formatting Objects
-        addMapping("root",                      "Document");
-        addMapping("page-sequence",             "Part");
-        addMapping("flow",                      "Sect");
-        addMapping("static-content",            "Sect");
-        // Block-level Formatting Objects
-        addMapping("block",                     "P");
-        addMapping("block-container",           "Div");
-        // Inline-level Formatting Objects
-        addMapping("character",                 "Span");
-        addMapping("external-graphic",          "Figure");
-        addMapping("instream-foreign-object",   "Figure");
-        addMapping("inline",                    "Span");
-        addMapping("inline-container",          "Div");
-        addMapping("page-number",               "Quote");
-        addMapping("page-number-citation",      "Quote");
-        addMapping("page-number-citation-last", "Quote");
-        // Formatting Objects for Tables
-        addMapping("table-and-caption",         "Div");
-        addMapping("table",                     "Table");
-        addMapping("table-caption",             "Caption");
-        addMapping("table-header",              "THead");
-        addMapping("table-footer",              "TFoot");
-        addMapping("table-body",                "TBody");
-        addMapping("table-row",                 "TR");
-        addMapping("table-cell",                new TableCellMapper());
-        // Formatting Objects for Lists
-        addMapping("list-block",                "L");
-        addMapping("list-item",                 "LI");
-        addMapping("list-item-body",            "LBody");
-        addMapping("list-item-label",           "Lbl");
-        // Dynamic Effects: Link and Multi Formatting Objects
-        addMapping("basic-link",                "Link");
-        // Out-of-Line Formatting Objects
-        addMapping("float",                     "Div");
-        addMapping("footnote",                  "Note");
-        addMapping("footnote-body",             "Sect");
-        addMapping("wrapper",                   "Span");
-        addMapping("marker",                    "Private");
-    }
-
-    private static void addStructureType(String structureType) {
-        STANDARD_STRUCTURE_TYPES.put(structureType, new PDFName(structureType));
-    }
-
-    private static void addMapping(String fo, String structureType) {
-        PDFName type = STANDARD_STRUCTURE_TYPES.get(structureType);
-        assert type != null;
-        addMapping(fo, new SimpleMapper(type));
-    }
-
-    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 PDFName mapFormattingObject(String fo, String role,
-            PDFObject parent, EventBroadcaster eventBroadcaster) {
-        PDFName type = null;
-        if (role == null) {
-            type = getDefaultMappingFor(fo, parent);
-        } else {
-            type = STANDARD_STRUCTURE_TYPES.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 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);
-    }
-
-    private static class SimpleMapper implements Mapper {
-
-        private PDFName structureType;
-
-        public SimpleMapper(PDFName structureType) {
-            this.structureType = structureType;
-        }
-
-        public PDFName getStructureType(PDFObject parent) {
-            return structureType;
-        }
-
-    }
-
-    private static class TableCellMapper implements Mapper {
-
-        public PDFName getStructureType(PDFObject parent) {
-            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 = STANDARD_STRUCTURE_TYPES.get("TH");
-            } else {
-                type = STANDARD_STRUCTURE_TYPES.get("TD");
-            }
-            assert type != null;
-            return type;
-        }
-
-    }
-
-    private FOToPDFRoleMap() { }
-}
diff --git a/src/java/org/apache/fop/render/pdf/PDFEventProducer.java b/src/java/org/apache/fop/render/pdf/PDFEventProducer.java
index 40062f7..4b82538 100644
--- a/src/java/org/apache/fop/render/pdf/PDFEventProducer.java
+++ b/src/java/org/apache/fop/render/pdf/PDFEventProducer.java
@@ -59,12 +59,11 @@
      * 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.
diff --git a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
index 6559e8d..ee00d24 100644
--- a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
+++ b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
@@ -132,7 +132,7 @@
                 ? structureTreeElement.getParentStructElem()
                 : structureTreeElement;
         pageParentTreeArray.add(parent);
-        String type = parent.getStructureType().toString();
+        String type = parent.getStructureType().getName().toString();
         int mcid = pageParentTreeArray.length() - 1;
         return new MarkedContentInfo(type, mcid, structureTreeElement);
     }
diff --git a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java
index 0f8e745..0d4a6b7 100644
--- a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java
+++ b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java
@@ -21,25 +21,272 @@
 
 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.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;
+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 PDFFactory pdfFactory;
+    private static final String ROLE = "role";
 
-    private PDFLogicalStructureHandler logicalStructureHandler;
+    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;
 
@@ -51,97 +298,65 @@
         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;
     }
 
+    void setLogicalStructureHandler(PDFLogicalStructureHandler logicalStructureHandler) {
+        createRootStructureElement(logicalStructureHandler);
+    }
+
+    private void createRootStructureElement(PDFLogicalStructureHandler logicalStructureHandler) {
+        assert rootStructureElement == null;
+        PDFParentTree parentTree = logicalStructureHandler.getParentTree();
+        PDFStructTreeRoot structTreeRoot = pdfFactory.getDocument().makeStructTreeRoot(parentTree);
+        rootStructureElement = createStructureElement("root", structTreeRoot,
+                new AttributesImpl(), pdfFactory, 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) {
-        PDFName structureType = FOToPDFRoleMap.mapFormattingObject(name, role, parent, eventBroadcaster);
-        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, name);
-        } else {
-            structElem = createStructureElement(name, parent, role);
-        }
-        parent.addKid(structElem);
-        ancestors.addFirst(structElem);
-        return structElem;
+        return startNode(name, attributes);
     }
 
 }
diff --git a/src/java/org/apache/fop/render/pdf/PageSequenceStructElem.java b/src/java/org/apache/fop/render/pdf/PageSequenceStructElem.java
new file mode 100644
index 0000000..09d5b81
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/PageSequenceStructElem.java
@@ -0,0 +1,79 @@
+/*
+ * 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);
+            }
+        }
+    }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/TableStructElem.java b/src/java/org/apache/fop/render/pdf/TableStructElem.java
new file mode 100644
index 0000000..c44acb2
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/TableStructElem.java
@@ -0,0 +1,48 @@
+/*
+ * 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();
+    }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java
index c99bb21..9e810c8 100644
--- a/src/java/org/apache/fop/render/ps/PSFontUtils.java
+++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java
@@ -38,7 +38,7 @@
 
 import org.apache.fop.fonts.Base14Font;
 import org.apache.fop.fonts.CIDFontType;
-import org.apache.fop.fonts.CIDSubset;
+import org.apache.fop.fonts.CIDSet;
 import org.apache.fop.fonts.CMapSegment;
 import org.apache.fop.fonts.CustomFont;
 import org.apache.fop.fonts.EmbeddingMode;
@@ -457,15 +457,17 @@
         // TODO /FontInfo
 
         gen.write("/CIDCount ");
-        CIDSubset cidSubset = font.getCIDSubset();
-        int subsetSize = cidSubset.getSubsetSize();
-        gen.write(subsetSize);
+        CIDSet cidSet = font.getCIDSet();
+        int numberOfGlyphs = cidSet.getNumberOfGlyphs();
+        gen.write(numberOfGlyphs);
         gen.writeln(" def");
         gen.writeln("/GDBytes 2 def"); // TODO always 2?
         gen.writeln("/CIDMap [<");
         int colCount = 0;
         int lineCount = 1;
-        for (int cid = 0; cid < subsetSize; cid++) {
+        int nextBitSet = 0;
+        int previousBitSet = 0;
+        for (int cid = 0; cid < numberOfGlyphs; cid++) {
             if (colCount++ == 20) {
                 gen.newLine();
                 colCount = 1;
@@ -478,7 +480,23 @@
             if (font.getEmbeddingMode() != EmbeddingMode.FULL) {
                 gid = HexEncoder.encode(cid, 4);
             } else {
-                gid = HexEncoder.encode(cidSubset.getGlyphIndexForSubsetIndex(cid), 4);
+                previousBitSet = nextBitSet;
+                nextBitSet = cidSet.getGlyphIndices().nextSetBit(nextBitSet);
+                while (previousBitSet++ < nextBitSet) {
+                    // if there are gaps in the indices we pad them with zeros
+                    gen.write("0000");
+                    cid++;
+                    if (colCount++ == 20) {
+                        gen.newLine();
+                        colCount = 1;
+                        if (lineCount++ == 800) {
+                            gen.writeln("> <");
+                            lineCount = 1;
+                        }
+                    }
+                }
+                gid = HexEncoder.encode(nextBitSet, 4);
+                nextBitSet++;
             }
             gen.write(gid);
         }
diff --git a/status.xml b/status.xml
index 145cd15..7571ddf 100644
--- a/status.xml
+++ b/status.xml
@@ -62,6 +62,62 @@
       documents. Example: the fix of marks layering will be such a case when it's done.
     -->
     <release version="FOP Trunk" date="TBD">
+      <action context="Fonts" dev="MH" type="add" fixes-bug="53868" importance="low" due-to="Luis Bernardo">
+        Full font embedding in PDF
+      </action>
+      <action context="Renderers" dev="PH" type="add" fixes-bug="53865" importance="low">
+        Added configuration for RowPerStrip configuration in the Tiff renderer.
+        RowsPerStrip can be configured to 1 or to the total # of rows.
+        See docs for fop.xconf configuration details.
+      </action>
+      <action context="Layout" dev="VH" type="fix" fixes-bug="53598" due-to="Robert Meyer">
+        Always set the breakClass field to a legal value in BreakElement, so as to avoid 
+        IllegalArgumentExceptions in other parts of the code.
+      </action>
+      <action context="Layout" dev="VH" type="fix" fixes-bug="45715" due-to="Luis Bernardo">
+        Restored support for break-before on fo:table.
+      </action>
+      <action context="Layout" dev="VH" type="fix" fixes-bug="53827">
+        When an fo:block has a non-zero value for its text-indent property and is broken over two 
+        pages of different widths, then the first line on the second page is missing one word and 
+        appears indented.
+      </action>
+      <action context="Renderers" dev="MH" type="fix" fixes-bug="53790">
+         Prevented the TIFF configurator from overriding the Bitmap configurator unless CCITT
+         compression is enabled.
+      </action>
+      <action context="Renderers" dev="MH" type="fix" fixes-bug="53786">
+         Removed the Attribute Qualifier on TLEs as they aren't used.
+      </action>
+      <action context="Renderers" dev="MH" type="fix" fixes-bug="48954" due-to="PH">
+         Support for character encoding of TLEs in AFP output
+      </action>
+      <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>
+      <action context="Fonts" dev="MH" type="fix" fixes-bug="53685">
+        Cached AFP charactersets have more unique keys preventing the two characters with
+        but different binaries conflicting.
+      </action>
+      <action context="Fonts" dev="MH" type="fix" fixes-bug="53657" due-to="Robert Meyer">
+        AFP fonts default to the nominal character increment to font metrics when glyph info
+        is missing from the characterset.
+      </action>
+      <action context="Layout" dev="VH" type="fix" fixes-bug="53688">
+        Wrong page number reported when a column overflows the region-body in a multi-column 
+        document.
+      </action>
+      <action context="Renderers" dev="VH" type="add" fixes-bug="53639">
+        When PDF accessibility is enabled, the Scope attribute must be present in the structure tree 
+        for table header elements.
+      </action>
+      <action context="Fonts" dev="MH" type="add" fixes-bug="53600" due-to="Robert Meyer">
+        Added an event if a glyph and its metric information does not exist in the character set
+      </action>
       <action context="Renderers" dev="VH" type="add" fixes-bug="53596">
         When PDF accessibility is enabled, the structure tree must contain information about the 
         number of columns or rows spanned by a table cell.
diff --git a/test/events/region-body_overflow.fo b/test/events/region-body_overflow.fo
new file mode 100644
index 0000000..99b6dde
--- /dev/null
+++ b/test/events/region-body_overflow.fo
@@ -0,0 +1,115 @@
+<?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$ -->
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+  <fo:layout-master-set>
+    <fo:simple-page-master master-name="page"
+      page-height="80pt" page-width="530pt" margin="10pt" margin-bottom="0">
+      <fo:region-body margin-bottom="20pt" column-count="5" column-gap="10pt"/>
+      <fo:region-after extent="15pt"/>
+    </fo:simple-page-master>
+  </fo:layout-master-set>
+  <fo:page-sequence master-reference="page" font-size="8pt" line-height="10pt">
+    <fo:static-content flow-name="xsl-region-after">
+      <fo:block text-align="center"><fo:page-number/></fo:block>
+    </fo:static-content>
+    <fo:flow flow-name="xsl-region-body">
+
+      <fo:block>Page 1 Column 1 Line 1</fo:block>
+      <fo:block>Page 1 Column 1 Line 2</fo:block>
+      <fo:block>Page 1 Column 1 Line 3</fo:block>
+      <fo:block>Page 1 Column 1 Line 4</fo:block>
+      <fo:block>Page 1 Column 1 Line 5</fo:block>
+      <fo:block>Page 1 Column 2 Line 1</fo:block>
+      <fo:block>Page 1 Column 2 Line 2</fo:block>
+      <fo:block>Page 1 Column 2 Line 3</fo:block>
+      <fo:block>Page 1 Column 2 Line 4</fo:block>
+      <fo:block>Page 1 Column 2 Line 5</fo:block>
+      <fo:block>Page 1 Column 3 Line 1</fo:block>
+      <fo:block>Page 1 Column 3 Line 2</fo:block>
+      <fo:block>Page 1 Column 3 Line 3</fo:block>
+      <fo:block>Page 1 Column 3 Line 4</fo:block>
+      <fo:block>Page 1 Column 3 Line 5</fo:block>
+      <fo:block>Page 1 Column 4 Line 1</fo:block>
+      <fo:block>Page 1 Column 4 Line 2</fo:block>
+      <fo:block>Page 1 Column 4 Line 3</fo:block>
+      <fo:block>Page 1 Column 4 Line 4</fo:block>
+      <fo:block>Page 1 Column 4 Line 5</fo:block>
+      <fo:block-container height="55pt" background-color="#F0F0F0">
+        <fo:block>Page 1 Column 5 Line 1</fo:block>
+        <fo:block>Page 1 Column 5 Line 2</fo:block>
+        <fo:block>Page 1 Column 5 Line 3</fo:block>
+        <fo:block>Page 1 Column 5 Line 4</fo:block>
+        <fo:block>Page 1 Column 5 Line 5</fo:block>
+      </fo:block-container>
+
+      <fo:block break-before="page">Page 2 Column 1 Line 1</fo:block>
+      <fo:block>Page 2 Column 1 Line 2</fo:block>
+      <fo:block>Page 2 Column 1 Line 3</fo:block>
+      <fo:block>Page 2 Column 1 Line 4</fo:block>
+      <fo:block>Page 2 Column 1 Line 5</fo:block>
+      <fo:block>Page 2 Column 2 Line 1</fo:block>
+      <fo:block>Page 2 Column 2 Line 2</fo:block>
+      <fo:block>Page 2 Column 2 Line 3</fo:block>
+      <fo:block>Page 2 Column 2 Line 4</fo:block>
+      <fo:block>Page 2 Column 2 Line 5</fo:block>
+      <fo:block>Page 2 Column 3 Line 1</fo:block>
+      <fo:block>Page 2 Column 3 Line 2</fo:block>
+      <fo:block>Page 2 Column 3 Line 3</fo:block>
+      <fo:block>Page 2 Column 3 Line 4</fo:block>
+      <fo:block>Page 2 Column 3 Line 5</fo:block>
+      <fo:block>Page 2 Column 4 Line 1</fo:block>
+      <fo:block>Page 2 Column 4 Line 2</fo:block>
+      <fo:block>Page 2 Column 4 Line 3</fo:block>
+      <fo:block>Page 2 Column 4 Line 4</fo:block>
+      <fo:block>Page 2 Column 4 Line 5</fo:block>
+      <fo:block>Page 2 Column 5 Line 1</fo:block>
+      <fo:block>Page 2 Column 5 Line 2</fo:block>
+      <fo:block>Page 2 Column 5 Line 3</fo:block>
+      <fo:block>Page 2 Column 5 Line 4</fo:block>
+      <fo:block>Page 2 Column 5 Line 5</fo:block>
+
+      <fo:block>Page 3 Column 1 Line 1</fo:block>
+      <fo:block>Page 3 Column 1 Line 2</fo:block>
+      <fo:block>Page 3 Column 1 Line 3</fo:block>
+      <fo:block>Page 3 Column 1 Line 4</fo:block>
+      <fo:block>Page 3 Column 1 Line 5</fo:block>
+      <fo:block>Page 3 Column 2 Line 1</fo:block>
+      <fo:block>Page 3 Column 2 Line 2</fo:block>
+      <fo:block>Page 3 Column 2 Line 3</fo:block>
+      <fo:block>Page 3 Column 2 Line 4</fo:block>
+      <fo:block>Page 3 Column 2 Line 5</fo:block>
+      <fo:block>Page 3 Column 3 Line 1</fo:block>
+      <fo:block>Page 3 Column 3 Line 2</fo:block>
+      <fo:block>Page 3 Column 3 Line 3</fo:block>
+      <fo:block>Page 3 Column 3 Line 4</fo:block>
+      <fo:block>Page 3 Column 3 Line 5</fo:block>
+      <fo:block>Page 3 Column 4 Line 1</fo:block>
+      <fo:block>Page 3 Column 4 Line 2</fo:block>
+      <fo:block>Page 3 Column 4 Line 3</fo:block>
+      <fo:block>Page 3 Column 4 Line 4</fo:block>
+      <fo:block>Page 3 Column 4 Line 5</fo:block>
+      <fo:block>Page 3 Column 5 Line 1</fo:block>
+      <fo:block>Page 3 Column 5 Line 2</fo:block>
+      <fo:block>Page 3 Column 5 Line 3</fo:block>
+      <fo:block>Page 3 Column 5 Line 4</fo:block>
+      <fo:block>Page 3 Column 5 Line 5</fo:block>
+
+    </fo:flow>
+  </fo:page-sequence>
+</fo:root>
diff --git a/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java b/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java
index 863bfe7..6092912 100644
--- a/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java
+++ b/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java
@@ -19,8 +19,6 @@
 
 package org.apache.fop.accessibility.fo;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -34,7 +32,6 @@
 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;
@@ -57,9 +54,17 @@
 
 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";
@@ -68,62 +73,30 @@
 
     @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);
diff --git a/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl b/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl
index db0dffb..c739462 100644
--- a/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl
+++ b/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl
@@ -50,6 +50,25 @@
     <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"/>
@@ -73,15 +92,7 @@
     <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>
 
diff --git a/test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl b/test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl
deleted file mode 100644
index 9608b2f..0000000
--- a/test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl
+++ /dev/null
@@ -1,66 +0,0 @@
-<?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>
diff --git a/test/java/org/apache/fop/afp/util/AFPResourceAccessorTestCase.java b/test/java/org/apache/fop/afp/util/AFPResourceAccessorTestCase.java
new file mode 100644
index 0000000..d729d33
--- /dev/null
+++ b/test/java/org/apache/fop/afp/util/AFPResourceAccessorTestCase.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+package org.apache.fop.afp.util;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.apache.fop.apps.io.InternalResourceResolver;
+
+public class AFPResourceAccessorTestCase {
+
+    private InternalResourceResolver nullBaseResourceResolver;
+    private InternalResourceResolver absoluteBaseResourceResolver;
+    private InternalResourceResolver relativeBaseResourceResolver;
+    private final URI absoluteBaseURI = URI.create("this:///purely.for.testing");
+    private final URI relativeBaseURI = URI.create("./this.is.purely.for.testing");
+    private AFPResourceAccessor nullBaseURISut;
+    private AFPResourceAccessor absoluteBaseURISut;
+    private AFPResourceAccessor relativeBaseURISut;
+
+    @Before
+    public void setUp() {
+        nullBaseResourceResolver = mock(InternalResourceResolver.class);
+        absoluteBaseResourceResolver = mock(InternalResourceResolver.class);
+        relativeBaseResourceResolver = mock(InternalResourceResolver.class);
+        nullBaseURISut = new AFPResourceAccessor(nullBaseResourceResolver);
+        absoluteBaseURISut = new AFPResourceAccessor(absoluteBaseResourceResolver,
+                absoluteBaseURI.toASCIIString());
+        relativeBaseURISut = new AFPResourceAccessor(relativeBaseResourceResolver,
+                relativeBaseURI.toASCIIString());
+    }
+
+    @Test
+    public void testCreateInputStream() throws IOException, URISyntaxException {
+        URI testURI = URI.create("test");
+        nullBaseURISut.createInputStream(testURI);
+        verify(nullBaseResourceResolver).getResource(testURI);
+
+        absoluteBaseURISut.createInputStream(testURI);
+        verify(absoluteBaseResourceResolver).getResource(getActualURI(absoluteBaseURI, testURI));
+
+        relativeBaseURISut.createInputStream(testURI);
+        verify(relativeBaseResourceResolver).getResource(getActualURI(relativeBaseURI, testURI));
+    }
+
+    private URI getActualURI(URI baseURI, URI testURI) throws URISyntaxException {
+        return InternalResourceResolver.getBaseURI(baseURI.toASCIIString()).resolve(testURI);
+    }
+
+    @Test
+    public void testResolveURI() throws URISyntaxException {
+        String testURI = "anotherTestURI";
+        assertEquals(URI.create("./" + testURI), nullBaseURISut.resolveURI(testURI));
+
+        assertEquals(getActualURI(absoluteBaseURI, URI.create(testURI)),
+                absoluteBaseURISut.resolveURI(testURI));
+
+        assertEquals(getActualURI(relativeBaseURI, URI.create(testURI)),
+                relativeBaseURISut.resolveURI(testURI));
+    }
+}
diff --git a/test/java/org/apache/fop/apps/TIFFRendererConfBuilder.java b/test/java/org/apache/fop/apps/TIFFRendererConfBuilder.java
index 8b72a55..f39df29 100644
--- a/test/java/org/apache/fop/apps/TIFFRendererConfBuilder.java
+++ b/test/java/org/apache/fop/apps/TIFFRendererConfBuilder.java
@@ -20,7 +20,7 @@
 package org.apache.fop.apps;
 
 import static org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererOption.COMPRESSION;
-
+import static org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererOption.SINGLE_STRIP;
 public class TIFFRendererConfBuilder extends BitmapRendererConfBuilder {
 
     public TIFFRendererConfBuilder() {
@@ -31,4 +31,9 @@
         createTextElement(COMPRESSION, mode);
         return this;
     }
+
+    public TIFFRendererConfBuilder setSingleStrip(boolean single) {
+        createTextElement(SINGLE_STRIP, String.valueOf(single));
+        return this;
+    }
 }
diff --git a/test/java/org/apache/fop/events/EventChecker.java b/test/java/org/apache/fop/events/EventChecker.java
index dac67a8..3f0eef6 100644
--- a/test/java/org/apache/fop/events/EventChecker.java
+++ b/test/java/org/apache/fop/events/EventChecker.java
@@ -19,6 +19,9 @@
 
 package org.apache.fop.events;
 
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 /**
@@ -28,10 +31,13 @@
 
     private final String expectedEventID;
 
+    private final Map<String, Object> expectedParams;
+
     private boolean eventReceived;
 
-    EventChecker(String expectedEventID) {
+    EventChecker(String expectedEventID, Map<String, Object> expectedParams) {
         this.expectedEventID = expectedEventID;
+        this.expectedParams = expectedParams;
     }
 
     public void processEvent(Event event) {
@@ -39,6 +45,9 @@
         String id = event.getEventID();
         if (id.equals(expectedEventID)) {
             eventReceived = true;
+            for (Map.Entry<String, Object> param : expectedParams.entrySet()) {
+                assertEquals(event.getParam(param.getKey()), param.getValue());
+            }
         }
     }
 
diff --git a/test/java/org/apache/fop/events/EventProcessingTestCase.java b/test/java/org/apache/fop/events/EventProcessingTestCase.java
index 9338fc0..fb17c9c 100644
--- a/test/java/org/apache/fop/events/EventProcessingTestCase.java
+++ b/test/java/org/apache/fop/events/EventProcessingTestCase.java
@@ -22,6 +22,9 @@
 import java.io.File;
 import java.io.InputStream;
 import java.net.URI;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.xml.transform.Result;
 import javax.xml.transform.Source;
@@ -62,9 +65,10 @@
         CONFIG_BASE_DIR = base.resolve("test/config/");
 
     }
-    public void doTest(InputStream inStream, URI fopConf, String expectedEventID, String mimeType)
-            throws Exception {
-        EventChecker eventChecker = new EventChecker(expectedEventID);
+
+    public void doTest(InputStream inStream, URI fopConf, String expectedEventID, String mimeType,
+            Map<String, Object> expectedParams) throws Exception {
+        EventChecker eventChecker = new EventChecker(expectedEventID, expectedParams);
         FopFactory fopFactory;
         if (fopConf != null) {
             fopFactory = FopFactory.newInstance(new File(fopConf));
@@ -81,6 +85,19 @@
         Result res = new SAXResult(fop.getDefaultHandler());
         transformer.transform(src, res);
         eventChecker.end();
+
+    }
+
+    public void doTest(InputStream inStream, URI fopConf, String expectedEventID, String mimeType)
+            throws Exception {
+        Map<String, Object> noParams = Collections.emptyMap();
+        doTest(inStream, fopConf, expectedEventID, mimeType, noParams);
+    }
+
+    public void doTest(String filename, String expectedEventID, Map<String, Object> expectedParams)
+            throws Exception {
+        doTest(BASE_DIR.resolve(filename).toURL().openStream(), null, expectedEventID,
+                MimeConstants.MIME_PDF, expectedParams);
     }
 
     public void doTest(String filename, String expectedEventID) throws Exception {
@@ -133,4 +150,12 @@
     public void testViewportBPDOverflow() throws Exception {
         doTest("viewport-overflow.fo", BlockLevelEventProducer.class.getName() + ".viewportBPDOverflow");
     }
+
+    @Test
+    public void testPageOverflow() throws Exception {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("page", "1");
+        doTest("region-body_overflow.fo", BlockLevelEventProducer.class.getName() + ".regionOverflow",
+                params);
+    }
 }
diff --git a/test/java/org/apache/fop/fo/pagination/LayoutMasterSetTestCase.java b/test/java/org/apache/fop/fo/pagination/LayoutMasterSetTestCase.java
new file mode 100644
index 0000000..cfe71f5
--- /dev/null
+++ b/test/java/org/apache/fop/fo/pagination/LayoutMasterSetTestCase.java
@@ -0,0 +1,95 @@
+/*
+ * 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"));
+    }
+
+}
diff --git a/test/java/org/apache/fop/fo/pagination/side-regions.fo b/test/java/org/apache/fop/fo/pagination/side-regions.fo
new file mode 100644
index 0000000..8a0fba2
--- /dev/null
+++ b/test/java/org/apache/fop/fo/pagination/side-regions.fo
@@ -0,0 +1,181 @@
+<?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>
diff --git a/test/java/org/apache/fop/fonts/CIDFullTestCase.java b/test/java/org/apache/fop/fonts/CIDFullTestCase.java
new file mode 100644
index 0000000..7df6cc2
--- /dev/null
+++ b/test/java/org/apache/fop/fonts/CIDFullTestCase.java
@@ -0,0 +1,120 @@
+/*
+ * 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.fonts;
+
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.fop.util.CharUtilities;
+
+public class CIDFullTestCase {
+
+    private CIDFull cidFull;
+    private MultiByteFont mbFont;
+    private BitSet bs;
+    private char[] chars;
+    private int[] widths;
+    private Map<Integer, Integer> glyphs;
+
+    @Before
+    public void setup() {
+        bs = new BitSet();
+        glyphs = new HashMap<Integer, Integer>();
+        chars = new char[18];
+        widths = new int[18];
+        int i = 0;
+        for (int j = 0; j < 20; j++) {
+            if (j == 10 || j == 11) {
+                continue;
+            }
+            bs.set(j);
+            glyphs.put(Integer.valueOf(j), Integer.valueOf(j));
+            chars[i] = (char) j;
+            widths[i] = 100;
+            i++;
+        }
+        mbFont = mock(MultiByteFont.class);
+        when(mbFont.getGlyphIndices()).thenReturn(bs);
+        when(mbFont.getChars()).thenReturn(chars);
+        when(mbFont.getWidths()).thenReturn(widths);
+        cidFull = new CIDFull(mbFont);
+    }
+
+    @Test
+    public void testGetOriginalGlyphIndex() {
+        // index 5 exists
+        assertEquals(cidFull.getOriginalGlyphIndex(5), 5);
+    }
+
+    @Test
+    public void testGetUnicode() {
+        // index 9 exists
+        assertEquals(cidFull.getUnicode(9), (char) 9);
+        // index 10 does not
+        assertEquals(cidFull.getUnicode(10), CharUtilities.NOT_A_CHARACTER);
+    }
+
+    @Test
+    public void testMapChar() {
+        // index 9 exists
+        char c = 'a';
+        assertEquals(cidFull.mapChar(9, c), (char) 9);
+    }
+
+    @Test
+    public void testGetGlyphs() {
+        Map<Integer, Integer> fontGlyphs = cidFull.getGlyphs();
+        for (Integer key : fontGlyphs.keySet()) {
+            assertEquals(fontGlyphs.get(key), glyphs.get(key));
+        }
+        assertTrue(fontGlyphs.size() == glyphs.size());
+    }
+
+    @Test
+    public void testGetChars() {
+        assertArrayEquals(cidFull.getChars(), chars);
+    }
+
+    @Test
+    public void testGetNumberOfGlyphs() {
+        assertTrue(cidFull.getNumberOfGlyphs() == 20);
+    }
+
+    @Test
+    public void testGetGlyphIndices() {
+        assertEquals(bs, cidFull.getGlyphIndices());
+    }
+
+    @Test
+    public void testGetWidths() {
+        assertArrayEquals(cidFull.getWidths(), widths);
+    }
+
+}
diff --git a/test/java/org/apache/fop/fonts/FontManagerTestCase.java b/test/java/org/apache/fop/fonts/FontManagerTestCase.java
new file mode 100644
index 0000000..9012f84
--- /dev/null
+++ b/test/java/org/apache/fop/fonts/FontManagerTestCase.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package org.apache.fop.fonts;
+
+import java.net.URI;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.apps.io.InternalResourceResolver;
+
+public class FontManagerTestCase {
+
+    private FontManager sut;
+    private FontCacheManager fontCacheManager;
+    private FontDetector fontDetector;
+    private InternalResourceResolver resolver;
+
+    @Before
+    public void setUp() {
+        resolver = mock(InternalResourceResolver.class);
+        fontCacheManager = mock(FontCacheManager.class);
+        fontDetector = mock(FontDetector.class);
+
+        sut = new FontManager(resolver, fontDetector, fontCacheManager);
+    }
+
+    @Test
+    public void testSetCacheFile() {
+        URI testURI = URI.create("test/uri");
+        sut.setCacheFile(testURI);
+
+        InOrder inOrder = inOrder(resolver, fontCacheManager);
+        inOrder.verify(resolver).resolveFromBase(testURI);
+        inOrder.verify(fontCacheManager).setCacheFile(any(URI.class));
+    }
+
+    @Test
+    public void testGetFontCache() {
+        sut.getFontCache();
+        verify(fontCacheManager).load();
+    }
+
+    @Test
+    public void testSaveCache() throws FOPException {
+        sut.saveCache();
+        verify(fontCacheManager).save();
+    }
+
+    @Test
+    public void testDeleteCache() throws FOPException {
+        sut.deleteCache();
+        verify(fontCacheManager).delete();
+    }
+}
diff --git a/test/java/org/apache/fop/layoutmgr/BreakElementTestCase.java b/test/java/org/apache/fop/layoutmgr/BreakElementTestCase.java
new file mode 100644
index 0000000..c836bce
--- /dev/null
+++ b/test/java/org/apache/fop/layoutmgr/BreakElementTestCase.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package org.apache.fop.layoutmgr;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.fop.fo.Constants;
+
+public class BreakElementTestCase {
+
+    /**
+     * Tests that the constructor sets the break class to a valid default value.
+     */
+    @Test
+    public void breakClassMustBeValid() {
+        LayoutContext context = LayoutContext.newInstance();
+        BreakElement breakElement = new BreakElement(new Position(null), 0, context);
+        assertEquals(Constants.EN_AUTO, breakElement.getBreakClass());
+    }
+}
diff --git a/test/java/org/apache/fop/pdf/PDFEncodingTestCase.java b/test/java/org/apache/fop/pdf/PDFEncodingTestCase.java
new file mode 100644
index 0000000..34e48f1
--- /dev/null
+++ b/test/java/org/apache/fop/pdf/PDFEncodingTestCase.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+package org.apache.fop.pdf;
+
+import org.junit.Test;
+
+import org.apache.fop.fonts.CodePointMapping;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+public class PDFEncodingTestCase {
+
+    /**
+     * Tests the createPDFEncoding method to ensure a null encoding type
+     * is handled correctly.
+     */
+    @Test
+    public void testCreatePDFEncodingForNull() {
+        Object encoding = PDFEncoding.createPDFEncoding(null, "Test");
+        assertEquals(encoding, null);
+    }
+
+    /**
+     * Tests that when a PDFEncoding object is created, if the encoding type is
+     * that of StandardEncoding, the baseEncoding tag is omitted.
+     */
+    @Test
+    public void testStandardEncodingDiffs() {
+        Object encoding = PDFEncoding.createPDFEncoding(CodePointMapping.getMapping(
+                CodePointMapping.SYMBOL_ENCODING), "Test");
+        if (encoding instanceof PDFEncoding) {
+            PDFEncoding pdfEncoding = (PDFEncoding) encoding;
+            assertFalse(pdfEncoding.entries.containsKey("BaseEncoding"));
+        }
+    }
+
+    /**
+     * Tests that when the StandardEncoding type is provided and there are no
+     * differences, the returned encoding object is null.
+     */
+    @Test
+    public void testStandardEncodingNoDiff() {
+        Object encoding = PDFEncoding.createPDFEncoding(CodePointMapping.getMapping(
+                CodePointMapping.STANDARD_ENCODING), "Test");
+        assertEquals(encoding, null);
+    }
+
+    /**
+     * Tests that when the SymbolEncoding type is provided and there are no
+     * differences, the returned encoding string is that of SymbolEncoding.
+     */
+    @Test
+    public void testCreatePDFEncodingSymbol() {
+        Object encoding = PDFEncoding.createPDFEncoding(CodePointMapping.getMapping(
+                CodePointMapping.SYMBOL_ENCODING), "Symbol");
+        assert (encoding instanceof String);
+        String pdfEncoding = (String) encoding;
+        assertEquals(pdfEncoding, "SymbolEncoding");
+    }
+}
diff --git a/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java b/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
index ac9df40..971471f 100644
--- a/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
+++ b/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
@@ -24,14 +24,16 @@
 
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+
 import org.apache.fop.apps.io.InternalResourceResolver;
 import org.apache.fop.apps.io.ResourceResolver;
 import org.apache.fop.apps.io.ResourceResolverFactory;
+import org.apache.fop.fonts.CIDSet;
 import org.apache.fop.fonts.CIDSubset;
+import org.apache.fop.fonts.EmbeddingMode;
 import org.apache.fop.fonts.MultiByteFont;
 
-import static org.junit.Assert.assertEquals;
-
 /**
  * Test case for {@link PDFFactory}.
  */
@@ -45,7 +47,7 @@
     public void testSubsetFontNamePrefix() {
         class MockedFont extends MultiByteFont {
             public MockedFont(InternalResourceResolver resolver) {
-                super(resolver);
+                super(resolver, EmbeddingMode.AUTO);
             }
 
             @Override
@@ -54,8 +56,8 @@
             }
 
             @Override
-            public CIDSubset getCIDSubset() {
-                return new CIDSubset();
+            public CIDSet getCIDSet() {
+                return new CIDSubset(this);
             }
         }
         PDFDocument doc = new PDFDocument("Test");
diff --git a/test/java/org/apache/fop/pdf/TableHeaderScopeTestCase.java b/test/java/org/apache/fop/pdf/TableHeaderScopeTestCase.java
new file mode 100644
index 0000000..a1d5814
--- /dev/null
+++ b/test/java/org/apache/fop/pdf/TableHeaderScopeTestCase.java
@@ -0,0 +1,132 @@
+/*
+ * 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;
+
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+import org.mockito.verification.VerificationMode;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.apache.fop.pdf.StandardStructureAttributes.Table.Scope;
+import org.apache.fop.pdf.StandardStructureTypes.Table;
+
+public class TableHeaderScopeTestCase {
+
+    private static final String ATTRIBUTE_ENTRY = "A";
+
+    private VersionController controller;
+
+    @Test
+    public void pdfDocumentDelegatesToVersionController() {
+        for (Scope scope : Scope.values()) {
+            testMakeStructureElementWithScope(scope);
+        }
+    }
+
+    private void testMakeStructureElementWithScope(Scope scope) {
+        VersionController controller = mock(VersionController.class);
+        PDFDocument document = new PDFDocument("Test", controller);
+        document.makeStructTreeRoot(null);
+        PDFStructElem th = new PDFStructElem(null, Table.TH);
+        document.registerStructureElement(th, scope);
+        verify(controller).addTableHeaderScopeAttribute(any(PDFStructElem.class), eq(scope));
+    }
+
+    @Test
+    public void versionControllerMayDelegateToScope() {
+        fixedController14doesNotAddAttribute();
+        fixedController15addsAttribute();
+        dynamicControllerAddsAttribute();
+    }
+
+    private void fixedController14doesNotAddAttribute() {
+        controller = VersionController.getFixedVersionController(Version.V1_4);
+        scopeMustNotBeAdded();
+    }
+
+    private void fixedController15addsAttribute() {
+        controller = VersionController.getFixedVersionController(Version.V1_5);
+        scopeMustBeAdded();
+    }
+
+    private void dynamicControllerAddsAttribute() {
+        PDFDocument document = new PDFDocument("Test");
+        controller = VersionController.getDynamicVersionController(Version.V1_4, document);
+        scopeMustBeAdded();
+        assertEquals(Version.V1_5, controller.getPDFVersion());
+    }
+
+    private void scopeMustBeAdded() {
+        scopeMustBeAdded(times(1));
+    }
+
+    private void scopeMustNotBeAdded() {
+        scopeMustBeAdded(never());
+    }
+
+    private void scopeMustBeAdded(VerificationMode nTimes) {
+        PDFStructElem structElem = mock(PDFStructElem.class);
+        controller.addTableHeaderScopeAttribute(structElem, Scope.COLUMN);
+        verify(structElem, nTimes).put(eq(ATTRIBUTE_ENTRY), any());
+    }
+
+    @Test
+    public void scopeAddsTheAttribute() {
+        for (Scope scope : Scope.values()) {
+            scopeAttributeMustBeAdded(scope);
+        }
+    }
+
+    private void scopeAttributeMustBeAdded(Scope scope) {
+        PDFStructElem structElem = mock(PDFStructElem.class);
+        Scope.addScopeAttribute(structElem, scope);
+        verify(structElem).put(eq(ATTRIBUTE_ENTRY), scopeAttribute(scope));
+    }
+
+    private PDFDictionary scopeAttribute(Scope scope) {
+        return argThat(new isScopeAttribute(scope));
+    }
+
+    private static class isScopeAttribute extends ArgumentMatcher<PDFDictionary> {
+
+        private final Scope expectedScope;
+
+        public isScopeAttribute(Scope expectedScope) {
+            this.expectedScope = expectedScope;
+        }
+
+        @Override
+        public boolean matches(Object argument) {
+            PDFDictionary attribute = (PDFDictionary) argument;
+            return "/Table".equals(attribute.get("O").toString())
+                    && expectedScope.getName().toString().equals(attribute.get("Scope").toString());
+        }
+
+    }
+
+}
diff --git a/test/java/org/apache/fop/render/bitmap/TIFFCompressionValueTestCase.java b/test/java/org/apache/fop/render/bitmap/TIFFCompressionValueTestCase.java
new file mode 100644
index 0000000..c4285f0
--- /dev/null
+++ b/test/java/org/apache/fop/render/bitmap/TIFFCompressionValueTestCase.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package org.apache.fop.render.bitmap;
+
+import java.awt.image.BufferedImage;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.CCITT_T4;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.CCITT_T6;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.DEFLATE;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.JPEG;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.LZW;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.NONE;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.PACKBITS;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.ZLIB;
+
+public class TIFFCompressionValueTestCase {
+
+    @Test
+    public void testGetName() {
+        testCompressionName("NONE", NONE);
+        testCompressionName("JPEG", JPEG);
+        testCompressionName("PackBits", PACKBITS);
+        testCompressionName("Deflate", DEFLATE);
+        testCompressionName("LZW", LZW);
+        testCompressionName("ZLib", ZLIB);
+        testCompressionName("CCITT T.4", CCITT_T4);
+        testCompressionName("CCITT T.6", CCITT_T6);
+    }
+
+    private void testCompressionName(String name, TIFFCompressionValue expected) {
+        assertEquals(name, expected.getName());
+        assertEquals(expected, TIFFCompressionValue.getType(name));
+    }
+
+    @Test
+    public void testGetImageType() {
+        for (TIFFCompressionValue value : TIFFCompressionValue.values()) {
+            if (value == CCITT_T4 || value == CCITT_T6) {
+                assertEquals(BufferedImage.TYPE_BYTE_BINARY, value.getImageType());
+            } else {
+                assertEquals(BufferedImage.TYPE_INT_ARGB, value.getImageType());
+            }
+        }
+    }
+
+    @Test
+    public void testHasCCITTCompression() {
+        for (TIFFCompressionValue value : TIFFCompressionValue.values()) {
+            if (value == CCITT_T4 || value == CCITT_T6) {
+                assertTrue(value.hasCCITTCompression());
+            } else {
+                assertFalse(value.hasCCITTCompression());
+            }
+        }
+    }
+}
diff --git a/test/java/org/apache/fop/render/bitmap/TIFFRendererConfigParserTestCase.java b/test/java/org/apache/fop/render/bitmap/TIFFRendererConfigParserTestCase.java
index d938d09..6932655 100644
--- a/test/java/org/apache/fop/render/bitmap/TIFFRendererConfigParserTestCase.java
+++ b/test/java/org/apache/fop/render/bitmap/TIFFRendererConfigParserTestCase.java
@@ -26,9 +26,11 @@
 import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 public class TIFFRendererConfigParserTestCase
-        extends AbstractBitmapRendererConfigParserTester {
+extends AbstractBitmapRendererConfigParserTester {
 
     public TIFFRendererConfigParserTestCase() {
         super(new TIFFRendererConfigParser());
@@ -47,9 +49,17 @@
 
     @Test
     public void testCompression() throws Exception {
-        for (TIFFCompressionValues value : TIFFCompressionValues.values()) {
+        for (TIFFCompressionValue value : TIFFCompressionValue.values()) {
             parseConfig(createRenderer().setCompressionMode(value.getName()));
             assertEquals(value, getConfig().getCompressionType());
         }
     }
+
+    @Test
+    public void testSingleStrip() throws Exception {
+        parseConfig(createRenderer().setSingleStrip(true));
+        assertTrue(getConfig().isSingleStrip());
+        parseConfig(createRenderer().setSingleStrip(false));
+        assertFalse(getConfig().isSingleStrip());
+    }
 }
diff --git a/test/java/org/apache/fop/render/bitmap/TIFFRendererConfiguratorTestCase.java b/test/java/org/apache/fop/render/bitmap/TIFFRendererConfiguratorTestCase.java
index 9dd40e0..3e6c951 100644
--- a/test/java/org/apache/fop/render/bitmap/TIFFRendererConfiguratorTestCase.java
+++ b/test/java/org/apache/fop/render/bitmap/TIFFRendererConfiguratorTestCase.java
@@ -23,14 +23,17 @@
 
 import org.junit.Test;
 
+
 import org.apache.fop.apps.FopConfBuilder;
 import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.apps.TIFFRendererConfBuilder;
 import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser;
 
-import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T4;
-import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T6;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.CCITT_T4;
+import static org.apache.fop.render.bitmap.TIFFCompressionValue.CCITT_T6;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 public class TIFFRendererConfiguratorTestCase extends AbstractBitmapRendererConfiguratorTest {
 
@@ -51,7 +54,7 @@
     @Test
     @Override
     public void testColorModes() throws Exception {
-        for (TIFFCompressionValues value : TIFFCompressionValues.values()) {
+        for (TIFFCompressionValue value : TIFFCompressionValue.values()) {
             parseConfig(createBuilder().setCompressionMode(value.getName()));
             if (value == CCITT_T6 || value == CCITT_T4) {
                 assertEquals(BufferedImage.TYPE_BYTE_BINARY, settings.getBufferedImageType());
@@ -60,4 +63,13 @@
             }
         }
     }
+
+    @Test
+    public void testSingleStrip() throws Exception {
+        parseConfig(createBuilder().setSingleStrip(true));
+        assertTrue(settings.getWriterParams().isSingleStrip());
+        parseConfig(createBuilder().setSingleStrip(false));
+        assertFalse(settings.getWriterParams().isSingleStrip());
+    }
+
 }
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_text-indent.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_text-indent.xml
new file mode 100644
index 0000000..0d1d141
--- /dev/null
+++ b/test/layoutengine/standard-testcases/flow_changing-ipd_text-indent.xml
@@ -0,0 +1,57 @@
+<?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$ -->
+<testcase>
+  <info>
+    <p>
+      This test checks that the text-indent property plays nicely with changing IPD.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="wide-page"
+          page-height="40pt" page-width="220pt" margin="10pt">
+          <fo:region-body/>
+        </fo:simple-page-master>
+        <fo:simple-page-master master-name="narrow-page"
+          page-height="60pt" page-width="180pt" margin="10pt">
+          <fo:region-body/>
+        </fo:simple-page-master>
+        <fo:page-sequence-master master-name="pages">
+          <fo:single-page-master-reference master-reference="wide-page"/>
+          <fo:single-page-master-reference master-reference="narrow-page"/>
+        </fo:page-sequence-master>
+      </fo:layout-master-set>
+
+      <fo:page-sequence master-reference="pages">
+        <fo:flow flow-name="xsl-region-body" text-align="justify" font-size="8pt" line-height="10pt">
+          <fo:block text-indent="2em">Setting a non-zero value for the “text-indent” property on an 
+            fo:block should not cause loss of text. Setting a non-zero value for the “text-indent” 
+            property on an fo:block should not cause loss of text.</fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+
+    </fo:root>
+  </fo>
+  <checks>
+    <eval expected="non-" xpath="//pageViewport[1]//lineArea[2]//word[position()=last()]"/>
+    <eval expected=""     xpath="//pageViewport[2]//lineArea[1]/@start-indent"/>
+    <eval expected="zero" xpath="//pageViewport[2]//lineArea[1]//word[1]"/>
+  </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/table_break-before.xml b/test/layoutengine/standard-testcases/table_break-before.xml
new file mode 100644
index 0000000..b0a9a05
--- /dev/null
+++ b/test/layoutengine/standard-testcases/table_break-before.xml
@@ -0,0 +1,75 @@
+<?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$ -->
+<testcase>
+  <info>
+    <p>
+      This test checks that break-before works on fo:table.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="page" page-width="200pt" page-height="100pt" 
+          margin="10pt">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <!-- Table as first child of parent element -->
+      <fo:page-sequence master-reference="page">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block>Page 1</fo:block>
+          <fo:block>
+            <fo:table break-before="page" width="100%" table-layout="fixed">
+              <fo:table-body>
+                <fo:table-row>
+                  <fo:table-cell>
+                    <fo:block>Page 2</fo:block>
+                  </fo:table-cell>
+                </fo:table-row>
+              </fo:table-body>
+            </fo:table>
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+      <!-- Table not as first child of parent element -->
+      <fo:page-sequence master-reference="page">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block>Page 3</fo:block>
+          <fo:table break-before="page" width="100%" table-layout="fixed">
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Page 4</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <eval expected="2" xpath="count(//pageSequence[1]/pageViewport)"/>
+    <eval expected="1" xpath="//lineArea[starts-with(., 'Page 1')]/ancestor::pageViewport/@nr" />
+    <eval expected="2" xpath="//lineArea[starts-with(., 'Page 2')]/ancestor::pageViewport/@nr" />
+    <eval expected="2" xpath="count(//pageSequence[2]/pageViewport)"/>
+    <eval expected="3" xpath="//lineArea[starts-with(., 'Page 3')]/ancestor::pageViewport/@nr" />
+    <eval expected="4" xpath="//lineArea[starts-with(., 'Page 4')]/ancestor::pageViewport/@nr" />
+  </checks>
+</testcase>
diff --git a/test/pdf/1.5/test.pdf b/test/pdf/1.5/test.pdf
index 6175a27..d97648e 100644
--- a/test/pdf/1.5/test.pdf
+++ b/test/pdf/1.5/test.pdf
Binary files differ
diff --git a/test/pdf/accessibility/fop.xconf b/test/pdf/accessibility/fop.xconf
index adfccd2..24346a1 100644
--- a/test/pdf/accessibility/fop.xconf
+++ b/test/pdf/accessibility/fop.xconf
@@ -6,6 +6,7 @@
   <font-base>../../resources/fonts/ttf/</font-base>
   <renderers>
     <renderer mime="application/pdf">
+      <version>1.4</version>
       <filterList>
         <value>null</value>
       </filterList>
diff --git a/test/pdf/accessibility/pdf/role.pdf b/test/pdf/accessibility/pdf/role.pdf
index 4dfb686..8fb665b 100644
--- a/test/pdf/accessibility/pdf/role.pdf
+++ b/test/pdf/accessibility/pdf/role.pdf
Binary files differ
diff --git a/test/pdf/accessibility/pdf/role_non-standard.pdf b/test/pdf/accessibility/pdf/role_non-standard.pdf
index 6f1edea..9effef7 100644
--- a/test/pdf/accessibility/pdf/role_non-standard.pdf
+++ b/test/pdf/accessibility/pdf/role_non-standard.pdf
Binary files differ
diff --git a/test/pdf/accessibility/pdf/side-regions.pdf b/test/pdf/accessibility/pdf/side-regions.pdf
new file mode 100644
index 0000000..6e5da93
--- /dev/null
+++ b/test/pdf/accessibility/pdf/side-regions.pdf
Binary files differ
diff --git a/test/pdf/accessibility/side-regions.fo b/test/pdf/accessibility/side-regions.fo
new file mode 100644
index 0000000..8a0fba2
--- /dev/null
+++ b/test/pdf/accessibility/side-regions.fo
@@ -0,0 +1,181 @@
+<?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>