Subject: [PATCH 15/20] Don't write empty leaf structure to PDF

Adds also support for writing the structure tree earlier to save memory.

---
 src/java/org/apache/fop/pdf/PDFFactory.java        |    3 +-
 src/java/org/apache/fop/pdf/PDFStructElem.java     |   41 +++++++++++++++++++-
 .../fop/render/pdf/PDFLogicalStructureHandler.java |   12 +++++-
 3 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java
index a741e18..7fc60d4 100644
--- a/src/java/org/apache/fop/pdf/PDFFactory.java
+++ b/src/java/org/apache/fop/pdf/PDFFactory.java
@@ -933,8 +933,7 @@ public class PDFFactory {
      */
     public PDFStructElem makeStructureElement(PDFName structureType, PDFObject parent) {
         PDFStructElem structElem = new PDFStructElem(parent, structureType);
-        getDocument().assignObjectNumber(structElem);
-        getDocument().addTrailerObject(structElem);
+        getDocument().lazyAssignObjectNumber(structElem);
         return structElem;
     }
 
diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java
index df8b42c..b0c1856 100644
--- a/src/java/org/apache/fop/pdf/PDFStructElem.java
+++ b/src/java/org/apache/fop/pdf/PDFStructElem.java
@@ -19,6 +19,7 @@
 
 package org.apache.fop.pdf;
 
+import java.util.Iterator;
 import java.util.Locale;
 
 import org.apache.fop.util.XMLUtil;
@@ -58,7 +59,7 @@ public class PDFStructElem extends PDFDictionary {
     /** {@inheritDoc} */
     public void setParent(PDFObject parent) {
         if (parent != null) {
-           put("P", new PDFReference(parent));
+           put("P", parent);
         }
     }
 
@@ -156,4 +157,42 @@ public class PDFStructElem extends PDFDictionary {
     public String getLanguage() {
         return (String)get("Lang");
     }
+
+    /**
+     * Simplifies node structure
+     *
+     * @return true, if the node is added to the document
+     */
+    public boolean prepare() {
+        Object k = get("K");
+        PDFArray kids = null;
+
+        if (k instanceof PDFArray)
+            kids = (PDFArray) k;
+        else if (k == null)
+            kids = new PDFArray();
+        else {
+            kids = new PDFArray();
+            kids.add(k);
+        }
+
+        /* prepare child nodes */
+        Iterator i = kids.iterator();
+        while (i.hasNext()) {
+            Object e = i.next();
+            if (e instanceof PDFStructElem) {
+                /* Remove leafs with no childs */
+                if (!((PDFStructElem)e).prepare())
+                    i.remove();
+            }
+        }
+        if (kids.length() == 1)
+            put("K", kids.get(0));
+        if (kids.length() == 0) {
+            remove("K");
+            return false;
+        }
+        getDocument().addObject(this, true);
+        return true;
+    }
 }
diff --git a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
index 8178d11..79b7cfb 100644
--- a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
+++ b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
@@ -19,7 +19,9 @@
 
 package org.apache.fop.render.pdf;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
@@ -74,6 +76,8 @@ class PDFLogicalStructureHandler {
 
     private PDFStructElem rootStructureElement;
 
+    private PDFStructElem currentPageSequence;
+
     /**
      * Class providing the necessary information for bracketing content
      * associated to a structure element as a marked-content sequence.
@@ -112,6 +116,7 @@ class PDFLogicalStructureHandler {
         PDFStructTreeRoot structTreeRoot = pdfDoc.getFactory().makeStructTreeRoot(parentTree);
         rootStructureElement = pdfDoc.getFactory().makeStructureElement(
                 FOToPDFRoleMap.mapFormattingObject("root", structTreeRoot), structTreeRoot);
+        pdfDoc.addTrailerObject (rootStructureElement);
         structTreeRoot.addKid(rootStructureElement);
     }
 
@@ -130,6 +135,7 @@ class PDFLogicalStructureHandler {
         if (language != null) {
             structElemPart.setLanguage(language);
         }
+        currentPageSequence = structElemPart;
 
         for (int i = 0, n = structureTree.getLength(); i < n; i++) {
             StructureElement node = structureTree.getChild(i);
@@ -198,7 +204,7 @@ class PDFLogicalStructureHandler {
         // before the array is complete, which would result in only part of it
         // being output to the PDF.
         // This should really be handled by PDFNumsArray
-        pdfDoc.registerObject(pageParentTreeArray);
+        pdfDoc.registerObject(pageParentTreeArray, true);
         parentTree.getNums().put(currentPage.getStructParents(), pageParentTreeArray);
     }
 
@@ -206,6 +212,10 @@ class PDFLogicalStructureHandler {
      * Receive notification of the end of the current page sequence.
      */
     void endPageSequence() {
+        if (!currentPageSequence.prepare())
+            /* Keep empty page sequence object */
+            pdfDoc.addObject(currentPageSequence, true);
+
         structTreeMap = new HashMap();
     }
 
-- 
1.6.4.2

