FOP-2583: PDF xform to PDF content missing with font merge

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop-pdf-images/trunk@1732852 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/java/org/apache/fop/render/pdf/pdfbox/MergeFontsPDFWriter.java b/src/java/org/apache/fop/render/pdf/pdfbox/MergeFontsPDFWriter.java
index 5caaaa6..139131d 100644
--- a/src/java/org/apache/fop/render/pdf/pdfbox/MergeFontsPDFWriter.java
+++ b/src/java/org/apache/fop/render/pdf/pdfbox/MergeFontsPDFWriter.java
@@ -67,10 +67,12 @@
     private static final Pattern SUBSET_PATTERN = Pattern.compile("[A-Z][A-Z][A-Z][A-Z][A-Z][A-Z]\\+.+");
     private Collection<String> parentFonts;
 
-    public MergeFontsPDFWriter(COSDictionary fonts, FontInfo fontInfo, String key, List<COSName> resourceNames) {
-        super(key, resourceNames, 0);
+    public MergeFontsPDFWriter(COSDictionary fonts, FontInfo fontInfo, UniqueName key,
+                               Collection<String> parentFonts, int mcid) {
+        super(key, mcid);
         this.fonts = fonts;
         this.fontInfo = fontInfo;
+        this.parentFonts = parentFonts;
     }
 
     public String writeText(PDStream pdStream) throws IOException {
@@ -95,8 +97,7 @@
                     internalName = getNewFont(fontData, fontInfo, fontsToRemove.values());
                 }
                 if (fontData == null || internalName == null) {
-                    s.append("/" + cn.getName());
-                    addKey(cn);
+                    s.append("/" + key.getName(cn));
                     if (op.getOperation().equals("Tf")) {
                         font = null;
                         oldFont = null;
diff --git a/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java b/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java
index 09e0d5f..5a4f520 100644
--- a/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java
+++ b/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java
@@ -99,6 +99,7 @@
     private final Map clonedVersion;
     private Map<COSName, String> newXObj = new HashMap<COSName, String>();
     private Map<Integer, PDFArray> pageNumbers;
+    private Collection<String> parentFonts = new ArrayList<String>();
 
     private int currentMCID;
 
@@ -350,12 +351,11 @@
         }
         COSDictionary fonts = (COSDictionary)sourcePageResources.getCOSDictionary().getDictionaryObject(COSName.FONT);
         COSDictionary fontsBackup = null;
-        String uniqueName = Integer.toString(key.hashCode());
+        UniqueName uniqueName = new UniqueName(key, sourceDoc, sourcePageResources);
         String newStream = null;
         if (fonts != null && pdfDoc.isMergeFontsEnabled()) {
             fontsBackup = new COSDictionary(fonts);
-            MergeFontsPDFWriter m = new MergeFontsPDFWriter(fonts, fontinfo, uniqueName,
-                    getResourceNames(sourcePageResources.getCOSDictionary()));
+            MergeFontsPDFWriter m = new MergeFontsPDFWriter(fonts, fontinfo, uniqueName, parentFonts, currentMCID);
             newStream = m.writeText(pdStream);
 //            if (newStream != null) {
 //                for (Object f : fonts.keySet().toArray()) {
@@ -367,8 +367,7 @@
 //            }
         }
         if (newStream == null) {
-            PDFWriter writer = new PDFWriter(uniqueName, getResourceNames(sourcePageResources.getCOSDictionary()),
-                    currentMCID);
+            PDFWriter writer = new PDFWriter(uniqueName, currentMCID);
             newStream = writer.writeText(pdStream);
             currentMCID = writer.getCurrentMCID();
 
@@ -470,7 +469,8 @@
         return boxStr.toString() + pdStream.getInputStreamAsString();
     }
 
-    private void mergeXObj(COSDictionary sourcePageResources, FontInfo fontinfo, String uniqueName) throws IOException {
+    private void mergeXObj(COSDictionary sourcePageResources, FontInfo fontinfo, UniqueName uniqueName)
+        throws IOException {
         COSDictionary xobj = (COSDictionary) sourcePageResources.getDictionaryObject(COSName.XOBJECT);
         if (xobj != null && pdfDoc.isMergeFontsEnabled()) {
             for (Map.Entry<COSName, COSBase> i : xobj.entrySet()) {
@@ -486,19 +486,18 @@
                         } else {
                             for (Map.Entry<COSName, COSBase> entry : src.entrySet()) {
                                 if (!target.keySet().contains(entry.getKey())) {
-                                    target.setItem(entry.getKey(), entry.getValue());
+                                    target.setItem(uniqueName.getName(entry.getKey()), entry.getValue());
                                 }
                             }
                         }
-                        PDFWriter writer = new MergeFontsPDFWriter(src, fontinfo, uniqueName,
-                                getResourceNames(sourcePageResources));
+                        PDFWriter writer = new MergeFontsPDFWriter(src, fontinfo, uniqueName, parentFonts, 0);
                         String c = writer.writeText(PDStream.createFromCOS(stream));
                         if (c != null) {
                             stream.removeItem(COSName.FILTER);
                             newXObj.put(i.getKey(), c);
                             for (Object e : src.keySet().toArray()) {
                                 COSName name = (COSName) e;
-                                src.setItem(name.getName() + uniqueName, src.getItem(name));
+                                src.setItem(uniqueName.getName(name), src.getItem(name));
                                 src.removeItem(name);
                             }
                         }
@@ -515,7 +514,7 @@
             for (COSName entry : xobj.keySet()) {
                 if (newXObj.containsKey(entry)) {
                     PDFStream s = (PDFStream) target.get(entry.getName());
-                    s.setData(newXObj.get(entry).getBytes("UTF-8"));
+                    s.setData(newXObj.get(entry).getBytes("ISO-8859-1"));
                     PDFDictionary xobjr = (PDFDictionary) s.get("Resources");
                     xobjr.put("Font", pageResources.get("Font"));
                 }
@@ -523,25 +522,11 @@
         }
     }
 
-    private List<COSName> getResourceNames(COSDictionary sourcePageResources) {
-        List<COSName> resourceNames = new ArrayList<COSName>();
-        for (COSBase e : sourcePageResources.getValues()) {
-            if (e instanceof COSObject) {
-                e = ((COSObject) e).getObject();
-            }
-            if (e instanceof COSDictionary) {
-                COSDictionary d = (COSDictionary) e;
-                resourceNames.addAll(d.keySet());
-            }
-        }
-        return resourceNames;
-    }
-
-    private void transferPageDict(COSDictionary fonts, String uniqueName, PDResources sourcePageResources)
+    private void transferPageDict(COSDictionary fonts, UniqueName uniqueName, PDResources sourcePageResources)
         throws IOException {
         if (fonts != null) {
             for (Map.Entry<COSName, COSBase> f : fonts.entrySet()) {
-                String name = f.getKey().getName() + uniqueName;
+                String name = uniqueName.getName(f.getKey());
                 targetPage.getPDFResources().addFont(name, (PDFDictionary)cloneForNewDocument(f.getValue()));
             }
         }
@@ -550,7 +535,7 @@
         }
     }
 
-    private void transferDict(Map.Entry<COSName, COSBase> dict, String uniqueName) throws IOException {
+    private void transferDict(Map.Entry<COSName, COSBase> dict, UniqueName uniqueName) throws IOException {
         COSBase src;
         if (dict.getValue() instanceof COSObject) {
             src = ((COSObject) dict.getValue()).getObject();
@@ -565,7 +550,7 @@
             }
             COSDictionary srcDict = (COSDictionary) src;
             for (Map.Entry<COSName, COSBase> v : srcDict.entrySet()) {
-                newDict.put(v.getKey().getName() + uniqueName, cloneForNewDocument(v.getValue()));
+                newDict.put(uniqueName.getName(v.getKey()), cloneForNewDocument(v.getValue()));
             }
             targetPage.getPDFResources().put(name, newDict);
         }
diff --git a/src/java/org/apache/fop/render/pdf/pdfbox/PDFWriter.java b/src/java/org/apache/fop/render/pdf/pdfbox/PDFWriter.java
index 5622ab4..8c8c7ee 100644
--- a/src/java/org/apache/fop/render/pdf/pdfbox/PDFWriter.java
+++ b/src/java/org/apache/fop/render/pdf/pdfbox/PDFWriter.java
@@ -40,13 +40,11 @@
 
 public class PDFWriter {
     protected StringBuilder s = new StringBuilder();
-    private String key;
-    private List<COSName> resourceNames;
+    protected UniqueName key;
     private int currentMCID;
 
-    public PDFWriter(String key, List<COSName> resourceNames, int currentMCID) {
+    public PDFWriter(UniqueName key, int currentMCID) {
         this.key = key;
-        this.resourceNames = resourceNames;
         this.currentMCID = currentMCID;
     }
 
@@ -93,8 +91,7 @@
             s.append(" ");
         } else if (c instanceof COSName) {
             COSName cn = (COSName)c;
-            s.append("/" + cn.getName());
-            addKey(cn);
+            s.append("/" + key.getName(cn));
             s.append(" ");
         } else if (c instanceof COSString) {
             s.append("<" + ((COSString) c).getHexString() + ">");
@@ -138,11 +135,6 @@
         dictArgs.add(updatedID);
     }
 
-    protected void addKey(COSName cn) {
-        if (resourceNames.contains(cn)) {
-            s.append(key);
-        }
-    }
     protected int getCurrentMCID() {
         return currentMCID;
     }
diff --git a/src/java/org/apache/fop/render/pdf/pdfbox/UniqueName.java b/src/java/org/apache/fop/render/pdf/pdfbox/UniqueName.java
new file mode 100644
index 0000000..cb4e56a
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/pdfbox/UniqueName.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+package org.apache.fop.render.pdf.pdfbox;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSObject;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDResources;
+
+public class UniqueName {
+    private String key;
+    private List<COSName> resourceNames;
+
+    public UniqueName(String key, PDDocument sourceDoc, PDResources sourcePageResources) {
+        if (checkIfDocResourcesEqualPage(sourceDoc, sourcePageResources)) {
+            this.key = "";
+        } else {
+            this.key = Integer.toString(key.hashCode());
+        }
+        resourceNames = getResourceNames(sourcePageResources.getCOSDictionary());
+    }
+
+    private boolean checkIfDocResourcesEqualPage(PDDocument sourceDoc, PDResources sourcePageResources) {
+        PDResources srcDocResources = sourceDoc.getDocumentCatalog().getPages().getResources();
+        if (srcDocResources != null) {
+            COSDictionary srcDocResourcesDict = srcDocResources.getCOSDictionary();
+            return srcDocResourcesDict.equals(sourcePageResources.getCOSObject());
+        }
+        return false;
+    }
+
+    protected String getName(COSName cn) {
+        if (resourceNames.contains(cn)) {
+            return cn.getName() + key;
+        }
+        return cn.getName();
+    }
+
+    private List<COSName> getResourceNames(COSDictionary sourcePageResources) {
+        List<COSName> resourceNames = new ArrayList<COSName>();
+        for (COSBase e : sourcePageResources.getValues()) {
+            if (e instanceof COSObject) {
+                e = ((COSObject) e).getObject();
+            }
+            if (e instanceof COSDictionary) {
+                COSDictionary d = (COSDictionary) e;
+                resourceNames.addAll(d.keySet());
+            }
+        }
+        return resourceNames;
+    }
+}
diff --git a/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java b/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java
index 9860e31..0a6257a 100644
--- a/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java
+++ b/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java
@@ -30,6 +30,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
@@ -76,6 +77,7 @@
 import org.apache.fop.pdf.PDFAnnotList;
 import org.apache.fop.pdf.PDFArray;
 import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFFilterList;
 import org.apache.fop.pdf.PDFGState;
 import org.apache.fop.pdf.PDFPage;
 import org.apache.fop.pdf.PDFResources;
@@ -116,6 +118,7 @@
     private static final String LINK = "test/resources/link.pdf";
     private static final String IMAGE = "test/resources/image.pdf";
     private static final String HELLOTagged = "test/resources/taggedWorld.pdf";
+    private static final String XFORM = "test/resources/xform.pdf";
 
     private PDFBoxAdapter getPDFBoxAdapter() {
         PDFDocument doc = new PDFDocument("");
@@ -361,6 +364,27 @@
     }
 
     @Test
+    public void testXform() throws Exception {
+        PDFDocument pdfdoc = new PDFDocument("");
+        pdfdoc.getFilterMap().put(PDFFilterList.DEFAULT_FILTER, Arrays.asList("null"));
+        pdfdoc.setMergeFontsEnabled(true);
+        PDFPage pdfpage = new PDFPage(new PDFResources(pdfdoc), 0, r, r, r, r);
+        pdfpage.setDocument(pdfdoc);
+        pdfpage.setObjectNumber(1);
+        Map<Integer, PDFArray> pageNumbers = new HashMap<Integer, PDFArray>();
+        PDFBoxAdapter adapter = new PDFBoxAdapter(pdfpage, new HashMap(), pageNumbers);
+        PDDocument doc = PDDocument.load(XFORM);
+        PDPage page = (PDPage) doc.getDocumentCatalog().getAllPages().get(0);
+        AffineTransform at = new AffineTransform();
+        Rectangle r = new Rectangle(0, 1650, 842000, 595000);
+        adapter.createStreamFromPDFBoxPage(doc, page, "key", at, new FontInfo(), r);
+        doc.close();
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        pdfdoc.output(bos);
+        Assert.assertFalse(bos.toString("UTF-8").contains("/W 5 /H 5 /BPC 8 /CS /RGB ID ÿÿÿ"));
+    }
+
+    @Test
     public void testPreloaderPDF() throws Exception {
         ImageSource imageSource = new ImageSource(ImageIO.createImageInputStream(new File(ROTATE)), "", true);
         ImageInfo imageInfo = new PreloaderPDF().preloadImage("", imageSource, new DefaultImageContext());
diff --git a/test/resources/xform.pdf b/test/resources/xform.pdf
new file mode 100644
index 0000000..2a3134f
--- /dev/null
+++ b/test/resources/xform.pdf
Binary files differ