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];
+ }
+ }
}