FOP-3049: Align AFP SVG text in the middle

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1897561 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fop-core/src/main/java/org/apache/fop/image/loader/batik/BatikUtil.java b/fop-core/src/main/java/org/apache/fop/image/loader/batik/BatikUtil.java
index cda57b5..7162df9 100644
--- a/fop-core/src/main/java/org/apache/fop/image/loader/batik/BatikUtil.java
+++ b/fop-core/src/main/java/org/apache/fop/image/loader/batik/BatikUtil.java
@@ -19,8 +19,10 @@
 
 package org.apache.fop.image.loader.batik;
 
+import org.w3c.dom.DOMImplementation;
 import org.w3c.dom.Document;
 
+import org.apache.batik.anim.dom.SVGDOMImplementation;
 import org.apache.batik.dom.AbstractDocument;
 import org.apache.batik.dom.util.DOMUtilities;
 
@@ -53,9 +55,13 @@
      * @return the cloned SVG DOM
      */
     public static Document cloneSVGDocument(Document doc) {
-        Document clonedDoc = DOMUtilities.deepCloneDocument(doc, doc.getImplementation());
+        DOMImplementation impl = doc.getImplementation();
+        if (!(impl instanceof SVGDOMImplementation)) {
+            impl = new SVGDOMImplementation();
+        }
+        Document clonedDoc = DOMUtilities.deepCloneDocument(doc, impl);
         if (clonedDoc instanceof AbstractDocument) {
-            ((AbstractDocument)clonedDoc).setDocumentURI(((AbstractDocument)doc).getDocumentURI());
+            clonedDoc.setDocumentURI(doc.getDocumentURI());
         }
         return clonedDoc;
     }
diff --git a/fop-core/src/main/java/org/apache/fop/svg/AbstractFOPTextPainter.java b/fop-core/src/main/java/org/apache/fop/svg/AbstractFOPTextPainter.java
index df24dbb..3084312 100644
--- a/fop-core/src/main/java/org/apache/fop/svg/AbstractFOPTextPainter.java
+++ b/fop-core/src/main/java/org/apache/fop/svg/AbstractFOPTextPainter.java
@@ -36,6 +36,7 @@
 import org.apache.batik.bridge.StrokingTextPainter;
 import org.apache.batik.bridge.TextNode;
 import org.apache.batik.bridge.TextPainter;
+import org.apache.batik.gvt.font.GVTGlyphVector;
 import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
 import org.apache.batik.gvt.text.TextPaintInfo;
 
@@ -157,7 +158,14 @@
                     if (font != null) {
                         fontSize = (int) Math.round(afpg2d.convertToAbsoluteLength(font.getFontSize()));
                     }
-                    if (fontSize < 6000) {
+                    if (anchor != null && TextNode.Anchor.ANCHOR_MIDDLE == anchor.getType()) {
+                        GVTGlyphVector gv = run.getLayout().getGlyphVector();
+                        Point2D glyphPos = gv.getGlyphPosition(0);
+                        double advanceChar = afpg2d.convertToAbsoluteLength(advance / txt.length());
+                        nativeTextHandler.drawString(g2d, txt,
+                                (float) (currentLocation.getX() - advanceChar - glyphPos.getX()),
+                                (float) (currentLocation.getY() + glyphPos.getY()));
+                    } else if (fontSize < 6000) {
                         nativeTextHandler.drawString(g2d, txt, (float) (x + tx), (float) y);
                     } else {
                         double scaleX = g2d.getTransform().getScaleX();
diff --git a/fop-core/src/test/java/org/apache/fop/render/afp/AFPTrueTypeTestCase.java b/fop-core/src/test/java/org/apache/fop/render/afp/AFPTrueTypeTestCase.java
index 9a9e5be..f875d80 100644
--- a/fop-core/src/test/java/org/apache/fop/render/afp/AFPTrueTypeTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/render/afp/AFPTrueTypeTestCase.java
@@ -21,17 +21,16 @@
 import java.awt.Color;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URI;
-import java.net.URISyntaxException;
 
 import javax.xml.transform.Result;
 import javax.xml.transform.Source;
 import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.sax.SAXResult;
 import javax.xml.transform.stream.StreamSource;
@@ -39,8 +38,6 @@
 import org.junit.Assert;
 import org.junit.Test;
 
-import org.xml.sax.SAXException;
-
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -53,6 +50,8 @@
 import org.apache.fop.afp.Factory;
 import org.apache.fop.afp.fonts.FopCharacterSet;
 import org.apache.fop.afp.modca.PageObject;
+import org.apache.fop.afp.parser.MODCAParser;
+import org.apache.fop.afp.parser.UnparsedStructuredField;
 import org.apache.fop.apps.EnvironmentalProfileFactory;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.apps.Fop;
@@ -66,8 +65,6 @@
 import org.apache.fop.fonts.MultiByteFont;
 import org.apache.fop.render.intermediate.IFException;
 
-
-
 public class AFPTrueTypeTestCase {
     private String font;
     private String fopxconf = "<fop version=\"1.0\">\n"
@@ -90,7 +87,7 @@
             + "</fop>";
 
     @Test
-    public void testAFPTrueType() throws IOException, SAXException, TransformerException, URISyntaxException {
+    public void testAFPTrueType() throws Exception {
         String fo = "<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">\n"
                 + "  <fo:layout-master-set>\n"
                 + "    <fo:simple-page-master master-name=\"simple\">\n"
@@ -189,7 +186,7 @@
     }
 
     @Test
-    public void testSVGAFPTrueType() throws IOException, SAXException, TransformerException, URISyntaxException {
+    public void testSVGAFPTrueType() throws Exception {
         String fo = "<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\" "
                 + "xmlns:fox=\"http://xmlgraphics.apache.org/fop/extensions\" "
                 + "xmlns:svg=\"http://www.w3.org/2000/svg\">\n"
@@ -228,7 +225,55 @@
         Assert.assertTrue(getAFP(fo).contains("DATA GRAPHICS"));
     }
 
-    private String getAFP(String fo) throws IOException, TransformerException, SAXException, URISyntaxException {
+    @Test
+    public void testSVGAnchorAFP() throws Exception {
+        String fo = "<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\" "
+                + "xmlns:svg=\"http://www.w3.org/2000/svg\">\n"
+                + "  <fo:layout-master-set>\n"
+                + "    <fo:simple-page-master master-name=\"simple\" page-height=\"27.9cm\" page-width=\"21.6cm\">\n"
+                + "      <fo:region-body />\n"
+                + "    </fo:simple-page-master>\n"
+                + "  </fo:layout-master-set>\n"
+                + "  <fo:page-sequence master-reference=\"simple\">\n"
+                + "    <fo:flow flow-name=\"xsl-region-body\">   \n"
+                + "      <fo:block font-size=\"0\">\n"
+                + "        <fo:instream-foreign-object content-height=\"792pt\" content-width=\"612pt\">\n"
+                + "<svg:svg xmlns=\"http://www.w3.org/2000/svg\" height=\"3mm\" viewBox=\"0 0 49.94 3\" "
+                + "width=\"49.94mm\">\n"
+                + "  <svg:g fill=\"black\" stroke=\"none\">\n"
+                + "    <svg:text font-family=\"ExpertSans\" font-size=\"2.8219\" text-anchor=\"middle\" x=\"24.97\" "
+                + "y=\"2.6228\">0000210122010000000100010004</svg:text>\n"
+                + "  </svg:g>\n"
+                + "</svg:svg>\n"
+                + "        </fo:instream-foreign-object>\n"
+                + "      </fo:block>\n"
+                + "    </fo:flow>\n"
+                + "  </fo:page-sequence>\n"
+                + "</fo:root>";
+        ByteArrayOutputStream bos = getAFPBytes(fo);
+        MODCAParser parser = new MODCAParser(new ByteArrayInputStream(bos.toByteArray()));
+        UnparsedStructuredField structuredField;
+        while ((structuredField = parser.readNextStructuredField()) != null) {
+            if (structuredField.toString().contains("Data Graphics")) {
+                break;
+            }
+        }
+        DataInputStream bis = new DataInputStream(new ByteArrayInputStream(structuredField.getData()));
+        bis.skip(34);
+        //X Y coordinates:
+        Assert.assertEquals(bis.readShort(), 3);
+        Assert.assertEquals(bis.readShort(), 5);
+    }
+
+    private String getAFP(String fo) throws Exception {
+        ByteArrayOutputStream bos = getAFPBytes(fo);
+        StringBuilder sb = new StringBuilder();
+        InputStream bis = new ByteArrayInputStream(bos.toByteArray());
+        new AFPParser(false).read(bis, sb);
+        return sb.toString();
+    }
+
+    private ByteArrayOutputStream getAFPBytes(String fo) throws Exception {
         FopFactoryBuilder confBuilder = new FopConfParser(
                 new ByteArrayInputStream(fopxconf.getBytes()),
                 EnvironmentalProfileFactory.createRestrictedIO(new URI("."),
@@ -243,11 +288,7 @@
         Result res = new SAXResult(fop.getDefaultHandler());
         transformer.transform(src, res);
         bos.close();
-
-        StringBuilder sb = new StringBuilder();
-        InputStream bis = new ByteArrayInputStream(bos.toByteArray());
-        new AFPParser(false).read(bis, sb);
-        return sb.toString();
+        return bos;
     }
 
     class MyResourceResolver implements ResourceResolver {