Merge pull request #970 from mashabow/cff-bounds-recalc
CFF bounds recalculation
This commit is contained in:
commit
b5da19dc4b
@ -4,6 +4,7 @@ from __future__ import print_function, division, absolute_import
|
||||
from fontTools.misc.py23 import *
|
||||
from fontTools.misc import sstruct
|
||||
from fontTools.misc import psCharStrings
|
||||
from fontTools.misc.arrayTools import unionRect, intRect
|
||||
from fontTools.misc.textTools import safeEval
|
||||
from fontTools.ttLib import TTFont
|
||||
from fontTools.ttLib.tables.otBase import OTTableWriter
|
||||
@ -101,6 +102,11 @@ class CFFFontSet(object):
|
||||
# use current 'major' value to determine output format
|
||||
assert self.major in (1, 2), "Unknown CFF format"
|
||||
isCFF2 = self.major == 2
|
||||
|
||||
if otFont.recalcBBoxes and not isCFF2:
|
||||
for topDict in self.topDictIndex:
|
||||
topDict.recalcFontBBox()
|
||||
|
||||
if not isCFF2:
|
||||
strings = IndexedStrings()
|
||||
else:
|
||||
@ -2313,6 +2319,21 @@ class TopDict(BaseDict):
|
||||
progress.increment(0) # update
|
||||
i = i + 1
|
||||
|
||||
def recalcFontBBox(self):
|
||||
fontBBox = None
|
||||
for charString in self.CharStrings.values():
|
||||
bounds = charString.calcBounds()
|
||||
if bounds is not None:
|
||||
if fontBBox is not None:
|
||||
fontBBox = unionRect(fontBBox, bounds)
|
||||
else:
|
||||
fontBBox = bounds
|
||||
|
||||
if fontBBox is None:
|
||||
self.FontBBox = self.defaults['FontBBox'][:]
|
||||
else:
|
||||
self.FontBBox = list(intRect(fontBBox))
|
||||
|
||||
|
||||
class FontDict(BaseDict):
|
||||
#
|
||||
|
@ -5,6 +5,7 @@ CFF dictionary data and Type1/Type2 CharStrings.
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from fontTools.misc.py23 import *
|
||||
from fontTools.misc.fixedTools import fixedToFloat
|
||||
from fontTools.pens.boundsPen import BoundsPen
|
||||
import struct
|
||||
import logging
|
||||
|
||||
@ -977,6 +978,11 @@ class T2CharString(object):
|
||||
extractor.execute(self)
|
||||
self.width = extractor.width
|
||||
|
||||
def calcBounds(self):
|
||||
boundsPen = BoundsPen(None)
|
||||
self.draw(boundsPen)
|
||||
return boundsPen.bounds
|
||||
|
||||
def check_program(self, program, isCFF2=False):
|
||||
if isCFF2:
|
||||
if self.program:
|
||||
|
@ -90,9 +90,11 @@ class TTFont(object):
|
||||
|
||||
If the recalcBBoxes argument is false, a number of things will *not*
|
||||
be recalculated upon save/compile:
|
||||
1) glyph bounding boxes
|
||||
2) maxp font bounding box
|
||||
3) hhea min/max values
|
||||
1) 'glyf' glyph bounding boxes
|
||||
2) 'CFF ' font bounding box
|
||||
3) 'head' font bounding box
|
||||
4) 'hhea' min/max values
|
||||
5) 'vhea' min/max values
|
||||
(1) is needed for certain kinds of CJK fonts (ask Werner Lemberg ;-).
|
||||
Additionally, upon importing an TTX file, this option cause glyphs
|
||||
to be compiled right away. This should reduce memory consumption
|
||||
|
@ -33,7 +33,7 @@ headFormat = """
|
||||
|
||||
class table__h_e_a_d(DefaultTable.DefaultTable):
|
||||
|
||||
dependencies = ['maxp', 'loca']
|
||||
dependencies = ['maxp', 'loca', 'CFF ']
|
||||
|
||||
def decompile(self, data, ttFont):
|
||||
dummy, rest = sstruct.unpack2(headFormat, data, self)
|
||||
@ -59,6 +59,11 @@ class table__h_e_a_d(DefaultTable.DefaultTable):
|
||||
setattr(self, stamp, value)
|
||||
|
||||
def compile(self, ttFont):
|
||||
if ttFont.recalcBBoxes:
|
||||
# For TT-flavored fonts, xMin, yMin, xMax and yMax are set in table__m_a_x_p.recalc().
|
||||
if 'CFF ' in ttFont:
|
||||
topDict = ttFont['CFF '].cff.topDictIndex[0]
|
||||
self.xMin, self.yMin, self.xMax, self.yMax = topDict.FontBBox
|
||||
if ttFont.recalcTimestamp:
|
||||
self.modified = timestampNow()
|
||||
data = sstruct.pack(headFormat, self)
|
||||
|
@ -5,6 +5,8 @@ from fontTools.misc.textTools import safeEval
|
||||
from fontTools.misc.fixedTools import (
|
||||
ensureVersionIsLong as fi2ve, versionToFixed as ve2fi)
|
||||
from . import DefaultTable
|
||||
import math
|
||||
|
||||
|
||||
hheaFormat = """
|
||||
> # big endian
|
||||
@ -32,30 +34,25 @@ class table__h_h_e_a(DefaultTable.DefaultTable):
|
||||
|
||||
# Note: Keep in sync with table__v_h_e_a
|
||||
|
||||
dependencies = ['hmtx', 'glyf']
|
||||
dependencies = ['hmtx', 'glyf', 'CFF ']
|
||||
|
||||
def decompile(self, data, ttFont):
|
||||
sstruct.unpack(hheaFormat, data, self)
|
||||
|
||||
def compile(self, ttFont):
|
||||
if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes:
|
||||
if ttFont.recalcBBoxes and (ttFont.isLoaded('glyf') or ttFont.isLoaded('CFF ')):
|
||||
self.recalc(ttFont)
|
||||
self.tableVersion = fi2ve(self.tableVersion)
|
||||
return sstruct.pack(hheaFormat, self)
|
||||
|
||||
def recalc(self, ttFont):
|
||||
hmtxTable = ttFont['hmtx']
|
||||
self.advanceWidthMax = max(adv for adv, _ in hmtxTable.metrics.values())
|
||||
|
||||
boundsWidthDict = {}
|
||||
if 'glyf' in ttFont:
|
||||
glyfTable = ttFont['glyf']
|
||||
INFINITY = 100000
|
||||
advanceWidthMax = 0
|
||||
minLeftSideBearing = +INFINITY # arbitrary big number
|
||||
minRightSideBearing = +INFINITY # arbitrary big number
|
||||
xMaxExtent = -INFINITY # arbitrary big negative number
|
||||
|
||||
for name in ttFont.getGlyphOrder():
|
||||
width, lsb = hmtxTable[name]
|
||||
advanceWidthMax = max(advanceWidthMax, width)
|
||||
g = glyfTable[name]
|
||||
if g.numberOfContours == 0:
|
||||
continue
|
||||
@ -63,25 +60,34 @@ class table__h_h_e_a(DefaultTable.DefaultTable):
|
||||
# Composite glyph without extents set.
|
||||
# Calculate those.
|
||||
g.recalcBounds(glyfTable)
|
||||
boundsWidthDict[name] = g.xMax - g.xMin
|
||||
elif 'CFF ' in ttFont:
|
||||
topDict = ttFont['CFF '].cff.topDictIndex[0]
|
||||
for name in ttFont.getGlyphOrder():
|
||||
cs = topDict.CharStrings[name]
|
||||
bounds = cs.calcBounds()
|
||||
if bounds is not None:
|
||||
boundsWidthDict[name] = math.ceil(bounds[2]) - math.floor(bounds[0])
|
||||
|
||||
if boundsWidthDict:
|
||||
minLeftSideBearing = float('inf')
|
||||
minRightSideBearing = float('inf')
|
||||
xMaxExtent = -float('inf')
|
||||
for name, boundsWidth in boundsWidthDict.items():
|
||||
advanceWidth, lsb = hmtxTable[name]
|
||||
rsb = advanceWidth - lsb - boundsWidth
|
||||
extent = lsb + boundsWidth
|
||||
minLeftSideBearing = min(minLeftSideBearing, lsb)
|
||||
rsb = width - lsb - (g.xMax - g.xMin)
|
||||
minRightSideBearing = min(minRightSideBearing, rsb)
|
||||
extent = lsb + (g.xMax - g.xMin)
|
||||
xMaxExtent = max(xMaxExtent, extent)
|
||||
|
||||
if xMaxExtent == -INFINITY:
|
||||
# No glyph has outlines.
|
||||
minLeftSideBearing = 0
|
||||
minRightSideBearing = 0
|
||||
xMaxExtent = 0
|
||||
|
||||
self.advanceWidthMax = advanceWidthMax
|
||||
self.minLeftSideBearing = minLeftSideBearing
|
||||
self.minRightSideBearing = minRightSideBearing
|
||||
self.xMaxExtent = xMaxExtent
|
||||
else:
|
||||
# XXX CFF recalc...
|
||||
pass
|
||||
|
||||
else: # No glyph has outlines.
|
||||
self.minLeftSideBearing = 0
|
||||
self.minRightSideBearing = 0
|
||||
self.xMaxExtent = 0
|
||||
|
||||
def toXML(self, writer, ttFont):
|
||||
formatstring, names, fixes = sstruct.getformat(hheaFormat)
|
||||
|
@ -5,6 +5,8 @@ from fontTools.misc.textTools import safeEval
|
||||
from fontTools.misc.fixedTools import (
|
||||
ensureVersionIsLong as fi2ve, versionToFixed as ve2fi)
|
||||
from . import DefaultTable
|
||||
import math
|
||||
|
||||
|
||||
vheaFormat = """
|
||||
> # big endian
|
||||
@ -31,30 +33,25 @@ class table__v_h_e_a(DefaultTable.DefaultTable):
|
||||
|
||||
# Note: Keep in sync with table__h_h_e_a
|
||||
|
||||
dependencies = ['vmtx', 'glyf']
|
||||
dependencies = ['vmtx', 'glyf', 'CFF ']
|
||||
|
||||
def decompile(self, data, ttFont):
|
||||
sstruct.unpack(vheaFormat, data, self)
|
||||
|
||||
def compile(self, ttFont):
|
||||
if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes:
|
||||
if ttFont.recalcBBoxes and (ttFont.isLoaded('glyf') or ttFont.isLoaded('CFF ')):
|
||||
self.recalc(ttFont)
|
||||
self.tableVersion = fi2ve(self.tableVersion)
|
||||
return sstruct.pack(vheaFormat, self)
|
||||
|
||||
def recalc(self, ttFont):
|
||||
vtmxTable = ttFont['vmtx']
|
||||
vmtxTable = ttFont['vmtx']
|
||||
self.advanceHeightMax = max(adv for adv, _ in vmtxTable.metrics.values())
|
||||
|
||||
boundsHeightDict = {}
|
||||
if 'glyf' in ttFont:
|
||||
glyfTable = ttFont['glyf']
|
||||
INFINITY = 100000
|
||||
advanceHeightMax = 0
|
||||
minTopSideBearing = +INFINITY # arbitrary big number
|
||||
minBottomSideBearing = +INFINITY # arbitrary big number
|
||||
yMaxExtent = -INFINITY # arbitrary big negative number
|
||||
|
||||
for name in ttFont.getGlyphOrder():
|
||||
height, tsb = vtmxTable[name]
|
||||
advanceHeightMax = max(advanceHeightMax, height)
|
||||
g = glyfTable[name]
|
||||
if g.numberOfContours == 0:
|
||||
continue
|
||||
@ -62,25 +59,34 @@ class table__v_h_e_a(DefaultTable.DefaultTable):
|
||||
# Composite glyph without extents set.
|
||||
# Calculate those.
|
||||
g.recalcBounds(glyfTable)
|
||||
boundsHeightDict[name] = g.yMax - g.yMin
|
||||
elif 'CFF ' in ttFont:
|
||||
topDict = ttFont['CFF '].cff.topDictIndex[0]
|
||||
for name in ttFont.getGlyphOrder():
|
||||
cs = topDict.CharStrings[name]
|
||||
bounds = cs.calcBounds()
|
||||
if bounds is not None:
|
||||
boundsHeightDict[name] = math.ceil(bounds[3]) - math.floor(bounds[1])
|
||||
|
||||
if boundsHeightDict:
|
||||
minTopSideBearing = float('inf')
|
||||
minBottomSideBearing = float('inf')
|
||||
yMaxExtent = -float('inf')
|
||||
for name, boundsHeight in boundsHeightDict.items():
|
||||
advanceHeight, tsb = vmtxTable[name]
|
||||
bsb = advanceHeight - tsb - boundsHeight
|
||||
extent = tsb + boundsHeight
|
||||
minTopSideBearing = min(minTopSideBearing, tsb)
|
||||
bsb = height - tsb - (g.yMax - g.yMin)
|
||||
minBottomSideBearing = min(minBottomSideBearing, bsb)
|
||||
extent = tsb + (g.yMax - g.yMin)
|
||||
yMaxExtent = max(yMaxExtent, extent)
|
||||
|
||||
if yMaxExtent == -INFINITY:
|
||||
# No glyph has outlines.
|
||||
minTopSideBearing = 0
|
||||
minBottomSideBearing = 0
|
||||
yMaxExtent = 0
|
||||
|
||||
self.advanceHeightMax = advanceHeightMax
|
||||
self.minTopSideBearing = minTopSideBearing
|
||||
self.minBottomSideBearing = minBottomSideBearing
|
||||
self.yMaxExtent = yMaxExtent
|
||||
else:
|
||||
# XXX CFF recalc...
|
||||
pass
|
||||
|
||||
else: # No glyph has outlines.
|
||||
self.minTopSideBearing = 0
|
||||
self.minBottomSideBearing = 0
|
||||
self.yMaxExtent = 0
|
||||
|
||||
def toXML(self, writer, ttFont):
|
||||
formatstring, names, fixes = sstruct.getformat(vheaFormat)
|
||||
|
48
Tests/cffLib/cffLib_test.py
Normal file
48
Tests/cffLib/cffLib_test.py
Normal file
@ -0,0 +1,48 @@
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from fontTools.cffLib import TopDict, PrivateDict, CharStrings
|
||||
from fontTools.misc.testTools import parseXML
|
||||
import unittest
|
||||
|
||||
|
||||
class TopDictTest(unittest.TestCase):
|
||||
|
||||
def test_recalcFontBBox(self):
|
||||
topDict = TopDict()
|
||||
topDict.CharStrings = CharStrings(None, None, None, PrivateDict(), None, None)
|
||||
topDict.CharStrings.fromXML(None, None, parseXML("""
|
||||
<CharString name=".notdef">
|
||||
endchar
|
||||
</CharString>
|
||||
<CharString name="foo"><!-- [100, -100, 300, 100] -->
|
||||
100 -100 rmoveto 200 hlineto 200 vlineto -200 hlineto endchar
|
||||
</CharString>
|
||||
<CharString name="bar"><!-- [0, 0, 200, 200] -->
|
||||
0 0 rmoveto 200 hlineto 200 vlineto -200 hlineto endchar
|
||||
</CharString>
|
||||
<CharString name="baz"><!-- [-55.1, -55.1, 55.1, 55.1] -->
|
||||
-55.1 -55.1 rmoveto 110.2 hlineto 110.2 vlineto -110.2 hlineto endchar
|
||||
</CharString>
|
||||
"""))
|
||||
|
||||
topDict.recalcFontBBox()
|
||||
self.assertEqual(topDict.FontBBox, [-56, -100, 300, 200])
|
||||
|
||||
def test_recalcFontBBox_empty(self):
|
||||
topDict = TopDict()
|
||||
topDict.CharStrings = CharStrings(None, None, None, PrivateDict(), None, None)
|
||||
topDict.CharStrings.fromXML(None, None, parseXML("""
|
||||
<CharString name=".notdef">
|
||||
endchar
|
||||
</CharString>
|
||||
<CharString name="space">
|
||||
123 endchar
|
||||
</CharString>
|
||||
"""))
|
||||
|
||||
topDict.recalcFontBBox()
|
||||
self.assertEqual(topDict.FontBBox, [0, 0, 0, 0])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
sys.exit(unittest.main())
|
32
Tests/misc/psCharStrings_test.py
Normal file
32
Tests/misc/psCharStrings_test.py
Normal file
@ -0,0 +1,32 @@
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from fontTools.cffLib import PrivateDict
|
||||
from fontTools.cffLib.specializer import stringToProgram
|
||||
from fontTools.misc.psCharStrings import T2CharString
|
||||
import unittest
|
||||
|
||||
|
||||
class T2CharStringTest(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def stringToT2CharString(cls, string):
|
||||
return T2CharString(program=stringToProgram(string), private=PrivateDict())
|
||||
|
||||
def test_calcBounds_empty(self):
|
||||
cs = self.stringToT2CharString("endchar")
|
||||
bounds = cs.calcBounds()
|
||||
self.assertEqual(bounds, None)
|
||||
|
||||
def test_calcBounds_line(self):
|
||||
cs = self.stringToT2CharString("100 100 rmoveto 40 10 rlineto -20 50 rlineto endchar")
|
||||
bounds = cs.calcBounds()
|
||||
self.assertEqual(bounds, (100, 100, 140, 160))
|
||||
|
||||
def test_calcBounds_curve(self):
|
||||
cs = self.stringToT2CharString("100 100 rmoveto -50 -150 200 0 -50 150 rrcurveto endchar")
|
||||
bounds = cs.calcBounds()
|
||||
self.assertEqual(bounds, (91.90524980688875, -12.5, 208.09475019311125, 100))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
sys.exit(unittest.main())
|
@ -5,8 +5,13 @@ from fontTools.misc.testTools import parseXML, getXML
|
||||
from fontTools.misc.textTools import deHexStr
|
||||
from fontTools.ttLib import TTFont, newTable
|
||||
from fontTools.misc.fixedTools import log
|
||||
import os
|
||||
import unittest
|
||||
|
||||
|
||||
CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
|
||||
DATA_DIR = os.path.join(CURR_DIR, 'data')
|
||||
|
||||
HHEA_DATA = deHexStr(
|
||||
'0001 0000 ' # 1.0 version
|
||||
'02EE ' # 750 ascent
|
||||
@ -155,6 +160,39 @@ class HheaDecompileOrFromXMLTest(unittest.TestCase):
|
||||
self.assertEqual(getattr(hhea, key), HHEA_AS_DICT[key])
|
||||
|
||||
|
||||
class HheaRecalcTest(unittest.TestCase):
|
||||
|
||||
def test_recalc_TTF(self):
|
||||
font = TTFont()
|
||||
font.importXML(os.path.join(DATA_DIR, '_h_h_e_a_recalc_TTF.ttx'))
|
||||
hhea = font['hhea']
|
||||
hhea.recalc(font)
|
||||
self.assertEqual(hhea.advanceWidthMax, 600)
|
||||
self.assertEqual(hhea.minLeftSideBearing, -56)
|
||||
self.assertEqual(hhea.minRightSideBearing, 100)
|
||||
self.assertEqual(hhea.xMaxExtent, 400)
|
||||
|
||||
def test_recalc_OTF(self):
|
||||
font = TTFont()
|
||||
font.importXML(os.path.join(DATA_DIR, '_h_h_e_a_recalc_OTF.ttx'))
|
||||
hhea = font['hhea']
|
||||
hhea.recalc(font)
|
||||
self.assertEqual(hhea.advanceWidthMax, 600)
|
||||
self.assertEqual(hhea.minLeftSideBearing, -56)
|
||||
self.assertEqual(hhea.minRightSideBearing, 100)
|
||||
self.assertEqual(hhea.xMaxExtent, 400)
|
||||
|
||||
def test_recalc_empty(self):
|
||||
font = TTFont()
|
||||
font.importXML(os.path.join(DATA_DIR, '_h_h_e_a_recalc_empty.ttx'))
|
||||
hhea = font['hhea']
|
||||
hhea.recalc(font)
|
||||
self.assertEqual(hhea.advanceWidthMax, 600)
|
||||
self.assertEqual(hhea.minLeftSideBearing, 0)
|
||||
self.assertEqual(hhea.minRightSideBearing, 0)
|
||||
self.assertEqual(hhea.xMaxExtent, 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
sys.exit(unittest.main())
|
||||
|
@ -5,8 +5,13 @@ from fontTools.misc.testTools import parseXML, getXML
|
||||
from fontTools.misc.textTools import deHexStr
|
||||
from fontTools.ttLib import TTFont, newTable
|
||||
from fontTools.misc.fixedTools import log
|
||||
import os
|
||||
import unittest
|
||||
|
||||
|
||||
CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
|
||||
DATA_DIR = os.path.join(CURR_DIR, 'data')
|
||||
|
||||
VHEA_DATA_VERSION_11 = deHexStr(
|
||||
'0001 1000 ' # 1.1 version
|
||||
'01F4 ' # 500 ascent
|
||||
@ -232,6 +237,39 @@ class VheaDecompileOrFromXMLTest(unittest.TestCase):
|
||||
self.assertEqual(getattr(vhea, key), VHEA_VERSION_11_AS_DICT[key])
|
||||
|
||||
|
||||
class VheaRecalcTest(unittest.TestCase):
|
||||
|
||||
def test_recalc_TTF(self):
|
||||
font = TTFont()
|
||||
font.importXML(os.path.join(DATA_DIR, '_v_h_e_a_recalc_TTF.ttx'))
|
||||
vhea = font['vhea']
|
||||
vhea.recalc(font)
|
||||
self.assertEqual(vhea.advanceHeightMax, 900)
|
||||
self.assertEqual(vhea.minTopSideBearing, 200)
|
||||
self.assertEqual(vhea.minBottomSideBearing, 377)
|
||||
self.assertEqual(vhea.yMaxExtent, 312)
|
||||
|
||||
def test_recalc_OTF(self):
|
||||
font = TTFont()
|
||||
font.importXML(os.path.join(DATA_DIR, '_v_h_e_a_recalc_OTF.ttx'))
|
||||
vhea = font['vhea']
|
||||
vhea.recalc(font)
|
||||
self.assertEqual(vhea.advanceHeightMax, 900)
|
||||
self.assertEqual(vhea.minTopSideBearing, 200)
|
||||
self.assertEqual(vhea.minBottomSideBearing, 377)
|
||||
self.assertEqual(vhea.yMaxExtent, 312)
|
||||
|
||||
def test_recalc_empty(self):
|
||||
font = TTFont()
|
||||
font.importXML(os.path.join(DATA_DIR, '_v_h_e_a_recalc_empty.ttx'))
|
||||
vhea = font['vhea']
|
||||
vhea.recalc(font)
|
||||
self.assertEqual(vhea.advanceHeightMax, 900)
|
||||
self.assertEqual(vhea.minTopSideBearing, 0)
|
||||
self.assertEqual(vhea.minBottomSideBearing, 0)
|
||||
self.assertEqual(vhea.yMaxExtent, 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
sys.exit(unittest.main())
|
||||
|
72
Tests/ttLib/tables/data/_h_h_e_a_recalc_OTF.ttx
Normal file
72
Tests/ttLib/tables/data/_h_h_e_a_recalc_OTF.ttx
Normal file
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ttFont sfntVersion="OTTO" ttLibVersion="3.12">
|
||||
|
||||
<GlyphOrder>
|
||||
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="A"/>
|
||||
<GlyphID id="2" name="B"/>
|
||||
<GlyphID id="3" name="C"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<hhea>
|
||||
<tableVersion value="0x00010000"/>
|
||||
<ascent value="800"/>
|
||||
<descent value="-200"/>
|
||||
<lineGap value="0"/>
|
||||
<advanceWidthMax value="999"/>
|
||||
<minLeftSideBearing value="99"/>
|
||||
<minRightSideBearing value="99"/>
|
||||
<xMaxExtent value="99"/>
|
||||
<caretSlopeRise value="1"/>
|
||||
<caretSlopeRun value="0"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved0 value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
<numberOfHMetrics value="4"/>
|
||||
</hhea>
|
||||
|
||||
<CFF>
|
||||
<major value="1"/>
|
||||
<minor value="0"/>
|
||||
<CFFFont name="Test">
|
||||
<Private>
|
||||
</Private>
|
||||
<CharStrings>
|
||||
<CharString name=".notdef">
|
||||
300
|
||||
0 0 rmoveto
|
||||
1 1 rlineto
|
||||
endchar
|
||||
</CharString>
|
||||
<CharString name="A">
|
||||
400
|
||||
-55.2 -55.2 rmoveto
|
||||
110.4 110.4 rlineto
|
||||
endchar
|
||||
</CharString>
|
||||
<CharString name="B">
|
||||
500
|
||||
100 0 rmoveto
|
||||
300 0 rlineto
|
||||
endchar
|
||||
</CharString>
|
||||
<CharString name="C">
|
||||
600
|
||||
endchar
|
||||
</CharString>
|
||||
</CharStrings>
|
||||
</CFFFont>
|
||||
</CFF>
|
||||
|
||||
<hmtx>
|
||||
<mtx name=".notdef" width="300" lsb="0"/>
|
||||
<mtx name="A" width="400" lsb="-56"/>
|
||||
<mtx name="B" width="500" lsb="100"/>
|
||||
<mtx name="C" width="600" lsb="0"/>
|
||||
</hmtx>
|
||||
|
||||
</ttFont>
|
63
Tests/ttLib/tables/data/_h_h_e_a_recalc_TTF.ttx
Normal file
63
Tests/ttLib/tables/data/_h_h_e_a_recalc_TTF.ttx
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.12">
|
||||
|
||||
<GlyphOrder>
|
||||
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="A"/>
|
||||
<GlyphID id="2" name="B"/>
|
||||
<GlyphID id="3" name="C"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<hhea>
|
||||
<tableVersion value="0x00010000"/>
|
||||
<ascent value="800"/>
|
||||
<descent value="-200"/>
|
||||
<lineGap value="0"/>
|
||||
<advanceWidthMax value="999"/>
|
||||
<minLeftSideBearing value="99"/>
|
||||
<minRightSideBearing value="99"/>
|
||||
<xMaxExtent value="99"/>
|
||||
<caretSlopeRise value="1"/>
|
||||
<caretSlopeRun value="0"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved0 value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
<numberOfHMetrics value="4"/>
|
||||
</hhea>
|
||||
|
||||
<glyf>
|
||||
<!-- The xMin, yMin, xMax and yMax values
|
||||
will be recalculated by the compiler. -->
|
||||
<TTGlyph name=".notdef" xMin="0" yMin="0" xMax="1" yMax="1">
|
||||
<contour>
|
||||
<pt x="0" y="0" on="1"/>
|
||||
<pt x="1" y="1" on="1"/>
|
||||
</contour>
|
||||
</TTGlyph>
|
||||
<TTGlyph name="A" xMin="-56" yMin="-56" xMax="56" yMax="56">
|
||||
<contour>
|
||||
<pt x="-56" y="-56" on="1"/>
|
||||
<pt x="56" y="56" on="1"/>
|
||||
</contour>
|
||||
</TTGlyph>
|
||||
<TTGlyph name="B" xMin="100" yMin="0" xMax="400" yMax="0">
|
||||
<contour>
|
||||
<pt x="100" y="0" on="1"/>
|
||||
<pt x="400" y="0" on="1"/>
|
||||
</contour>
|
||||
</TTGlyph>
|
||||
<TTGlyph name="C"/><!-- contains no outline data -->
|
||||
</glyf>
|
||||
|
||||
<hmtx>
|
||||
<mtx name=".notdef" width="300" lsb="0"/>
|
||||
<mtx name="A" width="400" lsb="-56"/>
|
||||
<mtx name="B" width="500" lsb="100"/>
|
||||
<mtx name="C" width="600" lsb="0"/>
|
||||
</hmtx>
|
||||
|
||||
</ttFont>
|
62
Tests/ttLib/tables/data/_h_h_e_a_recalc_empty.ttx
Normal file
62
Tests/ttLib/tables/data/_h_h_e_a_recalc_empty.ttx
Normal file
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ttFont sfntVersion="OTTO" ttLibVersion="3.12">
|
||||
|
||||
<GlyphOrder>
|
||||
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="A"/>
|
||||
<GlyphID id="2" name="B"/>
|
||||
<GlyphID id="3" name="C"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<hhea>
|
||||
<tableVersion value="0x00010000"/>
|
||||
<ascent value="800"/>
|
||||
<descent value="-200"/>
|
||||
<lineGap value="0"/>
|
||||
<advanceWidthMax value="999"/>
|
||||
<minLeftSideBearing value="99"/>
|
||||
<minRightSideBearing value="99"/>
|
||||
<xMaxExtent value="99"/>
|
||||
<caretSlopeRise value="1"/>
|
||||
<caretSlopeRun value="0"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved0 value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
<numberOfHMetrics value="4"/>
|
||||
</hhea>
|
||||
|
||||
<CFF>
|
||||
<major value="1"/>
|
||||
<minor value="0"/>
|
||||
<CFFFont name="Test">
|
||||
<Private>
|
||||
</Private>
|
||||
<CharStrings>
|
||||
<CharString name=".notdef">
|
||||
300 endchar
|
||||
</CharString>
|
||||
<CharString name="A">
|
||||
400 endchar
|
||||
</CharString>
|
||||
<CharString name="B">
|
||||
500 endchar
|
||||
</CharString>
|
||||
<CharString name="C">
|
||||
600 endchar
|
||||
</CharString>
|
||||
</CharStrings>
|
||||
</CFFFont>
|
||||
</CFF>
|
||||
|
||||
<hmtx>
|
||||
<mtx name=".notdef" width="300" lsb="0"/>
|
||||
<mtx name="A" width="400" lsb="0"/>
|
||||
<mtx name="B" width="500" lsb="0"/>
|
||||
<mtx name="C" width="600" lsb="0"/>
|
||||
</hmtx>
|
||||
|
||||
</ttFont>
|
72
Tests/ttLib/tables/data/_v_h_e_a_recalc_OTF.ttx
Normal file
72
Tests/ttLib/tables/data/_v_h_e_a_recalc_OTF.ttx
Normal file
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ttFont sfntVersion="OTTO" ttLibVersion="3.12">
|
||||
|
||||
<GlyphOrder>
|
||||
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="A"/>
|
||||
<GlyphID id="2" name="B"/>
|
||||
<GlyphID id="3" name="C"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<vhea>
|
||||
<tableVersion value="0x00011000"/>
|
||||
<ascent value="500"/>
|
||||
<descent value="-500"/>
|
||||
<lineGap value="0"/>
|
||||
<advanceHeightMax value="999"/>
|
||||
<minTopSideBearing value="99"/>
|
||||
<minBottomSideBearing value="99"/>
|
||||
<yMaxExtent value="99"/>
|
||||
<caretSlopeRise value="0"/>
|
||||
<caretSlopeRun value="1"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<reserved4 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
<numberOfVMetrics value="4"/>
|
||||
</vhea>
|
||||
|
||||
<CFF>
|
||||
<major value="1"/>
|
||||
<minor value="0"/>
|
||||
<CFFFont name="Test">
|
||||
<Private>
|
||||
</Private>
|
||||
<CharStrings>
|
||||
<CharString name=".notdef">
|
||||
300
|
||||
0 0 rmoveto
|
||||
1 1 rlineto
|
||||
endchar
|
||||
</CharString>
|
||||
<CharString name="A">
|
||||
400
|
||||
-55.2 -55.2 rmoveto
|
||||
110.4 110.4 rlineto
|
||||
endchar
|
||||
</CharString>
|
||||
<CharString name="B">
|
||||
500
|
||||
100 0 rmoveto
|
||||
300 0 rlineto
|
||||
endchar
|
||||
</CharString>
|
||||
<CharString name="C">
|
||||
600
|
||||
endchar
|
||||
</CharString>
|
||||
</CharStrings>
|
||||
</CFFFont>
|
||||
</CFF>
|
||||
|
||||
<vmtx>
|
||||
<mtx name=".notdef" height="600" tsb="222"/>
|
||||
<mtx name="A" height="700" tsb="200"/>
|
||||
<mtx name="B" height="800" tsb="300"/>
|
||||
<mtx name="C" height="900" tsb="0"/>
|
||||
</vmtx>
|
||||
|
||||
</ttFont>
|
63
Tests/ttLib/tables/data/_v_h_e_a_recalc_TTF.ttx
Normal file
63
Tests/ttLib/tables/data/_v_h_e_a_recalc_TTF.ttx
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.12">
|
||||
|
||||
<GlyphOrder>
|
||||
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="A"/>
|
||||
<GlyphID id="2" name="B"/>
|
||||
<GlyphID id="3" name="C"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<vhea>
|
||||
<tableVersion value="0x00011000"/>
|
||||
<ascent value="500"/>
|
||||
<descent value="-500"/>
|
||||
<lineGap value="0"/>
|
||||
<advanceHeightMax value="999"/>
|
||||
<minTopSideBearing value="99"/>
|
||||
<minBottomSideBearing value="99"/>
|
||||
<yMaxExtent value="99"/>
|
||||
<caretSlopeRise value="0"/>
|
||||
<caretSlopeRun value="1"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<reserved4 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
<numberOfVMetrics value="4"/>
|
||||
</vhea>
|
||||
|
||||
<glyf>
|
||||
<!-- The xMin, yMin, xMax and yMax values
|
||||
will be recalculated by the compiler. -->
|
||||
<TTGlyph name=".notdef" xMin="0" yMin="0" xMax="1" yMax="1">
|
||||
<contour>
|
||||
<pt x="0" y="0" on="1"/>
|
||||
<pt x="1" y="1" on="1"/>
|
||||
</contour>
|
||||
</TTGlyph>
|
||||
<TTGlyph name="A" xMin="-56" yMin="-56" xMax="56" yMax="56">
|
||||
<contour>
|
||||
<pt x="-56" y="-56" on="1"/>
|
||||
<pt x="56" y="56" on="1"/>
|
||||
</contour>
|
||||
</TTGlyph>
|
||||
<TTGlyph name="B" xMin="100" yMin="0" xMax="400" yMax="0">
|
||||
<contour>
|
||||
<pt x="100" y="0" on="1"/>
|
||||
<pt x="400" y="0" on="1"/>
|
||||
</contour>
|
||||
</TTGlyph>
|
||||
<TTGlyph name="C"/><!-- contains no outline data -->
|
||||
</glyf>
|
||||
|
||||
<vmtx>
|
||||
<mtx name=".notdef" height="600" tsb="222"/>
|
||||
<mtx name="A" height="700" tsb="200"/>
|
||||
<mtx name="B" height="800" tsb="300"/>
|
||||
<mtx name="C" height="900" tsb="0"/>
|
||||
</vmtx>
|
||||
|
||||
</ttFont>
|
62
Tests/ttLib/tables/data/_v_h_e_a_recalc_empty.ttx
Normal file
62
Tests/ttLib/tables/data/_v_h_e_a_recalc_empty.ttx
Normal file
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ttFont sfntVersion="OTTO" ttLibVersion="3.12">
|
||||
|
||||
<GlyphOrder>
|
||||
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="A"/>
|
||||
<GlyphID id="2" name="B"/>
|
||||
<GlyphID id="3" name="C"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<vhea>
|
||||
<tableVersion value="0x00011000"/>
|
||||
<ascent value="500"/>
|
||||
<descent value="-500"/>
|
||||
<lineGap value="0"/>
|
||||
<advanceHeightMax value="999"/>
|
||||
<minTopSideBearing value="99"/>
|
||||
<minBottomSideBearing value="99"/>
|
||||
<yMaxExtent value="99"/>
|
||||
<caretSlopeRise value="0"/>
|
||||
<caretSlopeRun value="1"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<reserved4 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
<numberOfVMetrics value="4"/>
|
||||
</vhea>
|
||||
|
||||
<CFF>
|
||||
<major value="1"/>
|
||||
<minor value="0"/>
|
||||
<CFFFont name="Test">
|
||||
<Private>
|
||||
</Private>
|
||||
<CharStrings>
|
||||
<CharString name=".notdef">
|
||||
300 endchar
|
||||
</CharString>
|
||||
<CharString name="A">
|
||||
400 endchar
|
||||
</CharString>
|
||||
<CharString name="B">
|
||||
500 endchar
|
||||
</CharString>
|
||||
<CharString name="C">
|
||||
600 endchar
|
||||
</CharString>
|
||||
</CharStrings>
|
||||
</CFFFont>
|
||||
</CFF>
|
||||
|
||||
<vmtx>
|
||||
<mtx name=".notdef" height="600" tsb="0"/>
|
||||
<mtx name="A" height="700" tsb="0"/>
|
||||
<mtx name="B" height="800" tsb="0"/>
|
||||
<mtx name="C" height="900" tsb="0"/>
|
||||
</vmtx>
|
||||
|
||||
</ttFont>
|
Loading…
x
Reference in New Issue
Block a user