Merge branch 'master' into fealib-duplicate-sub-warning
This commit is contained in:
commit
720488ed4b
@ -4,6 +4,6 @@ from fontTools.misc.loggingTools import configLogger
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
version = __version__ = "4.2.1.dev0"
|
version = __version__ = "4.2.3.dev0"
|
||||||
|
|
||||||
__all__ = ["version", "log", "configLogger"]
|
__all__ = ["version", "log", "configLogger"]
|
||||||
|
@ -751,6 +751,20 @@ class FontBuilder(object):
|
|||||||
from .feaLib.builder import addOpenTypeFeaturesFromString
|
from .feaLib.builder import addOpenTypeFeaturesFromString
|
||||||
addOpenTypeFeaturesFromString(self.font, features, filename=filename, tables=tables)
|
addOpenTypeFeaturesFromString(self.font, features, filename=filename, tables=tables)
|
||||||
|
|
||||||
|
def addFeatureVariations(self, conditionalSubstitutions, featureTag="rvrn"):
|
||||||
|
"""Add conditional substitutions to a Variable Font.
|
||||||
|
|
||||||
|
See `fontTools.varLib.featureVars.addFeatureVariations`.
|
||||||
|
"""
|
||||||
|
from .varLib import featureVars
|
||||||
|
|
||||||
|
if "fvar" not in self.font:
|
||||||
|
raise KeyError("'fvar' table is missing; can't add FeatureVariations.")
|
||||||
|
|
||||||
|
featureVars.addFeatureVariations(
|
||||||
|
self.font, conditionalSubstitutions, featureTag=featureTag
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def buildCmapSubTable(cmapping, format, platformID, platEncID):
|
def buildCmapSubTable(cmapping, format, platformID, platEncID):
|
||||||
subTable = cmap_classes[format](format)
|
subTable = cmap_classes[format](format)
|
||||||
|
@ -1307,6 +1307,9 @@ def subset_features(self, feature_indices):
|
|||||||
self.ensureDecompiled()
|
self.ensureDecompiled()
|
||||||
self.SubstitutionRecord = [r for r in self.SubstitutionRecord
|
self.SubstitutionRecord = [r for r in self.SubstitutionRecord
|
||||||
if r.FeatureIndex in feature_indices]
|
if r.FeatureIndex in feature_indices]
|
||||||
|
# remap feature indices
|
||||||
|
for r in self.SubstitutionRecord:
|
||||||
|
r.FeatureIndex = feature_indices.index(r.FeatureIndex)
|
||||||
self.SubstitutionCount = len(self.SubstitutionRecord)
|
self.SubstitutionCount = len(self.SubstitutionRecord)
|
||||||
return bool(self.SubstitutionCount)
|
return bool(self.SubstitutionCount)
|
||||||
|
|
||||||
|
@ -1179,7 +1179,7 @@ class Glyph(object):
|
|||||||
for end in endPts:
|
for end in endPts:
|
||||||
end = end + 1
|
end = end + 1
|
||||||
contour = coordinates[start:end]
|
contour = coordinates[start:end]
|
||||||
cFlags = flags[start:end]
|
cFlags = [flagOnCurve & f for f in flags[start:end]]
|
||||||
start = end
|
start = end
|
||||||
if 1 not in cFlags:
|
if 1 not in cFlags:
|
||||||
# There is not a single on-curve point on the curve,
|
# There is not a single on-curve point on the curve,
|
||||||
@ -1198,6 +1198,9 @@ class Glyph(object):
|
|||||||
while contour:
|
while contour:
|
||||||
nextOnCurve = cFlags.index(1) + 1
|
nextOnCurve = cFlags.index(1) + 1
|
||||||
if nextOnCurve == 1:
|
if nextOnCurve == 1:
|
||||||
|
# Skip a final lineTo(), as it is implied by
|
||||||
|
# pen.closePath()
|
||||||
|
if len(contour) > 1:
|
||||||
pen.lineTo(contour[0])
|
pen.lineTo(contour[0])
|
||||||
else:
|
else:
|
||||||
pen.qCurveTo(*contour[:nextOnCurve])
|
pen.qCurveTo(*contour[:nextOnCurve])
|
||||||
@ -1230,7 +1233,7 @@ class Glyph(object):
|
|||||||
# Start with the appropriate segment type based on the final segment
|
# Start with the appropriate segment type based on the final segment
|
||||||
segmentType = "line" if cFlags[-1] == 1 else "qcurve"
|
segmentType = "line" if cFlags[-1] == 1 else "qcurve"
|
||||||
for i, pt in enumerate(contour):
|
for i, pt in enumerate(contour):
|
||||||
if cFlags[i] == 1:
|
if cFlags[i] & flagOnCurve == 1:
|
||||||
pen.addPoint(pt, segmentType=segmentType)
|
pen.addPoint(pt, segmentType=segmentType)
|
||||||
segmentType = "line"
|
segmentType = "line"
|
||||||
else:
|
else:
|
||||||
|
@ -852,7 +852,11 @@ def validateLayerInfoVersion3Data(infoData):
|
|||||||
# -----------------
|
# -----------------
|
||||||
|
|
||||||
def _glifTreeFromFile(aFile):
|
def _glifTreeFromFile(aFile):
|
||||||
root = etree.parse(aFile).getroot()
|
if etree._have_lxml:
|
||||||
|
tree = etree.parse(aFile, parser=etree.XMLParser(remove_comments=True))
|
||||||
|
else:
|
||||||
|
tree = etree.parse(aFile)
|
||||||
|
root = tree.getroot()
|
||||||
if root.tag != "glyph":
|
if root.tag != "glyph":
|
||||||
raise GlifLibError("The GLIF is not properly formatted.")
|
raise GlifLibError("The GLIF is not properly formatted.")
|
||||||
if root.text and root.text.strip() != '':
|
if root.text and root.text.strip() != '':
|
||||||
@ -862,6 +866,9 @@ def _glifTreeFromFile(aFile):
|
|||||||
|
|
||||||
def _glifTreeFromString(aString):
|
def _glifTreeFromString(aString):
|
||||||
data = tobytes(aString, encoding="utf-8")
|
data = tobytes(aString, encoding="utf-8")
|
||||||
|
if etree._have_lxml:
|
||||||
|
root = etree.fromstring(data, parser=etree.XMLParser(remove_comments=True))
|
||||||
|
else:
|
||||||
root = etree.fromstring(data)
|
root = etree.fromstring(data)
|
||||||
if root.tag != "glyph":
|
if root.tag != "glyph":
|
||||||
raise GlifLibError("The GLIF is not properly formatted.")
|
raise GlifLibError("The GLIF is not properly formatted.")
|
||||||
|
@ -141,8 +141,14 @@ def _add_avar(font, axes):
|
|||||||
assert axis.maximum == max(keys)
|
assert axis.maximum == max(keys)
|
||||||
assert axis.default in keys
|
assert axis.default in keys
|
||||||
# No duplicates
|
# No duplicates
|
||||||
assert len(set(keys)) == len(keys)
|
assert len(set(keys)) == len(keys), (
|
||||||
assert len(set(vals)) == len(vals)
|
f"{axis.tag} axis: All axis mapping input='...' "
|
||||||
|
"values must be unique, but we found duplicates."
|
||||||
|
)
|
||||||
|
assert len(set(vals)) == len(vals), (
|
||||||
|
f"{axis.tag} axis: All axis mapping output='...' "
|
||||||
|
"values must be unique, but we found duplicates."
|
||||||
|
)
|
||||||
# Ascending values
|
# Ascending values
|
||||||
assert sorted(vals) == vals
|
assert sorted(vals) == vals
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#! /usr/bin/env python
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Tools to parse data files from the Unicode Character Database.
|
Tools to parse data files from the Unicode Character Database.
|
||||||
"""
|
"""
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#! /usr/bin/env python
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
"""usage: ttroundtrip [options] font1 ... fontN
|
"""usage: ttroundtrip [options] font1 ... fontN
|
||||||
|
|
||||||
|
18
NEWS.rst
18
NEWS.rst
@ -1,3 +1,21 @@
|
|||||||
|
4.2.2 (released 2019-12-12)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
- [subset] Fixed issue with subsetting FeatureVariations table when the index
|
||||||
|
of features changes as features get dropped. The feature index need to be
|
||||||
|
remapped to point to index of the remaining features (#1777, #1782).
|
||||||
|
- [fontBuilder] Added `addFeatureVariations` method to `FontBuilder` class. This
|
||||||
|
is a shorthand for calling `featureVars.addFeatureVariations` on the builder's
|
||||||
|
TTFont object (#1781).
|
||||||
|
- [glyf] Fixed the flags bug in glyph.drawPoints() like we did for glyph.draw()
|
||||||
|
(#1771, #1774).
|
||||||
|
|
||||||
|
4.2.1 (released 2019-12-06)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
- [glyf] Use the ``flagOnCurve`` bit mask in ``glyph.draw()``, so that we ignore
|
||||||
|
the ``overlap`` flag that may be set when instantiating variable fonts (#1771).
|
||||||
|
|
||||||
4.2.0 (released 2019-11-28)
|
4.2.0 (released 2019-11-28)
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#! /usr/bin/env python
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
# Sample script to convert legacy cmap subtables to format-4
|
# Sample script to convert legacy cmap subtables to format-4
|
||||||
# subtables. Note that this is rarely what one needs. You
|
# subtables. Note that this is rarely what one needs. You
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#! /usr/bin/env python
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
# Illustrates how a fonttools script can construct variable fonts.
|
# Illustrates how a fonttools script can construct variable fonts.
|
||||||
#
|
#
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#! /usr/bin/env python
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
from fontTools.misc.py23 import *
|
from fontTools.misc.py23 import *
|
||||||
from fontTools.ttLib import TTFont
|
from fontTools.ttLib import TTFont
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
"""Script to add a suffix to all family names in the input font's `name` table,
|
"""Script to add a suffix to all family names in the input font's `name` table,
|
||||||
and to optionally rename the output files with the given suffix.
|
and to optionally rename the output files with the given suffix.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#! /usr/bin/env python
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
from fontTools.misc.py23 import *
|
from fontTools.misc.py23 import *
|
||||||
from fontTools.ttLib import TTFont
|
from fontTools.ttLib import TTFont
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
""" Convert SVG paths to UFO glyphs. """
|
""" Convert SVG paths to UFO glyphs. """
|
||||||
|
|
||||||
|
|
||||||
__requires__ = ["FontTools", "ufoLib"]
|
__requires__ = ["fontTools"]
|
||||||
|
|
||||||
from fontTools.misc.py23 import SimpleNamespace
|
from fontTools.misc.py23 import SimpleNamespace
|
||||||
from fontTools.svgLib import SVGPath
|
from fontTools.svgLib import SVGPath
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.32">
|
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.2">
|
||||||
|
|
||||||
<GlyphOrder>
|
<GlyphOrder>
|
||||||
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
|
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<unitsPerEm value="1024"/>
|
<unitsPerEm value="1024"/>
|
||||||
<created value="Thu Nov 1 20:29:01 2018"/>
|
<created value="Thu Nov 1 20:29:01 2018"/>
|
||||||
<modified value="Thu Nov 1 20:29:01 2018"/>
|
<modified value="Thu Nov 1 20:29:01 2018"/>
|
||||||
<xMin value="100"/>
|
<xMin value="50"/>
|
||||||
<yMin value="0"/>
|
<yMin value="0"/>
|
||||||
<xMax value="500"/>
|
<xMax value="500"/>
|
||||||
<yMax value="400"/>
|
<yMax value="400"/>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
<descent value="200"/>
|
<descent value="200"/>
|
||||||
<lineGap value="0"/>
|
<lineGap value="0"/>
|
||||||
<advanceWidthMax value="600"/>
|
<advanceWidthMax value="600"/>
|
||||||
<minLeftSideBearing value="100"/>
|
<minLeftSideBearing value="50"/>
|
||||||
<minRightSideBearing value="100"/>
|
<minRightSideBearing value="100"/>
|
||||||
<xMaxExtent value="500"/>
|
<xMaxExtent value="500"/>
|
||||||
<caretSlopeRise value="1"/>
|
<caretSlopeRise value="1"/>
|
||||||
@ -126,7 +126,7 @@
|
|||||||
<mtx name=".notdef" width="600" lsb="0"/>
|
<mtx name=".notdef" width="600" lsb="0"/>
|
||||||
<mtx name=".null" width="600" lsb="0"/>
|
<mtx name=".null" width="600" lsb="0"/>
|
||||||
<mtx name="A" width="600" lsb="100"/>
|
<mtx name="A" width="600" lsb="100"/>
|
||||||
<mtx name="a" width="600" lsb="100"/>
|
<mtx name="a" width="600" lsb="50"/>
|
||||||
</hmtx>
|
</hmtx>
|
||||||
|
|
||||||
<cmap>
|
<cmap>
|
||||||
@ -164,12 +164,12 @@
|
|||||||
<instructions/>
|
<instructions/>
|
||||||
</TTGlyph>
|
</TTGlyph>
|
||||||
|
|
||||||
<TTGlyph name="a" xMin="100" yMin="0" xMax="500" yMax="400">
|
<TTGlyph name="a" xMin="50" yMin="0" xMax="250" yMax="200">
|
||||||
<contour>
|
<contour>
|
||||||
<pt x="100" y="0" on="1"/>
|
<pt x="50" y="0" on="1"/>
|
||||||
<pt x="100" y="400" on="1"/>
|
<pt x="50" y="200" on="1"/>
|
||||||
<pt x="500" y="400" on="1"/>
|
<pt x="250" y="200" on="1"/>
|
||||||
<pt x="500" y="0" on="1"/>
|
<pt x="250" y="0" on="1"/>
|
||||||
</contour>
|
</contour>
|
||||||
<instructions/>
|
<instructions/>
|
||||||
</TTGlyph>
|
</TTGlyph>
|
||||||
@ -269,6 +269,100 @@
|
|||||||
</extraNames>
|
</extraNames>
|
||||||
</post>
|
</post>
|
||||||
|
|
||||||
|
<GSUB>
|
||||||
|
<Version value="0x00010001"/>
|
||||||
|
<ScriptList>
|
||||||
|
<!-- ScriptCount=1 -->
|
||||||
|
<ScriptRecord index="0">
|
||||||
|
<ScriptTag value="DFLT"/>
|
||||||
|
<Script>
|
||||||
|
<DefaultLangSys>
|
||||||
|
<ReqFeatureIndex value="65535"/>
|
||||||
|
<!-- FeatureCount=1 -->
|
||||||
|
<FeatureIndex index="0" value="0"/>
|
||||||
|
</DefaultLangSys>
|
||||||
|
<!-- LangSysCount=0 -->
|
||||||
|
</Script>
|
||||||
|
</ScriptRecord>
|
||||||
|
</ScriptList>
|
||||||
|
<FeatureList>
|
||||||
|
<!-- FeatureCount=1 -->
|
||||||
|
<FeatureRecord index="0">
|
||||||
|
<FeatureTag value="rclt"/>
|
||||||
|
<Feature>
|
||||||
|
<!-- LookupCount=0 -->
|
||||||
|
</Feature>
|
||||||
|
</FeatureRecord>
|
||||||
|
</FeatureList>
|
||||||
|
<LookupList>
|
||||||
|
<!-- LookupCount=1 -->
|
||||||
|
<Lookup index="0">
|
||||||
|
<LookupType value="1"/>
|
||||||
|
<LookupFlag value="0"/>
|
||||||
|
<!-- SubTableCount=1 -->
|
||||||
|
<SingleSubst index="0" Format="1">
|
||||||
|
<Substitution in="A" out="a"/>
|
||||||
|
</SingleSubst>
|
||||||
|
</Lookup>
|
||||||
|
</LookupList>
|
||||||
|
<FeatureVariations>
|
||||||
|
<Version value="0x00010000"/>
|
||||||
|
<!-- FeatureVariationCount=2 -->
|
||||||
|
<FeatureVariationRecord index="0">
|
||||||
|
<ConditionSet>
|
||||||
|
<!-- ConditionCount=2 -->
|
||||||
|
<ConditionTable index="0" Format="1">
|
||||||
|
<AxisIndex value="3"/>
|
||||||
|
<FilterRangeMinValue value="0.8"/>
|
||||||
|
<FilterRangeMaxValue value="1.0"/>
|
||||||
|
</ConditionTable>
|
||||||
|
<ConditionTable index="1" Format="1">
|
||||||
|
<AxisIndex value="0"/>
|
||||||
|
<FilterRangeMinValue value="0.8"/>
|
||||||
|
<FilterRangeMaxValue value="1.0"/>
|
||||||
|
</ConditionTable>
|
||||||
|
</ConditionSet>
|
||||||
|
<FeatureTableSubstitution>
|
||||||
|
<Version value="0x00010000"/>
|
||||||
|
<!-- SubstitutionCount=1 -->
|
||||||
|
<SubstitutionRecord index="0">
|
||||||
|
<FeatureIndex value="0"/>
|
||||||
|
<Feature>
|
||||||
|
<!-- LookupCount=1 -->
|
||||||
|
<LookupListIndex index="0" value="0"/>
|
||||||
|
</Feature>
|
||||||
|
</SubstitutionRecord>
|
||||||
|
</FeatureTableSubstitution>
|
||||||
|
</FeatureVariationRecord>
|
||||||
|
<FeatureVariationRecord index="1">
|
||||||
|
<ConditionSet>
|
||||||
|
<!-- ConditionCount=2 -->
|
||||||
|
<ConditionTable index="0" Format="1">
|
||||||
|
<AxisIndex value="1"/>
|
||||||
|
<FilterRangeMinValue value="0.8"/>
|
||||||
|
<FilterRangeMaxValue value="1.0"/>
|
||||||
|
</ConditionTable>
|
||||||
|
<ConditionTable index="1" Format="1">
|
||||||
|
<AxisIndex value="2"/>
|
||||||
|
<FilterRangeMinValue value="0.8"/>
|
||||||
|
<FilterRangeMaxValue value="1.0"/>
|
||||||
|
</ConditionTable>
|
||||||
|
</ConditionSet>
|
||||||
|
<FeatureTableSubstitution>
|
||||||
|
<Version value="0x00010000"/>
|
||||||
|
<!-- SubstitutionCount=1 -->
|
||||||
|
<SubstitutionRecord index="0">
|
||||||
|
<FeatureIndex value="0"/>
|
||||||
|
<Feature>
|
||||||
|
<!-- LookupCount=1 -->
|
||||||
|
<LookupListIndex index="0" value="0"/>
|
||||||
|
</Feature>
|
||||||
|
</SubstitutionRecord>
|
||||||
|
</FeatureTableSubstitution>
|
||||||
|
</FeatureVariationRecord>
|
||||||
|
</FeatureVariations>
|
||||||
|
</GSUB>
|
||||||
|
|
||||||
<fvar>
|
<fvar>
|
||||||
|
|
||||||
<!-- Left -->
|
<!-- Left -->
|
||||||
|
@ -164,13 +164,20 @@ def test_build_var(tmpdir):
|
|||||||
pen.lineTo((500, 400))
|
pen.lineTo((500, 400))
|
||||||
pen.lineTo((500, 000))
|
pen.lineTo((500, 000))
|
||||||
pen.closePath()
|
pen.closePath()
|
||||||
|
glyph1 = pen.glyph()
|
||||||
|
|
||||||
glyph = pen.glyph()
|
pen = TTGlyphPen(None)
|
||||||
|
pen.moveTo((50, 0))
|
||||||
|
pen.lineTo((50, 200))
|
||||||
|
pen.lineTo((250, 200))
|
||||||
|
pen.lineTo((250, 0))
|
||||||
|
pen.closePath()
|
||||||
|
glyph2 = pen.glyph()
|
||||||
|
|
||||||
pen = TTGlyphPen(None)
|
pen = TTGlyphPen(None)
|
||||||
emptyGlyph = pen.glyph()
|
emptyGlyph = pen.glyph()
|
||||||
|
|
||||||
glyphs = {".notdef": emptyGlyph, "A": glyph, "a": glyph, ".null": emptyGlyph}
|
glyphs = {".notdef": emptyGlyph, "A": glyph1, "a": glyph2, ".null": emptyGlyph}
|
||||||
fb.setupGlyf(glyphs)
|
fb.setupGlyf(glyphs)
|
||||||
metrics = {}
|
metrics = {}
|
||||||
glyphTable = fb.font["glyf"]
|
glyphTable = fb.font["glyf"]
|
||||||
@ -206,6 +213,19 @@ def test_build_var(tmpdir):
|
|||||||
]
|
]
|
||||||
fb.setupGvar(variations)
|
fb.setupGvar(variations)
|
||||||
|
|
||||||
|
fb.addFeatureVariations(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
[
|
||||||
|
{"LEFT": (0.8, 1), "DOWN": (0.8, 1)},
|
||||||
|
{"RGHT": (0.8, 1), "UPPP": (0.8, 1)},
|
||||||
|
],
|
||||||
|
{"A": "a"}
|
||||||
|
)
|
||||||
|
],
|
||||||
|
featureTag="rclt",
|
||||||
|
)
|
||||||
|
|
||||||
fb.setupOS2()
|
fb.setupOS2()
|
||||||
fb.setupPost()
|
fb.setupPost()
|
||||||
fb.setupDummyDSIG()
|
fb.setupDummyDSIG()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import io
|
||||||
from fontTools.misc.py23 import *
|
from fontTools.misc.py23 import *
|
||||||
from fontTools import subset
|
from fontTools import subset
|
||||||
|
from fontTools.fontBuilder import FontBuilder
|
||||||
from fontTools.ttLib import TTFont, newTable
|
from fontTools.ttLib import TTFont, newTable
|
||||||
from fontTools.misc.loggingTools import CapturingLogHandler
|
from fontTools.misc.loggingTools import CapturingLogHandler
|
||||||
import difflib
|
import difflib
|
||||||
@ -728,5 +730,43 @@ class SubsetTest(unittest.TestCase):
|
|||||||
self.assertEqual(ttf.flavor, None)
|
self.assertEqual(ttf.flavor, None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_subset_feature_variations():
|
||||||
|
fb = FontBuilder(unitsPerEm=100)
|
||||||
|
fb.setupGlyphOrder([".notdef", "f", "f_f", "dollar", "dollar.rvrn"])
|
||||||
|
fb.setupCharacterMap({ord("f"): "f", ord("$"): "dollar"})
|
||||||
|
fb.setupNameTable({"familyName": "TestFeatureVars", "styleName": "Regular"})
|
||||||
|
fb.setupPost()
|
||||||
|
fb.setupFvar(axes=[("wght", 100, 400, 900, "Weight")], instances=[])
|
||||||
|
fb.addOpenTypeFeatures("""\
|
||||||
|
feature dlig {
|
||||||
|
sub f f by f_f;
|
||||||
|
} dlig;
|
||||||
|
""")
|
||||||
|
fb.addFeatureVariations(
|
||||||
|
[([{"wght": (0.20886, 1.0)}], {"dollar": "dollar.rvrn"})],
|
||||||
|
featureTag="rvrn"
|
||||||
|
)
|
||||||
|
buf = io.BytesIO()
|
||||||
|
fb.save(buf)
|
||||||
|
buf.seek(0)
|
||||||
|
|
||||||
|
font = TTFont(buf)
|
||||||
|
|
||||||
|
options = subset.Options()
|
||||||
|
subsetter = subset.Subsetter(options)
|
||||||
|
subsetter.populate(unicodes=[ord("f"), ord("$")])
|
||||||
|
subsetter.subset(font)
|
||||||
|
|
||||||
|
featureTags = {
|
||||||
|
r.FeatureTag for r in font["GSUB"].table.FeatureList.FeatureRecord
|
||||||
|
}
|
||||||
|
# 'dlig' is discretionary so it is dropped by default
|
||||||
|
assert "dlig" not in featureTags
|
||||||
|
assert "f_f" not in font.getGlyphOrder()
|
||||||
|
# 'rvrn' is required so it is kept by default
|
||||||
|
assert "rvrn" in featureTags
|
||||||
|
assert "dollar.rvrn" in font.getGlyphOrder()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit(unittest.main())
|
sys.exit(unittest.main())
|
||||||
|
@ -2,6 +2,8 @@ from fontTools.misc.py23 import *
|
|||||||
from fontTools.misc.fixedTools import otRound
|
from fontTools.misc.fixedTools import otRound
|
||||||
from fontTools.misc.testTools import getXML, parseXML
|
from fontTools.misc.testTools import getXML, parseXML
|
||||||
from fontTools.pens.ttGlyphPen import TTGlyphPen
|
from fontTools.pens.ttGlyphPen import TTGlyphPen
|
||||||
|
from fontTools.pens.recordingPen import RecordingPen, RecordingPointPen
|
||||||
|
from fontTools.pens.pointPen import PointToSegmentPen
|
||||||
from fontTools.ttLib import TTFont, newTable, TTLibError
|
from fontTools.ttLib import TTFont, newTable, TTLibError
|
||||||
from fontTools.ttLib.tables._g_l_y_f import (
|
from fontTools.ttLib.tables._g_l_y_f import (
|
||||||
GlyphCoordinates,
|
GlyphCoordinates,
|
||||||
@ -284,6 +286,58 @@ class glyfTableTest(unittest.TestCase):
|
|||||||
|
|
||||||
composite.compact(glyfTable)
|
composite.compact(glyfTable)
|
||||||
|
|
||||||
|
def test_bit6_draw_to_pen_issue1771(self):
|
||||||
|
# https://github.com/fonttools/fonttools/issues/1771
|
||||||
|
font = TTFont(sfntVersion="\x00\x01\x00\x00")
|
||||||
|
# glyph00003 contains a bit 6 flag on the first point,
|
||||||
|
# which triggered the issue
|
||||||
|
font.importXML(GLYF_TTX)
|
||||||
|
glyfTable = font['glyf']
|
||||||
|
pen = RecordingPen()
|
||||||
|
glyfTable["glyph00003"].draw(pen, glyfTable=glyfTable)
|
||||||
|
expected = [('moveTo', ((501, 1430),)),
|
||||||
|
('lineTo', ((683, 1430),)),
|
||||||
|
('lineTo', ((1172, 0),)),
|
||||||
|
('lineTo', ((983, 0),)),
|
||||||
|
('lineTo', ((591, 1193),)),
|
||||||
|
('lineTo', ((199, 0),)),
|
||||||
|
('lineTo', ((12, 0),)),
|
||||||
|
('closePath', ()),
|
||||||
|
('moveTo', ((249, 514),)),
|
||||||
|
('lineTo', ((935, 514),)),
|
||||||
|
('lineTo', ((935, 352),)),
|
||||||
|
('lineTo', ((249, 352),)),
|
||||||
|
('closePath', ())]
|
||||||
|
self.assertEqual(pen.value, expected)
|
||||||
|
|
||||||
|
def test_bit6_draw_to_pointpen(self):
|
||||||
|
# https://github.com/fonttools/fonttools/issues/1771
|
||||||
|
font = TTFont(sfntVersion="\x00\x01\x00\x00")
|
||||||
|
# glyph00003 contains a bit 6 flag on the first point
|
||||||
|
# which triggered the issue
|
||||||
|
font.importXML(GLYF_TTX)
|
||||||
|
glyfTable = font['glyf']
|
||||||
|
pen = RecordingPointPen()
|
||||||
|
glyfTable["glyph00003"].drawPoints(pen, glyfTable=glyfTable)
|
||||||
|
expected = [
|
||||||
|
('beginPath', (), {}),
|
||||||
|
('addPoint', ((501, 1430), 'line', False, None), {}),
|
||||||
|
('addPoint', ((683, 1430), 'line', False, None), {}),
|
||||||
|
('addPoint', ((1172, 0), 'line', False, None), {}),
|
||||||
|
('addPoint', ((983, 0), 'line', False, None), {}),
|
||||||
|
]
|
||||||
|
self.assertEqual(pen.value[:len(expected)], expected)
|
||||||
|
|
||||||
|
def test_draw_vs_drawpoints(self):
|
||||||
|
font = TTFont(sfntVersion="\x00\x01\x00\x00")
|
||||||
|
font.importXML(GLYF_TTX)
|
||||||
|
glyfTable = font['glyf']
|
||||||
|
pen1 = RecordingPen()
|
||||||
|
pen2 = RecordingPen()
|
||||||
|
glyfTable["glyph00003"].draw(pen1, glyfTable)
|
||||||
|
glyfTable["glyph00003"].drawPoints(PointToSegmentPen(pen2), glyfTable)
|
||||||
|
self.assertEqual(pen1.value, pen2.value)
|
||||||
|
|
||||||
|
|
||||||
class GlyphComponentTest:
|
class GlyphComponentTest:
|
||||||
|
|
||||||
|
@ -161,3 +161,21 @@ class ReadWriteFuncTest(unittest.TestCase):
|
|||||||
def testXmlDeclaration(self):
|
def testXmlDeclaration(self):
|
||||||
s = writeGlyphToString("a", _Glyph())
|
s = writeGlyphToString("a", _Glyph())
|
||||||
self.assertTrue(s.startswith(XML_DECLARATION % "UTF-8"))
|
self.assertTrue(s.startswith(XML_DECLARATION % "UTF-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_xml_remove_comments():
|
||||||
|
s = b"""<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<!-- a comment -->
|
||||||
|
<glyph name="A" format="2">
|
||||||
|
<advance width="1290"/>
|
||||||
|
<unicode hex="0041"/>
|
||||||
|
<!-- another comment -->
|
||||||
|
</glyph>
|
||||||
|
"""
|
||||||
|
|
||||||
|
g = _Glyph()
|
||||||
|
readGlyphFromString(s, g)
|
||||||
|
|
||||||
|
assert g.name == "A"
|
||||||
|
assert g.width == 1290
|
||||||
|
assert g.unicodes == [0x0041]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 4.2.1.dev0
|
current_version = 4.2.3.dev0
|
||||||
commit = True
|
commit = True
|
||||||
tag = False
|
tag = False
|
||||||
tag_name = {new_version}
|
tag_name = {new_version}
|
||||||
|
4
setup.py
4
setup.py
@ -1,4 +1,4 @@
|
|||||||
#! /usr/bin/env python
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import io
|
import io
|
||||||
@ -345,7 +345,7 @@ def find_data_files(manpath="share/man"):
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="fonttools",
|
name="fonttools",
|
||||||
version="4.2.1.dev0",
|
version="4.2.3.dev0",
|
||||||
description="Tools to manipulate font files",
|
description="Tools to manipulate font files",
|
||||||
author="Just van Rossum",
|
author="Just van Rossum",
|
||||||
author_email="just@letterror.com",
|
author_email="just@letterror.com",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user