You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2015/09/03 08:29:35 UTC

svn commit: r1700937 - in /pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf: GlyfSimpleDescript.java GlyphData.java GlyphTable.java HorizontalMetricsTable.java

Author: tilman
Date: Thu Sep  3 06:29:35 2015
New Revision: 1700937

URL: http://svn.apache.org/r1700937
Log:
PDFBOX-2946: use left side bearing when rendering TT fonts

Modified:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphData.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphTable.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java?rev=1700937&r1=1700936&r2=1700937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java Thu Sep  3 06:29:35 2015
@@ -1,215 +1,216 @@
-/*
-
-   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.
-
- */
-package org.apache.fontbox.ttf;
-
-import java.io.IOException;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * This class is based on code from Apache Batik a subproject of Apache XMLGraphics. see
- * http://xmlgraphics.apache.org/batik/ for further details.
- */
-public class GlyfSimpleDescript extends GlyfDescript
-{
-
-    /**
-     * Log instance.
-     */
-    private static final Log LOG = LogFactory.getLog(GlyfSimpleDescript.class);
-
-    private int[] endPtsOfContours;
-    private byte[] flags;
-    private short[] xCoordinates;
-    private short[] yCoordinates;
-    private final int pointCount;
-
-    /**
-     * Constructor.
-     * 
-     * @param numberOfContours number of contours
-     * @param bais the stream to be read
-     * @throws IOException is thrown if something went wrong
-     */
-    public GlyfSimpleDescript(short numberOfContours, TTFDataStream bais) throws IOException
-    {
-        super(numberOfContours, bais);
-
-        /*
-         * https://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html
-         * "If a glyph has zero contours, it need not have any glyph data." set the pointCount to zero to initialize
-         * attributes and avoid nullpointer but maybe there shouldn't have GlyphDescript in the GlyphData?
-         */
-        if (numberOfContours == 0)
-        {
-            pointCount = 0;
-            return;
-        }
-
-        // Simple glyph description
-        endPtsOfContours = bais.readUnsignedShortArray(numberOfContours);
-
-        int lastEndPt = endPtsOfContours[numberOfContours - 1];
-        if (numberOfContours == 1 && lastEndPt == 65535)
-        {
-            // PDFBOX-2939: assume an empty glyph
-            pointCount = 0;
-            return;
-        }
-        // The last end point index reveals the total number of points
-        pointCount = lastEndPt + 1;
-
-        flags = new byte[pointCount];
-        xCoordinates = new short[pointCount];
-        yCoordinates = new short[pointCount];
-
-        int instructionCount = bais.readUnsignedShort();
-        readInstructions(bais, instructionCount);
-        readFlags(pointCount, bais);
-        readCoords(pointCount, bais);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int getEndPtOfContours(int i)
-    {
-        return endPtsOfContours[i];
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public byte getFlags(int i)
-    {
-        return flags[i];
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public short getXCoordinate(int i)
-    {
-        return xCoordinates[i];
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public short getYCoordinate(int i)
-    {
-        return yCoordinates[i];
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isComposite()
-    {
-        return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int getPointCount()
-    {
-        return pointCount;
-    }
-
-    /**
-     * The table is stored as relative values, but we'll store them as absolutes.
-     */
-    private void readCoords(int count, TTFDataStream bais) throws IOException
-    {
-        short x = 0;
-        short y = 0;
-        for (int i = 0; i < count; i++)
-        {
-            if ((flags[i] & X_DUAL) != 0)
-            {
-                if ((flags[i] & X_SHORT_VECTOR) != 0)
-                {
-                    x += (short) bais.readUnsignedByte();
-                }
-            }
-            else
-            {
-                if ((flags[i] & X_SHORT_VECTOR) != 0)
-                {
-                    x += (short) -((short) bais.readUnsignedByte());
-                }
-                else
-                {
-                    x += bais.readSignedShort();
-                }
-            }
-            xCoordinates[i] = x;
-        }
-
-        for (int i = 0; i < count; i++)
-        {
-            if ((flags[i] & Y_DUAL) != 0)
-            {
-                if ((flags[i] & Y_SHORT_VECTOR) != 0)
-                {
-                    y += (short) bais.readUnsignedByte();
-                }
-            }
-            else
-            {
-                if ((flags[i] & Y_SHORT_VECTOR) != 0)
-                {
-                    y += (short) -((short) bais.readUnsignedByte());
-                }
-                else
-                {
-                    y += bais.readSignedShort();
-                }
-            }
-            yCoordinates[i] = y;
-        }
-    }
-
-    /**
-     * The flags are run-length encoded.
-     */
-    private void readFlags(int flagCount, TTFDataStream bais) throws IOException
-    {
-        for (int index = 0; index < flagCount; index++)
-        {
-            flags[index] = (byte) bais.readUnsignedByte();
-            if ((flags[index] & REPEAT) != 0)
-            {
-                int repeats = bais.readUnsignedByte();
-                for (int i = 1; i <= repeats; i++)
-                {
-                    flags[index + i] = flags[index];
-                }
-                index += repeats;
-            }
-        }
-    }
-}
+/*
+
+   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.
+
+ */
+package org.apache.fontbox.ttf;
+
+import java.io.IOException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class is based on code from Apache Batik a subproject of Apache XMLGraphics. see
+ * http://xmlgraphics.apache.org/batik/ for further details.
+ */
+public class GlyfSimpleDescript extends GlyfDescript
+{
+
+    /**
+     * Log instance.
+     */
+    private static final Log LOG = LogFactory.getLog(GlyfSimpleDescript.class);
+
+    private int[] endPtsOfContours;
+    private byte[] flags;
+    private short[] xCoordinates;
+    private short[] yCoordinates;
+    private final int pointCount;
+
+    /**
+     * Constructor.
+     * 
+     * @param numberOfContours number of contours
+     * @param bais the stream to be read
+     * @param x0 the initial X-position
+     * @throws IOException is thrown if something went wrong
+     */
+    public GlyfSimpleDescript(short numberOfContours, TTFDataStream bais, short x0) throws IOException
+    {
+        super(numberOfContours, bais);
+
+        /*
+         * https://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html
+         * "If a glyph has zero contours, it need not have any glyph data." set the pointCount to zero to initialize
+         * attributes and avoid nullpointer but maybe there shouldn't have GlyphDescript in the GlyphData?
+         */
+        if (numberOfContours == 0)
+        {
+            pointCount = 0;
+            return;
+        }
+
+        // Simple glyph description
+        endPtsOfContours = bais.readUnsignedShortArray(numberOfContours);
+
+        int lastEndPt = endPtsOfContours[numberOfContours - 1];
+        if (numberOfContours == 1 && lastEndPt == 65535)
+        {
+            // PDFBOX-2939: assume an empty glyph
+            pointCount = 0;
+            return;
+        }
+        // The last end point index reveals the total number of points
+        pointCount = lastEndPt + 1;
+
+        flags = new byte[pointCount];
+        xCoordinates = new short[pointCount];
+        yCoordinates = new short[pointCount];
+
+        int instructionCount = bais.readUnsignedShort();
+        readInstructions(bais, instructionCount);
+        readFlags(pointCount, bais);
+        readCoords(pointCount, bais, x0);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getEndPtOfContours(int i)
+    {
+        return endPtsOfContours[i];
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte getFlags(int i)
+    {
+        return flags[i];
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public short getXCoordinate(int i)
+    {
+        return xCoordinates[i];
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public short getYCoordinate(int i)
+    {
+        return yCoordinates[i];
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isComposite()
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getPointCount()
+    {
+        return pointCount;
+    }
+
+    /**
+     * The table is stored as relative values, but we'll store them as absolutes.
+     */
+    private void readCoords(int count, TTFDataStream bais, short x0) throws IOException
+    {
+        short x = x0;
+        short y = 0;
+        for (int i = 0; i < count; i++)
+        {
+            if ((flags[i] & X_DUAL) != 0)
+            {
+                if ((flags[i] & X_SHORT_VECTOR) != 0)
+                {
+                    x += (short) bais.readUnsignedByte();
+                }
+            }
+            else
+            {
+                if ((flags[i] & X_SHORT_VECTOR) != 0)
+                {
+                    x += (short) -((short) bais.readUnsignedByte());
+                }
+                else
+                {
+                    x += bais.readSignedShort();
+                }
+            }
+            xCoordinates[i] = x;
+        }
+
+        for (int i = 0; i < count; i++)
+        {
+            if ((flags[i] & Y_DUAL) != 0)
+            {
+                if ((flags[i] & Y_SHORT_VECTOR) != 0)
+                {
+                    y += (short) bais.readUnsignedByte();
+                }
+            }
+            else
+            {
+                if ((flags[i] & Y_SHORT_VECTOR) != 0)
+                {
+                    y += (short) -((short) bais.readUnsignedByte());
+                }
+                else
+                {
+                    y += bais.readSignedShort();
+                }
+            }
+            yCoordinates[i] = y;
+        }
+    }
+
+    /**
+     * The flags are run-length encoded.
+     */
+    private void readFlags(int flagCount, TTFDataStream bais) throws IOException
+    {
+        for (int index = 0; index < flagCount; index++)
+        {
+            flags[index] = (byte) bais.readUnsignedByte();
+            if ((flags[index] & REPEAT) != 0)
+            {
+                int repeats = bais.readUnsignedByte();
+                for (int i = 1; i <= repeats; i++)
+                {
+                    flags[index + i] = flags[index];
+                }
+                index += repeats;
+            }
+        }
+    }
+}

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphData.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphData.java?rev=1700937&r1=1700936&r2=1700937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphData.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphData.java Thu Sep  3 06:29:35 2015
@@ -41,9 +41,10 @@ public class GlyphData
      * 
      * @param glyphTable The glyph table this glyph belongs to.
      * @param data The stream to read the data from.
+     * @param leftSideBearing The left side bearing for this glyph.
      * @throws IOException If there is an error reading the data.
      */
-    public void initData( GlyphTable glyphTable, TTFDataStream data ) throws IOException
+    public void initData( GlyphTable glyphTable, TTFDataStream data, int leftSideBearing ) throws IOException
     {
         numberOfContours = data.readSignedShort();
         xMin = data.readSignedShort();
@@ -55,7 +56,8 @@ public class GlyphData
         if (numberOfContours >= 0) 
         {
             // create a simple glyph
-            glyphDescription = new GlyfSimpleDescript(numberOfContours, data);
+            short x0 = (short) (leftSideBearing - xMin);
+            glyphDescription = new GlyfSimpleDescript(numberOfContours, data, x0);
         }
         else 
         {

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphTable.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphTable.java?rev=1700937&r1=1700936&r2=1700937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphTable.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphTable.java Thu Sep  3 06:29:35 2015
@@ -90,7 +90,11 @@ public class GlyphTable extends TTFTable
             }
             glyphs[i] = new GlyphData();
             data.seek(offset + offsets[i]);
-            glyphs[i].initData(this, data);
+            
+            HorizontalMetricsTable hmt = font.getHorizontalMetrics();
+            int leftSideBearing = hmt == null ? 0 : hmt.getLeftSideBearing(i);
+            
+            glyphs[i].initData(this, data, leftSideBearing);
         }
         for (int i = 0; i < numGlyphs; i++)
         {
@@ -158,7 +162,11 @@ public class GlyphTable extends TTFTable
             {
                 data.seek(getOffset() + offsets[gid]);
                 glyph = new GlyphData();
-                glyph.initData(this, data);
+                
+                HorizontalMetricsTable hmt = font.getHorizontalMetrics();
+                int leftSideBearing = hmt == null ? 0 : hmt.getLeftSideBearing(gid);
+
+                glyph.initData(this, data, leftSideBearing);
 
                 // resolve composite glyph
                 if (glyph.getDescription().isComposite())

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java?rev=1700937&r1=1700936&r2=1700937&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java Thu Sep  3 06:29:35 2015
@@ -105,4 +105,21 @@ public class HorizontalMetricsTable exte
             return advanceWidth[advanceWidth.length -1];
         }
     }
+    
+    /**
+     * Returns the left side bearing for the given GID.
+     *
+     * @param gid GID
+     */
+    public int getLeftSideBearing(int gid)
+    {
+        if (gid < numHMetrics)
+        {
+            return leftSideBearing[gid];
+        }
+        else
+        {
+            return nonHorizontalLeftSideBearing[gid - numHMetrics];
+        }
+   }
 }