FOP-2753: PDF to PS allow fop fonts as fallback

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop-pdf-images/trunk@1812123 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/xmlgraphics-commons-svn-trunk.jar b/lib/xmlgraphics-commons-svn-trunk.jar
index fe78fa4..0e5af7b 100644
--- a/lib/xmlgraphics-commons-svn-trunk.jar
+++ b/lib/xmlgraphics-commons-svn-trunk.jar
Binary files differ
diff --git a/src/java/org/apache/fop/render/pdf/pdfbox/ImageConverterPDF2G2D.java b/src/java/org/apache/fop/render/pdf/pdfbox/ImageConverterPDF2G2D.java
index c7d9a47..e46a176 100644
--- a/src/java/org/apache/fop/render/pdf/pdfbox/ImageConverterPDF2G2D.java
+++ b/src/java/org/apache/fop/render/pdf/pdfbox/ImageConverterPDF2G2D.java
@@ -26,17 +26,27 @@
 import java.awt.image.BufferedImage;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.FontBoxFont;
+import org.apache.fontbox.ttf.TTFParser;
+import org.apache.fontbox.ttf.TrueTypeFont;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDResources;
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.font.CIDFontMapping;
+import org.apache.pdfbox.pdmodel.font.FontMapper;
+import org.apache.pdfbox.pdmodel.font.FontMappers;
+import org.apache.pdfbox.pdmodel.font.FontMapping;
+import org.apache.pdfbox.pdmodel.font.PDCIDSystemInfo;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
 import org.apache.pdfbox.pdmodel.graphics.PDXObject;
 import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
 import org.apache.pdfbox.pdmodel.graphics.shading.PDShading;
@@ -53,6 +63,12 @@
 import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
 import org.apache.xmlgraphics.ps.PSGenerator;
 
+import org.apache.fop.fonts.CustomFont;
+import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.Typeface;
+import org.apache.fop.render.java2d.CustomFontMetricsMapper;
+
 /**
  * Image converter implementation to convert PDF pages into Java2D images.
  */
@@ -110,6 +126,7 @@
         private final PDDocument pdDocument;
         private float dpi;
         private int selectedPage;
+        private FopFontProvider fopFontProvider = new FopFontProvider();
         private String uri;
 
         public Graphics2DImagePainterPDF(PDDocument pddoc, float dpi, int selectedPage, String uri) {
@@ -212,6 +229,84 @@
             PSPDFGraphics2D graphics = new PSPDFGraphics2D(textAsShapes, gen);
             return graphics;
         }
+
+        public void addFallbackFont(String s, Object font) {
+            fopFontProvider.fonts.put(s, font);
+        }
+    }
+
+    static class FopFontProvider {
+        private static FopFontMapper fopFontMapper = new FopFontMapper();
+        static {
+            FontMappers.set(fopFontMapper);
+        }
+        private Map<String, Object> fonts = new HashMap<String, Object>();
+        private Map<String, TrueTypeFont> ttFonts = new HashMap<String, TrueTypeFont>();
+
+        FopFontProvider() {
+            fopFontMapper.fopFontProvider.set(this);
+        }
+
+        private CustomFont getFont(String name) throws IOException {
+            Object typeface = fonts.get(name);
+            if (typeface instanceof LazyFont) {
+                Typeface rf = ((LazyFont) typeface).getRealFont();
+                return (CustomFont) rf;
+            } else if (typeface instanceof CustomFontMetricsMapper) {
+                Typeface rf = ((CustomFontMetricsMapper) typeface).getRealFont();
+                return (CustomFont) rf;
+            }
+            return null;
+        }
+
+        public TrueTypeFont getTrueTypeFont(String postScriptName) {
+            if (!ttFonts.containsKey(postScriptName)) {
+                try {
+                    CustomFont font = getFont(postScriptName);
+                    if (font instanceof MultiByteFont && !((MultiByteFont)font).isOTFFile()) {
+                        TTFParser ttfParser = new TTFParser(false, true);
+                        TrueTypeFont ttf = ttfParser.parse(font.getInputStream());
+                        ttFonts.put(postScriptName, ttf);
+                    }
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            return ttFonts.get(postScriptName);
+        }
+    }
+
+
+    static class FopFontMapper implements FontMapper {
+        private FontMapper defaultFontMapper;
+        private ThreadLocal<FopFontProvider> fopFontProvider = new ThreadLocal<FopFontProvider>();
+
+        FopFontMapper() {
+            defaultFontMapper = FontMappers.instance();
+        }
+
+        public FontMapping<TrueTypeFont> getTrueTypeFont(String baseFont, PDFontDescriptor fontDescriptor) {
+            TrueTypeFont fopFont = fopFontProvider.get().getTrueTypeFont(baseFont);
+            if (fopFont != null) {
+                return new FontMapping<TrueTypeFont>(fopFont, true);
+            }
+            return defaultFontMapper.getTrueTypeFont(baseFont, fontDescriptor);
+        }
+
+
+        public FontMapping<FontBoxFont> getFontBoxFont(String baseFont, PDFontDescriptor fontDescriptor) {
+            TrueTypeFont fopFont = fopFontProvider.get().getTrueTypeFont(baseFont);
+            if (fopFont != null) {
+                return new FontMapping<FontBoxFont>(fopFont, true);
+            }
+            return defaultFontMapper.getFontBoxFont(baseFont, fontDescriptor);
+        }
+
+
+        public CIDFontMapping getCIDFont(String baseFont, PDFontDescriptor fontDescriptor,
+                                         PDCIDSystemInfo cidSystemInfo) {
+            return defaultFontMapper.getCIDFont(baseFont, fontDescriptor, cidSystemInfo);
+        }
     }
 
 }
diff --git a/test/java/org/apache/fop/render/pdf/ImageConverterPDF2G2DTestCase.java b/test/java/org/apache/fop/render/pdf/ImageConverterPDF2G2DTestCase.java
new file mode 100644
index 0000000..39c1d53
--- /dev/null
+++ b/test/java/org/apache/fop/render/pdf/ImageConverterPDF2G2DTestCase.java
@@ -0,0 +1,96 @@
+/*
+ * 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: ImageConverterPDF2G2D.java 1808727 2017-09-18 15:02:56Z ssteiner $ */
+package org.apache.fop.render.pdf;
+
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.pdfbox.pdmodel.PDDocument;
+
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.java2d.GeneralGraphics2DImagePainter;
+import org.apache.xmlgraphics.java2d.GraphicContext;
+
+import org.apache.fop.fonts.EmbedFontInfo;
+import org.apache.fop.fonts.EmbeddingMode;
+import org.apache.fop.fonts.FontUris;
+import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.Typeface;
+import org.apache.fop.render.pdf.pdfbox.ImageConverterPDF2G2D;
+import org.apache.fop.render.pdf.pdfbox.ImagePDF;
+import org.apache.fop.render.pdf.pdfbox.PSPDFGraphics2D;
+
+public class ImageConverterPDF2G2DTestCase {
+    private static final String FONTSNOTEMBEDDED = "test/resources/fontsnotembedded.pdf";
+
+    @Test
+    public void testFontsNotEmbedded() throws IOException, ImageException {
+        Assert.assertTrue(pdfToPS(FONTSNOTEMBEDDED, "Helvetica-Bold"));
+        Assert.assertFalse(pdfToPS(FONTSNOTEMBEDDED, "xyz"));
+    }
+
+    private boolean pdfToPS(String pdf, String font) throws IOException, ImageException {
+        ImageConverterPDF2G2D i = new ImageConverterPDF2G2D();
+        ImageInfo imgi = new ImageInfo(pdf, "b");
+        PDDocument doc = PDDocument.load(new File(pdf));
+        org.apache.xmlgraphics.image.loader.Image img = new ImagePDF(imgi, doc);
+        ImageGraphics2D ig = (ImageGraphics2D)i.convert(img, null);
+        GeneralGraphics2DImagePainter g = (GeneralGraphics2DImagePainter) ig.getGraphics2DImagePainter();
+        MyLazyFont lazyFont = new MyLazyFont();
+        g.addFallbackFont(font, lazyFont);
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        PSPDFGraphics2D g2d = (PSPDFGraphics2D)
+                g.getGraphics(true, new PDFBoxAdapterTestCase.FOPPSGeneratorImpl(stream));
+        Rectangle2D rect = new Rectangle2D.Float(0, 0, 100, 100);
+        GraphicContext gc = new GraphicContext();
+        g2d.setGraphicContext(gc);
+        ig.getGraphics2DImagePainter().paint(g2d, rect);
+        doc.close();
+        return lazyFont.font.fontUsed;
+    }
+
+    static class MyLazyFont extends LazyFont {
+        Font font = new Font();
+        MyLazyFont() {
+            super(new EmbedFontInfo(new FontUris(null, null), false, false, null, ""), null, false);
+        }
+        public Typeface getRealFont() {
+            return font;
+        }
+    }
+
+    static class Font extends MultiByteFont {
+        boolean fontUsed;
+        public Font() {
+            super(null, EmbeddingMode.AUTO);
+        }
+        public boolean isOTFFile() {
+            fontUsed = true;
+            return true;
+        }
+    }
+}
diff --git a/test/resources/fontsnotembedded.pdf b/test/resources/fontsnotembedded.pdf
new file mode 100644
index 0000000..082fb77
--- /dev/null
+++ b/test/resources/fontsnotembedded.pdf
Binary files differ