You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2014/01/13 21:39:41 UTC

svn commit: r1557840 [5/9] - in /xmlgraphics/fop/branches/Temp_InlineContainer: ./ examples/fo/basic/ lib/ src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/ src/documentation/intermediate-format-ng/ src/java/org/apache/fop/ src/java/org/apac...

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java Mon Jan 13 20:39:34 2014
@@ -27,6 +27,7 @@ import java.io.OutputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.EnumMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.io.IOUtils;
@@ -55,24 +56,33 @@ import org.apache.fop.pdf.PDFFileSpec;
 import org.apache.fop.pdf.PDFICCBasedColorSpace;
 import org.apache.fop.pdf.PDFICCStream;
 import org.apache.fop.pdf.PDFInfo;
+import org.apache.fop.pdf.PDFLayer;
 import org.apache.fop.pdf.PDFMetadata;
 import org.apache.fop.pdf.PDFName;
 import org.apache.fop.pdf.PDFNames;
+import org.apache.fop.pdf.PDFNavigator;
+import org.apache.fop.pdf.PDFNull;
 import org.apache.fop.pdf.PDFNumber;
 import org.apache.fop.pdf.PDFOutputIntent;
 import org.apache.fop.pdf.PDFPage;
 import org.apache.fop.pdf.PDFPageLabels;
 import org.apache.fop.pdf.PDFReference;
+import org.apache.fop.pdf.PDFSetOCGStateAction;
 import org.apache.fop.pdf.PDFText;
+import org.apache.fop.pdf.PDFTransitionAction;
 import org.apache.fop.pdf.PDFXMode;
 import org.apache.fop.pdf.Version;
 import org.apache.fop.pdf.VersionController;
+import org.apache.fop.render.pdf.extensions.PDFActionExtension;
+import org.apache.fop.render.pdf.extensions.PDFArrayExtension;
+import org.apache.fop.render.pdf.extensions.PDFCollectionEntryExtension;
 import org.apache.fop.render.pdf.extensions.PDFDictionaryAttachment;
-import org.apache.fop.render.pdf.extensions.PDFDictionaryEntryExtension;
-import org.apache.fop.render.pdf.extensions.PDFDictionaryEntryType;
 import org.apache.fop.render.pdf.extensions.PDFDictionaryExtension;
 import org.apache.fop.render.pdf.extensions.PDFDictionaryType;
 import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileAttachment;
+import org.apache.fop.render.pdf.extensions.PDFObjectType;
+import org.apache.fop.render.pdf.extensions.PDFPageExtension;
+import org.apache.fop.render.pdf.extensions.PDFReferenceExtension;
 
 import static org.apache.fop.render.pdf.PDFEncryptionOption.ENCRYPTION_PARAMS;
 import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_ACCESSCONTENT;
@@ -260,10 +270,189 @@ class PDFRenderingUtil {
 
     public void renderDictionaryExtension(PDFDictionaryAttachment attachment, PDFPage currentPage) {
         PDFDictionaryExtension extension = attachment.getExtension();
-        if (extension.getDictionaryType() == PDFDictionaryType.Catalog) {
+        PDFDictionaryType type = extension.getDictionaryType();
+        if (type == PDFDictionaryType.Action) {
+            addNavigatorAction(extension);
+        } else if (type == PDFDictionaryType.Layer) {
+            addLayer(extension);
+        } else if (type == PDFDictionaryType.Navigator) {
+            addNavigator(extension);
+        } else {
+            renderDictionaryExtension(extension, currentPage);
+        }
+    }
+
+    public void addLayer(PDFDictionaryExtension extension) {
+        assert extension.getDictionaryType() == PDFDictionaryType.Layer;
+        String id = extension.getProperty(PDFDictionaryExtension.PROPERTY_ID);
+        if ((id != null) && (id.length() > 0)) {
+            PDFLayer layer = pdfDoc.getFactory().makeLayer(id);
+            layer.setResolver(new PDFLayer.Resolver(layer, extension) {
+                public void performResolution() {
+                    PDFDictionaryExtension extension = (PDFDictionaryExtension) getExtension();
+                    Object name = extension.findEntryValue("Name");
+                    Object intent = extension.findEntryValue("Intent");
+                    Object usage = makeDictionary(extension.findEntryValue("Usage"));
+                    getLayer().populate(name, intent, usage);
+                }
+            });
+        }
+    }
+
+    public void addNavigatorAction(PDFDictionaryExtension extension) {
+        assert extension.getDictionaryType() == PDFDictionaryType.Action;
+        String id = extension.getProperty(PDFDictionaryExtension.PROPERTY_ID);
+        if ((id != null) && (id.length() > 0)) {
+            String type = extension.getProperty(PDFActionExtension.PROPERTY_TYPE);
+            if (type != null) {
+                if (type.equals("SetOCGState")) {
+                    PDFSetOCGStateAction action = pdfDoc.getFactory().makeSetOCGStateAction(id);
+                    action.setResolver(new PDFSetOCGStateAction.Resolver(action, extension) {
+                        public void performResolution() {
+                            PDFDictionaryExtension extension = (PDFDictionaryExtension) getExtension();
+                            Object state = makeArray(extension.findEntryValue("State"));
+                            Object preserveRB = extension.findEntryValue("PreserveRB");
+                            Object nextAction = makeDictionaryOrArray(extension.findEntryValue("Next"));
+                            getAction().populate(state, preserveRB, nextAction);
+                        }
+                    });
+                } else if (type.equals("Trans")) {
+                    PDFTransitionAction action = pdfDoc.getFactory().makeTransitionAction(id);
+                    action.setResolver(new PDFTransitionAction.Resolver(action, extension) {
+                        public void performResolution() {
+                            PDFDictionaryExtension extension = (PDFDictionaryExtension) getExtension();
+                            Object transition = makeDictionary(extension.findEntryValue("Trans"));
+                            Object nextAction = makeDictionaryOrArray(extension.findEntryValue("Next"));
+                            getAction().populate(transition, nextAction);
+                        }
+                    });
+                } else {
+                    throw new UnsupportedOperationException();
+                }
+            }
+        }
+    }
+
+    public void addNavigator(PDFDictionaryExtension extension) {
+        assert extension.getDictionaryType() == PDFDictionaryType.Navigator;
+        String id = extension.getProperty(PDFDictionaryExtension.PROPERTY_ID);
+        if ((id != null) && (id.length() > 0)) {
+            PDFNavigator navigator = pdfDoc.getFactory().makeNavigator(id);
+            navigator.setResolver(new PDFNavigator.Resolver(navigator, extension) {
+                public void performResolution() {
+                    PDFDictionaryExtension extension = (PDFDictionaryExtension) getExtension();
+                    Object nextAction = makeDictionary(extension.findEntryValue("NA"));
+                    Object next = makeDictionary(extension.findEntryValue("Next"));
+                    Object prevAction = makeDictionary(extension.findEntryValue("PA"));
+                    Object prev = makeDictionary(extension.findEntryValue("Prev"));
+                    Object duration = extension.findEntryValue("Dur");
+                    getNavigator().populate(nextAction, next, prevAction, prev, duration);
+                }
+            });
+        }
+    }
+
+    private Object makeArray(Object value) {
+        if (value == null) {
+            return null;
+        } else if (value instanceof PDFReferenceExtension) {
+            return resolveReference((PDFReferenceExtension) value);
+        } else if (value instanceof List<?>) {
+            return populateArray(new PDFArray(), (List<?>) value);
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    private Object populateArray(PDFArray array, List<?> entries) {
+        for (PDFCollectionEntryExtension entry : (List<PDFCollectionEntryExtension>) entries) {
+            PDFObjectType type = entry.getType();
+            if (type == PDFObjectType.Array) {
+                array.add(makeArray(entry.getValue()));
+            } else if (type == PDFObjectType.Boolean) {
+                array.add(entry.getValueAsBoolean());
+            } else if (type == PDFObjectType.Dictionary) {
+                array.add(makeDictionary(entry.getValue()));
+            } else if (type == PDFObjectType.Name) {
+                array.add(new PDFName(entry.getValueAsString()));
+            } else if (type == PDFObjectType.Number) {
+                array.add(new PDFNumber(entry.getValueAsNumber()));
+            } else if (type == PDFObjectType.Reference) {
+                array.add(resolveReference((PDFReferenceExtension) entry));
+            } else if (type == PDFObjectType.String) {
+                array.add(entry.getValue());
+            }
+        }
+        return array;
+    }
+
+    private Object makeDictionary(Object value) {
+        if (value == null) {
+            return null;
+        } else if (value instanceof PDFReferenceExtension) {
+            return resolveReference((PDFReferenceExtension) value);
+        } else if (value instanceof List<?>) {
+            return populateDictionary(new PDFDictionary(), (List<?>) value);
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    private Object populateDictionary(PDFDictionary dictionary, List<?> entries) {
+        for (PDFCollectionEntryExtension entry : (List<PDFCollectionEntryExtension>) entries) {
+            PDFObjectType type = entry.getType();
+            String key = entry.getKey();
+            if (type == PDFObjectType.Array) {
+                dictionary.put(key, makeArray(entry.getValue()));
+            } else if (type == PDFObjectType.Boolean) {
+                dictionary.put(key, entry.getValueAsBoolean());
+            } else if (type == PDFObjectType.Dictionary) {
+                dictionary.put(key, makeDictionary(entry.getValue()));
+            } else if (type == PDFObjectType.Name) {
+                dictionary.put(key, new PDFName(entry.getValueAsString()));
+            } else if (type == PDFObjectType.Number) {
+                dictionary.put(key, new PDFNumber(entry.getValueAsNumber()));
+            } else if (type == PDFObjectType.Reference) {
+                dictionary.put(key, resolveReference((PDFReferenceExtension) entry));
+            } else if (type == PDFObjectType.String) {
+                dictionary.put(key, entry.getValue());
+            }
+        }
+        return dictionary;
+    }
+
+    private Object makeDictionaryOrArray(Object value) {
+        if (value == null) {
+            return null;
+        } else if (value instanceof PDFReferenceExtension) {
+            return resolveReference((PDFReferenceExtension) value);
+        } else if (value instanceof List<?>) {
+            if (hasKeyedEntry((List<?>) value)) {
+                return populateDictionary(new PDFDictionary(), (List<?>) value);
+            } else {
+                return populateArray(new PDFArray(), (List<?>) value);
+            }
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    private boolean hasKeyedEntry(List<?> entries) {
+        for (PDFCollectionEntryExtension entry : (List<PDFCollectionEntryExtension>) entries) {
+            if (entry.getKey() != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void renderDictionaryExtension(PDFDictionaryExtension extension, PDFPage currentPage) {
+        PDFDictionaryType type = extension.getDictionaryType();
+        if (type == PDFDictionaryType.Catalog) {
             augmentDictionary(pdfDoc.getRoot(), extension);
-        } else if (extension.getDictionaryType() == PDFDictionaryType.Page) {
-            if (extension.matchesPageNumber(currentPage.getPageIndex() + 1)) {
+        } else if (type == PDFDictionaryType.Page) {
+            assert extension instanceof PDFPageExtension;
+            if (((PDFPageExtension) extension).matchesPageNumber(currentPage.getPageIndex() + 1)) {
                 augmentDictionary(currentPage, extension);
             }
         } else {
@@ -272,9 +461,12 @@ class PDFRenderingUtil {
     }
 
     private PDFDictionary augmentDictionary(PDFDictionary dictionary, PDFDictionaryExtension extension) {
-        for (PDFDictionaryEntryExtension entry : extension.getEntries()) {
+        for (PDFCollectionEntryExtension entry : extension.getEntries()) {
             if (entry instanceof PDFDictionaryExtension) {
-                dictionary.put(entry.getKey(), augmentDictionary(new PDFDictionary(dictionary), (PDFDictionaryExtension) entry));
+                dictionary.put(entry.getKey(),
+                        augmentDictionary(new PDFDictionary(dictionary), (PDFDictionaryExtension) entry));
+            } else if (entry instanceof PDFArrayExtension) {
+                dictionary.put(entry.getKey(), augmentArray(new PDFArray(dictionary), (PDFArrayExtension) entry));
             } else {
                 augmentDictionary(dictionary, entry);
             }
@@ -282,22 +474,68 @@ class PDFRenderingUtil {
         return dictionary;
     }
 
-    private void augmentDictionary(PDFDictionary dictionary, PDFDictionaryEntryExtension entry) {
-        PDFDictionaryEntryType type = entry.getType();
+    private void augmentDictionary(PDFDictionary dictionary, PDFCollectionEntryExtension entry) {
+        PDFObjectType type = entry.getType();
         String key = entry.getKey();
-        if (type == PDFDictionaryEntryType.Boolean) {
+        if (type == PDFObjectType.Boolean) {
             dictionary.put(key, entry.getValueAsBoolean());
-        } else if (type == PDFDictionaryEntryType.Name) {
+        } else if (type == PDFObjectType.Name) {
             dictionary.put(key, new PDFName(entry.getValueAsString()));
-        } else if (type == PDFDictionaryEntryType.Number) {
+        } else if (type == PDFObjectType.Number) {
             dictionary.put(key, new PDFNumber(entry.getValueAsNumber()));
-        } else if (type == PDFDictionaryEntryType.String) {
+        } else if (type == PDFObjectType.Reference) {
+            assert entry instanceof PDFReferenceExtension;
+            dictionary.put(key, resolveReference((PDFReferenceExtension) entry));
+        } else if (type == PDFObjectType.String) {
             dictionary.put(key, entry.getValueAsString());
         } else {
             throw new IllegalStateException();
         }
     }
 
+    private Object resolveReference(PDFReferenceExtension entry) {
+        PDFReference reference = (PDFReference) entry.getResolvedReference();
+        if (reference == null) {
+            reference = pdfDoc.resolveExtensionReference(entry.getReferenceId());
+            if (reference != null) {
+                entry.setResolvedReference(reference);
+            }
+            return reference;
+        }
+        return PDFNull.INSTANCE;
+    }
+
+    private PDFArray augmentArray(PDFArray array, PDFArrayExtension extension) {
+        for (PDFCollectionEntryExtension entry : extension.getEntries()) {
+            if (entry instanceof PDFDictionaryExtension) {
+                array.add(augmentDictionary(new PDFDictionary(array), (PDFDictionaryExtension) entry));
+            } else if (entry instanceof PDFArrayExtension) {
+                array.add(augmentArray(new PDFArray(array), (PDFArrayExtension) entry));
+            } else {
+                augmentArray(array, entry);
+            }
+        }
+        return array;
+    }
+
+    private void augmentArray(PDFArray array, PDFCollectionEntryExtension entry) {
+        PDFObjectType type = entry.getType();
+        if (type == PDFObjectType.Boolean) {
+            array.add(entry.getValueAsBoolean());
+        } else if (type == PDFObjectType.Name) {
+            array.add(new PDFName(entry.getValueAsString()));
+        } else if (type == PDFObjectType.Number) {
+            array.add(new PDFNumber(entry.getValueAsNumber()));
+        } else if (type == PDFObjectType.Reference) {
+            assert entry instanceof PDFReferenceExtension;
+            array.add(resolveReference((PDFReferenceExtension) entry));
+        } else if (type == PDFObjectType.String) {
+            array.add(entry.getValueAsString());
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
     public PDFDocument setupPDFDocument(OutputStream out) throws IOException {
         if (this.pdfDoc != null) {
             throw new IllegalStateException("PDFDocument already set up");

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java Mon Jan 13 20:39:34 2014
@@ -358,6 +358,7 @@ class PDFStructureTreeBuilder implements
     }
 
     public StructureTreeElement startNode(String name, Attributes attributes, StructureTreeElement parent) {
+        assert parent == null || parent instanceof PDFStructElem;
         PDFStructElem parentElem = parent == null ? ancestors.getFirst() : (PDFStructElem) parent;
         PDFStructElem structElem = createStructureElement(name, parentElem, attributes,
                 pdfFactory, eventBroadcaster);

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryAttachment.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryAttachment.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryAttachment.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryAttachment.java Mon Jan 13 20:39:34 2014
@@ -43,14 +43,13 @@ public class PDFDictionaryAttachment ext
     }
 
     public void toSAX(ContentHandler handler) throws SAXException {
-        PDFDictionaryType dictionaryType = extension.getDictionaryType();
         int pageNumber = 0;
-        if (dictionaryType == PDFDictionaryType.Page) {
+        if (extension instanceof PDFPageExtension) {
             if (handler instanceof GenerationHelperContentHandler) {
                 Object context = ((GenerationHelperContentHandler) handler).getContentHandlerContext();
                 if (context instanceof IFContext) {
                     int pageIndex = ((IFContext) context).getPageIndex();
-                    if ((pageIndex >= 0) && extension.matchesPageNumber(pageIndex + 1)) {
+                    if ((pageIndex >= 0) && ((PDFPageExtension) extension).matchesPageNumber(pageIndex + 1)) {
                         pageNumber = pageIndex + 1;
                     } else {
                         pageNumber = -1;
@@ -69,24 +68,40 @@ public class PDFDictionaryAttachment ext
         String qn = PREFIX + ":" + ln;
         attributes = extractIFAttributes(attributes, dictionary);
         handler.startElement(CATEGORY, ln, qn, attributes);
-        for (PDFDictionaryEntryExtension entry : dictionary.getEntries()) {
+        for (PDFCollectionEntryExtension entry : dictionary.getEntries()) {
             toSAX(handler, entry);
         }
         handler.endElement(CATEGORY, ln, qn);
     }
 
-    private void toSAX(ContentHandler handler, PDFDictionaryEntryExtension entry) throws SAXException {
+    private void toSAX(ContentHandler handler, PDFArrayExtension array) throws SAXException {
+        AttributesImpl attributes = new AttributesImpl();
+        String ln = array.getElementName();
+        String qn = PREFIX + ":" + ln;
+        attributes = extractIFAttributes(attributes, array);
+        handler.startElement(CATEGORY, ln, qn, attributes);
+        for (PDFCollectionEntryExtension entry : array.getEntries()) {
+            toSAX(handler, entry);
+        }
+        handler.endElement(CATEGORY, ln, qn);
+    }
+
+    private void toSAX(ContentHandler handler, PDFCollectionEntryExtension entry) throws SAXException {
         if (entry instanceof PDFDictionaryExtension) {
             toSAX(handler, (PDFDictionaryExtension) entry);
+        } else if (entry instanceof PDFArrayExtension) {
+            toSAX(handler, (PDFArrayExtension) entry);
         } else {
             AttributesImpl attributes = new AttributesImpl();
             String ln = entry.getElementName();
             String qn = PREFIX + ":" + ln;
             attributes = extractIFAttributes(attributes, entry);
             handler.startElement(CATEGORY, ln, qn, attributes);
-            char[] characters = entry.getValueAsXMLEscapedString().toCharArray();
-            if (characters.length > 0) {
-                handler.characters(characters, 0, characters.length);
+            if (!(entry instanceof PDFReferenceExtension)) {
+                char[] characters = entry.getValueAsXMLEscapedString().toCharArray();
+                if (characters.length > 0) {
+                    handler.characters(characters, 0, characters.length);
+                }
             }
             handler.endElement(CATEGORY, ln, qn);
         }
@@ -94,16 +109,27 @@ public class PDFDictionaryAttachment ext
 
     private static AttributesImpl extractIFAttributes(AttributesImpl attributes, PDFDictionaryExtension dictionary) {
         PDFDictionaryType type = dictionary.getDictionaryType();
-        if (type == PDFDictionaryType.Catalog) {
-            // no specific attriburtes
+        if (dictionary.usesIDAttribute()) {
+            String idName = PDFDictionaryElement.ATT_ID;
+            String id = dictionary.getProperty(PDFDictionaryExtension.PROPERTY_ID);
+            if (id != null) {
+                attributes.addAttribute(null, idName, idName, "ID", id);
+            }
+        }
+        if (type == PDFDictionaryType.Action) {
+            String actionTypeName = PDFActionElement.ATT_TYPE;
+            String actionType = dictionary.getProperty(PDFActionExtension.PROPERTY_TYPE);
+            if (actionType != null) {
+                attributes.addAttribute(null, actionTypeName, actionTypeName, "CDATA", actionType);
+            }
         } else if (type == PDFDictionaryType.Page) {
-            String pageNumbersName = PDFDictionaryExtension.PROPERTY_PAGE_NUMBERS;
+            String pageNumbersName = PDFPageExtension.PROPERTY_PAGE_NUMBERS;
             String pageNumbers = dictionary.getProperty(pageNumbersName);
             if (pageNumbers != null) {
                 attributes.addAttribute(null, pageNumbersName, pageNumbersName, "CDATA", pageNumbers);
             }
         } else if (type == PDFDictionaryType.Dictionary) {
-            String keyName = PDFDictionaryEntryExtension.PROPERTY_KEY;
+            String keyName = PDFCollectionEntryElement.ATT_KEY;
             String key = dictionary.getKey();
             if (key != null) {
                 attributes.addAttribute(null, keyName, keyName, "CDATA", key);
@@ -112,12 +138,28 @@ public class PDFDictionaryAttachment ext
         return attributes;
     }
 
-    private static AttributesImpl extractIFAttributes(AttributesImpl attributes, PDFDictionaryEntryExtension entry) {
-        String keyName = PDFDictionaryEntryExtension.PROPERTY_KEY;
+    private static AttributesImpl extractIFAttributes(AttributesImpl attributes, PDFArrayExtension array) {
+        String keyName = PDFCollectionEntryExtension.PROPERTY_KEY;
+        String key = array.getKey();
+        if (key != null) {
+            attributes.addAttribute(null, keyName, keyName, "CDATA", key);
+        }
+        return attributes;
+    }
+
+    private static AttributesImpl extractIFAttributes(AttributesImpl attributes, PDFCollectionEntryExtension entry) {
+        String keyName = PDFCollectionEntryElement.ATT_KEY;
         String key = entry.getKey();
         if (key != null) {
             attributes.addAttribute(null, keyName, keyName, "CDATA", key);
         }
+        if (entry instanceof PDFReferenceExtension) {
+            String refid = ((PDFReferenceExtension) entry).getReferenceId();
+            if (refid != null) {
+                String refidName = PDFReferenceElement.ATT_REFID;
+                attributes.addAttribute(null, refidName, refidName, "IDREF", refid);
+            }
+        }
         return attributes;
     }
 

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryElement.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryElement.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryElement.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryElement.java Mon Jan 13 20:39:34 2014
@@ -23,7 +23,6 @@ import org.xml.sax.Attributes;
 import org.xml.sax.Locator;
 
 import org.apache.fop.apps.FOPException;
-import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.extensions.ExtensionAttachment;
@@ -34,38 +33,54 @@ import org.apache.fop.fo.extensions.Exte
  * Extension element for dictionaries: pdf:{catalog,page,dictionary}. The specific type
  * of dictionary is established at construction type.
  */
-public class PDFDictionaryElement extends AbstractPDFDictionaryElement {
+public class PDFDictionaryElement extends PDFCollectionEntryElement {
 
-    public static final String ATT_PAGE_NUMBERS = PDFDictionaryExtension.PROPERTY_PAGE_NUMBERS;
-
-    private PDFDictionaryExtension extension;
+    public static final String ATT_ID = PDFDictionaryExtension.PROPERTY_ID;
 
     /**
      * Main constructor
      * @param parent parent FO node
      */
     PDFDictionaryElement(FONode parent, PDFDictionaryType type) {
-        super(parent);
-        this.extension = new PDFDictionaryExtension(type);
+        super(parent, PDFObjectType.Dictionary, createExtension(type));
+    }
+
+    private static PDFDictionaryExtension createExtension(PDFDictionaryType type) {
+        if (type == PDFDictionaryType.Action) {
+            return new PDFActionExtension();
+        } else if (type == PDFDictionaryType.Catalog) {
+            return new PDFCatalogExtension();
+        } else if (type == PDFDictionaryType.Layer) {
+            return new PDFLayerExtension();
+        } else if (type == PDFDictionaryType.Navigator) {
+            return new PDFNavigatorExtension();
+        } else if (type == PDFDictionaryType.Page) {
+            return new PDFPageExtension();
+        } else {
+            return new PDFDictionaryExtension(type);
+        }
     }
 
-    public PDFDictionaryExtension getExtension() {
-        return extension;
+    public PDFDictionaryExtension getDictionaryExtension() {
+        assert getExtension() instanceof PDFDictionaryExtension;
+        return (PDFDictionaryExtension) getExtension();
     }
 
     @Override
     public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList propertyList) throws FOPException {
-        if (extension.getDictionaryType() == PDFDictionaryType.Catalog) {
-            // no specific properties
-        } else if (extension.getDictionaryType() == PDFDictionaryType.Page) {
-            String pageNumbers = attlist.getValue(ATT_PAGE_NUMBERS);
-            if (pageNumbers != null) {
-                extension.setProperty(ATT_PAGE_NUMBERS, pageNumbers);
+        PDFDictionaryExtension extension = getDictionaryExtension();
+        if (extension.usesIDAttribute()) {
+            String id = attlist.getValue(ATT_ID);
+            if (id != null) {
+                extension.setProperty(PDFDictionaryExtension.PROPERTY_ID, id);
             }
-        } else if (extension.getDictionaryType() == PDFDictionaryType.Dictionary) {
+        }
+        if (extension.getDictionaryType() == PDFDictionaryType.Dictionary) {
             String key = attlist.getValue(ATT_KEY);
             if (key == null) {
-                missingPropertyError(ATT_KEY);
+                if (parent instanceof PDFDictionaryElement) {
+                    missingPropertyError(ATT_KEY);
+                }
             } else if (key.length() == 0) {
                 invalidPropertyValueError(ATT_KEY, key, null);
             } else {
@@ -78,16 +93,18 @@ public class PDFDictionaryElement extend
     public void startOfNode() throws FOPException {
         super.startOfNode();
         String localName = getLocalName();
-        if (localName.equals("catalog")) {
-            if (parent.getNameId() != Constants.FO_DECLARATIONS) {
-                invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), "rule.childOfDeclarations");
-            }
+        if (localName.equals("action")) {
+            // handled in PDFActionElement subclass
+        } else if (localName.equals("catalog")) {
+            // handled in PDFCatalogElement subclass
+        } else if (localName.equals("layer")) {
+            // handled in PDFLayerElement subclass
+        } else if (localName.equals("navigator")) {
+            // handled in PDFNavigattorElement subclass
         } else if (localName.equals("page")) {
-            if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) {
-                invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), "rule.childOfSPM");
-            }
+            // handled in PDFPageElement subclass
         } else if (localName.equals("dictionary")) {
-            if (!PDFDictionaryType.hasValueOfElementName(parent.getLocalName())) {
+            if (!PDFDictionaryType.hasValueOfElementName(parent.getLocalName()) && !PDFObjectType.Array.elementName().equals(parent.getLocalName())) {
                 invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), null);
             }
         } else {
@@ -97,14 +114,15 @@ public class PDFDictionaryElement extend
 
     @Override
     protected void addChildNode(FONode child) throws FOPException {
+        PDFDictionaryExtension extension = getDictionaryExtension();
         if (child instanceof PDFDictionaryElement) {
-            PDFDictionaryExtension extension = ((PDFDictionaryElement) child).getExtension();
-            if (extension.getDictionaryType() == PDFDictionaryType.Dictionary) {
-                this.extension.addEntry(extension);
-            }
-        } else if (child instanceof PDFDictionaryEntryElement) {
-            PDFDictionaryEntryExtension extension = ((PDFDictionaryEntryElement) child).getExtension();
-            this.extension.addEntry(extension);
+            PDFDictionaryExtension entry = ((PDFDictionaryElement) child).getDictionaryExtension();
+            if (entry.getDictionaryType() == PDFDictionaryType.Dictionary) {
+                extension.addEntry(entry);
+            }
+        } else if (child instanceof PDFCollectionEntryElement) {
+            PDFCollectionEntryExtension entry = ((PDFCollectionEntryElement) child).getExtension();
+            extension.addEntry(entry);
         }
     }
 
@@ -115,12 +133,13 @@ public class PDFDictionaryElement extend
 
     @Override
     public String getLocalName() {
+        PDFDictionaryExtension extension = getDictionaryExtension();
         return extension.getDictionaryType().elementName();
     }
 
     @Override
     protected ExtensionAttachment instantiateExtensionAttachment() {
-        return new PDFDictionaryAttachment(extension);
+        return new PDFDictionaryAttachment(getDictionaryExtension());
     }
 
 }

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryExtension.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryExtension.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryExtension.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryExtension.java Mon Jan 13 20:39:34 2014
@@ -24,24 +24,36 @@ import java.util.Map;
 
 // CSOFF: LineLengthCheck
 
-public class PDFDictionaryExtension extends PDFDictionaryEntryExtension {
+public class PDFDictionaryExtension extends PDFCollectionExtension {
 
+    public static final String PROPERTY_ID = "id";
     public static final String PROPERTY_PAGE_NUMBERS = "page-numbers";
 
     private static final long serialVersionUID = -1L;
 
     private PDFDictionaryType dictionaryType;
     private Map<String, String> properties;
-    private List<PDFDictionaryEntryExtension> entries;
+    private List<PDFCollectionEntryExtension> entries;
 
     PDFDictionaryExtension() {
+        this(PDFDictionaryType.Dictionary);
     }
 
     PDFDictionaryExtension(PDFDictionaryType dictionaryType) {
-        super(PDFDictionaryEntryType.Dictionary);
+        super(PDFObjectType.Dictionary);
         this.dictionaryType = dictionaryType;
         this.properties = new java.util.HashMap<String, String>();
-        this.entries = new java.util.ArrayList<PDFDictionaryEntryExtension>();
+        this.entries = new java.util.ArrayList<PDFCollectionEntryExtension>();
+    }
+
+    @Override
+    public void setValue(Object value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object getValue() {
+        return getEntries();
     }
 
     public PDFDictionaryType getDictionaryType() {
@@ -56,15 +68,40 @@ public class PDFDictionaryExtension exte
         return properties.get(name);
     }
 
-    public void addEntry(PDFDictionaryEntryExtension entry) {
-        entries.add(entry);
+    @Override
+    public void addEntry(PDFCollectionEntryExtension entry) {
+        if ((entry.getKey() == null) || (entry.getKey().length() == 0)) {
+            throw new IllegalArgumentException();
+        } else {
+            entries.add(entry);
+        }
     }
 
-    public List<PDFDictionaryEntryExtension> getEntries() {
+    public List<PDFCollectionEntryExtension> getEntries() {
         return entries;
     }
 
-    public PDFDictionaryEntryExtension getLastEntry() {
+    public PDFCollectionEntryExtension findEntry(String key) {
+        for (PDFCollectionEntryExtension entry : entries) {
+            String entryKey = entry.getKey();
+            if ((entryKey != null) && entryKey.equals(key)) {
+                return entry;
+            }
+        }
+        return null;
+    }
+
+    public Object findEntryValue(String key) {
+        for (PDFCollectionEntryExtension entry : entries) {
+            String entryKey = entry.getKey();
+            if ((entryKey != null) && entryKey.equals(key)) {
+                return entry.getValue();
+            }
+        }
+        return null;
+    }
+
+    public PDFCollectionEntryExtension getLastEntry() {
         if (entries.size() > 0) {
             return entries.get(entries.size() - 1);
         } else {
@@ -72,48 +109,8 @@ public class PDFDictionaryExtension exte
         }
     }
 
-    /**
-     * Determine if page dictionary and page number matches.
-     * @param pageNumber page number, where first page number is 1
-     * @return true if this dictionary is a page dictionary and specified page number matches specified page-number property
-     */
-    public boolean matchesPageNumber(int pageNumber) {
-        if (dictionaryType != PDFDictionaryType.Page) {
-            return false;
-        }
-        String pageNumbers = getProperty(PROPERTY_PAGE_NUMBERS);
-        if ((pageNumbers == null) || (pageNumbers.length() == 0)) {
-            return false;
-        } else if (pageNumbers.equals("*")) {
-            return true;
-        } else {
-            for (String interval : pageNumbers.split("\\s*,\\s*")) {
-                String[] components = interval.split("\\s*-\\s*");
-                if (components.length < 1) {
-                    continue;
-                } else {
-                    try {
-                        int start = Integer.parseInt(components[0]);
-                        int end = 0;
-                        if (components.length > 1) {
-                            if (!components[1].equals("LAST")) {
-                                end = Integer.parseInt(components[1]);
-                            }
-                        }
-                        if ((end == 0) && (pageNumber == start)) {
-                            return true;
-                        } else if ((end > start) && (pageNumber >= start) && (pageNumber < end)) {
-                            return true;
-                        } else {
-                            continue;
-                        }
-                    } catch (NumberFormatException e) {
-                        continue;
-                    }
-                }
-            }
-        }
-        return false;
+    public boolean usesIDAttribute() {
+        return dictionaryType.usesIDAttribute();
     }
 
     @Override

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryType.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryType.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryType.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryType.java Mon Jan 13 20:39:34 2014
@@ -25,17 +25,28 @@ package org.apache.fop.render.pdf.extens
  * Enumeration type for PDF dictionary extension elements.
  */
 public enum PDFDictionaryType {
-    Dictionary("dictionary"),   // generic (nested) dictionary element
-    Catalog("catalog"),         // catalog dictionary element
-    Page("page");               // page dictionary element
+    Action("action", true),             // action dictionary element
+    Catalog("catalog"),                 // catalog dictionary element
+    Dictionary("dictionary"),           // generic (nested) dictionary element
+    Layer("layer", true),               // optional content group dictionary element
+    Navigator("navigator", true),       // navigation node dictionary element
+    Page("page");                       // page dictionary element
 
     private String elementName;
-    PDFDictionaryType(String elementName) {
+    private boolean usesIDAttribute;
+    PDFDictionaryType(String elementName, boolean usesIDAttribute) {
         this.elementName = elementName;
+        this.usesIDAttribute = usesIDAttribute;
+    }
+    PDFDictionaryType(String elementName) {
+        this(elementName, false);
     }
     public String elementName() {
         return elementName;
     }
+    public boolean usesIDAttribute() {
+        return usesIDAttribute;
+    }
     static PDFDictionaryType valueOfElementName(String elementName) {
         for (PDFDictionaryType type : values()) {
             if (type.elementName.equals(elementName)) {

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFElementMapping.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFElementMapping.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFElementMapping.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFElementMapping.java Mon Jan 13 20:39:34 2014
@@ -41,17 +41,56 @@ public class PDFElementMapping extends E
     protected void initialize() {
         if (foObjs == null) {
             foObjs = new java.util.HashMap<String, Maker>();
+            // pdf:action
+            foObjs.put(PDFDictionaryType.Action.elementName(), new PDFActionElementMaker());
+            // pdf:array
+            foObjs.put(PDFObjectType.Array.elementName(), new PDFArrayElementMaker());
+            // pdf:boolean
+            foObjs.put(PDFObjectType.Boolean.elementName(), new PDFCollectionEntryElementMaker(PDFObjectType.Boolean));
+            // pdf:catalog
+            foObjs.put(PDFDictionaryType.Catalog.elementName(), new PDFCatalogElementMaker());
+            // pdf:dictionary
+            foObjs.put(PDFDictionaryType.Dictionary.elementName(), new PDFDictionaryElementMaker());
             // pdf:embedded-file
             foObjs.put(PDFEmbeddedFileElement.ELEMENT, new PDFEmbeddedFileElementMaker());
-            // pdf:{catalog,page} et al.
-            for (PDFDictionaryType type : PDFDictionaryType.values()) {
-                foObjs.put(type.elementName(), new PDFDictionaryElementMaker(type));
-            }
-            for (PDFDictionaryEntryType type : PDFDictionaryEntryType.values()) {
-                if (type != PDFDictionaryEntryType.Dictionary) {
-                    foObjs.put(type.elementName(), new PDFDictionaryEntryElementMaker(type));
-                }
-            }
+            // pdf:name
+            foObjs.put(PDFObjectType.Name.elementName(), new PDFCollectionEntryElementMaker(PDFObjectType.Name));
+            // pdf:number
+            foObjs.put(PDFObjectType.Number.elementName(), new PDFCollectionEntryElementMaker(PDFObjectType.Number));
+            // pdf:navigator
+            foObjs.put(PDFDictionaryType.Navigator.elementName(), new PDFNavigatorElementMaker());
+            // pdf:layer
+            foObjs.put(PDFDictionaryType.Layer.elementName(), new PDFLayerElementMaker());
+            // pdf:page
+            foObjs.put(PDFDictionaryType.Page.elementName(), new PDFPageElementMaker());
+            // pdf:reference
+            foObjs.put(PDFObjectType.Reference.elementName(), new PDFReferenceElementMaker());
+            // pdf:string
+            foObjs.put(PDFObjectType.String.elementName(), new PDFCollectionEntryElementMaker(PDFObjectType.String));
+        }
+    }
+
+    static class PDFActionElementMaker extends ElementMapping.Maker {
+        public FONode make(FONode parent) {
+            return new PDFActionElement(parent);
+        }
+    }
+
+    static class PDFArrayElementMaker extends ElementMapping.Maker {
+        public FONode make(FONode parent) {
+            return new PDFArrayElement(parent);
+        }
+    }
+
+    static class PDFCatalogElementMaker extends ElementMapping.Maker {
+        public FONode make(FONode parent) {
+            return new PDFCatalogElement(parent);
+        }
+    }
+
+    static class PDFDictionaryElementMaker extends ElementMapping.Maker {
+        public FONode make(FONode parent) {
+            return new PDFDictionaryElement(parent, PDFDictionaryType.Dictionary);
         }
     }
 
@@ -61,23 +100,38 @@ public class PDFElementMapping extends E
         }
     }
 
-    static class PDFDictionaryElementMaker extends ElementMapping.Maker {
-        private PDFDictionaryType dictionaryType;
-        PDFDictionaryElementMaker(PDFDictionaryType dictionaryType) {
-            this.dictionaryType = dictionaryType;
+    static class PDFLayerElementMaker extends ElementMapping.Maker {
+        public FONode make(FONode parent) {
+            return new PDFLayerElement(parent);
         }
+    }
+
+    static class PDFNavigatorElementMaker extends ElementMapping.Maker {
         public FONode make(FONode parent) {
-            return new PDFDictionaryElement(parent, dictionaryType);
+            return new PDFNavigatorElement(parent);
         }
     }
 
-    static class PDFDictionaryEntryElementMaker extends ElementMapping.Maker {
-        private PDFDictionaryEntryType entryType;
-        PDFDictionaryEntryElementMaker(PDFDictionaryEntryType entryType) {
+    static class PDFPageElementMaker extends ElementMapping.Maker {
+        public FONode make(FONode parent) {
+            return new PDFPageElement(parent);
+        }
+    }
+
+    static class PDFCollectionEntryElementMaker extends ElementMapping.Maker {
+        private PDFObjectType entryType;
+        PDFCollectionEntryElementMaker(PDFObjectType entryType) {
             this.entryType = entryType;
         }
         public FONode make(FONode parent) {
-            return new PDFDictionaryEntryElement(parent, entryType);
+            return new PDFCollectionEntryElement(parent, entryType);
         }
     }
+
+    static class PDFReferenceElementMaker extends ElementMapping.Maker {
+        public FONode make(FONode parent) {
+            return new PDFReferenceElement(parent);
+        }
+    }
+
 }

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java Mon Jan 13 20:39:34 2014
@@ -49,7 +49,7 @@ public class PDFExtensionHandler extends
     private Attributes lastAttributes;
 
     // PDFDictionaryAttachment related
-    private Stack<PDFDictionaryExtension> dictionaries = new Stack<PDFDictionaryExtension>();
+    private Stack<PDFCollectionExtension> collections = new Stack<PDFCollectionExtension>();
     private boolean captureContent;
     private StringBuffer characters;
 
@@ -58,29 +58,78 @@ public class PDFExtensionHandler extends
         if (PDFExtensionAttachment.CATEGORY.equals(uri)) {
             if (localName.equals(PDFEmbeddedFileAttachment.ELEMENT)) {
                 lastAttributes = new AttributesImpl(attributes);
-            } else if (PDFDictionaryType.hasValueOfElementName(localName)) {
-                PDFDictionaryExtension dictionary = new PDFDictionaryExtension(PDFDictionaryType.valueOfElementName(localName));
-                String key = attributes.getValue(PDFDictionaryEntryExtension.PROPERTY_KEY);
+            } else if (PDFDictionaryType.Action.elementName().equals(localName)) {
+                PDFActionExtension action = new PDFActionExtension();
+                String id = attributes.getValue(PDFDictionaryElement.ATT_ID);
+                if (id != null) {
+                    action.setProperty(PDFDictionaryExtension.PROPERTY_ID, id);
+                }
+                String type = attributes.getValue(PDFActionElement.ATT_TYPE);
+                if (type != null) {
+                    action.setProperty(PDFActionExtension.PROPERTY_TYPE, type);
+                }
+                collections.push(action);
+            } else if (PDFObjectType.Array.elementName().equals(localName)) {
+                PDFArrayExtension array = new PDFArrayExtension();
+                String key = attributes.getValue(PDFCollectionEntryElement.ATT_KEY);
+                if (key != null) {
+                    array.setKey(key);
+                }
+                collections.push(array);
+            } else if (PDFDictionaryType.Catalog.elementName().equals(localName)) {
+                PDFCatalogExtension catalog = new PDFCatalogExtension();
+                collections.push(catalog);
+            } else if (PDFDictionaryType.Dictionary.elementName().equals(localName)) {
+                PDFDictionaryExtension dictionary = new PDFDictionaryExtension();
+                String key = attributes.getValue(PDFCollectionEntryElement.ATT_KEY);
                 if (key != null) {
                     dictionary.setKey(key);
                 }
-                if (dictionary.getDictionaryType() == PDFDictionaryType.Page) {
-                    String pageNumbers = attributes.getValue(PDFDictionaryElement.ATT_PAGE_NUMBERS);
-                    if (pageNumbers != null) {
-                        dictionary.setProperty(PDFDictionaryElement.ATT_PAGE_NUMBERS, pageNumbers);
-                    }
+                collections.push(dictionary);
+            } else if (PDFDictionaryType.Layer.elementName().equals(localName)) {
+                PDFLayerExtension layer = new PDFLayerExtension();
+                String id = attributes.getValue(PDFDictionaryElement.ATT_ID);
+                if (id != null) {
+                    layer.setProperty(PDFDictionaryExtension.PROPERTY_ID, id);
+                }
+                collections.push(layer);
+            } else if (PDFDictionaryType.Navigator.elementName().equals(localName)) {
+                PDFNavigatorExtension navigator = new PDFNavigatorExtension();
+                String id = attributes.getValue(PDFDictionaryElement.ATT_ID);
+                if (id != null) {
+                    navigator.setProperty(PDFDictionaryExtension.PROPERTY_ID, id);
+                }
+                collections.push(navigator);
+            } else if (PDFDictionaryType.Page.elementName().equals(localName)) {
+                PDFPageExtension page = new PDFPageExtension();
+                String pageNumbers = attributes.getValue(PDFPageElement.ATT_PAGE_NUMBERS);
+                if (pageNumbers != null) {
+                    page.setProperty(PDFPageExtension.PROPERTY_PAGE_NUMBERS, pageNumbers);
+                }
+                collections.push(page);
+            } else if (PDFObjectType.hasValueOfElementName(localName)) {
+                PDFCollectionEntryExtension entry;
+                if (PDFObjectType.Reference.elementName().equals(localName)) {
+                    entry = new PDFReferenceExtension();
+                } else {
+                    entry = new PDFCollectionEntryExtension(PDFObjectType.valueOfElementName(localName));
                 }
-                dictionaries.push(dictionary);
-            } else if (PDFDictionaryEntryType.hasValueOfElementName(localName)) {
-                PDFDictionaryEntryExtension entry = new PDFDictionaryEntryExtension(PDFDictionaryEntryType.valueOfElementName(localName));
-                String key = attributes.getValue(PDFDictionaryEntryElement.ATT_KEY);
+                String key = attributes.getValue(PDFCollectionEntryElement.ATT_KEY);
                 if (key != null) {
                     entry.setKey(key);
                 }
-                if (!dictionaries.empty()) {
-                    PDFDictionaryExtension dictionary = dictionaries.peek();
-                    dictionary.addEntry(entry);
-                    captureContent = true;
+                if (entry instanceof PDFReferenceExtension) {
+                    String refid = attributes.getValue(PDFReferenceElement.ATT_REFID);
+                    if (refid != null) {
+                        ((PDFReferenceExtension) entry).setReferenceId(refid);
+                    }
+                }
+                if (!collections.empty()) {
+                    PDFCollectionExtension collection = collections.peek();
+                    collection.addEntry(entry);
+                    if (!(entry instanceof PDFReferenceExtension)) {
+                        captureContent = true;
+                    }
                 }
             } else {
                 throw new SAXException("Unhandled element " + localName + " in namespace: " + uri);
@@ -107,33 +156,48 @@ public class PDFExtensionHandler extends
                 String name = lastAttributes.getValue("name");
                 String src = lastAttributes.getValue("src");
                 String desc = lastAttributes.getValue("description");
+                this.lastAttributes = null;
                 this.returnedObject = new PDFEmbeddedFileAttachment(name, src, desc);
             } else if (PDFDictionaryType.hasValueOfElementName(localName)) {
-                if (!dictionaries.empty()) {
-                    PDFDictionaryExtension dictionary = dictionaries.pop();
-                    if ((dictionary.getDictionaryType() == PDFDictionaryType.Catalog) || (dictionary.getDictionaryType() == PDFDictionaryType.Page)) {
+                if (!collections.empty() && (collections.peek() instanceof PDFDictionaryExtension)) {
+                    PDFDictionaryExtension dictionary = (PDFDictionaryExtension) collections.pop();
+                    if (!collections.empty()) {
+                        PDFCollectionExtension collectionOuter = collections.peek();
+                        collectionOuter.addEntry(dictionary);
+                    } else if (dictionary.getDictionaryType() != PDFDictionaryType.Dictionary) {
                         this.returnedObject = new PDFDictionaryAttachment(dictionary);
-                    } else if (!dictionaries.empty()) {
-                        PDFDictionaryExtension dictionaryOuter = dictionaries.peek();
-                        dictionaryOuter.addEntry(dictionary);
+                    } else {
+                        throw new SAXException(new IllegalStateException("generic dictionary not permitted at outer level"));
+                    }
+                } else {
+                    throw new SAXException(new IllegalStateException("collections stack is empty or not a dictionary"));
+                }
+            } else if (PDFObjectType.Array.elementName().equals(localName)) {
+                if (!collections.empty() && (collections.peek() instanceof PDFArrayExtension)) {
+                    PDFArrayExtension array = (PDFArrayExtension) collections.pop();
+                    if (!collections.empty()) {
+                        PDFCollectionExtension collectionOuter = collections.peek();
+                        collectionOuter.addEntry(array);
+                    } else {
+                        throw new SAXException(new IllegalStateException("array not permitted at outer level"));
                     }
                 } else {
-                    throw new SAXException(new IllegalStateException("no active dictionary"));
+                    throw new SAXException(new IllegalStateException("collections stack is empty or not an array"));
                 }
-            } else if (PDFDictionaryEntryType.hasValueOfElementName(localName)) {
-                if (!dictionaries.empty()) {
-                    PDFDictionaryExtension dictionary = dictionaries.peek();
-                    PDFDictionaryEntryExtension entry = dictionary.getLastEntry();
+            } else if (PDFObjectType.hasValueOfElementName(localName)) {
+                if (!collections.empty()) {
+                    PDFCollectionExtension collection = collections.peek();
+                    PDFCollectionEntryExtension entry = collection.getLastEntry();
                     if (entry != null) {
                         if (characters != null) {
                             entry.setValue(characters.toString());
                             characters = null;
                         }
                     } else {
-                        throw new SAXException(new IllegalStateException("no active entry"));
+                        throw new SAXException(new IllegalStateException("no current entry"));
                     }
                 } else {
-                    throw new SAXException(new IllegalStateException("no active dictionary"));
+                    throw new SAXException(new IllegalStateException("entry not permitted at outer level"));
                 }
             }
         }

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSFontUtils.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSFontUtils.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSFontUtils.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSFontUtils.java Mon Jan 13 20:39:34 2014
@@ -175,6 +175,15 @@ public class PSFontUtils extends org.apa
 
         if (!tracker.isResourceSupplied(WINANSI_ENCODING_RESOURCE)) {
             //Only out Base 14 fonts still use that
+            for (Typeface tf : fonts.values()) {
+                if (tf instanceof LazyFont) {
+                    tf = ((LazyFont)tf).getRealFont();
+                    if (tf instanceof SingleByteFont
+                            && ((SingleByteFont) tf).getEncoding().getName().equals("custom")) {
+                        defineEncoding(gen, ((SingleByteFont) tf).getEncoding());
+                    }
+                }
+            }
             defineWinAnsiEncoding(gen);
         }
         gen.commentln("%FOPBeginFontReencode");

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java Mon Jan 13 20:39:34 2014
@@ -19,26 +19,50 @@
 
 package org.apache.fop.render.ps;
 
+import java.awt.Color;
+import java.awt.Dimension;
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.imageio.ImageIO;
 
 import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 import org.apache.batik.bridge.BridgeContext;
 import org.apache.batik.bridge.GVTBuilder;
 import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.transcoder.SVGAbstractTranscoder;
+import org.apache.batik.transcoder.TranscoderException;
+import org.apache.batik.transcoder.TranscoderInput;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.image.PNGTranscoder;
 
 import org.apache.xmlgraphics.image.loader.Image;
 import org.apache.xmlgraphics.image.loader.ImageFlavor;
 import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
-import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
+import org.apache.xmlgraphics.ps.ImageEncoder;
+import org.apache.xmlgraphics.ps.ImageEncodingHelper;
 import org.apache.xmlgraphics.ps.PSGenerator;
 
 import org.apache.fop.image.loader.batik.BatikImageFlavors;
 import org.apache.fop.image.loader.batik.BatikUtil;
 import org.apache.fop.render.ImageHandler;
 import org.apache.fop.render.RenderingContext;
+import org.apache.fop.render.ps.svg.PSSVGGraphics2D;
 import org.apache.fop.svg.SVGEventProducer;
 import org.apache.fop.svg.SVGUserAgent;
 
@@ -47,6 +71,9 @@ import org.apache.fop.svg.SVGUserAgent;
  */
 public class PSImageHandlerSVG implements ImageHandler {
 
+    private static final Color FALLBACK_COLOR = new Color(255, 33, 117);
+    private HashMap<String, String> gradientsFound = new HashMap<String, String>();
+
     private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
         BatikImageFlavors.SVG_DOM
     };
@@ -58,78 +85,262 @@ public class PSImageHandlerSVG implement
         PSGenerator gen = psContext.getGenerator();
         ImageXMLDOM imageSVG = (ImageXMLDOM)image;
 
-        //Controls whether text painted by Batik is generated using text or path operations
-        boolean strokeText = false;
-        //TODO Configure text stroking
-
-        SVGUserAgent ua
-             = new SVGUserAgent(context.getUserAgent(), new AffineTransform());
-
-        PSGraphics2D graphics = new PSGraphics2D(strokeText, gen);
-        graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
-
-        BridgeContext ctx = new PSBridgeContext(ua,
-                (strokeText ? null : psContext.getFontInfo()),
-                context.getUserAgent().getImageManager(),
-                context.getUserAgent().getImageSessionContext());
-
-        //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
-        //to it.
-        Document clonedDoc = BatikUtil.cloneSVGDocument(imageSVG.getDocument());
+        if (shouldRaster(imageSVG)) {
+            InputStream is = renderSVGToInputStream(context, imageSVG);
 
-        GraphicsNode root;
+            float x = (float) pos.getX() / 1000f;
+            float y = (float) pos.getY() / 1000f;
+            float w = (float) pos.getWidth() / 1000f;
+            float h = (float) pos.getHeight() / 1000f;
+            Rectangle2D targetRect = new Rectangle2D.Double(x, y, w, h);
+
+            MaskedImage mi = convertToRGB(ImageIO.read(is));
+            BufferedImage ri = mi.getImage();
+            ImageEncoder encoder = ImageEncodingHelper.createRenderedImageEncoder(ri);
+            Dimension imgDim = new Dimension(ri.getWidth(), ri.getHeight());
+            String imgDescription = ri.getClass().getName();
+            ImageEncodingHelper helper = new ImageEncodingHelper(ri);
+            ColorModel cm = helper.getEncodedColorModel();
+            PSImageUtils.writeImage(encoder, imgDim, imgDescription, targetRect, cm, gen, ri, mi.getMaskColor());
+        } else {
+            //Controls whether text painted by Batik is generated using text or path operations
+            boolean strokeText = false;
+            //TODO Configure text stroking
+
+            SVGUserAgent ua
+                 = new SVGUserAgent(context.getUserAgent(), new AffineTransform());
+
+            PSSVGGraphics2D graphics = new PSSVGGraphics2D(strokeText, gen);
+            graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
+
+            BridgeContext ctx = new PSBridgeContext(ua,
+                    (strokeText ? null : psContext.getFontInfo()),
+                    context.getUserAgent().getImageManager(),
+                    context.getUserAgent().getImageSessionContext());
+
+            //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
+            //to it.
+            Document clonedDoc = BatikUtil.cloneSVGDocument(imageSVG.getDocument());
+
+            GraphicsNode root;
+            try {
+                GVTBuilder builder = new GVTBuilder();
+                root = builder.build(ctx, clonedDoc);
+            } catch (Exception e) {
+                SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
+                        context.getUserAgent().getEventBroadcaster());
+                eventProducer.svgNotBuilt(this, e, image.getInfo().getOriginalURI());
+                return;
+            }
+            // get the 'width' and 'height' attributes of the SVG document
+            float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
+            float h = (float)ctx.getDocumentSize().getHeight() * 1000f;
+
+            float sx = pos.width / w;
+            float sy = pos.height / h;
+
+            ctx = null;
+
+            gen.commentln("%FOPBeginSVG");
+            gen.saveGraphicsState();
+            final boolean clip = false;
+            if (clip) {
+                /*
+                 * Clip to the svg area.
+                 * Note: To have the svg overlay (under) a text area then use
+                 * an fo:block-container
+                 */
+                gen.writeln("newpath");
+                gen.defineRect(pos.getMinX() / 1000f, pos.getMinY() / 1000f,
+                        pos.width / 1000f, pos.height / 1000f);
+                gen.writeln("clip");
+            }
+
+            // transform so that the coordinates (0,0) is from the top left
+            // and positive is down and to the right. (0,0) is where the
+            // viewBox puts it.
+            gen.concatMatrix(sx, 0, 0, sy, pos.getMinX() / 1000f, pos.getMinY() / 1000f);
+
+            AffineTransform transform = new AffineTransform();
+            // scale to viewbox
+            transform.translate(pos.getMinX(), pos.getMinY());
+            gen.getCurrentState().concatMatrix(transform);
+            try {
+                root.paint(graphics);
+            } catch (Exception e) {
+                SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
+                        context.getUserAgent().getEventBroadcaster());
+                eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI());
+            }
+
+            gen.restoreGraphicsState();
+            gen.commentln("%FOPEndSVG");
+        }
+    }
+
+    private InputStream renderSVGToInputStream(RenderingContext context, ImageXMLDOM imageSVG) throws IOException {
+        PNGTranscoder png = new PNGTranscoder();
+        Float width = getDimension(imageSVG.getDocument(), "width") * 8;
+        png.addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, width);
+        Float height = getDimension(imageSVG.getDocument(), "height") * 8;
+        png.addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, height);
+        TranscoderInput input = new TranscoderInput(imageSVG.getDocument());
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        TranscoderOutput output = new TranscoderOutput(os);
         try {
-            GVTBuilder builder = new GVTBuilder();
-            root = builder.build(ctx, clonedDoc);
-        } catch (Exception e) {
+            png.transcode(input, output);
+        } catch (TranscoderException ex) {
             SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
                     context.getUserAgent().getEventBroadcaster());
-            eventProducer.svgNotBuilt(this, e, image.getInfo().getOriginalURI());
-            return;
+            eventProducer.svgRenderingError(this, ex, imageSVG.getInfo().getOriginalURI());
+        } finally {
+            os.flush();
+            os.close();
+        }
+        return new ByteArrayInputStream(os.toByteArray());
+    }
+
+    private MaskedImage convertToRGB(BufferedImage alphaImage) {
+        int[] red = new int[256];
+        int[] green = new int[256];
+        int[] blue = new int[256];
+        BufferedImage rgbImage = new BufferedImage(alphaImage.getWidth(),
+                alphaImage.getHeight(), BufferedImage.TYPE_INT_RGB);
+        //Count occurances of each colour in image
+        for (int cx = 0; cx < alphaImage.getWidth(); cx++) {
+            for (int cy = 0; cy < alphaImage.getHeight(); cy++) {
+                int pixelValue = alphaImage.getRGB(cx, cy);
+                Color pixelColor = new Color(pixelValue);
+                red[pixelColor.getRed()]++;
+                green[pixelColor.getGreen()]++;
+                blue[pixelColor.getBlue()]++;
+            }
+        }
+        //Find colour not in image
+        Color alphaSwap = null;
+        for (int i = 0; i < 256; i++) {
+            if (red[i] == 0) {
+                alphaSwap = new Color(i, 0, 0);
+                break;
+            } else if (green[i] == 0) {
+                alphaSwap = new Color(0, i, 0);
+                break;
+            } else if (blue[i] == 0) {
+                alphaSwap = new Color(0, 0, i);
+                break;
+            }
+        }
+        //Check if all variations are used in all three colours
+        if (alphaSwap == null) {
+            //Fallback colour is no unique colour channel can be found
+            alphaSwap = FALLBACK_COLOR;
+        }
+        //Replace alpha channel with the new mask colour
+        for (int cx = 0; cx < alphaImage.getWidth(); cx++) {
+            for (int cy = 0; cy < alphaImage.getHeight(); cy++) {
+                int pixelValue = alphaImage.getRGB(cx, cy);
+                if (pixelValue == 0) {
+                    rgbImage.setRGB(cx, cy, alphaSwap.getRGB());
+                } else {
+                    rgbImage.setRGB(cx, cy, alphaImage.getRGB(cx, cy));
+                }
+            }
+        }
+        return new MaskedImage(rgbImage, alphaSwap);
+    }
+
+    private static class MaskedImage {
+        private Color maskColor = new Color(0, 0, 0);
+        private BufferedImage image;
+
+        public MaskedImage(BufferedImage image, Color maskColor) {
+            this.image = image;
+            this.maskColor = maskColor;
+        }
+
+        public Color getMaskColor() {
+            return maskColor;
+        }
+
+        public BufferedImage getImage() {
+            return image;
+        }
+    }
+
+    private Float getDimension(Document document, String dimension) {
+        if (document.getFirstChild().getAttributes().getNamedItem(dimension) != null) {
+            String width = document.getFirstChild().getAttributes().getNamedItem(dimension).getNodeValue();
+            width = width.replaceAll("[^\\d.]", "");
+            return Float.parseFloat(width);
         }
-        // get the 'width' and 'height' attributes of the SVG document
-        float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
-        float h = (float)ctx.getDocumentSize().getHeight() * 1000f;
-
-        float sx = pos.width / w;
-        float sy = pos.height / h;
-
-        ctx = null;
-
-        gen.commentln("%FOPBeginSVG");
-        gen.saveGraphicsState();
-        final boolean clip = false;
-        if (clip) {
-            /*
-             * Clip to the svg area.
-             * Note: To have the svg overlay (under) a text area then use
-             * an fo:block-container
-             */
-            gen.writeln("newpath");
-            gen.defineRect(pos.getMinX() / 1000f, pos.getMinY() / 1000f,
-                    pos.width / 1000f, pos.height / 1000f);
-            gen.writeln("clip");
-        }
-
-        // transform so that the coordinates (0,0) is from the top left
-        // and positive is down and to the right. (0,0) is where the
-        // viewBox puts it.
-        gen.concatMatrix(sx, 0, 0, sy, pos.getMinX() / 1000f, pos.getMinY() / 1000f);
-
-        AffineTransform transform = new AffineTransform();
-        // scale to viewbox
-        transform.translate(pos.getMinX(), pos.getMinY());
-        gen.getCurrentState().concatMatrix(transform);
+        return null;
+    }
+
+    private boolean shouldRaster(ImageXMLDOM image) {
+        //A list of objects on which to check opacity
         try {
-            root.paint(graphics);
-        } catch (Exception e) {
-            SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
-                    context.getUserAgent().getEventBroadcaster());
-            eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI());
+        List<String> gradMatches = new ArrayList<String>();
+        gradMatches.add("radialGradient");
+        gradMatches.add("linearGradient");
+        return recurseSVGElements(image.getDocument().getChildNodes(), gradMatches, false);
+        } finally {
+            gradientsFound.clear();
         }
+    }
 
-        gen.restoreGraphicsState();
-        gen.commentln("%FOPEndSVG");
+    private boolean recurseSVGElements(NodeList childNodes, List<String> gradMatches, boolean isMatched) {
+        boolean opacityFound = false;
+        for (int i = 0; i < childNodes.getLength(); i++) {
+            Node curNode = childNodes.item(i);
+            if (isMatched && curNode.getLocalName() != null && curNode.getLocalName().equals("stop")) {
+                if (curNode.getAttributes().getNamedItem("style") != null) {
+                    String[] stylePairs = curNode.getAttributes().getNamedItem("style").getNodeValue()
+                            .split(";");
+                    for (int styleAtt = 0; styleAtt < stylePairs.length; styleAtt++) {
+                        String[] style = stylePairs[styleAtt].split(":");
+                        if (style[0].equalsIgnoreCase("stop-opacity")) {
+                            if (Double.parseDouble(style[1]) < 1) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+                if (curNode.getAttributes().getNamedItem("stop-opacity") != null) {
+                    String opacityValue = curNode.getAttributes().getNamedItem("stop-opacity").getNodeValue();
+                    if (Double.parseDouble(opacityValue) < 1) {
+                        return true;
+                    }
+                }
+            }
+            String nodeName = curNode.getLocalName();
+            //Special case where rasterization needed for radial gradients
+            if (nodeName != null && nodeName.equals("ellipse")) {
+                String found = "";
+                String ellipseFill = curNode.getAttributes().getNamedItem("fill").getNodeValue();
+                Pattern pattern = Pattern.compile("#(.*?)\\)");
+                Matcher matcher = pattern.matcher(ellipseFill);
+                if (matcher.find()) {
+                    found = matcher.group(1);
+                }
+                if (gradientsFound.get(found) != null) {
+                    return true;
+                }
+            }
+            boolean inMatch = false;
+            if (!isMatched) {
+                inMatch = nodeName != null && gradMatches.contains(nodeName);
+                if (inMatch) {
+                    gradientsFound.put(curNode.getAttributes().getNamedItem("id").getNodeValue(), nodeName);
+                }
+            } else {
+                inMatch = true;
+            }
+            opacityFound = recurseSVGElements(curNode.getChildNodes(), gradMatches, inMatch);
+            if (opacityFound) {
+                return true;
+            }
+        }
+        return opacityFound;
     }
 
     /** {@inheritDoc} */

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSPainter.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSPainter.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/ps/PSPainter.java Mon Jan 13 20:39:34 2014
@@ -116,7 +116,7 @@ public class PSPainter extends AbstractI
     }
 
     /** {@inheritDoc} */
-    public void startGroup(AffineTransform transform) throws IFException {
+    public void startGroup(AffineTransform transform, String layer) throws IFException {
         try {
             PSGenerator generator = getGenerator();
             saveGraphicsState();

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/rtf/RTFHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/rtf/RTFHandler.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/rtf/RTFHandler.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/rtf/RTFHandler.java Mon Jan 13 20:39:34 2014
@@ -157,6 +157,7 @@ public class RTFHandler extends FOEventH
 
     private PercentContext percentManager = new PercentContext();
 
+
     /**
      * Creates a new RTF structure handler.
      * @param userAgent the FOUserAgent for this process
@@ -270,7 +271,7 @@ public class RTFHandler extends FOEventH
 
             return;
         } else {
-            builderContext.popContainer();
+            builderContext.popContainer(RtfSection.class, this);
             this.pagemaster = null;
         }
     }
@@ -377,10 +378,10 @@ public class RTFHandler extends FOEventH
                 //just do nothing
             } else if (regionBefore != null
                     && fl.getFlowName().equals(regionBefore.getRegionName())) {
-                builderContext.popContainer();
+                builderContext.popContainer(RtfBefore.class, this);
             } else if (regionAfter != null
                     && fl.getFlowName().equals(regionAfter.getRegionName())) {
-                builderContext.popContainer();
+                builderContext.popContainer(RtfAfter.class, this);
             }
         } catch (Exception e) {
             log.error("endFlow: " + e.getMessage());
@@ -571,7 +572,7 @@ public class RTFHandler extends FOEventH
 
         nestedTableDepth--;
         builderContext.popTableContext();
-        builderContext.popContainer();
+        builderContext.popContainer(RtfTable.class, this);
     }
 
     /** {@inheritDoc} */
@@ -605,21 +606,25 @@ public class RTFHandler extends FOEventH
 
     /** {@inheritDoc} */
     public void startHeader(TableHeader header) {
+        builderContext.pushPart(header);
         startPart(header);
     }
 
     /** {@inheritDoc} */
     public void endHeader(TableHeader header) {
+        builderContext.popPart(header.getClass(), this);
         endPart(header);
     }
 
     /** {@inheritDoc} */
     public void startFooter(TableFooter footer) {
+        builderContext.pushPart(footer);
         startPart(footer);
     }
 
     /** {@inheritDoc} */
     public void endFooter(TableFooter footer) {
+        builderContext.popPart(footer.getClass(), this);
         endPart(footer);
     }
 
@@ -711,11 +716,13 @@ public class RTFHandler extends FOEventH
      * {@inheritDoc}
      */
     public void startBody(TableBody body) {
+        builderContext.pushPart(body);
         startPart(body);
     }
 
     /** {@inheritDoc} */
     public void endBody(TableBody body) {
+        builderContext.popPart(TableBody.class, this);
         endPart(body);
     }
 
@@ -784,7 +791,7 @@ public class RTFHandler extends FOEventH
         }
 
 
-        builderContext.popContainer();
+        builderContext.popContainer(RtfTableRow.class, this);
         builderContext.getTableContext().decreaseRowSpannings();
     }
 
@@ -893,7 +900,7 @@ public class RTFHandler extends FOEventH
             throw new RuntimeException(e.getMessage());
         }
 
-        builderContext.popContainer();
+        builderContext.popContainer(RtfTableCell.class, this);
         builderContext.getTableContext().selectNextColumn();
     }
 
@@ -929,7 +936,7 @@ public class RTFHandler extends FOEventH
             return;
         }
 
-        builderContext.popContainer();
+        builderContext.popContainer(RtfList.class, this);
     }
 
     /** {@inheritDoc} */
@@ -976,7 +983,7 @@ public class RTFHandler extends FOEventH
             return;
         }
 
-        builderContext.popContainer();
+        builderContext.popContainer(RtfListItem.class, this);
     }
 
     /** {@inheritDoc} */
@@ -1005,7 +1012,7 @@ public class RTFHandler extends FOEventH
             return;
         }
 
-        builderContext.popContainer();
+        builderContext.popContainer(RtfListItemLabel.class, this);
     }
 
     /** {@inheritDoc} */
@@ -1070,7 +1077,7 @@ public class RTFHandler extends FOEventH
             return;
         }
 
-        builderContext.popContainer();
+        builderContext.popContainer(RtfHyperLink.class, this);
     }
 
     /** {@inheritDoc} */
@@ -1306,7 +1313,7 @@ public class RTFHandler extends FOEventH
             return;
         }
 
-        builderContext.popContainer();
+        builderContext.popContainer(RtfFootnote.class, this);
     }
 
     /** {@inheritDoc} */
@@ -1688,6 +1695,19 @@ public class RTFHandler extends FOEventH
     }
 
     /**
+     * Closes any mismatched tags that are detected in the RTF structure.
+     * @param containerClass The class representing the tag to close.
+     * @return Determines whether the tag mismatch has been handled.
+     */
+    public boolean endContainer(Class containerClass) {
+        if (containerClass == RtfTableRow.class) {
+            endRow(null);
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Calls the event handlers for the passed FONode and all its elements.
      *
      * @param foNode FONode object which shall be recursed

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/rtf/rtflib/tools/BuilderContext.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/rtf/rtflib/tools/BuilderContext.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/rtf/rtflib/tools/BuilderContext.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/rtf/rtflib/tools/BuilderContext.java Mon Jan 13 20:39:34 2014
@@ -21,6 +21,12 @@ package org.apache.fop.render.rtf.rtflib
 
 import java.util.Stack;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.fo.FObj;
+import org.apache.fop.render.rtf.RTFHandler;
+import org.apache.fop.render.rtf.RTFPlaceHolderHelper;
 import org.apache.fop.render.rtf.rtflib.exceptions.RtfException;
 import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfOptions;
 import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfContainer;
@@ -38,6 +44,10 @@ import org.apache.fop.render.rtf.rtflib.
  */
 
 public class BuilderContext {
+
+    /** Static logging instance */
+    protected static final Log LOG = LogFactory.getLog(BuilderContext.class.getName());
+
     /** stack of RtfContainers */
     private final Stack containers = new Stack();
 
@@ -96,17 +106,22 @@ public class BuilderContext {
      * @throws RtfException if not caught
      */
     public RtfContainer getContainer(Class containerClass, boolean required,
-                              Object /*IBuilder*/ forWhichBuilder) throws RtfException {
+            Object forWhichBuilder) throws RtfException {
         // TODO what to do if the desired container is not at the top of the stack?
         // close top-of-stack container?
-        final RtfContainer result = (RtfContainer)getObjectFromStack(containers,
+        RtfContainer result = (RtfContainer)getObjectFromStack(containers,
                 containerClass);
 
         if (result == null && required) {
-            throw new RtfException(
-                "No RtfContainer of class '" + containerClass.getName()
-                + "' available for '" + forWhichBuilder.getClass().getName() + "' builder"
-               );
+            RTFPlaceHolderHelper placeHolderHelper = new RTFPlaceHolderHelper(this);
+            placeHolderHelper.createRTFPlaceholder(containerClass);
+            result = getContainer(containerClass, required, forWhichBuilder);
+            if (result == null) {
+                throw new RtfException(
+                    "No RtfContainer of class '" + containerClass.getName()
+                    + "' available for '" + forWhichBuilder.getClass().getName() + "' builder"
+                   );
+            }
         }
 
         return result;
@@ -121,6 +136,14 @@ public class BuilderContext {
     }
 
     /**
+     * Push a Class representing a non-writeable section of the FO tree
+     * @param part the part
+     */
+    public void pushPart(FObj part) {
+        containers.push(part);
+    }
+
+    /**
      * In some cases an RtfContainer must be replaced by another one on the
      * stack. This happens when handling nested fo:blocks for example: after
      * handling a nested block the enclosing block must switch to a new
@@ -142,8 +165,40 @@ public class BuilderContext {
     }
 
     /** pop the topmost RtfContainer from our stack */
-    public void popContainer() {
-        containers.pop();
+    public void popContainer(Class containerClass, RTFHandler handler) {
+        handlePop(containerClass, handler);
+    }
+
+    /** pop the topmost part class from our stack */
+    public void popPart(Class part, RTFHandler handler) {
+        handlePop(part, handler);
+    }
+
+    /**
+     * This method checks for any tag mismatches between what is being closed
+     * and what exists on the stack. If a mismatch is found, then it will push
+     * the object back onto the stack and attempt to close the given section
+     * before retrying with the current pop task.
+     * @param aClass The class to be popped from the stack
+     * @param handler The RTF handler class to fix any mismatches
+     */
+    private void handlePop(Class aClass, RTFHandler handler) {
+        Object object = containers.pop();
+        if (object.getClass() != aClass) {
+            pushAndClose(aClass, object, handler);
+        }
+    }
+
+    private void pushAndClose(Class aClass, Object object, RTFHandler handler) {
+        containers.push(object);
+        if (handler.endContainer(object.getClass())) {
+            popContainer(aClass, handler);
+        } else {
+            /* This should never happen unless a placeholder is not catered for
+             * in the RTFHandler.endContainer method. */
+            LOG.warn("Unhandled RTF structure tag mismatch detected between "
+                     + aClass.getSimpleName() + " and " + object.getClass().getSimpleName());
+        }
     }
 
     /* push an IBuilder to our stack /

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/txt/TXTRenderer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/txt/TXTRenderer.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/txt/TXTRenderer.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/txt/TXTRenderer.java Mon Jan 13 20:39:34 2014
@@ -583,6 +583,14 @@ public class TXTRenderer extends Abstrac
     }
 
     /** {@inheritDoc} */
+    protected void startLayer(String layer) {
+    }
+
+    /** {@inheritDoc} */
+    protected void endLayer() {
+    }
+
+    /** {@inheritDoc} */
     protected void concatenateTransformationMatrix(AffineTransform at) {
         currentState.push(new CTM(UnitConv.ptToMpt(at)));
     }

Modified: xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/xml/XMLRenderer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/xml/XMLRenderer.java?rev=1557840&r1=1557839&r2=1557840&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/xml/XMLRenderer.java (original)
+++ xmlgraphics/fop/branches/Temp_InlineContainer/src/java/org/apache/fop/render/xml/XMLRenderer.java Mon Jan 13 20:39:34 2014
@@ -545,6 +545,16 @@ public class XMLRenderer extends Abstrac
         //only necessary for graphical output
     }
 
+    /** {@inheritDoc} */
+    protected void startLayer(String layer) {
+        //only necessary for graphical output
+    }
+
+    /** {@inheritDoc} */
+    protected void endLayer() {
+        //only necessary for graphical output
+    }
+
     /**
      * {@inheritDoc}
      *          org.apache.fop.area.inline.InlineArea)



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org